www.pudn.com > cezip.rar > compress.cpp, change:2005-03-19,size:15819b
#include "stdafx.h"
#include "compress.h"
/////////////////////////////////////////////////////////////////////
//hashfun:计算hash值
//此前已经保证至少有三个元素
word hashfun(char *windows)
{
word a,b,c;
a=windows[0];
a*=256; //左移八位
a+=windows[1];
b=windows[1];
b*=256; //左移八位
b+=windows[2];
c=a^b;
return c;
}
/////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
//scrollwindows :滚动窗口
//i 开始位址 windows 窗口 content 缓存数组
//最多读入17个
//返回窗口读入的个数
int scrollwindows(word i,char *windows, char *content,word last)
{
word k,c;
c=i;
for( k = 0;k < 17 ; k++)
{
if(c+k == last) return k;
windows[k]=content[k+c];
}
return 17;
}
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
//seek :真正寻找匹配串
//返回匹配个数,并通过address传地址
char seek(char *windows,word *address,char *content,word i,word *hash,word *hashtable,word flag,word c_flag)
{
word hashnum,k,index,j;
char tem_match,match=0;
j=(word) flag;
hashnum=hashfun(windows);
if(hash[hashnum] == 65535)
{
hash[hashnum]=i;
hashtable[i]=65535; //防止死循环
*address=65535;
return 1;
}
else
{
k=hash[hashnum];
if(k == i) k=hashtable[i]; //前次已在hashtable中了,再找是自己和自己比,现在应跳过
while(k != 65535)
{
tem_match=0;
index=0;
while(windows[index] == content[k+index])
{
tem_match++;
index++;
if(index >= j) break; //最大匹配长度为窗口读入的个数
if(k+index >= 65534) break; //防止超出content的范围
}
if(tem_match>match) //k表示当前正在比较的字符串地址
{
*address=k;
match=tem_match;
}
if(match == j) break;//已到最大匹配
k=hashtable[k];
}
if(c_flag == 0)
{
hashtable[i]=hash[hashnum];
hash[hashnum]=i;
}
return match;
}
}
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
//seek_phrase:寻找匹配的字符串
//两次调用seek比较最佳的压缩方式
//返回匹配个数,并通过address传地址
char seek_phrase(char *windows,word flag ,word *c_flag,word *address,word i,char *content,word *hash,word *hashtable,word last,int type)
{
char match1,match2,match;
word address1,address2;
int lev; //随type 的不同而不同
if(type == 1) lev =2;
else lev=3;
match1=seek(windows,&address1,content,i,hash,hashtable,flag,*c_flag);
if( flag <= 3) //跳过贪婪匹配
{match2=0;address2=address1;}
else
match2=seek(windows+1,&address2,content,i+1,hash,hashtable,flag-1,*c_flag); //注意windows+1和i+1
if(match1 < match2 || match1 <= lev)
{
match=1;
*c_flag=1; //匹配一个,下个的hashtable已写入,否则会死循环
*address=address2;
}
else
{
match=match1;
*c_flag=0; //下个的hashtable已写入,但可以跳过它
*address=address1;
}
return match;
}
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
//out_code2:将压缩结果写入特定的缓存
void out_code2(char match,word *af_length,word *cp_length,word address,char *windows,char *neirong,char *len_date)
{
word ah,al;
int c;
char len;
if(match == 0|| match== 2 || match == 3)
{
MessageBox(NULL,_T("Compress Fatal Error!"),_T("Error!"),MB_OK);
exit(0);
} //检验
if(match == 1)
{
neirong[*af_length-1]=windows[0];
if(windows[0] == -1)
{
(*cp_length)++; //++ 比 * 优先!!!
c=(*cp_length-1)/2;
len_date[c]=(len_date[c]*16+0); //写入len_date 左移4位
}
}
else
{
len=match-2;
c=(*cp_length-1)/2;
len_date[c]=(len_date[c]*16+len); //写入len_date 左移4位
neirong[*af_length-1]=-1;
if(address<0)
{
MessageBox(NULL,_T("Compress Fatal Error!"),_T("Error!"),MB_OK);
exit(0);
} //检验
ah=address/256;
al=address%256;
neirong[*af_length]=(char)ah; //写入outdate
neirong[*af_length+1]=(char)al;
(*af_length)++;
(*af_length)++;
}
}
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
//file_out_code2:写入文件
//
void file_out_code2(FILE *out,word af_length,word cp_length,char *neirong,word last,char *len_date)
{
int i,c=0;
word len=0;
fwrite(&last,2,1,out);
fwrite(&af_length,2,1,out);
fwrite(&cp_length,2,1,out);
i=cp_length/2;
if(cp_length%2 != 0)
{
len_date[i]=len_date[i]*16;
i++;
}
fwrite(len_date,i,1,out);
fwrite(neirong,af_length,1,out);
}
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
//compress: 压缩数据的函数
//in 源数据区;out 目标数据区;
//一次最大处理65536个字节;
//type : 1 为文本型,2为其他型。
int compress(FILE *in,FILE *out,int type)
{
word af_length; //type1时 :计算处理的次数,为对照表(table)提供长度。//type2时 :为neirong提供长度
word cp_length; //type1时 :计算作缩略的次数,为len_date提供长度。 //type2时 :计算-1和作缩略的次数,为len_date提供长度。
char* content; //将待压数据读入缓存
word* hash; //hash值的索引
char windows[17]; //预读区,限制了最大匹配长度为17
word* hashtable; //hash 表
char* len_date; //记录每次缩略的长度
char *neirong; //经处理过的字符或地址。255 -1 代表缩略 ,后跟两字节地址, 其余皆为字符。
word i; //计数,指明当前处理的位置
word address; //能匹配的地址
char match; //能匹配的长度
int k=1; //辅助计数
fseek(in,0,SEEK_END);
long length=ftell(in); //计算文件长度
fseek(in,0,SEEK_SET);
a_file+=length;
len_fi=length;
fwrite(&length,4,1,out);
word last; //本次处理的个数
word flag; //窗口中读入的个数
word c_flag; //是否加入hashtable过。 0 为否;1 为加入过
word ii=0; //遇到文件的末尾使用,加0
word a; //初始化使用
last=(word)((65535>length)?length:65535);
al_se=no_se=0;
len_se=0;
len_db=0;
pe_num=0;
al_se=length/16384+1;
content = (char*)malloc(65536*sizeof(char)); //各数据缓存的初始化
memset(content,0,sizeof(content));
hash = (word*)malloc(65536*sizeof(word));
memset(hash,0,sizeof(hash));
hashtable = (word*)malloc(65536*sizeof(word));
memset(hashtable,0,sizeof(hashtable));
len_date = (char*)malloc(65536*sizeof(char));
memset(len_date,0,sizeof(len_date));
while(k>0)
{
len_se=16387;
c_flag=0;
af_length=0;
cp_length=0;
length -= 65535;
for(a=0;a<65535;a++) //初始化为0
len_date[a]=0;
len_date[a]=0;
neirong=(char *)malloc(last);
fread(content,1,last,in);
for(a=0;a<65535;a++) //初始化为65535
{
hash[a]=65535;
hashtable[a]=65535;
}
hash[65535]=65536;
hashtable[65535]=65535; //单独初始化,防止上个for死循环
flag=scrollwindows(0,windows,content,last);
for(i=0;i 17)
{
MessageBox(NULL,_T("Compress Error!"),_T("Error"),MB_OK);
return 1;
} //做一些检测
if(match > 2) cp_length++;
out_code2(match,&af_length,&cp_length,address,windows,neirong,len_date);
i+=match;
if(i == 0) break;//防止i重回0,死循环
flag=scrollwindows(i,windows,content,last); //滚动窗口
}
len_cp+=cp_length;len_cp+=2;
len_af+=af_length;len_af+=2;
file_out_code2(out,af_length,cp_length,neirong,last,len_date);
free(neirong);
k = (65535>length)?length:65535;
if(k < 0) break;
last=(word) k;
}
fwrite(&ii,2,1,out);
result=2.5*len_cp+len_af;
af_file+=result;
result=result/len_fi;
len_af=len_cp=0;
return 0;
}
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
//decompress : 解压缩
//
int decompress(FILE *in,int type)
{
char* content; //解压完的缓存
unsigned char* len_date; //缩略的长度对照表 用af_index寻址。
content = (char*)malloc(65536*sizeof(char));
memset(content,0,sizeof(content));
len_date = (unsigned char*)malloc(65536*sizeof(unsigned char));
memset(len_date,0,sizeof(len_date));
unsigned short last,af_length,cp_length;
unsigned char tem,ah,al;
unsigned int a;
unsigned int b; //负责len_date中的寻址
unsigned int c; //缩略长度
unsigned int d; //
unsigned int address; //负责content中寻址。
FILE *out;
char filena[20]; //放文件名
unsigned char co_len=0; //密码长度
unsigned char fi_num; //文件个数
long fi_len=0; //文件长度
unsigned char fn_len=0; //文件名长度
int flag=1;
fread(&co_len,1,1,in);
fi_num=co_len;
for(;;)
{
fi_len=0; //文件长度
fn_len=0;
fread(&fn_len,1,1,in);
if(feof(in)) break;
fread(filena,fn_len,1,in);
if((out=fopen(filena,"wb")) == NULL)
{
MessageBox(NULL,_T("Can't open file!"),_T("Error"),MB_OK);
return 1;
}
fread(&fi_len,4,1,in);
al_se=no_se=0;
al_se=fi_len/16384+1;
while(1)
{
last=0;
af_length=0;
cp_length=0;
fread(&last,2,1,in);
if(last == 0) break;
fread(&af_length,2,1,in);
fread(&cp_length,2,1,in);
if(al_se-no_se >= 4)
len_se=last/4+3;
else
len_se=last/(al_se-no_se)+2;
for(a=0;;)
{
if(cp_length == 0) break;
fread(&tem,1,1,in);
len_date[a]=tem/16;
a++;
if(a == cp_length) break;
len_date[a]=tem%16;
a++;
if(a == cp_length) break;
}
for(a=b=0;a=-1;i--)
{
if(savePath[i] == '\\') break;
}
if(i<0) i=0;
strcpy(file1,savePath+i+1);
fn_len = strlen(file1);
fn_len++;
fseek(out,8260,0);
fwrite(file1,fn_len,1,out);
fclose(out);
if((out=fopen(savePath,"ab")) == NULL)
{
MessageBox(NULL,_T("Can't create exe file!"),_T("Error"),MB_OK);
return 1;
}
fwrite(&itemCount,1,1,out);
for(i=0;i