/// <summary> /// Apply a patch to an existing file, and create a new file applies a single patch to one file; if the oldfile does not have the expected checksum: if there is already a file with the additional extension .orig, then this is compared with /// the md5sum of the new file also the old file is compared with the md5sum of the new file. if the file is already there, it is copied to ANewFile generally: oldfile is not touched, and there is always a newfile created, either copied /// or patched. the orig file is left untouched /// </summary> public Boolean ApplyPatch(String AOldFile, String ANewFile, String APatchFile) { TPatchFileInfo patchFileInfo = null; BZip2InputStream bzCtrl = null; BZip2InputStream bzDiff = null; BZip2InputStream bzExtra = null; FileStream fsCtrl; FileStream fsDiff; FileStream fsExtra; FileStream fsOld; FileStream fsNew; BinaryReader brOld; BinaryWriter bwNew; Int32 oldsize; FileVersionInfo ver; Int32 i; Int32 oldpos; Int32 newpos; Int32 lenread; byte[] buf = new byte[9]; if (AOldFile.Equals(ANewFile) == true) { throw new Exception("OldFileName name must be different from NewFileName"); } ReadHeader(APatchFile, out patchFileInfo); if ((!CheckMd5Sum(AOldFile, patchFileInfo.OldMd5sum))) { // see if there is a file with extension .orig // we might have given the patched file already, and moved the original file to .orig if (System.IO.File.Exists(AOldFile + ".orig") && CheckMd5Sum(AOldFile + ".orig", patchFileInfo.OldMd5sum)) { System.IO.File.Copy(AOldFile + ".orig", AOldFile, true); } else if (System.IO.File.Exists(AOldFile + ".orig") && CheckMd5Sum(AOldFile + ".orig", patchFileInfo.NewMd5sum)) { System.IO.File.Copy(AOldFile + ".orig", ANewFile, true); } else if (CheckMd5Sum(AOldFile, patchFileInfo.NewMd5sum)) { // the new file is already there System.IO.File.Copy(AOldFile, ANewFile, true); return(true); } else { throw new Exception("different base file, md5sum does not match. Expected: " + patchFileInfo.OldMd5sum); } } ver = FileVersionInfo.GetVersionInfo(AOldFile); if (patchFileInfo.StoredVersion.Compare(new TFileVersionInfo(ver)) != 0) { throw new Exception( "the existing file has an unexpected version number, expected " + patchFileInfo.StoredVersion.ToString() + ", but was " + ver.FileVersion); } fsCtrl = bz2read(ref bzCtrl, HEADER_SIZE, APatchFile); fsDiff = bz2read(ref bzDiff, HEADER_SIZE + patchFileInfo.bzctrllen, APatchFile); fsExtra = bz2read(ref bzExtra, HEADER_SIZE + patchFileInfo.bzctrllen + patchFileInfo.bzdatalen, APatchFile); try { fsOld = new FileStream(AOldFile, FileMode.Open); brOld = new BinaryReader(fsOld); } catch (Exception) { throw new Exception("Cannot read file " + AOldFile); } oldsize = (int)fsOld.Length; byte[] old = brOld.ReadBytes(oldsize); if (old.Length != oldsize) { throw new Exception("old file " + AOldFile + " has invalid size"); } brOld.Close(); fsOld.Close(); byte[] pNew = new byte[patchFileInfo.newsize + 1]; Int32[] ctrl = new Int32[3]; oldpos = 0; newpos = 0; while (newpos < patchFileInfo.newsize) { for (i = 0; i <= patchFileInfo.FormatVersion; i += 1) { // we only support version 2 lenread = loopread(ref bzCtrl, ref buf, 0, 8); if (lenread < 8) { throw new Exception("Corrupt patch (4)"); } ctrl[i] = (Int32)offtin(buf, 0); } if (newpos + ctrl[0] > patchFileInfo.newsize) { throw new Exception("Corrupt patch (5)"); } lenread = loopread(ref bzDiff, ref pNew, newpos, ctrl[0]); if ((lenread < 0) || (lenread != ctrl[0])) { throw new Exception("Corrupt patch (6)"); } for (i = 0; i < ctrl[0]; i++) { if ((oldpos + i >= 0) && (oldpos + i < oldsize)) { pNew[newpos + i] = (byte)(((Int32)pNew[newpos + i] + (Int32)old[oldpos + i]) % 256); } } newpos = newpos + ctrl[0]; oldpos = oldpos + ctrl[0]; if (patchFileInfo.FormatVersion == 2) { if (newpos + ctrl[1] > patchFileInfo.newsize) { throw new Exception("Corrupt patch (7)"); } lenread = loopread(ref bzExtra, ref pNew, newpos, ctrl[1]); if ((lenread < 0) || (lenread != ctrl[1])) { throw new Exception("Corrupt patch (8)"); } newpos = newpos + ctrl[1]; oldpos = oldpos + ctrl[2]; } } // make sure there is nothing left to read if ((loopread(ref bzCtrl, ref buf, 0, 1) != 0) || (loopread(ref bzDiff, ref buf, 0, 1) != 0) || (loopread(ref bzExtra, ref buf, 0, 1) != 0)) { throw new Exception("Corrupt patch (9)"); } bzCtrl.Close(); bzDiff.Close(); bzExtra.Close(); fsCtrl.Close(); fsDiff.Close(); fsExtra.Close(); fsNew = new FileStream(ANewFile, FileMode.Create); bwNew = new BinaryWriter(fsNew); bwNew.Write(pNew, 0, patchFileInfo.newsize); bwNew.Close(); fsNew.Close(); System.IO.File.SetLastWriteTime(ANewFile, patchFileInfo.NewFileDateTime); if ((!CheckMd5Sum(ANewFile, patchFileInfo.NewMd5sum))) { return(false); } return(true); }
/// <summary> /// called by ApplyPatch, can also be useful to analyse patch files /// </summary> public Boolean ReadHeader(String APatchFile, out TPatchFileInfo patchFileInfo) { FileStream fsHeader; BinaryReader brHeader; Int32 i; byte[] header = new byte[HEADER_SIZE]; patchFileInfo = new TPatchFileInfo(); fsHeader = new FileStream(APatchFile, FileMode.Open); brHeader = new BinaryReader(fsHeader); if ((int)fsHeader.Length < HEADER_SIZE) { throw new Exception("Corrupt patch (1)"); } // see header format in unit description header = brHeader.ReadBytes(HEADER_SIZE); brHeader.Close(); fsHeader.Close(); if (header.Length != HEADER_SIZE) { throw new Exception("Corrupt patch (2)"); } for (i = 0; i <= 7; i++) { if (header[i] != (byte)(FORMAT_DESCR)[i]) { throw new Exception("wrong version"); } } patchFileInfo.FormatVersion = 2; patchFileInfo.bzctrllen = (int)offtin(header, 8); patchFileInfo.bzdatalen = (int)offtin(header, 16); patchFileInfo.newsize = (int)offtin(header, 24); if ((patchFileInfo.bzctrllen < 0) || (patchFileInfo.bzdatalen < 0) || (patchFileInfo.newsize < 0)) { throw new Exception("Corrupt patch (3)"); } patchFileInfo.NewFileDateTime = new DateTime(offtin(header, 32)); patchFileInfo.OldMd5sum = ""; for (i = 0; i <= 31; i += 1) { patchFileInfo.OldMd5sum = patchFileInfo.OldMd5sum + Convert.ToChar(header[40 + i]); } patchFileInfo.NewMd5sum = ""; for (i = 0; i <= 31; i += 1) { patchFileInfo.NewMd5sum = patchFileInfo.NewMd5sum + Convert.ToChar(header[72 + i]); } patchFileInfo.StoredVersion = new TFileVersionInfo(); patchFileInfo.StoredVersion.FileMajorPart = (UInt16)(((UInt16)(header[104]) * 256 + header[105])); patchFileInfo.StoredVersion.FileMinorPart = (UInt16)(header[106] * 256 + header[107]); patchFileInfo.StoredVersion.FileBuildPart = (UInt16)(header[108] * 256 + header[109]); patchFileInfo.StoredVersion.FilePrivatePart = (UInt16)(header[110] * 256 + header[111]); return true; }
/// <summary> /// called by ApplyPatch, can also be useful to analyse patch files /// </summary> public Boolean ReadHeader(String APatchFile, out TPatchFileInfo patchFileInfo) { FileStream fsHeader; BinaryReader brHeader; Int32 i; byte[] header = new byte[HEADER_SIZE]; patchFileInfo = new TPatchFileInfo(); fsHeader = new FileStream(APatchFile, FileMode.Open); brHeader = new BinaryReader(fsHeader); if ((int)fsHeader.Length < HEADER_SIZE) { throw new Exception("Corrupt patch (1)"); } // see header format in unit description header = brHeader.ReadBytes(HEADER_SIZE); brHeader.Close(); fsHeader.Close(); if (header.Length != HEADER_SIZE) { throw new Exception("Corrupt patch (2)"); } for (i = 0; i <= 7; i++) { if (header[i] != (byte)(FORMAT_DESCR)[i]) { throw new Exception("wrong version"); } } patchFileInfo.FormatVersion = 2; patchFileInfo.bzctrllen = (int)offtin(header, 8); patchFileInfo.bzdatalen = (int)offtin(header, 16); patchFileInfo.newsize = (int)offtin(header, 24); if ((patchFileInfo.bzctrllen < 0) || (patchFileInfo.bzdatalen < 0) || (patchFileInfo.newsize < 0)) { throw new Exception("Corrupt patch (3)"); } patchFileInfo.NewFileDateTime = new DateTime(offtin(header, 32)); patchFileInfo.OldMd5sum = ""; for (i = 0; i <= 31; i += 1) { patchFileInfo.OldMd5sum = patchFileInfo.OldMd5sum + Convert.ToChar(header[40 + i]); } patchFileInfo.NewMd5sum = ""; for (i = 0; i <= 31; i += 1) { patchFileInfo.NewMd5sum = patchFileInfo.NewMd5sum + Convert.ToChar(header[72 + i]); } patchFileInfo.StoredVersion = new TFileVersionInfo(); patchFileInfo.StoredVersion.FileMajorPart = (UInt16)(((UInt16)(header[104]) * 256 + header[105])); patchFileInfo.StoredVersion.FileMinorPart = (UInt16)(header[106] * 256 + header[107]); patchFileInfo.StoredVersion.FileBuildPart = (UInt16)(header[108] * 256 + header[109]); patchFileInfo.StoredVersion.FilePrivatePart = (UInt16)(header[110] * 256 + header[111]); return(true); }