/// <summary> /// Applies a BSDIFF-format patch to an original and produces the updated version /// </summary> /// <param name="input">Readable, seekable stream of the original (older) data</param> /// <param name="openPatchStream"><see cref="OpenPatchStream"/></param> /// <param name="output">Writable stream where the updated data will be written</param> public static void Apply(Stream input, OpenPatchStream openPatchStream, Stream output) { Stream controlStream, diffStream, extraStream; var newSize = CreatePatchStreams(openPatchStream, out controlStream, out diffStream, out extraStream); // prepare to read three parts of the patch in parallel ApplyInternal(newSize, input, controlStream, diffStream, extraStream, output); }
private static long CreatePatchStreams(OpenPatchStream openPatchStream, out Stream ctrl, out Stream diff, out Stream extra) { // read header long controlLength, diffLength, newSize; using (var patchStream = openPatchStream(0, BsDiff.HeaderSize)) { // check patch stream capabilities if (!patchStream.CanRead) { throw new ArgumentException("Patch stream must be readable", nameof(openPatchStream)); } if (!patchStream.CanSeek) { throw new ArgumentException("Patch stream must be seekable", nameof(openPatchStream)); } var header = new byte[BsDiff.HeaderSize]; patchStream.Read(header, 0, BsDiff.HeaderSize); // check for appropriate magic var signature = header.ReadLong(); if (signature != BsDiff.Signature) { throw new InvalidOperationException("Corrupt patch"); } // read lengths from header controlLength = header.ReadLongAt(8); diffLength = header.ReadLongAt(16); newSize = header.ReadLongAt(24); if (controlLength < 0 || diffLength < 0 || newSize < 0) { throw new InvalidOperationException("Corrupt patch"); } } // prepare to read three parts of the patch in parallel Stream compressedControlStream = openPatchStream(BsDiff.HeaderSize, controlLength), compressedDiffStream = openPatchStream(BsDiff.HeaderSize + controlLength, diffLength), compressedExtraStream = openPatchStream(BsDiff.HeaderSize + controlLength + diffLength, 0); // decompress each part (to read it) ctrl = BsDiff.GetEncodingStream(compressedControlStream, false); diff = BsDiff.GetEncodingStream(compressedDiffStream, false); extra = BsDiff.GetEncodingStream(compressedExtraStream, false); return(newSize); }
public static void Apply(Stream input, byte[] diff, Stream output) { OpenPatchStream openPatchStream = (uOffset, uLength) => { var offset = (int)uOffset; var length = (int)uLength; return(new MemoryStream(diff, offset, uLength > 0 ? length : diff.Length - offset)); }; Stream controlStream, diffStream, extraStream; var newSize = CreatePatchStreams(openPatchStream, out controlStream, out diffStream, out extraStream); // prepare to read three parts of the patch in parallel ApplyInternal(newSize, input, controlStream, diffStream, extraStream, output); }