www.pudn.com > 新文件夹.rar > ms-expand.c
// LZ77 compression / decompression algorithm // this is the compression Microsoft used in Windows *.HLP and *.MRB files // It is also used with Install Shield files. These files are // recognizable by the letters SZDD in the first 4 bytes. The file // names for files compressed in this way are usually the name of the // file as it would be installed but with the last character replaced // by '_' // This program is a complete hack. I am not responsible for the // algorithm code in any way. I stole the compression code from // somebody else who didn't put a blame line in the file so I've // forgotten who he was. I just adapted it to run under linux from // the command line. (D. Risacher) #define MSEXPAND #include#include #define N 4096 #define F 16 #define THRESHOLD 3 #define dad (node+1) #define lson (node+1+N) #define rson (node+1+N+N) #define root (node+1+N+N+N) #define NIL -1 #define int16 short char *buffer; int16 *node; int16 pos; #include #include int main (int argc, char**argv) { FILE *fin, *fout; if (argc != 3) { fprintf(stderr, "%s: file-to-expand destination\n"); fprintf(stderr, "WARNING: this program is a complete hack.\n"); exit(1); } fin = fopen(argv[1],"r"); fout = fopen(argv[2],"w"); expand(fin, fout); } int16 filelength(int16 f) { struct stat buf; fstat(f, &buf); return buf.st_size; } #define min(x,y) (x>y?y:x) int16 insert(int16 i,int16 run) { int16 c,j,k,l,n,match; int16 *p; k=l=1; match=THRESHOLD-1; p=&root[(unsigned char)buffer[i]]; lson[i]=rson[i]=NIL; while((j=*p)!=NIL) { for(n=min(k,l);n match) { match=n; pos=j; } if(c<0) { p=&lson[j]; k=n; } else if(c>0) { p=&rson[j]; l=n; } else { dad[j]=NIL; dad[lson[j]]=lson+i-node; dad[rson[j]]=rson+i-node; lson[i]=lson[j]; rson[i]=rson[j]; break; } } dad[i]=p-node; *p=i; return match; } void delete(int16 z) { int16 j; if(dad[z]!=NIL) { if(rson[z]==NIL) { j=lson[z]; } else if(lson[z]==NIL) { j=rson[z]; } else { j=lson[z]; if(rson[j]!=NIL) { do { j=rson[j]; } while(rson[j]!=NIL); node[dad[j]]=lson[j]; dad[lson[j]]=dad[j]; lson[j]=lson[z]; dad[lson[z]]=lson+j-node; } rson[j]=rson[z]; dad[rson[z]]=rson+j-node; } dad[j]=dad[z]; node[dad[z]]=j; dad[z]=NIL; } } struct header_struct { long magic, magic2; int16 magic3; long filesize; } __attribute__ ((packed)); void compress(FILE *f,FILE *out) { int16 ch,i,run,len,match,size,mask; char buf[17]; buffer=malloc(N+F+(N+1+N+N+256)*sizeof(int16)); // 28.5 k ! if(buffer) { #ifdef MSEXPAND struct header_struct header; header.magic=0x44445A53L; // SZDD header.magic2=0x3327F088L; header.magic3=0x0041; header.filesize=filelength(fileno(f)); fwrite(&header,sizeof(header),1,out); #endif node=(int16 *)(buffer+N+F); for(i=0;i<256;i++) root[i]=NIL; for(i=NIL;i =N-F) { delete(i+F-N); buffer[i+F]=buffer[i+F-N]=ch; } else { delete(i+F); buffer[i+F]=ch; } match=insert(i,run); if(ch==-1) { run--; len--; } if(len++>=run) { if(match>=THRESHOLD) { #ifdef MSEXPAND buf[size++]=pos; buf[size++]=((pos>>4)&0xF0)+(match-3); #else buf[0]|=mask; *(int16 *)(buf+size)=((match-3)<<12)|((i-pos-1)&(N-1)); size+=2; #endif len-=match; } else { #ifdef MSEXPAND buf[0]|=mask; #endif buf[size++]=buffer[i]; len--; } if(!((mask+=mask)&0xFF)) { fwrite(buf,size,1,out); size=mask=1; buf[0]=0; } } i=(i+1)&(N-1); } while(len>0); if(size>1) fwrite(buf,size,1,out); free(buffer); } } void expand(FILE *f,FILE *out) { int16 bits,ch,i,j,len,mask; char *buffer; #ifdef MSEXPAND struct header_struct header; i=fread(&header,1,sizeof(header),f); if(i!=sizeof(header)||header.magic!=0x44445A53L||header.magic2!=0x3327F088L||header.magic3!=0x0041) { fwrite(&header,1,i,out); while((ch=getc(f))!=-1) putc(ch,out); return; } #endif buffer=malloc(N); if(buffer) { i=N-F; while((bits=getc(f))!=-1) { for(mask=0x01;mask&0xFF;mask<<=1) { #ifdef MSEXPAND if(!(bits&mask)) { j=getc(f); if(j==-1) break; len=getc(f); j+=(len&0xF0)<<4; len=(len&15)+3; #else if(bits&mask) { j=getw(f); len=((j>>12)&15)+3; j=(i-j-1)&(N-1); #endif while(len--) { putc(buffer[i]=buffer[j],out); j=(j+1)&(N-1); i=(i+1)&(N-1); } } else { ch=getc(f); #ifndef MSEXPAND if(ch==-1) break; #endif putc(buffer[i]=ch,out); i=(i+1)&(N-1); } } } free(buffer); } }