/* Copyright (c) 2002-2012 Croteam Ltd. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "stdh.h" #include #include #include #include #include #include #include #define DIFF_OLD 0 // copy from old file #define DIFF_NEW 1 // copy from new file #define DIFF_XOR 2 // xor between an old block and a new block UBYTE *_pubOld = NULL; SLONG _slSizeOld = 0; UBYTE *_pubNew = NULL; SLONG _slSizeNew = 0; ULONG _ulCRC; CTStream *_pstrmOut; // emit one block copied from old file void EmitOld_t(SLONG slOffsetOld, SLONG slSizeOld) { (*_pstrmOut)< _aebiOld; CStaticStackArray _aebiNew; // make array of entity offsets in a block void MakeInfos(CStaticStackArray &aebi, UBYTE *pubBlock, SLONG slSize, UBYTE *pubFirst, UBYTE *&pubEnd) { // clear all offsets aebi.PopAll(); // until end of block UBYTE *pub = pubFirst; while (pub=0) { EntityBlockInfo &ebiOld = _aebiOld[ieibOld]; // if same if ( ebiOld.ebi_slSize==ebiNew.ebi_slSize) { if (memcmp(_pubOld+ebiOld.ebi_slOffset, _pubNew+ebiNew.ebi_slOffset, ebiNew.ebi_slSize)==0) { //CPrintF("Same blocks\n"); // emit copy from old EmitOld_t(ebiOld.ebi_slOffset, ebiOld.ebi_slSize); bDone = TRUE; } else { //CPrintF("Different blocks\n"); } } else { //CPrintF("Different sizes\n"); } if (!bDone) { // emit xor EmitXor_t( ebiOld.ebi_slOffset, ebiOld.ebi_slSize, ebiNew.ebi_slOffset, ebiNew.ebi_slSize); bDone = TRUE; } } else { //CPrintF("Not found\n"); } if (!bDone) { // emit from new EmitNew_t(ebiNew.ebi_slOffset, ebiNew.ebi_slSize); bDone = TRUE; } } // emit chunk after entities by xor EmitXor_t( pubEntEndOld-_pubOld, _pubOld+_slSizeOld-pubEntEndOld, pubEntEndNew-_pubNew, _pubNew+_slSizeNew-pubEntEndNew); } void UnDiff_t(void) { // start at beginning UBYTE *pubOld = _pubOld; UBYTE *pubNew = _pubNew; SLONG slSizeOldStream = 0; SLONG slSizeOutStream = 0; // get header with size of files if (*(SLONG*)pubNew!='FFID') { ThrowF_t(TRANS("Not a DIFF stream!")); } pubNew+=sizeof(SLONG); slSizeOldStream = *(SLONG*)pubNew; pubNew+=sizeof(SLONG); slSizeOutStream = *(SLONG*)pubNew; pubNew+=sizeof(SLONG); ULONG ulCRC = *(ULONG*)pubNew; pubNew+=sizeof(ULONG); CRC_Start(_ulCRC); if (slSizeOldStream!=_slSizeOld) { ThrowF_t(TRANS("Invalid DIFF stream!")); } // while not end of diff file while (pubNew<_pubNew+_slSizeNew) { // read block type UBYTE ubType = *pubNew++; switch(ubType) { // if block type is 'copy from old file' case DIFF_OLD: { // get data offset and size SLONG slOffsetOld = *(SLONG*)pubNew; pubNew+=sizeof(SLONG); SLONG slSizeOld = *(SLONG*)pubNew; pubNew+=sizeof(SLONG); // copy it from there (*_pstrmOut).Write_t(_pubOld+slOffsetOld, slSizeOld); CRC_AddBlock(_ulCRC, _pubOld+slOffsetOld, slSizeOld); } break; // if block type is 'copy from new file' case DIFF_NEW: { // get data size SLONG slSizeNew = *(SLONG*)pubNew; pubNew+=sizeof(SLONG); // copy it from there (*_pstrmOut).Write_t(pubNew, slSizeNew); CRC_AddBlock(_ulCRC, pubNew, slSizeNew); pubNew+=slSizeNew; } break; // if block type is 'xor between an old block and a new block' case DIFF_XOR: { // get data offset and sizes SLONG slOffsetOld = *(SLONG*)pubNew; pubNew+=sizeof(SLONG); SLONG slSizeOld = *(SLONG*)pubNew; pubNew+=sizeof(SLONG); SLONG slSizeNew = *(SLONG*)pubNew; pubNew+=sizeof(SLONG); // xor it SLONG slSizeXor = Min(slSizeOld, slSizeNew); UBYTE *pub0 = _pubOld+slOffsetOld; UBYTE *pub1 = pubNew; for (INDEX i=0; iGetHighPrecisionTimer(); _slSizeOld = pstrmOld->GetStreamSize()-pstrmOld->GetPos_t(); _pubOld = (UBYTE*)AllocMemory(_slSizeOld); pstrmOld->Read_t(_pubOld, _slSizeOld); _slSizeNew = pstrmNew->GetStreamSize()-pstrmNew->GetPos_t(); _pubNew = (UBYTE*)AllocMemory(_slSizeNew); pstrmNew->Read_t(_pubNew, _slSizeNew); CRC_Start(_ulCRC); CRC_AddBlock(_ulCRC, _pubNew, _slSizeNew); CRC_Finish(_ulCRC); _pstrmOut = pstrmDiff; MakeDiff_t(); CTimerValue tv1 = _pTimer->GetHighPrecisionTimer(); //CPrintF("diff encoded in %.2gs\n", (tv1-tv0).GetSeconds()); Cleanup(); } catch (char *) { Cleanup(); throw; } } // make a new saved game from difference file and old saved game void DIFF_Undiff_t(CTStream *pstrmOld, CTStream *pstrmDiff, CTStream *pstrmNew) { try { CTimerValue tv0 = _pTimer->GetHighPrecisionTimer(); _slSizeOld = pstrmOld->GetStreamSize()-pstrmOld->GetPos_t(); _pubOld = (UBYTE*)AllocMemory(_slSizeOld); pstrmOld->Read_t(_pubOld, _slSizeOld); _slSizeNew = pstrmDiff->GetStreamSize()-pstrmDiff->GetPos_t(); _pubNew = (UBYTE*)AllocMemory(_slSizeNew); pstrmDiff->Read_t(_pubNew, _slSizeNew); _pstrmOut = pstrmNew; UnDiff_t(); CTimerValue tv1 = _pTimer->GetHighPrecisionTimer(); //CPrintF("diff decoded in %.2gs\n", (tv1-tv0).GetSeconds()); Cleanup(); } catch (char *) { Cleanup(); throw; } }