标签:
7-10 lzw.c
1 #include <stdlib.h> 2 #include <stdio.h> 3 #define BITS 12 //每个数据项的二进制位数 4 #define HASHING_SHIFT BITS-8 //HASH表的移位数 5 #define MAX_VALUE (1<<BITS)-1 6 #define MAX_CODE MAX_VALUE-1 //最大标号 7 #define TABLE_SIZE 4099 //HASH表的长度 8 typedef struct{ 9 int *code; //代码 10 unsigned int *prefix; //前缀 11 unsigned char *suffix; //后缀 12 }LZW_DATA; 13 unsigned char decode_stack[TABLE_SIZE]; //用于保存解压缩后的数据 14 LZW_DATA lzw1,*lzw; 15 16 void compress(FILE *input,FILE *output); //压缩函数 17 void expand(FILE *input,FILE *output); //解压函数 18 unsigned int hashsearch(int hash_prefix,unsigned int hash_character); //HASH表搜索函数 19 char *decode(unsigned char *buffer,unsigned int code); 20 unsigned int incode(FILE *input); 21 void outcode(FILE *output,unsigned int code); 22 23 void compress(FILE *input,FILE *output) //压缩函数 24 { 25 unsigned int curr_code; 26 unsigned int suffix; //后缀字符 27 unsigned int prefix; //前缀字符 28 unsigned int index; 29 int i; 30 31 if(!(lzw1.code=malloc(TABLE_SIZE*sizeof(unsigned int)))) //代码值数组 32 { 33 printf("内存分配失败!\n"); 34 exit(0); 35 } 36 if(!(lzw1.prefix=malloc(TABLE_SIZE*sizeof(unsigned int))))//压缩前数据 37 { 38 printf("内存分配失败!\n"); 39 exit(0); 40 } 41 if(!(lzw1.suffix=malloc(TABLE_SIZE*sizeof(unsigned char))))//压缩后数据 42 { 43 printf("内存分配失败!\n"); 44 exit(0); 45 } 46 lzw=&lzw1; 47 curr_code=258; //编译表中的字符串编号从258开始 48 for(i=0;i<TABLE_SIZE;i++) //初始化标号数组 49 lzw->code[i]=-1; 50 i=0; 51 printf("\n开始压缩."); 52 prefix=getc(input); //从文件读取一个字节 53 while((suffix=getc(input))!= (unsigned)EOF) //循环处理输入文件中的内容 54 { 55 if (++i==1000) //处理1000个字节显示一个小数点,表示系统正在处理 56 { 57 i=0; 58 printf("."); 59 } 60 index=hashsearch(prefix,suffix); //在HASH表中查找并返回索引号 61 if (lzw->code[index]!=-1)//若该标号存在 62 prefix=lzw->code[index];//使用该标号作为前缀 63 else{ //若标号不存在 64 if (curr_code<=(MAX_CODE)){ //标号未超过最大标号 65 lzw->code[index]=curr_code++; //增加一个标号 66 lzw->prefix[index]=prefix; //保存前缀 67 lzw->suffix[index]=suffix; //保存后缀 68 } 69 outcode(output,prefix); //输出前缀字节的内容 70 prefix=suffix;//将后缀作前缀,准备下次循环 71 } 72 } 73 outcode(output,prefix); //输出前缀 74 outcode(output,(MAX_VALUE)); //输出结束标志 75 outcode(output,0); 76 77 free(lzw->code); //释放分配的内存 78 free(lzw->prefix); 79 free(lzw->suffix); 80 } 81 82 unsigned int hashsearch(int prefix,unsigned int suffix)//HASH表搜索函数 83 { 84 int index; 85 int offset; 86 index=(suffix << HASHING_SHIFT)^prefix; //构造HASH地址 87 if(index == 0) 88 offset=1; 89 else 90 offset=TABLE_SIZE-index; 91 while(1) 92 { 93 if(lzw->code[index]==-1) //找到一个空表项 94 return(index); //返回HASH地址 95 if (lzw->prefix[index]==prefix && lzw->suffix[index]==suffix) //找到目标数据 96 return(index); //返回HASH地址 97 index-=offset; //处理冲突,调整HASH地址 98 if(index<0) index+=TABLE_SIZE; //调整HASH地址 99 } 100 } 101 102 void outcode(FILE *output,unsigned int code) //输出压缩后的字节内容 103 { 104 static int ob=0; //静态变量,保存已输出数据的二进制位数 105 static unsigned long obb=0L;//静态变量,保存需输出数据的二进制位数 106 obb |= (unsigned long) code << (32-BITS-ob); //进行移位合并 107 ob+=BITS; //增加需输出数据的二进制位 108 while (ob>=8) //达到一个字节,则输出 109 { 110 putc(obb>>24,output); //右移24位,使低字节8位为需要输出的数据 111 obb<<= 8; //左移8位,去掉已输入的一个字节数据 112 ob-=8; //减去已输出的8位,保留剩余的未输出的位数 113 } 114 return; 115 } 116 void expand(FILE *input,FILE *output) //解压缩函数 117 { 118 unsigned int curr_code; 119 unsigned int suffix; 120 unsigned int prefix; 121 int ch; 122 int i; 123 unsigned char *ps; 124 char *decode(unsigned char *buffer,unsigned int code); 125 126 if(!(lzw1.code=malloc(TABLE_SIZE*sizeof(unsigned int)))) //代码值数组 127 { 128 printf("内存分配失败!\n"); 129 exit(0); 130 } 131 if(!(lzw1.prefix=malloc(TABLE_SIZE*sizeof(unsigned int))))//压缩前数据 132 { 133 printf("内存分配失败!\n"); 134 exit(0); 135 } 136 if(!(lzw1.suffix=malloc(TABLE_SIZE*sizeof(unsigned char))))//压缩后数据 137 { 138 printf("内存分配失败!\n"); 139 exit(0); 140 } 141 lzw=&lzw1; 142 curr_code=258; //定义标号从258开始 143 i=0; 144 printf("\n解压缩."); 145 prefix=incode(input); //读入第一个编码,并初始化字符变量 146 ch=prefix; //保存前缀到字符变量 147 putc(prefix,output); // 输出字符到输出文件上 148 while ((suffix=incode(input))!=(MAX_VALUE)) //循环进行解压缩 149 { 150 if (++i==1000) //处理1000个字节就显示一个点 151 { 152 i=0; 153 printf("."); 154 } 155 if (suffix>=curr_code)//后缀是未定义的标号 156 { 157 *decode_stack=ch; //保存前缀字符 158 ps=decode(decode_stack+1,prefix);//调用函数进行解码 159 } 160 else 161 ps=decode(decode_stack,suffix); //调用解码函数处理后缀 162 163 ch=*ps; 164 while(ps>=decode_stack) //循环输出解码的字节 165 putc(*ps--,output); 166 if (curr_code<=MAX_CODE) //若标号未超过最大值 167 { 168 lzw->prefix[curr_code]=prefix; //保存前缀到编译表 169 lzw->suffix[curr_code]=ch; //保存后缀到编译表 170 curr_code++; //标号增加 171 } 172 prefix=suffix; //后缀作前缀,准备下次的循环 173 } 174 175 free(lzw->code); //释放分配的内存 176 free(lzw->prefix); 177 free(lzw->suffix); 178 } 179 char *decode(unsigned char *buffer,unsigned int code) //解码函数 180 { 181 int i=0; 182 while(code>257) //code不是ASCII码字符 183 { 184 *buffer++ =lzw->suffix[code]; //保存标号到缓冲区 185 code=lzw->prefix[code]; //取得该标号的前缀 186 if (i++>=TABLE_SIZE) 187 { 188 printf("内存溢出!\n"); 189 exit(1); 190 } 191 } 192 *buffer=code; //将标号放入缓冲区 193 return(buffer); //返回缓冲区中的内容 194 } 195 196 unsigned int incode(FILE *input) //从压缩文件中读取数据 197 { 198 unsigned int ret; 199 static int ib=0; //静态变量,保存读入数据的二进制位数 200 static unsigned long ibb=0L; //静态变量,保存已读入数据的二进制位 201 while (ib <= 24) //若数据位数小于24位 202 { 203 ibb |= (unsigned long) getc(input) << (24-ib); //从文件中获取一个字节,并组合到需输出的二进制位中 204 ib += 8; 205 } 206 ret=ibb>>(32-BITS); //右移20位二进制数 (32-12) 207 ibb <<= BITS; //再左多12位 208 ib -= BITS; //减去已返回的位数 209 return(ret);//返回移位后的数据 210 } 211 int main(int argc, char *argv[]) 212 { 213 FILE *fp1,*fp2; 214 int flag=0; 215 char *op; 216 if(argc!=4) //判断传入参数的数量 217 flag=1; 218 else{ 219 op=argv[1]; 220 if ((strcmp(op,"-z")!=0) && strcmp(op,"-e")!=0) flag=1; 221 } 222 if(flag) 223 { 224 printf("使用方法:command -z/-e source dest\n"); 225 exit(1); 226 } 227 if((fp1=fopen(argv[2],"rb"))==NULL) //打开文件出错 228 { 229 printf("不能打开源文件!\n"); 230 exit(1); 231 } 232 if((fp2=fopen(argv[3],"wb"))==NULL) //创建文件出错 233 { 234 printf("不能创建目标文件!\n"); 235 exit(1); 236 } 237 if(strcmp(op,"-z")==0) 238 compress(fp1,fp2);//调用压缩函数 239 else 240 expand(fp1,fp2);//调用解压缩函数 241 fclose(fp1);//释放文件指针 242 fclose(fp2); 243 return 0; 244 }
标签:
原文地址:http://www.cnblogs.com/wozixiaoyao/p/5686024.html