/// <summary> /// Writes the patched file into the output stream asynchronously. /// This method is only asynchronous for the final step of writing the patched data into the output stream. /// For large outputs, this may be beneficial. /// </summary> /// <returns></returns> public async Task <(VCDiffResult result, long bytesWritten)> DecodeAsync() { if (!Decode_Init(out var bytesWritten, out var result, out var decodeAsync)) { return(decodeAsync); } while (delta.CanRead) { //delta is streamed in order aka not random access using var w = new WindowDecoder <TDeltaBuffer>(source.Length, delta, maxTargetFileSize); if (w.Decode(this.IsSDCHFormat)) { using var body = new BodyDecoder <TDeltaBuffer, TSourceBuffer, TDeltaBuffer>(w, source, delta, outputStream); if (this.IsSDCHFormat && w.AddRunLength == 0 && w.AddressesForCopyLength == 0 && w.InstructionAndSizesLength > 0) { //interleaved //decodedinterleave actually has an internal loop for waiting and streaming the incoming rest of the interleaved window result = await body.DecodeInterleaveAsync(); if (result != VCDiffResult.SUCCESS && result != VCDiffResult.EOD) { return(result, bytesWritten); } bytesWritten += body.TotalBytesDecoded; } //technically add could be 0 if it is all copy instructions //so do an or check on those two else if (!this.IsSDCHFormat || (this.IsSDCHFormat && (w.AddRunLength > 0 || w.AddressesForCopyLength > 0) && w.InstructionAndSizesLength > 0)) { //not interleaved //expects the full window to be available //in the stream result = await body.DecodeAsync(); if (result != VCDiffResult.SUCCESS) { return(result, bytesWritten); } bytesWritten += body.TotalBytesDecoded; } else { //invalid file return(VCDiffResult.ERROR, bytesWritten); } } else { return((VCDiffResult)w.Result, bytesWritten); } } return(result, bytesWritten); }
/// <summary> /// The main decoder loop for the data /// </summary> /// <param name="w">the window decoder</param> /// <param name="source">The source dictionary data</param> /// <param name="delta">The delta</param> /// <param name="decodedTarget">the out stream</param> /// <param name="customTable">custom table if any. Default is null.</param> public BodyDecoder(WindowDecoder w, IByteBuffer source, IByteBuffer delta, Stream decodedTarget, CustomCodeTableDecoder?customTable = null) { if (customTable != null) { this.customTable = customTable; addressCache = new AddressCache(customTable.NearSize, customTable.SameSize); } else { addressCache = new AddressCache(); } window = w; this.outputStream = decodedTarget; this.source = source; this.delta = delta; this.targetData = new MemoryStream(); }
/// <summary> /// The main decoder loop for the data /// </summary> /// <param name="w">the window decoder</param> /// <param name="dictionary">the dictionary data</param> /// <param name="target">the target data</param> /// <param name="sout">the out stream</param> /// <param name="customTable">custom table if any. Default is null.</param> public BodyDecoder(WindowDecoder w, IByteBuffer dictionary, IByteBuffer target, ByteStreamWriter sout, CustomCodeTableDecoder customTable = null) { if (customTable != null) { this.customTable = customTable; addressCache = new AddressCache((byte)customTable.NearSize, (byte)customTable.SameSize); } else { addressCache = new AddressCache(); } window = w; this.sout = sout; this.dict = dictionary; this.target = target; targetData = new List <byte>(); }
/// <summary> /// The main decoder loop for the data /// </summary> /// <param name="w">the window decoder</param> /// <param name="source">The source dictionary data</param> /// <param name="delta">The delta</param> /// <param name="decodedTarget">the out stream</param> /// <param name="customTable">custom table if any. Default is null.</param> public BodyDecoder(WindowDecoder <TWindowDecoderByteBuffer> w, TSourceBuffer source, TDeltaBuffer delta, Stream decodedTarget, CustomCodeTableDecoder?customTable = null) { if (customTable != null) { this.customTable = customTable; addressCache = new AddressCache(customTable.NearSize, customTable.SameSize); } else { addressCache = new AddressCache(); } window = w; this.outputStream = decodedTarget; this.source = source; this.delta = delta; this.targetData = Pool.MemoryStreamManager.GetStream(nameof(BodyDecoder <TWindowDecoderByteBuffer, TSourceBuffer, TDeltaBuffer>), (int)w.TargetWindowLength); }
/// <summary> /// Use this after calling Start /// Each time the decode is called it is expected /// that at least 1 Window header is available in the stream /// </summary> /// <param name="bytesWritten">bytes decoded for all available windows</param> /// <returns></returns> public VCDiffResult Decode(out long bytesWritten) { if (!isStarted) { bytesWritten = 0; return(VCDiffResult.ERRROR); } VCDiffResult result = VCDiffResult.SUCCESS; bytesWritten = 0; if (!delta.CanRead) { return(VCDiffResult.EOD); } while (delta.CanRead) { //delta is streamed in order aka not random access WindowDecoder w = new WindowDecoder(dict.Length, delta); if (w.Decode(googleVersion)) { using (BodyDecoder body = new BodyDecoder(w, dict, delta, sout)) { if (googleVersion && w.AddRunLength == 0 && w.AddressesForCopyLength == 0 && w.InstructionAndSizesLength > 0) { //interleaved //decodedinterleave actually has an internal loop for waiting and streaming the incoming rest of the interleaved window result = body.DecodeInterleave(); if (result != VCDiffResult.SUCCESS && result != VCDiffResult.EOD) { return(result); } bytesWritten += body.Decoded; } //technically add could be 0 if it is all copy instructions //so do an or check on those two else if (googleVersion && (w.AddRunLength > 0 || w.AddressesForCopyLength > 0) && w.InstructionAndSizesLength > 0) { //not interleaved //expects the full window to be available //in the stream result = body.Decode(); if (result != VCDiffResult.SUCCESS) { return(result); } bytesWritten += body.Decoded; } else if (!googleVersion) { //not interleaved //expects the full window to be available //in the stream result = body.Decode(); if (result != VCDiffResult.SUCCESS) { return(result); } bytesWritten += body.Decoded; } else { //invalid file return(VCDiffResult.ERRROR); } } } else { return((VCDiffResult)w.Result); } } return(result); }
/// <summary> /// Writes the patched file into the output stream. /// </summary> /// <param name="bytesWritten">Number of bytes written into the output stream.</param> /// <returns></returns> public VCDiffResult Decode(out long bytesWritten) { if (!this.IsInitialized) { var initializeResult = this.Initialize(); if (initializeResult != VCDiffResult.SUCCESS || !this.IsInitialized) { bytesWritten = 0; return initializeResult; } } VCDiffResult result = VCDiffResult.SUCCESS; bytesWritten = 0; if (!delta.CanRead) return VCDiffResult.EOD; while (delta.CanRead) { //delta is streamed in order aka not random access WindowDecoder w = new WindowDecoder(source.Length, delta); if (w.Decode(this.IsSDCHFormat)) { using BodyDecoder body = new BodyDecoder(w, source, delta, outputStream); if (this.IsSDCHFormat && w.AddRunLength == 0 && w.AddressesForCopyLength == 0 && w.InstructionAndSizesLength > 0) { //interleaved //decodedinterleave actually has an internal loop for waiting and streaming the incoming rest of the interleaved window result = body.DecodeInterleave(); if (result != VCDiffResult.SUCCESS && result != VCDiffResult.EOD) { return result; } bytesWritten += body.TotalBytesDecoded; } //technically add could be 0 if it is all copy instructions //so do an or check on those two else if (!this.IsSDCHFormat || (this.IsSDCHFormat && (w.AddRunLength > 0 || w.AddressesForCopyLength > 0) && w.InstructionAndSizesLength > 0)) { //not interleaved //expects the full window to be available //in the stream result = body.Decode(); if (result != VCDiffResult.SUCCESS) { return result; } bytesWritten += body.TotalBytesDecoded; } else { //invalid file return VCDiffResult.ERROR; } } else { return (VCDiffResult)w.Result; } } return result; }