/*- * Copyright 2003-2005 Colin Percival * Copyright 2012 Matthew Endsley * All rights reserved * * Redistribution and use in source and binary forms, with or without * modification, are permitted providing that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "bsdiff.h" #include #include #ifndef MIN #define MIN(x,y) (((x)<(y)) ? (x) : (y)) #endif static void split(int64_t *I,int64_t *V,int64_t start,int64_t len,int64_t h) { int64_t i,j,k,x,tmp,jj,kk; if(len<16) { for(k=start;kstart) split(I,V,start,jj-start,h); for(i=0;ikk) split(I,V,kk,start+len-kk,h); } static void qsufsort(int64_t *I,int64_t *V,const uint8_t *old,int64_t oldsize) { int64_t buckets[256]; int64_t i,h,len; for(i=0;i<256;i++) buckets[i]=0; for(i=0;i0;i--) buckets[i]=buckets[i-1]; buckets[0]=0; for(i=0;iy) { *pos=I[st]; return x; } else { *pos=I[en]; return y; } }; x=st+(en-st)/2; if(memcmp(old+I[x],new,MIN(oldsize-I[x],newsize))<0) { return search(I,old,oldsize,new,newsize,x,en,pos); } else { return search(I,old,oldsize,new,newsize,st,x,pos); }; } static int64_t writedata(struct bsdiff_stream* stream, const void* buffer, int64_t length) { int64_t result = 0; while (length > 0) { const int smallsize = (int)MIN(length, INT_MAX); const int writeresult = stream->write(stream, buffer, smallsize); if (writeresult == -1) { return -1; } result += writeresult; length -= smallsize; buffer = (uint8_t*)buffer + smallsize; } return result; } struct bsdiff_request { const uint8_t* old; int64_t oldsize; const uint8_t* new; int64_t newsize; struct bsdiff_stream* stream; int64_t *I; uint8_t *buffer; }; static int bsdiff_internal(const struct bsdiff_request req) { int64_t *I,*V; int64_t scan,pos,len; int64_t lastscan,lastpos,lastoffset; int64_t oldscore,scsc; int64_t s,Sf,lenf,Sb,lenb; int64_t overlap,Ss,lens; int64_t i; uint8_t *buffer; uint8_t buf[8 * 3]; if((V=req.stream->malloc((req.oldsize+1)*sizeof(int64_t)))==NULL) return -1; I = req.I; qsufsort(I,V,req.old,req.oldsize); req.stream->free(V); buffer = req.buffer; /* Compute the differences, writing ctrl as we go */ scan=0;len=0;pos=0; lastscan=0;lastpos=0;lastoffset=0; while(scanoldscore+8)) break; if((scan+lastoffsetSf*2-lenf) { Sf=s; lenf=i; }; }; lenb=0; if(scan=lastscan+i)&&(pos>=i);i++) { if(req.old[pos-i]==req.new[scan-i]) s++; if(s*2-i>Sb*2-lenb) { Sb=s; lenb=i; }; }; }; if(lastscan+lenf>scan-lenb) { overlap=(lastscan+lenf)-(scan-lenb); s=0;Ss=0;lens=0; for(i=0;iSs) { Ss=s; lens=i+1; }; }; lenf+=lens-overlap; lenb-=lens; }; offtout(lenf,buf); offtout((scan-lenb)-(lastscan+lenf),buf+8); offtout((pos-lenb)-(lastpos+lenf),buf+16); /* Write control data */ if (writedata(req.stream, buf, sizeof(buf))) return -1; /* Write diff data */ for(i=0;imalloc((oldsize+1)*sizeof(int64_t)))==NULL) return -1; if((req.buffer= diffstream->malloc(newsize+1))==NULL) { diffstream->free(req.I); return -1; } req.old = old; req.oldsize = oldsize; req.new = newone; req.newsize = newsize; req.stream = diffstream; result = bsdiff_internal(req); diffstream->free(req.buffer); diffstream->free(req.I); return result; }