Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/VCDiff.Tests/ExternDiffTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class ExternDiffTests
[InlineData("sample.xdelta")]
[InlineData("sample_nosmallstr.xdelta")]
[InlineData("sample_appheader.xdelta")]
[InlineData("a-to-b-lzma-compression.xdelta")]

public async Task ExternTest_ImplAsync(string patchfile)
{
Expand Down Expand Up @@ -53,6 +54,7 @@ public async Task ExternTest_ImplAsync(string patchfile)
[InlineData("sample.xdelta")]
[InlineData("sample_nosmallstr.xdelta")]
[InlineData("sample_appheader.xdelta")]
[InlineData("a-to-b-lzma-compression.xdelta")]

public void ExternTest_Impl(string patchfile)
{
Expand Down
Binary file not shown.
16 changes: 16 additions & 0 deletions src/VCDiff/Compressors/ICompressor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using VCDiff.Includes;
using VCDiff.Shared;

namespace VCDiff.Compressors
{
/// <summary>
/// A compression method for secondary compression, for use when <see cref="VCDiffCodeFlags.VCDDECOMPRESS"/> is enabled in the header and the appropriate <see cref="VCDiffCompressFlags"/> flag is enabled for the section in the window.
/// </summary>
/// <remarks>
/// Implementations are stateful, and a single instance must be used for the entire file for a single operation (compression or decompression).
/// </remarks>
internal interface ICompressor
{
PinnedArrayRental Decompress(WindowSectionType windowSectionType, PinnedArrayRental sectionData);
}
}
82 changes: 82 additions & 0 deletions src/VCDiff/Compressors/XzCompressor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using SharpCompress.Compressors.Xz;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using VCDiff.Shared;

namespace VCDiff.Compressors
{
internal class XzCompressor : ICompressor, IDisposable
{
public XzCompressor()
{
addRunCompressedBuffer = new();
instructionsCompressedBuffer = new();
addressesCompressedBuffer = new();

addRunDecompressor = new(addRunCompressedBuffer);
instructionsDecompressor = new(instructionsCompressedBuffer);
addressesDecompressor = new(addressesCompressedBuffer);
}

private readonly MemoryStream addRunCompressedBuffer;
private readonly MemoryStream instructionsCompressedBuffer;
private readonly MemoryStream addressesCompressedBuffer;
private readonly XZStream addRunDecompressor;
private readonly XZStream instructionsDecompressor;
private readonly XZStream addressesDecompressor;

public PinnedArrayRental Decompress(WindowSectionType windowSectionType, PinnedArrayRental sectionData)
{
if (sectionData.Data == null)
{
throw new ArgumentException("Cannot decompress null data");
}

MemoryStream memoryStream;
XZStream xzStream;
switch (windowSectionType)
{
case WindowSectionType.AddRunData:
memoryStream = addRunCompressedBuffer;
xzStream = addRunDecompressor;
break;
case WindowSectionType.InstructionsAndSizes:
memoryStream = instructionsCompressedBuffer;
xzStream = instructionsDecompressor;
break;
case WindowSectionType.AddressForCopy:
memoryStream = addressesCompressedBuffer;
xzStream = addressesDecompressor;
break;
default:
throw new ArgumentOutOfRangeException(nameof(windowSectionType));
}

var uncompressedLength = VarIntBE.ParseInt32(sectionData.AsSpan(), out int uncompressedLengthByteCount);
var compressedData = sectionData.AsSpan().Slice(uncompressedLengthByteCount);

// Each section in a window uses the same compression stream throughout the file
// If this is not the first window, reuse the same stream from before, just using different data
memoryStream.SetLength(compressedData.Length);
memoryStream.Position = 0;
memoryStream.Write(compressedData);
memoryStream.Position = 0;

var decompressedData = new PinnedArrayRental(uncompressedLength);
xzStream.ReadExactly(decompressedData.AsSpan());

return decompressedData;
}
public void Dispose()
{
addressesCompressedBuffer?.Dispose();
instructionsCompressedBuffer?.Dispose();
addressesCompressedBuffer?.Dispose();
addRunDecompressor?.Dispose();
instructionsDecompressor?.Dispose();
addressesDecompressor?.Dispose();
}
}
}
9 changes: 5 additions & 4 deletions src/VCDiff/Decoders/BodyDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.IO;
using VCDiff.Includes;
using VCDiff.Shared;

Expand All @@ -20,6 +19,7 @@ internal class BodyDecoder<TWindowDecoderByteBuffer, TSourceBuffer, TDeltaBuffer
private AddressCache addressCache;
private MemoryStream targetData;
private CustomCodeTableDecoder? customTable;
private readonly bool disableChecksums;

//the total bytes decoded
public long TotalBytesDecoded { get; private set; }
Expand All @@ -32,7 +32,7 @@ internal class BodyDecoder<TWindowDecoderByteBuffer, TSourceBuffer, TDeltaBuffer
/// <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)
public BodyDecoder(WindowDecoder<TWindowDecoderByteBuffer> w, TSourceBuffer source, TDeltaBuffer delta, Stream decodedTarget, CustomCodeTableDecoder? customTable = null, bool disableChecksums = false)
{
if (customTable != null)
{
Expand All @@ -48,6 +48,7 @@ public BodyDecoder(WindowDecoder<TWindowDecoderByteBuffer> w, TSourceBuffer sour
this.source = source;
this.delta = delta;
this.targetData = Pool.MemoryStreamManager.GetStream(nameof(BodyDecoder<TWindowDecoderByteBuffer, TSourceBuffer, TDeltaBuffer>), (int) w.TargetWindowLength);
this.disableChecksums = disableChecksums;
}

private VCDiffResult DecodeInterleaveCore()
Expand Down Expand Up @@ -254,7 +255,7 @@ private VCDiffResult DecodeCore()
{
uint adler = Checksum.ComputeGoogleAdler32(targetData.GetBuffer().AsSpan(0, (int)targetData.Length));

if (adler != window.Checksum)
if (adler != window.Checksum && !disableChecksums)
{
result = VCDiffResult.ERROR;
}
Expand All @@ -263,7 +264,7 @@ private VCDiffResult DecodeCore()
{
uint adler = Checksum.ComputeXdelta3Adler32(targetData.GetBuffer().AsSpan(0, (int)targetData.Length));

if (adler != window.Checksum)
if (adler != window.Checksum && !disableChecksums)
{
result = VCDiffResult.ERROR;
}
Expand Down
16 changes: 16 additions & 0 deletions src/VCDiff/Decoders/SharedDecompressors.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using SharpCompress.Compressors.Xz;
using System.IO;

namespace VCDiff.Decoders
{
internal class SharedDecompressors
{
public XZStream? AddRunDecompressor;
public XZStream? InstructionsDecompressor;
public XZStream? AddressesDecompressor;

public MemoryStream? AddRunCompressedBuffer;
public MemoryStream? InstructionsCompressedBuffer;

Check warning on line 13 in src/VCDiff/Decoders/SharedDecompressors.cs

View workflow job for this annotation

GitHub Actions / build (Release, macos-latest)

Field 'SharedDecompressors.InstructionsCompressedBuffer' is never assigned to, and will always have its default value null

Check warning on line 13 in src/VCDiff/Decoders/SharedDecompressors.cs

View workflow job for this annotation

GitHub Actions / build (Debug, macos-latest)

Field 'SharedDecompressors.InstructionsCompressedBuffer' is never assigned to, and will always have its default value null

Check warning on line 13 in src/VCDiff/Decoders/SharedDecompressors.cs

View workflow job for this annotation

GitHub Actions / build (Debug, ubuntu-latest)

Field 'SharedDecompressors.InstructionsCompressedBuffer' is never assigned to, and will always have its default value null
public MemoryStream? AddressesCompressedBuffer;
}
}
Loading
Loading