/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . You can contact Cyan Worlds, Inc. by email legal@cyan.com or by snail mail at: Cyan Worlds, Inc. 14617 N Newport Hwy Mead, WA 99021 *==LICENSE==*/ ////////////////////////////////////////////////////////////////////////////// // // plBSDiffBuffer - A utility class for writing and applying a difference // buffer--i.e. a buffer containing a series of modifications // that will modify an old data buffer to match a new one. // It's a useful utility class when doing binary file // patching, for example, as you can write out the changes // to this class, get back a data buffer suitable for writing, // then use this class again later to reconstruct the new buffer. // ////////////////////////////////////////////////////////////////////////////// #include "hsTypes.h" #include "plBSDiffBuffer.h" #include "hsUtils.h" #include "hsStream.h" #define plBSDiffBuffer_MIN(x,y) (((x)<(y)) ? (x) : (y)) ////////////////////////////////////////////////////////////////////////////// //// Constructor/Destructors ///////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //// Creation Constructor //////////////////////////////////////////////////// // Use this constructor when creating a new diff buffer. Pass in the length // of the final new buffer. You don't need to pass in the length of the old // buffer, but if you do, it'll help this class do some internal space // optimization. plBSDiffBuffer::plBSDiffBuffer( UInt32 newLength, UInt32 oldLength ) : fNewLength( newLength ) , fPatchLength( 0 ) { fPatchBuffer = nil; fWriting = true; } //// Application Constructor ///////////////////////////////////////////////// // Use this constructor when taking a diff buffer and applying it to an old // buffer. Pass in a pointer to the diff buffer and its length. The buffer // will be copied, so you don't need to keep it around after you construct // this object. plBSDiffBuffer::plBSDiffBuffer( void *buffer, UInt32 length ) : fNewLength( 0 ) , fPatchLength( 0 ) , fPatchBuffer( nil ) , fWriting( false ) { if (!buffer || length < 32) hsAssert(false, "Corrupt Patch Buffer!"); if((fPatchBuffer=TRACKED_NEW unsigned char[length+1])!=nil) { fPatchLength = length; memcpy(fPatchBuffer, buffer, fPatchLength); } } plBSDiffBuffer::~plBSDiffBuffer() { if ( fPatchBuffer ) delete[] fPatchBuffer; } ////////////////////////////////////////////////////////////////////////////// //// Creation/Write Functions //////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //// Diff ///////////////////////////////////////////////////////////////////// // Diff() creates the diff buffer from the new and old. UInt32 plBSDiffBuffer::Diff( UInt32 oldLength, void *oldBuffer, UInt32 newLength, void *newBuffer ) { hsAssert( fWriting, "Trying to Add() to a difference buffer that's reading" ); Int32 *I,*V; Int32 scan,pos,len; Int32 lastscan,lastpos,lastoffset; Int32 oldscore,scsc; Int32 s,Sf,lenf,Sb,lenb; Int32 overlap,Ss,lens; Int32 i; UInt32 cblen,dblen,eblen; unsigned char *oldbuf, *newbuf; unsigned char *cb,*db,*eb; unsigned char header[32]; if (oldBuffer == nil || oldLength < 0 || newBuffer == nil || newLength < 0) { return (-1); } oldbuf = (unsigned char *)oldBuffer; newbuf = (unsigned char *)newBuffer; if(((I=TRACKED_NEW Int32[oldLength+1])==nil) || ((V=TRACKED_NEW Int32[oldLength+1])==nil)) { delete[] I; delete[] V; return fPatchLength; } IQSuffixSort(I,V,oldbuf,oldLength); delete[] V; /* * These could probably be smaller, especially cb. */ if(((cb=TRACKED_NEW unsigned char[newLength+1])==nil) || ((db=TRACKED_NEW unsigned char[newLength+1])==nil) || ((eb=TRACKED_NEW unsigned char[newLength+1])==nil)) { delete[] I; delete[] cb; delete[] db; delete[] eb; return fPatchLength; } cblen=0; dblen=0; eblen=0; /* Header is 0 8 "BSDIFF40" 8 8 length of bzip2ed ctrl block 16 8 length of bzip2ed diff block 24 8 length of new file */ /* File is 0 32 Header 32 ?? Bzip2ed ctrl block ?? ?? Bzip2ed diff block ?? ?? Bzip2ed extra block */ memcpy(header,"BSDIFF40",8); memset(header+8,0,24); scan=0;len=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(oldbuf[pos-i]==newbuf[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; }; for(i=0;istart) ISplit(I,V,start,jj-start,h); for(i=0;ikk) ISplit(I,V,kk,start+len-kk,h); } void plBSDiffBuffer::IQSuffixSort(Int32 *I,Int32 *V,unsigned char *old,UInt32 oldsize) { UInt32 buckets[256]; UInt32 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(oldBuffer+I[x],newBuffer,plBSDiffBuffer_MIN(oldLength-I[x],newLength))<0) { return ISearch(I,oldBuffer,oldLength,newBuffer,newLength,x,en,pos); } else { return ISearch(I,oldBuffer,oldLength,newBuffer,newLength,st,x,pos); }; }