michael@0: /* vim:set ts=8 sw=8 sts=8 noet: */ michael@0: /* michael@0: bsdiff.c -- Binary patch generator. michael@0: michael@0: Copyright 2003 Colin Percival michael@0: michael@0: For the terms under which this work may be distributed, please see michael@0: the adjoining file "LICENSE". michael@0: michael@0: ChangeLog: michael@0: 2005-05-05 - Use the modified header struct from bspatch.h; use 32-bit michael@0: values throughout. michael@0: --Benjamin Smedberg michael@0: 2005-05-18 - Use the same CRC algorithm as bzip2, and leverage the CRC table michael@0: provided by libbz2. michael@0: --Darin Fisher michael@0: */ michael@0: michael@0: #include "bspatch.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #ifdef XP_WIN michael@0: #include michael@0: #include michael@0: #else michael@0: #include michael@0: #include michael@0: #define _O_BINARY 0 michael@0: #endif michael@0: michael@0: #undef MIN michael@0: #define MIN(x,y) (((x)<(y)) ? (x) : (y)) michael@0: michael@0: /*---------------------------------------------------------------------------*/ michael@0: michael@0: /* This variable lives in libbz2. It's declared in bzlib_private.h, so we just michael@0: * declare it here to avoid including that entire header file. michael@0: */ michael@0: extern unsigned int BZ2_crc32Table[256]; michael@0: michael@0: static unsigned int michael@0: crc32(const unsigned char *buf, unsigned int len) michael@0: { michael@0: unsigned int crc = 0xffffffffL; michael@0: michael@0: const unsigned char *end = buf + len; michael@0: for (; buf != end; ++buf) michael@0: crc = (crc << 8) ^ BZ2_crc32Table[(crc >> 24) ^ *buf]; michael@0: michael@0: crc = ~crc; michael@0: return crc; michael@0: } michael@0: michael@0: /*---------------------------------------------------------------------------*/ michael@0: michael@0: static void michael@0: reporterr(int e, const char *fmt, ...) michael@0: { michael@0: if (fmt) { michael@0: va_list args; michael@0: va_start(args, fmt); michael@0: vfprintf(stderr, fmt, args); michael@0: va_end(args); michael@0: } michael@0: michael@0: exit(e); michael@0: } michael@0: michael@0: static void michael@0: split(int32_t *I,int32_t *V,int32_t start,int32_t len,int32_t h) michael@0: { michael@0: int32_t i,j,k,x,tmp,jj,kk; michael@0: michael@0: if(len<16) { michael@0: for(k=start;kstart) split(I,V,start,jj-start,h); michael@0: michael@0: for(i=0;ikk) split(I,V,kk,start+len-kk,h); michael@0: } michael@0: michael@0: static void michael@0: qsufsort(int32_t *I,int32_t *V,unsigned char *old,int32_t oldsize) michael@0: { michael@0: int32_t buckets[256]; michael@0: int32_t i,h,len; michael@0: michael@0: for(i=0;i<256;i++) buckets[i]=0; michael@0: for(i=0;i0;i--) buckets[i]=buckets[i-1]; michael@0: buckets[0]=0; michael@0: michael@0: for(i=0;iy) { michael@0: *pos=I[st]; michael@0: return x; michael@0: } else { michael@0: *pos=I[en]; michael@0: return y; michael@0: } michael@0: }; michael@0: michael@0: x=st+(en-st)/2; michael@0: if(memcmp(old+I[x],newbuf,MIN(oldsize-I[x],newsize))<0) { michael@0: return search(I,old,oldsize,newbuf,newsize,x,en,pos); michael@0: } else { michael@0: return search(I,old,oldsize,newbuf,newsize,st,x,pos); michael@0: }; michael@0: } michael@0: michael@0: int main(int argc,char *argv[]) michael@0: { michael@0: int fd; michael@0: unsigned char *old,*newbuf; michael@0: int32_t oldsize,newsize; michael@0: int32_t *I,*V; michael@0: michael@0: int32_t scan,pos,len; michael@0: int32_t lastscan,lastpos,lastoffset; michael@0: int32_t oldscore,scsc; michael@0: michael@0: int32_t s,Sf,lenf,Sb,lenb; michael@0: int32_t overlap,Ss,lens; michael@0: int32_t i; michael@0: michael@0: int32_t dblen,eblen; michael@0: unsigned char *db,*eb; michael@0: michael@0: unsigned int scrc; michael@0: michael@0: MBSPatchHeader header = { michael@0: {'M','B','D','I','F','F','1','0'}, michael@0: 0, 0, 0, 0, 0, 0 michael@0: }; michael@0: michael@0: uint32_t numtriples; michael@0: michael@0: if(argc!=4) michael@0: reporterr(1,"usage: %s \n",argv[0]); michael@0: michael@0: /* Allocate oldsize+1 bytes instead of oldsize bytes to ensure michael@0: that we never try to malloc(0) and get a NULL pointer */ michael@0: if(((fd=open(argv[1],O_RDONLY|_O_BINARY,0))<0) || michael@0: ((oldsize=lseek(fd,0,SEEK_END))==-1) || michael@0: ((old=(unsigned char*) malloc(oldsize+1))==NULL) || michael@0: (lseek(fd,0,SEEK_SET)!=0) || michael@0: (read(fd,old,oldsize)!=oldsize) || michael@0: (close(fd)==-1)) michael@0: reporterr(1,"%s\n",argv[1]); michael@0: michael@0: scrc = crc32(old, oldsize); michael@0: michael@0: if(((I=(int32_t*) malloc((oldsize+1)*sizeof(int32_t)))==NULL) || michael@0: ((V=(int32_t*) malloc((oldsize+1)*sizeof(int32_t)))==NULL)) michael@0: reporterr(1,NULL); michael@0: michael@0: qsufsort(I,V,old,oldsize); michael@0: michael@0: free(V); michael@0: michael@0: /* Allocate newsize+1 bytes instead of newsize bytes to ensure michael@0: that we never try to malloc(0) and get a NULL pointer */ michael@0: if(((fd=open(argv[2],O_RDONLY|_O_BINARY,0))<0) || michael@0: ((newsize=lseek(fd,0,SEEK_END))==-1) || michael@0: ((newbuf=(unsigned char*) malloc(newsize+1))==NULL) || michael@0: (lseek(fd,0,SEEK_SET)!=0) || michael@0: (read(fd,newbuf,newsize)!=newsize) || michael@0: (close(fd)==-1)) reporterr(1,"%s\n",argv[2]); michael@0: michael@0: if(((db=(unsigned char*) malloc(newsize+1))==NULL) || michael@0: ((eb=(unsigned char*) malloc(newsize+1))==NULL)) michael@0: reporterr(1,NULL); michael@0: michael@0: dblen=0; michael@0: eblen=0; michael@0: michael@0: if((fd=open(argv[3],O_CREAT|O_TRUNC|O_WRONLY|_O_BINARY,0666))<0) michael@0: reporterr(1,"%s\n",argv[3]); michael@0: michael@0: /* start writing here */ michael@0: michael@0: /* We don't know the lengths yet, so we will write the header again michael@0: at the end */ michael@0: michael@0: if(write(fd,&header,sizeof(MBSPatchHeader))!=sizeof(MBSPatchHeader)) michael@0: reporterr(1,"%s\n",argv[3]); michael@0: michael@0: scan=0;len=0; michael@0: lastscan=0;lastpos=0;lastoffset=0; michael@0: numtriples = 0; michael@0: while(scanoldscore+8)) break; michael@0: michael@0: if((scan+lastoffsetSf*2-lenf) { Sf=s; lenf=i; }; michael@0: }; michael@0: michael@0: lenb=0; michael@0: if(scan=lastscan+i)&&(pos>=i);i++) { michael@0: if(old[pos-i]==newbuf[scan-i]) s++; michael@0: if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; }; michael@0: }; michael@0: }; michael@0: michael@0: if(lastscan+lenf>scan-lenb) { michael@0: overlap=(lastscan+lenf)-(scan-lenb); michael@0: s=0;Ss=0;lens=0; michael@0: for(i=0;iSs) { Ss=s; lens=i+1; }; michael@0: }; michael@0: michael@0: lenf+=lens-overlap; michael@0: lenb-=lens; michael@0: }; michael@0: michael@0: for(i=0;i