⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 compress.cpp

📁 这是我自己写的wince程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#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<last;)
		{
			if(flag <= 2) match=1;
			else  
				match=seek_phrase(windows,flag, &c_flag, &address,i,content,hash,hashtable,last,type);     
			af_length++;
			if(match == 2 || match <= 0|| match > 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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -