From 17789bde16e1a95d837971af0bc734103bf797bc Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 9 Aug 2026 00:55:17 +0700 Subject: [PATCH 01/72] Implement Header Reader API --- .../Extension/ExceptionHelper.cs | 73 + SharpHDiffPatch.New/Extension/MemoryAlloc.cs | 103 ++ .../Extension/MetadataExtension.cs | 61 + .../Extension/StreamExtension.cs | 311 ++++ .../Extension/StringExtension.cs | 101 ++ SharpHDiffPatch.New/HPatch.cs | 42 + SharpHDiffPatch.New/HPatchContext.cs | 13 + SharpHDiffPatch.New/Header/HDiffChecksum.cs | 8 + .../Header/HDiffCompression.cs | 15 + SharpHDiffPatch.New/Header/HDiffInfo.cs | 40 + SharpHDiffPatch.New/Header/HDiffMagic.cs | 8 + SharpHDiffPatch.New/Header/HeaderReader.cs | 449 ++++++ .../Header/Metadata/ChecksumDataInfo.cs | 69 + .../Header/Metadata/ChunkSizeInfo.cs | 10 + .../Header/Metadata/EntryCountSizeInfo.cs | 10 + .../Header/Metadata/ExternSizeInfo.cs | 12 + .../Header/Metadata/FileIndexPair.cs | 12 + .../Metadata/HeaderDirectoryPatchMetadata.cs | 103 ++ .../Header/Metadata/IMetadataInit.cs | 12 + .../Header/Metadata/MetadataTypeConst.cs | 15 + .../Header/Metadata/PatchMetadata.cs | 75 + .../Header/Metadata/UnmanagedArray.cs | 124 ++ .../Header/Metadata/Utf16UnmanagedString.cs | 91 ++ .../IO/Compression/BZip2/BZip2Constants.cs | 159 ++ .../IO/Compression/BZip2/BZip2Crc32.cs | 421 ++++++ .../IO/Compression/BZip2/BZip2Exception.cs | 54 + .../IO/Compression/BZip2/BZip2InputStream.cs | 1321 +++++++++++++++++ .../IO/Compression/BZip2/LICENSE | 17 + .../IO/Compression/BZip2/README.md | 23 + .../IO/Compression/CompressionStreamHelper.cs | 102 ++ .../IO/Compression/Lzma/LICENSE.txt | 21 + .../IO/Compression/Lzma/LZ/LzOutWindow.cs | 268 ++++ .../IO/Compression/Lzma/LzmaBase.cs | 70 + .../IO/Compression/Lzma/LzmaDecoder.cs | 459 ++++++ .../IO/Compression/Lzma/LzmaExceptions.cs | 13 + .../IO/Compression/Lzma/LzmaInputStream.cs | 287 ++++ .../IO/Compression/Lzma/README.md | 18 + .../Compression/Lzma/RangeCoder/RangeCoder.cs | 135 ++ .../Lzma/RangeCoder/RangeCoderBit.cs | 55 + .../Lzma/RangeCoder/RangeCoderBitTree.cs | 60 + .../IO/Reader/BittableStreamReader.cs | 621 ++++++++ .../CompilerFeatureRequiredAttribute.cs | 28 + .../IsExternalInit.cs | 6 + .../RequiredMemberAttribute.cs | 9 + .../SharpHDiffPatch.New.csproj | 54 + SharpHDiffPatch.sln | 18 + 46 files changed, 5976 insertions(+) create mode 100644 SharpHDiffPatch.New/Extension/ExceptionHelper.cs create mode 100644 SharpHDiffPatch.New/Extension/MemoryAlloc.cs create mode 100644 SharpHDiffPatch.New/Extension/MetadataExtension.cs create mode 100644 SharpHDiffPatch.New/Extension/StreamExtension.cs create mode 100644 SharpHDiffPatch.New/Extension/StringExtension.cs create mode 100644 SharpHDiffPatch.New/HPatch.cs create mode 100644 SharpHDiffPatch.New/HPatchContext.cs create mode 100644 SharpHDiffPatch.New/Header/HDiffChecksum.cs create mode 100644 SharpHDiffPatch.New/Header/HDiffCompression.cs create mode 100644 SharpHDiffPatch.New/Header/HDiffInfo.cs create mode 100644 SharpHDiffPatch.New/Header/HDiffMagic.cs create mode 100644 SharpHDiffPatch.New/Header/HeaderReader.cs create mode 100644 SharpHDiffPatch.New/Header/Metadata/ChecksumDataInfo.cs create mode 100644 SharpHDiffPatch.New/Header/Metadata/ChunkSizeInfo.cs create mode 100644 SharpHDiffPatch.New/Header/Metadata/EntryCountSizeInfo.cs create mode 100644 SharpHDiffPatch.New/Header/Metadata/ExternSizeInfo.cs create mode 100644 SharpHDiffPatch.New/Header/Metadata/FileIndexPair.cs create mode 100644 SharpHDiffPatch.New/Header/Metadata/HeaderDirectoryPatchMetadata.cs create mode 100644 SharpHDiffPatch.New/Header/Metadata/IMetadataInit.cs create mode 100644 SharpHDiffPatch.New/Header/Metadata/MetadataTypeConst.cs create mode 100644 SharpHDiffPatch.New/Header/Metadata/PatchMetadata.cs create mode 100644 SharpHDiffPatch.New/Header/Metadata/UnmanagedArray.cs create mode 100644 SharpHDiffPatch.New/Header/Metadata/Utf16UnmanagedString.cs create mode 100644 SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Constants.cs create mode 100644 SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Crc32.cs create mode 100644 SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Exception.cs create mode 100644 SharpHDiffPatch.New/IO/Compression/BZip2/BZip2InputStream.cs create mode 100644 SharpHDiffPatch.New/IO/Compression/BZip2/LICENSE create mode 100644 SharpHDiffPatch.New/IO/Compression/BZip2/README.md create mode 100644 SharpHDiffPatch.New/IO/Compression/CompressionStreamHelper.cs create mode 100644 SharpHDiffPatch.New/IO/Compression/Lzma/LICENSE.txt create mode 100644 SharpHDiffPatch.New/IO/Compression/Lzma/LZ/LzOutWindow.cs create mode 100644 SharpHDiffPatch.New/IO/Compression/Lzma/LzmaBase.cs create mode 100644 SharpHDiffPatch.New/IO/Compression/Lzma/LzmaDecoder.cs create mode 100644 SharpHDiffPatch.New/IO/Compression/Lzma/LzmaExceptions.cs create mode 100644 SharpHDiffPatch.New/IO/Compression/Lzma/LzmaInputStream.cs create mode 100644 SharpHDiffPatch.New/IO/Compression/Lzma/README.md create mode 100644 SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoder.cs create mode 100644 SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs create mode 100644 SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs create mode 100644 SharpHDiffPatch.New/IO/Reader/BittableStreamReader.cs create mode 100644 SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/CompilerFeatureRequiredAttribute.cs create mode 100644 SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/IsExternalInit.cs create mode 100644 SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/RequiredMemberAttribute.cs create mode 100644 SharpHDiffPatch.New/SharpHDiffPatch.New.csproj diff --git a/SharpHDiffPatch.New/Extension/ExceptionHelper.cs b/SharpHDiffPatch.New/Extension/ExceptionHelper.cs new file mode 100644 index 0000000..5e19ea9 --- /dev/null +++ b/SharpHDiffPatch.New/Extension/ExceptionHelper.cs @@ -0,0 +1,73 @@ +using System; +#if NET8_0_OR_GREATER +using System.Collections.Generic; +#endif + +namespace SharpHDiffPatch.New.Extension; + +file static class Const +{ +#if NET8_0_OR_GREATER + internal static readonly Dictionary ExceptionToReturnCodeMap = new() + { + { HDiffHeaderSignatureEmptyOrUnreadable, 0b_00000000_00000000_00000000_00000010 }, + { HDiffHeaderMagicNotSupported, 0b_00000000_00000000_00000000_00000100 }, + { HDiffHeaderCompressionNotSupported, 0b_00000000_00000000_00000000_00001000 }, + { HDiffHeaderChecksumNotSupported, 0b_00000000_00000000_00000000_00010000 } + }; +#endif + + public const string HDiffHeaderSignatureEmptyOrUnreadable = "HDIFF_HeaderSignatureEmptyOrUnreadable"; + public const string HDiffHeaderMagicNotSupported = "HDIFF_HeaderMagicNotSupported"; + public const string HDiffHeaderCompressionNotSupported = "HDIFF_HeaderCompressionNotSupported"; + public const string HDiffHeaderChecksumNotSupported = "HDIFF_HeaderChecksumNotSupported"; +} + +public static class ExceptionHelper +{ + public static void ThrowHDiffHeaderSignatureEmptyOrUnreadable() + => throw new InvalidOperationException($"[{Const.HDiffHeaderSignatureEmptyOrUnreadable}] Header signature is empty or unreadable!"); + public static void ThrowHdiffHeaderMagicNotSupported(ReadOnlySpan magic) + => throw new NotSupportedException($"[{Const.HDiffHeaderMagicNotSupported}] Header magic: {magic.ToString()} is not supported!"); + public static void ThrowHdiffHeaderCompressionNotSupported(ReadOnlySpan enumString) + => throw new NotSupportedException($"[{Const.HDiffHeaderCompressionNotSupported}] HDIFF compression: {enumString.ToString()} is not supported!"); + public static void ThrowHdiffHeaderChecksumNotSupported(ReadOnlySpan enumString) + => throw new NotSupportedException($"[{Const.HDiffHeaderChecksumNotSupported}] HDIFF checksum: {enumString.ToString()} is not supported!"); + +#if NET8_0_OR_GREATER + public static int TryGetReturnCodeFromError(Exception ex) + { + try + { + ReadOnlySpan message = ex.Message; + if (message.IsEmpty) + { + return -1; + } + + Span splitRanges = stackalloc Range[2]; + int splitLen = message.GetSplits(splitRanges, ' '); + + ReadOnlySpan splitFirst; + if (splitLen == 0 || + (splitFirst = message[splitRanges[0]])[0] != '[' || + splitFirst[^1] != ']') + { + return -1; + } + + splitFirst = splitFirst.Slice(1, message.Length - 2); +#if NET9_0_OR_GREATER + return Const.ExceptionToReturnCodeMap.GetAlternateLookup>() + .TryGetValue(splitFirst, out int returnCode) ? returnCode : -1; +#else + return Const.ExceptionToReturnCodeMap.GetValueOrDefault(splitFirst.ToString(), -1); +#endif + } + catch + { + return -1; + } + } +#endif +} \ No newline at end of file diff --git a/SharpHDiffPatch.New/Extension/MemoryAlloc.cs b/SharpHDiffPatch.New/Extension/MemoryAlloc.cs new file mode 100644 index 0000000..fdc2445 --- /dev/null +++ b/SharpHDiffPatch.New/Extension/MemoryAlloc.cs @@ -0,0 +1,103 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SharpHDiffPatch.New.Header.Metadata; + +#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type + +namespace SharpHDiffPatch.New.Extension; + +internal static unsafe class MemoryAlloc +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T* Alloc(int elementCount = 1, bool initializeAlloc = false) + where T : unmanaged + { + if (typeof(T) == typeof(byte)) + { + return (T*)Alloc(elementCount, initializeAlloc); + } + + return (T*)Alloc(elementCount * sizeof(T), initializeAlloc); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void* Alloc(long byteCount, bool initializeAlloc = false) + { +#if NET6_0_OR_GREATER + return initializeAlloc ? + NativeMemory.AllocZeroed((nuint)byteCount) : + NativeMemory.Alloc((nuint)byteCount); +#else + var ptr = (void*)Marshal.AllocHGlobal((nint)byteCount); + if (!initializeAlloc) return ptr; + + Zero(ptr, byteCount); + return ptr; +#endif + } + + public static T* CopyToUnmanagedUnsafe(this ref T toCopy) + where T : unmanaged + { + T* allocP = Alloc(); + ref T allocRef = ref allocP[0]; + allocRef = toCopy; + return allocP; + } + + public static nint CopyToUnmanaged(this ref T toCopy) + where T : unmanaged + => (nint)toCopy.CopyToUnmanagedUnsafe(); + + public static void Free(T* ptr) + where T : unmanaged + { + if (ptr == null) + { + return; + } + + Free((void*)ptr); + } + + public static void Free(void* ptr) + { + if (ptr == null) + { + return; + } + + ref byte asRef = ref Unsafe.AsRef(ptr); + asRef.TryDisposeIfMetadataType(); + +#if NET6_0_OR_GREATER + NativeMemory.Free(ptr); +#else + Marshal.FreeHGlobal((nint)ptr); +#endif + } + +#if !NET7_0_OR_GREATER + public static void Zero(void* ptr, long byteCount) + { + ref byte current = ref Unsafe.AsRef(ptr); + while (byteCount >= sizeof(nuint)) + { + Unsafe.As(ref current) = 0; + + current = ref Unsafe.Add(ref current, sizeof(nuint)); + byteCount -= sizeof(nuint); + } + + while (byteCount != 0) + { + current = 0; + current = ref Unsafe.Add(ref current, 1); + --byteCount; + } + } +#else + public static void Zero(void* ptr, long byteCount) + => NativeMemory.Fill(ptr, (nuint)byteCount, 0); +#endif +} diff --git a/SharpHDiffPatch.New/Extension/MetadataExtension.cs b/SharpHDiffPatch.New/Extension/MetadataExtension.cs new file mode 100644 index 0000000..7d8110d --- /dev/null +++ b/SharpHDiffPatch.New/Extension/MetadataExtension.cs @@ -0,0 +1,61 @@ +using System; +using System.Runtime.CompilerServices; +using SharpHDiffPatch.New.Header.Metadata; + +namespace SharpHDiffPatch.New.Extension; + +internal static class MetadataExtension +{ + extension(ref T metadata) where T : unmanaged + { + public bool TryGetMetadataType(out MetadataTypeConst metadataType) + { + ref MetadataTypeConst metadataTypeCopy = ref Unsafe.As(ref metadata); + metadataType = metadataTypeCopy; + + return IsTypeDefined(metadataType); + } + + public bool TryDisposeIfMetadataType() + { + if (!metadata.TryGetMetadataType(out MetadataTypeConst metadataType)) + { + return false; + } + + switch (metadataType) + { + case MetadataTypeConst.ChecksumDataInfoType: + Unsafe.As(ref metadata).Dispose(); + break; + case MetadataTypeConst.HeaderDirectoryPatchMetadataType: + Unsafe.As(ref metadata).Dispose(); + break; + case MetadataTypeConst.PatchMetadataType: + Unsafe.As(ref metadata).Dispose(); + break; + case MetadataTypeConst.UnmanagedArrayType: + Unsafe.As>(ref metadata).Dispose(); + break; + case MetadataTypeConst.Utf16UnmanagedStringType: + Unsafe.As(ref metadata).Dispose(); + break; + case MetadataTypeConst.IsMetadataType: + default: + return false; + } + + return true; + } + } + + public static bool IsTypeDefined(MetadataTypeConst metadataType) + { +#if NET6_0_OR_GREATER + return Enum.IsDefined(metadataType) +#else + return Enum.IsDefined(typeof(MetadataTypeConst), metadataType) +#endif + && metadataType.HasFlag(MetadataTypeConst.IsMetadataType); + } +} diff --git a/SharpHDiffPatch.New/Extension/StreamExtension.cs b/SharpHDiffPatch.New/Extension/StreamExtension.cs new file mode 100644 index 0000000..822d632 --- /dev/null +++ b/SharpHDiffPatch.New/Extension/StreamExtension.cs @@ -0,0 +1,311 @@ +using SharpHDiffPatch.New.Header.Metadata; +using SharpHDiffPatch.New.IO.Reader; +using System; +using System.Buffers; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices.ComTypes; +using System.Threading; +using System.Threading.Tasks; + +namespace SharpHDiffPatch.New.Extension; + +internal static class StreamExtension +{ + extension(Stream stream) + { +#if NET6_0 + public async ValueTask ReadExactlyAsync( + Memory buffer, + CancellationToken cancellationToken = default) + { + await stream.ReadAtLeastAsync(buffer, buffer.Length, true, cancellationToken); + } +#endif + + public async ValueTask ReadExactlyAsync( + byte[] buffer, + int offset, + int count, + CancellationToken cancellationToken = default) + { +#if !NET6_0_OR_GREATER + ValueTask vt = stream.ReadAtLeastAsync(buffer, offset, count, count, true, cancellationToken); + await vt; +#else + await stream.ReadAtLeastAsync(buffer.AsMemory(offset, count), count, true, cancellationToken); +#endif + } + +#if !NET6_0_OR_GREATER + public async ValueTask ReadAtLeastAsync( + byte[] buffer, + int offset, + int count, + int minimumBytes, + bool throwOnEndOfStream = false, + CancellationToken cancellationToken = default) + { + Debug.Assert(minimumBytes <= buffer.Length); + + int totalRead = offset; + while (totalRead < minimumBytes) + { + int read = await stream.ReadAsync(buffer, totalRead, count - totalRead, cancellationToken).ConfigureAwait(false); + if (read == 0) + { + return throwOnEndOfStream ? throw new EndOfStreamException() : totalRead; + } + + totalRead += read; + } + + return totalRead; + } +#else + public async ValueTask ReadAtLeastAsync( + Memory buffer, + int minimumBytes, + bool throwOnEndOfStream = false, + CancellationToken cancellationToken = default) + { + Debug.Assert(minimumBytes <= buffer.Length); + + int totalRead = 0; + while (totalRead < minimumBytes) + { + int read = await stream.ReadAsync(buffer[totalRead..], cancellationToken).ConfigureAwait(false); + if (read == 0) + { + return throwOnEndOfStream ? throw new EndOfStreamException() : totalRead; + } + + totalRead += read; + } + + return totalRead; + } +#endif + } + + extension(BittableStreamReader reader) + { + public async ValueTask CreateUnmanagedStringListAsync(int count, int bufferSize, CancellationToken token) + { + if (count == 0) + { + return 0; + } + + long readerOffset = reader.Offset; + UnmanagedArray unmanagedBuffer = UnmanagedArray.CreateAlloc(count); + + for (int i = 0; i < count; i++) + { + string readString = await reader.ReadStringToNullAsync(token); + + ref Utf16UnmanagedString current = ref unmanagedBuffer[i]; + current = Utf16UnmanagedString.CreateFromManaged(readString); + if (reader.Offset - readerOffset > bufferSize) + { + throw new IndexOutOfRangeException("Read is out of index!"); + } + } + + return unmanagedBuffer.CopyToUnmanaged(); + } + + public unsafe UnmanagedArray* CreateUnmanagedStringList(int count, int bufferSize) + { + if (count == 0) + { + return null; + } + + long readerOffset = reader.Offset; + UnmanagedArray* readOnlyArraySpan = UnmanagedArray.CreateAllocUnsafe(count); + + for (int i = 0; i < count; i++) + { + readOnlyArraySpan[0][i] = Utf16UnmanagedString.CreateFromManaged(reader.ReadStringToNull()); + if (reader.Offset - readerOffset > bufferSize) + { + throw new IndexOutOfRangeException("Read is out of index!"); + } + } + + return readOnlyArraySpan; + } + + public async ValueTask CreateUnmanagedInt64ListAsync(int count, CancellationToken token) + { + if (count == 0) + { + return 0; + } + + long[] array = ArrayPool.Shared.Rent(count); + try + { + long backNumber = -1; + for (int i = 0; i < count; i++) + { + array[i] = backNumber += 1 + await reader.ReadLong7BitAsync(token); + } + + unsafe + { + long* alloc = MemoryAlloc.Alloc(count); + array.AsSpan(0, count).CopyTo(new Span(alloc, count)); + return (nint)alloc; + } + } + finally + { + ArrayPool.Shared.Return(array); + } + } + + public unsafe long* CreateUnmanagedInt64List(int count) + { + if (count == 0) + { + return null; + } + + long* alloc = MemoryAlloc.Alloc(count); + for (int i = 0; i < count; i++) + { + alloc[i] = reader.ReadLong7Bit(); + } + + return alloc; + } + + public async ValueTask CreateUnmanagedInt64As32ListAsync(int count, CancellationToken token) + { + if (count == 0) + { + return 0; + } + + int[] array = ArrayPool.Shared.Rent(count); + try + { + long backNumber = -1; + for (int i = 0; i < count; i++) + { + array[i] = (int)(backNumber += 1 + await reader.ReadLong7BitAsync(token)); + } + + unsafe + { + int* alloc = MemoryAlloc.Alloc(count); + array.AsSpan(0, count).CopyTo(new Span(alloc, count)); + return (nint)alloc; + } + } + finally + { + ArrayPool.Shared.Return(array); + } + } + + public unsafe int* CreateUnmanagedInt64As32List(int count) + { + if (count == 0) + { + return null; + } + + int* alloc = MemoryAlloc.Alloc(count); + for (int i = 0; i < count; i++) + { + alloc[i] = (int)reader.ReadLong7Bit(); + } + + return alloc; + } + + public async ValueTask CreateUnmanagedIndexPairListAsync(int count, CancellationToken token) + { + if (count == 0) + { + return 0; + } + + FileIndexPair[] array = ArrayPool.Shared.Rent(count); + try + { + long oldIndexNumber = -1; + long newIndexNumber = -1; + for (int i = 0; i < count; i++) + { + oldIndexNumber += 1 + await reader.ReadLong7BitAsync(token); + newIndexNumber += 1 + await reader.ReadLong7BitAsync(token); + array[i] = new FileIndexPair + { + OldIndex = (int)oldIndexNumber, + NewIndex = (int)newIndexNumber + }; + } + + unsafe + { + FileIndexPair* alloc = MemoryAlloc.Alloc(count); + array.AsSpan(0, count).CopyTo(new Span(alloc, count)); + return (nint)alloc; + } + } + finally + { + ArrayPool.Shared.Return(array); + } + } + + public unsafe FileIndexPair* CreateUnmanagedIndexPairList(int count) + { + if (count == 0) + { + return null; + } + + FileIndexPair* alloc = MemoryAlloc.Alloc(count); + long oldIndexNumber = -1; + long newIndexNumber = -1; + for (int i = 0; i < count; i++) + { + alloc[i].OldIndex = (int)(oldIndexNumber += 1 + reader.ReadLong7Bit()); + alloc[i].NewIndex = (int)(newIndexNumber += 1 + reader.ReadLong7Bit()); + } + + return alloc; + } + + public async ValueTask AdvanceSeekToAsync(int advancedBytes, CancellationToken token) + { + byte[] buffer = ArrayPool.Shared.Rent(advancedBytes); + try + { + await reader.ReadBytesAsync(buffer.AsMemory(0, advancedBytes), token); + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + + public void AdvanceSeekTo(int advancedBytes) + { + byte[] buffer = ArrayPool.Shared.Rent(advancedBytes); + try + { + reader.ReadBytes(buffer.AsSpan(0, advancedBytes)); + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + } +} diff --git a/SharpHDiffPatch.New/Extension/StringExtension.cs b/SharpHDiffPatch.New/Extension/StringExtension.cs new file mode 100644 index 0000000..ea6666d --- /dev/null +++ b/SharpHDiffPatch.New/Extension/StringExtension.cs @@ -0,0 +1,101 @@ +using System; +using System.Threading.Tasks; +using SharpHDiffPatch.New.IO.Reader; + +namespace SharpHDiffPatch.New.Extension; + +internal static class StringExtension +{ + public static int GetSplits( + this ReadOnlySpan span, + Span ranges, + char separator, + StringSplitOptions splitOptions = StringSplitOptions.None) + { +#if NET8_0_OR_GREATER + return span.Split(ranges, + separator, + splitOptions); +#else + if (ranges.Length == 0) + { + return 0; + } + +#if NET6_0_OR_GREATER + bool isTrimEntries = splitOptions.HasFlag(StringSplitOptions.TrimEntries); +#else + bool isTrimEntries = false; +#endif + bool isRemoveEmpty = splitOptions.HasFlag(StringSplitOptions.RemoveEmptyEntries); + + int rangeCount = 0; + int startInclusive = 0; + + if (ranges.Length > 1) + { + while (true) + { + int separatorOffset = span[startInclusive..].IndexOf(separator); + if (separatorOffset < 0) + { + break; + } + + int endExclusive = startInclusive + separatorOffset; + int untrimmedEndExclusive = endExclusive; + + if (isTrimEntries) + { + TrimSplitEntry(span, ref startInclusive, ref endExclusive); + } + + if (isRemoveEmpty && + startInclusive == endExclusive) + { + continue; + } + + if (rangeCount >= ranges.Length - 1) + { + break; + } + + ranges[rangeCount++] = new Range(startInclusive, endExclusive); + + startInclusive = untrimmedEndExclusive + 1; + } + } + + int remainderEndExclusive = span.Length; + if (isTrimEntries) + { + TrimSplitEntry(span, ref startInclusive, ref remainderEndExclusive); + } + if (startInclusive != remainderEndExclusive) + { + ranges[rangeCount++] = new Range(startInclusive, remainderEndExclusive); + } + + return rangeCount; +#endif + } + +#if !NET8_0_OR_GREATER + private static void TrimSplitEntry( + ReadOnlySpan source, + ref int startInclusive, + ref int endExclusive) + { + while (startInclusive < endExclusive && char.IsWhiteSpace(source[startInclusive])) + { + startInclusive++; + } + + while (endExclusive > startInclusive && char.IsWhiteSpace(source[endExclusive - 1])) + { + endExclusive--; + } + } +#endif +} diff --git a/SharpHDiffPatch.New/HPatch.cs b/SharpHDiffPatch.New/HPatch.cs new file mode 100644 index 0000000..cb41c39 --- /dev/null +++ b/SharpHDiffPatch.New/HPatch.cs @@ -0,0 +1,42 @@ +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using SharpHDiffPatch.New.Header; +using SharpHDiffPatch.New.IO.Reader; + +namespace SharpHDiffPatch.New; + +public delegate (Stream Stream, bool LeaveOpen) CreateStream(long position); + +public delegate ValueTask<(Stream Stream, bool LeaveOpen)> CreateStreamAsync(long position, CancellationToken token); + +public static class HPatch +{ + public static HDiffInfo CreateInstance(CreateStream createStream) + { + (Stream stream, bool isDispose) = createStream(0); + using BittableStreamReader reader = new(stream, leaveOpen: !isDispose); + + string signature = reader.ReadStringToNull(); + HDiffInfo info = default; + HeaderReader.ReadHeaderSignature(signature, ref info); + HeaderReader.ReadHDiffHeaderMetadata(ref info, reader, createStream); + + return info; + } + + public static async ValueTask CreateInstanceAsync( + CreateStreamAsync createStream, + CancellationToken token = default) + { + (Stream stream, bool isDispose) = await createStream(0, token); + using BittableStreamReader reader = new(stream, leaveOpen: !isDispose); + + string signature = await reader.ReadStringToNullAsync(token: token); + HDiffInfo info = default; + HeaderReader.ReadHeaderSignature(signature, ref info); + info = await HeaderReader.ReadHDiffHeaderMetadataAsync(info, reader, createStream, token); + + return info; + } +} diff --git a/SharpHDiffPatch.New/HPatchContext.cs b/SharpHDiffPatch.New/HPatchContext.cs new file mode 100644 index 0000000..e115275 --- /dev/null +++ b/SharpHDiffPatch.New/HPatchContext.cs @@ -0,0 +1,13 @@ +using System; +using SharpHDiffPatch.New.Header; + +namespace SharpHDiffPatch.New; + +public class HPatchContext : IDisposable +{ + public required HDiffInfo Info { get; init; } + + public void Dispose() + { + } +} diff --git a/SharpHDiffPatch.New/Header/HDiffChecksum.cs b/SharpHDiffPatch.New/Header/HDiffChecksum.cs new file mode 100644 index 0000000..c4ab82f --- /dev/null +++ b/SharpHDiffPatch.New/Header/HDiffChecksum.cs @@ -0,0 +1,8 @@ +namespace SharpHDiffPatch.New.Header; + +public enum HDiffChecksum +{ + NoChecksum, + FAdler64, + Crc32 +} diff --git a/SharpHDiffPatch.New/Header/HDiffCompression.cs b/SharpHDiffPatch.New/Header/HDiffCompression.cs new file mode 100644 index 0000000..80815dd --- /dev/null +++ b/SharpHDiffPatch.New/Header/HDiffCompression.cs @@ -0,0 +1,15 @@ +// ReSharper disable UnusedMember.Global +// ReSharper disable IdentifierTypo +// ReSharper disable InconsistentNaming +namespace SharpHDiffPatch.New.Header; + +public enum HDiffCompression +{ + Uncompressed, + Lzma, + Lzma2, + Zlib, + PBZ2, + BZ2, + Zstd +} diff --git a/SharpHDiffPatch.New/Header/HDiffInfo.cs b/SharpHDiffPatch.New/Header/HDiffInfo.cs new file mode 100644 index 0000000..62a5416 --- /dev/null +++ b/SharpHDiffPatch.New/Header/HDiffInfo.cs @@ -0,0 +1,40 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SharpHDiffPatch.New.Extension; +using SharpHDiffPatch.New.Header.Metadata; + +namespace SharpHDiffPatch.New.Header; + +[StructLayout(LayoutKind.Sequential)] +public unsafe struct HDiffInfo : IDisposable +{ + public HDiffMagic MagicType; + public HDiffCompression CompressionType; + public HDiffChecksum ChecksumType; + public void* MetadataP; + + public ref T MetadataAs() + where T : unmanaged, IMetadataInit + => ref MetadataP == null ? + ref Unsafe.NullRef() : + ref Unsafe.AsRef(MetadataP); + + public ref T AllocMetadata() + where T : unmanaged, IMetadataInit + { + if (MetadataP != null) MemoryAlloc.Free(MetadataP); + + MetadataP = MemoryAlloc.Alloc(1, true); + ((T*)MetadataP)->Init(); // Start metadata initialization + return ref Unsafe.AsRef(MetadataP); + } + + public void Dispose() + { + if (MetadataP == null) return; + + MemoryAlloc.Free(MetadataP); + MetadataP = null; + } +} diff --git a/SharpHDiffPatch.New/Header/HDiffMagic.cs b/SharpHDiffPatch.New/Header/HDiffMagic.cs new file mode 100644 index 0000000..ab236e3 --- /dev/null +++ b/SharpHDiffPatch.New/Header/HDiffMagic.cs @@ -0,0 +1,8 @@ +namespace SharpHDiffPatch.New.Header; + +public enum HDiffMagic +{ + Unknown, + HDiff13, + HDiff19 +} diff --git a/SharpHDiffPatch.New/Header/HeaderReader.cs b/SharpHDiffPatch.New/Header/HeaderReader.cs new file mode 100644 index 0000000..a52e076 --- /dev/null +++ b/SharpHDiffPatch.New/Header/HeaderReader.cs @@ -0,0 +1,449 @@ +using SharpHDiffPatch.New.Extension; +using System; +using System.Buffers; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using SharpHDiffPatch.New.IO.Compression; +using SharpHDiffPatch.New.IO.Reader; +using SharpHDiffPatch.New.Header.Metadata; + +namespace SharpHDiffPatch.New.Header; + +public class HeaderReader +{ + private delegate ref PatchMetadata PatchMetadataAllocator(ref HDiffInfo info); + +#if NET8_0_OR_GREATER + [UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)], EntryPoint = "Extent_HeaderReader_ReadHeaderSignature")] + public static unsafe int ReadHeaderSignature_Extent(void* wSignP, int wSignLen, HDiffInfo* signP) + { + try + { + ReadOnlySpan signature = new(wSignP, wSignLen); + ReadHeaderSignature(signature, ref signP[0]); + return 0; + } + catch (Exception ex) + { + return ExceptionHelper.TryGetReturnCodeFromError(ex); + } + } +#endif + + public static void ReadHeaderSignature(ReadOnlySpan signature, ref HDiffInfo info) + { + ReadBasicHeaderSignature(signature, + out info.MagicType, + out info.CompressionType, + out info.ChecksumType); + } + + private static void ReadBasicHeaderSignature( + ReadOnlySpan signature, + out HDiffMagic magicType, + out HDiffCompression compressionType, + out HDiffChecksum checksumType) + { + Unsafe.SkipInit(out magicType); + Unsafe.SkipInit(out compressionType); + Unsafe.SkipInit(out checksumType); + + Span ranges = stackalloc Range[4]; + int signatureSplits = signature.GetSplits(ranges, '&'); + + if (signature.IsEmpty || + signatureSplits == 0) + { + ExceptionHelper.ThrowHDiffHeaderSignatureEmptyOrUnreadable(); + } + +#if !NET6_0_OR_GREATER + string magicSpan = signature[ranges[0]].ToString(); + string compressionTypeSpan = signature[ranges[1]].ToString(); + string checksumTypeSpan = signature[ranges[2]].ToString(); +#else + ReadOnlySpan magicSpan = signature[ranges[0]]; + ReadOnlySpan compressionTypeSpan = signature[ranges[1]]; + ReadOnlySpan checksumTypeSpan = signature[ranges[2]]; +#endif + + if (!Enum.TryParse(magicSpan, true, out magicType)) + { + ExceptionHelper.ThrowHdiffHeaderMagicNotSupported(magicSpan); + } + + // Parse HDIFF19 (Directory Patch) enums + if (magicType == HDiffMagic.HDiff19) + { + if (compressionTypeSpan.Length != 0 && + !Enum.TryParse(compressionTypeSpan, true, out compressionType)) + { + ExceptionHelper.ThrowHdiffHeaderCompressionNotSupported(compressionTypeSpan); + } + + if (checksumTypeSpan.Length != 0 && + !Enum.TryParse(checksumTypeSpan, true, out checksumType)) + { + ExceptionHelper.ThrowHdiffHeaderChecksumNotSupported(checksumTypeSpan); + } + + return; + } + + // Parse HDIFF13 (Single Patch) enums + if (magicType == HDiffMagic.HDiff13) + { + if (compressionTypeSpan.Length != 0 && + !Enum.TryParse(compressionTypeSpan, true, out compressionType)) + { + ExceptionHelper.ThrowHdiffHeaderCompressionNotSupported(compressionTypeSpan); + } + + return; + } + + ExceptionHelper.ThrowHdiffHeaderMagicNotSupported(magicSpan); + } + + internal static void ReadHDiffHeaderMetadata( + ref HDiffInfo info, + BittableStreamReader streamReader, + CreateStream additionalStreamCreate) + { + PatchMetadataAllocator patchMetadataAllocator = DefaultPatchMetadataAllocator; + switch (info.MagicType) + { + case HDiffMagic.HDiff19: + ReadHDiff19HeaderInfoCore(ref info, streamReader, additionalStreamCreate); + patchMetadataAllocator = HDiff19PatchMetadataAllocator; + // Continue reading HDiff13 data section. + goto case HDiffMagic.HDiff13; + case HDiffMagic.HDiff13: + ReadHDiff13HeaderInfoCore(ref info, streamReader, patchMetadataAllocator); + break; + } + } + + internal static async Task ReadHDiffHeaderMetadataAsync( + HDiffInfo info, + BittableStreamReader streamReader, + CreateStreamAsync additionalStreamCreate, + CancellationToken token) + { + PatchMetadataAllocator patchMetadataAllocator = DefaultPatchMetadataAllocator; + switch (info.MagicType) + { + case HDiffMagic.HDiff19: + info = await ReadHDiff19HeaderInfoAsyncCore(info, + streamReader, + additionalStreamCreate, + token); + + patchMetadataAllocator = HDiff19PatchMetadataAllocator; + // Continue reading HDiff13 data section. + goto case HDiffMagic.HDiff13; + case HDiffMagic.HDiff13: + info = await ReadHDiff13HeaderInfoAsyncCore(info, + streamReader, + patchMetadataAllocator, + token); + break; + } + + return info; + } + + private static ref PatchMetadata DefaultPatchMetadataAllocator(ref HDiffInfo info) + => ref info.AllocMetadata(); + + private static unsafe ref PatchMetadata HDiff19PatchMetadataAllocator(ref HDiffInfo info) + { + PatchMetadata* patchMetadata = MemoryAlloc.Alloc(); + patchMetadata->Init(); + + ref HeaderDirectoryPatchMetadata dirPatchMetadata = ref info.MetadataAs(); + dirPatchMetadata.PatchMetadataP = patchMetadata; + return ref Unsafe.AsRef(patchMetadata); + } + + private static unsafe void ReadHDiff19HeaderInfoCore( + ref HDiffInfo info, + BittableStreamReader streamReader, + CreateStream additionalStreamCreate) + { + byte isInputDir = streamReader.ReadByte(); + byte isOutputDir = streamReader.ReadByte(); + + int inputPathEntryCount = (int)streamReader.ReadLong7Bit(); + long inputPathEntryBufferSize = streamReader.ReadLong7Bit(); + int outputPathEntryCount = (int)streamReader.ReadLong7Bit(); + long outputPathEntryBufferSize = streamReader.ReadLong7Bit(); + + int inputRefFileCount = (int)streamReader.ReadLong7Bit(); + long inputPathEntryTotalSize = streamReader.ReadLong7Bit(); + int outputRefFileCount = (int)streamReader.ReadLong7Bit(); + long outputPathEntryTotalSize = streamReader.ReadLong7Bit(); + + int sameFilePathEntryCount = (int)streamReader.ReadLong7Bit(); + long sameFilePathEntryTotalSize = streamReader.ReadLong7Bit(); + + int newExecuteCount = streamReader.ReadInt7Bit(); + long privateReservedDataSize = streamReader.ReadLong7Bit(); + long privateExternDataSize = streamReader.ReadLong7Bit(); + long externDataSize = streamReader.ReadLong7Bit(); + + long headDataSize = streamReader.ReadLong7Bit(); + long headDataCompressedSize = streamReader.ReadLong7Bit(); + long checksumByteSize = streamReader.ReadLong7Bit(); + + int checksumDataLen = (int)checksumByteSize * 4; + Span checksumData = stackalloc byte[checksumDataLen]; + + streamReader.ReadBytes(checksumData); + long headDataOffset = streamReader.Offset; + + // Try seek primary reader. Read the HDiff13 signature and sanity. + long toSkipHeadDataSize = headDataCompressedSize > 0 ? headDataCompressedSize : headDataSize; + streamReader.AdvanceSeekTo((int)toSkipHeadDataSize); + string sanityDiffPatchSignature = streamReader.ReadStringToNull(); + ReadBasicHeaderSignature(sanityDiffPatchSignature, out _, out _, out _); + + // Read HeadData. + (Stream additionalStream, bool leaveOpenAdditionalStream) = additionalStreamCreate(headDataOffset); + using Stream additionalStreamDecompressed = DecompressStreamFactory.CreateStream(info.CompressionType, additionalStream, leaveOpenAdditionalStream); + using BittableStreamReader anotherStreamReader = new(additionalStreamDecompressed, leaveOpen: leaveOpenAdditionalStream); + + UnmanagedArray* inputPathEntryArray = anotherStreamReader.CreateUnmanagedStringList(inputPathEntryCount, (int)inputPathEntryBufferSize); + UnmanagedArray* outputPathEntryArray = anotherStreamReader.CreateUnmanagedStringList(outputPathEntryCount, (int)outputPathEntryBufferSize); + int* inputFilesIndexArray = anotherStreamReader.CreateUnmanagedInt64As32List(inputRefFileCount); + int* outputFilesIndexArray = anotherStreamReader.CreateUnmanagedInt64As32List(outputRefFileCount); + long* outputFilesSizesArray = anotherStreamReader.CreateUnmanagedInt64List(outputRefFileCount); + FileIndexPair* sameFilePathIndexPairArray = anotherStreamReader.CreateUnmanagedIndexPairList(sameFilePathEntryCount); + int* newExecuteListArray = anotherStreamReader.CreateUnmanagedInt64As32List(newExecuteCount); + + ref HeaderDirectoryPatchMetadata dirTypeMetadata = ref info.AllocMetadata(); + dirTypeMetadata.IsInputDir = isInputDir; + dirTypeMetadata.IsOutputDir = isOutputDir; + + EntryCountSizeInfo* inputPathCountSizeInfoP = dirTypeMetadata.InputPathCountSizeInfoP; + EntryCountSizeInfo* outputPathCountSizeInfoP = dirTypeMetadata.OutputPathCountSizeInfoP; + EntryCountSizeInfo* sameFilePathCountSizeInfoP = dirTypeMetadata.SameFilePathCountSizeInfoP; + ExternSizeInfo* externSizeInfo = dirTypeMetadata.ExternSizeInfoP; + ChunkSizeInfo* headDataSizeP = dirTypeMetadata.HeadDataSizeP; + ChecksumDataInfo* checksumDataInfoP = dirTypeMetadata.ChecksumDataInfoP; + + inputPathCountSizeInfoP->Count = inputPathEntryCount; + inputPathCountSizeInfoP->Size = inputPathEntryTotalSize; + outputPathCountSizeInfoP->Count = outputPathEntryCount; + outputPathCountSizeInfoP->Size = outputPathEntryTotalSize; + sameFilePathCountSizeInfoP->Count = sameFilePathEntryCount; + sameFilePathCountSizeInfoP->Size = sameFilePathEntryTotalSize; + + dirTypeMetadata.SameFilePathIndexPairP = sameFilePathIndexPairArray; + dirTypeMetadata.NewExecuteListP = newExecuteListArray; + + dirTypeMetadata.InputPathListP = inputPathEntryArray; + dirTypeMetadata.OutputPathListP = outputPathEntryArray; + dirTypeMetadata.InputFileIndexListP = inputFilesIndexArray; + dirTypeMetadata.OutputFileIndexListP = outputFilesIndexArray; + dirTypeMetadata.OutputFileSizeListP = outputFilesSizesArray; + + externSizeInfo->NewExecuteCount = newExecuteCount; + externSizeInfo->PrivateReservedDataSize = privateReservedDataSize; + externSizeInfo->PrivateExternDataSize = privateExternDataSize; + externSizeInfo->ExternDataSize = externDataSize; + + headDataSizeP->Size = headDataSize; + headDataSizeP->CompressedSize = headDataCompressedSize; + + checksumDataInfoP->AllocBytes((int)checksumByteSize, 4); + checksumData.CopyTo(checksumDataInfoP->GetAllSpan()); + } + + private static async Task ReadHDiff19HeaderInfoAsyncCore( + HDiffInfo info, + BittableStreamReader streamReader, + CreateStreamAsync additionalStreamCreate, + CancellationToken token) + { + byte isInputDir = await streamReader.ReadByteAsync(token); + byte isOutputDir = await streamReader.ReadByteAsync(token); + + int inputPathEntryCount = (int)await streamReader.ReadLong7BitAsync(token); + long inputPathEntryBufferSize = await streamReader.ReadLong7BitAsync(token); + int outputPathEntryCount = (int)await streamReader.ReadLong7BitAsync(token); + long outputPathEntryBufferSize = await streamReader.ReadLong7BitAsync(token); + + int inputRefFileCount = (int)await streamReader.ReadLong7BitAsync(token); + long inputPathEntryTotalSize = await streamReader.ReadLong7BitAsync(token); + int outputRefFileCount = (int)await streamReader.ReadLong7BitAsync(token); + long outputPathEntryTotalSize = await streamReader.ReadLong7BitAsync(token); + + int sameFilePathEntryCount = (int)await streamReader.ReadLong7BitAsync(token); + long sameFilePathEntryTotalSize = await streamReader.ReadLong7BitAsync(token); + + int newExecuteCount = await streamReader.ReadInt7BitAsync(token); + long privateReservedDataSize = await streamReader.ReadLong7BitAsync(token); + long privateExternDataSize = await streamReader.ReadLong7BitAsync(token); + long externDataSize = await streamReader.ReadLong7BitAsync(token); + + long headDataSize = await streamReader.ReadLong7BitAsync(token); + long headDataCompressedSize = await streamReader.ReadLong7BitAsync(token); + long checksumByteSize = await streamReader.ReadLong7BitAsync(token); + + int checksumDataLen = (int)checksumByteSize * 4; + byte[] checksumData = ArrayPool.Shared.Rent(checksumDataLen); + await streamReader.ReadBytesAsync(checksumData.AsMemory(0, checksumDataLen), token); + + long headDataOffset = streamReader.Offset; + + // Try seek primary reader. Read the HDiff13 signature and sanity. + long toSkipHeadDataSize = headDataCompressedSize > 0 ? headDataCompressedSize : headDataSize; + await streamReader.AdvanceSeekToAsync((int)toSkipHeadDataSize, token); + string sanityDiffPatchSignature = await streamReader.ReadStringToNullAsync(token); + ReadBasicHeaderSignature(sanityDiffPatchSignature, out _, out _, out _); + + // Read HeadData. + (Stream additionalStream, bool leaveOpenAdditionalStream) = await additionalStreamCreate(headDataOffset, token); + using Stream additionalStreamDecompressed = + DecompressStreamFactory.CreateStream(info.CompressionType, additionalStream, leaveOpenAdditionalStream); + using BittableStreamReader anotherStreamReader = new(additionalStreamDecompressed, leaveOpen: leaveOpenAdditionalStream); + + nint inputPathEntryArray = await anotherStreamReader.CreateUnmanagedStringListAsync(inputPathEntryCount, (int)inputPathEntryBufferSize, token); + nint outputPathEntryArray = await anotherStreamReader.CreateUnmanagedStringListAsync(outputPathEntryCount, (int)outputPathEntryBufferSize, token); + nint inputFilesIndexArray = await anotherStreamReader.CreateUnmanagedInt64As32ListAsync(inputRefFileCount, token); + nint outputFilesIndexArray = await anotherStreamReader.CreateUnmanagedInt64As32ListAsync(outputRefFileCount, token); + nint outputFilesSizesArray = await anotherStreamReader.CreateUnmanagedInt64ListAsync(outputRefFileCount, token); + nint sameFilePathIndexPairArray = await anotherStreamReader.CreateUnmanagedIndexPairListAsync(sameFilePathEntryCount, token); + nint newExecuteListArray = await anotherStreamReader.CreateUnmanagedInt64As32ListAsync(newExecuteCount, token); + + try + { + ref HeaderDirectoryPatchMetadata dirTypeMetadata = ref info.AllocMetadata(); + dirTypeMetadata.IsInputDir = isInputDir; + dirTypeMetadata.IsOutputDir = isOutputDir; + + unsafe + { + EntryCountSizeInfo* inputPathCountSizeInfoP = dirTypeMetadata.InputPathCountSizeInfoP; + EntryCountSizeInfo* outputPathCountSizeInfoP = dirTypeMetadata.OutputPathCountSizeInfoP; + EntryCountSizeInfo* sameFilePathCountSizeInfoP = dirTypeMetadata.SameFilePathCountSizeInfoP; + ExternSizeInfo* externSizeInfo = dirTypeMetadata.ExternSizeInfoP; + ChunkSizeInfo* headDataSizeP = dirTypeMetadata.HeadDataSizeP; + ChecksumDataInfo* checksumDataInfoP = dirTypeMetadata.ChecksumDataInfoP; + + inputPathCountSizeInfoP->Count = inputPathEntryCount; + inputPathCountSizeInfoP->Size = inputPathEntryTotalSize; + outputPathCountSizeInfoP->Count = outputPathEntryCount; + outputPathCountSizeInfoP->Size = outputPathEntryTotalSize; + sameFilePathCountSizeInfoP->Count = sameFilePathEntryCount; + sameFilePathCountSizeInfoP->Size = sameFilePathEntryTotalSize; + + dirTypeMetadata.SameFilePathIndexPairP = (FileIndexPair*)sameFilePathIndexPairArray; + dirTypeMetadata.NewExecuteListP = (int*)newExecuteListArray; + + dirTypeMetadata.InputPathListP = (UnmanagedArray*)inputPathEntryArray; + dirTypeMetadata.OutputPathListP = (UnmanagedArray*)outputPathEntryArray; + dirTypeMetadata.InputFileIndexListP = (int*)inputFilesIndexArray; + dirTypeMetadata.OutputFileIndexListP = (int*)outputFilesIndexArray; + dirTypeMetadata.OutputFileSizeListP = (long*)outputFilesSizesArray; + + externSizeInfo->NewExecuteCount = newExecuteCount; + externSizeInfo->PrivateReservedDataSize = privateReservedDataSize; + externSizeInfo->PrivateExternDataSize = privateExternDataSize; + externSizeInfo->ExternDataSize = externDataSize; + + headDataSizeP->Size = headDataSize; + headDataSizeP->CompressedSize = headDataCompressedSize; + + checksumDataInfoP->AllocBytes((int)checksumByteSize, 4); + checksumData.CopyTo(checksumDataInfoP->GetAllSpan()); + + return info; + } + } + finally + { + ArrayPool.Shared.Return(checksumData); + } + } + + private static unsafe void ReadHDiff13HeaderInfoCore( + ref HDiffInfo info, + BittableStreamReader streamReader, + PatchMetadataAllocator metadataAllocator) + { + long newSize = streamReader.ReadLong7Bit(); + long oldSize = streamReader.ReadLong7Bit(); + + long coverDataCount = streamReader.ReadLong7Bit(); + + long coverDataSize = streamReader.ReadLong7Bit(); + long coverDataSizeC = streamReader.ReadLong7Bit(); + long rleControlDataSize = streamReader.ReadLong7Bit(); + long rleControlDataSizeC = streamReader.ReadLong7Bit(); + long rleCodeDataSize = streamReader.ReadLong7Bit(); + long rleCodeDataSizeC = streamReader.ReadLong7Bit(); + long newDiffSize = streamReader.ReadLong7Bit(); + long newDiffSizeC = streamReader.ReadLong7Bit(); + + ref PatchMetadata patchMetadata = ref metadataAllocator(ref info); + + patchMetadata.DiffNewSize = newSize; + patchMetadata.DiffOldSize = oldSize; + patchMetadata.CoverDataCount = coverDataCount; + + patchMetadata.CoverDataSizeP->Size = coverDataSize; + patchMetadata.CoverDataSizeP->CompressedSize = coverDataSizeC; + patchMetadata.RleControlDataSizeP->Size = rleControlDataSize; + patchMetadata.RleControlDataSizeP->CompressedSize = rleControlDataSizeC; + patchMetadata.RleCodeDataSizeP->Size = rleCodeDataSize; + patchMetadata.RleCodeDataSizeP->CompressedSize = rleCodeDataSizeC; + patchMetadata.NewDiffDataSizeP->CompressedSize = newDiffSize; + patchMetadata.NewDiffDataSizeP->CompressedSize = newDiffSizeC; + } + + private static async Task ReadHDiff13HeaderInfoAsyncCore( + HDiffInfo info, + BittableStreamReader streamReader, + PatchMetadataAllocator metadataAllocator, + CancellationToken token) + { + long newSize = await streamReader.ReadLong7BitAsync(token); + long oldSize = await streamReader.ReadLong7BitAsync(token); + + long coverDataCount = await streamReader.ReadLong7BitAsync(token); + + long coverDataSize = await streamReader.ReadLong7BitAsync(token); + long coverDataSizeC = await streamReader.ReadLong7BitAsync(token); + long rleControlDataSize = await streamReader.ReadLong7BitAsync(token); + long rleControlDataSizeC = await streamReader.ReadLong7BitAsync(token); + long rleCodeDataSize = await streamReader.ReadLong7BitAsync(token); + long rleCodeDataSizeC = await streamReader.ReadLong7BitAsync(token); + long newDiffSize = await streamReader.ReadLong7BitAsync(token); + long newDiffSizeC = await streamReader.ReadLong7BitAsync(token); + + unsafe + { + ref PatchMetadata patchMetadata = ref metadataAllocator(ref info); + + patchMetadata.DiffNewSize = newSize; + patchMetadata.DiffOldSize = oldSize; + patchMetadata.CoverDataCount = coverDataCount; + + patchMetadata.CoverDataSizeP->Size = coverDataSize; + patchMetadata.CoverDataSizeP->CompressedSize = coverDataSizeC; + patchMetadata.RleControlDataSizeP->Size = rleControlDataSize; + patchMetadata.RleControlDataSizeP->CompressedSize = rleControlDataSizeC; + patchMetadata.RleCodeDataSizeP->Size = rleCodeDataSize; + patchMetadata.RleCodeDataSizeP->CompressedSize = rleCodeDataSizeC; + patchMetadata.NewDiffDataSizeP->CompressedSize = newDiffSize; + patchMetadata.NewDiffDataSizeP->CompressedSize = newDiffSizeC; + + return info; + } + } +} diff --git a/SharpHDiffPatch.New/Header/Metadata/ChecksumDataInfo.cs b/SharpHDiffPatch.New/Header/Metadata/ChecksumDataInfo.cs new file mode 100644 index 0000000..0a9528f --- /dev/null +++ b/SharpHDiffPatch.New/Header/Metadata/ChecksumDataInfo.cs @@ -0,0 +1,69 @@ +using System; +using System.Runtime.CompilerServices; +using SharpHDiffPatch.New.Extension; + +namespace SharpHDiffPatch.New.Header.Metadata; + +public unsafe struct ChecksumDataInfo : IMetadataInit +{ + public ChecksumDataInfo() + { + Init(); + } + + public void Init() + { + if (IsDisposed || IsInitialized) + { + return; + } + + IsInitialized = true; + IsDisposed = false; + MetadataType = MetadataTypeConst.ChecksumDataInfoType; + } + + public void Dispose() + { + if (IsDisposed) + { + return; + } + + IsDisposed = true; + IsInitialized = false; + + if (_byte != null) MemoryAlloc.Free(_byte); + _byte = null; + } + + public MetadataTypeConst MetadataType { get; private set; } + + public bool IsInitialized + { + get => _isInitialized == 1; + private set => _isInitialized = value ? (byte)1 : (byte)0; + } + + public bool IsDisposed + { + get => _isDisposed == 1; + private set => _isDisposed = value ? (byte)1 : (byte)0; + } + + private byte _isInitialized; + private byte _isDisposed; + + private int _dataSize; + private int _dataCount; + private void* _byte; + + public void AllocBytes(int dataSize, int elementCount) + => _byte = MemoryAlloc.Alloc((_dataSize = dataSize) * (_dataCount = elementCount), true); + + public Span GetAllSpan() + => new(_byte, _dataCount * _dataSize); + + public Span GetSpan(int index) + => new(Unsafe.Add(_byte, index * _dataSize), _dataSize); +} diff --git a/SharpHDiffPatch.New/Header/Metadata/ChunkSizeInfo.cs b/SharpHDiffPatch.New/Header/Metadata/ChunkSizeInfo.cs new file mode 100644 index 0000000..6d5b507 --- /dev/null +++ b/SharpHDiffPatch.New/Header/Metadata/ChunkSizeInfo.cs @@ -0,0 +1,10 @@ +using System.Runtime.InteropServices; + +namespace SharpHDiffPatch.New.Header.Metadata; + +[StructLayout(LayoutKind.Sequential)] +public struct ChunkSizeInfo +{ + public long Size; + public long CompressedSize; +} diff --git a/SharpHDiffPatch.New/Header/Metadata/EntryCountSizeInfo.cs b/SharpHDiffPatch.New/Header/Metadata/EntryCountSizeInfo.cs new file mode 100644 index 0000000..a6785e3 --- /dev/null +++ b/SharpHDiffPatch.New/Header/Metadata/EntryCountSizeInfo.cs @@ -0,0 +1,10 @@ +using System.Runtime.InteropServices; + +namespace SharpHDiffPatch.New.Header.Metadata; + +[StructLayout(LayoutKind.Sequential)] +public struct EntryCountSizeInfo +{ + public int Count; + public long Size; +} \ No newline at end of file diff --git a/SharpHDiffPatch.New/Header/Metadata/ExternSizeInfo.cs b/SharpHDiffPatch.New/Header/Metadata/ExternSizeInfo.cs new file mode 100644 index 0000000..f8f4b52 --- /dev/null +++ b/SharpHDiffPatch.New/Header/Metadata/ExternSizeInfo.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace SharpHDiffPatch.New.Header.Metadata; + +[StructLayout(LayoutKind.Sequential)] +public struct ExternSizeInfo +{ + public int NewExecuteCount; + public long PrivateReservedDataSize; + public long PrivateExternDataSize; + public long ExternDataSize; +} diff --git a/SharpHDiffPatch.New/Header/Metadata/FileIndexPair.cs b/SharpHDiffPatch.New/Header/Metadata/FileIndexPair.cs new file mode 100644 index 0000000..06a844a --- /dev/null +++ b/SharpHDiffPatch.New/Header/Metadata/FileIndexPair.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace SharpHDiffPatch.New.Header.Metadata; + +[StructLayout(LayoutKind.Sequential)] +public struct FileIndexPair +{ + public int OldIndex; + public int NewIndex; + + public override string ToString() => $"Old: {OldIndex} - New: {NewIndex}"; +} diff --git a/SharpHDiffPatch.New/Header/Metadata/HeaderDirectoryPatchMetadata.cs b/SharpHDiffPatch.New/Header/Metadata/HeaderDirectoryPatchMetadata.cs new file mode 100644 index 0000000..ab6dcbc --- /dev/null +++ b/SharpHDiffPatch.New/Header/Metadata/HeaderDirectoryPatchMetadata.cs @@ -0,0 +1,103 @@ +using System.Runtime.InteropServices; +using SharpHDiffPatch.New.Extension; + +namespace SharpHDiffPatch.New.Header.Metadata; + +[StructLayout(LayoutKind.Sequential)] +public unsafe struct HeaderDirectoryPatchMetadata : IMetadataInit +{ + public HeaderDirectoryPatchMetadata() + { + Init(); + } + + public void Init() + { + if (IsDisposed || IsInitialized) + { + return; + } + + IsInitialized = true; + IsDisposed = false; + MetadataType = MetadataTypeConst.HeaderDirectoryPatchMetadataType; + InputPathCountSizeInfoP = MemoryAlloc.Alloc(1, true); + OutputPathCountSizeInfoP = MemoryAlloc.Alloc(1, true); + SameFilePathCountSizeInfoP = MemoryAlloc.Alloc(1, true); + ExternSizeInfoP = MemoryAlloc.Alloc(1, true); + HeadDataSizeP = MemoryAlloc.Alloc(1, true); + PatchMetadataP = MemoryAlloc.Alloc(1, true); + ChecksumDataInfoP = MemoryAlloc.Alloc(1, true); + } + + public void Dispose() + { + if (IsDisposed || !IsInitialized) + { + return; + } + + IsDisposed = true; + IsInitialized = false; + MemoryAlloc.Free(InputPathCountSizeInfoP); + MemoryAlloc.Free(OutputPathCountSizeInfoP); + MemoryAlloc.Free(SameFilePathCountSizeInfoP); + MemoryAlloc.Free(SameFilePathIndexPairP); + + MemoryAlloc.Free(InputPathListP); + MemoryAlloc.Free(OutputPathListP); + MemoryAlloc.Free(InputFileIndexListP); + MemoryAlloc.Free(OutputFileIndexListP); + MemoryAlloc.Free(OutputFileSizeListP); + + MemoryAlloc.Free(ExternSizeInfoP); + + MemoryAlloc.Free(HeadDataSizeP); + MemoryAlloc.Free(PatchMetadataP); + MemoryAlloc.Free(ChecksumDataInfoP); + MemoryAlloc.Free(NewExecuteListP); + } + + public MetadataTypeConst MetadataType { get; private set; } + + public bool IsInitialized + { + get => _isInitialized == 1; + private set => _isInitialized = value ? (byte)1 : (byte)0; + } + + public bool IsDisposed + { + get => _isDisposed == 1; + private set => _isDisposed = value ? (byte)1 : (byte)0; + } + + private byte _isInitialized; + private byte _isDisposed; + + public byte IsInputDir; + public byte IsOutputDir; + + public EntryCountSizeInfo* InputPathCountSizeInfoP; + public EntryCountSizeInfo* OutputPathCountSizeInfoP; + public EntryCountSizeInfo* SameFilePathCountSizeInfoP; + public FileIndexPair* SameFilePathIndexPairP; + + public UnmanagedArray* InputPathListP; + public UnmanagedArray* OutputPathListP; + public int* InputFileIndexListP; + public int* OutputFileIndexListP; + public long* OutputFileSizeListP; + + // Seems unused. + // TODO: See original code to see what it is. + public ExternSizeInfo* ExternSizeInfoP; + + // File Reference Chunk Info, including: + // - Filename string chunks + // - Checksum chunks + public ChunkSizeInfo* HeadDataSizeP; + public PatchMetadata* PatchMetadataP; + public ChecksumDataInfo* ChecksumDataInfoP; + public int* NewExecuteListP; +} \ No newline at end of file diff --git a/SharpHDiffPatch.New/Header/Metadata/IMetadataInit.cs b/SharpHDiffPatch.New/Header/Metadata/IMetadataInit.cs new file mode 100644 index 0000000..6a4938f --- /dev/null +++ b/SharpHDiffPatch.New/Header/Metadata/IMetadataInit.cs @@ -0,0 +1,12 @@ +using System; + +namespace SharpHDiffPatch.New.Header.Metadata; + +public interface IMetadataInit : IDisposable +{ + public MetadataTypeConst MetadataType { get; } + public bool IsInitialized { get; } + public bool IsDisposed { get; } + + void Init(); +} diff --git a/SharpHDiffPatch.New/Header/Metadata/MetadataTypeConst.cs b/SharpHDiffPatch.New/Header/Metadata/MetadataTypeConst.cs new file mode 100644 index 0000000..13c4920 --- /dev/null +++ b/SharpHDiffPatch.New/Header/Metadata/MetadataTypeConst.cs @@ -0,0 +1,15 @@ +using System; + +namespace SharpHDiffPatch.New.Header.Metadata; + +[Flags] +public enum MetadataTypeConst : short +{ + IsMetadataType = unchecked((short)0b_10000000_10000000), + + PatchMetadataType = IsMetadataType | 0b_01000000_00000000, + HeaderDirectoryPatchMetadataType = IsMetadataType | 0b_00100000_00000000, + ChecksumDataInfoType = IsMetadataType | 0b_00010000_00000000, + UnmanagedArrayType = IsMetadataType | 0b_00001000_00000000, + Utf16UnmanagedStringType = IsMetadataType | 0b_00000100_00000000 +} diff --git a/SharpHDiffPatch.New/Header/Metadata/PatchMetadata.cs b/SharpHDiffPatch.New/Header/Metadata/PatchMetadata.cs new file mode 100644 index 0000000..705e7b7 --- /dev/null +++ b/SharpHDiffPatch.New/Header/Metadata/PatchMetadata.cs @@ -0,0 +1,75 @@ +using System.Runtime.InteropServices; +using SharpHDiffPatch.New.Extension; + +namespace SharpHDiffPatch.New.Header.Metadata; + +[StructLayout(LayoutKind.Sequential)] +public unsafe struct PatchMetadata : IMetadataInit +{ + public PatchMetadata() + { + Init(); + } + + public void Init() + { + if (IsDisposed || IsInitialized) + { + return; + } + + IsInitialized = true; + IsDisposed = false; + MetadataType = MetadataTypeConst.PatchMetadataType; + CoverDataSizeP = MemoryAlloc.Alloc(1, true); + RleControlDataSizeP = MemoryAlloc.Alloc(1, true); + RleCodeDataSizeP = MemoryAlloc.Alloc(1, true); + NewDiffDataSizeP = MemoryAlloc.Alloc(1, true); + } + + public void Dispose() + { + if (IsDisposed || !IsInitialized) + { + return; + } + + IsDisposed = true; + IsInitialized = false; + MemoryAlloc.Free(CoverDataSizeP); + MemoryAlloc.Free(RleControlDataSizeP); + MemoryAlloc.Free(RleCodeDataSizeP); + MemoryAlloc.Free(NewDiffDataSizeP); + CoverDataSizeP = null; + RleControlDataSizeP = null; + RleCodeDataSizeP = null; + NewDiffDataSizeP = null; + } + + public MetadataTypeConst MetadataType { get; private set; } + + public bool IsInitialized + { + get => _isInitialized == 1; + private set => _isInitialized = value ? (byte)1 : (byte)0; + } + + public bool IsDisposed + { + get => _isDisposed == 1; + private set => _isDisposed = value ? (byte)1 : (byte)0; + } + + private byte _isInitialized; + private byte _isDisposed; + + public long DiffNewSize; + public long DiffOldSize; + + public long CoverDataCount; + + public ChunkSizeInfo* CoverDataSizeP; + public ChunkSizeInfo* RleControlDataSizeP; + public ChunkSizeInfo* RleCodeDataSizeP; + public ChunkSizeInfo* NewDiffDataSizeP; +} diff --git a/SharpHDiffPatch.New/Header/Metadata/UnmanagedArray.cs b/SharpHDiffPatch.New/Header/Metadata/UnmanagedArray.cs new file mode 100644 index 0000000..d2f7c06 --- /dev/null +++ b/SharpHDiffPatch.New/Header/Metadata/UnmanagedArray.cs @@ -0,0 +1,124 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SharpHDiffPatch.New.Extension; + +namespace SharpHDiffPatch.New.Header.Metadata; + +[StructLayout(LayoutKind.Sequential)] +public unsafe struct UnmanagedArray : IMetadataInit + where T : unmanaged +{ + public UnmanagedArray() + { + Init(); + } + + public void Init() + { + if (IsDisposed || IsInitialized) + { + return; + } + + TypeSize = sizeof(T); + IsInitialized = true; + IsDisposed = false; + MetadataType = MetadataTypeConst.UnmanagedArrayType; + } + + public void Dispose() + { + if (IsDisposed || !IsInitialized || Data == null) + { + return; + } + + IsDisposed = true; + IsInitialized = false; + T* oldData = Data; + Data = null; + + if (oldData != null) + { + // Try to automatically dispose if data is a member of IMetadataInit + ref byte startRef = ref Unsafe.AsRef(oldData); + ref byte endRef = ref Unsafe.Add(ref startRef, TypeSize * Length); + if (startRef.TryGetMetadataType(out _)) + { + while (Unsafe.IsAddressLessThan(ref startRef, ref endRef)) + { + startRef.TryDisposeIfMetadataType(); + startRef = ref Unsafe.Add(ref startRef, TypeSize); + } + } + } + + MemoryAlloc.Free(oldData); + } + + public MetadataTypeConst MetadataType { get; private set; } + + public bool IsInitialized + { + get => _isInitialized == 1; + private set => _isInitialized = value ? (byte)1 : (byte)0; + } + + public bool IsDisposed + { + get => _isDisposed == 1; + private set => _isDisposed = value ? (byte)1 : (byte)0; + } + + private byte _isInitialized; + private byte _isDisposed; + + public int Length; + public int TypeSize; + public T* Data; + + public Span GetSpan() + { + if (sizeof(T) != TypeSize) + { + throw new ArrayTypeMismatchException("Type mismatched!"); + } + + return Data == null ? Span.Empty : new Span(Data, Length); + } + + public static UnmanagedArray* CreateAllocUnsafe(int count, bool initialize = false) + { + UnmanagedArray* alloc = MemoryAlloc.Alloc>(); + alloc->Data = MemoryAlloc.Alloc(count, initialize); + alloc->Length = count; + alloc->Init(); + + return alloc; + } + + public static UnmanagedArray CreateAlloc(int count, bool initialize = false) + { + var array = new UnmanagedArray + { + Data = MemoryAlloc.Alloc(count, initialize), + Length = count + }; + + array.Init(); + return array; + } + + + public static implicit operator Span(UnmanagedArray unmanagedSpan) => unmanagedSpan.GetSpan(); + + public ref T this[int index] + { + get + { + if (index > Length - 1) throw new ArgumentOutOfRangeException(); + return ref Unsafe.AsRef(Unsafe.Add(Data, index)); + } + } +} diff --git a/SharpHDiffPatch.New/Header/Metadata/Utf16UnmanagedString.cs b/SharpHDiffPatch.New/Header/Metadata/Utf16UnmanagedString.cs new file mode 100644 index 0000000..8c63b67 --- /dev/null +++ b/SharpHDiffPatch.New/Header/Metadata/Utf16UnmanagedString.cs @@ -0,0 +1,91 @@ +using System; +using System.Runtime.InteropServices; +using SharpHDiffPatch.New.Extension; + +namespace SharpHDiffPatch.New.Header.Metadata; + +[StructLayout(LayoutKind.Sequential)] +public unsafe struct Utf16UnmanagedString : IMetadataInit +{ + public Utf16UnmanagedString() + { + Init(); + } + + public void Init() + { + if (IsDisposed || IsInitialized) + { + return; + } + + IsInitialized = true; + IsDisposed = false; + MetadataType = MetadataTypeConst.Utf16UnmanagedStringType; + } + + public void Dispose() + { + if (IsDisposed || !IsInitialized || Native is { Chars: null, Length: 0 }) + { + return; + } + + IsDisposed = true; + IsInitialized = false; + NativeStringW old = Native; + Native = NativeStringW.Empty; + + MemoryAlloc.Free(old.Chars); + } + + public MetadataTypeConst MetadataType { get; private set; } + + public bool IsInitialized + { + get => _isInitialized == 1; + private set => _isInitialized = value ? (byte)1 : (byte)0; + } + + public bool IsDisposed + { + get => _isDisposed == 1; + private set => _isDisposed = value ? (byte)1 : (byte)0; + } + + private byte _isInitialized; + private byte _isDisposed; + public NativeStringW Native; + + public static Utf16UnmanagedString CreateFromManaged(ReadOnlySpan source) + { + int lengthToAlloc = source.Length + 1; + char* nativeChar = MemoryAlloc.Alloc(lengthToAlloc, true); + + source.CopyTo(new Span(nativeChar, source.Length)); + Utf16UnmanagedString thisStruct = new() + { + Native = new NativeStringW(nativeChar, source.Length) + }; + thisStruct.Init(); + + return thisStruct; + } + + public static implicit operator ReadOnlySpan(Utf16UnmanagedString unmanaged) + => unmanaged.Native; + + [StructLayout(LayoutKind.Sequential)] + public readonly struct NativeStringW(char* chars, int length) + { + public static NativeStringW Empty => default; + + public readonly char* Chars = chars; + public readonly int Length = length; + + public static implicit operator ReadOnlySpan(NativeStringW unmanaged) + => new(unmanaged.Chars, unmanaged.Length); + + public override string ToString() => new(Chars, 0, Length); + } +} diff --git a/SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Constants.cs b/SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Constants.cs new file mode 100644 index 0000000..330b194 --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Constants.cs @@ -0,0 +1,159 @@ +using System; + +namespace SharpHDiffPatch.New.IO.Compression.BZip2; + +/// +/// Defines internal values for both compression and decompression +/// +internal static class BZip2Constants +{ + internal enum DecodeState : byte + { + StartBlock, + RandPartA, + RandPartB, + RandPartC, + NoRandPartA, + NoRandPartB, + NoRandPartC + } + + /// + /// Random numbers used to randomise repetitive blocks + /// + public static readonly ushort[] RandomNumbers = + [ + 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, + 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, + 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, + 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, + 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, + 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, + 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, + 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, + 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, + 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, + 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, + 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, + 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, + 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, + 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, + 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, + 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, + 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, + 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, + 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, + 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, + 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, + 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, + 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, + 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, + 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, + 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, + 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, + 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, + 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, + 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, + 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, + 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, + 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, + 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, + 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, + 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, + 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, + 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, + 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, + 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, + 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, + 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, + 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, + 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, + 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, + 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, + 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, + 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, + 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, + 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, + 936, 638 + ]; + + /// + /// When multiplied by compression parameter (1-9) gives the block size for compression + /// 9 gives the best compression but uses the most memory. + /// + public const int BaseBlockSize = 100000; + + /// + /// Backend constant + /// + public const int MaximumAlphaSize = 258; + + /// + /// Backend constant + /// + public const int MaximumCodeLength = 23; + + /// + /// Backend constant + /// + public const int RunA = 0; + + /// + /// Backend constant + /// + public const int RunB = 1; + + /// + /// Backend constant + /// + public const int GroupCount = 6; + + /// + /// Backend constant + /// + public const int GroupSize = 50; + + /// + /// Backend constant + /// + public const int MaximumSelectors = 2 + 900000 / GroupSize; + + /// + /// Initial Identity MTF constant + /// + public static ReadOnlySpan IdentityMtf => + [ + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, + 104, 105, 106, 107, 108, 109, 110, 111, + 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, + 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 138, 139, 140, 141, 142, 143, + 144, 145, 146, 147, 148, 149, 150, 151, + 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, 165, 166, 167, + 168, 169, 170, 171, 172, 173, 174, 175, + 176, 177, 178, 179, 180, 181, 182, 183, + 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, + 200, 201, 202, 203, 204, 205, 206, 207, + 208, 209, 210, 211, 212, 213, 214, 215, + 216, 217, 218, 219, 220, 221, 222, 223, + 224, 225, 226, 227, 228, 229, 230, 231, + 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, + 248, 249, 250, 251, 252, 253, 254, 255 + ]; +} \ No newline at end of file diff --git a/SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Crc32.cs b/SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Crc32.cs new file mode 100644 index 0000000..aacca67 --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Crc32.cs @@ -0,0 +1,421 @@ +using System; +using System.Buffers.Binary; +using System.IO.Hashing; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if NET6_0_OR_GREATER +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +// ReSharper disable IdentifierTypo +// ReSharper disable InconsistentNaming +#endif + +namespace SharpHDiffPatch.New.IO.Compression.BZip2; + +file static class BZip2Crc32Premul +{ + internal const uint InitialState = uint.MaxValue; + internal const int HashSize = sizeof(uint); + private const uint Polynomial = 0x04C11DB7u; + + // Eight concatenated 256-entry tables. + private static readonly uint[] SCrcLookup = CreateSlicingBy8Lookup(); + +#if NET6_0_OR_GREATER + internal const int PclmulThreshold = 128; + + /* + * P(x) = x^32 + 0x04C11DB7 + * + * Folding constants: + * + * k1 = x^576 mod P = 0x8833794C + * k2 = x^512 mod P = 0xE6228B11 + * k3 = x^192 mod P = 0xC5B9CD4C + * k4 = x^128 mod P = 0xE8A45605 + * k5 = x^96 mod P = 0xF200AA66 + * k6 = x^64 mod P = 0x490D678D + * + * mu = floor(x^64 / P) over GF(2) = 0x104D101DF + * + * Vector128.Create() specifies the low 64-bit lane first. + */ + private static readonly Vector128 SK1K2 = + Vector128.Create(0xE6228B11UL, // k2 + 0x8833794CUL // k1 + ); + + private static readonly Vector128 SK3K4 = + Vector128.Create(0xE8A45605UL, // k4 + 0xC5B9CD4CUL // k3 + ); + + private static readonly Vector128 SFoldConstants = + Vector128.Create(0x04C11DB7UL, // x^32 mod P + 0xF200AA66UL // k5 + ); + + private static readonly Vector128 SReverseBytesMask = + Vector128.Create((byte)15, 14, 13, 12, + 11, 10, 9, 8, + 7, 6, 5, 4, + 3, 2, 1, 0); + + private static readonly Vector128 SLower64Mask = + Vector128.Create(ulong.MaxValue, 0UL); + + private static readonly Vector128 SLow32PerLaneMask = + Vector128.Create(0xFFFFFFFFUL, 0xFFFFFFFFUL); + + private const ulong K6 = 0x490D678DUL; + private const ulong Mu = 0x104D101DFUL; + + [MethodImpl(MethodImplOptions.NoInlining)] + internal static uint UpdatePclmul( + uint crc, + ReadOnlySpan source) + { + // The vector path processes complete 16-byte blocks. + int vectorLength = source.Length & -Vector128.Count; + + ref byte sourceRef = ref MemoryMarshal.GetReference(source); + + Vector128 x1; + int offset; + + if (vectorLength >= 4 * Vector128.Count) + { + // Start four independent 128-bit folding streams. + x1 = LoadReversed(ref sourceRef); + Vector128 x2 = LoadReversed(ref Unsafe.Add(ref sourceRef, 16)); + Vector128 x3 = LoadReversed(ref Unsafe.Add(ref sourceRef, 32)); + Vector128 x4 = LoadReversed(ref Unsafe.Add(ref sourceRef, 48)); + + offset = 64; + + /* + * The CRC occupies the most-significant 32 bits of the + * first reversed 128-bit input block. + */ + Vector128 initialCrc = Sse2.ShiftLeftLogical128BitLane(Vector128.CreateScalar((ulong)crc << 32), 8); + + x1 = Sse2.Xor(x1, initialCrc); + + while (vectorLength - offset >= 64) + { + Vector128 y1 = LoadReversed(ref Unsafe.Add(ref sourceRef, offset)); + Vector128 y2 = LoadReversed(ref Unsafe.Add(ref sourceRef, offset + 16)); + Vector128 y3 = LoadReversed(ref Unsafe.Add(ref sourceRef, offset + 32)); + Vector128 y4 = LoadReversed(ref Unsafe.Add(ref sourceRef, offset + 48)); + + x1 = FoldPolynomialPair(y1, x1, SK1K2); + x2 = FoldPolynomialPair(y2, x2, SK1K2); + x3 = FoldPolynomialPair(y3, x3, SK1K2); + x4 = FoldPolynomialPair(y4, x4, SK1K2); + + offset += 64; + } + + // Merge the four parallel streams. + x1 = FoldPolynomialPair(x2, x1, SK3K4); + x1 = FoldPolynomialPair(x3, x1, SK3K4); + x1 = FoldPolynomialPair(x4, x1, SK3K4); + } + else + { + x1 = LoadReversed(ref sourceRef); + Vector128 initialCrc = Sse2.ShiftLeftLogical128BitLane(Vector128.CreateScalar((ulong)crc << 32), 8); + x1 = Sse2.Xor(x1, initialCrc); + + offset = 16; + } + + // Fold remaining complete 16-byte blocks. + while (vectorLength - offset >= 16) + { + Vector128 next = LoadReversed(ref Unsafe.Add(ref sourceRef, offset)); + + x1 = FoldPolynomialPair(next, x1, SK3K4); + offset += 16; + } + + /* + * Fold 128 bits down toward 64 bits. + * + * SFoldConstants contains: + * low lane: x^32 mod P + * high lane: x^96 mod P + */ + x1 = FoldPolynomialPair(Vector128.Zero, x1, SFoldConstants); + + /* + * Fold 64 bits toward 32 bits: + * + * upper64(x1) * k6 XOR lower64(x1) + */ + Vector128 lower64 = Sse2.And(x1, SLower64Mask); + Vector128 folded64 = Pclmulqdq.CarrylessMultiply(x1, Vector128.CreateScalar(K6), 0x01); + + x1 = Sse2.Xor(folded64, lower64); + + // Barrett reduction from the remaining polynomial to 32 bits. + Vector128 temporary = x1; + + x1 = Sse2.ShiftRightLogical128BitLane(x1, 4); + x1 = Sse2.And(x1, SLow32PerLaneMask); + x1 = Pclmulqdq.CarrylessMultiply(x1, Vector128.CreateScalar(Mu), 0x00); + x1 = Sse2.ShiftRightLogical128BitLane(x1, 4); + x1 = Sse2.And(x1, SLow32PerLaneMask); + x1 = Pclmulqdq.CarrylessMultiply(x1, Vector128.CreateScalar((ulong)Polynomial), 0x00); + x1 = Sse2.Xor(x1, temporary); + uint reducedCrc = x1.AsUInt32().GetElement(0); + + // Process the final 0–15 bytes using the existing implementation. + return UpdateSlicingBy8(reducedCrc, source[vectorLength..]); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector128 LoadReversed(ref byte source) + { + var value = Unsafe.ReadUnaligned>(ref source); + return Ssse3.Shuffle(value, SReverseBytesMask).AsUInt64(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector128 FoldPolynomialPair( + Vector128 target, + Vector128 source, + Vector128 constants) + { + /* + * target XOR= + * CLMUL(source.low, constants.low) XOR + * CLMUL(source.high, constants.high) + */ + Vector128 lowerProduct = Pclmulqdq.CarrylessMultiply(source, constants, 0x00); + Vector128 upperProduct = Pclmulqdq.CarrylessMultiply(source, constants, 0x11); + Vector128 products = Sse2.Xor(lowerProduct, upperProduct); + return Sse2.Xor(target, products); + } +#endif + + internal static uint UpdateSlicingBy8( + uint crc, + ReadOnlySpan source) + // The JIT treats this as a platform constant. + => BitConverter.IsLittleEndian + ? UpdateSlicingBy8LittleEndian(crc, source) + : UpdateSlicingBy8Portable(crc, source); + + private static uint UpdateSlicingBy8LittleEndian( + uint crc, + ReadOnlySpan source) + { + ref byte sourceRef = ref MemoryMarshal.GetReference(source); + ref uint tableRef = ref SCrcLookup[0]; + + int offset = 0; + int length = source.Length; + + /* + * Two-block unrolling reduces loop bookkeeping. + * + * The two CRC operations are still dependent, so larger + * unrolling generally provides diminishing returns. + */ + while (length >= 16) + { + ulong block0 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref sourceRef, offset)); + ulong block1 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref sourceRef, offset + 8)); + crc = UpdateSlicingBy8Block(crc, block0, ref tableRef); + crc = UpdateSlicingBy8Block(crc, block1, ref tableRef); + + offset += 16; + length -= 16; + } + + if (length >= 8) + { + ulong block = Unsafe.ReadUnaligned(ref Unsafe.Add(ref sourceRef, offset)); + crc = UpdateSlicingBy8Block(crc, block, ref tableRef); + offset += 8; + length -= 8; + } + + // Process the remaining 0–7 bytes. + while (length != 0) + { + byte value = Unsafe.Add(ref sourceRef, offset); + byte index = (byte)((crc >> 24) ^ value); + crc = (crc << 8) ^ Unsafe.Add(ref tableRef, index); + offset++; + length--; + } + + return crc; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint UpdateSlicingBy8Block( + uint crc, + ulong block, + ref uint table) + { + /* + * A little-endian ulong load gives: + * + * bits 0–7 = source[0] + * bits 8–15 = source[1] + * ... + * bits 56–63 = source[7] + * + * ReverseEndianness converts source[0..3] into the + * big-endian uint required by the non-reflected CRC. + */ + uint first = crc ^ BinaryPrimitives.ReverseEndianness((uint)block); + return Unsafe.Add(ref table, 0 * 256 + (byte)(block >> 56)) ^ + Unsafe.Add(ref table, 1 * 256 + (byte)(block >> 48)) ^ + Unsafe.Add(ref table, 2 * 256 + (byte)(block >> 40)) ^ + Unsafe.Add(ref table, 3 * 256 + (byte)(block >> 32)) ^ + Unsafe.Add(ref table, 4 * 256 + (byte)first) ^ + Unsafe.Add(ref table, 5 * 256 + (byte)(first >> 8)) ^ + Unsafe.Add(ref table, 6 * 256 + (byte)(first >> 16)) ^ + Unsafe.Add(ref table, 7 * 256 + (byte)(first >> 24)); + } + + private static uint UpdateSlicingBy8Portable( + uint crc, + ReadOnlySpan source) + { + ref byte sourceRef = ref MemoryMarshal.GetReference(source); + ref uint tableRef = ref SCrcLookup[0]; + + int offset = 0; + int length = source.Length; + + while (length >= 8) + { + uint first = crc ^ + ((uint)Unsafe.Add(ref sourceRef, offset) << 24) ^ + ((uint)Unsafe.Add(ref sourceRef, offset + 1) << 16) ^ + ((uint)Unsafe.Add(ref sourceRef, offset + 2) << 8) ^ + Unsafe.Add(ref sourceRef, offset + 3); + + crc = Unsafe.Add(ref tableRef, 0 * 256 + Unsafe.Add(ref sourceRef, offset + 7)) ^ + Unsafe.Add(ref tableRef, 1 * 256 + Unsafe.Add(ref sourceRef, offset + 6)) ^ + Unsafe.Add(ref tableRef, 2 * 256 + Unsafe.Add(ref sourceRef, offset + 5)) ^ + Unsafe.Add(ref tableRef, 3 * 256 + Unsafe.Add(ref sourceRef, offset + 4)) ^ + Unsafe.Add(ref tableRef, 4 * 256 + (byte)first) ^ + Unsafe.Add(ref tableRef, 5 * 256 + (byte)(first >> 8)) ^ + Unsafe.Add(ref tableRef, 6 * 256 + (byte)(first >> 16)) ^ + Unsafe.Add(ref tableRef, 7 * 256 + (byte)(first >> 24)); + + offset += 8; + length -= 8; + } + + while (length != 0) + { + byte index = (byte)((crc >> 24) ^ Unsafe.Add(ref sourceRef, offset)); + crc = (crc << 8) ^ Unsafe.Add(ref tableRef, index); + offset++; + length--; + } + + return crc; + } + + private static uint[] CreateSlicingBy8Lookup() + { + uint[] table = new uint[8 * 256]; + + // T0: CRC of one byte in the most-significant position. + for (uint value = 0; value < 256; value++) + { + uint crc = value << 24; + for (int bit = 0; bit < 8; bit++) + { + crc = (crc & 0x80000000u) != 0 ? (crc << 1) ^ Polynomial : crc << 1; + } + + table[value] = crc; + } + + /* + * For a non-reflected, left-shifting CRC: + * + * T[n][x] = advance T[n - 1][x] by one zero byte. + */ + for (int slice = 1; slice < 8; slice++) + { + int previousOffset = (slice - 1) * 256; + int currentOffset = slice * 256; + + for (int value = 0; value < 256; value++) + { + uint crc = table[previousOffset + value]; + table[currentOffset + value] = (crc << 8) ^ table[(byte)(crc >> 24)]; + } + } + + return table; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static uint UpdateByte(uint crc, byte value) + { + ref uint table = ref SCrcLookup[0]; + + byte index = (byte)((crc >> 24) ^ value); + return (crc << 8) ^ Unsafe.Add(ref table, index); + } +} + +public sealed class BZip2Crc32 : NonCryptographicHashAlgorithm +{ + private uint _crc = BZip2Crc32Premul.InitialState; + + public BZip2Crc32() + : base(BZip2Crc32Premul.HashSize) + { + } + + private BZip2Crc32(uint crc) + : base(BZip2Crc32Premul.HashSize) + { + _crc = crc; + } + + public BZip2Crc32 Clone() => new(_crc); + + public void AppendByte(byte value) => _crc = BZip2Crc32Premul.UpdateByte(_crc, value); + + public override void Append(ReadOnlySpan source) => _crc = Update(_crc, source); + + public override void Reset() => _crc = BZip2Crc32Premul.InitialState; + + protected override void GetCurrentHashCore(Span destination) => BinaryPrimitives.WriteUInt32BigEndian(destination, ~_crc); + + protected override void GetHashAndResetCore(Span destination) + { + BinaryPrimitives.WriteUInt32BigEndian(destination, ~_crc); + _crc = BZip2Crc32Premul.InitialState; + } + + public uint GetCurrentHashAsUInt32() => ~_crc; + + private static uint Update(uint crc, ReadOnlySpan source) + { +#if NET6_0_OR_GREATER + if (BitConverter.IsLittleEndian && + Pclmulqdq.IsSupported && + Ssse3.IsSupported && + source.Length >= BZip2Crc32Premul.PclmulThreshold) + { + return BZip2Crc32Premul.UpdatePclmul(crc, source); + } +#endif + + return BZip2Crc32Premul.UpdateSlicingBy8(crc, source); + } +} \ No newline at end of file diff --git a/SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Exception.cs b/SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Exception.cs new file mode 100644 index 0000000..4971ee2 --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Exception.cs @@ -0,0 +1,54 @@ +using System; +using System.Runtime.Serialization; + +namespace SharpHDiffPatch.New.IO.Compression.BZip2; + +/// +/// BZip2Exception represents exceptions specific to BZip2 classes and code. +/// +[Serializable] +public class BZip2Exception : Exception +{ + /// + /// Initialise a new instance of . + /// + public BZip2Exception() + { + } + + /// + /// Initialise a new instance of with its message string. + /// + /// A that describes the error. + public BZip2Exception(string message) + : base(message) + { + } + + /// + /// Initialise a new instance of . + /// + /// A that describes the error. + /// The that caused this exception. + public BZip2Exception(string message, Exception innerException) + : base(message, innerException) + { + } + + /// + /// Initializes a new instance of the BZip2Exception class with serialized data. + /// + /// + /// The System.Runtime.Serialization.SerializationInfo that holds the serialized + /// object data about the exception being thrown. + /// + /// + /// The System.Runtime.Serialization.StreamingContext that contains contextual information + /// about the source or destination. + /// + [Obsolete("Obsolete")] + protected BZip2Exception(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } +} \ No newline at end of file diff --git a/SharpHDiffPatch.New/IO/Compression/BZip2/BZip2InputStream.cs b/SharpHDiffPatch.New/IO/Compression/BZip2/BZip2InputStream.cs new file mode 100644 index 0000000..4edafda --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/BZip2/BZip2InputStream.cs @@ -0,0 +1,1321 @@ +using System; +using System.Buffers; +using System.IO; +using System.Numerics; +using System.Runtime.CompilerServices; + +// ReSharper disable CommentTypo + +namespace SharpHDiffPatch.New.IO.Compression.BZip2; + +/// +/// An input stream that decompresses files in the BZip2 format. +/// +public sealed class BZip2InputStream : Stream +{ + private const int InputBufferSize = 32 << 10; + private const int MaximumHuffmanLength = 20; + private const int AlphaTableStride = BZip2Constants.MaximumAlphaSize; + private const int CodeTableStride = BZip2Constants.MaximumCodeLength; + + private readonly bool _decompressConcatenated; + private readonly bool _leaveOpen; + private readonly Stream _baseStream; + + // Buffer compressed input. The original implementation called Stream.ReadByte() + // for every compressed byte, which is particularly expensive for unbuffered streams. + private readonly byte[] _inputBuffer; + private int _inputOffset; + private int _inputCount; + + private int _last; + private int _blockSize100K; + private bool _blockRandomised; + + private uint _bsBuff; + private int _bsLive; + + private readonly BZip2Crc32 _nCrc32 = new(); + + private readonly byte[] _seqToUnseq; + private byte[] _selector; + + // Reused per block. This removes the allocations previously made by + // ReceiveDecodingTables() and GetAndMoveToFrontDecode(). + private byte[] _yy; + private readonly byte[] _codeLengths; + + private int[] _tt = []; + private byte[] _ll8 = []; + private ushort[] _perm; + + private readonly int[] _unZfTab; + private readonly int[] _limit = new int[BZip2Constants.GroupCount * CodeTableStride]; + private readonly int[] _baseArray = new int[BZip2Constants.GroupCount * CodeTableStride]; + private readonly byte[] _minLens = new byte[BZip2Constants.GroupCount]; + + private bool _streamEnd; + private bool _blockEndPending; + private int _currentChar = -1; + + private BZip2Constants.DecodeState _currentState = BZip2Constants.DecodeState.StartBlock; + + private uint _storedBlockCrc; + private uint _computedCombinedCrc; + + private byte _count; + private ushort _chPrev; + private ushort _ch2; + private int _tPos; + private ushort _rNToGo; + private ushort _rTPos; + private int _i2; + private byte _j2; + private byte _z; + + private readonly int _inputBufferCapacity; + private bool _disposed; + + private static long TryGetStreamLength(Stream stream) + { + try + { + return stream.Length; + } + catch + { + return -1; + } + } + + public BZip2InputStream(Stream stream, bool decompressConcatenated, bool leaveOpen = false) + { + if (stream == null!) + { + throw new ArgumentNullException(nameof(stream)); + } + + _baseStream = stream; + _decompressConcatenated = decompressConcatenated; + _leaveOpen = leaveOpen; + + try + { + long streamLength = TryGetStreamLength(stream); + _inputBufferCapacity = + streamLength is > 0 and < InputBufferSize + ? (int)streamLength + : InputBufferSize; + + _yy = ArrayPool.Shared.Rent(256); + _seqToUnseq = ArrayPool.Shared.Rent(256); + _unZfTab = ArrayPool.Shared.Rent(256); + _inputBuffer = ArrayPool.Shared.Rent(_inputBufferCapacity); + _selector = ArrayPool.Shared.Rent(BZip2Constants.MaximumSelectors); + _codeLengths = ArrayPool.Shared.Rent(BZip2Constants.GroupCount * AlphaTableStride); + _perm = ArrayPool.Shared.Rent(BZip2Constants.GroupCount * AlphaTableStride); + + Initialize(); + + if (_streamEnd) + { + return; + } + + int origPtr = InitBlock(); + if (!_streamEnd) + { + SetupBlock(origPtr); + } + } + catch + { + ReturnPooledBuffers(); + throw; + } + } + + protected override void Dispose(bool disposing) + { + if (_disposed) + { + base.Dispose(disposing); + return; + } + + _disposed = true; + + ReturnPooledBuffers(); + + if (disposing && IsStreamOwner && !_leaveOpen) + { + _baseStream.Dispose(); + } + + base.Dispose(disposing); + } + + private void ReturnPooledBuffers() + { + if (_yy.Length != 0) ArrayPool.Shared.Return(_yy); + if (_inputBuffer.Length != 0) ArrayPool.Shared.Return(_inputBuffer); + if (_selector.Length != 0) ArrayPool.Shared.Return(_selector); + if (_codeLengths.Length != 0) ArrayPool.Shared.Return(_codeLengths); + if (_perm.Length != 0) ArrayPool.Shared.Return(_perm); + if (_ll8.Length != 0) ArrayPool.Shared.Return(_ll8); + if (_tt.Length != 0) ArrayPool.Shared.Return(_tt); + if (_unZfTab.Length != 0) ArrayPool.Shared.Return(_unZfTab); + if (_seqToUnseq.Length != 0) ArrayPool.Shared.Return(_seqToUnseq); + } + + public bool IsStreamOwner { get; set; } = true; + + public override bool CanRead => _baseStream.CanRead; + public override bool CanSeek => false; + public override bool CanWrite => false; + public override long Length => _baseStream.Length; + + public override long Position + { + get => throw new NotSupportedException("Cannot get the position of the compressed data"); + set => throw new NotSupportedException("BZip2InputStream position cannot be set"); + } + + public override void Flush() => _baseStream.Flush(); + + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException("BZip2InputStream Seek not supported"); + + public override void SetLength(long value) => throw new NotSupportedException("BZip2InputStream SetLength not supported"); + + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException("BZip2InputStream Write not supported"); + + public override void WriteByte(byte value) => throw new NotSupportedException("BZip2InputStream WriteByte not supported"); + + public override int Read(byte[] buffer, int offset, int count) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + + if ((uint)offset > (uint)buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + + return (uint)count > (uint)(buffer.Length - offset) + ? throw new ArgumentOutOfRangeException(nameof(count)) + : ReadCore(buffer.AsSpan(offset, count)); + } + +#if NET6_0_OR_GREATER + public override int Read(Span buffer) => ReadCore(buffer); +#endif + + private int ReadCore(Span destination) + { + int written = 0; + int crcStart = 0; + + // Huffman decoding and inverse-BWT traversal are inherently serial, but the + // second RLE stage frequently exposes byte runs. Emit those runs in bulk and + // feed the CRC one span at a time instead of one byte at a time. + while (written < destination.Length && !_streamEnd) + { + if (_blockEndPending) + { + AppendCrc(destination.Slice(crcStart, written - crcStart)); + crcStart = written; + FinishBlock(); + continue; + } + + if (_currentState is BZip2Constants.DecodeState.NoRandPartC + or BZip2Constants.DecodeState.RandPartC) + { + int available = _z - _j2 + 1; // Includes the already prepared current byte. + int toWrite = Math.Min(available, destination.Length - written); + + destination.Slice(written, toWrite).Fill((byte)_currentChar); + written += toWrite; + + if (toWrite < available) + { + // Leave the next repeated byte prepared for the following Read(). + _j2 += (byte)toWrite; + break; + } + + if (_currentState == BZip2Constants.DecodeState.RandPartC) + { + CompleteRandPartC(); + } + else + { + CompleteNoRandPartC(); + } + + continue; + } + + destination[written++] = (byte)_currentChar; + AdvanceState(); + } + + AppendCrc(destination.Slice(crcStart, written - crcStart)); + + // Match the old implementation's timing: consuming the final byte of a block + // also validates that block and prepares the next one before Read() returns. + if (_blockEndPending) + { + FinishBlock(); + } + + return written; + } + + public override int ReadByte() + { + if (_streamEnd) + { + return -1; + } + + int value = _currentChar; + _nCrc32.AppendByte((byte)value); + AdvanceState(); + + if (_blockEndPending) + { + FinishBlock(); + } + + return value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AppendCrc(ReadOnlySpan source) + { + if (!source.IsEmpty) + { + _nCrc32.Append(source); + } + } + + private void FinishBlock() + { + _blockEndPending = false; + EndBlock(); + + int origPtr = InitBlock(); + if (!_streamEnd) + { + SetupBlock(origPtr); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AdvanceState() + { + switch (_currentState) + { + case BZip2Constants.DecodeState.RandPartB: + SetupRandPartB(); + break; + + case BZip2Constants.DecodeState.RandPartC: + SetupRandPartC(); + break; + + case BZip2Constants.DecodeState.NoRandPartB: + SetupNoRandPartB(); + break; + + case BZip2Constants.DecodeState.NoRandPartC: + SetupNoRandPartC(); + break; + + case BZip2Constants.DecodeState.StartBlock: + case BZip2Constants.DecodeState.RandPartA: + case BZip2Constants.DecodeState.NoRandPartA: + break; + } + } + + private void Initialize() + { + int magic1 = BsR(8); + int magic2 = BsR(8); + int magic3 = BsR(8); + int magic4 = BsR(8); + + if (magic1 != 'B' || + magic2 != 'Z' || + magic3 != 'h' || + magic4 < '1' || + magic4 > '9') + { + _streamEnd = true; + return; + } + + SetDecompressStructureSizes(magic4 - '0'); + _computedCombinedCrc = 0; + } + + private int InitBlock() + { + int origPtr = 0; + while (true) + { + int magic1 = BsR(8); + int magic2 = BsR(8); + int magic3 = BsR(8); + int magic4 = BsR(8); + int magic5 = BsR(8); + int magic6 = BsR(8); + + if (magic1 == 0x17 && magic2 == 0x72 && magic3 == 0x45 && + magic4 == 0x38 && magic5 == 0x50 && magic6 == 0x90) + { + if (Complete()) + { + return origPtr; + } + + // Complete() consumed the next member's BZh header. Continue by + // reading that member's first block marker. + continue; + } + + if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59 || + magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) + { + BadBlockHeader(); + } + + _storedBlockCrc = unchecked((uint)BsGetInt32()); + _blockRandomised = BsR1() != 0; + + origPtr = GetAndMoveToFrontDecode(); + + _nCrc32.Reset(); + _currentState = BZip2Constants.DecodeState.StartBlock; + return origPtr; + } + } + + private void EndBlock() + { + uint computedBlockCrc = _nCrc32.GetCurrentHashAsUInt32(); + if (_storedBlockCrc != computedBlockCrc) + { + CrcError(); + } + + _computedCombinedCrc = + BitOperations.RotateLeft(_computedCombinedCrc, 1) ^ + computedBlockCrc; + } + + private bool Complete() + { + if (unchecked((uint)BsGetInt32()) != _computedCombinedCrc) + { + CrcError(); + } + + if (!_decompressConcatenated) + { + // Bulk input may have prefetched data following the first member. Restore + // the underlying position when possible so callers can continue reading it. + RewindUnreadInput(); + _streamEnd = true; + return true; + } + + // Each bzip2 member is padded to the next byte boundary. At this point the + // remaining bits in the cache are only that padding. + _bsBuff = 0; + _bsLive = 0; + + if (TryInitializeNextMember()) return false; + + _streamEnd = true; + return true; + } + + private bool TryInitializeNextMember() + { + if (!TryReadCompressedByte(out int magic1)) + { + return false; + } + + int magic2 = ReadCompressedByte(); + int magic3 = ReadCompressedByte(); + int magic4 = ReadCompressedByte(); + + if (magic1 != 'B' || + magic2 != 'Z' || + magic3 != 'h') + { + throw new BZip2Exception("Unexpected data after a valid BZip2 stream"); + } + + if (magic4 is < '1' or > '9') + { + throw new BZip2Exception("Invalid BZip2 block size"); + } + + SetDecompressStructureSizes(magic4 - '0'); + _computedCombinedCrc = 0; + return true; + } + + private void RewindUnreadInput() + { + int unread = _inputCount - _inputOffset; + if (unread != 0 && _baseStream.CanSeek) + { + _baseStream.Seek(-unread, SeekOrigin.Current); + } + + _inputOffset = 0; + _inputCount = 0; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void FillBuffer() + { + _bsBuff = (_bsBuff << 8) | (uint)ReadCompressedByte(); + _bsLive += 8; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int ReadCompressedByte() + { + if (!TryReadCompressedByte(out int value)) + { + CompressedStreamEof(); + } + + return value; + } + + private bool TryReadCompressedByte(out int value) + { + if (_inputOffset >= _inputCount) + { + // A non-seekable stream must not be read past the end of the first member + // when concatenation is disabled. Seekable streams are rewound in Complete(). + int requested = _blockSize100K == 0 || + (!_decompressConcatenated && !_baseStream.CanSeek) + ? 1 + : _inputBufferCapacity; + + _inputCount = _baseStream.Read(_inputBuffer, 0, requested); + _inputOffset = 0; + + if (_inputCount <= 0) + { + value = -1; + return false; + } + } + + value = _inputBuffer[_inputOffset++]; + return true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int BsR1() + { + if (_bsLive == 0) FillBuffer(); + return (int)((_bsBuff >> --_bsLive) & 1u); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int BsR(int bitCount) + { + while (_bsLive < bitCount) + { + FillBuffer(); + } + + int shift = _bsLive - bitCount; + uint mask = (1u << bitCount) - 1u; + int value = (int)((_bsBuff >> shift) & mask); + _bsLive = shift; + return value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int BsGetInt32() => (BsR(16) << 16) | BsR(16); + +#if NET6_0_OR_GREATER + [SkipLocalsInit] +#endif + private void ReceiveDecodingTables(out int nInUse, + out int alphaSize, + out int selectorCount) + { + nInUse = 0; + + // The format stores sixteen group-presence bits followed by sixteen symbol + // bits for every present group. Reading them in 16-bit chunks removes up to + // 272 calls to BsR1() per block. + int inUse16 = BsR(16); + for (int group = 0; group < 16; group++) + { + if ((inUse16 & (0x8000 >> group)) == 0) + { + continue; + } + + int inUseGroup = BsR(16); + int symbolBase = group << 4; + + while (inUseGroup != 0) + { + int bit = BitOperations.LeadingZeroCount((uint)inUseGroup) - 16; + _seqToUnseq[nInUse++] = (byte)(symbolBase + bit); + + inUseGroup &= ~(0x8000 >> bit); + } + } + + int nGroups = BsR(3); + alphaSize = nInUse + 2; + selectorCount = BsR(15); + + if (nGroups < 2 || nGroups > BZip2Constants.GroupCount || + selectorCount < 1 || selectorCount > BZip2Constants.MaximumSelectors) + { + DataError(); + } + + Span selectorPositionInitial = [0, 1, 2, 3, 4, 5]; + + // Decode selector MTF values immediately, avoiding selectorMtf[] entirely. + for (int i = 0; i < selectorCount; i++) + { + int selectorMtf = 0; + while (BsR1() != 0) + { + selectorMtf++; + if (selectorMtf >= nGroups) + { + DataError(); + } + } + + ref byte selectorPosition = ref selectorPositionInitial[0]; + byte selected = Unsafe.Add(ref selectorPosition, selectorMtf); + + while (selectorMtf != 0) + { + Unsafe.Add(ref selectorPosition, selectorMtf) = + Unsafe.Add(ref selectorPosition, selectorMtf - 1); + + selectorMtf--; + } + + selectorPosition = selected; + _selector[i] = selected; + } + + for (int table = 0; table < nGroups; table++) + { + int alphaOffset = table * AlphaTableStride; + int currentLength = BsR(5); + + for (int symbol = 0; symbol < alphaSize; symbol++) + { + while (BsR1() != 0) + { + currentLength += BsR1() == 0 ? 1 : -1; + if ((uint)(currentLength - 1) >= MaximumHuffmanLength) + { + DataError(); + } + } + + if ((uint)(currentLength - 1) >= MaximumHuffmanLength) + { + DataError(); + } + + _codeLengths[alphaOffset + symbol] = (byte)currentLength; + } + } + + for (int table = 0; table < nGroups; table++) + { + int alphaOffset = table * AlphaTableStride; + int minLength = MaximumHuffmanLength; + int maxLength = 0; + + ref byte codeLength = + ref Unsafe.Add(ref _codeLengths[0], alphaOffset); + + int remaining = alphaSize; + + while (remaining != 0) + { + int length = codeLength; + + minLength = Math.Min(minLength, length); + maxLength = Math.Max(maxLength, length); + + codeLength = ref Unsafe.Add(ref codeLength, 1); + remaining--; + } + + HbCreateDecodeTables(table, minLength, maxLength, alphaSize); + + _minLens[table] = (byte)minLength; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int DecodeNextSymbol( + ref int groupNumber, + ref int groupPosition, + int selectorCount, + int alphaSize) + { + if (groupPosition == 0) + { + int nextGroup = groupNumber + 1; + if ((uint)nextGroup >= (uint)selectorCount) + { + DataError(); + } + + groupNumber = nextGroup; + groupPosition = BZip2Constants.GroupSize; + } + + groupPosition--; + + ref byte selectorRef = ref _selector[0]; + int table = Unsafe.Add(ref selectorRef, groupNumber); + + int codeOffset = table * CodeTableStride; + int alphaOffset = table * AlphaTableStride; + + ref int limitRef = ref _limit[0]; + ref int baseRef = ref _baseArray[0]; + ref ushort permRef = ref _perm[0]; + ref byte minRef = ref _minLens[0]; + + int codeLength = Unsafe.Add(ref minRef, table); + int codeBits = BsR(codeLength); + + while (codeBits > Unsafe.Add(ref limitRef, codeOffset + codeLength)) + { + if (codeLength >= MaximumHuffmanLength) + { + DataError(); + } + + codeLength++; + codeBits = (codeBits << 1) | BsR1(); + } + + int permIndex = codeBits - Unsafe.Add(ref baseRef, codeOffset + codeLength); + if ((uint)permIndex >= (uint)alphaSize) + { + DataError(); + } + + return Unsafe.Add(ref permRef, alphaOffset + permIndex); + } + + private int GetAndMoveToFrontDecode() + { + int blockCapacity = BZip2Constants.BaseBlockSize * _blockSize100K; + int origPtr = BsR(24); + + ReceiveDecodingTables(out int nInUse, + out int alphaSize, + out int selectorCount); + + int endOfBlock = nInUse + 1; + int groupNumber = -1; + int groupPosition = 0; + + BZip2Constants.IdentityMtf.CopyTo(_yy); + + _last = -1; + int nextSymbol = DecodeNextSymbol(ref groupNumber, ref groupPosition, selectorCount, alphaSize); + + while (nextSymbol != endOfBlock) + { + if (nextSymbol is BZip2Constants.RunA or BZip2Constants.RunB) + { + int runLength = -1; + int runPower = 1; + + do + { + if (runPower > blockCapacity) + { + BlockOverrun(); + } + + runLength += nextSymbol == BZip2Constants.RunA + ? runPower + : runPower << 1; + + runPower <<= 1; + nextSymbol = DecodeNextSymbol(ref groupNumber, ref groupPosition, selectorCount, alphaSize); + } + while (nextSymbol is BZip2Constants.RunA or BZip2Constants.RunB); + + runLength++; + int runStart = _last + 1; + + if (nInUse == 0 || runLength < 0 || runLength > blockCapacity - runStart) + { + BlockOverrun(); + } + + byte value = _seqToUnseq[_yy[0]]; + _unZfTab[value] += runLength; + + // Span.Fill is lowered to an optimized bulk fill by modern runtimes + // and uses SIMD when profitable. System.Memory supplies it on netstandard2.0. + _ll8.AsSpan(runStart, runLength).Fill(value); + _last += runLength; + continue; + } + + int mtfIndex = nextSymbol - 1; + if ((uint)mtfIndex >= (uint)nInUse) + { + DataError(); + } + + int nextIndex = _last + 1; + if (nextIndex >= blockCapacity) + { + BlockOverrun(); + } + + byte mtfValue = _yy[mtfIndex]; + byte valueAtIndex = _seqToUnseq[mtfValue]; + + _last = nextIndex; + _unZfTab[valueAtIndex]++; + _ll8[nextIndex] = valueAtIndex; + + if (mtfIndex != 0) + { + // Small MTF indexes dominate normal data, and a short scalar move avoids + // the fixed cost of entering the runtime copy helper. Larger moves use + // overlap-safe memmove, whose implementation selects the best CPU path. + if (mtfIndex <= 16) + { + ref byte yy = ref _yy[0]; + + int moveIndex = mtfIndex; + do + { + Unsafe.Add(ref yy, moveIndex) = Unsafe.Add(ref yy, moveIndex - 1); + } + while (--moveIndex != 0); + } + else + { + _yy.AsSpan(0, mtfIndex).CopyTo(_yy.AsSpan(1)); + } + + _yy[0] = mtfValue; + } + + nextSymbol = DecodeNextSymbol(ref groupNumber, ref groupPosition, selectorCount, alphaSize); + } + + return origPtr; + } + +#if NET6_0_OR_GREATER + [SkipLocalsInit] +#endif + private void SetupBlock(int origPtr) + { + int last = _last; + + if (last < 0 || (uint)origPtr > (uint)last) + { + DataError(); + } + + Span cumulativeFrequency = stackalloc int[257]; + + ref int frequency = ref cumulativeFrequency[0]; + ref int counts = ref _unZfTab[0]; + + frequency = 0; + int cumulative = 0; + + for (int symbol = 0; symbol < 256; symbol++) + { + ref int count = ref Unsafe.Add(ref counts, symbol); + + cumulative += count; + Unsafe.Add(ref frequency, symbol + 1) = cumulative; + + count = 0; + } + + int length = last + 1; + if (length >= 256 * 1024) + { + BuildTransformationTable4Way(cumulativeFrequency, length); + } + else + { + BuildTransformationTableScalar(cumulativeFrequency, length); + } + + _tPos = _tt[origPtr]; + _count = 0; + _i2 = 0; + _ch2 = 256; + + if (_blockRandomised) + { + _rNToGo = 0; + _rTPos = 0; + SetupRandPartA(); + } + else + { + SetupNoRandPartA(); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void BuildTransformationTableScalar( + Span cumulativeFrequency, + int length) + { + ref byte source = ref _ll8[0]; + ref int destination = ref _tt[0]; + ref int cursors = ref cumulativeFrequency[0]; + + ref byte current = ref source; + + int index = 0; + int remaining = length; + + while (remaining != 0) + { + byte value = current; + ref int cursor = ref Unsafe.Add(ref cursors, value); + + Unsafe.Add(ref destination, cursor) = index; + cursor++; + + current = ref Unsafe.Add(ref current, 1); + index++; + remaining--; + } + } + +#if NET6_0_OR_GREATER + [SkipLocalsInit] +#endif + private void BuildTransformationTable4Way( + Span cumulativeFrequency, + int length) + { + const int symbolCount = 256; + const int chunkCount = 4; + + // 4 × 256 local histograms and 4 × 256 independent cursors. + Span chunkCounts = stackalloc int[chunkCount * symbolCount]; + Span chunkCursors = stackalloc int[chunkCount * symbolCount]; +#if NET6_0_OR_GREATER + chunkCounts.Clear(); +#endif + + int chunkSize = length / chunkCount; + + const int start0 = 0; + int start2 = chunkSize * 2; + int start3 = chunkSize * 3; + + ref byte ll8 = ref _ll8[0]; + ref int counts = ref chunkCounts[0]; + + // First pass: calculate one histogram per contiguous chunk. + CountChunk(ref ll8, start0, chunkSize, ref Unsafe.Add(ref counts, 0 * symbolCount)); + CountChunk(ref ll8, chunkSize, start2, ref Unsafe.Add(ref counts, 1 * symbolCount)); + CountChunk(ref ll8, start2, start3, ref Unsafe.Add(ref counts, 2 * symbolCount)); + CountChunk(ref ll8, start3, length, ref Unsafe.Add(ref counts, 3 * symbolCount)); + + ref int globalStart = ref cumulativeFrequency[0]; + ref int cursors = ref chunkCursors[0]; + + // Assign a disjoint output range to each chunk for every symbol. + for (int symbol = 0; symbol < symbolCount; symbol++) + { + int position = Unsafe.Add(ref globalStart, symbol); + Unsafe.Add(ref cursors, 0 * symbolCount + symbol) = position; + position += Unsafe.Add(ref counts, 0 * symbolCount + symbol); + Unsafe.Add(ref cursors, 1 * symbolCount + symbol) = position; + position += Unsafe.Add(ref counts, 1 * symbolCount + symbol); + Unsafe.Add(ref cursors, 2 * symbolCount + symbol) = position; + position += Unsafe.Add(ref counts, 2 * symbolCount + symbol); + Unsafe.Add(ref cursors, 3 * symbolCount + symbol) = position; + } + + ref int tt = ref _tt[0]; + + // The four scatter loops no longer share cursor state. + ScatterChunk(ref ll8, ref tt, start0, chunkSize, ref Unsafe.Add(ref cursors, 0 * symbolCount)); + ScatterChunk(ref ll8, ref tt, chunkSize, start2, ref Unsafe.Add(ref cursors, 1 * symbolCount)); + ScatterChunk(ref ll8, ref tt, start2, start3, ref Unsafe.Add(ref cursors, 2 * symbolCount)); + ScatterChunk(ref ll8, ref tt, start3, length, ref Unsafe.Add(ref cursors, 3 * symbolCount)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void CountChunk( + ref byte source, + int start, + int end, + ref int counts) + { + ref byte current = ref Unsafe.Add(ref source, start); + int remaining = end - start; + + while (remaining >= 4) + { + byte value0 = current; + byte value1 = Unsafe.Add(ref current, 1); + byte value2 = Unsafe.Add(ref current, 2); + byte value3 = Unsafe.Add(ref current, 3); + + Unsafe.Add(ref counts, value0)++; + Unsafe.Add(ref counts, value1)++; + Unsafe.Add(ref counts, value2)++; + Unsafe.Add(ref counts, value3)++; + + current = ref Unsafe.Add(ref current, 4); + remaining -= 4; + } + + while (remaining != 0) + { + Unsafe.Add(ref counts, current)++; + current = ref Unsafe.Add(ref current, 1); + remaining--; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void ScatterChunk( + ref byte source, + ref int destination, + int start, + int end, + ref int cursors) + { + ref byte current = ref Unsafe.Add(ref source, start); + + int index = start; + int remaining = end - start; + + while (remaining != 0) + { + byte value = current; + ref int cursor = ref Unsafe.Add(ref cursors, value); + + Unsafe.Add(ref destination, cursor) = index; + cursor++; + + current = ref Unsafe.Add(ref current, 1); + index++; + remaining--; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetupRandPartA() + { + if (_i2 <= _last) + { + _chPrev = _ch2; + _ch2 = _ll8[_tPos]; + _tPos = _tt[_tPos]; + + if (_rNToGo == 0) + { + _rNToGo = BZip2Constants.RandomNumbers[_rTPos++]; + if (_rTPos == 512) + { + _rTPos = 0; + } + } + + _rNToGo--; + _ch2 ^= (ushort)(_rNToGo == 1 ? 1 : 0); + _i2++; + + _currentChar = _ch2; + _currentState = BZip2Constants.DecodeState.RandPartB; + + return; + } + + _currentState = BZip2Constants.DecodeState.StartBlock; + _blockEndPending = true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetupNoRandPartA() + { + if (_i2 <= _last) + { + _chPrev = _ch2; + _ch2 = _ll8[_tPos]; + _tPos = _tt[_tPos]; + _i2++; + + _currentChar = _ch2; + _currentState = BZip2Constants.DecodeState.NoRandPartB; + return; + } + + _currentState = BZip2Constants.DecodeState.StartBlock; + _blockEndPending = true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetupRandPartB() + { + if (_ch2 != _chPrev) + { + _currentState = BZip2Constants.DecodeState.RandPartA; + _count = 1; + SetupRandPartA(); + return; + } + + _count++; + if (_count < 4) + { + _currentState = BZip2Constants.DecodeState.RandPartA; + SetupRandPartA(); + return; + } + + _z = _ll8[_tPos]; + _tPos = _tt[_tPos]; + + if (_rNToGo == 0) + { + _rNToGo = BZip2Constants.RandomNumbers[_rTPos++]; + if (_rTPos == 512) + { + _rTPos = 0; + } + } + + _rNToGo--; + _z ^= (byte)(_rNToGo == 1 ? 1 : 0); + _j2 = 0; + _currentState = BZip2Constants.DecodeState.RandPartC; + SetupRandPartC(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetupRandPartC() + { + if (_j2 < _z) + { + _currentChar = _ch2; + _j2++; + return; + } + + CompleteRandPartC(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CompleteRandPartC() + { + _currentState = BZip2Constants.DecodeState.RandPartA; + _i2++; + _count = 0; + SetupRandPartA(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetupNoRandPartB() + { + if (_ch2 != _chPrev) + { + _currentState = BZip2Constants.DecodeState.NoRandPartA; + _count = 1; + SetupNoRandPartA(); + return; + } + + _count++; + if (_count < 4) + { + _currentState = BZip2Constants.DecodeState.NoRandPartA; + SetupNoRandPartA(); + return; + } + + _z = _ll8[_tPos]; + _tPos = _tt[_tPos]; + _currentState = BZip2Constants.DecodeState.NoRandPartC; + _j2 = 0; + SetupNoRandPartC(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetupNoRandPartC() + { + if (_j2 < _z) + { + _currentChar = _ch2; + _j2++; + return; + } + + CompleteNoRandPartC(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CompleteNoRandPartC() + { + _i2++; + _currentState = BZip2Constants.DecodeState.NoRandPartA; + _count = 0; + SetupNoRandPartA(); + } + + private void SetDecompressStructureSizes(int newSize100K) + { + if ((uint)(newSize100K - 1) >= 9) + { + throw new BZip2Exception("Invalid block size"); + } + + _blockSize100K = newSize100K; + int requiredLength = BZip2Constants.BaseBlockSize * newSize100K; + + if (_ll8.Length >= requiredLength && _tt.Length >= requiredLength) + { + return; + } + + byte[] newLl8 = ArrayPool.Shared.Rent(requiredLength); + int[] newTt = ArrayPool.Shared.Rent(requiredLength); + + byte[] oldLl8 = _ll8; + int[] oldTt = _tt; + + _ll8 = newLl8; + _tt = newTt; + + if (oldLl8.Length != 0) ArrayPool.Shared.Return(oldLl8); + if (oldTt.Length != 0) ArrayPool.Shared.Return(oldTt); + } + +#if NET6_0_OR_GREATER + [SkipLocalsInit] +#endif + private void HbCreateDecodeTables( + int table, + int minLength, + int maxLength, + int alphaSize) + { + int codeOffset = table * CodeTableStride; + int alphaOffset = table * AlphaTableStride; + + Span lengthCounts = stackalloc int[CodeTableStride]; +#if NET6_0_OR_GREATER + lengthCounts.Clear(); +#endif + + ref int countRef = ref lengthCounts[0]; + ref byte lengthsRef = ref Unsafe.Add(ref _codeLengths[0], alphaOffset); + + for (int symbol = 0; symbol < alphaSize; symbol++) + { + int length = Unsafe.Add(ref lengthsRef, symbol); + Unsafe.Add(ref countRef, length)++; + } + + Span positions = stackalloc int[CodeTableStride]; + + ref int positionRef = ref positions[0]; + int permutationIndex = alphaOffset; + + for (int length = minLength; length <= maxLength; length++) + { + Unsafe.Add(ref positionRef, length) = permutationIndex; + permutationIndex += Unsafe.Add(ref countRef, length); + } + + ref ushort permRef = ref _perm[0]; + + // Stable scatter preserves ascending symbol order within each length. + for (int symbol = 0; symbol < alphaSize; symbol++) + { + int length = Unsafe.Add(ref lengthsRef, symbol); + ref int position = ref Unsafe.Add(ref positionRef, length); + + Unsafe.Add(ref permRef, position++) = (ushort)symbol; + } + + // Build baseArray directly from the already available counts. + ref int baseRef = ref Unsafe.Add(ref _baseArray[0], codeOffset); + + baseRef = 0; + + for (int length = 1; length < CodeTableStride; length++) + { + Unsafe.Add(ref baseRef, length) = Unsafe.Add(ref baseRef, length - 1) + Unsafe.Add(ref countRef, length - 1); + } + + ref int limitRef = ref Unsafe.Add(ref _limit[0], codeOffset); + int code = 0; + for (int length = minLength; length <= maxLength; length++) + { + code += Unsafe.Add(ref baseRef, length + 1) - Unsafe.Add(ref baseRef, length); + Unsafe.Add(ref limitRef, length) = code - 1; + code <<= 1; + } + + for (int length = minLength + 1; length <= maxLength; length++) + { + Unsafe.Add(ref baseRef, length) = ((Unsafe.Add(ref limitRef, length - 1) + 1) << 1) - Unsafe.Add(ref baseRef, length); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void CompressedStreamEof() => throw new EndOfStreamException("BZip2 input stream end of compressed stream"); + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void BlockOverrun() => throw new BZip2Exception("BZip2 input stream block overrun"); + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void BadBlockHeader() => throw new BZip2Exception("BZip2 input stream bad block header"); + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void CrcError() => throw new BZip2Exception("BZip2 input stream crc error"); + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void DataError() => throw new BZip2Exception("Bzip data error"); +} \ No newline at end of file diff --git a/SharpHDiffPatch.New/IO/Compression/BZip2/LICENSE b/SharpHDiffPatch.New/IO/Compression/BZip2/LICENSE new file mode 100644 index 0000000..2021420 --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/BZip2/LICENSE @@ -0,0 +1,17 @@ +Copyright © 2000-2018 SharpZipLib Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/SharpHDiffPatch.New/IO/Compression/BZip2/README.md b/SharpHDiffPatch.New/IO/Compression/BZip2/README.md new file mode 100644 index 0000000..402803f --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/BZip2/README.md @@ -0,0 +1,23 @@ +# Attention +This implementation of BZip2InputStream has been heavily modified from the original SharpZipLib implementation and is more optimized. +The original implementation can be found [here](https://github.com/icsharpcode/SharpZipLib/tree/master/src/ICSharpCode.SharpZipLib/BZip2) + +## Benchmark result +File: UnityPlayer.dll.bz2 (The UnityPlayer.dll file was originated from Honkai Impact 3rd (Mainland China server) v8.9.0, compressed with BZip2) +Size: 12,869,917 bytes compressed (30,144,408 bytes uncompressed) +Uncompressed File Hash: 7D0B8178 (CRC32) + +| Method | Mean | Error | StdDev | Allocated | +|------------------------- |---------:|--------:|--------:|-----------:| +| BZip2InputStreamModified | 661.7 ms | 3.29 ms | 2.91 ms | 1.38 KB | +| BZip2InputStreamOld | 738.1 ms | 2.29 ms | 2.15 ms | 5481.11 KB | + +Hardware Bench: +- CPU: AMD Ryzen 7 9800X3D +- Memory: G.Skill Ripjaws M5 64GB (32x2) DDR5-6000 CL36-36-36-96 + +Big credits to the original authors of SharpZipLib for their work on BZip2 decompression. +- [Mike Krüger](http://www.icsharpcode.net/pub/relations/krueger.aspx) +- John Reilly +- David Pierson +- Neil McNeight \ No newline at end of file diff --git a/SharpHDiffPatch.New/IO/Compression/CompressionStreamHelper.cs b/SharpHDiffPatch.New/IO/Compression/CompressionStreamHelper.cs new file mode 100644 index 0000000..ef5ff35 --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/CompressionStreamHelper.cs @@ -0,0 +1,102 @@ +// ReSharper disable IdentifierTypo +// ReSharper disable ConvertSwitchStatementToSwitchExpression +// ReSharper disable CommentTypo +// ReSharper disable InconsistentNaming + +#if NET6_0_OR_GREATER +using System.Collections.Generic; +using ZstdNet; +#endif + +using System; +using System.IO; +using System.IO.Compression; +using System.Runtime.InteropServices; +using SharpHDiffPatch.New.Header; +using SharpHDiffPatch.New.IO.Compression.BZip2; +using SharpHDiffPatch.New.IO.Compression.Lzma; +#if NETSTANDARD2_0_OR_GREATER || NET6_0_OR_GREATER +using ZstdManagedDecompressor = ZstdSharp.Decompressor; +using ZstdManagedDecompressorParameter = ZstdSharp.Unsafe.ZSTD_dParameter; +using ZstdManagedStream = ZstdSharp.DecompressionStream; +#endif + +#if !NETSTANDARD2_0_OR_GREATER +using ZstdNativeDecompressor = ZstdNet.DecompressionOptions; +using ZstdNativeDecompressorParameter = ZstdNet.ZSTD_dParameter; +using ZstdNativeStream = ZstdNet.DecompressionStream; +#endif + +namespace SharpHDiffPatch.New.IO.Compression; + +internal static class DecompressStreamFactory +{ + private delegate Stream ZstdStreamFallback(Stream stream, bool leaveOpen); + private static ZstdStreamFallback? _createZstdStreamFallback; + private static readonly int ZstdWindowLogMax = Environment.Is64BitProcess ? 31 : 30; + + internal static Stream CreateStream( + HDiffCompression type, + Stream sourceStream, + bool leaveOpen) + { + return type switch + { + HDiffCompression.Uncompressed => sourceStream, + HDiffCompression.Zstd => CreateZstdStream(sourceStream, leaveOpen), + HDiffCompression.Zlib => new DeflateStream(sourceStream, CompressionMode.Decompress, leaveOpen), + HDiffCompression.BZ2 => new BZip2InputStream(sourceStream, false, leaveOpen), + HDiffCompression.PBZ2 => new BZip2InputStream(sourceStream, true, leaveOpen), + HDiffCompression.Lzma or HDiffCompression.Lzma2 => CreateLzmaStream(sourceStream, leaveOpen), + _ => throw new NotSupportedException($"[PatchCore::GetDecompressStreamPlugin] Compression Type: {type} is not supported") + }; + } + + private static Stream CreateZstdStream(Stream rawStream, bool leaveOpen) + { + if (_createZstdStreamFallback != null) return _createZstdStreamFallback(rawStream, leaveOpen); + +#if !(NETSTANDARD2_0_OR_GREATER || NET461_OR_GREATER) + if (DllUtils.IsLibraryExist(DllUtils.DllName)) + _createZstdStreamFallback = CreateZstdNativeStream; + else + _createZstdStreamFallback = CreateZstdManagedStream; +#else + _createZstdStreamFallback = CreateZstdManagedStream; +#endif + return _createZstdStreamFallback(rawStream, leaveOpen); + } + + /* HACK: The default window log max size is 30. This is unacceptable since the native HPatch implementation + * always use 31 as the size_t, which is 8 bytes length. + * + * Code Snippets (decompress_plugin_demo.h:963): + * #define _ZSTD_WINDOWLOG_MAX ((sizeof(size_t)<=4)?30:31) + */ +#if !NETSTANDARD2_0_OR_GREATER + private static Stream CreateZstdNativeStream(Stream rawStream, bool leaveOpen) => + new ZstdNativeStream(rawStream, new ZstdNativeDecompressor(null, new Dictionary + { + { ZstdNativeDecompressorParameter.ZSTD_d_windowLogMax, ZstdWindowLogMax } + })); +#endif + + private static Stream CreateZstdManagedStream(Stream rawStream, bool leaveOpen) + { + ZstdManagedDecompressor decompressor = new(); + decompressor.SetParameter(ZstdManagedDecompressorParameter.ZSTD_d_windowLogMax, ZstdWindowLogMax); + return new ZstdManagedStream(rawStream, decompressor, 16 << 10, leaveOpen: leaveOpen); + } + + private static Stream CreateLzmaStream(Stream rawStream, bool leaveOpen) + { + int propLen = rawStream.ReadByte(); + if (propLen != 5) return new LzmaInputStream([(byte)propLen], rawStream, leaveOpen); // Get LZMA2 if propLen != 5 + + // Get LZMA if propLen == 5 + byte[] props = new byte[propLen]; + _ = rawStream.Read(props, 0, propLen); + int dicSize = MemoryMarshal.Read(props.AsSpan(1)); + return new LzmaInputStream(props, rawStream, -1, -1, rawStream, false, leaveOpen); + } +} diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/LICENSE.txt b/SharpHDiffPatch.New/IO/Compression/Lzma/LICENSE.txt new file mode 100644 index 0000000..94e2f5b --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/Lzma/LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Adam Hathcock + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/LZ/LzOutWindow.cs b/SharpHDiffPatch.New/IO/Compression/Lzma/LZ/LzOutWindow.cs new file mode 100644 index 0000000..fc55a50 --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/Lzma/LZ/LzOutWindow.cs @@ -0,0 +1,268 @@ +using System; +using System.Buffers; +using System.Runtime.CompilerServices; + +namespace SharpHDiffPatch.New.IO.Compression.Lzma.LZ; + +internal class OutWindow : IDisposable +{ + private byte[] _buffer = []; + private int _windowSize; + private int _pos; + private int _streamPos; + private int _pendingLen; + private int _pendingDist; + private System.IO.Stream _stream; + + public long Total; + public long Limit; + + public void Create(int windowSize) + { + if (_buffer.Length < windowSize) + { + ReturnPooledBuffer(); + _buffer = ArrayPool.Shared.Rent(windowSize); + } + + _buffer[windowSize - 1] = 0; + _windowSize = windowSize; + _pos = 0; + _streamPos = 0; + _pendingLen = 0; + Total = 0; + Limit = 0; + } + + public void Reset() => Create(_windowSize); + + public void Init(System.IO.Stream stream) + { + ReleaseStream(); + _stream = stream; + } + + public void Train(System.IO.Stream stream) + { + long len = stream.Length; + int size = len < _windowSize ? (int)len : _windowSize; + stream.Position = len - size; + + Total = 0; + Limit = size; + _pos = _windowSize - size; + CopyStream(stream, size); + + if (_pos == _windowSize) + { + _pos = 0; + } + _streamPos = _pos; + } + + public void ReleaseStream() + { + Flush(); + _stream = null; + } + + public void Flush() + { + if (_stream is null) + { + return; + } + int size = _pos - _streamPos; + if (size == 0) + { + return; + } + + _stream.Write(_buffer, _streamPos, size); + if (_pos >= _windowSize) + { + _pos = 0; + } + + _streamPos = _pos; + } + + public void CopyBlock(int distance, int len) + { + int remaining = len; + int source = _pos - distance - 1; + if (source < 0) + { + source += _windowSize; + } + + while (remaining > 0 && _pos < _windowSize && Total < Limit) + { + int copySize = Math.Min(remaining, _windowSize - _pos); + long available = Limit - Total; + if (copySize > available) + { + copySize = (int)available; + } + + ref byte buffer = ref _buffer[0]; + int beforeWrap = Math.Min(copySize, _windowSize - source); + CopyBytes(ref buffer, source, _pos, beforeWrap); + source += beforeWrap; + _pos += beforeWrap; + + int afterWrap = copySize - beforeWrap; + if (afterWrap > 0) + { + source = 0; + CopyBytes(ref buffer, source, _pos, afterWrap); + source += afterWrap; + _pos += afterWrap; + } + + remaining -= copySize; + Total += copySize; + if (_pos >= _windowSize) + { + Flush(); + } + } + + _pendingLen = remaining; + _pendingDist = distance; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe void CopyBytes(ref byte buffer, int sourceOffset, int destinationOffset, int count) + { + ref byte source = ref Unsafe.Add(ref buffer, sourceOffset); + ref byte destination = ref Unsafe.Add(ref buffer, destinationOffset); + + bool isNonOverlapping = sourceOffset + count <= destinationOffset || destinationOffset + count <= sourceOffset; + + if (count >= 16 && isNonOverlapping) + { + ReadOnlySpan sourceSpan = new(Unsafe.AsPointer(ref source), count); + Span destinationSpan = new(Unsafe.AsPointer(ref destination), count); + + sourceSpan.CopyTo(destinationSpan); + return; + } + + ref byte destinationEnd = ref Unsafe.Add(ref destination, count); + while (Unsafe.IsAddressLessThan(ref destination, ref destinationEnd)) + { + destination = source; + source = ref Unsafe.Add(ref source, 1); + destination = ref Unsafe.Add(ref destination, 1); + } + } + + public void PutByte(byte b) + { + _buffer[_pos++] = b; + Total++; + + if (_pos >= _windowSize) + { + Flush(); + } + } + + public byte GetByte(int distance) + { + int pos = _pos - distance - 1; + if (pos < 0) + { + pos += _windowSize; + } + return _buffer[pos]; + } + + public int CopyStream(System.IO.Stream stream, int len) + { + int size = len; + while (size > 0 && _pos < _windowSize && Total < Limit) + { + int curSize = _windowSize - _pos; + if (curSize > Limit - Total) + { + curSize = (int)(Limit - Total); + } + + if (curSize > size) + { + curSize = size; + } + + int numReadBytes = stream.Read(_buffer, _pos, curSize); + if (numReadBytes == 0) + { + throw new LzmaDataErrorException(); + } + + size -= numReadBytes; + _pos += numReadBytes; + Total += numReadBytes; + if (_pos >= _windowSize) + { + Flush(); + } + } + return len - size; + } + + public void SetLimit(long size) => Limit = Total + size; + + public bool HasSpace => _pos < _windowSize && Total < Limit; + + public bool HasPending => _pendingLen > 0; + + public int Read(byte[] buffer, int offset, int count) + { + if (_streamPos >= _pos) + { + return 0; + } + + int size = _pos - _streamPos; + if (size > count) + { + size = count; + } + + _buffer.AsSpan(_streamPos, size).CopyTo(buffer.AsSpan(offset, size)); + _streamPos += size; + if (_streamPos < _windowSize) return size; + + _pos = 0; + _streamPos = 0; + return size; + } + + public void CopyPending() + { + if (_pendingLen > 0) + { + CopyBlock(_pendingDist, _pendingLen); + } + } + + public int AvailableBytes => _pos - _streamPos; + + public void Dispose() + { + ReleaseStream(); + ReturnPooledBuffer(); + } + + private void ReturnPooledBuffer() + { + byte[] buffer = _buffer; + _buffer = []; + if (buffer.Length != 0) + { + ArrayPool.Shared.Return(buffer); + } + } +} \ No newline at end of file diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/LzmaBase.cs b/SharpHDiffPatch.New/IO/Compression/Lzma/LzmaBase.cs new file mode 100644 index 0000000..c047eb9 --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/Lzma/LzmaBase.cs @@ -0,0 +1,70 @@ +namespace SharpHDiffPatch.New.IO.Compression.Lzma; + +internal abstract class Base +{ + public const uint KNumStates = 12; + + public struct State + { + public uint Index; + + public void Init() => Index = 0; + + public void UpdateChar() + { + switch (Index) + { + case < 4: + Index = 0; + break; + case < 10: + Index -= 3; + break; + default: + Index -= 6; + break; + } + } + + public void UpdateMatch() => Index = (uint)(Index < 7 ? 7 : 10); + + public void UpdateRep() => Index = (uint)(Index < 7 ? 8 : 11); + + public void UpdateShortRep() => Index = (uint)(Index < 7 ? 9 : 11); + + public bool IsCharState() => Index < 7; + } + + public const int KNumPosSlotBits = 6; + + public const int KNumLenToPosStatesBits = 2; // it's for speed optimization + public const uint KNumLenToPosStates = 1 << KNumLenToPosStatesBits; + + public const uint KMatchMinLen = 2; + + public static uint GetLenToPosState(uint len) + { + len -= KMatchMinLen; + if (len < KNumLenToPosStates) + { + return len; + } + return KNumLenToPosStates - 1; + } + + public const int KNumAlignBits = 4; + + public const uint KStartPosModelIndex = 4; + public const uint KEndPosModelIndex = 14; + + public const uint KNumFullDistances = 1 << ((int)KEndPosModelIndex / 2); + + public const int KNumPosStatesBitsMax = 4; + public const uint KNumPosStatesMax = 1 << KNumPosStatesBitsMax; + + public const int KNumLowLenBits = 3; + public const int KNumMidLenBits = 3; + public const int KNumHighLenBits = 8; + public const uint KNumLowLenSymbols = 1 << KNumLowLenBits; + public const uint KNumMidLenSymbols = 1 << KNumMidLenBits; +} \ No newline at end of file diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/LzmaDecoder.cs b/SharpHDiffPatch.New/IO/Compression/Lzma/LzmaDecoder.cs new file mode 100644 index 0000000..4973456 --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/Lzma/LzmaDecoder.cs @@ -0,0 +1,459 @@ +using System; +using System.Buffers; +using System.Runtime.CompilerServices; +using SharpHDiffPatch.New.IO.Compression.Lzma.LZ; +using SharpHDiffPatch.New.IO.Compression.Lzma.RangeCoder; + +namespace SharpHDiffPatch.New.IO.Compression.Lzma; + +internal class Decoder : IDisposable +{ + private class LenDecoder : IDisposable + { + private const int KLowModelsCount = (int)Base.KNumPosStatesMax << Base.KNumLowLenBits; + private const int KMidModelsOffset = KLowModelsCount; + private const int KHighModelsOffset = KMidModelsOffset + ((int)Base.KNumPosStatesMax << Base.KNumMidLenBits); + private const int KModelsCount = KHighModelsOffset + (1 << Base.KNumHighLenBits); + + private BitDecoder _choice; + private BitDecoder _choice2; + private BitDecoder[] _models = []; + private uint _numPosStates; + + public void Create(uint numPosStates) + { + if (_models.Length == 0) + { + _models = ArrayPool.Shared.Rent(KModelsCount); + } + _numPosStates = numPosStates; + } + + public void Init() + { + _choice.Init(); + _choice2.Init(); + + int activeLowModels = (int)_numPosStates << Base.KNumLowLenBits; + int activeMidModels = (int)_numPosStates << Base.KNumMidLenBits; + BitDecoder.Init(_models, 0, activeLowModels); + BitDecoder.Init(_models, KMidModelsOffset, activeMidModels); + BitDecoder.Init(_models, KHighModelsOffset, 1 << Base.KNumHighLenBits); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint Decode(RangeDecoder rangeDecoder, uint posState) + { + if (_choice.Decode(rangeDecoder) == 0) + { + int modelOffset = (int)posState << Base.KNumLowLenBits; + return BitTreeDecoder.Decode(_models, modelOffset, rangeDecoder, Base.KNumLowLenBits); + } + + uint symbol = Base.KNumLowLenSymbols; + if (_choice2.Decode(rangeDecoder) == 0) + { + int modelOffset = KMidModelsOffset + ((int)posState << Base.KNumMidLenBits); + symbol += BitTreeDecoder.Decode(_models, modelOffset, rangeDecoder, Base.KNumMidLenBits); + } + else + { + symbol += Base.KNumMidLenSymbols; + symbol += BitTreeDecoder.Decode(_models, KHighModelsOffset, rangeDecoder, Base.KNumHighLenBits); + } + return symbol; + } + + public void Dispose() + { + BitDecoder[] models = _models; + _models = []; + _numPosStates = 0; + + if (models.Length != 0) + { + ArrayPool.Shared.Return(models); + } + } + } + + private class LiteralDecoder : IDisposable + { + private const int KNumModelsPerState = 0x300; + + private BitDecoder[] _coders; + private int _modelCount; + private int _numPrevBits; + private int _numPosBits; + private uint _posMask; + + public void Create(int numPosBits, int numPrevBits) + { + if (_coders != null && _numPrevBits == numPrevBits && _numPosBits == numPosBits) + { + return; + } + + _numPosBits = numPosBits; + _posMask = ((uint)1 << numPosBits) - 1; + _numPrevBits = numPrevBits; + + int numStates = 1 << (_numPrevBits + _numPosBits); + int modelCount = checked(numStates * KNumModelsPerState); + + ReturnModels(); + _coders = ArrayPool.Shared.Rent(modelCount); + _modelCount = modelCount; + } + + public void Init() => BitDecoder.Init(_coders, 0, _modelCount); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private uint GetState(uint pos, byte prevByte) => ((pos & _posMask) << _numPrevBits) + (uint)(prevByte >> (8 - _numPrevBits)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte DecodeNormal(RangeDecoder rangeDecoder, uint pos, byte prevByte) + { + ref BitDecoder decoders = ref Unsafe.Add( + ref _coders[0], + (int)GetState(pos, prevByte) * KNumModelsPerState); + uint symbol = 1; + do + { + symbol = (symbol << 1) | Unsafe.Add(ref decoders, (int)symbol).Decode(rangeDecoder); + } while (symbol < 0x100); + return unchecked((byte)symbol); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte DecodeWithMatchByte( + RangeDecoder rangeDecoder, + uint pos, + byte prevByte, + byte matchByte) + { + ref BitDecoder decoders = ref Unsafe.Add( + ref _coders[0], + (int)GetState(pos, prevByte) * KNumModelsPerState); + uint symbol = 1; + do + { + uint matchBit = (uint)(matchByte >> 7) & 1; + matchByte <<= 1; + + int modelIndex = (int)(((1 + matchBit) << 8) + symbol); + uint bit = Unsafe.Add(ref decoders, modelIndex).Decode(rangeDecoder); + symbol = (symbol << 1) | bit; + + if (matchBit == bit) continue; + + while (symbol < 0x100) + { + symbol = (symbol << 1) | Unsafe.Add(ref decoders, (int)symbol).Decode(rangeDecoder); + } + break; + } while (symbol < 0x100); + return unchecked((byte)symbol); + } + + public void Dispose() => ReturnModels(); + + private void ReturnModels() + { + if (_coders == null) return; + + ArrayPool.Shared.Return(_coders); + _coders = null; + _modelCount = 0; + } + } + + private OutWindow _outWindow; + + private const int KStatePosModelsCount = (int)Base.KNumStates << Base.KNumPosStatesBitsMax; + private const int KStateModelsCount = (int)Base.KNumStates; + private const int KIsMatchOffset = 0; + private const int KIsRepOffset = KIsMatchOffset + KStatePosModelsCount; + private const int KIsRepG0Offset = KIsRepOffset + KStateModelsCount; + private const int KIsRepG1Offset = KIsRepG0Offset + KStateModelsCount; + private const int KIsRepG2Offset = KIsRepG1Offset + KStateModelsCount; + private const int KIsRep0LongOffset = KIsRepG2Offset + KStateModelsCount; + private const int KPosDecodersOffset = KIsRep0LongOffset + KStatePosModelsCount; + private const int KPosDecodersCount = (int)(Base.KNumFullDistances - Base.KEndPosModelIndex); + private const int KPosSlotModelsOffset = KPosDecodersOffset + KPosDecodersCount; + private const int KPosSlotModelsCount = (int)Base.KNumLenToPosStates << Base.KNumPosSlotBits; + private const int KPosAlignModelsOffset = KPosSlotModelsOffset + KPosSlotModelsCount; + private const int KModelsCount = KPosAlignModelsOffset + (1 << Base.KNumAlignBits); + + private BitDecoder[] _models = ArrayPool.Shared.Rent(KModelsCount); + private readonly LenDecoder _lenDecoder = new(); + private readonly LenDecoder _repLenDecoder = new(); + private readonly LiteralDecoder _literalDecoder = new(); + + private int _dictionarySize = -1; + + private uint _posStateMask; + + private Base.State _state; + private uint _rep0, _rep1, _rep2, _rep3; + + private void CreateDictionary() + { + if (_dictionarySize < 0) + { + throw new LzmaInvalidParamException(); + } + _outWindow = new OutWindow(); + int blockSize = Math.Max(_dictionarySize, 1 << 12); + _outWindow.Create(blockSize); + } + + private void SetLiteralProperties(int lp, int lc) + { + if (lp > 8 || lc > 8) + { + throw new LzmaInvalidParamException(); + } + + _literalDecoder.Create(lp, lc); + } + + private void SetPosBitsProperties(int pb) + { + if (pb > Base.KNumPosStatesBitsMax) + { + throw new LzmaInvalidParamException(); + } + + uint numPosStates = (uint)1 << pb; + _lenDecoder.Create(numPosStates); + _repLenDecoder.Create(numPosStates); + _posStateMask = numPosStates - 1; + } + + private void Init() + { + BitDecoder.Init(_models, 0, KModelsCount); + + _literalDecoder.Init(); + _lenDecoder.Init(); + _repLenDecoder.Init(); + + _state.Init(); + _rep0 = 0; + _rep1 = 0; + _rep2 = 0; + _rep3 = 0; + } + + public void Code( + System.IO.Stream inStream, + System.IO.Stream outStream, + long inSize, + long outSize) + { + if (_outWindow is null) + { + CreateDictionary(); + } + + if (_outWindow != null) + { + _outWindow.Init(outStream); + if (outSize > 0) + { + _outWindow.SetLimit(outSize); + } + else + { + _outWindow.SetLimit(long.MaxValue - _outWindow.Total); + } + + RangeDecoder rangeDecoder = new(); + rangeDecoder.Init(inStream, inSize); + + Code(_dictionarySize, _outWindow, rangeDecoder); + + _outWindow.Dispose(); + rangeDecoder.Dispose(); + } + + _outWindow = null; + } + + internal bool Code(int dictionarySize, OutWindow outWindow, RangeDecoder rangeDecoder) + { + int dictionarySizeCheck = Math.Max(dictionarySize, 1); + + outWindow.CopyPending(); + + ref BitDecoder models = ref _models[0]; + ref BitDecoder isMatchDecoders = ref Unsafe.Add(ref models, KIsMatchOffset); + ref BitDecoder isRepDecoders = ref Unsafe.Add(ref models, KIsRepOffset); + ref BitDecoder isRepG0Decoders = ref Unsafe.Add(ref models, KIsRepG0Offset); + ref BitDecoder isRepG1Decoders = ref Unsafe.Add(ref models, KIsRepG1Offset); + ref BitDecoder isRepG2Decoders = ref Unsafe.Add(ref models, KIsRepG2Offset); + ref BitDecoder isRep0LongDecoders = ref Unsafe.Add(ref models, KIsRep0LongOffset); + + while (outWindow.HasSpace) + { + uint posState = (uint)outWindow.Total & _posStateMask; + int stateIndex = (int)_state.Index; + int statePosIndex = (stateIndex << Base.KNumPosStatesBitsMax) + (int)posState; + + if (Unsafe.Add(ref isMatchDecoders, statePosIndex).Decode(rangeDecoder) == 0) + { + byte prevByte = outWindow.GetByte(0); + byte b = !_state.IsCharState() + ? _literalDecoder.DecodeWithMatchByte(rangeDecoder, (uint)outWindow.Total, prevByte, outWindow.GetByte((int)_rep0)) + : _literalDecoder.DecodeNormal(rangeDecoder, (uint)outWindow.Total, prevByte); + + outWindow.PutByte(b); + _state.UpdateChar(); + } + else + { + uint len; + if (Unsafe.Add(ref isRepDecoders, stateIndex).Decode(rangeDecoder) == 1) + { + if (Unsafe.Add(ref isRepG0Decoders, stateIndex).Decode(rangeDecoder) == 0) + { + if (Unsafe.Add(ref isRep0LongDecoders, statePosIndex).Decode(rangeDecoder) == 0) + { + _state.UpdateShortRep(); + outWindow.PutByte(outWindow.GetByte((int)_rep0)); + continue; + } + } + else + { + uint distance; + if (Unsafe.Add(ref isRepG1Decoders, stateIndex).Decode(rangeDecoder) == 0) + { + distance = _rep1; + } + else + { + if (Unsafe.Add(ref isRepG2Decoders, stateIndex).Decode(rangeDecoder) == 0) + { + distance = _rep2; + } + else + { + distance = _rep3; + _rep3 = _rep2; + } + _rep2 = _rep1; + } + _rep1 = _rep0; + _rep0 = distance; + } + len = _repLenDecoder.Decode(rangeDecoder, posState) + Base.KMatchMinLen; + _state.UpdateRep(); + } + else + { + _rep3 = _rep2; + _rep2 = _rep1; + _rep1 = _rep0; + + len = Base.KMatchMinLen + _lenDecoder.Decode(rangeDecoder, posState); + _state.UpdateMatch(); + + int posSlotOffset = KPosSlotModelsOffset + ((int)Base.GetLenToPosState(len) << Base.KNumPosSlotBits); + uint posSlot = BitTreeDecoder.Decode(_models, posSlotOffset, rangeDecoder, Base.KNumPosSlotBits); + if (posSlot >= Base.KStartPosModelIndex) + { + int numDirectBits = (int)((posSlot >> 1) - 1); + _rep0 = (2 | (posSlot & 1)) << numDirectBits; + + if (posSlot < Base.KEndPosModelIndex) + { + _rep0 += BitTreeDecoder.ReverseDecode( + _models, + KPosDecodersOffset + _rep0 - posSlot - 1, + rangeDecoder, + numDirectBits + ); + } + else + { + _rep0 += rangeDecoder.DecodeDirectBits(numDirectBits - Base.KNumAlignBits) << Base.KNumAlignBits; + _rep0 += BitTreeDecoder.ReverseDecode( + _models, + KPosAlignModelsOffset, + rangeDecoder, + Base.KNumAlignBits); + } + } + else + { + _rep0 = posSlot; + } + } + if (_rep0 >= outWindow.Total || _rep0 >= dictionarySizeCheck) + { + return _rep0 == 0xFFFFFFFF + ? true + : throw new LzmaDataErrorException(); + } + outWindow.CopyBlock((int)_rep0, (int)len); + } + } + return false; + } + + public void SetDecoderProperties(byte[] properties) + { + if (properties.Length < 1) + { + throw new LzmaInvalidParamException(); + } + + int lc = properties[0] % 9; + int remainder = properties[0] / 9; + int lp = remainder % 5; + int pb = remainder / 5; + if (pb > Base.KNumPosStatesBitsMax) + { + throw new LzmaInvalidParamException(); + } + + SetLiteralProperties(lp, lc); + SetPosBitsProperties(pb); + Init(); + + if (properties.Length < 5) return; + + _dictionarySize = 0; + for (int i = 0; i < 4; i++) + { + _dictionarySize += properties[1 + i] << (i * 8); + } + } + + public void Train(System.IO.Stream stream) + { + if (_outWindow is null) + { + CreateDictionary(); + } + + _outWindow?.Train(stream); + } + + public void Dispose() + { + BitDecoder[] models = _models; + _models = []; + + _lenDecoder.Dispose(); + _repLenDecoder.Dispose(); + _literalDecoder.Dispose(); + + if (models.Length != 0) + { + ArrayPool.Shared.Return(models); + } + } +} diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/LzmaExceptions.cs b/SharpHDiffPatch.New/IO/Compression/Lzma/LzmaExceptions.cs new file mode 100644 index 0000000..2c7a5f5 --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/Lzma/LzmaExceptions.cs @@ -0,0 +1,13 @@ +using System; + +namespace SharpHDiffPatch.New.IO.Compression.Lzma; + +/// +/// The exception that is thrown when an error in input stream occurs during decoding. +/// +internal class LzmaDataErrorException() : Exception("Data Error"); + +/// +/// The exception that is thrown when the value of an argument is outside the allowable range. +/// +internal class LzmaInvalidParamException() : Exception("Invalid Parameter"); \ No newline at end of file diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/LzmaInputStream.cs b/SharpHDiffPatch.New/IO/Compression/Lzma/LzmaInputStream.cs new file mode 100644 index 0000000..534d720 --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/Lzma/LzmaInputStream.cs @@ -0,0 +1,287 @@ +using System; +using System.Buffers.Binary; +using System.IO; +using SharpHDiffPatch.New.IO.Compression.Lzma.LZ; +using SharpHDiffPatch.New.IO.Compression.Lzma.RangeCoder; + +namespace SharpHDiffPatch.New.IO.Compression.Lzma; + +public sealed class LzmaInputStream : Stream +{ + private readonly Stream _inputStream; + private readonly long _inputSize; + private readonly long _outputSize; + + private readonly int _dictionarySize; + private readonly OutWindow _outWindow = new(); + private readonly RangeDecoder _rangeDecoder = new(); + private Decoder _decoder; + + private long _position; + private bool _endReached; + private long _availableBytes; + private long _rangeDecoderLimit; + private long _inputPosition; + + // LZMA2 + private readonly bool _isLzma2; + private readonly bool _leaveOpen; + + private bool _uncompressedChunk; + private bool _needDictReset = true; + private bool _needProps = true; + private bool _isDisposed; + + public LzmaInputStream(byte[] properties, Stream inputStream, bool leaveOpen = false) + : this(properties, inputStream, -1, -1, null, properties.Length < 5, leaveOpen) { } + + public LzmaInputStream(byte[] properties, Stream inputStream, long inputSize, bool leaveOpen = false) + : this(properties, inputStream, inputSize, -1, null, properties.Length < 5, leaveOpen) { } + + public LzmaInputStream(byte[] properties, Stream inputStream, long inputSize, long outputSize, bool leaveOpen = false) + : this(properties, inputStream, inputSize, outputSize, null, properties.Length < 5, leaveOpen) { } + + public LzmaInputStream( + byte[] properties, + Stream inputStream, + long inputSize, + long outputSize, + Stream presetDictionary, + bool isLzma2, + bool leaveOpen = false) + { + _inputStream = inputStream; + _inputSize = inputSize; + _outputSize = outputSize; + _isLzma2 = isLzma2; + _leaveOpen = leaveOpen; + + if (!isLzma2) + { + _dictionarySize = BinaryPrimitives.ReadInt32LittleEndian(properties.AsSpan(1)); + _outWindow.Create(_dictionarySize); + if (presetDictionary != null) + { + _outWindow.Train(presetDictionary); + } + + _rangeDecoder.Init(inputStream, inputSize); + + _decoder = new Decoder(); + _decoder.SetDecoderProperties(properties); + Properties = properties; + + _availableBytes = outputSize < 0 ? long.MaxValue : outputSize; + _rangeDecoderLimit = inputSize; + } + else + { + _dictionarySize = 2 | (properties[0] & 1); + _dictionarySize <<= (properties[0] >> 1) + 11; + + _outWindow.Create(_dictionarySize); + if (presetDictionary != null) + { + _outWindow.Train(presetDictionary); + _needDictReset = false; + } + + Properties = new byte[1]; + _availableBytes = 0; + } + } + + public override bool CanRead => true; + + public override bool CanSeek => false; + + public override bool CanWrite => false; + + public override void Flush() { } + + protected override void Dispose(bool disposing) + { + if (_isDisposed) + { + return; + } + + _isDisposed = true; + _decoder?.Dispose(); + _rangeDecoder.Dispose(); + _outWindow.Dispose(); + + if (disposing && !_leaveOpen) + { + _inputStream?.Dispose(); + } + base.Dispose(disposing); + } + + public override long Length => _position + _availableBytes; + + public override long Position + { + get => _position; + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (_endReached) + { + return 0; + } + + int total = 0; + while (total < count) + { + if (_availableBytes == 0) + { + if (_isLzma2) + { + DecodeChunkHeader(); + } + else + { + _endReached = true; + } + if (_endReached) + { + break; + } + } + + int toProcess = count - total; + if (toProcess > _availableBytes) + { + toProcess = (int)_availableBytes; + } + + _outWindow.SetLimit(toProcess); + if (_uncompressedChunk) + { + _inputPosition += _outWindow.CopyStream(_inputStream, toProcess); + } + else if (_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder) && _outputSize < 0) + { + _availableBytes = _outWindow.AvailableBytes; + } + + int read = _outWindow.Read(buffer, offset, toProcess); + total += read; + offset += read; + _position += read; + _availableBytes -= read; + + if (_availableBytes != 0 || _uncompressedChunk) continue; + + // Check range corruption scenario + if (!_rangeDecoder.IsFinished || (_rangeDecoderLimit >= 0 && _rangeDecoder.Total != _rangeDecoderLimit)) + { + // Stream might have End Of Stream marker + _outWindow.SetLimit(toProcess + 1); + if (!_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder)) + { + _rangeDecoder.ReleaseStream(); + throw new LzmaDataErrorException(); + } + } + + _rangeDecoder.ReleaseStream(); + _inputPosition += _rangeDecoder.Total; + if (_outWindow.HasPending) + { + throw new LzmaDataErrorException(); + } + } + + if (!_endReached) return total; + if ((_inputSize >= 0 && _inputPosition != _inputSize) || (_outputSize >= 0 && _position != _outputSize)) + { + throw new LzmaDataErrorException(); + } + + return total; + } + + private void DecodeChunkHeader() + { + int control = _inputStream.ReadByte(); + _inputPosition++; + + switch (control) + { + case 0x00: + _endReached = true; + return; + case >= 0xE0: + case 0x01: + _needProps = true; + _needDictReset = false; + _outWindow.Reset(); + break; + default: + { + if (_needDictReset) + { + throw new LzmaDataErrorException(); + } + + break; + } + } + + switch (control) + { + case >= 0x80: + { + _uncompressedChunk = false; + + _availableBytes = (control & 0x1F) << 16; + _availableBytes += (_inputStream.ReadByte() << 8) + _inputStream.ReadByte() + 1; + _inputPosition += 2; + + _rangeDecoderLimit = (_inputStream.ReadByte() << 8) + _inputStream.ReadByte() + 1; + _inputPosition += 2; + + if (control >= 0xC0) + { + _needProps = false; + Properties[0] = (byte)_inputStream.ReadByte(); + _inputPosition++; + + _decoder ??= new Decoder(); + _decoder.SetDecoderProperties(Properties); + } + else if (_needProps) + { + throw new LzmaDataErrorException(); + } + else if (control >= 0xA0) + { + _decoder ??= new Decoder(); + _decoder.SetDecoderProperties(Properties); + } + + _rangeDecoder.Init(_inputStream, _rangeDecoderLimit); + break; + } + case > 0x02: + throw new LzmaDataErrorException(); + default: + _uncompressedChunk = true; + _availableBytes = (_inputStream.ReadByte() << 8) + _inputStream.ReadByte() + 1; + _inputPosition += 2; + break; + } + } + + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); + + public override void SetLength(long value) => throw new NotSupportedException(); + + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); + + public byte[] Properties { get; } +} \ No newline at end of file diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/README.md b/SharpHDiffPatch.New/IO/Compression/Lzma/README.md new file mode 100644 index 0000000..d0609ca --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/Lzma/README.md @@ -0,0 +1,18 @@ +# Attention +This implementation of LzmaStream has been heavily modified from the original managed-lzma and sharpcompress implementation and is more optimized. +The original implementation can be found [here](https://github.com/adamhathcock/sharpcompress/tree/master/src/SharpCompress/Compressors/LZMA) + +## Benchmark result +| Method | Mean | Error | StdDev | Ratio | Gen0 | Gen1 | Allocated | Alloc Ratio | +|--------- |---------:|---------:|---------:|------:|-------:|-------:|----------:|------------:| +| Lzma2New | 23.75 us | 0.197 us | 0.165 us | 0.72 | 0.1526 | - | 8.23 KB | 0.17 | +| Lzma2Old | 33.17 us | 0.061 us | 0.054 us | 1.00 | 0.9766 | 0.1221 | 48.52 KB | 1.00 | + +Hardware Bench: +- CPU: AMD Ryzen 7 9800X3D +- Memory: G.Skill Ripjaws M5 64GB (32x2) DDR5-6000 CL36-36-36-96 + +Big credits to the original authors of LZMA compression, managed-lzma and sharpcompress for their work. +- [Adam Hathcock (sharpcompress)](https://github.com/adamhathcock) +- [Igor Pavlov (LZMA compression)](https://sourceforge.net/u/ipavlov/profile/) +- [Tobias Käs (managed-lzma)](https://github.com/weltkante/managed-lzma) \ No newline at end of file diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoder.cs b/SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoder.cs new file mode 100644 index 0000000..95b88ab --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoder.cs @@ -0,0 +1,135 @@ +using System; +using System.Buffers; +using System.Runtime.CompilerServices; + +namespace SharpHDiffPatch.New.IO.Compression.Lzma.RangeCoder; + +internal class RangeDecoder : IDisposable +{ + public const uint KTopValue = 1 << 24; + private const int InputBufferSize = 32 << 10; + public uint Range; + public uint Code; + + public System.IO.Stream Stream; + public long Total; + + private byte[] _inputBuffer = []; + private int _inputOffset; + private int _inputCount; + private long _inputLimit; + private bool _useInputBuffer; + + public void Init(System.IO.Stream stream, long inputLimit = -1) + { + Stream = stream; + _inputOffset = 0; + _inputCount = 0; + _inputLimit = inputLimit; + _useInputBuffer = inputLimit >= 0; + + Code = 0; + Range = 0xFFFFFFFF; + Total = 0; + for (int i = 0; i < 5; i++) + { + Code = (Code << 8) | ReadByte(); + } + } + + public void ReleaseStream() => Stream = null; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Normalize() + { + while (Range < KTopValue) + { + Code = (Code << 8) | ReadByte(); + Range <<= 8; + } + } + + public void Decode(uint start, uint size) + { + Code -= start * Range; + Range *= size; + Normalize(); + } + + public uint DecodeDirectBits(int numTotalBits) + { + uint range = Range; + uint code = Code; + uint result = 0; + for (int i = numTotalBits; i > 0; i--) + { + range >>= 1; + uint t = (code - range) >> 31; + code -= range & (t - 1); + result = (result << 1) | (1 - t); + + if (range >= KTopValue) continue; + code = (code << 8) | ReadByte(); + range <<= 8; + } + + Range = range; + Code = code; + return result; + } + + public bool IsFinished => Code == 0; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal uint ReadByte() + { + if (!_useInputBuffer) + { + Total++; + return (byte)Stream.ReadByte(); + } + + if (_inputOffset >= _inputCount) + { + FillInputBuffer(); + } + + Total++; + return _inputBuffer[_inputOffset++]; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void FillInputBuffer() + { + long remaining = _inputLimit - Total; + if (remaining <= 0) + { + throw new LzmaDataErrorException(); + } + + if (_inputBuffer.Length == 0) + { + _inputBuffer = ArrayPool.Shared.Rent(InputBufferSize); + } + + int requested = (int)Math.Min(_inputBuffer.Length, remaining); + _inputCount = Stream.Read(_inputBuffer, 0, requested); + _inputOffset = 0; + if (_inputCount <= 0) + { + throw new LzmaDataErrorException(); + } + } + + public void Dispose() + { + ReleaseStream(); + byte[] inputBuffer = _inputBuffer; + _inputBuffer = []; + + if (inputBuffer.Length != 0) + { + ArrayPool.Shared.Return(inputBuffer); + } + } +} \ No newline at end of file diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs b/SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs new file mode 100644 index 0000000..9011a3a --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs @@ -0,0 +1,55 @@ +using System; +using System.Runtime.CompilerServices; + +namespace SharpHDiffPatch.New.IO.Compression.Lzma.RangeCoder; + +internal struct BitDecoder +{ + public const int KNumBitModelTotalBits = 11; + public const uint KBitModelTotal = 1 << KNumBitModelTotalBits; + private const int KNumMoveBits = 5; + + private uint _prob; + + public void Init() => _prob = KBitModelTotal >> 1; + + public static void Init(BitDecoder[] decoders) => Init(decoders, 0, decoders.Length); + + public static void Init(BitDecoder[] decoders, int start, int length) => decoders.AsSpan(start, length).Fill(new BitDecoder { _prob = KBitModelTotal >> 1 }); + + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint Decode(RangeDecoder rangeDecoder) + { + uint range = rangeDecoder.Range; + uint code = rangeDecoder.Code; + uint probability = _prob; + uint newBound = (range >> KNumBitModelTotalBits) * probability; + uint symbol; + + if (code < newBound) + { + range = newBound; + probability += (KBitModelTotal - probability) >> KNumMoveBits; + symbol = 0; + } + else + { + range -= newBound; + code -= newBound; + probability -= probability >> KNumMoveBits; + symbol = 1; + } + + if (range < RangeDecoder.KTopValue) + { + code = (code << 8) | rangeDecoder.ReadByte(); + range <<= 8; + } + + rangeDecoder.Range = range; + rangeDecoder.Code = code; + _prob = probability; + return symbol; + } +} \ No newline at end of file diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs b/SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs new file mode 100644 index 0000000..6f39a2a --- /dev/null +++ b/SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs @@ -0,0 +1,60 @@ +using System.Runtime.CompilerServices; + +namespace SharpHDiffPatch.New.IO.Compression.Lzma.RangeCoder; + +internal readonly struct BitTreeDecoder(int numBitLevels) +{ + private readonly BitDecoder[] _models = new BitDecoder[1 << numBitLevels]; + + public void Init() => BitDecoder.Init(_models, 1, _models.Length - 1); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint Decode(RangeDecoder rangeDecoder) + { + ref BitDecoder models = ref _models[0]; + uint m = 1; + + for (int bitIndex = numBitLevels; bitIndex > 0; bitIndex--) + { + m = (m << 1) + Unsafe.Add(ref models, (int)m).Decode(rangeDecoder); + } + return m - ((uint)1 << numBitLevels); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint Decode( + BitDecoder[] models, + int startIndex, + RangeDecoder rangeDecoder, + int numBitLevels) + { + ref BitDecoder modelBase = ref Unsafe.Add(ref models[0], startIndex); + uint m = 1; + + for (int bitIndex = numBitLevels; bitIndex > 0; bitIndex--) + { + m = (m << 1) + Unsafe.Add(ref modelBase, (int)m).Decode(rangeDecoder); + } + return m - ((uint)1 << numBitLevels); + } + + public static uint ReverseDecode( + BitDecoder[] models, + uint startIndex, + RangeDecoder rangeDecoder, + int numBitLevels) + { + ref BitDecoder modelBase = ref models[0]; + uint m = 1; + uint symbol = 0; + + for (int bitIndex = 0; bitIndex < numBitLevels; bitIndex++) + { + int modelIndex = unchecked((int)(startIndex + m)); + uint bit = Unsafe.Add(ref modelBase, modelIndex).Decode(rangeDecoder); + m = (m << 1) + bit; + symbol |= bit << bitIndex; + } + return symbol; + } +} \ No newline at end of file diff --git a/SharpHDiffPatch.New/IO/Reader/BittableStreamReader.cs b/SharpHDiffPatch.New/IO/Reader/BittableStreamReader.cs new file mode 100644 index 0000000..85b875a --- /dev/null +++ b/SharpHDiffPatch.New/IO/Reader/BittableStreamReader.cs @@ -0,0 +1,621 @@ +using System; +using System.Buffers; +using System.IO; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace SharpHDiffPatch.New.IO.Reader; + +internal sealed class BittableStreamReader + : IDisposable +#if NET6_0_OR_GREATER + , IAsyncDisposable +#endif +{ + private const int DefaultBufferSize = 64 << 10; + private const int MaxPackedUIntBytes = 11; + + private int _offset; + private int _bufferedLength; + + private readonly byte[] _backedBuffer; + public readonly Stream BackedStream; + + private readonly bool _leaveOpen; + private bool _isDisposed; + + public int TagBitCount; + public byte Tag; + public byte PreviousByte; + + public long Offset => _offset; + + public BittableStreamReader(Stream stream, int bufferSize = -1, bool leaveOpen = false) + { + if (stream is null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (!stream.CanRead) + { + throw new ArgumentException("The stream must be readable.", nameof(stream)); + } + + if (bufferSize <= 0) + { + bufferSize = DefaultBufferSize; + } + + // A complete packed UInt64 must fit in the buffer so decoding can run + // against memory even when the value crosses a stream-read boundary. + bufferSize = Math.Max(bufferSize, MaxPackedUIntBytes); + + BackedStream = stream; + _backedBuffer = ArrayPool.Shared.Rent(bufferSize); + _leaveOpen = leaveOpen; + } + + public byte ReadByte() + { + EnsureBuffered(1); + + PreviousByte = _backedBuffer[_offset++]; + TagBitCount = 0; + Tag = 0; + return PreviousByte; + } + + public async ValueTask ReadByteAsync(CancellationToken token = default) + { + await EnsureBufferedAsync(1, token).ConfigureAwait(false); + + PreviousByte = _backedBuffer[_offset++]; + TagBitCount = 0; + Tag = 0; + return PreviousByte; + } + + public void ReadBytes(byte[] buffer) + => ReadBytes(buffer, 0, buffer?.Length ?? throw new ArgumentNullException(nameof(buffer))); + + public void ReadBytes(byte[] buffer, int offset, int count) + => ReadBytes(new Span(buffer, offset, count)); + + public void ReadBytes(Memory buffer) + => ReadBytes(buffer.Span); + + public void ReadBytes(Span buffer) + { + ResetTag(); + + while (!buffer.IsEmpty) + { + EnsureBuffered(1); + + int copyLength = Math.Min(buffer.Length, _bufferedLength - _offset); + new ReadOnlySpan(_backedBuffer, _offset, copyLength).CopyTo(buffer); + + _offset += copyLength; + buffer = buffer[copyLength..]; + } + } + + public ValueTask ReadBytesAsync(byte[] buffer, CancellationToken token = default) + { + if (buffer is null) + { + throw new ArgumentNullException(nameof(buffer)); + } + + return ReadBytesAsync(new Memory(buffer), token); + } + + public ValueTask ReadBytesAsync( + byte[] buffer, + int offset, + int count, + CancellationToken token = default) + => ReadBytesAsync(new Memory(buffer, offset, count), token); + + public async ValueTask ReadBytesAsync( + Memory buffer, + CancellationToken token = default) + { + ResetTag(); + + while (!buffer.IsEmpty) + { + await EnsureBufferedAsync(1, token).ConfigureAwait(false); + + int copyLength = Math.Min(buffer.Length, _bufferedLength - _offset); + new ReadOnlyMemory(_backedBuffer, _offset, copyLength).CopyTo(buffer); + + _offset += copyLength; + buffer = buffer[copyLength..]; + } + } + + public string ReadStringToNull() => ReadStringToNull(DefaultBufferSize); + + public string ReadStringToNull(int maxByteCount) + { + if (maxByteCount < 0) + { + throw new ArgumentOutOfRangeException(nameof(maxByteCount)); + } + + ResetTag(); + + byte[] stringBuffer = ArrayPool.Shared.Rent(Math.Max(1, Math.Min(maxByteCount, 256))); + int stringLength = 0; + try + { + while (true) + { + try + { + EnsureBuffered(1); + } + catch (EndOfStreamException exception) + { + throw new EndOfStreamException("The stream ended before the null terminator was found.", exception); + } + + int available = _bufferedLength - _offset; + int terminatorIndex = Array.IndexOf(_backedBuffer, (byte)0, _offset, available); + int bytesToCopy = terminatorIndex >= 0 ? terminatorIndex - _offset : available; + + AppendStringBytes(ref stringBuffer, + ref stringLength, + _backedBuffer, + _offset, + bytesToCopy, + maxByteCount); + + _offset += bytesToCopy; + if (terminatorIndex < 0) continue; + + ++_offset; + return Encoding.UTF8.GetString(stringBuffer, 0, stringLength); + } + } + finally + { + ArrayPool.Shared.Return(stringBuffer); + } + } + + public ValueTask ReadStringToNullAsync(CancellationToken token) + => ReadStringToNullAsync(DefaultBufferSize, token); + + public async ValueTask ReadStringToNullAsync( + int maxByteCount, + CancellationToken token = default) + { + if (maxByteCount < 0) + { + throw new ArgumentOutOfRangeException(nameof(maxByteCount)); + } + + ResetTag(); + + byte[] stringBuffer = ArrayPool.Shared.Rent(Math.Max(1, Math.Min(maxByteCount, 256))); + int stringLength = 0; + try + { + while (true) + { + try + { + await EnsureBufferedAsync(1, token).ConfigureAwait(false); + } + catch (EndOfStreamException exception) + { + throw new EndOfStreamException("The stream ended before the null terminator was found.", exception); + } + + int available = _bufferedLength - _offset; + int terminatorIndex = Array.IndexOf(_backedBuffer, (byte)0, _offset, available); + int bytesToCopy = terminatorIndex >= 0 ? terminatorIndex - _offset : available; + + AppendStringBytes( + ref stringBuffer, + ref stringLength, + _backedBuffer, + _offset, + bytesToCopy, + maxByteCount); + + _offset += bytesToCopy; + if (terminatorIndex < 0) continue; + ++_offset; + return Encoding.UTF8.GetString(stringBuffer, 0, stringLength); + } + } + finally + { + ArrayPool.Shared.Return(stringBuffer); + } + } + + public int ReadInt7Bit() + => ReadInt7Bit(0); + + public int ReadInt7Bit(int tagBit) + { + byte code = ReadFirstCode(tagBit); + return ReadInt7BitCore(code, tagBit); + } + + public int ReadInt7Bit(int tagBit, byte previousByte) + { + SetTagState(tagBit, previousByte); + return ReadInt7BitCore(previousByte, tagBit); + } + + public ValueTask ReadInt7BitAsync(CancellationToken token) + => ReadInt7BitAsync(0, token); + + public async ValueTask ReadInt7BitAsync( + int tagBit, + CancellationToken token = default) + { + byte code = await ReadFirstCodeAsync(tagBit, token); + return await ReadInt7BitCoreAsync(code, tagBit, token); + } + + public ValueTask ReadInt7BitAsync( + int tagBit, + byte previousByte, + CancellationToken token = default) + { + SetTagState(tagBit, previousByte); + return ReadInt7BitCoreAsync(previousByte, tagBit, token); + } + + public long ReadLong7Bit() + => ReadLong7Bit(0); + + public long ReadLong7Bit(int tagBit) + { + byte code = ReadFirstCode(tagBit); + return ReadLong7BitCore(code, tagBit); + } + + public long ReadLong7Bit(int tagBit, byte previousByte) + { + SetTagState(tagBit, previousByte); + return ReadLong7BitCore(previousByte, tagBit); + } + + public ValueTask ReadLong7BitAsync(CancellationToken token = default) + => ReadLong7BitAsync(0, token); + + public async ValueTask ReadLong7BitAsync( + int tagBit, + CancellationToken token = default) + { + byte code = await ReadFirstCodeAsync(tagBit, token); + return await ReadLong7BitCoreAsync(code, tagBit, token); + } + + public ValueTask ReadLong7BitAsync( + int tagBit, + byte previousByte, + CancellationToken token = default) + { + SetTagState(tagBit, previousByte); + return ReadLong7BitCoreAsync(previousByte, tagBit, token); + } + + public void ResetTag() + { + ThrowIfDisposed(); + + TagBitCount = 0; + Tag = 0; + PreviousByte = 0; + } + + private static void AppendStringBytes( + ref byte[] destination, + ref int destinationLength, + byte[] source, + int sourceOffset, + int count, + int maxByteCount) + { + if (count > maxByteCount - destinationLength) + { + throw new InvalidDataException($"The null-terminated string exceeds the maximum length of {maxByteCount} bytes."); + } + + int requiredLength = destinationLength + count; + if (requiredLength > destination.Length) + { + int newLength = destination.Length > int.MaxValue / 2 + ? int.MaxValue + : destination.Length * 2; + + byte[] replacement = ArrayPool.Shared.Rent(Math.Max(requiredLength, newLength)); + Buffer.BlockCopy(destination, 0, replacement, 0, destinationLength); + ArrayPool.Shared.Return(destination); + destination = replacement; + } + + Buffer.BlockCopy(source, sourceOffset, destination, destinationLength, count); + destinationLength = requiredLength; + } + + private int ReadInt7BitCore(byte code, int tagBit) + { + int value = code & ((1 << (7 - tagBit)) - 1); + if ((code & (1 << (7 - tagBit))) == 0) + { + return value; + } + + EnsureBuffered(MaxPackedUIntBytes - 1); + + do + { + if (value >> (sizeof(int) * 8 - 7) != 0) + { + return 0; + } + + code = ReadBufferedByte(); + value = (value << 7) | (code & ((1 << 7) - 1)); + } + while ((code & (1 << 7)) != 0); + + return value; + } + + private async ValueTask ReadInt7BitCoreAsync( + byte code, + int tagBit, + CancellationToken token) + { + int value = code & ((1 << (7 - tagBit)) - 1); + if ((code & (1 << (7 - tagBit))) == 0) + { + return value; + } + + await EnsureBufferedAsync(MaxPackedUIntBytes - 1, token); + + do + { + if (value >> (sizeof(int) * 8 - 7) != 0) + { + return 0; + } + + code = ReadBufferedByte(); + value = (value << 7) | (code & ((1 << 7) - 1)); + } + while ((code & (1 << 7)) != 0); + + return value; + } + + private long ReadLong7BitCore(byte code, int tagBit) + { + long value = code & ((1 << (7 - tagBit)) - 1); + if ((code & (1 << (7 - tagBit))) == 0) + { + return value; + } + + EnsureBuffered(MaxPackedUIntBytes - 1); + + do + { + if (value >> (sizeof(long) * 8 - 7) != 0) + { + return 0; + } + + code = ReadBufferedByte(); + value = (value << 7) | (code & (((long)1 << 7) - 1)); + } + while ((code & (1 << 7)) != 0); + + return value; + } + + private async ValueTask ReadLong7BitCoreAsync( + byte code, + int tagBit, + CancellationToken token) + { + long value = code & ((1 << (7 - tagBit)) - 1); + if ((code & (1 << (7 - tagBit))) == 0) + { + return value; + } + + await EnsureBufferedAsync(MaxPackedUIntBytes - 1, token); + + do + { + if (value >> (sizeof(long) * 8 - 7) != 0) + { + return 0; + } + + code = ReadBufferedByte(); + value = (value << 7) | (code & (((long)1 << 7) - 1)); + } + while ((code & (1 << 7)) != 0); + + return value; + } + + private byte ReadFirstCode(int tagBit) + { + ValidateTagBit(tagBit); + EnsureBuffered(MaxPackedUIntBytes); + + byte code = ReadBufferedByte(); + SetTagState(tagBit, code); + return code; + } + + private async ValueTask ReadFirstCodeAsync( + int tagBit, + CancellationToken token) + { + ValidateTagBit(tagBit); + await EnsureBufferedAsync(MaxPackedUIntBytes, token); + + byte code = ReadBufferedByte(); + SetTagState(tagBit, code); + return code; + } + + private void SetTagState(int tagBit, byte previousByte) + { + ValidateTagBit(tagBit); + ThrowIfDisposed(); + + TagBitCount = tagBit; + Tag = tagBit == 0 ? (byte)0 : (byte)(previousByte >> (8 - tagBit)); + PreviousByte = previousByte; + } + + private byte ReadBufferedByte() => _offset >= _bufferedLength + ? throw new EndOfStreamException("The stream ended in the middle of a 7-bit encoded integer.") + : _backedBuffer[_offset++]; + + private void EnsureBuffered(int minimumByteCount) + { + ThrowIfDisposed(); + + int available = _bufferedLength - _offset; + if (available >= minimumByteCount) + { + return; + } + + if (available > 0) + { + Buffer.BlockCopy(_backedBuffer, _offset, _backedBuffer, 0, available); + } + + _offset = 0; + _bufferedLength = available; + while (_bufferedLength < minimumByteCount) + { + int read = BackedStream.Read(_backedBuffer, + _bufferedLength, + _backedBuffer.Length - _bufferedLength); + + if (read == 0) + { + break; + } + _bufferedLength += read; + } + + if (_bufferedLength == 0) + { + throw new EndOfStreamException("Unable to read beyond the end of the stream."); + } + } + + private async ValueTask EnsureBufferedAsync( + int minimumByteCount, + CancellationToken token) + { + ThrowIfDisposed(); + + int available = _bufferedLength - _offset; + if (available >= minimumByteCount) + { + return; + } + + if (available > 0) + { + Buffer.BlockCopy(_backedBuffer, _offset, _backedBuffer, 0, available); + } + + _offset = 0; + _bufferedLength = available; + + while (_bufferedLength < minimumByteCount) + { +#if NET6_0_OR_GREATER + int read = await BackedStream.ReadAsync(_backedBuffer.AsMemory(_bufferedLength, _backedBuffer.Length - _bufferedLength), + token).ConfigureAwait(false); +#else + int read = await BackedStream.ReadAsync(_backedBuffer, + _bufferedLength, + _backedBuffer.Length - _bufferedLength, + token).ConfigureAwait(false); +#endif + + if (read == 0) + { + break; + } + _bufferedLength += read; + } + + if (_bufferedLength == 0) + { + throw new EndOfStreamException("Unable to read beyond the end of the stream."); + } + } + + private void ThrowIfDisposed() + { + if (_isDisposed) + { + throw new ObjectDisposedException(nameof(BittableStreamReader)); + } + } + + private static void ValidateTagBit(int tagBit) + { + if ((uint)tagBit > 7) + { + throw new ArgumentOutOfRangeException(nameof(tagBit), tagBit, "The tag-bit count must be between 0 and 7."); + } + } + + public void Dispose() + { + if (_isDisposed) + { + return; + } + + _isDisposed = true; + ArrayPool.Shared.Return(_backedBuffer); + + if (!_leaveOpen) + { + BackedStream.Dispose(); + } + } + +#if NET6_0_OR_GREATER + public ValueTask DisposeAsync() + { + if (_isDisposed) + { + return ValueTask.CompletedTask; + } + + _isDisposed = true; + ArrayPool.Shared.Return(_backedBuffer); + + return _leaveOpen ? ValueTask.CompletedTask : BackedStream.DisposeAsync(); + } +#endif +} diff --git a/SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/CompilerFeatureRequiredAttribute.cs b/SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/CompilerFeatureRequiredAttribute.cs new file mode 100644 index 0000000..7191d28 --- /dev/null +++ b/SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/CompilerFeatureRequiredAttribute.cs @@ -0,0 +1,28 @@ +#pragma warning disable IDE0130 +#if !NET7_0_OR_GREATER +namespace System.Runtime.CompilerServices; + +[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] +public sealed class CompilerFeatureRequiredAttribute(string featureName) : Attribute +{ + /// + /// The name of the compiler feature. + /// + public string FeatureName { get; } = featureName; + + /// + /// If true, the compiler can choose to allow access to the location where this attribute is applied if it does not understand . + /// + public bool IsOptional { get; init; } + + /// + /// The used for the ref structs C# feature. + /// + public const string RefStructs = nameof(RefStructs); + + /// + /// The used for the required members C# feature. + /// + public const string RequiredMembers = nameof(RequiredMembers); +} +#endif \ No newline at end of file diff --git a/SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/IsExternalInit.cs b/SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/IsExternalInit.cs new file mode 100644 index 0000000..f32817a --- /dev/null +++ b/SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/IsExternalInit.cs @@ -0,0 +1,6 @@ +#pragma warning disable IDE0130 +#if NETSTANDARD2_0 +namespace System.Runtime.CompilerServices; + +internal static class IsExternalInit; +#endif \ No newline at end of file diff --git a/SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/RequiredMemberAttribute.cs b/SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/RequiredMemberAttribute.cs new file mode 100644 index 0000000..230b71b --- /dev/null +++ b/SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/RequiredMemberAttribute.cs @@ -0,0 +1,9 @@ +#pragma warning disable IDE0130 +#if !NET7_0_OR_GREATER +namespace System.Runtime.CompilerServices; + +/// Specifies that a type has required members or that a member is required. +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, Inherited = false)] +[ComponentModel.EditorBrowsable(ComponentModel.EditorBrowsableState.Never)] +internal sealed class RequiredMemberAttribute : Attribute; +#endif diff --git a/SharpHDiffPatch.New/SharpHDiffPatch.New.csproj b/SharpHDiffPatch.New/SharpHDiffPatch.New.csproj new file mode 100644 index 0000000..88e2ded --- /dev/null +++ b/SharpHDiffPatch.New/SharpHDiffPatch.New.csproj @@ -0,0 +1,54 @@ + + + + SharpHDiffPatch.New + SharpHDiffPatch - A port of HPatchZ for HDiff file patching implementation written in C# + SharpHDiffPatch is a patching library for HDiffPatch format written in C#, purposedly as a port of HPatchZ implementation. Supporting file and directory patching with BZip2, Deflate, Zstd, LZMA2 (not LZMA) and No compression diff format. + https://github.com/CollapseLauncher/SharpHDiffPatch.Core + MIT + Copyright (c) 2025 Collapse Project Team, Kemal Setya Adhi (neon-nyan) + neon-nyan + netstandard2.0;net6.0;net7.0;net8.0;net9.0;net10.0 + icon.png + true + README.md + 3.0.0 + 3.0.0 + true + true + Debug;Release + true + hdiff + + AnyCPU;x64;x86;ARM64 + enable + 14 + + + + + + + + + + + + + + + + + + + + + + + + + + True + + + diff --git a/SharpHDiffPatch.sln b/SharpHDiffPatch.sln index 5dd2029..835745b 100644 --- a/SharpHDiffPatch.sln +++ b/SharpHDiffPatch.sln @@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpHDiffPatch.Core", "Sha EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpHDiffPatch", "SharpHDiffPatch\SharpHDiffPatch.csproj", "{506DDD1C-DD74-4FCE-A0C9-D90E904CF708}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpHDiffPatch.New", "SharpHDiffPatch.New\SharpHDiffPatch.New.csproj", "{7CE06EE4-B691-464B-9AB1-9882CF83E48E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -51,6 +53,22 @@ Global {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Release|x64.Build.0 = Release|x64 {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Release|x86.ActiveCfg = Release|x86 {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Release|x86.Build.0 = Release|x86 + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|ARM64.Build.0 = Debug|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|x64.ActiveCfg = Debug|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|x64.Build.0 = Debug|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|x86.ActiveCfg = Debug|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|x86.Build.0 = Debug|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|Any CPU.Build.0 = Release|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|ARM64.ActiveCfg = Release|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|ARM64.Build.0 = Release|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|x64.ActiveCfg = Release|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|x64.Build.0 = Release|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|x86.ActiveCfg = Release|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 2621f4da2ed463d18bed366eb33459fc436140c7 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 9 Aug 2026 01:25:07 +0700 Subject: [PATCH 02/72] Rename project SharpHDiffPatch -> SharpHPatchZ --- SharpHDiffPatch.sln | 3 ++- .../Extension/ExceptionHelper.cs | 0 .../Extension/MemoryAlloc.cs | 0 .../Extension/MetadataExtension.cs | 0 .../Extension/StreamExtension.cs | 0 .../Extension/StringExtension.cs | 0 {SharpHDiffPatch.New => SharpHPatchZ}/HPatch.cs | 0 {SharpHDiffPatch.New => SharpHPatchZ}/HPatchContext.cs | 0 .../Header/HDiffChecksum.cs | 0 .../Header/HDiffCompression.cs | 0 {SharpHDiffPatch.New => SharpHPatchZ}/Header/HDiffInfo.cs | 0 {SharpHDiffPatch.New => SharpHPatchZ}/Header/HDiffMagic.cs | 0 .../Header/HeaderReader.cs | 0 .../Header/Metadata/ChecksumDataInfo.cs | 0 .../Header/Metadata/ChunkSizeInfo.cs | 0 .../Header/Metadata/EntryCountSizeInfo.cs | 0 .../Header/Metadata/ExternSizeInfo.cs | 0 .../Header/Metadata/FileIndexPair.cs | 0 .../Header/Metadata/HeaderDirectoryPatchMetadata.cs | 0 .../Header/Metadata/IMetadataInit.cs | 0 .../Header/Metadata/MetadataTypeConst.cs | 0 .../Header/Metadata/PatchMetadata.cs | 0 .../Header/Metadata/UnmanagedArray.cs | 0 .../Header/Metadata/Utf16UnmanagedString.cs | 0 .../IO/Compression/BZip2/BZip2Constants.cs | 0 .../IO/Compression/BZip2/BZip2Crc32.cs | 0 .../IO/Compression/BZip2/BZip2Exception.cs | 0 .../IO/Compression/BZip2/BZip2InputStream.cs | 0 .../IO/Compression/BZip2/LICENSE | 0 .../IO/Compression/BZip2/README.md | 0 .../IO/Compression/CompressionStreamHelper.cs | 0 .../IO/Compression/Lzma/LICENSE.txt | 0 .../IO/Compression/Lzma/LZ/LzOutWindow.cs | 0 .../IO/Compression/Lzma/LzmaBase.cs | 0 .../IO/Compression/Lzma/LzmaDecoder.cs | 0 .../IO/Compression/Lzma/LzmaExceptions.cs | 0 .../IO/Compression/Lzma/LzmaInputStream.cs | 0 .../IO/Compression/Lzma/README.md | 0 .../IO/Compression/Lzma/RangeCoder/RangeCoder.cs | 0 .../IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs | 0 .../IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs | 0 .../IO/Reader/BittableStreamReader.cs | 0 .../CompilerFeatureRequiredAttribute.cs | 0 .../System.Runtime.CompilerServices/IsExternalInit.cs | 0 .../RequiredMemberAttribute.cs | 0 .../SharpHPatchZ.csproj | 7 +++---- 46 files changed, 5 insertions(+), 5 deletions(-) rename {SharpHDiffPatch.New => SharpHPatchZ}/Extension/ExceptionHelper.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Extension/MemoryAlloc.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Extension/MetadataExtension.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Extension/StreamExtension.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Extension/StringExtension.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/HPatch.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/HPatchContext.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Header/HDiffChecksum.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Header/HDiffCompression.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Header/HDiffInfo.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Header/HDiffMagic.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Header/HeaderReader.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Header/Metadata/ChecksumDataInfo.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Header/Metadata/ChunkSizeInfo.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Header/Metadata/EntryCountSizeInfo.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Header/Metadata/ExternSizeInfo.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Header/Metadata/FileIndexPair.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Header/Metadata/HeaderDirectoryPatchMetadata.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Header/Metadata/IMetadataInit.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Header/Metadata/MetadataTypeConst.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Header/Metadata/PatchMetadata.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Header/Metadata/UnmanagedArray.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/Header/Metadata/Utf16UnmanagedString.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/BZip2/BZip2Constants.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/BZip2/BZip2Crc32.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/BZip2/BZip2Exception.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/BZip2/BZip2InputStream.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/BZip2/LICENSE (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/BZip2/README.md (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/CompressionStreamHelper.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/Lzma/LICENSE.txt (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/Lzma/LZ/LzOutWindow.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/Lzma/LzmaBase.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/Lzma/LzmaDecoder.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/Lzma/LzmaExceptions.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/Lzma/LzmaInputStream.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/Lzma/README.md (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/Lzma/RangeCoder/RangeCoder.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/IO/Reader/BittableStreamReader.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/NetStandardCompat/System.Runtime.CompilerServices/CompilerFeatureRequiredAttribute.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/NetStandardCompat/System.Runtime.CompilerServices/IsExternalInit.cs (100%) rename {SharpHDiffPatch.New => SharpHPatchZ}/NetStandardCompat/System.Runtime.CompilerServices/RequiredMemberAttribute.cs (100%) rename SharpHDiffPatch.New/SharpHDiffPatch.New.csproj => SharpHPatchZ/SharpHPatchZ.csproj (79%) diff --git a/SharpHDiffPatch.sln b/SharpHDiffPatch.sln index 835745b..76b4e9c 100644 --- a/SharpHDiffPatch.sln +++ b/SharpHDiffPatch.sln @@ -7,7 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpHDiffPatch.Core", "Sha EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpHDiffPatch", "SharpHDiffPatch\SharpHDiffPatch.csproj", "{506DDD1C-DD74-4FCE-A0C9-D90E904CF708}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpHDiffPatch.New", "SharpHDiffPatch.New\SharpHDiffPatch.New.csproj", "{7CE06EE4-B691-464B-9AB1-9882CF83E48E}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpHPatchZ", "SharpHPatchZ\SharpHPatchZ.csproj", "{7CE06EE4-B691-464B-9AB1-9882CF83E48E}" +EndProject EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/SharpHDiffPatch.New/Extension/ExceptionHelper.cs b/SharpHPatchZ/Extension/ExceptionHelper.cs similarity index 100% rename from SharpHDiffPatch.New/Extension/ExceptionHelper.cs rename to SharpHPatchZ/Extension/ExceptionHelper.cs diff --git a/SharpHDiffPatch.New/Extension/MemoryAlloc.cs b/SharpHPatchZ/Extension/MemoryAlloc.cs similarity index 100% rename from SharpHDiffPatch.New/Extension/MemoryAlloc.cs rename to SharpHPatchZ/Extension/MemoryAlloc.cs diff --git a/SharpHDiffPatch.New/Extension/MetadataExtension.cs b/SharpHPatchZ/Extension/MetadataExtension.cs similarity index 100% rename from SharpHDiffPatch.New/Extension/MetadataExtension.cs rename to SharpHPatchZ/Extension/MetadataExtension.cs diff --git a/SharpHDiffPatch.New/Extension/StreamExtension.cs b/SharpHPatchZ/Extension/StreamExtension.cs similarity index 100% rename from SharpHDiffPatch.New/Extension/StreamExtension.cs rename to SharpHPatchZ/Extension/StreamExtension.cs diff --git a/SharpHDiffPatch.New/Extension/StringExtension.cs b/SharpHPatchZ/Extension/StringExtension.cs similarity index 100% rename from SharpHDiffPatch.New/Extension/StringExtension.cs rename to SharpHPatchZ/Extension/StringExtension.cs diff --git a/SharpHDiffPatch.New/HPatch.cs b/SharpHPatchZ/HPatch.cs similarity index 100% rename from SharpHDiffPatch.New/HPatch.cs rename to SharpHPatchZ/HPatch.cs diff --git a/SharpHDiffPatch.New/HPatchContext.cs b/SharpHPatchZ/HPatchContext.cs similarity index 100% rename from SharpHDiffPatch.New/HPatchContext.cs rename to SharpHPatchZ/HPatchContext.cs diff --git a/SharpHDiffPatch.New/Header/HDiffChecksum.cs b/SharpHPatchZ/Header/HDiffChecksum.cs similarity index 100% rename from SharpHDiffPatch.New/Header/HDiffChecksum.cs rename to SharpHPatchZ/Header/HDiffChecksum.cs diff --git a/SharpHDiffPatch.New/Header/HDiffCompression.cs b/SharpHPatchZ/Header/HDiffCompression.cs similarity index 100% rename from SharpHDiffPatch.New/Header/HDiffCompression.cs rename to SharpHPatchZ/Header/HDiffCompression.cs diff --git a/SharpHDiffPatch.New/Header/HDiffInfo.cs b/SharpHPatchZ/Header/HDiffInfo.cs similarity index 100% rename from SharpHDiffPatch.New/Header/HDiffInfo.cs rename to SharpHPatchZ/Header/HDiffInfo.cs diff --git a/SharpHDiffPatch.New/Header/HDiffMagic.cs b/SharpHPatchZ/Header/HDiffMagic.cs similarity index 100% rename from SharpHDiffPatch.New/Header/HDiffMagic.cs rename to SharpHPatchZ/Header/HDiffMagic.cs diff --git a/SharpHDiffPatch.New/Header/HeaderReader.cs b/SharpHPatchZ/Header/HeaderReader.cs similarity index 100% rename from SharpHDiffPatch.New/Header/HeaderReader.cs rename to SharpHPatchZ/Header/HeaderReader.cs diff --git a/SharpHDiffPatch.New/Header/Metadata/ChecksumDataInfo.cs b/SharpHPatchZ/Header/Metadata/ChecksumDataInfo.cs similarity index 100% rename from SharpHDiffPatch.New/Header/Metadata/ChecksumDataInfo.cs rename to SharpHPatchZ/Header/Metadata/ChecksumDataInfo.cs diff --git a/SharpHDiffPatch.New/Header/Metadata/ChunkSizeInfo.cs b/SharpHPatchZ/Header/Metadata/ChunkSizeInfo.cs similarity index 100% rename from SharpHDiffPatch.New/Header/Metadata/ChunkSizeInfo.cs rename to SharpHPatchZ/Header/Metadata/ChunkSizeInfo.cs diff --git a/SharpHDiffPatch.New/Header/Metadata/EntryCountSizeInfo.cs b/SharpHPatchZ/Header/Metadata/EntryCountSizeInfo.cs similarity index 100% rename from SharpHDiffPatch.New/Header/Metadata/EntryCountSizeInfo.cs rename to SharpHPatchZ/Header/Metadata/EntryCountSizeInfo.cs diff --git a/SharpHDiffPatch.New/Header/Metadata/ExternSizeInfo.cs b/SharpHPatchZ/Header/Metadata/ExternSizeInfo.cs similarity index 100% rename from SharpHDiffPatch.New/Header/Metadata/ExternSizeInfo.cs rename to SharpHPatchZ/Header/Metadata/ExternSizeInfo.cs diff --git a/SharpHDiffPatch.New/Header/Metadata/FileIndexPair.cs b/SharpHPatchZ/Header/Metadata/FileIndexPair.cs similarity index 100% rename from SharpHDiffPatch.New/Header/Metadata/FileIndexPair.cs rename to SharpHPatchZ/Header/Metadata/FileIndexPair.cs diff --git a/SharpHDiffPatch.New/Header/Metadata/HeaderDirectoryPatchMetadata.cs b/SharpHPatchZ/Header/Metadata/HeaderDirectoryPatchMetadata.cs similarity index 100% rename from SharpHDiffPatch.New/Header/Metadata/HeaderDirectoryPatchMetadata.cs rename to SharpHPatchZ/Header/Metadata/HeaderDirectoryPatchMetadata.cs diff --git a/SharpHDiffPatch.New/Header/Metadata/IMetadataInit.cs b/SharpHPatchZ/Header/Metadata/IMetadataInit.cs similarity index 100% rename from SharpHDiffPatch.New/Header/Metadata/IMetadataInit.cs rename to SharpHPatchZ/Header/Metadata/IMetadataInit.cs diff --git a/SharpHDiffPatch.New/Header/Metadata/MetadataTypeConst.cs b/SharpHPatchZ/Header/Metadata/MetadataTypeConst.cs similarity index 100% rename from SharpHDiffPatch.New/Header/Metadata/MetadataTypeConst.cs rename to SharpHPatchZ/Header/Metadata/MetadataTypeConst.cs diff --git a/SharpHDiffPatch.New/Header/Metadata/PatchMetadata.cs b/SharpHPatchZ/Header/Metadata/PatchMetadata.cs similarity index 100% rename from SharpHDiffPatch.New/Header/Metadata/PatchMetadata.cs rename to SharpHPatchZ/Header/Metadata/PatchMetadata.cs diff --git a/SharpHDiffPatch.New/Header/Metadata/UnmanagedArray.cs b/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs similarity index 100% rename from SharpHDiffPatch.New/Header/Metadata/UnmanagedArray.cs rename to SharpHPatchZ/Header/Metadata/UnmanagedArray.cs diff --git a/SharpHDiffPatch.New/Header/Metadata/Utf16UnmanagedString.cs b/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs similarity index 100% rename from SharpHDiffPatch.New/Header/Metadata/Utf16UnmanagedString.cs rename to SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs diff --git a/SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Constants.cs b/SharpHPatchZ/IO/Compression/BZip2/BZip2Constants.cs similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Constants.cs rename to SharpHPatchZ/IO/Compression/BZip2/BZip2Constants.cs diff --git a/SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Crc32.cs b/SharpHPatchZ/IO/Compression/BZip2/BZip2Crc32.cs similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Crc32.cs rename to SharpHPatchZ/IO/Compression/BZip2/BZip2Crc32.cs diff --git a/SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Exception.cs b/SharpHPatchZ/IO/Compression/BZip2/BZip2Exception.cs similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/BZip2/BZip2Exception.cs rename to SharpHPatchZ/IO/Compression/BZip2/BZip2Exception.cs diff --git a/SharpHDiffPatch.New/IO/Compression/BZip2/BZip2InputStream.cs b/SharpHPatchZ/IO/Compression/BZip2/BZip2InputStream.cs similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/BZip2/BZip2InputStream.cs rename to SharpHPatchZ/IO/Compression/BZip2/BZip2InputStream.cs diff --git a/SharpHDiffPatch.New/IO/Compression/BZip2/LICENSE b/SharpHPatchZ/IO/Compression/BZip2/LICENSE similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/BZip2/LICENSE rename to SharpHPatchZ/IO/Compression/BZip2/LICENSE diff --git a/SharpHDiffPatch.New/IO/Compression/BZip2/README.md b/SharpHPatchZ/IO/Compression/BZip2/README.md similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/BZip2/README.md rename to SharpHPatchZ/IO/Compression/BZip2/README.md diff --git a/SharpHDiffPatch.New/IO/Compression/CompressionStreamHelper.cs b/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/CompressionStreamHelper.cs rename to SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/LICENSE.txt b/SharpHPatchZ/IO/Compression/Lzma/LICENSE.txt similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/Lzma/LICENSE.txt rename to SharpHPatchZ/IO/Compression/Lzma/LICENSE.txt diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/LZ/LzOutWindow.cs b/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/Lzma/LZ/LzOutWindow.cs rename to SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/LzmaBase.cs b/SharpHPatchZ/IO/Compression/Lzma/LzmaBase.cs similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/Lzma/LzmaBase.cs rename to SharpHPatchZ/IO/Compression/Lzma/LzmaBase.cs diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/LzmaDecoder.cs b/SharpHPatchZ/IO/Compression/Lzma/LzmaDecoder.cs similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/Lzma/LzmaDecoder.cs rename to SharpHPatchZ/IO/Compression/Lzma/LzmaDecoder.cs diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/LzmaExceptions.cs b/SharpHPatchZ/IO/Compression/Lzma/LzmaExceptions.cs similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/Lzma/LzmaExceptions.cs rename to SharpHPatchZ/IO/Compression/Lzma/LzmaExceptions.cs diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/LzmaInputStream.cs b/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/Lzma/LzmaInputStream.cs rename to SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/README.md b/SharpHPatchZ/IO/Compression/Lzma/README.md similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/Lzma/README.md rename to SharpHPatchZ/IO/Compression/Lzma/README.md diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoder.cs b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoder.cs rename to SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs rename to SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs diff --git a/SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs similarity index 100% rename from SharpHDiffPatch.New/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs rename to SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs diff --git a/SharpHDiffPatch.New/IO/Reader/BittableStreamReader.cs b/SharpHPatchZ/IO/Reader/BittableStreamReader.cs similarity index 100% rename from SharpHDiffPatch.New/IO/Reader/BittableStreamReader.cs rename to SharpHPatchZ/IO/Reader/BittableStreamReader.cs diff --git a/SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/CompilerFeatureRequiredAttribute.cs b/SharpHPatchZ/NetStandardCompat/System.Runtime.CompilerServices/CompilerFeatureRequiredAttribute.cs similarity index 100% rename from SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/CompilerFeatureRequiredAttribute.cs rename to SharpHPatchZ/NetStandardCompat/System.Runtime.CompilerServices/CompilerFeatureRequiredAttribute.cs diff --git a/SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/IsExternalInit.cs b/SharpHPatchZ/NetStandardCompat/System.Runtime.CompilerServices/IsExternalInit.cs similarity index 100% rename from SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/IsExternalInit.cs rename to SharpHPatchZ/NetStandardCompat/System.Runtime.CompilerServices/IsExternalInit.cs diff --git a/SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/RequiredMemberAttribute.cs b/SharpHPatchZ/NetStandardCompat/System.Runtime.CompilerServices/RequiredMemberAttribute.cs similarity index 100% rename from SharpHDiffPatch.New/NetStandardCompat/System.Runtime.CompilerServices/RequiredMemberAttribute.cs rename to SharpHPatchZ/NetStandardCompat/System.Runtime.CompilerServices/RequiredMemberAttribute.cs diff --git a/SharpHDiffPatch.New/SharpHDiffPatch.New.csproj b/SharpHPatchZ/SharpHPatchZ.csproj similarity index 79% rename from SharpHDiffPatch.New/SharpHDiffPatch.New.csproj rename to SharpHPatchZ/SharpHPatchZ.csproj index 88e2ded..19bdf1e 100644 --- a/SharpHDiffPatch.New/SharpHDiffPatch.New.csproj +++ b/SharpHPatchZ/SharpHPatchZ.csproj @@ -1,9 +1,9 @@  - SharpHDiffPatch.New - SharpHDiffPatch - A port of HPatchZ for HDiff file patching implementation written in C# - SharpHDiffPatch is a patching library for HDiffPatch format written in C#, purposedly as a port of HPatchZ implementation. Supporting file and directory patching with BZip2, Deflate, Zstd, LZMA2 (not LZMA) and No compression diff format. + SharpHPatch + SharpHPatch (formerly: SharpHDiffPatch) - Apply binary patches for HDiffPatch format. + SharpHPatch is a port of HPatchZ implementation from HDiffPatch project (by housisong), written in C#. Provides as nearly as fast as the native implementation, supporting multi-threading and several compressed formats. https://github.com/CollapseLauncher/SharpHDiffPatch.Core MIT Copyright (c) 2025 Collapse Project Team, Kemal Setya Adhi (neon-nyan) @@ -19,7 +19,6 @@ Debug;Release true hdiff - AnyCPU;x64;x86;ARM64 enable 14 From 187ce28aa00207c2999bb557d1bbc397702fe577 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 9 Aug 2026 01:39:06 +0700 Subject: [PATCH 03/72] Rename namespaces --- SharpHDiffPatch.sln | 41 ++++++++++----- SharpHPatchZ/Extension/ExceptionHelper.cs | 2 +- SharpHPatchZ/Extension/MemoryAlloc.cs | 3 +- SharpHPatchZ/Extension/MetadataExtension.cs | 4 +- SharpHPatchZ/Extension/StreamExtension.cs | 9 ++-- SharpHPatchZ/Extension/StringExtension.cs | 4 +- SharpHPatchZ/HPatch.cs | 6 +-- SharpHPatchZ/HPatchContext.cs | 13 ----- SharpHPatchZ/Header/HDiffChecksum.cs | 2 +- SharpHPatchZ/Header/HDiffCompression.cs | 2 +- SharpHPatchZ/Header/HDiffInfo.cs | 6 +-- SharpHPatchZ/Header/HDiffMagic.cs | 2 +- SharpHPatchZ/Header/HeaderReader.cs | 10 ++-- .../Header/Metadata/ChecksumDataInfo.cs | 4 +- SharpHPatchZ/Header/Metadata/ChunkSizeInfo.cs | 2 +- .../Header/Metadata/EntryCountSizeInfo.cs | 2 +- .../Header/Metadata/ExternSizeInfo.cs | 2 +- SharpHPatchZ/Header/Metadata/FileIndexPair.cs | 2 +- .../Metadata/HeaderDirectoryPatchMetadata.cs | 4 +- SharpHPatchZ/Header/Metadata/IMetadataInit.cs | 2 +- .../Header/Metadata/MetadataTypeConst.cs | 2 +- SharpHPatchZ/Header/Metadata/PatchMetadata.cs | 4 +- .../Header/Metadata/UnmanagedArray.cs | 4 +- .../Header/Metadata/Utf16UnmanagedString.cs | 4 +- .../IO/Compression/BZip2/BZip2Constants.cs | 2 +- .../IO/Compression/BZip2/BZip2Crc32.cs | 2 +- .../IO/Compression/BZip2/BZip2Exception.cs | 2 +- .../IO/Compression/BZip2/BZip2InputStream.cs | 14 +++--- .../IO/Compression/CompressionStreamHelper.cs | 8 +-- .../IO/Compression/Lzma/LZ/LzOutWindow.cs | 23 +++++---- SharpHPatchZ/IO/Compression/Lzma/LzmaBase.cs | 2 +- .../IO/Compression/Lzma/LzmaDecoder.cs | 6 +-- .../IO/Compression/Lzma/LzmaExceptions.cs | 2 +- .../IO/Compression/Lzma/LzmaInputStream.cs | 24 ++++----- .../Compression/Lzma/RangeCoder/RangeCoder.cs | 9 ++-- .../Lzma/RangeCoder/RangeCoderBit.cs | 2 +- .../Lzma/RangeCoder/RangeCoderBitTree.cs | 2 +- .../IO/Reader/BittableStreamReader.cs | 2 +- SharpHPatchZ/SharpHPatchZ.csproj | 6 +-- Test/Program.cs | 50 +++++++++++++++++++ Test/Test.csproj | 17 +++++++ 41 files changed, 189 insertions(+), 120 deletions(-) delete mode 100644 SharpHPatchZ/HPatchContext.cs create mode 100644 Test/Program.cs create mode 100644 Test/Test.csproj diff --git a/SharpHDiffPatch.sln b/SharpHDiffPatch.sln index 76b4e9c..dd08966 100644 --- a/SharpHDiffPatch.sln +++ b/SharpHDiffPatch.sln @@ -9,6 +9,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpHDiffPatch", "SharpHDi EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpHPatchZ", "SharpHPatchZ\SharpHPatchZ.csproj", "{7CE06EE4-B691-464B-9AB1-9882CF83E48E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{3AE3BAA8-B233-4547-82C2-0DE8012B4F23}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -56,20 +57,36 @@ Global {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Release|x86.Build.0 = Release|x86 {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|ARM64.ActiveCfg = Debug|Any CPU - {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|ARM64.Build.0 = Debug|Any CPU - {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|x64.ActiveCfg = Debug|Any CPU - {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|x64.Build.0 = Debug|Any CPU - {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|x86.ActiveCfg = Debug|Any CPU - {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|x86.Build.0 = Debug|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|ARM64.Build.0 = Debug|ARM64 + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|x64.ActiveCfg = Debug|x64 + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|x64.Build.0 = Debug|x64 + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|x86.ActiveCfg = Debug|x86 + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|x86.Build.0 = Debug|x86 {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|Any CPU.ActiveCfg = Release|Any CPU {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|Any CPU.Build.0 = Release|Any CPU - {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|ARM64.ActiveCfg = Release|Any CPU - {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|ARM64.Build.0 = Release|Any CPU - {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|x64.ActiveCfg = Release|Any CPU - {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|x64.Build.0 = Release|Any CPU - {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|x86.ActiveCfg = Release|Any CPU - {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|x86.Build.0 = Release|Any CPU + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|ARM64.ActiveCfg = Release|ARM64 + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|ARM64.Build.0 = Release|ARM64 + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|x64.ActiveCfg = Release|x64 + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|x64.Build.0 = Release|x64 + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|x86.ActiveCfg = Release|x86 + {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|x86.Build.0 = Release|x86 + {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Debug|ARM64.Build.0 = Debug|ARM64 + {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Debug|x64.ActiveCfg = Debug|x64 + {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Debug|x64.Build.0 = Debug|x64 + {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Debug|x86.ActiveCfg = Debug|x86 + {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Debug|x86.Build.0 = Debug|x86 + {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Release|Any CPU.Build.0 = Release|Any CPU + {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Release|ARM64.ActiveCfg = Release|ARM64 + {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Release|ARM64.Build.0 = Release|ARM64 + {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Release|x64.ActiveCfg = Release|x64 + {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Release|x64.Build.0 = Release|x64 + {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Release|x86.ActiveCfg = Release|x86 + {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SharpHPatchZ/Extension/ExceptionHelper.cs b/SharpHPatchZ/Extension/ExceptionHelper.cs index 5e19ea9..a59a0c1 100644 --- a/SharpHPatchZ/Extension/ExceptionHelper.cs +++ b/SharpHPatchZ/Extension/ExceptionHelper.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; #endif -namespace SharpHDiffPatch.New.Extension; +namespace SharpHPatchZ.Extension; file static class Const { diff --git a/SharpHPatchZ/Extension/MemoryAlloc.cs b/SharpHPatchZ/Extension/MemoryAlloc.cs index fdc2445..74d05c0 100644 --- a/SharpHPatchZ/Extension/MemoryAlloc.cs +++ b/SharpHPatchZ/Extension/MemoryAlloc.cs @@ -1,10 +1,9 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SharpHDiffPatch.New.Header.Metadata; #pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type -namespace SharpHDiffPatch.New.Extension; +namespace SharpHPatchZ.Extension; internal static unsafe class MemoryAlloc { diff --git a/SharpHPatchZ/Extension/MetadataExtension.cs b/SharpHPatchZ/Extension/MetadataExtension.cs index 7d8110d..e3e412e 100644 --- a/SharpHPatchZ/Extension/MetadataExtension.cs +++ b/SharpHPatchZ/Extension/MetadataExtension.cs @@ -1,8 +1,8 @@ using System; using System.Runtime.CompilerServices; -using SharpHDiffPatch.New.Header.Metadata; +using SharpHPatchZ.Header.Metadata; -namespace SharpHDiffPatch.New.Extension; +namespace SharpHPatchZ.Extension; internal static class MetadataExtension { diff --git a/SharpHPatchZ/Extension/StreamExtension.cs b/SharpHPatchZ/Extension/StreamExtension.cs index 822d632..0e32e21 100644 --- a/SharpHPatchZ/Extension/StreamExtension.cs +++ b/SharpHPatchZ/Extension/StreamExtension.cs @@ -1,14 +1,13 @@ -using SharpHDiffPatch.New.Header.Metadata; -using SharpHDiffPatch.New.IO.Reader; -using System; +using System; using System.Buffers; using System.Diagnostics; using System.IO; -using System.Runtime.InteropServices.ComTypes; using System.Threading; using System.Threading.Tasks; +using SharpHPatchZ.Header.Metadata; +using SharpHPatchZ.IO.Reader; -namespace SharpHDiffPatch.New.Extension; +namespace SharpHPatchZ.Extension; internal static class StreamExtension { diff --git a/SharpHPatchZ/Extension/StringExtension.cs b/SharpHPatchZ/Extension/StringExtension.cs index ea6666d..d3ef098 100644 --- a/SharpHPatchZ/Extension/StringExtension.cs +++ b/SharpHPatchZ/Extension/StringExtension.cs @@ -1,8 +1,6 @@ using System; -using System.Threading.Tasks; -using SharpHDiffPatch.New.IO.Reader; -namespace SharpHDiffPatch.New.Extension; +namespace SharpHPatchZ.Extension; internal static class StringExtension { diff --git a/SharpHPatchZ/HPatch.cs b/SharpHPatchZ/HPatch.cs index cb41c39..f446b15 100644 --- a/SharpHPatchZ/HPatch.cs +++ b/SharpHPatchZ/HPatch.cs @@ -1,10 +1,10 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -using SharpHDiffPatch.New.Header; -using SharpHDiffPatch.New.IO.Reader; +using SharpHPatchZ.Header; +using SharpHPatchZ.IO.Reader; -namespace SharpHDiffPatch.New; +namespace SharpHPatchZ; public delegate (Stream Stream, bool LeaveOpen) CreateStream(long position); diff --git a/SharpHPatchZ/HPatchContext.cs b/SharpHPatchZ/HPatchContext.cs deleted file mode 100644 index e115275..0000000 --- a/SharpHPatchZ/HPatchContext.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using SharpHDiffPatch.New.Header; - -namespace SharpHDiffPatch.New; - -public class HPatchContext : IDisposable -{ - public required HDiffInfo Info { get; init; } - - public void Dispose() - { - } -} diff --git a/SharpHPatchZ/Header/HDiffChecksum.cs b/SharpHPatchZ/Header/HDiffChecksum.cs index c4ab82f..515d171 100644 --- a/SharpHPatchZ/Header/HDiffChecksum.cs +++ b/SharpHPatchZ/Header/HDiffChecksum.cs @@ -1,4 +1,4 @@ -namespace SharpHDiffPatch.New.Header; +namespace SharpHPatchZ.Header; public enum HDiffChecksum { diff --git a/SharpHPatchZ/Header/HDiffCompression.cs b/SharpHPatchZ/Header/HDiffCompression.cs index 80815dd..b42c79f 100644 --- a/SharpHPatchZ/Header/HDiffCompression.cs +++ b/SharpHPatchZ/Header/HDiffCompression.cs @@ -1,7 +1,7 @@ // ReSharper disable UnusedMember.Global // ReSharper disable IdentifierTypo // ReSharper disable InconsistentNaming -namespace SharpHDiffPatch.New.Header; +namespace SharpHPatchZ.Header; public enum HDiffCompression { diff --git a/SharpHPatchZ/Header/HDiffInfo.cs b/SharpHPatchZ/Header/HDiffInfo.cs index 62a5416..85add11 100644 --- a/SharpHPatchZ/Header/HDiffInfo.cs +++ b/SharpHPatchZ/Header/HDiffInfo.cs @@ -1,10 +1,10 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SharpHDiffPatch.New.Extension; -using SharpHDiffPatch.New.Header.Metadata; +using SharpHPatchZ.Extension; +using SharpHPatchZ.Header.Metadata; -namespace SharpHDiffPatch.New.Header; +namespace SharpHPatchZ.Header; [StructLayout(LayoutKind.Sequential)] public unsafe struct HDiffInfo : IDisposable diff --git a/SharpHPatchZ/Header/HDiffMagic.cs b/SharpHPatchZ/Header/HDiffMagic.cs index ab236e3..44e4f48 100644 --- a/SharpHPatchZ/Header/HDiffMagic.cs +++ b/SharpHPatchZ/Header/HDiffMagic.cs @@ -1,4 +1,4 @@ -namespace SharpHDiffPatch.New.Header; +namespace SharpHPatchZ.Header; public enum HDiffMagic { diff --git a/SharpHPatchZ/Header/HeaderReader.cs b/SharpHPatchZ/Header/HeaderReader.cs index a52e076..7462473 100644 --- a/SharpHPatchZ/Header/HeaderReader.cs +++ b/SharpHPatchZ/Header/HeaderReader.cs @@ -1,4 +1,7 @@ -using SharpHDiffPatch.New.Extension; +using SharpHPatchZ.Extension; +using SharpHPatchZ.Header.Metadata; +using SharpHPatchZ.IO.Compression; +using SharpHPatchZ.IO.Reader; using System; using System.Buffers; using System.IO; @@ -6,11 +9,8 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; -using SharpHDiffPatch.New.IO.Compression; -using SharpHDiffPatch.New.IO.Reader; -using SharpHDiffPatch.New.Header.Metadata; -namespace SharpHDiffPatch.New.Header; +namespace SharpHPatchZ.Header; public class HeaderReader { diff --git a/SharpHPatchZ/Header/Metadata/ChecksumDataInfo.cs b/SharpHPatchZ/Header/Metadata/ChecksumDataInfo.cs index 0a9528f..e7f1dee 100644 --- a/SharpHPatchZ/Header/Metadata/ChecksumDataInfo.cs +++ b/SharpHPatchZ/Header/Metadata/ChecksumDataInfo.cs @@ -1,8 +1,8 @@ using System; using System.Runtime.CompilerServices; -using SharpHDiffPatch.New.Extension; +using SharpHPatchZ.Extension; -namespace SharpHDiffPatch.New.Header.Metadata; +namespace SharpHPatchZ.Header.Metadata; public unsafe struct ChecksumDataInfo : IMetadataInit { diff --git a/SharpHPatchZ/Header/Metadata/ChunkSizeInfo.cs b/SharpHPatchZ/Header/Metadata/ChunkSizeInfo.cs index 6d5b507..9de7bc1 100644 --- a/SharpHPatchZ/Header/Metadata/ChunkSizeInfo.cs +++ b/SharpHPatchZ/Header/Metadata/ChunkSizeInfo.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -namespace SharpHDiffPatch.New.Header.Metadata; +namespace SharpHPatchZ.Header.Metadata; [StructLayout(LayoutKind.Sequential)] public struct ChunkSizeInfo diff --git a/SharpHPatchZ/Header/Metadata/EntryCountSizeInfo.cs b/SharpHPatchZ/Header/Metadata/EntryCountSizeInfo.cs index a6785e3..3b862e1 100644 --- a/SharpHPatchZ/Header/Metadata/EntryCountSizeInfo.cs +++ b/SharpHPatchZ/Header/Metadata/EntryCountSizeInfo.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -namespace SharpHDiffPatch.New.Header.Metadata; +namespace SharpHPatchZ.Header.Metadata; [StructLayout(LayoutKind.Sequential)] public struct EntryCountSizeInfo diff --git a/SharpHPatchZ/Header/Metadata/ExternSizeInfo.cs b/SharpHPatchZ/Header/Metadata/ExternSizeInfo.cs index f8f4b52..1b778e3 100644 --- a/SharpHPatchZ/Header/Metadata/ExternSizeInfo.cs +++ b/SharpHPatchZ/Header/Metadata/ExternSizeInfo.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -namespace SharpHDiffPatch.New.Header.Metadata; +namespace SharpHPatchZ.Header.Metadata; [StructLayout(LayoutKind.Sequential)] public struct ExternSizeInfo diff --git a/SharpHPatchZ/Header/Metadata/FileIndexPair.cs b/SharpHPatchZ/Header/Metadata/FileIndexPair.cs index 06a844a..b8f9fc5 100644 --- a/SharpHPatchZ/Header/Metadata/FileIndexPair.cs +++ b/SharpHPatchZ/Header/Metadata/FileIndexPair.cs @@ -1,6 +1,6 @@ using System.Runtime.InteropServices; -namespace SharpHDiffPatch.New.Header.Metadata; +namespace SharpHPatchZ.Header.Metadata; [StructLayout(LayoutKind.Sequential)] public struct FileIndexPair diff --git a/SharpHPatchZ/Header/Metadata/HeaderDirectoryPatchMetadata.cs b/SharpHPatchZ/Header/Metadata/HeaderDirectoryPatchMetadata.cs index ab6dcbc..79013d5 100644 --- a/SharpHPatchZ/Header/Metadata/HeaderDirectoryPatchMetadata.cs +++ b/SharpHPatchZ/Header/Metadata/HeaderDirectoryPatchMetadata.cs @@ -1,7 +1,7 @@ using System.Runtime.InteropServices; -using SharpHDiffPatch.New.Extension; +using SharpHPatchZ.Extension; -namespace SharpHDiffPatch.New.Header.Metadata; +namespace SharpHPatchZ.Header.Metadata; [StructLayout(LayoutKind.Sequential)] public unsafe struct HeaderDirectoryPatchMetadata : IMetadataInit diff --git a/SharpHPatchZ/Header/Metadata/IMetadataInit.cs b/SharpHPatchZ/Header/Metadata/IMetadataInit.cs index 6a4938f..0e5a959 100644 --- a/SharpHPatchZ/Header/Metadata/IMetadataInit.cs +++ b/SharpHPatchZ/Header/Metadata/IMetadataInit.cs @@ -1,6 +1,6 @@ using System; -namespace SharpHDiffPatch.New.Header.Metadata; +namespace SharpHPatchZ.Header.Metadata; public interface IMetadataInit : IDisposable { diff --git a/SharpHPatchZ/Header/Metadata/MetadataTypeConst.cs b/SharpHPatchZ/Header/Metadata/MetadataTypeConst.cs index 13c4920..606a7fa 100644 --- a/SharpHPatchZ/Header/Metadata/MetadataTypeConst.cs +++ b/SharpHPatchZ/Header/Metadata/MetadataTypeConst.cs @@ -1,6 +1,6 @@ using System; -namespace SharpHDiffPatch.New.Header.Metadata; +namespace SharpHPatchZ.Header.Metadata; [Flags] public enum MetadataTypeConst : short diff --git a/SharpHPatchZ/Header/Metadata/PatchMetadata.cs b/SharpHPatchZ/Header/Metadata/PatchMetadata.cs index 705e7b7..c96eb49 100644 --- a/SharpHPatchZ/Header/Metadata/PatchMetadata.cs +++ b/SharpHPatchZ/Header/Metadata/PatchMetadata.cs @@ -1,7 +1,7 @@ using System.Runtime.InteropServices; -using SharpHDiffPatch.New.Extension; +using SharpHPatchZ.Extension; -namespace SharpHDiffPatch.New.Header.Metadata; +namespace SharpHPatchZ.Header.Metadata; [StructLayout(LayoutKind.Sequential)] public unsafe struct PatchMetadata : IMetadataInit diff --git a/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs b/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs index d2f7c06..f5f71e6 100644 --- a/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs +++ b/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs @@ -1,9 +1,9 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SharpHDiffPatch.New.Extension; +using SharpHPatchZ.Extension; -namespace SharpHDiffPatch.New.Header.Metadata; +namespace SharpHPatchZ.Header.Metadata; [StructLayout(LayoutKind.Sequential)] public unsafe struct UnmanagedArray : IMetadataInit diff --git a/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs b/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs index 8c63b67..fe39974 100644 --- a/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs +++ b/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs @@ -1,8 +1,8 @@ using System; using System.Runtime.InteropServices; -using SharpHDiffPatch.New.Extension; +using SharpHPatchZ.Extension; -namespace SharpHDiffPatch.New.Header.Metadata; +namespace SharpHPatchZ.Header.Metadata; [StructLayout(LayoutKind.Sequential)] public unsafe struct Utf16UnmanagedString : IMetadataInit diff --git a/SharpHPatchZ/IO/Compression/BZip2/BZip2Constants.cs b/SharpHPatchZ/IO/Compression/BZip2/BZip2Constants.cs index 330b194..7e746b6 100644 --- a/SharpHPatchZ/IO/Compression/BZip2/BZip2Constants.cs +++ b/SharpHPatchZ/IO/Compression/BZip2/BZip2Constants.cs @@ -1,6 +1,6 @@ using System; -namespace SharpHDiffPatch.New.IO.Compression.BZip2; +namespace SharpHPatchZ.IO.Compression.BZip2; /// /// Defines internal values for both compression and decompression diff --git a/SharpHPatchZ/IO/Compression/BZip2/BZip2Crc32.cs b/SharpHPatchZ/IO/Compression/BZip2/BZip2Crc32.cs index aacca67..151166d 100644 --- a/SharpHPatchZ/IO/Compression/BZip2/BZip2Crc32.cs +++ b/SharpHPatchZ/IO/Compression/BZip2/BZip2Crc32.cs @@ -10,7 +10,7 @@ // ReSharper disable InconsistentNaming #endif -namespace SharpHDiffPatch.New.IO.Compression.BZip2; +namespace SharpHPatchZ.IO.Compression.BZip2; file static class BZip2Crc32Premul { diff --git a/SharpHPatchZ/IO/Compression/BZip2/BZip2Exception.cs b/SharpHPatchZ/IO/Compression/BZip2/BZip2Exception.cs index 4971ee2..5a9ccfe 100644 --- a/SharpHPatchZ/IO/Compression/BZip2/BZip2Exception.cs +++ b/SharpHPatchZ/IO/Compression/BZip2/BZip2Exception.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.Serialization; -namespace SharpHDiffPatch.New.IO.Compression.BZip2; +namespace SharpHPatchZ.IO.Compression.BZip2; /// /// BZip2Exception represents exceptions specific to BZip2 classes and code. diff --git a/SharpHPatchZ/IO/Compression/BZip2/BZip2InputStream.cs b/SharpHPatchZ/IO/Compression/BZip2/BZip2InputStream.cs index 4edafda..85aa82c 100644 --- a/SharpHPatchZ/IO/Compression/BZip2/BZip2InputStream.cs +++ b/SharpHPatchZ/IO/Compression/BZip2/BZip2InputStream.cs @@ -6,7 +6,7 @@ // ReSharper disable CommentTypo -namespace SharpHDiffPatch.New.IO.Compression.BZip2; +namespace SharpHPatchZ.IO.Compression.BZip2; /// /// An input stream that decompresses files in the BZip2 format. @@ -18,8 +18,8 @@ public sealed class BZip2InputStream : Stream private const int AlphaTableStride = BZip2Constants.MaximumAlphaSize; private const int CodeTableStride = BZip2Constants.MaximumCodeLength; - private readonly bool _decompressConcatenated; - private readonly bool _leaveOpen; + private readonly bool _decompressConcatenated; + private readonly bool _leaveOpen; private readonly Stream _baseStream; // Buffer compressed input. The original implementation called Stream.ReadByte() @@ -49,10 +49,10 @@ public sealed class BZip2InputStream : Stream private byte[] _ll8 = []; private ushort[] _perm; - private readonly int[] _unZfTab; - private readonly int[] _limit = new int[BZip2Constants.GroupCount * CodeTableStride]; - private readonly int[] _baseArray = new int[BZip2Constants.GroupCount * CodeTableStride]; - private readonly byte[] _minLens = new byte[BZip2Constants.GroupCount]; + private readonly int[] _unZfTab; + private readonly int[] _limit = new int[BZip2Constants.GroupCount * CodeTableStride]; + private readonly int[] _baseArray = new int[BZip2Constants.GroupCount * CodeTableStride]; + private readonly byte[] _minLens = new byte[BZip2Constants.GroupCount]; private bool _streamEnd; private bool _blockEndPending; diff --git a/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs b/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs index ef5ff35..b1c7271 100644 --- a/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs +++ b/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs @@ -12,9 +12,9 @@ using System.IO; using System.IO.Compression; using System.Runtime.InteropServices; -using SharpHDiffPatch.New.Header; -using SharpHDiffPatch.New.IO.Compression.BZip2; -using SharpHDiffPatch.New.IO.Compression.Lzma; +using SharpHPatchZ.Header; +using SharpHPatchZ.IO.Compression.BZip2; +using SharpHPatchZ.IO.Compression.Lzma; #if NETSTANDARD2_0_OR_GREATER || NET6_0_OR_GREATER using ZstdManagedDecompressor = ZstdSharp.Decompressor; using ZstdManagedDecompressorParameter = ZstdSharp.Unsafe.ZSTD_dParameter; @@ -27,7 +27,7 @@ using ZstdNativeStream = ZstdNet.DecompressionStream; #endif -namespace SharpHDiffPatch.New.IO.Compression; +namespace SharpHPatchZ.IO.Compression; internal static class DecompressStreamFactory { diff --git a/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs b/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs index fc55a50..86ff605 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs @@ -1,18 +1,19 @@ using System; using System.Buffers; +using System.IO; using System.Runtime.CompilerServices; -namespace SharpHDiffPatch.New.IO.Compression.Lzma.LZ; +namespace SharpHPatchZ.IO.Compression.Lzma.LZ; internal class OutWindow : IDisposable { - private byte[] _buffer = []; - private int _windowSize; - private int _pos; - private int _streamPos; - private int _pendingLen; - private int _pendingDist; - private System.IO.Stream _stream; + private byte[] _buffer = []; + private int _windowSize; + private int _pos; + private int _streamPos; + private int _pendingLen; + private int _pendingDist; + private Stream? _stream; public long Total; public long Limit; @@ -36,13 +37,13 @@ public void Create(int windowSize) public void Reset() => Create(_windowSize); - public void Init(System.IO.Stream stream) + public void Init(Stream stream) { ReleaseStream(); _stream = stream; } - public void Train(System.IO.Stream stream) + public void Train(Stream stream) { long len = stream.Length; int size = len < _windowSize ? (int)len : _windowSize; @@ -179,7 +180,7 @@ public byte GetByte(int distance) return _buffer[pos]; } - public int CopyStream(System.IO.Stream stream, int len) + public int CopyStream(Stream stream, int len) { int size = len; while (size > 0 && _pos < _windowSize && Total < Limit) diff --git a/SharpHPatchZ/IO/Compression/Lzma/LzmaBase.cs b/SharpHPatchZ/IO/Compression/Lzma/LzmaBase.cs index c047eb9..972676b 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LzmaBase.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LzmaBase.cs @@ -1,4 +1,4 @@ -namespace SharpHDiffPatch.New.IO.Compression.Lzma; +namespace SharpHPatchZ.IO.Compression.Lzma; internal abstract class Base { diff --git a/SharpHPatchZ/IO/Compression/Lzma/LzmaDecoder.cs b/SharpHPatchZ/IO/Compression/Lzma/LzmaDecoder.cs index 4973456..505577f 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LzmaDecoder.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LzmaDecoder.cs @@ -1,10 +1,10 @@ using System; using System.Buffers; using System.Runtime.CompilerServices; -using SharpHDiffPatch.New.IO.Compression.Lzma.LZ; -using SharpHDiffPatch.New.IO.Compression.Lzma.RangeCoder; +using SharpHPatchZ.IO.Compression.Lzma.LZ; +using SharpHPatchZ.IO.Compression.Lzma.RangeCoder; -namespace SharpHDiffPatch.New.IO.Compression.Lzma; +namespace SharpHPatchZ.IO.Compression.Lzma; internal class Decoder : IDisposable { diff --git a/SharpHPatchZ/IO/Compression/Lzma/LzmaExceptions.cs b/SharpHPatchZ/IO/Compression/Lzma/LzmaExceptions.cs index 2c7a5f5..e17a855 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LzmaExceptions.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LzmaExceptions.cs @@ -1,6 +1,6 @@ using System; -namespace SharpHDiffPatch.New.IO.Compression.Lzma; +namespace SharpHPatchZ.IO.Compression.Lzma; /// /// The exception that is thrown when an error in input stream occurs during decoding. diff --git a/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs b/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs index 534d720..0a4b67c 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs @@ -1,16 +1,16 @@ using System; using System.Buffers.Binary; using System.IO; -using SharpHDiffPatch.New.IO.Compression.Lzma.LZ; -using SharpHDiffPatch.New.IO.Compression.Lzma.RangeCoder; +using SharpHPatchZ.IO.Compression.Lzma.LZ; +using SharpHPatchZ.IO.Compression.Lzma.RangeCoder; -namespace SharpHDiffPatch.New.IO.Compression.Lzma; +namespace SharpHPatchZ.IO.Compression.Lzma; public sealed class LzmaInputStream : Stream { private readonly Stream _inputStream; - private readonly long _inputSize; - private readonly long _outputSize; + private readonly long _inputSize; + private readonly long _outputSize; private readonly int _dictionarySize; private readonly OutWindow _outWindow = new(); @@ -42,13 +42,13 @@ public LzmaInputStream(byte[] properties, Stream inputStream, long inputSize, lo : this(properties, inputStream, inputSize, outputSize, null, properties.Length < 5, leaveOpen) { } public LzmaInputStream( - byte[] properties, - Stream inputStream, - long inputSize, - long outputSize, - Stream presetDictionary, - bool isLzma2, - bool leaveOpen = false) + byte[] properties, + Stream inputStream, + long inputSize, + long outputSize, + Stream? presetDictionary, + bool isLzma2, + bool leaveOpen = false) { _inputStream = inputStream; _inputSize = inputSize; diff --git a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs index 95b88ab..47746bb 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs @@ -1,8 +1,9 @@ using System; using System.Buffers; +using System.IO; using System.Runtime.CompilerServices; -namespace SharpHDiffPatch.New.IO.Compression.Lzma.RangeCoder; +namespace SharpHPatchZ.IO.Compression.Lzma.RangeCoder; internal class RangeDecoder : IDisposable { @@ -11,8 +12,8 @@ internal class RangeDecoder : IDisposable public uint Range; public uint Code; - public System.IO.Stream Stream; - public long Total; + public Stream Stream; + public long Total; private byte[] _inputBuffer = []; private int _inputOffset; @@ -20,7 +21,7 @@ internal class RangeDecoder : IDisposable private long _inputLimit; private bool _useInputBuffer; - public void Init(System.IO.Stream stream, long inputLimit = -1) + public void Init(Stream stream, long inputLimit = -1) { Stream = stream; _inputOffset = 0; diff --git a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs index 9011a3a..0d2bdc0 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.CompilerServices; -namespace SharpHDiffPatch.New.IO.Compression.Lzma.RangeCoder; +namespace SharpHPatchZ.IO.Compression.Lzma.RangeCoder; internal struct BitDecoder { diff --git a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs index 6f39a2a..f8ec21e 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs @@ -1,6 +1,6 @@ using System.Runtime.CompilerServices; -namespace SharpHDiffPatch.New.IO.Compression.Lzma.RangeCoder; +namespace SharpHPatchZ.IO.Compression.Lzma.RangeCoder; internal readonly struct BitTreeDecoder(int numBitLevels) { diff --git a/SharpHPatchZ/IO/Reader/BittableStreamReader.cs b/SharpHPatchZ/IO/Reader/BittableStreamReader.cs index 85b875a..7893b52 100644 --- a/SharpHPatchZ/IO/Reader/BittableStreamReader.cs +++ b/SharpHPatchZ/IO/Reader/BittableStreamReader.cs @@ -5,7 +5,7 @@ using System.Threading; using System.Threading.Tasks; -namespace SharpHDiffPatch.New.IO.Reader; +namespace SharpHPatchZ.IO.Reader; internal sealed class BittableStreamReader : IDisposable diff --git a/SharpHPatchZ/SharpHPatchZ.csproj b/SharpHPatchZ/SharpHPatchZ.csproj index 19bdf1e..7d03ae8 100644 --- a/SharpHPatchZ/SharpHPatchZ.csproj +++ b/SharpHPatchZ/SharpHPatchZ.csproj @@ -1,9 +1,9 @@  - SharpHPatch - SharpHPatch (formerly: SharpHDiffPatch) - Apply binary patches for HDiffPatch format. - SharpHPatch is a port of HPatchZ implementation from HDiffPatch project (by housisong), written in C#. Provides as nearly as fast as the native implementation, supporting multi-threading and several compressed formats. + SharpHPatchZ + SharpHPatchZ (formerly: SharpHDiffPatch) - Apply binary patches for HDiffPatch format. + SharpHPatchZ is a port of HPatchZ implementation from HDiffPatch project (by housisong), written in C#. Provides as nearly as fast as the native implementation, supporting multi-threading and several compressed formats. https://github.com/CollapseLauncher/SharpHDiffPatch.Core MIT Copyright (c) 2025 Collapse Project Team, Kemal Setya Adhi (neon-nyan) diff --git a/Test/Program.cs b/Test/Program.cs new file mode 100644 index 0000000..751fded --- /dev/null +++ b/Test/Program.cs @@ -0,0 +1,50 @@ +using SharpHDiffPatch.Core; +using SharpHPatchZ; +using SharpHPatchZ.Header; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Test; + +public class Program +{ + private static string TestPathInput = @"G:\Hi3SEA"; + private static string TestPathOutput = @"G:\Hi3CN-dotnet"; + private static string TestPathPatch = @"G:\Hi3SEAtoCNExecOnly.lzma2.diff"; + private static string TestPathPatchNoComp = @"G:\Hi3SEAtoCNExecOnly.nocomp.diff"; + public static async Task Main() + { + HDiffPatch hPatchOld = new(); + hPatchOld.Initialize(CreateStream); + // hPatchOld.Patch(TestPathInput, TestPathOutput, true); + + using (HDiffInfo info1 = await HPatch.CreateInstanceAsync(CreateStreamAsync)) + { + } + + using (HDiffInfo info2 = HPatch.CreateInstance(CreateStream)) + { + } + } + + public static Stream CreateStream() + { + FileStream stream = File.Open(TestPathPatch, FileMode.Open, FileAccess.Read, FileShare.Read); + return stream; + } + + public static (Stream, bool) CreateStream(long position) + { + FileStream stream = File.Open(TestPathPatch, FileMode.Open, FileAccess.Read, FileShare.Read); + stream.Position = position; + return (stream, false); + } + + public static ValueTask<(Stream, bool)> CreateStreamAsync(long position, CancellationToken token) + { + FileStream stream = File.Open(TestPathPatch, FileMode.Open, FileAccess.Read, FileShare.Read); + stream.Position = position; + return new ValueTask<(Stream, bool)>((stream, false)); + } +} \ No newline at end of file diff --git a/Test/Test.csproj b/Test/Test.csproj new file mode 100644 index 0000000..3abe44b --- /dev/null +++ b/Test/Test.csproj @@ -0,0 +1,17 @@ + + + + Exe + net10.0 + disable + enable + 14 + AnyCPU;x64;ARM64;x86 + + + + + + + + From 9b7e5c2767578030eb2fe29b2b9c86340686cccf Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Tue, 11 Aug 2026 00:26:06 +0700 Subject: [PATCH 04/72] Move and rename extern prefix --- SharpHPatchZ/Extension/ExceptionHelper.cs | 32 ++++- SharpHPatchZ/Extension/MemoryAlloc.cs | 16 +++ SharpHPatchZ/HPatch.UnmanagedExtern.cs | 152 +++++++++++++++++++++ SharpHPatchZ/HPatch.cs | 40 +++--- SharpHPatchZ/Header/HDiffChecksumResult.cs | 18 +++ SharpHPatchZ/Header/HeaderReader.cs | 40 ++---- SharpHPatchZ/Native/PInvoke.Unix.cs | 12 ++ SharpHPatchZ/Native/PInvoke.Windows.cs | 15 ++ SharpHPatchZ/Native/PInvoke.cs | 37 +++++ 9 files changed, 312 insertions(+), 50 deletions(-) create mode 100644 SharpHPatchZ/HPatch.UnmanagedExtern.cs create mode 100644 SharpHPatchZ/Header/HDiffChecksumResult.cs create mode 100644 SharpHPatchZ/Native/PInvoke.Unix.cs create mode 100644 SharpHPatchZ/Native/PInvoke.Windows.cs create mode 100644 SharpHPatchZ/Native/PInvoke.cs diff --git a/SharpHPatchZ/Extension/ExceptionHelper.cs b/SharpHPatchZ/Extension/ExceptionHelper.cs index a59a0c1..f61828c 100644 --- a/SharpHPatchZ/Extension/ExceptionHelper.cs +++ b/SharpHPatchZ/Extension/ExceptionHelper.cs @@ -1,6 +1,8 @@ using System; +using System.IO; #if NET8_0_OR_GREATER using System.Collections.Generic; +// ReSharper disable InconsistentNaming #endif namespace SharpHPatchZ.Extension; @@ -13,26 +15,46 @@ file static class Const { HDiffHeaderSignatureEmptyOrUnreadable, 0b_00000000_00000000_00000000_00000010 }, { HDiffHeaderMagicNotSupported, 0b_00000000_00000000_00000000_00000100 }, { HDiffHeaderCompressionNotSupported, 0b_00000000_00000000_00000000_00001000 }, - { HDiffHeaderChecksumNotSupported, 0b_00000000_00000000_00000000_00010000 } - }; + { HDiffHeaderChecksumNotSupported, 0b_00000000_00000000_00000000_00010000 }, + { HDiffHeaderEndOfFileOrData, 0b_00000000_00000000_00000000_00100000 }, + { HDiffPathIsEmptyOrInvalid, 0b_00000000_00000000_00000000_01000000 }, + { HDiffFILEDescriptorNull, 0b_00000000_00000000_00000000_10000000 }, + { HDiffIOException, 0b_00000000_00000000_00000001_00000000 }, + { HDiffInfoIsNull, 0b_00000000_00000000_00000010_00000000 } +}; #endif public const string HDiffHeaderSignatureEmptyOrUnreadable = "HDIFF_HeaderSignatureEmptyOrUnreadable"; public const string HDiffHeaderMagicNotSupported = "HDIFF_HeaderMagicNotSupported"; public const string HDiffHeaderCompressionNotSupported = "HDIFF_HeaderCompressionNotSupported"; public const string HDiffHeaderChecksumNotSupported = "HDIFF_HeaderChecksumNotSupported"; + public const string HDiffHeaderEndOfFileOrData = "HDIFF_EndOfFileOrData"; + public const string HDiffPathIsEmptyOrInvalid = "HDIFF_PathIsEmptyOrInvalid"; + public const string HDiffFILEDescriptorNull = "HDIFF_FILEDescriptorNull"; + public const string HDiffIOException = "HDIFF_IOException"; + public const string HDiffInfoIsNull = "HDIFF_InfoIsNull"; } public static class ExceptionHelper { public static void ThrowHDiffHeaderSignatureEmptyOrUnreadable() => throw new InvalidOperationException($"[{Const.HDiffHeaderSignatureEmptyOrUnreadable}] Header signature is empty or unreadable!"); - public static void ThrowHdiffHeaderMagicNotSupported(ReadOnlySpan magic) + public static void ThrowHDiffHeaderMagicNotSupported(ReadOnlySpan magic) => throw new NotSupportedException($"[{Const.HDiffHeaderMagicNotSupported}] Header magic: {magic.ToString()} is not supported!"); - public static void ThrowHdiffHeaderCompressionNotSupported(ReadOnlySpan enumString) + public static void ThrowHDiffHeaderCompressionNotSupported(ReadOnlySpan enumString) => throw new NotSupportedException($"[{Const.HDiffHeaderCompressionNotSupported}] HDIFF compression: {enumString.ToString()} is not supported!"); - public static void ThrowHdiffHeaderChecksumNotSupported(ReadOnlySpan enumString) + public static void ThrowHDiffHeaderChecksumNotSupported(ReadOnlySpan enumString) => throw new NotSupportedException($"[{Const.HDiffHeaderChecksumNotSupported}] HDIFF checksum: {enumString.ToString()} is not supported!"); + public static void ThrowHDiffEndOfFileOrData(Exception innerException) + => throw new EndOfStreamException($"[{Const.HDiffHeaderEndOfFileOrData}] HDiff Data has reached End-of-File or Data", innerException); + public static void ThrowHDiffPathIsEmptyOrInvalid() + => throw new InvalidOperationException($"[{Const.HDiffPathIsEmptyOrInvalid}] File or Directory path is empty or invalid"); + public static void ThrowHDiffFILEDescriptorNull() + => throw new NullReferenceException($"[{Const.HDiffFILEDescriptorNull}] FILE descriptor cannot be null!"); + public static void ThrowHDiffIOException(Exception ex) + => throw new IOException($"[{Const.HDiffIOException}] An IO Error has occurred with message: {ex.Message}", ex); + public static void ThrowHDiffInfoIsNull() + => throw new NullReferenceException($"[{Const.HDiffInfoIsNull}] HDiffInfo pointer is null!"); #if NET8_0_OR_GREATER public static int TryGetReturnCodeFromError(Exception ex) diff --git a/SharpHPatchZ/Extension/MemoryAlloc.cs b/SharpHPatchZ/Extension/MemoryAlloc.cs index 74d05c0..4e22403 100644 --- a/SharpHPatchZ/Extension/MemoryAlloc.cs +++ b/SharpHPatchZ/Extension/MemoryAlloc.cs @@ -48,6 +48,22 @@ public static nint CopyToUnmanaged(this ref T toCopy) where T : unmanaged => (nint)toCopy.CopyToUnmanagedUnsafe(); + public static void CopyTo(this ref T from, ref T to) + where T : unmanaged + => to = from; + + public static void CopyTo(this ref T from, void* to) + where T : unmanaged + => Unsafe.AsRef(to) = from; + + public static void CopyTo(void* from, void* to) + where T : unmanaged + => Unsafe.AsRef(to) = Unsafe.AsRef(from); + + public static void CopyTo(void* from, ref T to) + where T : unmanaged + => to = Unsafe.AsRef(from); + public static void Free(T* ptr) where T : unmanaged { diff --git a/SharpHPatchZ/HPatch.UnmanagedExtern.cs b/SharpHPatchZ/HPatch.UnmanagedExtern.cs new file mode 100644 index 0000000..94b118c --- /dev/null +++ b/SharpHPatchZ/HPatch.UnmanagedExtern.cs @@ -0,0 +1,152 @@ +#if NET8_0_OR_GREATER +using System; +using System.IO; +using System.Runtime.InteropServices; +using Microsoft.Win32.SafeHandles; +using SharpHPatchZ.Extension; +using SharpHPatchZ.Header; +using SharpHPatchZ.Native; +// ReSharper disable InconsistentNaming + +#if USEWINDOWS +using ConventionCall = System.Runtime.CompilerServices.CallConvStdcall; +#else +using ConventionCall = System.Runtime.CompilerServices.CallConvCdecl; +#endif + +namespace SharpHPatchZ; + +public static partial class HPatch +{ + [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_read_header_signature_string")] + public static unsafe int SharpHPatchZ_ReadHeaderSignatureString(void* signWP, int signWLen, HDiffMagic* magicTypeP, HDiffCompression* compressionTypeP, HDiffChecksum* checksumTypeP) + { + try + { + ReadOnlySpan signature = new(signWP, signWLen); + ref HDiffMagic magicTypeRef = ref magicTypeP[0]; + ref HDiffCompression compressionTypeRef = ref compressionTypeP[0]; + ref HDiffChecksum checksumTypeRef = ref checksumTypeP[0]; + + HeaderReader.ReadBasicHeaderSignature(signature, + out magicTypeRef, + out compressionTypeRef, + out checksumTypeRef); + return 0; + } + catch (Exception ex) + { + return ExceptionHelper.TryGetReturnCodeFromError(ex); + } + } + + [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_init_from_memory")] + public static unsafe int SharpHPatchZ_InitializeFromMemory(byte* dataP, long dataLength, HDiffInfo* signP) + { + try + { + HDiffInfo thisInfo = CreateInstance(CreateUnmanagedStreamWrapper); + thisInfo.CopyTo(signP); + + return 0; + } + catch (Exception ex) + { + return ExceptionHelper.TryGetReturnCodeFromError(ex); + } + + (Stream Stream, bool LeaveOpen) CreateUnmanagedStreamWrapper(long position) + { + UnmanagedMemoryStream stream = new(dataP, dataLength); + stream.Position = position; + return (stream, false); + } + } + + [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_init_from_filepath")] + public static unsafe int SharpHPatchZ_InitializeFromFilePath(char* pathW, int pathWLength, HDiffInfo* signP) + { + try + { + if (pathW == null || + pathWLength == 0) + { + ExceptionHelper.ThrowHDiffPathIsEmptyOrInvalid(); + } + + string filePath = new ReadOnlySpan(pathW, pathWLength).Trim('\0').ToString(); + HDiffInfo thisInfo = CreateInstance(CreateFileStreamWrapper); + thisInfo.CopyTo(signP); + + return 0; + + (Stream Stream, bool LeaveOpen) CreateFileStreamWrapper(long position) + { + FileStream stream = new(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); + stream.Position = position; + return (stream, false); + } + } + catch (Exception ex) + { + return ExceptionHelper.TryGetReturnCodeFromError(ex); + } + } + + [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_init_from_FILE")] + public static unsafe int SharpHPatchZ_InitializeFromFILE(void* FILEP, HDiffInfo* signP) + { + try + { + if (FILEP == null) + { + ExceptionHelper.ThrowHDiffFILEDescriptorNull(); + } + + HDiffInfo thisInfo = CreateInstance(CreateFileStreamWrapper); + thisInfo.CopyTo(signP); + + return 0; + } + catch (Exception ex) + { + return ExceptionHelper.TryGetReturnCodeFromError(ex); + } + + (Stream Stream, bool LeaveOpen) CreateFileStreamWrapper(long position) + { + try + { + SafeFileHandle fileHandle = PInvoke.GetSafeFileHandleFromFILE(FILEP); + FileStream stream = new(fileHandle, FileAccess.Read); + stream.Position = position; + return (stream, true); + } + catch (IOException ex) + { + ExceptionHelper.ThrowHDiffIOException(ex); + throw; + } + } + } + + [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_free_diff_info")] + public static unsafe int SharpHPatchZ_FreeDiffInfo(HDiffInfo* ptr) + { + try + { + if (ptr == null) + { + ExceptionHelper.ThrowHDiffInfoIsNull(); + } + + MemoryAlloc.Free(ptr->MetadataP); + return 0; + } + catch (Exception ex) + { + return ExceptionHelper.TryGetReturnCodeFromError(ex); + } + } +} +#endif diff --git a/SharpHPatchZ/HPatch.cs b/SharpHPatchZ/HPatch.cs index f446b15..e2cb4ce 100644 --- a/SharpHPatchZ/HPatch.cs +++ b/SharpHPatchZ/HPatch.cs @@ -1,41 +1,49 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using SharpHPatchZ.Extension; using SharpHPatchZ.Header; using SharpHPatchZ.IO.Reader; namespace SharpHPatchZ; public delegate (Stream Stream, bool LeaveOpen) CreateStream(long position); - public delegate ValueTask<(Stream Stream, bool LeaveOpen)> CreateStreamAsync(long position, CancellationToken token); -public static class HPatch +public static partial class HPatch { - public static HDiffInfo CreateInstance(CreateStream createStream) + public static HDiffInfo CreateInstance(CreateStream createPatchStream) { - (Stream stream, bool isDispose) = createStream(0); - using BittableStreamReader reader = new(stream, leaveOpen: !isDispose); - - string signature = reader.ReadStringToNull(); - HDiffInfo info = default; - HeaderReader.ReadHeaderSignature(signature, ref info); - HeaderReader.ReadHDiffHeaderMetadata(ref info, reader, createStream); - - return info; + try + { + (Stream stream, bool leaveOpen) = createPatchStream(0); + using BittableStreamReader reader = new(stream, leaveOpen: leaveOpen); + + string signature = reader.ReadStringToNull(); + HDiffInfo info = default; + HeaderReader.ReadHeaderSignature(signature, ref info); + HeaderReader.ReadHDiffHeaderMetadata(ref info, reader, createPatchStream); + + return info; + } + catch (EndOfStreamException eofStream) + { + ExceptionHelper.ThrowHDiffEndOfFileOrData(eofStream); + throw; + } } public static async ValueTask CreateInstanceAsync( - CreateStreamAsync createStream, + CreateStreamAsync createPatchStreamAsync, CancellationToken token = default) { - (Stream stream, bool isDispose) = await createStream(0, token); - using BittableStreamReader reader = new(stream, leaveOpen: !isDispose); + (Stream stream, bool leaveOpen) = await createPatchStreamAsync(0, token); + using BittableStreamReader reader = new(stream, leaveOpen: leaveOpen); string signature = await reader.ReadStringToNullAsync(token: token); HDiffInfo info = default; HeaderReader.ReadHeaderSignature(signature, ref info); - info = await HeaderReader.ReadHDiffHeaderMetadataAsync(info, reader, createStream, token); + info = await HeaderReader.ReadHDiffHeaderMetadataAsync(info, reader, createPatchStreamAsync, token); return info; } diff --git a/SharpHPatchZ/Header/HDiffChecksumResult.cs b/SharpHPatchZ/Header/HDiffChecksumResult.cs new file mode 100644 index 0000000..8f41e97 --- /dev/null +++ b/SharpHPatchZ/Header/HDiffChecksumResult.cs @@ -0,0 +1,18 @@ +using System.Runtime.InteropServices; + +namespace SharpHPatchZ.Header; + +[StructLayout(LayoutKind.Sequential)] +public struct HDiffChecksumResult +{ + public bool HasChecksumSupport; + public bool IsSuccessful; + public HDiffInfo DiffInfo; + + public static implicit operator bool(HDiffChecksumResult result) + { + return !result.HasChecksumSupport || + // Pass it as true anyways while Diff has no checksum support + result.IsSuccessful; + } +} diff --git a/SharpHPatchZ/Header/HeaderReader.cs b/SharpHPatchZ/Header/HeaderReader.cs index 7462473..67f776a 100644 --- a/SharpHPatchZ/Header/HeaderReader.cs +++ b/SharpHPatchZ/Header/HeaderReader.cs @@ -1,14 +1,13 @@ -using SharpHPatchZ.Extension; -using SharpHPatchZ.Header.Metadata; -using SharpHPatchZ.IO.Compression; -using SharpHPatchZ.IO.Reader; -using System; +using System; using System.Buffers; using System.IO; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using SharpHPatchZ.Extension; +using SharpHPatchZ.Header.Metadata; +using SharpHPatchZ.IO.Compression; +using SharpHPatchZ.IO.Reader; namespace SharpHPatchZ.Header; @@ -16,23 +15,6 @@ public class HeaderReader { private delegate ref PatchMetadata PatchMetadataAllocator(ref HDiffInfo info); -#if NET8_0_OR_GREATER - [UnmanagedCallersOnly(CallConvs = [typeof(CallConvStdcall)], EntryPoint = "Extent_HeaderReader_ReadHeaderSignature")] - public static unsafe int ReadHeaderSignature_Extent(void* wSignP, int wSignLen, HDiffInfo* signP) - { - try - { - ReadOnlySpan signature = new(wSignP, wSignLen); - ReadHeaderSignature(signature, ref signP[0]); - return 0; - } - catch (Exception ex) - { - return ExceptionHelper.TryGetReturnCodeFromError(ex); - } - } -#endif - public static void ReadHeaderSignature(ReadOnlySpan signature, ref HDiffInfo info) { ReadBasicHeaderSignature(signature, @@ -41,7 +23,7 @@ public static void ReadHeaderSignature(ReadOnlySpan signature, ref HDiffIn out info.ChecksumType); } - private static void ReadBasicHeaderSignature( + internal static void ReadBasicHeaderSignature( ReadOnlySpan signature, out HDiffMagic magicType, out HDiffCompression compressionType, @@ -72,7 +54,7 @@ private static void ReadBasicHeaderSignature( if (!Enum.TryParse(magicSpan, true, out magicType)) { - ExceptionHelper.ThrowHdiffHeaderMagicNotSupported(magicSpan); + ExceptionHelper.ThrowHDiffHeaderMagicNotSupported(magicSpan); } // Parse HDIFF19 (Directory Patch) enums @@ -81,13 +63,13 @@ private static void ReadBasicHeaderSignature( if (compressionTypeSpan.Length != 0 && !Enum.TryParse(compressionTypeSpan, true, out compressionType)) { - ExceptionHelper.ThrowHdiffHeaderCompressionNotSupported(compressionTypeSpan); + ExceptionHelper.ThrowHDiffHeaderCompressionNotSupported(compressionTypeSpan); } if (checksumTypeSpan.Length != 0 && !Enum.TryParse(checksumTypeSpan, true, out checksumType)) { - ExceptionHelper.ThrowHdiffHeaderChecksumNotSupported(checksumTypeSpan); + ExceptionHelper.ThrowHDiffHeaderChecksumNotSupported(checksumTypeSpan); } return; @@ -99,13 +81,13 @@ private static void ReadBasicHeaderSignature( if (compressionTypeSpan.Length != 0 && !Enum.TryParse(compressionTypeSpan, true, out compressionType)) { - ExceptionHelper.ThrowHdiffHeaderCompressionNotSupported(compressionTypeSpan); + ExceptionHelper.ThrowHDiffHeaderCompressionNotSupported(compressionTypeSpan); } return; } - ExceptionHelper.ThrowHdiffHeaderMagicNotSupported(magicSpan); + ExceptionHelper.ThrowHDiffHeaderMagicNotSupported(magicSpan); } internal static void ReadHDiffHeaderMetadata( diff --git a/SharpHPatchZ/Native/PInvoke.Unix.cs b/SharpHPatchZ/Native/PInvoke.Unix.cs new file mode 100644 index 0000000..effe480 --- /dev/null +++ b/SharpHPatchZ/Native/PInvoke.Unix.cs @@ -0,0 +1,12 @@ +using System.Runtime.InteropServices; + +namespace SharpHPatchZ.Native; + +internal static unsafe partial class PInvoke +{ + public static class Unix + { + [DllImport("__Internal", EntryPoint = "fileno", CallingConvention = CallingConvention.Cdecl)] + public static extern int fileno(void* stream); + } +} diff --git a/SharpHPatchZ/Native/PInvoke.Windows.cs b/SharpHPatchZ/Native/PInvoke.Windows.cs new file mode 100644 index 0000000..ff5d695 --- /dev/null +++ b/SharpHPatchZ/Native/PInvoke.Windows.cs @@ -0,0 +1,15 @@ +using System.Runtime.InteropServices; + +namespace SharpHPatchZ.Native; + +internal static unsafe partial class PInvoke +{ + public static class Windows + { + [DllImport("ucrtbase", CallingConvention = CallingConvention.Cdecl)] + public static extern int _fileno(void* stream); + + [DllImport("ucrtbase", CallingConvention = CallingConvention.Cdecl)] + public static extern nint _get_osfhandle(int fd); + } +} diff --git a/SharpHPatchZ/Native/PInvoke.cs b/SharpHPatchZ/Native/PInvoke.cs new file mode 100644 index 0000000..03269af --- /dev/null +++ b/SharpHPatchZ/Native/PInvoke.cs @@ -0,0 +1,37 @@ +using System; +using System.IO; +using Microsoft.Win32.SafeHandles; +// ReSharper disable InconsistentNaming + +namespace SharpHPatchZ.Native; + +internal static unsafe partial class PInvoke +{ +#if NET8_0_OR_GREATER + public static SafeFileHandle GetSafeFileHandleFromFILE(void* file) + { + nint handle; + + if (OperatingSystem.IsWindows()) + { + int fd = Windows._fileno(file); + if (fd < 0) + throw new IOException("_fileno() failed."); + + handle = Windows._get_osfhandle(fd); + if (handle == -1) + throw new IOException("_get_osfhandle() failed."); + } + else + { + int fd = Unix.fileno(file); + if (fd < 0) + throw new IOException("fileno() failed."); + + handle = fd; + } + + return new SafeFileHandle(handle, ownsHandle: false); + } +#endif +} From cf553852da2a18cf232ba9eb265252128fa96553 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 17 Aug 2026 23:35:21 +0700 Subject: [PATCH 05/72] Push local changes --- SharpHPatchZ/Extension/MetadataExtension.cs | 2 +- SharpHPatchZ/HPatch.cs | 13 +- SharpHPatchZ/Header/HeaderReader.cs | 103 ++-- ...hMetadata.cs => DirectoryPatchMetadata.cs} | 4 +- SharpHPatchZ/Header/Metadata/PatchMetadata.cs | 1 + .../IO/Compression/CompressionStreamHelper.cs | 11 + .../IO/Reader/BittableStreamReader.cs | 136 ++++- .../Reader/DecompressionTransitionStream.cs | 492 ++++++++++++++++++ SharpHPatchZ/PatchOptions.cs | 18 + SharpHPatchZ/ProgressCallback.cs | 53 ++ 10 files changed, 762 insertions(+), 71 deletions(-) rename SharpHPatchZ/Header/Metadata/{HeaderDirectoryPatchMetadata.cs => DirectoryPatchMetadata.cs} (96%) create mode 100644 SharpHPatchZ/IO/Reader/DecompressionTransitionStream.cs create mode 100644 SharpHPatchZ/PatchOptions.cs create mode 100644 SharpHPatchZ/ProgressCallback.cs diff --git a/SharpHPatchZ/Extension/MetadataExtension.cs b/SharpHPatchZ/Extension/MetadataExtension.cs index e3e412e..dcc8647 100644 --- a/SharpHPatchZ/Extension/MetadataExtension.cs +++ b/SharpHPatchZ/Extension/MetadataExtension.cs @@ -29,7 +29,7 @@ public bool TryDisposeIfMetadataType() Unsafe.As(ref metadata).Dispose(); break; case MetadataTypeConst.HeaderDirectoryPatchMetadataType: - Unsafe.As(ref metadata).Dispose(); + Unsafe.As(ref metadata).Dispose(); break; case MetadataTypeConst.PatchMetadataType: Unsafe.As(ref metadata).Dispose(); diff --git a/SharpHPatchZ/HPatch.cs b/SharpHPatchZ/HPatch.cs index e2cb4ce..33b512b 100644 --- a/SharpHPatchZ/HPatch.cs +++ b/SharpHPatchZ/HPatch.cs @@ -22,7 +22,7 @@ public static HDiffInfo CreateInstance(CreateStream createPatchStream) string signature = reader.ReadStringToNull(); HDiffInfo info = default; HeaderReader.ReadHeaderSignature(signature, ref info); - HeaderReader.ReadHDiffHeaderMetadata(ref info, reader, createPatchStream); + HeaderReader.ReadHDiffHeaderMetadata(ref info, reader); return info; } @@ -43,8 +43,17 @@ public static async ValueTask CreateInstanceAsync( string signature = await reader.ReadStringToNullAsync(token: token); HDiffInfo info = default; HeaderReader.ReadHeaderSignature(signature, ref info); - info = await HeaderReader.ReadHDiffHeaderMetadataAsync(info, reader, createPatchStreamAsync, token); + info = await HeaderReader.ReadHDiffHeaderMetadataAsync(info, reader, token); return info; } + + public static void Patch(HDiffInfo info, + CreateStream createPatchStream, + string inputPath, + string outputPath, + PatchOptions options = default) + { + + } } diff --git a/SharpHPatchZ/Header/HeaderReader.cs b/SharpHPatchZ/Header/HeaderReader.cs index 67f776a..14668f8 100644 --- a/SharpHPatchZ/Header/HeaderReader.cs +++ b/SharpHPatchZ/Header/HeaderReader.cs @@ -92,14 +92,13 @@ internal static void ReadBasicHeaderSignature( internal static void ReadHDiffHeaderMetadata( ref HDiffInfo info, - BittableStreamReader streamReader, - CreateStream additionalStreamCreate) + BittableStreamReader streamReader) { PatchMetadataAllocator patchMetadataAllocator = DefaultPatchMetadataAllocator; switch (info.MagicType) { case HDiffMagic.HDiff19: - ReadHDiff19HeaderInfoCore(ref info, streamReader, additionalStreamCreate); + ReadHDiff19HeaderInfoCore(ref info, streamReader); patchMetadataAllocator = HDiff19PatchMetadataAllocator; // Continue reading HDiff13 data section. goto case HDiffMagic.HDiff13; @@ -112,7 +111,6 @@ internal static void ReadHDiffHeaderMetadata( internal static async Task ReadHDiffHeaderMetadataAsync( HDiffInfo info, BittableStreamReader streamReader, - CreateStreamAsync additionalStreamCreate, CancellationToken token) { PatchMetadataAllocator patchMetadataAllocator = DefaultPatchMetadataAllocator; @@ -121,7 +119,6 @@ internal static async Task ReadHDiffHeaderMetadataAsync( case HDiffMagic.HDiff19: info = await ReadHDiff19HeaderInfoAsyncCore(info, streamReader, - additionalStreamCreate, token); patchMetadataAllocator = HDiff19PatchMetadataAllocator; @@ -146,15 +143,14 @@ private static unsafe ref PatchMetadata HDiff19PatchMetadataAllocator(ref HDiffI PatchMetadata* patchMetadata = MemoryAlloc.Alloc(); patchMetadata->Init(); - ref HeaderDirectoryPatchMetadata dirPatchMetadata = ref info.MetadataAs(); + ref DirectoryPatchMetadata dirPatchMetadata = ref info.MetadataAs(); dirPatchMetadata.PatchMetadataP = patchMetadata; return ref Unsafe.AsRef(patchMetadata); } private static unsafe void ReadHDiff19HeaderInfoCore( ref HDiffInfo info, - BittableStreamReader streamReader, - CreateStream additionalStreamCreate) + BittableStreamReader streamReader) { byte isInputDir = streamReader.ReadByte(); byte isOutputDir = streamReader.ReadByte(); @@ -185,28 +181,33 @@ private static unsafe void ReadHDiff19HeaderInfoCore( Span checksumData = stackalloc byte[checksumDataLen]; streamReader.ReadBytes(checksumData); - long headDataOffset = streamReader.Offset; - // Try seek primary reader. Read the HDiff13 signature and sanity. - long toSkipHeadDataSize = headDataCompressedSize > 0 ? headDataCompressedSize : headDataSize; - streamReader.AdvanceSeekTo((int)toSkipHeadDataSize); - string sanityDiffPatchSignature = streamReader.ReadStringToNull(); - ReadBasicHeaderSignature(sanityDiffPatchSignature, out _, out _, out _); + if (headDataCompressedSize > 0) + { + streamReader.ContinueWithDecompressor(new HDiffDecompressor(info.CompressionType), + headDataCompressedSize, + headDataSize); + } - // Read HeadData. - (Stream additionalStream, bool leaveOpenAdditionalStream) = additionalStreamCreate(headDataOffset); - using Stream additionalStreamDecompressed = DecompressStreamFactory.CreateStream(info.CompressionType, additionalStream, leaveOpenAdditionalStream); - using BittableStreamReader anotherStreamReader = new(additionalStreamDecompressed, leaveOpen: leaveOpenAdditionalStream); + long headDataStartOffset = streamReader.Offset; - UnmanagedArray* inputPathEntryArray = anotherStreamReader.CreateUnmanagedStringList(inputPathEntryCount, (int)inputPathEntryBufferSize); - UnmanagedArray* outputPathEntryArray = anotherStreamReader.CreateUnmanagedStringList(outputPathEntryCount, (int)outputPathEntryBufferSize); - int* inputFilesIndexArray = anotherStreamReader.CreateUnmanagedInt64As32List(inputRefFileCount); - int* outputFilesIndexArray = anotherStreamReader.CreateUnmanagedInt64As32List(outputRefFileCount); - long* outputFilesSizesArray = anotherStreamReader.CreateUnmanagedInt64List(outputRefFileCount); - FileIndexPair* sameFilePathIndexPairArray = anotherStreamReader.CreateUnmanagedIndexPairList(sameFilePathEntryCount); - int* newExecuteListArray = anotherStreamReader.CreateUnmanagedInt64As32List(newExecuteCount); + UnmanagedArray* inputPathEntryArray = streamReader.CreateUnmanagedStringList(inputPathEntryCount, (int)inputPathEntryBufferSize); + UnmanagedArray* outputPathEntryArray = streamReader.CreateUnmanagedStringList(outputPathEntryCount, (int)outputPathEntryBufferSize); + int* inputFilesIndexArray = streamReader.CreateUnmanagedInt64As32List(inputRefFileCount); + int* outputFilesIndexArray = streamReader.CreateUnmanagedInt64As32List(outputRefFileCount); + long* outputFilesSizesArray = streamReader.CreateUnmanagedInt64List(outputRefFileCount); + FileIndexPair* sameFilePathIndexPairArray = streamReader.CreateUnmanagedIndexPairList(sameFilePathEntryCount); + int* newExecuteListArray = streamReader.CreateUnmanagedInt64As32List(newExecuteCount); - ref HeaderDirectoryPatchMetadata dirTypeMetadata = ref info.AllocMetadata(); + if (streamReader.Offset - headDataStartOffset != headDataSize) + { + throw new InvalidDataException("The directory head data length does not match its declared length."); + } + + string sanityDiffPatchSignature = streamReader.ReadStringToNull(); + ReadBasicHeaderSignature(sanityDiffPatchSignature, out _, out _, out _); + + ref DirectoryPatchMetadata dirTypeMetadata = ref info.AllocMetadata(); dirTypeMetadata.IsInputDir = isInputDir; dirTypeMetadata.IsOutputDir = isOutputDir; @@ -248,7 +249,6 @@ private static unsafe void ReadHDiff19HeaderInfoCore( private static async Task ReadHDiff19HeaderInfoAsyncCore( HDiffInfo info, BittableStreamReader streamReader, - CreateStreamAsync additionalStreamCreate, CancellationToken token) { byte isInputDir = await streamReader.ReadByteAsync(token); @@ -280,32 +280,35 @@ private static async Task ReadHDiff19HeaderInfoAsyncCore( byte[] checksumData = ArrayPool.Shared.Rent(checksumDataLen); await streamReader.ReadBytesAsync(checksumData.AsMemory(0, checksumDataLen), token); - long headDataOffset = streamReader.Offset; + if (headDataCompressedSize > 0) + { + streamReader.ContinueWithDecompressor(new HDiffDecompressor(info.CompressionType), + headDataCompressedSize, + headDataSize); + } - // Try seek primary reader. Read the HDiff13 signature and sanity. - long toSkipHeadDataSize = headDataCompressedSize > 0 ? headDataCompressedSize : headDataSize; - await streamReader.AdvanceSeekToAsync((int)toSkipHeadDataSize, token); - string sanityDiffPatchSignature = await streamReader.ReadStringToNullAsync(token); - ReadBasicHeaderSignature(sanityDiffPatchSignature, out _, out _, out _); + long headDataStartOffset = streamReader.Offset; - // Read HeadData. - (Stream additionalStream, bool leaveOpenAdditionalStream) = await additionalStreamCreate(headDataOffset, token); - using Stream additionalStreamDecompressed = - DecompressStreamFactory.CreateStream(info.CompressionType, additionalStream, leaveOpenAdditionalStream); - using BittableStreamReader anotherStreamReader = new(additionalStreamDecompressed, leaveOpen: leaveOpenAdditionalStream); + nint inputPathEntryArray = await streamReader.CreateUnmanagedStringListAsync(inputPathEntryCount, (int)inputPathEntryBufferSize, token); + nint outputPathEntryArray = await streamReader.CreateUnmanagedStringListAsync(outputPathEntryCount, (int)outputPathEntryBufferSize, token); + nint inputFilesIndexArray = await streamReader.CreateUnmanagedInt64As32ListAsync(inputRefFileCount, token); + nint outputFilesIndexArray = await streamReader.CreateUnmanagedInt64As32ListAsync(outputRefFileCount, token); + nint outputFilesSizesArray = await streamReader.CreateUnmanagedInt64ListAsync(outputRefFileCount, token); + nint sameFilePathIndexPairArray = await streamReader.CreateUnmanagedIndexPairListAsync(sameFilePathEntryCount, token); + nint newExecuteListArray = await streamReader.CreateUnmanagedInt64As32ListAsync(newExecuteCount, token); - nint inputPathEntryArray = await anotherStreamReader.CreateUnmanagedStringListAsync(inputPathEntryCount, (int)inputPathEntryBufferSize, token); - nint outputPathEntryArray = await anotherStreamReader.CreateUnmanagedStringListAsync(outputPathEntryCount, (int)outputPathEntryBufferSize, token); - nint inputFilesIndexArray = await anotherStreamReader.CreateUnmanagedInt64As32ListAsync(inputRefFileCount, token); - nint outputFilesIndexArray = await anotherStreamReader.CreateUnmanagedInt64As32ListAsync(outputRefFileCount, token); - nint outputFilesSizesArray = await anotherStreamReader.CreateUnmanagedInt64ListAsync(outputRefFileCount, token); - nint sameFilePathIndexPairArray = await anotherStreamReader.CreateUnmanagedIndexPairListAsync(sameFilePathEntryCount, token); - nint newExecuteListArray = await anotherStreamReader.CreateUnmanagedInt64As32ListAsync(newExecuteCount, token); + if (streamReader.Offset - headDataStartOffset != headDataSize) + { + throw new InvalidDataException("The directory head data length does not match its declared length."); + } + + string sanityDiffPatchSignature = await streamReader.ReadStringToNullAsync(token); + ReadBasicHeaderSignature(sanityDiffPatchSignature, out _, out _, out _); try { - ref HeaderDirectoryPatchMetadata dirTypeMetadata = ref info.AllocMetadata(); - dirTypeMetadata.IsInputDir = isInputDir; + ref DirectoryPatchMetadata dirTypeMetadata = ref info.AllocMetadata(); + dirTypeMetadata.IsInputDir = isInputDir; dirTypeMetadata.IsOutputDir = isOutputDir; unsafe @@ -384,8 +387,9 @@ private static unsafe void ReadHDiff13HeaderInfoCore( patchMetadata.RleControlDataSizeP->CompressedSize = rleControlDataSizeC; patchMetadata.RleCodeDataSizeP->Size = rleCodeDataSize; patchMetadata.RleCodeDataSizeP->CompressedSize = rleCodeDataSizeC; - patchMetadata.NewDiffDataSizeP->CompressedSize = newDiffSize; + patchMetadata.NewDiffDataSizeP->Size = newDiffSize; patchMetadata.NewDiffDataSizeP->CompressedSize = newDiffSizeC; + patchMetadata.DiffDataOffset = streamReader.OffsetUnderlyingStream; } private static async Task ReadHDiff13HeaderInfoAsyncCore( @@ -422,8 +426,9 @@ private static async Task ReadHDiff13HeaderInfoAsyncCore( patchMetadata.RleControlDataSizeP->CompressedSize = rleControlDataSizeC; patchMetadata.RleCodeDataSizeP->Size = rleCodeDataSize; patchMetadata.RleCodeDataSizeP->CompressedSize = rleCodeDataSizeC; - patchMetadata.NewDiffDataSizeP->CompressedSize = newDiffSize; + patchMetadata.NewDiffDataSizeP->Size = newDiffSize; patchMetadata.NewDiffDataSizeP->CompressedSize = newDiffSizeC; + patchMetadata.DiffDataOffset = streamReader.OffsetUnderlyingStream; return info; } diff --git a/SharpHPatchZ/Header/Metadata/HeaderDirectoryPatchMetadata.cs b/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs similarity index 96% rename from SharpHPatchZ/Header/Metadata/HeaderDirectoryPatchMetadata.cs rename to SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs index 79013d5..9e621d9 100644 --- a/SharpHPatchZ/Header/Metadata/HeaderDirectoryPatchMetadata.cs +++ b/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs @@ -4,9 +4,9 @@ namespace SharpHPatchZ.Header.Metadata; [StructLayout(LayoutKind.Sequential)] -public unsafe struct HeaderDirectoryPatchMetadata : IMetadataInit +public unsafe struct DirectoryPatchMetadata : IMetadataInit { - public HeaderDirectoryPatchMetadata() + public DirectoryPatchMetadata() { Init(); } diff --git a/SharpHPatchZ/Header/Metadata/PatchMetadata.cs b/SharpHPatchZ/Header/Metadata/PatchMetadata.cs index c96eb49..30eff9a 100644 --- a/SharpHPatchZ/Header/Metadata/PatchMetadata.cs +++ b/SharpHPatchZ/Header/Metadata/PatchMetadata.cs @@ -67,6 +67,7 @@ public bool IsDisposed public long DiffOldSize; public long CoverDataCount; + public long DiffDataOffset; public ChunkSizeInfo* CoverDataSizeP; public ChunkSizeInfo* RleControlDataSizeP; diff --git a/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs b/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs index b1c7271..4695991 100644 --- a/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs +++ b/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs @@ -29,6 +29,17 @@ namespace SharpHPatchZ.IO.Compression; +internal interface IDecompressor +{ + Stream CreateDecompressionStream(Stream sourceStream, bool leaveOpen); +} + +internal readonly struct HDiffDecompressor(HDiffCompression type) : IDecompressor +{ + public Stream CreateDecompressionStream(Stream sourceStream, bool leaveOpen) + => DecompressStreamFactory.CreateStream(type, sourceStream, leaveOpen); +} + internal static class DecompressStreamFactory { private delegate Stream ZstdStreamFallback(Stream stream, bool leaveOpen); diff --git a/SharpHPatchZ/IO/Reader/BittableStreamReader.cs b/SharpHPatchZ/IO/Reader/BittableStreamReader.cs index 7893b52..bd50449 100644 --- a/SharpHPatchZ/IO/Reader/BittableStreamReader.cs +++ b/SharpHPatchZ/IO/Reader/BittableStreamReader.cs @@ -4,6 +4,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using SharpHPatchZ.IO.Compression; namespace SharpHPatchZ.IO.Reader; @@ -19,17 +20,45 @@ internal sealed class BittableStreamReader private int _offset; private int _bufferedLength; - private readonly byte[] _backedBuffer; - public readonly Stream BackedStream; + private byte[] _backedBuffer; + public Stream BackedStream { get; private set; } - private readonly bool _leaveOpen; - private bool _isDisposed; + private bool _leaveOpen; + private bool _isDisposed; + + private long _consumedByteCount; + + private bool _hasUnderlyingStreamTransition; + private long _underlyingStreamTransitionLogicalEnd; + private long _underlyingStreamTransitionStart; + private long _underlyingStreamTransitionEnd; public int TagBitCount; public byte Tag; public byte PreviousByte; - public long Offset => _offset; + public long Offset => _consumedByteCount + _offset; + + public long OffsetUnderlyingStream + { + get + { + long logicalOffset = Offset; + if (!_hasUnderlyingStreamTransition) + { + return logicalOffset; + } + + // Compressed and decompressed bytes have no one-to-one mapping. Until + // the decoded segment is fully consumed, its source position remains at + // the compressed segment start. At the boundary it advances by the + // declared compressed length, then raw bytes continue one-to-one. + return logicalOffset < _underlyingStreamTransitionLogicalEnd + ? _underlyingStreamTransitionStart + : checked(_underlyingStreamTransitionEnd + + logicalOffset - _underlyingStreamTransitionLogicalEnd); + } + } public BittableStreamReader(Stream stream, int bufferSize = -1, bool leaveOpen = false) { @@ -57,6 +86,77 @@ public BittableStreamReader(Stream stream, int bufferSize = -1, bool leaveOpen = _leaveOpen = leaveOpen; } + public BittableStreamReader ContinueWithDecompressor( + IDecompressor decompressor, + long compressedLength, + long decompressedLength) + { + if (decompressor is null) + { + throw new ArgumentNullException(nameof(decompressor)); + } + + if (compressedLength < 0) + { + throw new ArgumentOutOfRangeException(nameof(compressedLength)); + } + + if (decompressedLength < 0) + { + throw new ArgumentOutOfRangeException(nameof(decompressedLength)); + } + + ThrowIfDisposed(); + ResetTag(); + + long transitionLogicalEnd = checked(Offset + decompressedLength); + long transitionUnderlyingStart = OffsetUnderlyingStream; + long transitionUnderlyingEnd = checked(transitionUnderlyingStart + compressedLength); + + byte[] replacementBuffer = ArrayPool.Shared.Rent(_backedBuffer.Length); + BufferedRemainderStream? remainderStream = null; + try + { + remainderStream = new BufferedRemainderStream(BackedStream, + _backedBuffer, + _offset, + _bufferedLength - _offset, + _leaveOpen); + + BoundedReadStream compressedStream = new(remainderStream, compressedLength); + Stream decompressedStream = decompressor.CreateDecompressionStream(compressedStream, leaveOpen: true); + Stream transitionStream = new DecompressionTransitionStream( + decompressedStream, + compressedStream, + remainderStream, + decompressedLength); + + _consumedByteCount += _offset; + _backedBuffer = replacementBuffer; + BackedStream = transitionStream; + _offset = 0; + _bufferedLength = 0; + _leaveOpen = false; + + _hasUnderlyingStreamTransition = true; + _underlyingStreamTransitionLogicalEnd = transitionLogicalEnd; + _underlyingStreamTransitionStart = transitionUnderlyingStart; + _underlyingStreamTransitionEnd = transitionUnderlyingEnd; + return this; + } + catch + { + ArrayPool.Shared.Return(replacementBuffer); + + // Decoder construction may consume input, so the original reader can no + // longer be restored safely after a failure. Transfer cleanup to the + // remainder stream and leave this instance disposed. + _isDisposed = true; + remainderStream?.Dispose(); + throw; + } + } + public byte ReadByte() { EnsureBuffered(1); @@ -98,7 +198,7 @@ public void ReadBytes(Span buffer) new ReadOnlySpan(_backedBuffer, _offset, copyLength).CopyTo(buffer); _offset += copyLength; - buffer = buffer[copyLength..]; + buffer = buffer[copyLength..]; } } @@ -133,7 +233,7 @@ public async ValueTask ReadBytesAsync( new ReadOnlyMemory(_backedBuffer, _offset, copyLength).CopyTo(buffer); _offset += copyLength; - buffer = buffer[copyLength..]; + buffer = buffer[copyLength..]; } } @@ -149,7 +249,7 @@ public string ReadStringToNull(int maxByteCount) ResetTag(); byte[] stringBuffer = ArrayPool.Shared.Rent(Math.Max(1, Math.Min(maxByteCount, 256))); - int stringLength = 0; + int stringLength = 0; try { while (true) @@ -191,7 +291,7 @@ public ValueTask ReadStringToNullAsync(CancellationToken token) => ReadStringToNullAsync(DefaultBufferSize, token); public async ValueTask ReadStringToNullAsync( - int maxByteCount, + int maxByteCount, CancellationToken token = default) { if (maxByteCount < 0) @@ -202,7 +302,7 @@ public async ValueTask ReadStringToNullAsync( ResetTag(); byte[] stringBuffer = ArrayPool.Shared.Rent(Math.Max(1, Math.Min(maxByteCount, 256))); - int stringLength = 0; + int stringLength = 0; try { while (true) @@ -260,7 +360,7 @@ public ValueTask ReadInt7BitAsync(CancellationToken token) public async ValueTask ReadInt7BitAsync( int tagBit, - CancellationToken token = default) + CancellationToken token = default) { byte code = await ReadFirstCodeAsync(tagBit, token); return await ReadInt7BitCoreAsync(code, tagBit, token); @@ -506,8 +606,9 @@ private void EnsureBuffered(int minimumByteCount) Buffer.BlockCopy(_backedBuffer, _offset, _backedBuffer, 0, available); } - _offset = 0; - _bufferedLength = available; + _consumedByteCount += _offset; + _offset = 0; + _bufferedLength = available; while (_bufferedLength < minimumByteCount) { int read = BackedStream.Read(_backedBuffer, @@ -544,14 +645,15 @@ private async ValueTask EnsureBufferedAsync( Buffer.BlockCopy(_backedBuffer, _offset, _backedBuffer, 0, available); } - _offset = 0; - _bufferedLength = available; + _consumedByteCount += _offset; + _offset = 0; + _bufferedLength = available; while (_bufferedLength < minimumByteCount) { #if NET6_0_OR_GREATER int read = await BackedStream.ReadAsync(_backedBuffer.AsMemory(_bufferedLength, _backedBuffer.Length - _bufferedLength), - token).ConfigureAwait(false); + token).ConfigureAwait(false); #else int read = await BackedStream.ReadAsync(_backedBuffer, _bufferedLength, @@ -618,4 +720,4 @@ public ValueTask DisposeAsync() return _leaveOpen ? ValueTask.CompletedTask : BackedStream.DisposeAsync(); } #endif -} +} \ No newline at end of file diff --git a/SharpHPatchZ/IO/Reader/DecompressionTransitionStream.cs b/SharpHPatchZ/IO/Reader/DecompressionTransitionStream.cs new file mode 100644 index 0000000..511ea35 --- /dev/null +++ b/SharpHPatchZ/IO/Reader/DecompressionTransitionStream.cs @@ -0,0 +1,492 @@ +using System; +using System.Buffers; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace SharpHPatchZ.IO.Reader; + +internal sealed class BufferedRemainderStream : Stream +{ + private readonly Stream _stream; + private readonly bool _leaveOpen; + + private byte[]? _buffer; + private int _offset; + private readonly int _end; + private bool _isDisposed; + + public BufferedRemainderStream( + Stream stream, + byte[] buffer, + int offset, + int count, + bool leaveOpen) + { + _stream = stream ?? throw new ArgumentNullException(nameof(stream)); + _buffer = buffer ?? throw new ArgumentNullException(nameof(buffer)); + _offset = offset; + _end = checked(offset + count); + _leaveOpen = leaveOpen; + } + + public override bool CanRead => !_isDisposed; + public override bool CanSeek => false; + public override bool CanWrite => false; + public override long Length => throw new NotSupportedException(); + + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + ValidateArguments(buffer, offset, count); + ThrowIfDisposed(); + + int bufferedRead = ReadBuffered(new Span(buffer, offset, count)); + return bufferedRead != 0 || count == 0 + ? bufferedRead + : _stream.Read(buffer, offset, count); + } + +#if NET6_0_OR_GREATER + public override int Read(Span buffer) + { + ThrowIfDisposed(); + + int bufferedRead = ReadBuffered(buffer); + return bufferedRead != 0 || buffer.IsEmpty + ? bufferedRead + : _stream.Read(buffer); + } + + public override async ValueTask ReadAsync( + Memory buffer, + CancellationToken cancellationToken = default) + { + ThrowIfDisposed(); + + int bufferedRead = ReadBuffered(buffer.Span); + return bufferedRead != 0 || buffer.IsEmpty + ? bufferedRead + : await _stream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false); + } +#endif + + public override async Task ReadAsync( + byte[] buffer, + int offset, + int count, + CancellationToken cancellationToken) + { + ValidateArguments(buffer, offset, count); + ThrowIfDisposed(); + + int bufferedRead = ReadBuffered(new Span(buffer, offset, count)); + return bufferedRead != 0 || count == 0 + ? bufferedRead + : await _stream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); + } + + private int ReadBuffered(Span destination) + { + byte[]? source = _buffer; + if (source is null) + { + return 0; + } + + int count = Math.Min(destination.Length, _end - _offset); + new ReadOnlySpan(source, _offset, count).CopyTo(destination); + _offset += count; + + if (_offset == _end) + { + _buffer = null; + ArrayPool.Shared.Return(source); + } + + return count; + } + + protected override void Dispose(bool disposing) + { + if (_isDisposed) + { + return; + } + + _isDisposed = true; + byte[]? buffer = _buffer; + _buffer = null; + if (buffer is not null) + { + ArrayPool.Shared.Return(buffer); + } + + if (disposing && !_leaveOpen) + { + _stream.Dispose(); + } + + base.Dispose(disposing); + } + +#if NET6_0_OR_GREATER + public override async ValueTask DisposeAsync() + { + if (_isDisposed) + { + return; + } + + _isDisposed = true; + byte[]? buffer = _buffer; + _buffer = null; + if (buffer is not null) + { + ArrayPool.Shared.Return(buffer); + } + + if (!_leaveOpen) + { + await _stream.DisposeAsync().ConfigureAwait(false); + } + } +#endif + + public override void Flush() { } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); + public override void SetLength(long value) => throw new NotSupportedException(); + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); + + private void ThrowIfDisposed() + { + if (_isDisposed) + { + throw new ObjectDisposedException(nameof(BufferedRemainderStream)); + } + } + + private static void ValidateArguments(byte[] buffer, int offset, int count) + { + if (buffer is null) throw new ArgumentNullException(nameof(buffer)); + if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset)); + if (count < 0) throw new ArgumentOutOfRangeException(nameof(count)); + if (buffer.Length - offset < count) throw new ArgumentException("Offset and count exceed the buffer length."); + } +} + +internal sealed class BoundedReadStream : Stream +{ + private readonly Stream _stream; + private readonly long _length; + private long _position; + + public long Remaining => _length - _position; + + public BoundedReadStream(Stream stream, long length) + { + _stream = stream ?? throw new ArgumentNullException(nameof(stream)); + _length = length >= 0 ? length : throw new ArgumentOutOfRangeException(nameof(length)); + } + + public override bool CanRead => true; + public override bool CanSeek => false; + public override bool CanWrite => false; + public override long Length => _length; + + public override long Position + { + get => _position; + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + int requested = (int)Math.Min(count, Remaining); + int read = _stream.Read(buffer, offset, requested); + _position += read; + return read; + } + +#if NET6_0_OR_GREATER + public override int Read(Span buffer) + { + int requested = (int)Math.Min(buffer.Length, Remaining); + int read = _stream.Read(buffer[..requested]); + _position += read; + return read; + } + + public override async ValueTask ReadAsync( + Memory buffer, + CancellationToken cancellationToken = default) + { + int requested = (int)Math.Min(buffer.Length, Remaining); + int read = await _stream.ReadAsync(buffer[..requested], cancellationToken).ConfigureAwait(false); + _position += read; + return read; + } +#endif + + public override async Task ReadAsync( + byte[] buffer, + int offset, + int count, + CancellationToken cancellationToken) + { + int requested = (int)Math.Min(count, Remaining); + int read = await _stream.ReadAsync(buffer, offset, requested, cancellationToken).ConfigureAwait(false); + _position += read; + return read; + } + + public override void Flush() { } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); + public override void SetLength(long value) => throw new NotSupportedException(); + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); +} + +internal sealed class DecompressionTransitionStream : Stream +{ + private readonly Stream _decompressedStream; + private readonly BoundedReadStream _compressedStream; + private readonly BufferedRemainderStream _remainderStream; + + private long _decompressedRemaining; + private bool _isDecoding = true; + private bool _isDisposed; + + public DecompressionTransitionStream( + Stream decompressedStream, + BoundedReadStream compressedStream, + BufferedRemainderStream remainderStream, + long decompressedLength) + { + _decompressedStream = decompressedStream ?? throw new ArgumentNullException(nameof(decompressedStream)); + _compressedStream = compressedStream ?? throw new ArgumentNullException(nameof(compressedStream)); + _remainderStream = remainderStream ?? throw new ArgumentNullException(nameof(remainderStream)); + _decompressedRemaining = decompressedLength >= 0 + ? decompressedLength + : throw new ArgumentOutOfRangeException(nameof(decompressedLength)); + } + + public override bool CanRead => !_isDisposed; + public override bool CanSeek => false; + public override bool CanWrite => false; + public override long Length => throw new NotSupportedException(); + + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + ThrowIfDisposed(); + if (count == 0) return 0; + + if (_isDecoding) + { + if (_decompressedRemaining != 0) + { + int requested = (int)Math.Min(count, _decompressedRemaining); + int read = _decompressedStream.Read(buffer, offset, requested); + if (read == 0) ThrowUnexpectedDecompressedEof(); + + _decompressedRemaining -= read; + return read; + } + + FinishDecoding(); + } + + return _remainderStream.Read(buffer, offset, count); + } + +#if NET6_0_OR_GREATER + public override int Read(Span buffer) + { + ThrowIfDisposed(); + if (buffer.IsEmpty) return 0; + + if (_isDecoding) + { + if (_decompressedRemaining != 0) + { + int requested = (int)Math.Min(buffer.Length, _decompressedRemaining); + int read = _decompressedStream.Read(buffer[..requested]); + if (read == 0) ThrowUnexpectedDecompressedEof(); + + _decompressedRemaining -= read; + return read; + } + + FinishDecoding(); + } + + return _remainderStream.Read(buffer); + } + + public override async ValueTask ReadAsync( + Memory buffer, + CancellationToken cancellationToken = default) + { + ThrowIfDisposed(); + if (buffer.IsEmpty) return 0; + + if (_isDecoding) + { + if (_decompressedRemaining != 0) + { + int requested = (int)Math.Min(buffer.Length, _decompressedRemaining); + int read = await _decompressedStream.ReadAsync(buffer[..requested], cancellationToken).ConfigureAwait(false); + if (read == 0) ThrowUnexpectedDecompressedEof(); + + _decompressedRemaining -= read; + return read; + } + + await FinishDecodingAsync(cancellationToken).ConfigureAwait(false); + } + + return await _remainderStream.ReadAsync(buffer, cancellationToken).ConfigureAwait(false); + } +#endif + + public override async Task ReadAsync( + byte[] buffer, + int offset, + int count, + CancellationToken cancellationToken) + { + ThrowIfDisposed(); + if (count == 0) return 0; + + if (_isDecoding) + { + if (_decompressedRemaining != 0) + { + int requested = (int)Math.Min(count, _decompressedRemaining); + int read = await _decompressedStream.ReadAsync(buffer, offset, requested, cancellationToken).ConfigureAwait(false); + if (read == 0) ThrowUnexpectedDecompressedEof(); + + _decompressedRemaining -= read; + return read; + } + + await FinishDecodingAsync(cancellationToken).ConfigureAwait(false); + } + + return await _remainderStream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false); + } + + private void FinishDecoding() + { + if (_decompressedStream.ReadByte() != -1) + { + throw new InvalidDataException("The decompressed segment is longer than its declared length."); + } + + byte[] scratch = ArrayPool.Shared.Rent(4096); + try + { + while (_compressedStream.Remaining != 0) + { + int read = _compressedStream.Read(scratch, 0, (int)Math.Min(scratch.Length, _compressedStream.Remaining)); + if (read == 0) throw new EndOfStreamException("The compressed segment ended before its declared length."); + } + } + finally + { + ArrayPool.Shared.Return(scratch); + } + + _decompressedStream.Dispose(); + _isDecoding = false; + } + + private async ValueTask FinishDecodingAsync(CancellationToken token) + { + byte[] scratch = ArrayPool.Shared.Rent(4096); + try + { + int extra = await _decompressedStream.ReadAsync(scratch, 0, 1, token).ConfigureAwait(false); + if (extra != 0) + { + throw new InvalidDataException("The decompressed segment is longer than its declared length."); + } + + while (_compressedStream.Remaining != 0) + { + int read = await _compressedStream.ReadAsync( + scratch, + 0, + (int)Math.Min(scratch.Length, _compressedStream.Remaining), + token).ConfigureAwait(false); + + if (read == 0) throw new EndOfStreamException("The compressed segment ended before its declared length."); + } + } + finally + { + ArrayPool.Shared.Return(scratch); + } + +#if NET6_0_OR_GREATER + await _decompressedStream.DisposeAsync().ConfigureAwait(false); +#else + _decompressedStream.Dispose(); +#endif + _isDecoding = false; + } + + protected override void Dispose(bool disposing) + { + if (_isDisposed) return; + _isDisposed = true; + + if (disposing) + { + _decompressedStream.Dispose(); + _compressedStream.Dispose(); + _remainderStream.Dispose(); + } + + base.Dispose(disposing); + } + +#if NET6_0_OR_GREATER + public override async ValueTask DisposeAsync() + { + if (_isDisposed) return; + _isDisposed = true; + + await _decompressedStream.DisposeAsync().ConfigureAwait(false); + _compressedStream.Dispose(); + await _remainderStream.DisposeAsync().ConfigureAwait(false); + GC.SuppressFinalize(this); + } +#endif + + public override void Flush() { } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); + public override void SetLength(long value) => throw new NotSupportedException(); + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); + + private void ThrowIfDisposed() + { + if (_isDisposed) + { + throw new ObjectDisposedException(nameof(DecompressionTransitionStream)); + } + } + + private static void ThrowUnexpectedDecompressedEof() + => throw new EndOfStreamException("The decompressed segment ended before its declared length."); +} diff --git a/SharpHPatchZ/PatchOptions.cs b/SharpHPatchZ/PatchOptions.cs new file mode 100644 index 0000000..63ff2ec --- /dev/null +++ b/SharpHPatchZ/PatchOptions.cs @@ -0,0 +1,18 @@ +using System.Runtime.InteropServices; + +namespace SharpHPatchZ; + +[StructLayout(LayoutKind.Sequential)] +public struct PatchOptions +{ + public uint ParallelThreads; + public bool IgnoreErrors; + public bool UseSIMD; + + public PatchOptions() + { + ParallelThreads = 0; + IgnoreErrors = false; + UseSIMD = true; + } +} diff --git a/SharpHPatchZ/ProgressCallback.cs b/SharpHPatchZ/ProgressCallback.cs new file mode 100644 index 0000000..e03bd0c --- /dev/null +++ b/SharpHPatchZ/ProgressCallback.cs @@ -0,0 +1,53 @@ +#if NET6_0_OR_GREATER +using System.Runtime.CompilerServices; +#endif +using System.Runtime.InteropServices; + +namespace SharpHPatchZ; + +public delegate void ProcessedBytesManagedCallback(long totalProcessed, long totalSize, int written); + +[StructLayout(LayoutKind.Sequential)] +public readonly struct ProgressCallback +{ +#if NET6_0_OR_GREATER + public readonly unsafe delegate* unmanaged[Cdecl] ProcessedBytesCallback; +#else + public readonly ProcessedBytesManagedCallback ProcessedBytesCallback; +#endif + + public ProgressCallback() : this(null) { } + +#if NET6_0_OR_GREATER + public unsafe ProgressCallback(ProcessedBytesManagedCallback? callback) + { + if (callback != null) + { + nint callbackPtr = Marshal.GetFunctionPointerForDelegate(callback); + ProcessedBytesCallback = (delegate* unmanaged[Cdecl])callbackPtr; + return; + } + + ProcessedBytesCallback = &NopProcessedBytesCallback; + } +#else + public ProgressCallback(ProcessedBytesManagedCallback? callback) + { + if (callback != null) + { + ProcessedBytesCallback = callback; + return; + } + + ProcessedBytesCallback = NopProcessedBytesCallback; + } +#endif + +#if NET6_0_OR_GREATER + [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])] + [SkipLocalsInit] +#endif + private static void NopProcessedBytesCallback(long totalProcessed, long totalSize, int written) { } + + public static ProgressCallback CreateFromManaged(ProcessedBytesManagedCallback callback) => new(callback); +} From c99778f958a4fbe05cf436d85e8183b0e9e05cae Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Fri, 21 Aug 2026 23:35:33 +0700 Subject: [PATCH 06/72] Implement RandomMergedStreamReader Attempt to implement a thread-safe Merged Stream Wrapper for Read/Write operations. Warning: Most of the Code for the reader are vibe-coded. So, need to check it further. --- SharpHPatchZ/Extension/ExceptionHelper.cs | 6 +- SharpHPatchZ/Extension/MetadataExtension.cs | 16 +- SharpHPatchZ/HPatch.cs | 72 ++++- SharpHPatchZ/Header/HDiffInfo.cs | 27 ++ SharpHPatchZ/Header/HeaderReader.cs | 52 ++-- .../Header/Metadata/DirectoryPatchMetadata.cs | 2 +- .../Header/Metadata/MetadataTypeConst.cs | 10 +- .../Header/Metadata/UnmanagedArray.cs | 1 - SharpHPatchZ/IO/RandomAccessCompat.cs | 273 ++++++++++++++++++ .../IO/Reader/RandomMergedStreamReader.cs | 217 ++++++++++++++ SharpHPatchZ/Native/PInvoke.Unix.cs | 33 ++- SharpHPatchZ/Native/PInvoke.Windows.cs | 37 ++- SharpHPatchZ/Native/PInvoke.cs | 6 +- SharpHPatchZ/PatchOptions.cs | 16 +- Test/Program.cs | 2 +- 15 files changed, 707 insertions(+), 63 deletions(-) create mode 100644 SharpHPatchZ/IO/RandomAccessCompat.cs create mode 100644 SharpHPatchZ/IO/Reader/RandomMergedStreamReader.cs diff --git a/SharpHPatchZ/Extension/ExceptionHelper.cs b/SharpHPatchZ/Extension/ExceptionHelper.cs index f61828c..a9b04d1 100644 --- a/SharpHPatchZ/Extension/ExceptionHelper.cs +++ b/SharpHPatchZ/Extension/ExceptionHelper.cs @@ -20,7 +20,8 @@ file static class Const { HDiffPathIsEmptyOrInvalid, 0b_00000000_00000000_00000000_01000000 }, { HDiffFILEDescriptorNull, 0b_00000000_00000000_00000000_10000000 }, { HDiffIOException, 0b_00000000_00000000_00000001_00000000 }, - { HDiffInfoIsNull, 0b_00000000_00000000_00000010_00000000 } + { HDiffInfoIsNull, 0b_00000000_00000000_00000010_00000000 }, + { HDiffInfoPatchMetadataNotAllocated, 0b_00000000_00000000_00000100_00000000 } }; #endif @@ -33,6 +34,7 @@ file static class Const public const string HDiffFILEDescriptorNull = "HDIFF_FILEDescriptorNull"; public const string HDiffIOException = "HDIFF_IOException"; public const string HDiffInfoIsNull = "HDIFF_InfoIsNull"; + public const string HDiffInfoPatchMetadataNotAllocated = "HDIFF_InfoPatchMetadataNotAllocated"; } public static class ExceptionHelper @@ -55,6 +57,8 @@ public static void ThrowHDiffIOException(Exception ex) => throw new IOException($"[{Const.HDiffIOException}] An IO Error has occurred with message: {ex.Message}", ex); public static void ThrowHDiffInfoIsNull() => throw new NullReferenceException($"[{Const.HDiffInfoIsNull}] HDiffInfo pointer is null!"); + public static void ThrowHDiffInfoPatchMetadataNotAllocated() + => throw new NullReferenceException($"[{Const.HDiffInfoPatchMetadataNotAllocated}] HDiffInfo patch metadata is not allocated!"); #if NET8_0_OR_GREATER public static int TryGetReturnCodeFromError(Exception ex) diff --git a/SharpHPatchZ/Extension/MetadataExtension.cs b/SharpHPatchZ/Extension/MetadataExtension.cs index dcc8647..fbd0539 100644 --- a/SharpHPatchZ/Extension/MetadataExtension.cs +++ b/SharpHPatchZ/Extension/MetadataExtension.cs @@ -6,6 +6,20 @@ namespace SharpHPatchZ.Extension; internal static class MetadataExtension { + public static unsafe bool TryGetMetadataType(void* metadataP, out MetadataTypeConst metadataType) + { + if (metadataP == null) + { + metadataType = default; + return false; + } + + ref MetadataTypeConst metadataTypeCopy = ref Unsafe.AsRef(metadataP); + metadataType = metadataTypeCopy; + + return IsTypeDefined(metadataType); + } + extension(ref T metadata) where T : unmanaged { public bool TryGetMetadataType(out MetadataTypeConst metadataType) @@ -28,7 +42,7 @@ public bool TryDisposeIfMetadataType() case MetadataTypeConst.ChecksumDataInfoType: Unsafe.As(ref metadata).Dispose(); break; - case MetadataTypeConst.HeaderDirectoryPatchMetadataType: + case MetadataTypeConst.DirectoryPatchMetadataType: Unsafe.As(ref metadata).Dispose(); break; case MetadataTypeConst.PatchMetadataType: diff --git a/SharpHPatchZ/HPatch.cs b/SharpHPatchZ/HPatch.cs index 33b512b..11e4b96 100644 --- a/SharpHPatchZ/HPatch.cs +++ b/SharpHPatchZ/HPatch.cs @@ -1,9 +1,11 @@ -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using SharpHPatchZ.Extension; +using SharpHPatchZ.Extension; using SharpHPatchZ.Header; +using SharpHPatchZ.Header.Metadata; +using SharpHPatchZ.IO.Compression; using SharpHPatchZ.IO.Reader; +using System.IO; +using System.Threading; +using System.Threading.Tasks; namespace SharpHPatchZ; @@ -48,12 +50,64 @@ public static async ValueTask CreateInstanceAsync( return info; } - public static void Patch(HDiffInfo info, - CreateStream createPatchStream, - string inputPath, - string outputPath, - PatchOptions options = default) + public static void Patch(ref HDiffInfo info, + CreateStream createPatchStream, + string inputPath, + string outputPath, + PatchOptions options = default, + CancellationToken token = default) + { + GetPatchDataOffsets(ref info, + out long coverDataOffset, + out long rleControlDataOffset, + out long rleCodeDataOffset, + out long newDataOffset, + out HDiffCompression compType); + + (Stream coverStream, bool coverStreamLeaveOpen) = createPatchStream(coverDataOffset); + (Stream rleControlStream, bool rleControlStreamLeaveOpen) = createPatchStream(rleControlDataOffset); + (Stream rleCodeStream, bool rleCodeStreamLeaveOpen) = createPatchStream(rleCodeDataOffset); + (Stream newDataStream, bool newDataStreamLeaveOpen) = createPatchStream(newDataOffset); + + using Stream decCoverStream = DecompressStreamFactory.CreateStream(compType, coverStream, coverStreamLeaveOpen); + using Stream decRleControlStream = DecompressStreamFactory.CreateStream(compType, rleControlStream, rleControlStreamLeaveOpen); + using Stream decRleCodeStream = DecompressStreamFactory.CreateStream(compType, rleCodeStream, rleCodeStreamLeaveOpen); + using Stream decNewDataStream = DecompressStreamFactory.CreateStream(compType, newDataStream, newDataStreamLeaveOpen); + + using BittableStreamReader coverReader = new(decCoverStream, options.ReaderBufferSize, leaveOpen: coverStreamLeaveOpen); + using BittableStreamReader rleControlReader = new(decRleControlStream, options.ReaderBufferSize, leaveOpen: rleControlStreamLeaveOpen); + using BittableStreamReader rleCodeReader = new(decRleCodeStream, options.ReaderBufferSize, leaveOpen: rleCodeStreamLeaveOpen); + using BittableStreamReader newDataReader = new(decNewDataStream, options.ReaderBufferSize, leaveOpen: newDataStreamLeaveOpen); + } + + public static async Task PatchAsync(HDiffInfo info, + CreateStreamAsync createPatchStreamAsync, + string inputPath, + string outputPath, + PatchOptions options = default, + CancellationToken token = default) + { + + } + + public static unsafe void GetPatchDataOffsets(ref HDiffInfo info, + out long coverDataOffset, + out long rleControlDataOffset, + out long rleCodeDataOffset, + out long newDataOffset, + out HDiffCompression compressionType) { + ref PatchMetadata patchMetadata = ref info.GetPatchMetadata(); + + compressionType = info.CompressionType; + + ChunkSizeInfo* coverDataSizeP = patchMetadata.CoverDataSizeP; + ChunkSizeInfo* rleControlDataSizeP = patchMetadata.RleControlDataSizeP; + ChunkSizeInfo* rleCodeDataSizeP = patchMetadata.RleCodeDataSizeP; + coverDataOffset = patchMetadata.DiffDataOffset; + rleControlDataOffset = coverDataOffset + (coverDataSizeP->CompressedSize > 0 ? coverDataSizeP->CompressedSize : coverDataSizeP->Size); + rleCodeDataOffset = rleControlDataOffset + (rleControlDataSizeP->CompressedSize > 0 ? rleControlDataSizeP->CompressedSize : rleControlDataSizeP->Size); + newDataOffset = rleCodeDataOffset + (rleCodeDataSizeP->CompressedSize > 0 ? rleCodeDataSizeP->CompressedSize : rleCodeDataSizeP->Size); } } diff --git a/SharpHPatchZ/Header/HDiffInfo.cs b/SharpHPatchZ/Header/HDiffInfo.cs index 85add11..069526a 100644 --- a/SharpHPatchZ/Header/HDiffInfo.cs +++ b/SharpHPatchZ/Header/HDiffInfo.cs @@ -30,6 +30,33 @@ public ref T AllocMetadata() return ref Unsafe.AsRef(MetadataP); } + public ref PatchMetadata GetPatchMetadata() + { + void* patchMetadataP; + if (MetadataExtension.TryGetMetadataType(MetadataP, out MetadataTypeConst rootMetadataType) && + rootMetadataType == MetadataTypeConst.DirectoryPatchMetadataType) + { + ref DirectoryPatchMetadata dirPatchMetadata = ref MetadataAs(); + if (Unsafe.IsNullRef(ref dirPatchMetadata) || dirPatchMetadata.PatchMetadataP == null) + { + ExceptionHelper.ThrowHDiffInfoPatchMetadataNotAllocated(); + } + + patchMetadataP = dirPatchMetadata.PatchMetadataP; + } + else + { + patchMetadataP = MetadataP; + } + + if (patchMetadataP == null) + { + ExceptionHelper.ThrowHDiffInfoPatchMetadataNotAllocated(); + } + + return ref Unsafe.AsRef(patchMetadataP); + } + public void Dispose() { if (MetadataP == null) return; diff --git a/SharpHPatchZ/Header/HeaderReader.cs b/SharpHPatchZ/Header/HeaderReader.cs index 14668f8..6e20db7 100644 --- a/SharpHPatchZ/Header/HeaderReader.cs +++ b/SharpHPatchZ/Header/HeaderReader.cs @@ -57,37 +57,41 @@ internal static void ReadBasicHeaderSignature( ExceptionHelper.ThrowHDiffHeaderMagicNotSupported(magicSpan); } - // Parse HDIFF19 (Directory Patch) enums - if (magicType == HDiffMagic.HDiff19) + switch (magicType) { - if (compressionTypeSpan.Length != 0 && - !Enum.TryParse(compressionTypeSpan, true, out compressionType)) + // Parse HDIFF19 (Directory Patch) enums + case HDiffMagic.HDiff19: { - ExceptionHelper.ThrowHDiffHeaderCompressionNotSupported(compressionTypeSpan); + if (compressionTypeSpan.Length != 0 && + !Enum.TryParse(compressionTypeSpan, true, out compressionType)) + { + ExceptionHelper.ThrowHDiffHeaderCompressionNotSupported(compressionTypeSpan); + } + + if (checksumTypeSpan.Length != 0 && + !Enum.TryParse(checksumTypeSpan, true, out checksumType)) + { + ExceptionHelper.ThrowHDiffHeaderChecksumNotSupported(checksumTypeSpan); + } + + return; } - - if (checksumTypeSpan.Length != 0 && - !Enum.TryParse(checksumTypeSpan, true, out checksumType)) + // Parse HDIFF13 (Single Patch) enums + case HDiffMagic.HDiff13: { - ExceptionHelper.ThrowHDiffHeaderChecksumNotSupported(checksumTypeSpan); - } - - return; - } + if (compressionTypeSpan.Length != 0 && + !Enum.TryParse(compressionTypeSpan, true, out compressionType)) + { + ExceptionHelper.ThrowHDiffHeaderCompressionNotSupported(compressionTypeSpan); + } - // Parse HDIFF13 (Single Patch) enums - if (magicType == HDiffMagic.HDiff13) - { - if (compressionTypeSpan.Length != 0 && - !Enum.TryParse(compressionTypeSpan, true, out compressionType)) - { - ExceptionHelper.ThrowHDiffHeaderCompressionNotSupported(compressionTypeSpan); + return; } - - return; + case HDiffMagic.Unknown: + default: + ExceptionHelper.ThrowHDiffHeaderMagicNotSupported(magicSpan); + break; } - - ExceptionHelper.ThrowHDiffHeaderMagicNotSupported(magicSpan); } internal static void ReadHDiffHeaderMetadata( diff --git a/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs b/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs index 9e621d9..e50c832 100644 --- a/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs +++ b/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs @@ -20,7 +20,7 @@ public void Init() IsInitialized = true; IsDisposed = false; - MetadataType = MetadataTypeConst.HeaderDirectoryPatchMetadataType; + MetadataType = MetadataTypeConst.DirectoryPatchMetadataType; InputPathCountSizeInfoP = MemoryAlloc.Alloc(1, true); OutputPathCountSizeInfoP = MemoryAlloc.Alloc(1, true); SameFilePathCountSizeInfoP = MemoryAlloc.Alloc(1, true); diff --git a/SharpHPatchZ/Header/Metadata/MetadataTypeConst.cs b/SharpHPatchZ/Header/Metadata/MetadataTypeConst.cs index 606a7fa..85ce765 100644 --- a/SharpHPatchZ/Header/Metadata/MetadataTypeConst.cs +++ b/SharpHPatchZ/Header/Metadata/MetadataTypeConst.cs @@ -7,9 +7,9 @@ public enum MetadataTypeConst : short { IsMetadataType = unchecked((short)0b_10000000_10000000), - PatchMetadataType = IsMetadataType | 0b_01000000_00000000, - HeaderDirectoryPatchMetadataType = IsMetadataType | 0b_00100000_00000000, - ChecksumDataInfoType = IsMetadataType | 0b_00010000_00000000, - UnmanagedArrayType = IsMetadataType | 0b_00001000_00000000, - Utf16UnmanagedStringType = IsMetadataType | 0b_00000100_00000000 + PatchMetadataType = IsMetadataType | 0b_01000000_00000000, + DirectoryPatchMetadataType = IsMetadataType | 0b_00100000_00000000, + ChecksumDataInfoType = IsMetadataType | 0b_00010000_00000000, + UnmanagedArrayType = IsMetadataType | 0b_00001000_00000000, + Utf16UnmanagedStringType = IsMetadataType | 0b_00000100_00000000 } diff --git a/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs b/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs index f5f71e6..bddc85b 100644 --- a/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs +++ b/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs @@ -110,7 +110,6 @@ public static UnmanagedArray CreateAlloc(int count, bool initialize = false) return array; } - public static implicit operator Span(UnmanagedArray unmanagedSpan) => unmanagedSpan.GetSpan(); public ref T this[int index] diff --git a/SharpHPatchZ/IO/RandomAccessCompat.cs b/SharpHPatchZ/IO/RandomAccessCompat.cs new file mode 100644 index 0000000..514ad6c --- /dev/null +++ b/SharpHPatchZ/IO/RandomAccessCompat.cs @@ -0,0 +1,273 @@ +using System; +using System.IO; +using Microsoft.Win32.SafeHandles; + +#if !NET6_0_OR_GREATER +using System.ComponentModel; +using System.Runtime.InteropServices; +using SharpHPatchZ.Native; +#endif +// ReSharper disable InconsistentNaming +// ReSharper disable StringLiteralTypo + +namespace SharpHPatchZ.IO; + +/// +/// Provides position-independent file I/O on all target frameworks supported by +/// SharpHPatchZ. Modern targets use the runtime implementation; .NET Standard 2.0 +/// calls the equivalent operating-system APIs directly. +/// +internal static class RandomAccessCompat +{ +#if !NET6_0_OR_GREATER + private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + private static readonly unsafe bool UseLongLongPReadWrite = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && sizeof(nint) == 4; +#endif + + public static int Read(SafeFileHandle handle, Span buffer, long fileOffset) + { +#if NET6_0_OR_GREATER + return RandomAccess.Read(handle, buffer, fileOffset); +#else + ValidateArguments(handle, fileOffset); + + if (buffer.IsEmpty) + { + return 0; + } + + return IsWindows + ? ReadWindows(handle, buffer, fileOffset) + : ReadUnix(handle, buffer, fileOffset); +#endif + } + + public static void Write(SafeFileHandle handle, ReadOnlySpan buffer, long fileOffset) + { +#if NET6_0_OR_GREATER + RandomAccess.Write(handle, buffer, fileOffset); +#else + ValidateArguments(handle, fileOffset); + + if (IsWindows) + { + WriteWindows(handle, buffer, fileOffset); + } + else + { + WriteUnix(handle, buffer, fileOffset); + } +#endif + } + + +#if !NET6_0_OR_GREATER + private static void ValidateArguments(SafeFileHandle handle, long fileOffset) + { + if (handle is null) + { + throw new ArgumentNullException(nameof(handle)); + } + + if (handle.IsClosed || handle.IsInvalid) + { + throw new ObjectDisposedException(nameof(handle)); + } + + if (fileOffset < 0) + { + throw new ArgumentOutOfRangeException(nameof(fileOffset)); + } + } + + private const int ErrorHandleEof = 38; + private const int ErrorInterrupted = 4; + + private static int ReadWindows( + SafeFileHandle handle, + Span buffer, + long fileOffset) + { + bool addedRef = false; + try + { + handle.DangerousAddRef(ref addedRef); + PInvoke.Windows.NativeOverlappedData overlapped = new(fileOffset); + + bool success = PInvoke.Windows.ReadFile(handle.DangerousGetHandle(), + ref buffer.GetPinnableReference(), + (uint)buffer.Length, + out uint bytesRead, + ref overlapped); + if (success) + { + return checked((int)bytesRead); + } + + int error = Marshal.GetLastWin32Error(); + return error == ErrorHandleEof + ? 0 + : throw CreateIOException("ReadFile", error); + } + finally + { + if (addedRef) + { + handle.DangerousRelease(); + } + } + } + + private static void WriteWindows( + SafeFileHandle handle, + ReadOnlySpan buffer, + long fileOffset) + { + bool addedRef = false; + try + { + handle.DangerousAddRef(ref addedRef); + + while (!buffer.IsEmpty) + { + PInvoke.Windows.NativeOverlappedData overlapped = new(fileOffset); + bool success = PInvoke.Windows.WriteFile(handle.DangerousGetHandle(), + ref MemoryMarshal.GetReference(buffer), + (uint)buffer.Length, + out uint bytesWritten, + ref overlapped); + if (!success) + { + throw CreateIOException("WriteFile", Marshal.GetLastWin32Error()); + } + + if (bytesWritten == 0) + { + throw new IOException("WriteFile completed without writing any data."); + } + + int written = checked((int)bytesWritten); + buffer = buffer[written..]; + fileOffset = checked(fileOffset + written); + } + } + finally + { + if (addedRef) + { + handle.DangerousRelease(); + } + } + } + + private static int ReadUnix( + SafeFileHandle handle, + Span buffer, + long fileOffset) + { + bool addedRef = false; + try + { + handle.DangerousAddRef(ref addedRef); + int fileDescriptor = handle.DangerousGetHandle().ToInt32(); + + while (true) + { + long result = InvokePRead(fileDescriptor, + ref MemoryMarshal.GetReference(buffer), + (uint)buffer.Length, + fileOffset).ToInt64(); + if (result >= 0) + { + return checked((int)result); + } + + int error = Marshal.GetLastWin32Error(); + if (error != ErrorInterrupted) + { + throw CreateIOException("pread", error); + } + } + } + finally + { + if (addedRef) + { + handle.DangerousRelease(); + } + } + } + + private static void WriteUnix( + SafeFileHandle handle, + ReadOnlySpan buffer, + long fileOffset) + { + bool addedRef = false; + try + { + handle.DangerousAddRef(ref addedRef); + int fileDescriptor = handle.DangerousGetHandle().ToInt32(); + + while (!buffer.IsEmpty) + { + long result; + do + { + result = InvokePWrite(fileDescriptor, + ref MemoryMarshal.GetReference(buffer), + (uint)buffer.Length, + fileOffset).ToInt64(); + } + while (result < 0 && Marshal.GetLastWin32Error() == ErrorInterrupted); + + switch (result) + { + case < 0: + throw CreateIOException("pwrite", Marshal.GetLastWin32Error()); + case 0: + throw new IOException("pwrite completed without writing any data."); + } + + int written = checked((int)result); + buffer = buffer[written..]; + fileOffset = checked(fileOffset + written); + } + } + finally + { + if (addedRef) + { + handle.DangerousRelease(); + } + } + } + + private static IntPtr InvokePRead( + int fileDescriptor, + ref byte buffer, + nuint count, + long fileOffset) + { + // Linux x86 exposes the 64-bit offset ABI as pread64. Other supported + // Unix targets use a 64-bit off_t for pread. + return UseLongLongPReadWrite + ? PInvoke.Unix.PRead64(fileDescriptor, ref buffer, count, fileOffset) + : PInvoke.Unix.PRead(fileDescriptor, ref buffer, count, fileOffset); + } + + private static IntPtr InvokePWrite( + int fileDescriptor, + ref byte buffer, + nuint count, + long fileOffset) + { + return UseLongLongPReadWrite + ? PInvoke.Unix.PWrite64(fileDescriptor, ref buffer, count, fileOffset) + : PInvoke.Unix.PWrite(fileDescriptor, ref buffer, count, fileOffset); + } + + private static IOException CreateIOException(string operation, int error) + => new($"{operation} failed with native error {error}.", new Win32Exception(error)); +#endif +} diff --git a/SharpHPatchZ/IO/Reader/RandomMergedStreamReader.cs b/SharpHPatchZ/IO/Reader/RandomMergedStreamReader.cs new file mode 100644 index 0000000..1897ed8 --- /dev/null +++ b/SharpHPatchZ/IO/Reader/RandomMergedStreamReader.cs @@ -0,0 +1,217 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Threading; + +namespace SharpHPatchZ.IO.Reader; + +internal sealed class RandomMergedStreamReader : IDisposable +{ + private readonly ConcurrentDictionary> _fileStreams = []; + private readonly ReaderWriterLockSlim _lifetimeLock = new(); + private readonly long[] _fileStreamEnds; + private readonly string[] _fileStreamPaths; + private int _disposed; + + public long Length => _fileStreamEnds[^1]; + + public RandomMergedStreamReader(string[] fileStreams, long[] fileStreamEnds) + { + if (fileStreams is null) + { + throw new ArgumentNullException(nameof(fileStreams)); + } + + if (fileStreamEnds is null) + { + throw new ArgumentNullException(nameof(fileStreamEnds)); + } + + if (fileStreams.Length == 0) + { + throw new ArgumentException("At least one file is required.", nameof(fileStreams)); + } + + if (fileStreams.Length != fileStreamEnds.Length) + { + throw new ArgumentException("The path and end-offset arrays must have the same length.", + nameof(fileStreamEnds)); + } + + long previousEnd = 0; + for (int index = 0; index < fileStreams.Length; index++) + { + if (string.IsNullOrWhiteSpace(fileStreams[index])) + { + throw new ArgumentException("A file path cannot be null or empty.", nameof(fileStreams)); + } + + if (fileStreamEnds[index] < previousEnd) + { + throw new ArgumentException("File end offsets must be non-negative and ordered.", + nameof(fileStreamEnds)); + } + + previousEnd = fileStreamEnds[index]; + } + + _fileStreamPaths = fileStreams; + _fileStreamEnds = fileStreamEnds; + } + + public void Write(Span buffer, long offset) + { + _lifetimeLock.EnterReadLock(); + try + { + ThrowIfDisposed(); + ValidateOffset(offset); + + if (buffer.Length > Length - offset) + { + throw new EndOfStreamException("The write exceeds the merged stream length."); + } + + while (!buffer.IsEmpty) + { + int streamIndex = FindStreamIndex(offset); + long streamStart = GetStreamStart(streamIndex); + int writeLength = (int)Math.Min(buffer.Length, _fileStreamEnds[streamIndex] - offset); + + FileStream stream = GetFileStream(streamIndex); + RandomAccessCompat.Write(stream.SafeFileHandle!, + buffer[..writeLength], + offset - streamStart); + + buffer = buffer[writeLength..]; + offset += writeLength; + } + } + finally + { + _lifetimeLock.ExitReadLock(); + } + } + + public int Read(Span buffer, long offset) + { + _lifetimeLock.EnterReadLock(); + try + { + ThrowIfDisposed(); + ValidateOffset(offset); + + int totalRead = 0; + while (!buffer.IsEmpty && offset < Length) + { + int streamIndex = FindStreamIndex(offset); + long streamStart = GetStreamStart(streamIndex); + int readLength = (int)Math.Min(buffer.Length, _fileStreamEnds[streamIndex] - offset); + + FileStream stream = GetFileStream(streamIndex); + int read = RandomAccessCompat.Read(stream.SafeFileHandle!, + buffer[..readLength], + offset - streamStart); + + if (read == 0) + { + throw new EndOfStreamException("An underlying file ended before its declared length."); + } + + totalRead += read; + offset += read; + buffer = buffer[read..]; + } + + return totalRead; + } + finally + { + _lifetimeLock.ExitReadLock(); + } + } + + public void Dispose() + { + _lifetimeLock.EnterWriteLock(); + try + { + if (Interlocked.Exchange(ref _disposed, 1) == 1) + { + return; + } + + foreach (KeyValuePair> kvp in _fileStreams) + { + if (kvp.Value.IsValueCreated) + { + kvp.Value.Value.Dispose(); + } + } + _fileStreams.Clear(); + } + finally + { + _lifetimeLock.ExitWriteLock(); + } + } + + private FileStream GetFileStream(int streamIndex) + { + Lazy lazyStream = _fileStreams.GetOrAdd( + streamIndex, + index => new Lazy( + () => new FileStream(_fileStreamPaths[index], + FileMode.Open, + FileAccess.ReadWrite, + FileShare.ReadWrite, + bufferSize: 1, + FileOptions.RandomAccess), + LazyThreadSafetyMode.ExecutionAndPublication)); + + return lazyStream.Value; + } + + private int FindStreamIndex(long offset) + { + int low = 0; + int high = _fileStreamEnds.Length - 1; + + // Find the first segment whose cumulative end is greater than the offset. + // This also skips any zero-length segments. + while (low < high) + { + int middle = low + ((high - low) >> 1); + if (_fileStreamEnds[middle] > offset) + { + high = middle; + } + else + { + low = middle + 1; + } + } + + return low; + } + + private long GetStreamStart(int streamIndex) + => streamIndex == 0 ? 0 : _fileStreamEnds[streamIndex - 1]; + + private void ValidateOffset(long offset) + { + if ((ulong)offset > (ulong)Length) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + } + + private void ThrowIfDisposed() + { + if (Volatile.Read(ref _disposed) != 0) + { + throw new ObjectDisposedException(nameof(RandomMergedStreamReader)); + } + } +} diff --git a/SharpHPatchZ/Native/PInvoke.Unix.cs b/SharpHPatchZ/Native/PInvoke.Unix.cs index effe480..bfd6369 100644 --- a/SharpHPatchZ/Native/PInvoke.Unix.cs +++ b/SharpHPatchZ/Native/PInvoke.Unix.cs @@ -1,4 +1,5 @@ using System.Runtime.InteropServices; +// ReSharper disable IdentifierTypo namespace SharpHPatchZ.Native; @@ -6,7 +7,35 @@ internal static unsafe partial class PInvoke { public static class Unix { - [DllImport("__Internal", EntryPoint = "fileno", CallingConvention = CallingConvention.Cdecl)] - public static extern int fileno(void* stream); + [DllImport("libc", EntryPoint = "fileno", CallingConvention = CallingConvention.Cdecl)] + public static extern int GetFileDescriptor(void* stream); + + [DllImport("libc", EntryPoint = "pread", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] + public static extern nint PRead( + int fileDescriptor, + ref byte buffer, + nuint count, + long fileOffset); + + [DllImport("libc", EntryPoint = "pread64", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] + public static extern nint PRead64( + int fileDescriptor, + ref byte buffer, + nuint count, + long fileOffset); + + [DllImport("libc", EntryPoint = "pwrite", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] + public static extern nint PWrite( + int fileDescriptor, + ref byte buffer, + nuint count, + long fileOffset); + + [DllImport("libc", EntryPoint = "pwrite64", SetLastError = true, CallingConvention = CallingConvention.Cdecl)] + public static extern nint PWrite64( + int fileDescriptor, + ref byte buffer, + nuint count, + long fileOffset); } } diff --git a/SharpHPatchZ/Native/PInvoke.Windows.cs b/SharpHPatchZ/Native/PInvoke.Windows.cs index ff5d695..93fa91d 100644 --- a/SharpHPatchZ/Native/PInvoke.Windows.cs +++ b/SharpHPatchZ/Native/PInvoke.Windows.cs @@ -1,4 +1,5 @@ using System.Runtime.InteropServices; +// ReSharper disable StringLiteralTypo namespace SharpHPatchZ.Native; @@ -6,10 +7,38 @@ internal static unsafe partial class PInvoke { public static class Windows { - [DllImport("ucrtbase", CallingConvention = CallingConvention.Cdecl)] - public static extern int _fileno(void* stream); + [DllImport("ucrtbase", EntryPoint = "_fileno", CallingConvention = CallingConvention.Cdecl)] + public static extern int GetFileDescriptor(void* stream); - [DllImport("ucrtbase", CallingConvention = CallingConvention.Cdecl)] - public static extern nint _get_osfhandle(int fd); + [DllImport("ucrtbase", EntryPoint = "_get_osfhandle", CallingConvention = CallingConvention.Cdecl)] + public static extern nint GetOSFileHandle(int fd); + + [DllImport("kernel32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ReadFile( + nint fileHandle, + ref byte buffer, + uint bytesToRead, + out uint bytesRead, + ref NativeOverlappedData overlapped); + + [DllImport("kernel32", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool WriteFile( + nint fileHandle, + ref byte buffer, + uint bytesToWrite, + out uint bytesWritten, + ref NativeOverlappedData overlapped); + + [StructLayout(LayoutKind.Sequential)] + public struct NativeOverlappedData(long offset) + { + private readonly nint _internal = 0; + private readonly nint _internalHigh = 0; + private readonly uint _offset = unchecked((uint)offset); + private readonly uint _offsetHigh = unchecked((uint)(offset >> 32)); + private readonly nint _eventHandle = 0; + } } } diff --git a/SharpHPatchZ/Native/PInvoke.cs b/SharpHPatchZ/Native/PInvoke.cs index 03269af..9862021 100644 --- a/SharpHPatchZ/Native/PInvoke.cs +++ b/SharpHPatchZ/Native/PInvoke.cs @@ -14,17 +14,17 @@ public static SafeFileHandle GetSafeFileHandleFromFILE(void* file) if (OperatingSystem.IsWindows()) { - int fd = Windows._fileno(file); + int fd = Windows.GetFileDescriptor(file); if (fd < 0) throw new IOException("_fileno() failed."); - handle = Windows._get_osfhandle(fd); + handle = Windows.GetOSFileHandle(fd); if (handle == -1) throw new IOException("_get_osfhandle() failed."); } else { - int fd = Unix.fileno(file); + int fd = Unix.GetFileDescriptor(file); if (fd < 0) throw new IOException("fileno() failed."); diff --git a/SharpHPatchZ/PatchOptions.cs b/SharpHPatchZ/PatchOptions.cs index 63ff2ec..c28120e 100644 --- a/SharpHPatchZ/PatchOptions.cs +++ b/SharpHPatchZ/PatchOptions.cs @@ -3,16 +3,10 @@ namespace SharpHPatchZ; [StructLayout(LayoutKind.Sequential)] -public struct PatchOptions +public struct PatchOptions() { - public uint ParallelThreads; - public bool IgnoreErrors; - public bool UseSIMD; - - public PatchOptions() - { - ParallelThreads = 0; - IgnoreErrors = false; - UseSIMD = true; - } + public uint ParallelThreads = 0; + public bool IgnoreErrors = false; + public bool UseSIMD = true; + public int ReaderBufferSize = -1; } diff --git a/Test/Program.cs b/Test/Program.cs index 751fded..62bb2eb 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -17,7 +17,7 @@ public static async Task Main() { HDiffPatch hPatchOld = new(); hPatchOld.Initialize(CreateStream); - // hPatchOld.Patch(TestPathInput, TestPathOutput, true); + hPatchOld.Patch(TestPathInput, TestPathOutput, true); using (HDiffInfo info1 = await HPatch.CreateInstanceAsync(CreateStreamAsync)) { From 2e23f9991f3fffea8129af276984bcd618778e81 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sat, 22 Aug 2026 22:52:44 +0700 Subject: [PATCH 07/72] Implement Similar Copy-Over routines + Struct type adjustment inside DirectoryPatchMetadata + Use UnmanagedArray for some input-output ref lists instead of a direct array pointer + Fix CreateUnmanagedInt64List and CreateUnmanagedInt64As32List reading on backed numbers + Add extern functions: - shpz_get_last_errorA - shpz_get_last_errorW - shpz_patch_from_filepath - shpz_patch_from_FILE + Make some string arguments in extern functions auto-detect the encoding of the string - shpz_read_header_signature_string - shpz_init_from_filepath - shpz_patch_from_filepath + Make the ExceptionHelper throw functions returns the Exception instead of throwing within + Add implicit cast for Utf16UnmanagedString and NativeStringW + Remove unnecessary type size check on UnmanagedArray.GetSpan() + Use numbered error code on ExceptionHelper instead of flags + Add callback allocation check on ProgressCallback to avoit ExecutionEngineException due to attempt on calling null callback. --- SharpHPatchZ/Extension/ExceptionHelper.cs | 235 ++++++++++++--- SharpHPatchZ/Extension/MemoryAlloc.cs | 32 +- SharpHPatchZ/Extension/PathHelper.cs | 29 ++ SharpHPatchZ/Extension/StreamExtension.cs | 34 ++- SharpHPatchZ/Extension/StringExtension.cs | 80 +++++ SharpHPatchZ/HPatch.UnmanagedExtern.cs | 152 ++++++++-- SharpHPatchZ/HPatch.cs | 105 +++---- SharpHPatchZ/Header/HDiffInfo.cs | 4 +- SharpHPatchZ/Header/HeaderReader.cs | 29 +- .../Header/Metadata/DirectoryPatchMetadata.cs | 14 +- .../Header/Metadata/UnmanagedArray.cs | 10 +- .../Header/Metadata/Utf16UnmanagedString.cs | 12 + .../IO/Compression/CompressionStreamHelper.cs | 13 +- ...Reader.cs => RandomMergedStreamWrapper.cs} | 6 +- SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs | 281 ++++++++++++++++++ SharpHPatchZ/Patch/PatcherBase.cs | 55 ++++ .../Patch/PatcherFactory.HDiff13Derived.cs | 119 ++++++++ SharpHPatchZ/Patch/PatcherFactory.cs | 36 +++ SharpHPatchZ/PatchOptions.cs | 2 +- SharpHPatchZ/PatchResult.cs | 18 ++ SharpHPatchZ/ProgressCallback.cs | 12 +- Test/Program.cs | 16 +- 22 files changed, 1072 insertions(+), 222 deletions(-) create mode 100644 SharpHPatchZ/Extension/PathHelper.cs rename SharpHPatchZ/IO/Reader/{RandomMergedStreamReader.cs => RandomMergedStreamWrapper.cs} (97%) create mode 100644 SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs create mode 100644 SharpHPatchZ/Patch/PatcherBase.cs create mode 100644 SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs create mode 100644 SharpHPatchZ/Patch/PatcherFactory.cs create mode 100644 SharpHPatchZ/PatchResult.cs diff --git a/SharpHPatchZ/Extension/ExceptionHelper.cs b/SharpHPatchZ/Extension/ExceptionHelper.cs index a9b04d1..b59be42 100644 --- a/SharpHPatchZ/Extension/ExceptionHelper.cs +++ b/SharpHPatchZ/Extension/ExceptionHelper.cs @@ -1,70 +1,120 @@ using System; using System.IO; -#if NET8_0_OR_GREATER using System.Collections.Generic; +using System.Text; +using System.Threading; +using SharpHPatchZ.Header; + // ReSharper disable InconsistentNaming -#endif namespace SharpHPatchZ.Extension; file static class Const { -#if NET8_0_OR_GREATER internal static readonly Dictionary ExceptionToReturnCodeMap = new() { - { HDiffHeaderSignatureEmptyOrUnreadable, 0b_00000000_00000000_00000000_00000010 }, - { HDiffHeaderMagicNotSupported, 0b_00000000_00000000_00000000_00000100 }, - { HDiffHeaderCompressionNotSupported, 0b_00000000_00000000_00000000_00001000 }, - { HDiffHeaderChecksumNotSupported, 0b_00000000_00000000_00000000_00010000 }, - { HDiffHeaderEndOfFileOrData, 0b_00000000_00000000_00000000_00100000 }, - { HDiffPathIsEmptyOrInvalid, 0b_00000000_00000000_00000000_01000000 }, - { HDiffFILEDescriptorNull, 0b_00000000_00000000_00000000_10000000 }, - { HDiffIOException, 0b_00000000_00000000_00000001_00000000 }, - { HDiffInfoIsNull, 0b_00000000_00000000_00000010_00000000 }, - { HDiffInfoPatchMetadataNotAllocated, 0b_00000000_00000000_00000100_00000000 } -}; -#endif + // Not Supported + { HDiffHeaderMagicNotSupported, 0x10 }, + { HDiffHeaderCompressionNotSupported, 0x11 }, + { HDiffHeaderChecksumNotSupported, 0x12 }, + { HDiffPatchFactoryNotSupported, 0x13 }, + + // Memory Allocation / Descriptor + { HDiffInfoNotAllocated, 0x30 }, + { HDiffInfoDirectoryPatchMetadataNotAllocated, 0x31 }, + { HDiffInfoPatchMetadataNotAllocated, 0x32 }, + { HDiffFILEDescriptorNull, 0x33 }, + { HDiffArgumentNull, 0x34 }, + + // IO / File / Paths + { HDiffHeaderSignatureEmptyOrUnreadable, 0x50 }, + { HDiffHeaderEndOfFileOrData, 0x51 }, + { HDiffPathIsEmptyOrInvalid, 0x52 }, + { HDiffIOException, 0x53 }, + { HDiffPatchInputPathNotExist, 0x54 }, + { HDiffPatchInputSizeMismatched, 0x55 }, + { HDiffPatchPathNotADirectory, 0x56 }, + { HDiffPatchPathNotAFile, 0x57 }, + { HDiffPatchInputFilesMismatched, 0x58 } + }; + + public const string HDiffHeaderMagicNotSupported = "HDIFF_HeaderMagicNotSupported"; + public const string HDiffHeaderCompressionNotSupported = "HDIFF_HeaderCompressionNotSupported"; + public const string HDiffHeaderChecksumNotSupported = "HDIFF_HeaderChecksumNotSupported"; + public const string HDiffPatchFactoryNotSupported = "HDIFF_PatchFactoryNotSupported"; - public const string HDiffHeaderSignatureEmptyOrUnreadable = "HDIFF_HeaderSignatureEmptyOrUnreadable"; - public const string HDiffHeaderMagicNotSupported = "HDIFF_HeaderMagicNotSupported"; - public const string HDiffHeaderCompressionNotSupported = "HDIFF_HeaderCompressionNotSupported"; - public const string HDiffHeaderChecksumNotSupported = "HDIFF_HeaderChecksumNotSupported"; - public const string HDiffHeaderEndOfFileOrData = "HDIFF_EndOfFileOrData"; - public const string HDiffPathIsEmptyOrInvalid = "HDIFF_PathIsEmptyOrInvalid"; - public const string HDiffFILEDescriptorNull = "HDIFF_FILEDescriptorNull"; - public const string HDiffIOException = "HDIFF_IOException"; - public const string HDiffInfoIsNull = "HDIFF_InfoIsNull"; - public const string HDiffInfoPatchMetadataNotAllocated = "HDIFF_InfoPatchMetadataNotAllocated"; + public const string HDiffInfoNotAllocated = "HDIFF_InfoNotAllocated"; + public const string HDiffInfoDirectoryPatchMetadataNotAllocated = "HDIFF_InfoDirectoryPatchMetadataNotAllocated"; + public const string HDiffInfoPatchMetadataNotAllocated = "HDIFF_InfoPatchMetadataNotAllocated"; + public const string HDiffFILEDescriptorNull = "HDIFF_FILEDescriptorNull"; + public const string HDiffArgumentNull = "HDIFF_ArgumentNull"; + + public const string HDiffHeaderSignatureEmptyOrUnreadable = "HDIFF_HeaderSignatureEmptyOrUnreadable"; + public const string HDiffHeaderEndOfFileOrData = "HDIFF_EndOfFileOrData"; + public const string HDiffPathIsEmptyOrInvalid = "HDIFF_PathIsEmptyOrInvalid"; + public const string HDiffIOException = "HDIFF_IOException"; + public const string HDiffPatchInputPathNotExist = "HDIFF_PatchInputPathNotExist"; + public const string HDiffPatchInputSizeMismatched = "HDIFF_PatchInputSizeMismatched"; + public const string HDiffPatchPathNotADirectory = "HDIFF_PatchPathNotADirectory"; + public const string HDiffPatchPathNotAFile = "HDIFF_PatchPathNotAFile"; + public const string HDiffPatchInputFilesMismatched = "HDIFF_PatchInputFilesMismatched"; } public static class ExceptionHelper { - public static void ThrowHDiffHeaderSignatureEmptyOrUnreadable() - => throw new InvalidOperationException($"[{Const.HDiffHeaderSignatureEmptyOrUnreadable}] Header signature is empty or unreadable!"); - public static void ThrowHDiffHeaderMagicNotSupported(ReadOnlySpan magic) - => throw new NotSupportedException($"[{Const.HDiffHeaderMagicNotSupported}] Header magic: {magic.ToString()} is not supported!"); - public static void ThrowHDiffHeaderCompressionNotSupported(ReadOnlySpan enumString) - => throw new NotSupportedException($"[{Const.HDiffHeaderCompressionNotSupported}] HDIFF compression: {enumString.ToString()} is not supported!"); - public static void ThrowHDiffHeaderChecksumNotSupported(ReadOnlySpan enumString) - => throw new NotSupportedException($"[{Const.HDiffHeaderChecksumNotSupported}] HDIFF checksum: {enumString.ToString()} is not supported!"); - public static void ThrowHDiffEndOfFileOrData(Exception innerException) - => throw new EndOfStreamException($"[{Const.HDiffHeaderEndOfFileOrData}] HDiff Data has reached End-of-File or Data", innerException); - public static void ThrowHDiffPathIsEmptyOrInvalid() - => throw new InvalidOperationException($"[{Const.HDiffPathIsEmptyOrInvalid}] File or Directory path is empty or invalid"); - public static void ThrowHDiffFILEDescriptorNull() - => throw new NullReferenceException($"[{Const.HDiffFILEDescriptorNull}] FILE descriptor cannot be null!"); - public static void ThrowHDiffIOException(Exception ex) - => throw new IOException($"[{Const.HDiffIOException}] An IO Error has occurred with message: {ex.Message}", ex); - public static void ThrowHDiffInfoIsNull() - => throw new NullReferenceException($"[{Const.HDiffInfoIsNull}] HDiffInfo pointer is null!"); - public static void ThrowHDiffInfoPatchMetadataNotAllocated() - => throw new NullReferenceException($"[{Const.HDiffInfoPatchMetadataNotAllocated}] HDiffInfo patch metadata is not allocated!"); + private static Exception? LastException; -#if NET8_0_OR_GREATER - public static int TryGetReturnCodeFromError(Exception ex) + public static NotSupportedException ThrowHDiffHeaderMagicNotSupported(ReadOnlySpan magic) + => new($"[{Const.HDiffHeaderMagicNotSupported}] Header magic: {magic.ToString()} is not supported!"); + public static NotSupportedException ThrowHDiffHeaderCompressionNotSupported(ReadOnlySpan enumString) + => new($"[{Const.HDiffHeaderCompressionNotSupported}] HDIFF compression: {enumString.ToString()} is not supported!"); + public static NotSupportedException ThrowHDiffHeaderChecksumNotSupported(ReadOnlySpan enumString) + => new($"[{Const.HDiffHeaderChecksumNotSupported}] HDIFF checksum: {enumString.ToString()} is not supported!"); + public static NotSupportedException ThrowHDiffPatchFactoryNotSupported(HDiffMagic type) + => new($"[{Const.HDiffPatchFactoryNotSupported}] No factory supported for type: {type}!"); + + public static NullReferenceException ThrowHDiffInfoNotAllocated() + => new($"[{Const.HDiffInfoNotAllocated}] HDiffInfo pointer is not allocated!"); + public static NullReferenceException ThrowHDiffInfoDirectoryPatchMetadataNotAllocated() + => new($"[{Const.HDiffInfoDirectoryPatchMetadataNotAllocated}] HDiffInfo directory patch metadata is not allocated!"); + public static NullReferenceException ThrowHDiffInfoPatchMetadataNotAllocated() + => new($"[{Const.HDiffInfoPatchMetadataNotAllocated}] HDiffInfo patch metadata is not allocated!"); + public static NullReferenceException ThrowHDiffFILEDescriptorNull() + => new($"[{Const.HDiffFILEDescriptorNull}] FILE descriptor cannot be null!"); + public static NullReferenceException ThrowHDiffArgumentNull(string nameOfArg) + => new($"[{Const.HDiffArgumentNull}] Argument: {nameOfArg} cannot be null!"); + + public static InvalidOperationException ThrowHDiffHeaderSignatureEmptyOrUnreadable() + => new($"[{Const.HDiffHeaderSignatureEmptyOrUnreadable}] Header signature is empty or unreadable!"); + public static EndOfStreamException ThrowHDiffEndOfFileOrData(Exception innerException) + => new($"[{Const.HDiffHeaderEndOfFileOrData}] HDiff Data has reached End-of-File or Data", innerException); + public static InvalidOperationException ThrowHDiffPathIsEmptyOrInvalid() + => new($"[{Const.HDiffPathIsEmptyOrInvalid}] File or Directory path is empty or invalid"); + public static IOException ThrowHDiffIOException(Exception ex) + => new($"[{Const.HDiffIOException}] An IO Error has occurred with message: {ex.Message}", ex); + public static FileNotFoundException ThrowHDiffPatchInputPathNotExist(string filePath) + => new($"[{Const.HDiffPatchInputPathNotExist}] Input path does not exist: {filePath}", filePath); + public static InvalidOperationException ThrowHDiffPatchInputSizeMismatched(string filePath, long existingSize, long expectingSize) + => new($"[{Const.HDiffPatchInputSizeMismatched}] Input file size does not match: {filePath} (Expecting: {expectingSize} bytes, but got: {existingSize} instead)."); + public static InvalidOperationException ThrowHDiffPatchPathNotADirectory(string path) + => new($"[{Const.HDiffPatchPathNotADirectory}] Path is not a directory!: {path}"); + public static InvalidOperationException ThrowHDiffPatchPathNotAFile(string path) + => new($"[{Const.HDiffPatchPathNotAFile}] Path is not a file!: {path}"); + public static InvalidOperationException ThrowHDiffPatchInputFilesMismatched(long existingSize, long expectingSize) + => new($"[{Const.HDiffPatchInputFilesMismatched}] Input file size mismatched! Expecting: {expectingSize} bytes but got: {expectingSize} bytes instead."); + + + public static int TryGetReturnCodeFromError(Exception? ex) { + if (ex == null) + { + return 0; + } + try { + Interlocked.Exchange(ref LastException, ex); + ReadOnlySpan message = ex.Message; if (message.IsEmpty) { @@ -86,6 +136,9 @@ public static int TryGetReturnCodeFromError(Exception ex) #if NET9_0_OR_GREATER return Const.ExceptionToReturnCodeMap.GetAlternateLookup>() .TryGetValue(splitFirst, out int returnCode) ? returnCode : -1; +#elif !NET6_0_OR_GREATER && NETSTANDARD + return splitFirst.ToString() is var splitFirstAsStr && + Const.ExceptionToReturnCodeMap.TryGetValue(splitFirstAsStr, out int value) ? value : -1; #else return Const.ExceptionToReturnCodeMap.GetValueOrDefault(splitFirst.ToString(), -1); #endif @@ -95,5 +148,93 @@ public static int TryGetReturnCodeFromError(Exception ex) return -1; } } + +#if NET8_0_OR_GREATER + public static int TryGetLastErrorMessageUtf8(Span spanByte, LastErrorMessageType lastErrorMessageType) + { + Exception? thisException = Volatile.Read(ref LastException); + if (thisException == null || + spanByte.Length == 0) + { + return 0; + } + + spanByte[^1] = 0; + spanByte = spanByte[..^1]; // Slice and reserve last one byte for the null-terminator. + + StringBuilder builder = new(); + if (lastErrorMessageType.HasFlag(LastErrorMessageType.Message)) + { + builder.AppendLine(thisException.Message); + } + + if (lastErrorMessageType.HasFlag(LastErrorMessageType.StackTrace)) + { + builder.AppendLine(thisException.StackTrace); + } + + int written = 0; + foreach (ReadOnlyMemory chunk in builder.GetChunks()) + { + if (!Encoding.UTF8.TryGetBytes(chunk.Span, spanByte, out int thisWritten)) + { + return -1; + } + + written += thisWritten; + spanByte = spanByte[thisWritten..]; + } + + if (!spanByte.IsEmpty) spanByte[0] = 0; // Append null-terminator on last. + return written; + } + + public static int TryGetLastErrorMessageUnicode(Span spanChar, LastErrorMessageType lastErrorMessageType) + { + Exception? thisException = Volatile.Read(ref LastException); + if (thisException == null || + spanChar.Length == 0) + { + return 0; + } + + spanChar[^1] = '\0'; + spanChar = spanChar[..^1]; // Slice and reserve last one byte for the null-terminator. + + StringBuilder builder = new(); + if (lastErrorMessageType.HasFlag(LastErrorMessageType.Message)) + { + builder.AppendLine(thisException.Message); + } + + if (lastErrorMessageType.HasFlag(LastErrorMessageType.StackTrace)) + { + builder.AppendLine(thisException.StackTrace); + } + + int written = 0; + foreach (ReadOnlyMemory chunk in builder.GetChunks()) + { + if (!chunk.Span.TryCopyTo(spanChar)) + { + return -1; + } + + int thisWritten = chunk.Length; + written += thisWritten; + spanChar = spanChar[thisWritten..]; + } + + if (!spanChar.IsEmpty) spanChar[0] = '\0'; // Append null-terminator on last. + return written; + } + + [Flags] + public enum LastErrorMessageType + { + Message = 1, + StackTrace = 2, + MessageAndStackTrace = Message | StackTrace + } #endif } \ No newline at end of file diff --git a/SharpHPatchZ/Extension/MemoryAlloc.cs b/SharpHPatchZ/Extension/MemoryAlloc.cs index 4e22403..5be5330 100644 --- a/SharpHPatchZ/Extension/MemoryAlloc.cs +++ b/SharpHPatchZ/Extension/MemoryAlloc.cs @@ -1,8 +1,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type - namespace SharpHPatchZ.Extension; internal static unsafe class MemoryAlloc @@ -35,26 +33,20 @@ internal static unsafe class MemoryAlloc #endif } - public static T* CopyToUnmanagedUnsafe(this ref T toCopy) - where T : unmanaged + extension(ref T toCopy) where T : unmanaged { - T* allocP = Alloc(); - ref T allocRef = ref allocP[0]; - allocRef = toCopy; - return allocP; - } - - public static nint CopyToUnmanaged(this ref T toCopy) - where T : unmanaged - => (nint)toCopy.CopyToUnmanagedUnsafe(); - - public static void CopyTo(this ref T from, ref T to) - where T : unmanaged - => to = from; + public T* CopyToUnmanagedUnsafe() + { + T* allocP = Alloc(); + ref T allocRef = ref allocP[0]; + allocRef = toCopy; + return allocP; + } - public static void CopyTo(this ref T from, void* to) - where T : unmanaged - => Unsafe.AsRef(to) = from; + public nint CopyToUnmanaged() => (nint)toCopy.CopyToUnmanagedUnsafe(); + public void CopyTo(ref T to) => to = toCopy; + public void CopyTo(void* to) => Unsafe.AsRef(to) = toCopy; + } public static void CopyTo(void* from, void* to) where T : unmanaged diff --git a/SharpHPatchZ/Extension/PathHelper.cs b/SharpHPatchZ/Extension/PathHelper.cs new file mode 100644 index 0000000..09f2834 --- /dev/null +++ b/SharpHPatchZ/Extension/PathHelper.cs @@ -0,0 +1,29 @@ +using System; +using System.IO; + +namespace SharpHPatchZ.Extension; + +internal static class PathHelper +{ + extension(string path) + { + public DirectoryInfo GetDirectoryInfo() + => new FileInfo(path).Exists + ? throw ExceptionHelper.ThrowHDiffPatchPathNotADirectory(path) + : new DirectoryInfo(path); + + public FileInfo GetFileInfo() + => new DirectoryInfo(path).Exists + ? throw ExceptionHelper.ThrowHDiffPatchPathNotAFile(path) + : new FileInfo(path); + + public bool IsDirectory() + { + ReadOnlySpan pathSpan = path; + if (pathSpan.IsEmpty) return false; + + char lastChar = pathSpan[^1]; + return lastChar is '\\' or '/'; + } + } +} diff --git a/SharpHPatchZ/Extension/StreamExtension.cs b/SharpHPatchZ/Extension/StreamExtension.cs index 0e32e21..2777195 100644 --- a/SharpHPatchZ/Extension/StreamExtension.cs +++ b/SharpHPatchZ/Extension/StreamExtension.cs @@ -154,9 +154,9 @@ public async ValueTask CreateUnmanagedInt64ListAsync(int count, Cancellati unsafe { - long* alloc = MemoryAlloc.Alloc(count); - array.AsSpan(0, count).CopyTo(new Span(alloc, count)); - return (nint)alloc; + UnmanagedArray* allocArray = UnmanagedArray.CreateAllocUnsafe(count); + array.AsSpan(0, count).CopyTo(allocArray->GetSpan()); + return (nint)allocArray; } } finally @@ -165,20 +165,23 @@ public async ValueTask CreateUnmanagedInt64ListAsync(int count, Cancellati } } - public unsafe long* CreateUnmanagedInt64List(int count) + public unsafe UnmanagedArray* CreateUnmanagedInt64List(int count) { if (count == 0) { return null; } - long* alloc = MemoryAlloc.Alloc(count); + UnmanagedArray* allocArray = UnmanagedArray.CreateAllocUnsafe(count); + Span allocSpan = allocArray->GetSpan(); + + long backNumber = -1; for (int i = 0; i < count; i++) { - alloc[i] = reader.ReadLong7Bit(); + allocSpan[i] = backNumber += 1 + reader.ReadLong7Bit(); } - return alloc; + return allocArray; } public async ValueTask CreateUnmanagedInt64As32ListAsync(int count, CancellationToken token) @@ -199,9 +202,9 @@ public async ValueTask CreateUnmanagedInt64As32ListAsync(int count, Cancel unsafe { - int* alloc = MemoryAlloc.Alloc(count); - array.AsSpan(0, count).CopyTo(new Span(alloc, count)); - return (nint)alloc; + UnmanagedArray* allocArray = UnmanagedArray.CreateAllocUnsafe(count); + array.AsSpan(0, count).CopyTo(allocArray->GetSpan()); + return (nint)allocArray; } } finally @@ -210,20 +213,23 @@ public async ValueTask CreateUnmanagedInt64As32ListAsync(int count, Cancel } } - public unsafe int* CreateUnmanagedInt64As32List(int count) + public unsafe UnmanagedArray* CreateUnmanagedInt64As32List(int count) { if (count == 0) { return null; } - int* alloc = MemoryAlloc.Alloc(count); + UnmanagedArray* allocArray = UnmanagedArray.CreateAllocUnsafe(count); + Span allocSpan = allocArray->GetSpan(); + + long backNumber = -1; for (int i = 0; i < count; i++) { - alloc[i] = (int)reader.ReadLong7Bit(); + allocSpan[i] = (int)(backNumber += 1 + reader.ReadLong7Bit()); } - return alloc; + return allocArray; } public async ValueTask CreateUnmanagedIndexPairListAsync(int count, CancellationToken token) diff --git a/SharpHPatchZ/Extension/StringExtension.cs b/SharpHPatchZ/Extension/StringExtension.cs index d3ef098..b075ade 100644 --- a/SharpHPatchZ/Extension/StringExtension.cs +++ b/SharpHPatchZ/Extension/StringExtension.cs @@ -1,4 +1,6 @@ using System; +using System.Runtime.InteropServices; +using System.Text; namespace SharpHPatchZ.Extension; @@ -96,4 +98,82 @@ private static void TrimSplitEntry( } } #endif + +#if NET6_0_OR_GREATER + public static unsafe NativeStringEncoding GuessStringEncoding( + void* stringP, + nuint maxBytes) + { + byte* ptr = (byte*)stringP; + + if (ptr == null) + throw new ArgumentNullException(nameof(ptr)); + + if (maxBytes >= 2) + { + // UTF-16 LE BOM + if (ptr[0] == 0xFF && ptr[1] == 0xFE) + return NativeStringEncoding.Unicode; + + // UTF-8 BOM + if (maxBytes >= 3 && + ptr[0] == 0xEF && + ptr[1] == 0xBB && + ptr[2] == 0xBF) + { + return NativeStringEncoding.Utf8; + } + } + + // Heuristic: + // ASCII text encoded as UTF-16LE tends to have NUL bytes + // in every odd byte. + nuint pairs = 0; + nuint zeroHighBytes = 0; + + nuint checkLength = Math.Min(maxBytes, 64u); + + for (nuint i = 0; i + 1 < checkLength; i += 2) + { + byte lo = ptr[i]; + byte hi = ptr[i + 1]; + + // UTF-16 terminator + if (lo == 0 && hi == 0) + break; + + pairs++; + + if (hi == 0) + zeroHighBytes++; + } + + if (pairs != 0 && + zeroHighBytes * 4 >= pairs * 3) // >= 75% + { + return NativeStringEncoding.Unicode; + } + + return NativeStringEncoding.Utf8; + } + + public static unsafe string? GetManagedStringAuto(void* ptr) + { + if (ptr == null) return null; + + NativeStringEncoding encoding = GuessStringEncoding(ptr, 8); + return encoding switch + { + NativeStringEncoding.Unicode => MemoryMarshal.CreateReadOnlySpanFromNullTerminated((char*)ptr).ToString(), + NativeStringEncoding.Utf8 => Encoding.UTF8.GetString(MemoryMarshal.CreateReadOnlySpanFromNullTerminated((byte*)ptr)), + _ => null + }; + } +#endif +} + +public enum NativeStringEncoding +{ + Utf8, + Unicode } diff --git a/SharpHPatchZ/HPatch.UnmanagedExtern.cs b/SharpHPatchZ/HPatch.UnmanagedExtern.cs index 94b118c..7ec7047 100644 --- a/SharpHPatchZ/HPatch.UnmanagedExtern.cs +++ b/SharpHPatchZ/HPatch.UnmanagedExtern.cs @@ -1,12 +1,17 @@ #if NET8_0_OR_GREATER using System; +using System.Buffers; using System.IO; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; using SharpHPatchZ.Extension; using SharpHPatchZ.Header; using SharpHPatchZ.Native; + // ReSharper disable InconsistentNaming +// ReSharper disable IdentifierTypo +// ReSharper disable StringLiteralTypo #if USEWINDOWS using ConventionCall = System.Runtime.CompilerServices.CallConvStdcall; @@ -19,11 +24,13 @@ namespace SharpHPatchZ; public static partial class HPatch { [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_read_header_signature_string")] - public static unsafe int SharpHPatchZ_ReadHeaderSignatureString(void* signWP, int signWLen, HDiffMagic* magicTypeP, HDiffCompression* compressionTypeP, HDiffChecksum* checksumTypeP) + public static unsafe int SharpHPatchZ_ReadHeaderSignatureStringAuto(void* signatureP, HDiffMagic* magicTypeP, HDiffCompression* compressionTypeP, HDiffChecksum* checksumTypeP) { + char[]? signatureWideBuffer = null; try { - ReadOnlySpan signature = new(signWP, signWLen); + string? signature = StringExtension.GetManagedStringAuto(signatureP); + ref HDiffMagic magicTypeRef = ref magicTypeP[0]; ref HDiffCompression compressionTypeRef = ref compressionTypeP[0]; ref HDiffChecksum checksumTypeRef = ref checksumTypeP[0]; @@ -38,6 +45,10 @@ public static unsafe int SharpHPatchZ_ReadHeaderSignatureString(void* signWP, in { return ExceptionHelper.TryGetReturnCodeFromError(ex); } + finally + { + if (signatureWideBuffer != null) ArrayPool.Shared.Return(signatureWideBuffer); + } } [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_init_from_memory")] @@ -64,28 +75,20 @@ public static unsafe int SharpHPatchZ_InitializeFromMemory(byte* dataP, long dat } [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_init_from_filepath")] - public static unsafe int SharpHPatchZ_InitializeFromFilePath(char* pathW, int pathWLength, HDiffInfo* signP) + public static unsafe int SharpHPatchZ_InitializeFromFilePathAuto(void* pathP, HDiffInfo* signP) { try { - if (pathW == null || - pathWLength == 0) + string? filePath = StringExtension.GetManagedStringAuto(pathP); + if (filePath == null) { - ExceptionHelper.ThrowHDiffPathIsEmptyOrInvalid(); + throw ExceptionHelper.ThrowHDiffPathIsEmptyOrInvalid(); } - string filePath = new ReadOnlySpan(pathW, pathWLength).Trim('\0').ToString(); - HDiffInfo thisInfo = CreateInstance(CreateFileStreamWrapper); + HDiffInfo thisInfo = CreateInstance(pos => CreateFileStreamWrapper(filePath, pos)); thisInfo.CopyTo(signP); return 0; - - (Stream Stream, bool LeaveOpen) CreateFileStreamWrapper(long position) - { - FileStream stream = new(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); - stream.Position = position; - return (stream, false); - } } catch (Exception ex) { @@ -100,10 +103,10 @@ public static unsafe int SharpHPatchZ_InitializeFromFILE(void* FILEP, HDiffInfo* { if (FILEP == null) { - ExceptionHelper.ThrowHDiffFILEDescriptorNull(); + throw ExceptionHelper.ThrowHDiffFILEDescriptorNull(); } - HDiffInfo thisInfo = CreateInstance(CreateFileStreamWrapper); + HDiffInfo thisInfo = CreateInstance(pos => CreateFileStreamWrapper(FILEP, pos)); thisInfo.CopyTo(signP); return 0; @@ -112,21 +115,78 @@ public static unsafe int SharpHPatchZ_InitializeFromFILE(void* FILEP, HDiffInfo* { return ExceptionHelper.TryGetReturnCodeFromError(ex); } + } - (Stream Stream, bool LeaveOpen) CreateFileStreamWrapper(long position) + [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_patch_from_filepath")] + public static unsafe int SharpHPatchZ_PatchFromFilePathAuto( + void* patchPathP, + void* inputPathP, + void* outputPathP, + HDiffInfo* infoP, + PatchOptions* optionsP, + ProgressCallback* progressCallbackP) + { + string? patchPath = StringExtension.GetManagedStringAuto(patchPathP); + string? inputPath = StringExtension.GetManagedStringAuto(inputPathP); + string? outputPath = StringExtension.GetManagedStringAuto(outputPathP); + + try { - try - { - SafeFileHandle fileHandle = PInvoke.GetSafeFileHandleFromFILE(FILEP); - FileStream stream = new(fileHandle, FileAccess.Read); - stream.Position = position; - return (stream, true); - } - catch (IOException ex) - { - ExceptionHelper.ThrowHDiffIOException(ex); - throw; - } + if (patchPath == null) throw ExceptionHelper.ThrowHDiffArgumentNull(nameof(patchPathP)); + if (inputPath == null) throw ExceptionHelper.ThrowHDiffArgumentNull(nameof(inputPathP)); + if (outputPath == null) throw ExceptionHelper.ThrowHDiffArgumentNull(nameof(outputPathP)); + if (infoP == null) throw ExceptionHelper.ThrowHDiffInfoNotAllocated(); + + PatchOptions options = optionsP == null ? new PatchOptions() : Unsafe.AsRef(optionsP); // Copy + ProgressCallback progressCallback = progressCallbackP == null ? new ProgressCallback() : Unsafe.AsRef(progressCallbackP); + ref HDiffInfo info = ref infoP[0]; + + return Patch(info, + pos => CreateFileStreamWrapper(patchPath, pos), + inputPath, + outputPath, + options, + progressCallback); + } + catch (Exception ex) + { + return ExceptionHelper.TryGetReturnCodeFromError(ex); + } + } + + [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_patch_from_FILE")] + public static unsafe int SharpHPatchZ_PatchFromFILE( + void* FILEP, + void* inputPathP, + void* outputPathP, + HDiffInfo* infoP, + PatchOptions* optionsP, + ProgressCallback* progressCallbackP) + { + string? inputPath = StringExtension.GetManagedStringAuto(inputPathP); + string? outputPath = StringExtension.GetManagedStringAuto(outputPathP); + + try + { + if (FILEP == null) throw ExceptionHelper.ThrowHDiffArgumentNull(nameof(FILEP)); + if (inputPath == null) throw ExceptionHelper.ThrowHDiffArgumentNull(nameof(inputPathP)); + if (outputPath == null) throw ExceptionHelper.ThrowHDiffArgumentNull(nameof(outputPathP)); + if (infoP == null) throw ExceptionHelper.ThrowHDiffInfoNotAllocated(); + + PatchOptions options = optionsP == null ? new PatchOptions() : Unsafe.AsRef(optionsP); // Copy + ProgressCallback progressCallback = progressCallbackP == null ? new ProgressCallback() : Unsafe.AsRef(progressCallbackP); + ref HDiffInfo info = ref infoP[0]; + + return Patch(info, + pos => CreateFileStreamWrapper(FILEP, pos), + inputPath, + outputPath, + options, + progressCallback); + } + catch (Exception ex) + { + return ExceptionHelper.TryGetReturnCodeFromError(ex); } } @@ -137,7 +197,7 @@ public static unsafe int SharpHPatchZ_FreeDiffInfo(HDiffInfo* ptr) { if (ptr == null) { - ExceptionHelper.ThrowHDiffInfoIsNull(); + throw ExceptionHelper.ThrowHDiffInfoNotAllocated(); } MemoryAlloc.Free(ptr->MetadataP); @@ -148,5 +208,35 @@ public static unsafe int SharpHPatchZ_FreeDiffInfo(HDiffInfo* ptr) return ExceptionHelper.TryGetReturnCodeFromError(ex); } } + + [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_get_last_errorA")] + public static unsafe int SharpHPatchZ_GetLastErrorUtf8(byte* bufferA, int bufferLength, ExceptionHelper.LastErrorMessageType messageType) + => ExceptionHelper.TryGetLastErrorMessageUtf8(new Span(bufferA, bufferLength), messageType); + + [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_get_last_errorW")] + public static unsafe int SharpHPatchZ_GetLastErrorUnicode(char* bufferW, int bufferLength, ExceptionHelper.LastErrorMessageType messageType) + => ExceptionHelper.TryGetLastErrorMessageUnicode(new Span(bufferW, bufferLength), messageType); + + private static (Stream Stream, bool LeaveOpen) CreateFileStreamWrapper(string filePath, long position) + { + FileStream stream = new(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); + stream.Position = position; + return (stream, false); + } + + private static unsafe (Stream Stream, bool LeaveOpen) CreateFileStreamWrapper(void* FILEP, long position) + { + try + { + SafeFileHandle fileHandle = PInvoke.GetSafeFileHandleFromFILE(FILEP); + FileStream stream = new(fileHandle, FileAccess.Read); + stream.Position = position; + return (stream, true); + } + catch (IOException ex) + { + throw ExceptionHelper.ThrowHDiffIOException(ex); + } + } } #endif diff --git a/SharpHPatchZ/HPatch.cs b/SharpHPatchZ/HPatch.cs index 11e4b96..c836392 100644 --- a/SharpHPatchZ/HPatch.cs +++ b/SharpHPatchZ/HPatch.cs @@ -1,11 +1,11 @@ -using SharpHPatchZ.Extension; +using System; +using SharpHPatchZ.Extension; using SharpHPatchZ.Header; -using SharpHPatchZ.Header.Metadata; -using SharpHPatchZ.IO.Compression; using SharpHPatchZ.IO.Reader; using System.IO; using System.Threading; using System.Threading.Tasks; +using SharpHPatchZ.Patch; namespace SharpHPatchZ; @@ -30,8 +30,7 @@ public static HDiffInfo CreateInstance(CreateStream createPatchStream) } catch (EndOfStreamException eofStream) { - ExceptionHelper.ThrowHDiffEndOfFileOrData(eofStream); - throw; + throw ExceptionHelper.ThrowHDiffEndOfFileOrData(eofStream); } } @@ -40,6 +39,9 @@ public static async ValueTask CreateInstanceAsync( CancellationToken token = default) { (Stream stream, bool leaveOpen) = await createPatchStreamAsync(0, token); +#if NET6_0_OR_GREATER + await +#endif using BittableStreamReader reader = new(stream, leaveOpen: leaveOpen); string signature = await reader.ReadStringToNullAsync(token: token); @@ -50,64 +52,47 @@ public static async ValueTask CreateInstanceAsync( return info; } - public static void Patch(ref HDiffInfo info, - CreateStream createPatchStream, - string inputPath, - string outputPath, - PatchOptions options = default, - CancellationToken token = default) + public static PatchResult Patch(HDiffInfo info, + CreateStream createPatchStream, + string inputPath, + string outputPath, + PatchOptions options = default, + ProgressCallback progressCallback = default, + CancellationToken token = default) { - GetPatchDataOffsets(ref info, - out long coverDataOffset, - out long rleControlDataOffset, - out long rleCodeDataOffset, - out long newDataOffset, - out HDiffCompression compType); - - (Stream coverStream, bool coverStreamLeaveOpen) = createPatchStream(coverDataOffset); - (Stream rleControlStream, bool rleControlStreamLeaveOpen) = createPatchStream(rleControlDataOffset); - (Stream rleCodeStream, bool rleCodeStreamLeaveOpen) = createPatchStream(rleCodeDataOffset); - (Stream newDataStream, bool newDataStreamLeaveOpen) = createPatchStream(newDataOffset); - - using Stream decCoverStream = DecompressStreamFactory.CreateStream(compType, coverStream, coverStreamLeaveOpen); - using Stream decRleControlStream = DecompressStreamFactory.CreateStream(compType, rleControlStream, rleControlStreamLeaveOpen); - using Stream decRleCodeStream = DecompressStreamFactory.CreateStream(compType, rleCodeStream, rleCodeStreamLeaveOpen); - using Stream decNewDataStream = DecompressStreamFactory.CreateStream(compType, newDataStream, newDataStreamLeaveOpen); - - using BittableStreamReader coverReader = new(decCoverStream, options.ReaderBufferSize, leaveOpen: coverStreamLeaveOpen); - using BittableStreamReader rleControlReader = new(decRleControlStream, options.ReaderBufferSize, leaveOpen: rleControlStreamLeaveOpen); - using BittableStreamReader rleCodeReader = new(decRleCodeStream, options.ReaderBufferSize, leaveOpen: rleCodeStreamLeaveOpen); - using BittableStreamReader newDataReader = new(decNewDataStream, options.ReaderBufferSize, leaveOpen: newDataStreamLeaveOpen); - } - - public static async Task PatchAsync(HDiffInfo info, - CreateStreamAsync createPatchStreamAsync, - string inputPath, - string outputPath, - PatchOptions options = default, - CancellationToken token = default) - { - + try + { + using PatcherBase patcher = PatcherFactory.CreateFromInfo(ref info, createPatchStream, options, progressCallback); + patcher.StartPatch(inputPath, outputPath, token); + return true; + } + catch (Exception ex) + { + return ex; + } } - public static unsafe void GetPatchDataOffsets(ref HDiffInfo info, - out long coverDataOffset, - out long rleControlDataOffset, - out long rleCodeDataOffset, - out long newDataOffset, - out HDiffCompression compressionType) + public static async Task PatchAsync( + HDiffInfo info, + CreateStreamAsync createPatchStreamAsync, + string inputPath, + string outputPath, + PatchOptions options = default, + ProgressCallback progressCallback = default, + CancellationToken token = default) { - ref PatchMetadata patchMetadata = ref info.GetPatchMetadata(); - - compressionType = info.CompressionType; - - ChunkSizeInfo* coverDataSizeP = patchMetadata.CoverDataSizeP; - ChunkSizeInfo* rleControlDataSizeP = patchMetadata.RleControlDataSizeP; - ChunkSizeInfo* rleCodeDataSizeP = patchMetadata.RleCodeDataSizeP; - - coverDataOffset = patchMetadata.DiffDataOffset; - rleControlDataOffset = coverDataOffset + (coverDataSizeP->CompressedSize > 0 ? coverDataSizeP->CompressedSize : coverDataSizeP->Size); - rleCodeDataOffset = rleControlDataOffset + (rleControlDataSizeP->CompressedSize > 0 ? rleControlDataSizeP->CompressedSize : rleControlDataSizeP->Size); - newDataOffset = rleCodeDataOffset + (rleCodeDataSizeP->CompressedSize > 0 ? rleCodeDataSizeP->CompressedSize : rleCodeDataSizeP->Size); + try + { +#if NET6_0_OR_GREATER + await +#endif + using PatcherBase patcher = await PatcherFactory.CreateFromInfoAsync(info, createPatchStreamAsync, options, progressCallback, token); + await patcher.StartPatchAsync(inputPath, outputPath, token); + return true; + } + catch (Exception ex) + { + return ex; + } } } diff --git a/SharpHPatchZ/Header/HDiffInfo.cs b/SharpHPatchZ/Header/HDiffInfo.cs index 069526a..e03f2f1 100644 --- a/SharpHPatchZ/Header/HDiffInfo.cs +++ b/SharpHPatchZ/Header/HDiffInfo.cs @@ -39,7 +39,7 @@ public ref PatchMetadata GetPatchMetadata() ref DirectoryPatchMetadata dirPatchMetadata = ref MetadataAs(); if (Unsafe.IsNullRef(ref dirPatchMetadata) || dirPatchMetadata.PatchMetadataP == null) { - ExceptionHelper.ThrowHDiffInfoPatchMetadataNotAllocated(); + throw ExceptionHelper.ThrowHDiffInfoPatchMetadataNotAllocated(); } patchMetadataP = dirPatchMetadata.PatchMetadataP; @@ -51,7 +51,7 @@ public ref PatchMetadata GetPatchMetadata() if (patchMetadataP == null) { - ExceptionHelper.ThrowHDiffInfoPatchMetadataNotAllocated(); + throw ExceptionHelper.ThrowHDiffInfoPatchMetadataNotAllocated(); } return ref Unsafe.AsRef(patchMetadataP); diff --git a/SharpHPatchZ/Header/HeaderReader.cs b/SharpHPatchZ/Header/HeaderReader.cs index 6e20db7..1c07616 100644 --- a/SharpHPatchZ/Header/HeaderReader.cs +++ b/SharpHPatchZ/Header/HeaderReader.cs @@ -39,7 +39,7 @@ internal static void ReadBasicHeaderSignature( if (signature.IsEmpty || signatureSplits == 0) { - ExceptionHelper.ThrowHDiffHeaderSignatureEmptyOrUnreadable(); + throw ExceptionHelper.ThrowHDiffHeaderSignatureEmptyOrUnreadable(); } #if !NET6_0_OR_GREATER @@ -54,7 +54,7 @@ internal static void ReadBasicHeaderSignature( if (!Enum.TryParse(magicSpan, true, out magicType)) { - ExceptionHelper.ThrowHDiffHeaderMagicNotSupported(magicSpan); + throw ExceptionHelper.ThrowHDiffHeaderMagicNotSupported(magicSpan); } switch (magicType) @@ -65,13 +65,13 @@ internal static void ReadBasicHeaderSignature( if (compressionTypeSpan.Length != 0 && !Enum.TryParse(compressionTypeSpan, true, out compressionType)) { - ExceptionHelper.ThrowHDiffHeaderCompressionNotSupported(compressionTypeSpan); + throw ExceptionHelper.ThrowHDiffHeaderCompressionNotSupported(compressionTypeSpan); } if (checksumTypeSpan.Length != 0 && !Enum.TryParse(checksumTypeSpan, true, out checksumType)) { - ExceptionHelper.ThrowHDiffHeaderChecksumNotSupported(checksumTypeSpan); + throw ExceptionHelper.ThrowHDiffHeaderChecksumNotSupported(checksumTypeSpan); } return; @@ -82,15 +82,14 @@ internal static void ReadBasicHeaderSignature( if (compressionTypeSpan.Length != 0 && !Enum.TryParse(compressionTypeSpan, true, out compressionType)) { - ExceptionHelper.ThrowHDiffHeaderCompressionNotSupported(compressionTypeSpan); + throw ExceptionHelper.ThrowHDiffHeaderCompressionNotSupported(compressionTypeSpan); } return; } case HDiffMagic.Unknown: default: - ExceptionHelper.ThrowHDiffHeaderMagicNotSupported(magicSpan); - break; + throw ExceptionHelper.ThrowHDiffHeaderMagicNotSupported(magicSpan); } } @@ -197,11 +196,11 @@ private static unsafe void ReadHDiff19HeaderInfoCore( UnmanagedArray* inputPathEntryArray = streamReader.CreateUnmanagedStringList(inputPathEntryCount, (int)inputPathEntryBufferSize); UnmanagedArray* outputPathEntryArray = streamReader.CreateUnmanagedStringList(outputPathEntryCount, (int)outputPathEntryBufferSize); - int* inputFilesIndexArray = streamReader.CreateUnmanagedInt64As32List(inputRefFileCount); - int* outputFilesIndexArray = streamReader.CreateUnmanagedInt64As32List(outputRefFileCount); - long* outputFilesSizesArray = streamReader.CreateUnmanagedInt64List(outputRefFileCount); + UnmanagedArray* inputFilesIndexArray = streamReader.CreateUnmanagedInt64As32List(inputRefFileCount); + UnmanagedArray* outputFilesIndexArray = streamReader.CreateUnmanagedInt64As32List(outputRefFileCount); + UnmanagedArray* outputFilesSizesArray = streamReader.CreateUnmanagedInt64List(outputRefFileCount); FileIndexPair* sameFilePathIndexPairArray = streamReader.CreateUnmanagedIndexPairList(sameFilePathEntryCount); - int* newExecuteListArray = streamReader.CreateUnmanagedInt64As32List(newExecuteCount); + UnmanagedArray* newExecuteListArray = streamReader.CreateUnmanagedInt64As32List(newExecuteCount); if (streamReader.Offset - headDataStartOffset != headDataSize) { @@ -332,13 +331,13 @@ private static async Task ReadHDiff19HeaderInfoAsyncCore( sameFilePathCountSizeInfoP->Size = sameFilePathEntryTotalSize; dirTypeMetadata.SameFilePathIndexPairP = (FileIndexPair*)sameFilePathIndexPairArray; - dirTypeMetadata.NewExecuteListP = (int*)newExecuteListArray; + dirTypeMetadata.NewExecuteListP = (UnmanagedArray*)newExecuteListArray; dirTypeMetadata.InputPathListP = (UnmanagedArray*)inputPathEntryArray; dirTypeMetadata.OutputPathListP = (UnmanagedArray*)outputPathEntryArray; - dirTypeMetadata.InputFileIndexListP = (int*)inputFilesIndexArray; - dirTypeMetadata.OutputFileIndexListP = (int*)outputFilesIndexArray; - dirTypeMetadata.OutputFileSizeListP = (long*)outputFilesSizesArray; + dirTypeMetadata.InputFileIndexListP = (UnmanagedArray*)inputFilesIndexArray; + dirTypeMetadata.OutputFileIndexListP = (UnmanagedArray*)outputFilesIndexArray; + dirTypeMetadata.OutputFileSizeListP = (UnmanagedArray*)outputFilesSizesArray; externSizeInfo->NewExecuteCount = newExecuteCount; externSizeInfo->PrivateReservedDataSize = privateReservedDataSize; diff --git a/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs b/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs index e50c832..d785682 100644 --- a/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs +++ b/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs @@ -85,9 +85,9 @@ public bool IsDisposed public UnmanagedArray* InputPathListP; public UnmanagedArray* OutputPathListP; - public int* InputFileIndexListP; - public int* OutputFileIndexListP; - public long* OutputFileSizeListP; + public UnmanagedArray* InputFileIndexListP; + public UnmanagedArray* OutputFileIndexListP; + public UnmanagedArray* OutputFileSizeListP; // Seems unused. // TODO: See original code to see what it is. @@ -96,8 +96,8 @@ public bool IsDisposed // File Reference Chunk Info, including: // - Filename string chunks // - Checksum chunks - public ChunkSizeInfo* HeadDataSizeP; - public PatchMetadata* PatchMetadataP; - public ChecksumDataInfo* ChecksumDataInfoP; - public int* NewExecuteListP; + public ChunkSizeInfo* HeadDataSizeP; + public PatchMetadata* PatchMetadataP; + public ChecksumDataInfo* ChecksumDataInfoP; + public UnmanagedArray* NewExecuteListP; } \ No newline at end of file diff --git a/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs b/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs index bddc85b..b639666 100644 --- a/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs +++ b/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs @@ -78,15 +78,7 @@ public bool IsDisposed public int TypeSize; public T* Data; - public Span GetSpan() - { - if (sizeof(T) != TypeSize) - { - throw new ArrayTypeMismatchException("Type mismatched!"); - } - - return Data == null ? Span.Empty : new Span(Data, Length); - } + public Span GetSpan() => Data == null ? Span.Empty : new Span(Data, Length); public static UnmanagedArray* CreateAllocUnsafe(int count, bool initialize = false) { diff --git a/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs b/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs index fe39974..8874901 100644 --- a/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs +++ b/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs @@ -75,6 +75,13 @@ public static Utf16UnmanagedString CreateFromManaged(ReadOnlySpan source) public static implicit operator ReadOnlySpan(Utf16UnmanagedString unmanaged) => unmanaged.Native; + public static implicit operator string(Utf16UnmanagedString unmanaged) + => unmanaged.Native.Length == 0 + ? "" + : unmanaged.Native.ToString(); + + public override string ToString() => Native.ToString(); + [StructLayout(LayoutKind.Sequential)] public readonly struct NativeStringW(char* chars, int length) { @@ -87,5 +94,10 @@ public static implicit operator ReadOnlySpan(NativeStringW unmanaged) => new(unmanaged.Chars, unmanaged.Length); public override string ToString() => new(Chars, 0, Length); + + public static implicit operator string(NativeStringW unmanaged) + => unmanaged.Length == 0 + ? "" + : unmanaged.ToString(); } } diff --git a/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs b/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs index 4695991..27283fb 100644 --- a/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs +++ b/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs @@ -37,7 +37,7 @@ internal interface IDecompressor internal readonly struct HDiffDecompressor(HDiffCompression type) : IDecompressor { public Stream CreateDecompressionStream(Stream sourceStream, bool leaveOpen) - => DecompressStreamFactory.CreateStream(type, sourceStream, leaveOpen); + => DecompressStreamFactory.Create(type, sourceStream, leaveOpen); } internal static class DecompressStreamFactory @@ -46,12 +46,10 @@ internal static class DecompressStreamFactory private static ZstdStreamFallback? _createZstdStreamFallback; private static readonly int ZstdWindowLogMax = Environment.Is64BitProcess ? 31 : 30; - internal static Stream CreateStream( - HDiffCompression type, - Stream sourceStream, - bool leaveOpen) - { - return type switch + internal static Stream Create(HDiffCompression type, + Stream sourceStream, + bool leaveOpen) + => type switch { HDiffCompression.Uncompressed => sourceStream, HDiffCompression.Zstd => CreateZstdStream(sourceStream, leaveOpen), @@ -61,7 +59,6 @@ internal static Stream CreateStream( HDiffCompression.Lzma or HDiffCompression.Lzma2 => CreateLzmaStream(sourceStream, leaveOpen), _ => throw new NotSupportedException($"[PatchCore::GetDecompressStreamPlugin] Compression Type: {type} is not supported") }; - } private static Stream CreateZstdStream(Stream rawStream, bool leaveOpen) { diff --git a/SharpHPatchZ/IO/Reader/RandomMergedStreamReader.cs b/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs similarity index 97% rename from SharpHPatchZ/IO/Reader/RandomMergedStreamReader.cs rename to SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs index 1897ed8..9f353ff 100644 --- a/SharpHPatchZ/IO/Reader/RandomMergedStreamReader.cs +++ b/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs @@ -6,7 +6,7 @@ namespace SharpHPatchZ.IO.Reader; -internal sealed class RandomMergedStreamReader : IDisposable +internal sealed class RandomMergedStreamWrapper : IDisposable { private readonly ConcurrentDictionary> _fileStreams = []; private readonly ReaderWriterLockSlim _lifetimeLock = new(); @@ -16,7 +16,7 @@ internal sealed class RandomMergedStreamReader : IDisposable public long Length => _fileStreamEnds[^1]; - public RandomMergedStreamReader(string[] fileStreams, long[] fileStreamEnds) + public RandomMergedStreamWrapper(string[] fileStreams, long[] fileStreamEnds) { if (fileStreams is null) { @@ -211,7 +211,7 @@ private void ThrowIfDisposed() { if (Volatile.Read(ref _disposed) != 0) { - throw new ObjectDisposedException(nameof(RandomMergedStreamReader)); + throw new ObjectDisposedException(nameof(RandomMergedStreamWrapper)); } } } diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs new file mode 100644 index 0000000..43da7dd --- /dev/null +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs @@ -0,0 +1,281 @@ +using System; +using System.Buffers; +using System.IO; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using SharpHPatchZ.Extension; +using SharpHPatchZ.Header; +using SharpHPatchZ.Header.Metadata; +using SharpHPatchZ.IO.Reader; + +namespace SharpHPatchZ.Patch; + +internal sealed class HDiff13DerivedPatcher( + BittableStreamReader coverReader, + BittableStreamReader rleCtrlReader, + BittableStreamReader rleCodeReader, + BittableStreamReader newDataReader, + HDiffInfo info, + PatchOptions options, + ProgressCallback progressCallback) + : PatcherBase(info, options, progressCallback) +{ + private readonly BittableStreamReader _coverReader = coverReader; + private readonly BittableStreamReader _rleCtrlReader = rleCtrlReader; + private readonly BittableStreamReader _rleCodeReader = rleCodeReader; + private readonly BittableStreamReader _newDataReader = newDataReader; + + private CopySimilarFilesContext? _copySimilarFilesContext; + + public override void StartPatch(string inputPath, string outputPath, CancellationToken token) + { + InitializeInputOutputStream(inputPath, outputPath); + + // Start both CopyOver and CorePatch routine if context is not null. + if (_copySimilarFilesContext != null) + { + TaskCompletionSource copyOverTcs = new(null!, TaskCreationOptions.RunContinuationsAsynchronously); + TaskCompletionSource corePatcherTcs = new(null!, TaskCreationOptions.RunContinuationsAsynchronously); + + Thread copyOverThread = new(_ => + { + try + { + _copySimilarFilesContext.RunCopy(this, Options, token); + copyOverTcs.SetResult(true); + } + catch (OperationCanceledException) when (token.IsCancellationRequested) + { + copyOverTcs.SetCanceled(); + } + catch (Exception ex) + { + copyOverTcs.SetException(ex); + } + }); + + Thread corePatcherThread = new(_ => + { + try + { + StartCorePatcher(token); + corePatcherTcs.SetResult(true); + } + catch (OperationCanceledException) when (token.IsCancellationRequested) + { + corePatcherTcs.SetCanceled(); + } + catch (Exception ex) + { + corePatcherTcs.SetException(ex); + } + }); + + copyOverThread.Start(); + corePatcherThread.Start(); + Task.WhenAll(copyOverTcs.Task, corePatcherTcs.Task).Wait(token); + return; + } + + // Otherwise, run the CorePatch routine only + StartCorePatcher(token); + } + + public override Task StartPatchAsync(string inputPath, string outputPath, CancellationToken token) + => Task.Factory.StartNew(_ => StartPatch(inputPath, outputPath, token), + token, + TaskCreationOptions.LongRunning); + + private unsafe void StartCorePatcher(CancellationToken token) + { + + } + + private unsafe void InitializeInputOutputStream(string inputPath, string outputPath) + { + ref PatchMetadata patchMetadata = ref Info.GetPatchMetadata(); + if (Unsafe.IsNullRef(ref patchMetadata)) throw ExceptionHelper.ThrowHDiffInfoPatchMetadataNotAllocated(); + + // Return only single stream for HDiff13 + if (Info.MagicType == HDiffMagic.HDiff13) + { + FileInfo inputFile = inputPath.GetFileInfo(); + FileInfo outputFile = outputPath.GetFileInfo(); + + // Sanity input existence and its size + if (!inputFile.Exists) throw ExceptionHelper.ThrowHDiffPatchInputPathNotExist(inputFile.FullName); + if (inputFile.Length != patchMetadata.DiffOldSize) + throw ExceptionHelper.ThrowHDiffPatchInputSizeMismatched( + inputFile.FullName, inputFile.Length, patchMetadata.DiffOldSize); + + InputStream = new RandomMergedStreamWrapper([inputFile.FullName], [inputFile.Length]); + OutputStream = new RandomMergedStreamWrapper([outputFile.FullName], [patchMetadata.DiffNewSize]); + + return; + } + + // Return multiple stream for HDiff19 + DirectoryInfo inputDir = inputPath.GetDirectoryInfo(); + DirectoryInfo outputDir = outputPath.GetDirectoryInfo(); + outputDir.Create(); + + ref DirectoryPatchMetadata dirMetadata = ref Info.MetadataAs(); + if (Unsafe.IsNullRef(ref dirMetadata)) throw ExceptionHelper.ThrowHDiffInfoDirectoryPatchMetadataNotAllocated(); + + // All input and output paths + Utf16UnmanagedString[] allInputPaths = CopyToManagedStringList(dirMetadata.InputPathListP); + Utf16UnmanagedString[] allOutputPaths = CopyToManagedStringList(dirMetadata.OutputPathListP); + + // Similar input and output paths + (string[] similarInputFiles, string[] similarOutputFiles) = + CopySimilarFilePairsFromIndexes(allInputPaths, allOutputPaths, ref dirMetadata); + + // Reference / Merged Input and Output paths + long refInputTotalSize = dirMetadata.InputPathCountSizeInfoP->Size; + int refInputCount = dirMetadata.InputFileIndexListP->Length; + string[] refInputFiles = new string[refInputCount]; + long[] refInputFilesSize = new long[refInputCount]; + + int refOutputCount = dirMetadata.OutputFileIndexListP->Length; + string[] refOutputFiles = new string[refInputCount]; + long[] refOutputFilesSize = new long[refInputCount]; + + // -- Reference Input + Span refInputFileIndexSpan = dirMetadata.InputFileIndexListP->GetSpan(); + long lastInputFileEnds = 0; + for (int i = 0; i < refInputCount; i++) + { + int fileIndex = refInputFileIndexSpan[i]; + refInputFiles[i] = Path.GetFullPath(Path.Combine(inputDir.FullName, allInputPaths[fileIndex])); + + string filePath = refInputFiles[i]; + FileInfo fileInfo = new(filePath); + long fileSize = fileInfo.Exists ? fileInfo.Length : 0; + + lastInputFileEnds += fileSize; + refInputFilesSize[i] = lastInputFileEnds; + } + + // -- Reference Input Size sanity + if (lastInputFileEnds != refInputTotalSize) + { + throw ExceptionHelper.ThrowHDiffPatchInputFilesMismatched(lastInputFileEnds, refInputTotalSize); + } + + // -- Reference Output + Span refOutputFileIndexSpan = dirMetadata.OutputFileIndexListP->GetSpan(); + Span refOutputFileSizeSpan = dirMetadata.OutputFileSizeListP->GetSpan(); + + for (int i = 0; i < refOutputCount; i++) + { + int fileIndex = refOutputFileIndexSpan[i]; + long fileSize = refOutputFileSizeSpan[i]; + + refOutputFiles[i] = Path.GetFullPath(Path.Combine(outputDir.FullName, allOutputPaths[fileIndex])); + refOutputFilesSize[i] = fileSize; + } + + InputStream = new RandomMergedStreamWrapper(refInputFiles, refInputFilesSize); + OutputStream = new RandomMergedStreamWrapper(refOutputFiles, refOutputFilesSize); + _copySimilarFilesContext = new CopySimilarFilesContext + { + InputDir = inputDir.FullName, + OutputDir = outputDir.FullName, + InputPaths = similarInputFiles, + OutputPaths = similarOutputFiles + }; + } + + private static unsafe Utf16UnmanagedString[] CopyToManagedStringList(UnmanagedArray* unmanagedArray) + { + var strings = new Utf16UnmanagedString[unmanagedArray->Length]; + Span span = unmanagedArray->GetSpan(); + + span.CopyTo(strings); + return strings; + } + + private static unsafe (string[], string[]) CopySimilarFilePairsFromIndexes( + Span inputPaths, Span outputPaths, ref DirectoryPatchMetadata dirMetadata) + { + int count = dirMetadata.SameFilePathCountSizeInfoP->Count; + + string[] resultInputs = new string[count]; + string[] resultOutputs = new string[count]; + + for (int i = 0; i < count; i++) + { + ref FileIndexPair pair = ref dirMetadata.SameFilePathIndexPairP[i]; + resultInputs[i] = inputPaths[pair.OldIndex]; + resultOutputs[i] = outputPaths[pair.NewIndex]; + } + + return (resultInputs, resultOutputs); + } + + protected override void DisposeCore() + { + base.DisposeCore(); + _coverReader.Dispose(); + _rleCtrlReader.Dispose(); + _rleCodeReader.Dispose(); + _newDataReader.Dispose(); + } + +#if NET6_0_OR_GREATER + protected override ValueTask DisposeCoreAsync() + => new(Task.WhenAll(base.DisposeCoreAsync().AsTask(), + _coverReader.DisposeAsync().AsTask(), + _rleCtrlReader.DisposeAsync().AsTask(), + _rleCodeReader.DisposeAsync().AsTask(), + _newDataReader.DisposeAsync().AsTask())); +#endif + + private class CopySimilarFilesContext + { + public required string InputDir { get; init; } + public required string OutputDir { get; init; } + + public required string[] InputPaths { get; init; } + public required string[] OutputPaths { get; init; } + + public void RunCopy(PatcherBase patcher, + PatchOptions options, + CancellationToken token) + { + int bufferSize = options.CopyBufferSize; + if (bufferSize <= 0) bufferSize = 16 << 10; + + byte[] buffer = ArrayPool.Shared.Rent(bufferSize); + try + { + int count = InputPaths.Length; + token.ThrowIfCancellationRequested(); + + for (int i = 0; i < count; i++) + { + string inputPath = Path.Combine(InputDir, InputPaths[i]); + string outputPath = Path.Combine(OutputDir, OutputPaths[i]); + + if (Path.GetDirectoryName(outputPath) is { } outputDir) + Directory.CreateDirectory(outputDir); + + using FileStream inputStream = File.Open(inputPath, FileMode.Open, FileAccess.Read); + using FileStream outputStream = File.Create(outputPath, bufferSize); + int read; + while ((read = inputStream.Read(buffer, 0, bufferSize)) > 0) + { + token.ThrowIfCancellationRequested(); + outputStream.Write(buffer, 0, read); + patcher.AdvanceProgress(read); + } + } + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + } +} diff --git a/SharpHPatchZ/Patch/PatcherBase.cs b/SharpHPatchZ/Patch/PatcherBase.cs new file mode 100644 index 0000000..cfc4c74 --- /dev/null +++ b/SharpHPatchZ/Patch/PatcherBase.cs @@ -0,0 +1,55 @@ +using SharpHPatchZ.Header; +using SharpHPatchZ.IO.Reader; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace SharpHPatchZ.Patch; + +internal abstract class PatcherBase(HDiffInfo info, PatchOptions options, ProgressCallback progressCallback) + : IDisposable +#if NET6_0_OR_GREATER + , IAsyncDisposable +#endif +{ + protected RandomMergedStreamWrapper? InputStream { get; set; } + protected RandomMergedStreamWrapper? OutputStream { get; set; } + + protected HDiffInfo Info { get; set; } = info; + protected PatchOptions Options { get; set; } = options; + protected ProgressCallback ProgressCallback { get; } = !progressCallback.IsAllocated ? new ProgressCallback() : progressCallback; + + protected long TotalWritten; + protected long TotalSize = info.GetPatchMetadata().DiffNewSize; + + public abstract void StartPatch(string inputPath, string outputPath, CancellationToken token); + public abstract Task StartPatchAsync(string inputPath, string outputPath, CancellationToken token); + + internal unsafe void AdvanceProgress(int written) + { + Interlocked.Add(ref TotalWritten, written); + ProgressCallback.ProcessedBytesCallback(TotalWritten, TotalSize, written); + } + + public void Dispose() => DisposeCore(); + +#if NET6_0_OR_GREATER + public ValueTask DisposeAsync() => DisposeCoreAsync(); +#endif + + protected virtual void DisposeCore() + { + InputStream?.Dispose(); + OutputStream?.Dispose(); + } + +#if NET6_0_OR_GREATER + protected virtual ValueTask DisposeCoreAsync() + { + InputStream?.Dispose(); + OutputStream?.Dispose(); + + return ValueTask.CompletedTask; + } +#endif +} diff --git a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs new file mode 100644 index 0000000..5c0558d --- /dev/null +++ b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs @@ -0,0 +1,119 @@ +using SharpHPatchZ.Header; +using SharpHPatchZ.Header.Metadata; +using SharpHPatchZ.IO.Compression; +using SharpHPatchZ.IO.Reader; +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace SharpHPatchZ.Patch; + +internal static partial class PatcherFactory +{ + private static class HDiff13Derived + { + public static HDiff13DerivedPatcher Create( + ref HDiffInfo info, + CreateStream createPatchStream, + PatchOptions options, + ProgressCallback progressCallback) + { + GetPatchContextInfos(ref info, + out long coverDataOffset, + out long rleCtrlDataOffset, + out long rleCodeDataOffset, + out long newDataOffset); + + DiffReadersContext context = CreateReaderContext(info.CompressionType, + options, + createPatchStream(coverDataOffset), + createPatchStream(rleCtrlDataOffset), + createPatchStream(rleCodeDataOffset), + createPatchStream(newDataOffset)); + + return new HDiff13DerivedPatcher(context.Cover, + context.RleCtrl, + context.RleCode, + context.NewData, + info, + options, + progressCallback); + } + + public static async Task CreateAsync( + HDiffInfo info, + CreateStreamAsync createPatchStreamAsync, + PatchOptions options, + ProgressCallback progressCallback, + CancellationToken token) + { + GetPatchContextInfos(ref info, + out long coverDataOffset, + out long rleCtrlDataOffset, + out long rleCodeDataOffset, + out long newDataOffset); + + DiffReadersContext context = CreateReaderContext(info.CompressionType, + options, + await createPatchStreamAsync(coverDataOffset, token), + await createPatchStreamAsync(rleCtrlDataOffset, token), + await createPatchStreamAsync(rleCodeDataOffset, token), + await createPatchStreamAsync(newDataOffset, token)); + + return new HDiff13DerivedPatcher(context.Cover, + context.RleCtrl, + context.RleCode, + context.NewData, + info, + options, + progressCallback); + } + + private static DiffReadersContext CreateReaderContext(HDiffCompression compType, + PatchOptions options, + ValueTuple coverCtx, + ValueTuple rleCtrlCtx, + ValueTuple rleCodeCtx, + ValueTuple newDataCtx) + { + int bufferSize = options.ReaderBufferSize; + + Stream decCoverStream = DecompressStreamFactory.Create(compType, coverCtx.Item1, coverCtx.Item2); + Stream decRleControlStream = DecompressStreamFactory.Create(compType, rleCtrlCtx.Item1, rleCtrlCtx.Item2); + Stream decRleCodeStream = DecompressStreamFactory.Create(compType, rleCodeCtx.Item1, rleCodeCtx.Item2); + Stream decNewDataStream = DecompressStreamFactory.Create(compType, newDataCtx.Item1, newDataCtx.Item2); + + BittableStreamReader coverReader = new(decCoverStream, bufferSize, coverCtx.Item2); + BittableStreamReader rleCtrlReader = new(decRleControlStream, bufferSize, rleCtrlCtx.Item2); + BittableStreamReader rleCodeReader = new(decRleCodeStream, bufferSize, rleCodeCtx.Item2); + BittableStreamReader newDataReader = new(decNewDataStream, bufferSize, newDataCtx.Item2); + + return new DiffReadersContext(coverReader, rleCtrlReader, rleCodeReader, newDataReader); + } + + private static unsafe void GetPatchContextInfos(ref HDiffInfo info, + out long coverDataOffset, + out long rleCtrlDataOffset, + out long rleCodeDataOffset, + out long newDataOffset) + { + ref PatchMetadata patchMetadata = ref info.GetPatchMetadata(); + + ChunkSizeInfo* coverDataSizeP = patchMetadata.CoverDataSizeP; + ChunkSizeInfo* rleControlDataSizeP = patchMetadata.RleControlDataSizeP; + ChunkSizeInfo* rleCodeDataSizeP = patchMetadata.RleCodeDataSizeP; + + coverDataOffset = patchMetadata.DiffDataOffset; + rleCtrlDataOffset = coverDataOffset + (coverDataSizeP->CompressedSize > 0 ? coverDataSizeP->CompressedSize : coverDataSizeP->Size); + rleCodeDataOffset = rleCtrlDataOffset + (rleControlDataSizeP->CompressedSize > 0 ? rleControlDataSizeP->CompressedSize : rleControlDataSizeP->Size); + newDataOffset = rleCodeDataOffset + (rleCodeDataSizeP->CompressedSize > 0 ? rleCodeDataSizeP->CompressedSize : rleCodeDataSizeP->Size); + } + + private record struct DiffReadersContext( + BittableStreamReader Cover, + BittableStreamReader RleCtrl, + BittableStreamReader RleCode, + BittableStreamReader NewData); + } +} diff --git a/SharpHPatchZ/Patch/PatcherFactory.cs b/SharpHPatchZ/Patch/PatcherFactory.cs new file mode 100644 index 0000000..c86972e --- /dev/null +++ b/SharpHPatchZ/Patch/PatcherFactory.cs @@ -0,0 +1,36 @@ +using System.Threading; +using System.Threading.Tasks; +using SharpHPatchZ.Extension; +using SharpHPatchZ.Header; + +namespace SharpHPatchZ.Patch; + +internal static partial class PatcherFactory +{ + public static PatcherBase CreateFromInfo(ref HDiffInfo info, + CreateStream createPatchStream, + PatchOptions options, + ProgressCallback progressCallback) + { + if (info.MagicType is HDiffMagic.HDiff19 or HDiffMagic.HDiff13) + { + return HDiff13Derived.Create(ref info, createPatchStream, options, progressCallback); + } + + throw ExceptionHelper.ThrowHDiffPatchFactoryNotSupported(info.MagicType); + } + + public static async Task CreateFromInfoAsync(HDiffInfo info, + CreateStreamAsync createPatchStreamAsync, + PatchOptions options, + ProgressCallback progressCallback, + CancellationToken token) + { + if (info.MagicType is HDiffMagic.HDiff19 or HDiffMagic.HDiff13) + { + return await HDiff13Derived.CreateAsync(info, createPatchStreamAsync, options, progressCallback, token); + } + + throw ExceptionHelper.ThrowHDiffPatchFactoryNotSupported(info.MagicType); + } +} diff --git a/SharpHPatchZ/PatchOptions.cs b/SharpHPatchZ/PatchOptions.cs index c28120e..38864ba 100644 --- a/SharpHPatchZ/PatchOptions.cs +++ b/SharpHPatchZ/PatchOptions.cs @@ -6,7 +6,7 @@ namespace SharpHPatchZ; public struct PatchOptions() { public uint ParallelThreads = 0; - public bool IgnoreErrors = false; public bool UseSIMD = true; public int ReaderBufferSize = -1; + public int CopyBufferSize = -1; } diff --git a/SharpHPatchZ/PatchResult.cs b/SharpHPatchZ/PatchResult.cs new file mode 100644 index 0000000..6e6b877 --- /dev/null +++ b/SharpHPatchZ/PatchResult.cs @@ -0,0 +1,18 @@ +using System; +using SharpHPatchZ.Extension; + +namespace SharpHPatchZ; + +public class PatchResult +{ + public Exception? Exception { get; init; } + + public bool IsSuccessful { get; init; } + + public static implicit operator bool(PatchResult result) => result.IsSuccessful; + public static implicit operator Exception?(PatchResult result) => result.Exception; + public static implicit operator int(PatchResult result) => ExceptionHelper.TryGetReturnCodeFromError(result); + + public static implicit operator PatchResult(Exception ex) => new() { Exception = ex, IsSuccessful = false }; + public static implicit operator PatchResult(bool value) => new() { Exception = !value ? new Exception() : null, IsSuccessful = value }; +} diff --git a/SharpHPatchZ/ProgressCallback.cs b/SharpHPatchZ/ProgressCallback.cs index e03bd0c..08c1f22 100644 --- a/SharpHPatchZ/ProgressCallback.cs +++ b/SharpHPatchZ/ProgressCallback.cs @@ -8,18 +8,24 @@ namespace SharpHPatchZ; public delegate void ProcessedBytesManagedCallback(long totalProcessed, long totalSize, int written); [StructLayout(LayoutKind.Sequential)] -public readonly struct ProgressCallback +public readonly +#if NET6_0_OR_GREATER + unsafe +#endif + struct ProgressCallback { #if NET6_0_OR_GREATER - public readonly unsafe delegate* unmanaged[Cdecl] ProcessedBytesCallback; + public readonly delegate* unmanaged[Cdecl] ProcessedBytesCallback; #else public readonly ProcessedBytesManagedCallback ProcessedBytesCallback; #endif + internal bool IsAllocated => ProcessedBytesCallback != null; + public ProgressCallback() : this(null) { } #if NET6_0_OR_GREATER - public unsafe ProgressCallback(ProcessedBytesManagedCallback? callback) + public ProgressCallback(ProcessedBytesManagedCallback? callback) { if (callback != null) { diff --git a/Test/Program.cs b/Test/Program.cs index 62bb2eb..6fe5f1c 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -1,4 +1,5 @@ -using SharpHDiffPatch.Core; +using System; +using SharpHDiffPatch.Core; using SharpHPatchZ; using SharpHPatchZ.Header; using System.IO; @@ -17,15 +18,26 @@ public static async Task Main() { HDiffPatch hPatchOld = new(); hPatchOld.Initialize(CreateStream); - hPatchOld.Patch(TestPathInput, TestPathOutput, true); + // hPatchOld.Patch(TestPathInput, TestPathOutput, true); + + ProgressCallback progressCallback = ProgressCallback.CreateFromManaged(WriteProgress); using (HDiffInfo info1 = await HPatch.CreateInstanceAsync(CreateStreamAsync)) { + PatchResult result = await HPatch.PatchAsync(info1, CreateStreamAsync, TestPathInput, TestPathOutput, progressCallback: progressCallback); } + Console.WriteLine(); using (HDiffInfo info2 = HPatch.CreateInstance(CreateStream)) { + PatchResult result = HPatch.Patch(info2, CreateStream, TestPathInput, TestPathOutput, progressCallback: progressCallback); } + Console.WriteLine(); + } + + public static void WriteProgress(long totalProcessed, long totalSize, int written) + { + Console.Write($"{totalProcessed} / {totalSize} {(int)(totalProcessed / (double)totalSize * 100)}%\r"); } public static Stream CreateStream() From afe45868e29f6d132c6a421904a9361eed00bbfb Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sat, 22 Aug 2026 23:12:53 +0700 Subject: [PATCH 08/72] Split HDiff13DerivedPatcher codes --- ...3DerivedPatcher.CopySimilarFilesContext.cs | 59 +++++++++++++++++ .../HDiff13DerivedPatcher.CorePatcher.cs | 11 ++++ SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs | 64 +------------------ 3 files changed, 73 insertions(+), 61 deletions(-) create mode 100644 SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs create mode 100644 SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs new file mode 100644 index 0000000..abd0115 --- /dev/null +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs @@ -0,0 +1,59 @@ +using System.Buffers; +using System.IO; +using System.Threading; + +namespace SharpHPatchZ.Patch; + +internal sealed partial class HDiff13DerivedPatcher +{ + private class CopySimilarFilesContext(string inputDir, + string[] inputPaths, + string outputDir, + string[] outputPaths) + { + private string InputDir { get; } = inputDir; + private string OutputDir { get; } = outputDir; + + private string[] InputPaths { get; } = inputPaths; + private string[] OutputPaths { get; } = outputPaths; + + public void RunCopy(PatcherBase patcher, + PatchOptions options, + CancellationToken token) + { + int bufferSize = options.CopyBufferSize; + if (bufferSize <= 0) bufferSize = 16 << 10; + + byte[] buffer = ArrayPool.Shared.Rent(bufferSize); + try + { + int count = InputPaths.Length; + token.ThrowIfCancellationRequested(); + + for (int i = 0; i < count; i++) + { + token.ThrowIfCancellationRequested(); + string inputPath = Path.GetFullPath(Path.Combine(InputDir, InputPaths[i])); + string outputPath = Path.GetFullPath(Path.Combine(OutputDir, OutputPaths[i])); + + if (Path.GetDirectoryName(outputPath) is { } outputDir) + Directory.CreateDirectory(outputDir); + + using FileStream inputStream = File.Open(inputPath, FileMode.Open, FileAccess.Read); + using FileStream outputStream = File.Create(outputPath, bufferSize); + int read; + while ((read = inputStream.Read(buffer, 0, bufferSize)) > 0) + { + token.ThrowIfCancellationRequested(); + outputStream.Write(buffer, 0, read); + patcher.AdvanceProgress(read); + } + } + } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + } +} diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs new file mode 100644 index 0000000..0a5f4ce --- /dev/null +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs @@ -0,0 +1,11 @@ +using System.Threading; + +namespace SharpHPatchZ.Patch; + +internal sealed partial class HDiff13DerivedPatcher +{ + private unsafe void StartCorePatcher(CancellationToken token) + { + + } +} diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs index 43da7dd..ee9e2a1 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs @@ -1,5 +1,4 @@ using System; -using System.Buffers; using System.IO; using System.Runtime.CompilerServices; using System.Threading; @@ -11,7 +10,7 @@ namespace SharpHPatchZ.Patch; -internal sealed class HDiff13DerivedPatcher( +internal sealed partial class HDiff13DerivedPatcher( BittableStreamReader coverReader, BittableStreamReader rleCtrlReader, BittableStreamReader rleCodeReader, @@ -87,11 +86,6 @@ public override Task StartPatchAsync(string inputPath, string outputPath, Cancel token, TaskCreationOptions.LongRunning); - private unsafe void StartCorePatcher(CancellationToken token) - { - - } - private unsafe void InitializeInputOutputStream(string inputPath, string outputPath) { ref PatchMetadata patchMetadata = ref Info.GetPatchMetadata(); @@ -178,13 +172,8 @@ private unsafe void InitializeInputOutputStream(string inputPath, string outputP InputStream = new RandomMergedStreamWrapper(refInputFiles, refInputFilesSize); OutputStream = new RandomMergedStreamWrapper(refOutputFiles, refOutputFilesSize); - _copySimilarFilesContext = new CopySimilarFilesContext - { - InputDir = inputDir.FullName, - OutputDir = outputDir.FullName, - InputPaths = similarInputFiles, - OutputPaths = similarOutputFiles - }; + _copySimilarFilesContext = new CopySimilarFilesContext(inputDir.FullName, similarInputFiles, + outputDir.FullName, similarOutputFiles); } private static unsafe Utf16UnmanagedString[] CopyToManagedStringList(UnmanagedArray* unmanagedArray) @@ -231,51 +220,4 @@ protected override ValueTask DisposeCoreAsync() _rleCodeReader.DisposeAsync().AsTask(), _newDataReader.DisposeAsync().AsTask())); #endif - - private class CopySimilarFilesContext - { - public required string InputDir { get; init; } - public required string OutputDir { get; init; } - - public required string[] InputPaths { get; init; } - public required string[] OutputPaths { get; init; } - - public void RunCopy(PatcherBase patcher, - PatchOptions options, - CancellationToken token) - { - int bufferSize = options.CopyBufferSize; - if (bufferSize <= 0) bufferSize = 16 << 10; - - byte[] buffer = ArrayPool.Shared.Rent(bufferSize); - try - { - int count = InputPaths.Length; - token.ThrowIfCancellationRequested(); - - for (int i = 0; i < count; i++) - { - string inputPath = Path.Combine(InputDir, InputPaths[i]); - string outputPath = Path.Combine(OutputDir, OutputPaths[i]); - - if (Path.GetDirectoryName(outputPath) is { } outputDir) - Directory.CreateDirectory(outputDir); - - using FileStream inputStream = File.Open(inputPath, FileMode.Open, FileAccess.Read); - using FileStream outputStream = File.Create(outputPath, bufferSize); - int read; - while ((read = inputStream.Read(buffer, 0, bufferSize)) > 0) - { - token.ThrowIfCancellationRequested(); - outputStream.Write(buffer, 0, read); - patcher.AdvanceProgress(read); - } - } - } - finally - { - ArrayPool.Shared.Return(buffer); - } - } - } } From c26407a5453d4993d329b265512f816adcfcaeaf Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sat, 22 Aug 2026 23:13:22 +0700 Subject: [PATCH 09/72] Fix InvalidTypeWithPointersNotSupported error on older .NET --- SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs b/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs index 8874901..320bca2 100644 --- a/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs +++ b/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs @@ -26,7 +26,7 @@ public void Init() public void Dispose() { - if (IsDisposed || !IsInitialized || Native is { Chars: null, Length: 0 }) + if (IsDisposed || !IsInitialized || Native is { Chars: 0, Length: 0 }) { return; } @@ -36,7 +36,7 @@ public void Dispose() NativeStringW old = Native; Native = NativeStringW.Empty; - MemoryAlloc.Free(old.Chars); + MemoryAlloc.Free((char*)old.Chars); } public MetadataTypeConst MetadataType { get; private set; } @@ -87,13 +87,13 @@ public readonly struct NativeStringW(char* chars, int length) { public static NativeStringW Empty => default; - public readonly char* Chars = chars; - public readonly int Length = length; + public readonly nint Chars = (nint)chars; + public readonly int Length = length; public static implicit operator ReadOnlySpan(NativeStringW unmanaged) - => new(unmanaged.Chars, unmanaged.Length); + => new((char*)unmanaged.Chars, unmanaged.Length); - public override string ToString() => new(Chars, 0, Length); + public override string ToString() => new((char*)Chars, 0, Length); public static implicit operator string(NativeStringW unmanaged) => unmanaged.Length == 0 From 9aeb2711c3a5e47de4eb22997edb67951f56f9e1 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 23 Aug 2026 03:40:41 +0700 Subject: [PATCH 10/72] Implement BigArrayPool --- SharpHPatchZ/Extension/BigArrayPool.cs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 SharpHPatchZ/Extension/BigArrayPool.cs diff --git a/SharpHPatchZ/Extension/BigArrayPool.cs b/SharpHPatchZ/Extension/BigArrayPool.cs new file mode 100644 index 0000000..203e6b3 --- /dev/null +++ b/SharpHPatchZ/Extension/BigArrayPool.cs @@ -0,0 +1,9 @@ +using System; +using System.Buffers; + +namespace SharpHPatchZ.Extension; + +internal static class BigArrayPool +{ + public static ArrayPool Shared { get; } = ArrayPool.Create(128 << 20, Environment.ProcessorCount << 10); +} From 4fb74eddb61c0eb9f1dda9e7a072320301000b88 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 23 Aug 2026 03:41:33 +0700 Subject: [PATCH 11/72] Fix LZMA chunk decompression --- README.md | 2 +- SharpHPatchZ/Extension/ExceptionHelper.cs | 52 ++++++++---- SharpHPatchZ/Extension/StreamExtension.cs | 58 ++++++++++++++ .../IO/Compression/CompressionStreamHelper.cs | 80 ++++++++++++++----- .../IO/Compression/Lzma/LzmaInputStream.cs | 9 ++- .../Patch/PatcherFactory.HDiff13Derived.cs | 38 ++++++--- 6 files changed, 192 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 370532b..6ed3f3a 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Supporting file and directory patching with these compression formats: - BZip2 - Deflate - Zstd -- LZMA2 (not LZMA) +- LZMA and LZMA2 - No Compression. Unfortunately, the **``HDIFFSF20``** (Single Compressed) format is still unsupported. But we are planning to add it in the future. diff --git a/SharpHPatchZ/Extension/ExceptionHelper.cs b/SharpHPatchZ/Extension/ExceptionHelper.cs index b59be42..9227a0e 100644 --- a/SharpHPatchZ/Extension/ExceptionHelper.cs +++ b/SharpHPatchZ/Extension/ExceptionHelper.cs @@ -35,13 +35,20 @@ file static class Const { HDiffPatchInputSizeMismatched, 0x55 }, { HDiffPatchPathNotADirectory, 0x56 }, { HDiffPatchPathNotAFile, 0x57 }, - { HDiffPatchInputFilesMismatched, 0x58 } + { HDiffPatchInputFilesMismatched, 0x58 }, + + // Decompression Initialization + { HDiffCompLZMAPropertyMissing, 0xA0 }, + { HDiffCompLZMA2DictionaryInvalid, 0xA1 }, + { HDiffCompLZMA2NoCompressedPayload, 0xA2 }, + { HDiffCompLZMADictionaryInvalidLength, 0xA3 }, + { HDiffCompLZMASizeTooSmallForDictionaryRead, 0xA4 } }; - public const string HDiffHeaderMagicNotSupported = "HDIFF_HeaderMagicNotSupported"; - public const string HDiffHeaderCompressionNotSupported = "HDIFF_HeaderCompressionNotSupported"; - public const string HDiffHeaderChecksumNotSupported = "HDIFF_HeaderChecksumNotSupported"; - public const string HDiffPatchFactoryNotSupported = "HDIFF_PatchFactoryNotSupported"; + public const string HDiffHeaderMagicNotSupported = "HDIFF_HeaderMagicNotSupported"; + public const string HDiffHeaderCompressionNotSupported = "HDIFF_HeaderCompressionNotSupported"; + public const string HDiffHeaderChecksumNotSupported = "HDIFF_HeaderChecksumNotSupported"; + public const string HDiffPatchFactoryNotSupported = "HDIFF_PatchFactoryNotSupported"; public const string HDiffInfoNotAllocated = "HDIFF_InfoNotAllocated"; public const string HDiffInfoDirectoryPatchMetadataNotAllocated = "HDIFF_InfoDirectoryPatchMetadataNotAllocated"; @@ -49,15 +56,21 @@ file static class Const public const string HDiffFILEDescriptorNull = "HDIFF_FILEDescriptorNull"; public const string HDiffArgumentNull = "HDIFF_ArgumentNull"; - public const string HDiffHeaderSignatureEmptyOrUnreadable = "HDIFF_HeaderSignatureEmptyOrUnreadable"; - public const string HDiffHeaderEndOfFileOrData = "HDIFF_EndOfFileOrData"; - public const string HDiffPathIsEmptyOrInvalid = "HDIFF_PathIsEmptyOrInvalid"; - public const string HDiffIOException = "HDIFF_IOException"; - public const string HDiffPatchInputPathNotExist = "HDIFF_PatchInputPathNotExist"; - public const string HDiffPatchInputSizeMismatched = "HDIFF_PatchInputSizeMismatched"; - public const string HDiffPatchPathNotADirectory = "HDIFF_PatchPathNotADirectory"; - public const string HDiffPatchPathNotAFile = "HDIFF_PatchPathNotAFile"; - public const string HDiffPatchInputFilesMismatched = "HDIFF_PatchInputFilesMismatched"; + public const string HDiffHeaderSignatureEmptyOrUnreadable = "HDIFF_HeaderSignatureEmptyOrUnreadable"; + public const string HDiffHeaderEndOfFileOrData = "HDIFF_EndOfFileOrData"; + public const string HDiffPathIsEmptyOrInvalid = "HDIFF_PathIsEmptyOrInvalid"; + public const string HDiffIOException = "HDIFF_IOException"; + public const string HDiffPatchInputPathNotExist = "HDIFF_PatchInputPathNotExist"; + public const string HDiffPatchInputSizeMismatched = "HDIFF_PatchInputSizeMismatched"; + public const string HDiffPatchPathNotADirectory = "HDIFF_PatchPathNotADirectory"; + public const string HDiffPatchPathNotAFile = "HDIFF_PatchPathNotAFile"; + public const string HDiffPatchInputFilesMismatched = "HDIFF_PatchInputFilesMismatched"; + + public const string HDiffCompLZMAPropertyMissing = "HDIFF_CompLZMAPropertyMissing"; + public const string HDiffCompLZMA2DictionaryInvalid = "HDIFF_CompLZMA2DictionaryInvalid"; + public const string HDiffCompLZMA2NoCompressedPayload = "HDIFF_CompLZMA2NoCompressedPayload"; + public const string HDiffCompLZMADictionaryInvalidLength = "HDIFF_CompLZMADictionaryInvalidLength"; + public const string HDiffCompLZMASizeTooSmallForDictionaryRead = "HDIFF_CompLZMASizeToSmallForDictionaryRead"; } public static class ExceptionHelper @@ -103,6 +116,17 @@ public static InvalidOperationException ThrowHDiffPatchPathNotAFile(string path) public static InvalidOperationException ThrowHDiffPatchInputFilesMismatched(long existingSize, long expectingSize) => new($"[{Const.HDiffPatchInputFilesMismatched}] Input file size mismatched! Expecting: {expectingSize} bytes but got: {expectingSize} bytes instead."); + public static InvalidDataException ThrowHDiffCompLZMAPropertyMissing() + => new($"[{Const.HDiffCompLZMAPropertyMissing}] The LZMA stream is missing its properties."); + public static InvalidDataException ThrowHDiffCompLZMA2DictionaryInvalid(int property) + => new($"[{Const.HDiffCompLZMA2DictionaryInvalid}] The LZMA2 dictionary property must be at most 40, but was {property}."); + public static InvalidDataException ThrowHDiffCompLZMA2NoCompressedPayload() + => new($"[{Const.HDiffCompLZMA2NoCompressedPayload}] The LZMA2 stream has no compressed payload."); + public static InvalidDataException ThrowHDiffCompLZMADictionaryInvalidLength(int lzmaPropertySize, int property) + => new($"[{Const.HDiffCompLZMADictionaryInvalidLength}] The LZMA property length must be {lzmaPropertySize}, but was {property}."); + public static InvalidDataException ThrowHDiffCompLZMASizeTooSmallForDictionaryRead() + => new($"[{Const.HDiffCompLZMASizeTooSmallForDictionaryRead}] The LZMA compressed size is too small to contain its headers and payload."); + public static int TryGetReturnCodeFromError(Exception? ex) { diff --git a/SharpHPatchZ/Extension/StreamExtension.cs b/SharpHPatchZ/Extension/StreamExtension.cs index 2777195..e9a1589 100644 --- a/SharpHPatchZ/Extension/StreamExtension.cs +++ b/SharpHPatchZ/Extension/StreamExtension.cs @@ -22,6 +22,18 @@ public async ValueTask ReadExactlyAsync( } #endif + public void ReadExactly( + byte[] buffer, + int offset, + int count) + { +#if !NET6_0_OR_GREATER + _ = stream.ReadAtLeast(buffer, offset, count, count, true); +#else + _ = stream.ReadAtLeast(buffer.AsSpan(offset, count), count, true); +#endif + } + public async ValueTask ReadExactlyAsync( byte[] buffer, int offset, @@ -37,6 +49,30 @@ public async ValueTask ReadExactlyAsync( } #if !NET6_0_OR_GREATER + public int ReadAtLeast( + byte[] buffer, + int offset, + int count, + int minimumBytes, + bool throwOnEndOfStream = false) + { + Debug.Assert(minimumBytes <= buffer.Length); + + int totalRead = offset; + while (totalRead < minimumBytes) + { + int read = stream.Read(buffer, totalRead, count - totalRead); + if (read == 0) + { + return throwOnEndOfStream ? throw new EndOfStreamException() : totalRead; + } + + totalRead += read; + } + + return totalRead; + } + public async ValueTask ReadAtLeastAsync( byte[] buffer, int offset, @@ -62,6 +98,28 @@ public async ValueTask ReadAtLeastAsync( return totalRead; } #else + public int ReadAtLeast( + Span buffer, + int minimumBytes, + bool throwOnEndOfStream = false) + { + Debug.Assert(minimumBytes <= buffer.Length); + + int totalRead = 0; + while (totalRead < minimumBytes) + { + int read = stream.Read(buffer[totalRead..]); + if (read == 0) + { + return throwOnEndOfStream ? throw new EndOfStreamException() : totalRead; + } + + totalRead += read; + } + + return totalRead; + } + public async ValueTask ReadAtLeastAsync( Memory buffer, int minimumBytes, diff --git a/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs b/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs index 27283fb..6ebb8ad 100644 --- a/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs +++ b/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs @@ -11,7 +11,7 @@ using System; using System.IO; using System.IO.Compression; -using System.Runtime.InteropServices; +using SharpHPatchZ.Extension; using SharpHPatchZ.Header; using SharpHPatchZ.IO.Compression.BZip2; using SharpHPatchZ.IO.Compression.Lzma; @@ -31,13 +31,21 @@ namespace SharpHPatchZ.IO.Compression; internal interface IDecompressor { - Stream CreateDecompressionStream(Stream sourceStream, bool leaveOpen); + Stream CreateDecompressionStream( + Stream sourceStream, + long compressedSize, + long decompressedSize, + bool leaveOpen); } internal readonly struct HDiffDecompressor(HDiffCompression type) : IDecompressor { - public Stream CreateDecompressionStream(Stream sourceStream, bool leaveOpen) - => DecompressStreamFactory.Create(type, sourceStream, leaveOpen); + public Stream CreateDecompressionStream( + Stream sourceStream, + long compressedSize, + long decompressedSize, + bool leaveOpen) + => DecompressStreamFactory.Create(type, sourceStream, leaveOpen, compressedSize, decompressedSize); } internal static class DecompressStreamFactory @@ -48,17 +56,29 @@ internal static class DecompressStreamFactory internal static Stream Create(HDiffCompression type, Stream sourceStream, - bool leaveOpen) - => type switch + bool leaveOpen, + long compressedSize = -1, + long decompressedSize = -1) + { + if (compressedSize < -1) + throw new ArgumentOutOfRangeException(nameof(compressedSize)); + + if (decompressedSize < -1) + throw new ArgumentOutOfRangeException(nameof(decompressedSize)); + + if (type == HDiffCompression.Uncompressed || compressedSize == 0) + return sourceStream; + + return type switch { - HDiffCompression.Uncompressed => sourceStream, HDiffCompression.Zstd => CreateZstdStream(sourceStream, leaveOpen), HDiffCompression.Zlib => new DeflateStream(sourceStream, CompressionMode.Decompress, leaveOpen), HDiffCompression.BZ2 => new BZip2InputStream(sourceStream, false, leaveOpen), HDiffCompression.PBZ2 => new BZip2InputStream(sourceStream, true, leaveOpen), - HDiffCompression.Lzma or HDiffCompression.Lzma2 => CreateLzmaStream(sourceStream, leaveOpen), - _ => throw new NotSupportedException($"[PatchCore::GetDecompressStreamPlugin] Compression Type: {type} is not supported") + HDiffCompression.Lzma or HDiffCompression.Lzma2 => CreateLzmaStream(type, sourceStream, compressedSize, decompressedSize, leaveOpen), + _ => throw ExceptionHelper.ThrowHDiffHeaderCompressionNotSupported(type.ToString()) }; + } private static Stream CreateZstdStream(Stream rawStream, bool leaveOpen) { @@ -96,15 +116,39 @@ private static Stream CreateZstdManagedStream(Stream rawStream, bool leaveOpen) return new ZstdManagedStream(rawStream, decompressor, 16 << 10, leaveOpen: leaveOpen); } - private static Stream CreateLzmaStream(Stream rawStream, bool leaveOpen) + private static Stream CreateLzmaStream( + HDiffCompression type, + Stream rawStream, + long compressedSize, + long decompressedSize, + bool leaveOpen) { - int propLen = rawStream.ReadByte(); - if (propLen != 5) return new LzmaInputStream([(byte)propLen], rawStream, leaveOpen); // Get LZMA2 if propLen != 5 - - // Get LZMA if propLen == 5 - byte[] props = new byte[propLen]; - _ = rawStream.Read(props, 0, propLen); - int dicSize = MemoryMarshal.Read(props.AsSpan(1)); - return new LzmaInputStream(props, rawStream, -1, -1, rawStream, false, leaveOpen); + int property = rawStream.ReadByte(); + if (property < 0) + throw ExceptionHelper.ThrowHDiffCompLZMAPropertyMissing(); + + long payloadSize = compressedSize >= 0 ? compressedSize - 1 : -1; + if (type == HDiffCompression.Lzma2) + { + if (property > 40) + throw ExceptionHelper.ThrowHDiffCompLZMA2DictionaryInvalid(property); + return payloadSize == 0 + ? throw ExceptionHelper.ThrowHDiffCompLZMA2NoCompressedPayload() + : new LzmaInputStream([(byte)property], rawStream, payloadSize, decompressedSize, leaveOpen); + } + + const int lzmaPropertySize = 5; + if (property != lzmaPropertySize) + throw ExceptionHelper.ThrowHDiffCompLZMADictionaryInvalidLength(lzmaPropertySize, property); + + const int rangeDecoderHeaderSize = 5; + if (compressedSize is >= 0 and < 1 + lzmaPropertySize + rangeDecoderHeaderSize) + throw ExceptionHelper.ThrowHDiffCompLZMASizeTooSmallForDictionaryRead(); + + byte[] properties = new byte[lzmaPropertySize]; + rawStream.ReadExactly(properties, 0, properties.Length); + payloadSize = compressedSize >= 0 ? compressedSize - 1 - properties.Length : -1; + + return new LzmaInputStream(properties, rawStream, payloadSize, decompressedSize, leaveOpen); } } diff --git a/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs b/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs index 0a4b67c..e9e8153 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs @@ -15,7 +15,7 @@ public sealed class LzmaInputStream : Stream private readonly int _dictionarySize; private readonly OutWindow _outWindow = new(); private readonly RangeDecoder _rangeDecoder = new(); - private Decoder _decoder; + private Decoder? _decoder; private long _position; private bool _endReached; @@ -113,7 +113,7 @@ protected override void Dispose(bool disposing) if (disposing && !_leaveOpen) { - _inputStream?.Dispose(); + _inputStream.Dispose(); } base.Dispose(disposing); } @@ -133,6 +133,11 @@ public override int Read(byte[] buffer, int offset, int count) return 0; } + if (_decoder == null) + { + throw new NullReferenceException("Decoder is null"); + } + int total = 0; while (total < count) { diff --git a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs index 5c0558d..4278e4e 100644 --- a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs +++ b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs @@ -24,9 +24,10 @@ public static HDiff13DerivedPatcher Create( out long rleCtrlDataOffset, out long rleCodeDataOffset, out long newDataOffset); - + PatchMetadata patchMetadata = info.GetPatchMetadata(); DiffReadersContext context = CreateReaderContext(info.CompressionType, options, + patchMetadata, createPatchStream(coverDataOffset), createPatchStream(rleCtrlDataOffset), createPatchStream(rleCodeDataOffset), @@ -53,9 +54,10 @@ public static async Task CreateAsync( out long rleCtrlDataOffset, out long rleCodeDataOffset, out long newDataOffset); - + PatchMetadata patchMetadata = info.GetPatchMetadata(); DiffReadersContext context = CreateReaderContext(info.CompressionType, options, + patchMetadata, await createPatchStreamAsync(coverDataOffset, token), await createPatchStreamAsync(rleCtrlDataOffset, token), await createPatchStreamAsync(rleCodeDataOffset, token), @@ -70,19 +72,20 @@ await createPatchStreamAsync(rleCodeDataOffset, token), progressCallback); } - private static DiffReadersContext CreateReaderContext(HDiffCompression compType, - PatchOptions options, - ValueTuple coverCtx, - ValueTuple rleCtrlCtx, - ValueTuple rleCodeCtx, - ValueTuple newDataCtx) + private static unsafe DiffReadersContext CreateReaderContext(HDiffCompression compType, + PatchOptions options, + PatchMetadata patchMetadata, + ValueTuple coverCtx, + ValueTuple rleCtrlCtx, + ValueTuple rleCodeCtx, + ValueTuple newDataCtx) { int bufferSize = options.ReaderBufferSize; - Stream decCoverStream = DecompressStreamFactory.Create(compType, coverCtx.Item1, coverCtx.Item2); - Stream decRleControlStream = DecompressStreamFactory.Create(compType, rleCtrlCtx.Item1, rleCtrlCtx.Item2); - Stream decRleCodeStream = DecompressStreamFactory.Create(compType, rleCodeCtx.Item1, rleCodeCtx.Item2); - Stream decNewDataStream = DecompressStreamFactory.Create(compType, newDataCtx.Item1, newDataCtx.Item2); + Stream decCoverStream = CreateDecompressionStream(compType, *patchMetadata.CoverDataSizeP, coverCtx); + Stream decRleControlStream = CreateDecompressionStream(compType, *patchMetadata.RleControlDataSizeP, rleCtrlCtx); + Stream decRleCodeStream = CreateDecompressionStream(compType, *patchMetadata.RleCodeDataSizeP, rleCodeCtx); + Stream decNewDataStream = CreateDecompressionStream(compType, *patchMetadata.NewDiffDataSizeP, newDataCtx); BittableStreamReader coverReader = new(decCoverStream, bufferSize, coverCtx.Item2); BittableStreamReader rleCtrlReader = new(decRleControlStream, bufferSize, rleCtrlCtx.Item2); @@ -92,6 +95,17 @@ private static DiffReadersContext CreateReaderContext(HDiffCompression c return new DiffReadersContext(coverReader, rleCtrlReader, rleCodeReader, newDataReader); } + private static Stream CreateDecompressionStream( + HDiffCompression compType, + ChunkSizeInfo size, + ValueTuple streamContext) + => DecompressStreamFactory.Create( + compType, + streamContext.Item1, + streamContext.Item2, + size.CompressedSize, + size.Size); + private static unsafe void GetPatchContextInfos(ref HDiffInfo info, out long coverDataOffset, out long rleCtrlDataOffset, From 2a13db9a7d6600d7da6aa8bc5238f296f95e6bc2 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 23 Aug 2026 03:42:04 +0700 Subject: [PATCH 12/72] Update Test Use .NET Framework 4.7.2 for testing the lowest version of .NET to be supported --- Test/Program.cs | 7 ++++--- Test/Test.csproj | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Test/Program.cs b/Test/Program.cs index 6fe5f1c..283543c 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -13,6 +13,7 @@ public class Program private static string TestPathInput = @"G:\Hi3SEA"; private static string TestPathOutput = @"G:\Hi3CN-dotnet"; private static string TestPathPatch = @"G:\Hi3SEAtoCNExecOnly.lzma2.diff"; + private static string TestPathPatchLzma = @"G:\Hi3SEAtoCNExecOnly.lzma.diff"; private static string TestPathPatchNoComp = @"G:\Hi3SEAtoCNExecOnly.nocomp.diff"; public static async Task Main() { @@ -37,7 +38,7 @@ public static async Task Main() public static void WriteProgress(long totalProcessed, long totalSize, int written) { - Console.Write($"{totalProcessed} / {totalSize} {(int)(totalProcessed / (double)totalSize * 100)}%\r"); + // Console.Write($"{totalProcessed} / {totalSize} {(int)(totalProcessed / (double)totalSize * 100)}%\r"); } public static Stream CreateStream() @@ -48,14 +49,14 @@ public static Stream CreateStream() public static (Stream, bool) CreateStream(long position) { - FileStream stream = File.Open(TestPathPatch, FileMode.Open, FileAccess.Read, FileShare.Read); + FileStream stream = File.Open(TestPathPatchLzma, FileMode.Open, FileAccess.Read, FileShare.Read); stream.Position = position; return (stream, false); } public static ValueTask<(Stream, bool)> CreateStreamAsync(long position, CancellationToken token) { - FileStream stream = File.Open(TestPathPatch, FileMode.Open, FileAccess.Read, FileShare.Read); + FileStream stream = File.Open(TestPathPatchLzma, FileMode.Open, FileAccess.Read, FileShare.Read); stream.Position = position; return new ValueTask<(Stream, bool)>((stream, false)); } diff --git a/Test/Test.csproj b/Test/Test.csproj index 3abe44b..a54b2ff 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -2,7 +2,7 @@ Exe - net10.0 + net472 disable enable 14 From b762580a15f6c47540f42ec62af6bb8d6e5099a2 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 23 Aug 2026 03:42:20 +0700 Subject: [PATCH 13/72] Fix duplicate NuGet reference --- SharpHPatchZ/SharpHPatchZ.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/SharpHPatchZ/SharpHPatchZ.csproj b/SharpHPatchZ/SharpHPatchZ.csproj index 7d03ae8..ac8072c 100644 --- a/SharpHPatchZ/SharpHPatchZ.csproj +++ b/SharpHPatchZ/SharpHPatchZ.csproj @@ -39,7 +39,6 @@ - From 84f1b879227952025e9238615a986d0e3dd9b614 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 23 Aug 2026 03:42:35 +0700 Subject: [PATCH 14/72] Implement RleCoverInfo read --- SharpHPatchZ/Header/HeaderReader.cs | 4 +- SharpHPatchZ/Header/Metadata/PatchMetadata.cs | 4 +- .../IO/Reader/BittableStreamReader.cs | 12 ++- ...3DerivedPatcher.CopySimilarFilesContext.cs | 5 +- .../HDiff13DerivedPatcher.CorePatcher.cs | 17 ++++- SharpHPatchZ/Patch/RleCoverInfo.cs | 73 +++++++++++++++++++ 6 files changed, 105 insertions(+), 10 deletions(-) create mode 100644 SharpHPatchZ/Patch/RleCoverInfo.cs diff --git a/SharpHPatchZ/Header/HeaderReader.cs b/SharpHPatchZ/Header/HeaderReader.cs index 1c07616..8b538fe 100644 --- a/SharpHPatchZ/Header/HeaderReader.cs +++ b/SharpHPatchZ/Header/HeaderReader.cs @@ -367,7 +367,7 @@ private static unsafe void ReadHDiff13HeaderInfoCore( long newSize = streamReader.ReadLong7Bit(); long oldSize = streamReader.ReadLong7Bit(); - long coverDataCount = streamReader.ReadLong7Bit(); + int coverDataCount = (int)streamReader.ReadLong7Bit(); long coverDataSize = streamReader.ReadLong7Bit(); long coverDataSizeC = streamReader.ReadLong7Bit(); @@ -404,7 +404,7 @@ private static async Task ReadHDiff13HeaderInfoAsyncCore( long newSize = await streamReader.ReadLong7BitAsync(token); long oldSize = await streamReader.ReadLong7BitAsync(token); - long coverDataCount = await streamReader.ReadLong7BitAsync(token); + int coverDataCount = (int)await streamReader.ReadLong7BitAsync(token); long coverDataSize = await streamReader.ReadLong7BitAsync(token); long coverDataSizeC = await streamReader.ReadLong7BitAsync(token); diff --git a/SharpHPatchZ/Header/Metadata/PatchMetadata.cs b/SharpHPatchZ/Header/Metadata/PatchMetadata.cs index 30eff9a..2b92ce1 100644 --- a/SharpHPatchZ/Header/Metadata/PatchMetadata.cs +++ b/SharpHPatchZ/Header/Metadata/PatchMetadata.cs @@ -65,10 +65,10 @@ public bool IsDisposed public long DiffNewSize; public long DiffOldSize; - - public long CoverDataCount; public long DiffDataOffset; + public int CoverDataCount; + public ChunkSizeInfo* CoverDataSizeP; public ChunkSizeInfo* RleControlDataSizeP; public ChunkSizeInfo* RleCodeDataSizeP; diff --git a/SharpHPatchZ/IO/Reader/BittableStreamReader.cs b/SharpHPatchZ/IO/Reader/BittableStreamReader.cs index bd50449..fe0cfb2 100644 --- a/SharpHPatchZ/IO/Reader/BittableStreamReader.cs +++ b/SharpHPatchZ/IO/Reader/BittableStreamReader.cs @@ -14,6 +14,10 @@ internal sealed class BittableStreamReader , IAsyncDisposable #endif { + public const int KSignTagBit = 1; + public const int KByteRleType = 2; + + private const int DefaultBufferSize = 64 << 10; private const int MaxPackedUIntBytes = 11; @@ -124,7 +128,11 @@ public BittableStreamReader ContinueWithDecompressor( _leaveOpen); BoundedReadStream compressedStream = new(remainderStream, compressedLength); - Stream decompressedStream = decompressor.CreateDecompressionStream(compressedStream, leaveOpen: true); + Stream decompressedStream = decompressor.CreateDecompressionStream( + compressedStream, + compressedLength, + decompressedLength, + leaveOpen: true); Stream transitionStream = new DecompressionTransitionStream( decompressedStream, compressedStream, @@ -720,4 +728,4 @@ public ValueTask DisposeAsync() return _leaveOpen ? ValueTask.CompletedTask : BackedStream.DisposeAsync(); } #endif -} \ No newline at end of file +} diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs index abd0115..a36f849 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs @@ -1,6 +1,7 @@ using System.Buffers; using System.IO; using System.Threading; +using SharpHPatchZ.Extension; namespace SharpHPatchZ.Patch; @@ -24,7 +25,7 @@ public void RunCopy(PatcherBase patcher, int bufferSize = options.CopyBufferSize; if (bufferSize <= 0) bufferSize = 16 << 10; - byte[] buffer = ArrayPool.Shared.Rent(bufferSize); + byte[] buffer = BigArrayPool.Shared.Rent(bufferSize); try { int count = InputPaths.Length; @@ -52,7 +53,7 @@ public void RunCopy(PatcherBase patcher, } finally { - ArrayPool.Shared.Return(buffer); + BigArrayPool.Shared.Return(buffer); } } } diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs index 0a5f4ce..5d5825d 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs @@ -1,11 +1,24 @@ -using System.Threading; +using System; +using System.Threading; +using SharpHPatchZ.Extension; namespace SharpHPatchZ.Patch; internal sealed partial class HDiff13DerivedPatcher { - private unsafe void StartCorePatcher(CancellationToken token) + private void StartCorePatcher(CancellationToken token) { + ReadOnlySpan rleCoverSpan = RleCoverInfo.Read(_coverReader, + Info, + out RleCoverInfo[] rleCoverBackedBuffer, + token); + try + { + } + finally + { + BigArrayPool.Shared.Return(rleCoverBackedBuffer); + } } } diff --git a/SharpHPatchZ/Patch/RleCoverInfo.cs b/SharpHPatchZ/Patch/RleCoverInfo.cs new file mode 100644 index 0000000..893eed4 --- /dev/null +++ b/SharpHPatchZ/Patch/RleCoverInfo.cs @@ -0,0 +1,73 @@ +using SharpHPatchZ.Extension; +using SharpHPatchZ.Header; +using SharpHPatchZ.Header.Metadata; +using SharpHPatchZ.IO.Reader; +using System; +using System.Runtime.InteropServices; +using System.Threading; + +namespace SharpHPatchZ.Patch; + +[StructLayout(LayoutKind.Sequential)] +internal struct RleCoverInfo +{ + public long OldStreamPosition; + public long NewStreamPosition; + public long RleLength; + public long CopyLength; + + public RleCoverInfo() { } + + public RleCoverInfo(long oldStreamPosition, + long newStreamPosition, + long rleLength, + long copyLength) + { + OldStreamPosition = oldStreamPosition; + NewStreamPosition = newStreamPosition; + RleLength = rleLength; + CopyLength = copyLength; + } + + internal static Span Read(BittableStreamReader reader, + HDiffInfo info, + out RleCoverInfo[] backedBuffer, + CancellationToken token) + { + ref PatchMetadata patchMetadata = ref info.GetPatchMetadata(); + + int rleCoverCount = patchMetadata.CoverDataCount; + backedBuffer = BigArrayPool.Shared.Rent(rleCoverCount); + + long lastOldPosBack = 0; + long lastNewPosBack = 0; + + for (int i = 0; i < rleCoverCount; i++) + { + long oldPosBack = lastOldPosBack; + long newPosBack = lastNewPosBack; + + long incOldPos = reader.ReadLong7Bit(BittableStreamReader.KSignTagBit); + + byte incOldPosSign = (byte)(reader.PreviousByte >> (8 - BittableStreamReader.KSignTagBit)); + long oldPos = incOldPosSign == 0 ? oldPosBack + incOldPos : oldPosBack - incOldPos; + + long copyLength = reader.ReadLong7Bit(); + long coverLength = reader.ReadLong7Bit(); + + oldPosBack = oldPos; + newPosBack += copyLength; + oldPosBack += coverLength; + + backedBuffer[i] = new RleCoverInfo(oldPos, newPosBack, coverLength, copyLength); + newPosBack += coverLength; + + lastOldPosBack = oldPosBack; + lastNewPosBack = newPosBack; + } + + return backedBuffer.AsSpan(0, rleCoverCount); + } + + public override string ToString() => $"RleLength: {RleLength} | CopyLength: {CopyLength} | OldPos: {OldStreamPosition} | NewPos: {NewStreamPosition}"; +} From 64b558ce1e79d530443fbe2841687497d58259a4 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 23 Aug 2026 19:33:45 +0700 Subject: [PATCH 15/72] Update HDiff13DerivedPatcher.CopySimilarFilesContext.cs --- .../Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs index a36f849..0f39cbd 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs @@ -1,5 +1,4 @@ -using System.Buffers; -using System.IO; +using System.IO; using System.Threading; using SharpHPatchZ.Extension; From 662369d63ca2a028625cbfc746d7b0506f3c429b Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 23 Aug 2026 21:29:16 +0700 Subject: [PATCH 16/72] Implement core patching --- SharpHPatchZ/Extension/StreamExtension.cs | 6 +- .../IO/Reader/RandomMergedStreamWrapper.cs | 43 +- .../HDiff13DerivedPatcher.CorePatcher.cs | 643 +++++++++++++++++- SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs | 27 +- SharpHPatchZ/Patch/RleCoverInfo.cs | 2 + SharpHPatchZ/PatchOptions.cs | 14 +- Test/Program.cs | 13 +- Test/Test.csproj | 2 +- 8 files changed, 719 insertions(+), 31 deletions(-) diff --git a/SharpHPatchZ/Extension/StreamExtension.cs b/SharpHPatchZ/Extension/StreamExtension.cs index e9a1589..da840fc 100644 --- a/SharpHPatchZ/Extension/StreamExtension.cs +++ b/SharpHPatchZ/Extension/StreamExtension.cs @@ -204,10 +204,9 @@ public async ValueTask CreateUnmanagedInt64ListAsync(int count, Cancellati long[] array = ArrayPool.Shared.Rent(count); try { - long backNumber = -1; for (int i = 0; i < count; i++) { - array[i] = backNumber += 1 + await reader.ReadLong7BitAsync(token); + array[i] = await reader.ReadLong7BitAsync(token); } unsafe @@ -233,10 +232,9 @@ public async ValueTask CreateUnmanagedInt64ListAsync(int count, Cancellati UnmanagedArray* allocArray = UnmanagedArray.CreateAllocUnsafe(count); Span allocSpan = allocArray->GetSpan(); - long backNumber = -1; for (int i = 0; i < count; i++) { - allocSpan[i] = backNumber += 1 + reader.ReadLong7Bit(); + allocSpan[i] = reader.ReadLong7Bit(); } return allocArray; diff --git a/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs b/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs index 9f353ff..162c259 100644 --- a/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs +++ b/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs @@ -12,11 +12,14 @@ internal sealed class RandomMergedStreamWrapper : IDisposable private readonly ReaderWriterLockSlim _lifetimeLock = new(); private readonly long[] _fileStreamEnds; private readonly string[] _fileStreamPaths; + private readonly FileAccess _fileAccess; private int _disposed; - public long Length => _fileStreamEnds[^1]; + public long Length => _fileStreamEnds.Length == 0 ? 0 : _fileStreamEnds[^1]; - public RandomMergedStreamWrapper(string[] fileStreams, long[] fileStreamEnds) + public RandomMergedStreamWrapper(string[] fileStreams, + long[] fileStreamEnds, + bool createFiles = false) { if (fileStreams is null) { @@ -28,11 +31,6 @@ public RandomMergedStreamWrapper(string[] fileStreams, long[] fileStreamEnds) throw new ArgumentNullException(nameof(fileStreamEnds)); } - if (fileStreams.Length == 0) - { - throw new ArgumentException("At least one file is required.", nameof(fileStreams)); - } - if (fileStreams.Length != fileStreamEnds.Length) { throw new ArgumentException("The path and end-offset arrays must have the same length.", @@ -58,6 +56,12 @@ public RandomMergedStreamWrapper(string[] fileStreams, long[] fileStreamEnds) _fileStreamPaths = fileStreams; _fileStreamEnds = fileStreamEnds; + _fileAccess = createFiles ? FileAccess.ReadWrite : FileAccess.Read; + + if (createFiles) + { + CreateOutputFiles(); + } } public void Write(Span buffer, long offset) @@ -164,7 +168,7 @@ private FileStream GetFileStream(int streamIndex) index => new Lazy( () => new FileStream(_fileStreamPaths[index], FileMode.Open, - FileAccess.ReadWrite, + _fileAccess, FileShare.ReadWrite, bufferSize: 1, FileOptions.RandomAccess), @@ -173,6 +177,29 @@ private FileStream GetFileStream(int streamIndex) return lazyStream.Value; } + private void CreateOutputFiles() + { + long streamStart = 0; + for (int index = 0; index < _fileStreamPaths.Length; index++) + { + string path = _fileStreamPaths[index]; + string? directoryPath = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(directoryPath)) + { + Directory.CreateDirectory(directoryPath); + } + + using FileStream stream = new(path, + FileMode.Create, + FileAccess.ReadWrite, + FileShare.ReadWrite, + bufferSize: 1, + FileOptions.RandomAccess); + stream.SetLength(_fileStreamEnds[index] - streamStart); + streamStart = _fileStreamEnds[index]; + } + } + private int FindStreamIndex(long offset) { int low = 0; diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs index 5d5825d..d0670f4 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs @@ -1,12 +1,28 @@ -using System; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +#if NET6_0_OR_GREATER +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +#endif +using System.Runtime.ExceptionServices; using System.Threading; +using System.Threading.Tasks; using SharpHPatchZ.Extension; +using SharpHPatchZ.Header.Metadata; +using SharpHPatchZ.IO.Reader; +// ReSharper disable AccessToDisposedClosure namespace SharpHPatchZ.Patch; internal sealed partial class HDiff13DerivedPatcher { - private void StartCorePatcher(CancellationToken token) + private const int DefaultPatchBufferSize = 1 << 20; + + private unsafe void StartCorePatcher(CancellationToken token) { ReadOnlySpan rleCoverSpan = RleCoverInfo.Read(_coverReader, Info, @@ -14,11 +30,634 @@ private void StartCorePatcher(CancellationToken token) token); try { + if (InputStream is null || OutputStream is null) + { + throw new InvalidOperationException("The patch input and output streams have not been initialized."); + } + + PatchMetadata patchMetadata = Info.GetPatchMetadata(); + ValidateReaderOffset(_coverReader, + patchMetadata.CoverDataSizeP->Size, + "cover"); + + int bufferSize = Options.PatchWorkerBufferSize > 0 + ? Options.PatchWorkerBufferSize + : DefaultPatchBufferSize; + int workerCount = GetWorkerCount(Options.ParallelThreads); + if (workerCount == 1) + { + RunSequential(rleCoverSpan, patchMetadata, bufferSize, token); + } + else + { + RunParallel(rleCoverBackedBuffer, + rleCoverSpan.Length, + patchMetadata, + bufferSize, + workerCount, + token); + } } finally { BigArrayPool.Shared.Return(rleCoverBackedBuffer); } } + + private static int GetWorkerCount(uint requestedWorkerCount) + { + if (requestedWorkerCount == 0) + { + return Math.Max(1, Environment.ProcessorCount); + } + + if (requestedWorkerCount > int.MaxValue) + { + throw new ArgumentOutOfRangeException(nameof(PatchOptions.ParallelThreads)); + } + + return (int)requestedWorkerCount; + } + + private void RunSequential(ReadOnlySpan covers, + PatchMetadata patchMetadata, + int bufferSize, + CancellationToken token) + { + byte[] oldBuffer = BigArrayPool.Shared.Rent(bufferSize); + try + { + ProduceWork(covers, + patchMetadata.DiffNewSize, + bufferSize, + item => ProcessWorkItem(item, oldBuffer, token), + token); + ValidateDataReaders(patchMetadata); + } + finally + { + BigArrayPool.Shared.Return(oldBuffer); + } + } + + private void RunParallel(RleCoverInfo[] covers, + int coverCount, + PatchMetadata patchMetadata, + int bufferSize, + int workerCount, + CancellationToken token) + { + int queueCapacity = workerCount > int.MaxValue / 2 + ? int.MaxValue + : workerCount * 2; + + using CancellationTokenSource linkedCancellation = + CancellationTokenSource.CreateLinkedTokenSource(token); + using BlockingCollection workQueue = new(queueCapacity); + + ExceptionDispatchInfo? producerFailure = null; + ExceptionDispatchInfo? workerFailure = null; + ExceptionDispatchInfo? parallelFailure = null; + + Task producer = Task.Factory.StartNew( + () => + { + try + { + ProduceWork(covers.AsSpan(0, coverCount), + patchMetadata.DiffNewSize, + bufferSize, + item => AddWorkItem(workQueue, item, linkedCancellation.Token), + linkedCancellation.Token); + ValidateDataReaders(patchMetadata); + } + catch (Exception exception) + { + producerFailure = ExceptionDispatchInfo.Capture(exception); + linkedCancellation.Cancel(); + } + finally + { + workQueue.CompleteAdding(); + } + }, + CancellationToken.None, + TaskCreationOptions.LongRunning, + TaskScheduler.Default); + + try + { + Parallel.ForEach( + workQueue.GetConsumingEnumerable(linkedCancellation.Token), + new ParallelOptions + { + CancellationToken = linkedCancellation.Token, + MaxDegreeOfParallelism = workerCount + }, + () => BigArrayPool.Shared.Rent(bufferSize), + (item, _, oldBuffer) => + { + try + { + ProcessWorkItem(item, oldBuffer, linkedCancellation.Token); + } + catch (Exception exception) + { + Interlocked.CompareExchange( + ref workerFailure, + ExceptionDispatchInfo.Capture(exception), + null); + linkedCancellation.Cancel(); + throw; + } + + return oldBuffer; + }, + oldBuffer => BigArrayPool.Shared.Return(oldBuffer)); + } + catch (Exception exception) + { + parallelFailure = ExceptionDispatchInfo.Capture(exception); + linkedCancellation.Cancel(); + } + finally + { + producer.GetAwaiter().GetResult(); + + while (workQueue.TryTake(out PatchWorkItem abandonedItem)) + { + BigArrayPool.Shared.Return(abandonedItem.Buffer); + } + } + + // A real producer error is more useful than the cancellation observed by + // workers after the producer stopped. Conversely, a worker error takes + // precedence when cancellation is all the producer observed. + if (producerFailure?.SourceException is not OperationCanceledException) + { + producerFailure?.Throw(); + } + + workerFailure?.Throw(); + producerFailure?.Throw(); + parallelFailure?.Throw(); + } + + private static void AddWorkItem(BlockingCollection queue, + PatchWorkItem item, + CancellationToken token) + { + try + { + queue.Add(item, token); + } + catch + { + BigArrayPool.Shared.Return(item.Buffer); + throw; + } + } + + private void ProduceWork(ReadOnlySpan covers, + long newDataSize, + int bufferSize, + Action emit, + CancellationToken token) + { + RleDecoder rleDecoder = new(_rleCtrlReader, _rleCodeReader); + byte[] skipBuffer = BigArrayPool.Shared.Rent(Math.Min(bufferSize, 64 << 10)); + using PatchWorkBuilder workBuilder = new(bufferSize, emit); + try + { + long newPosition = 0; + for (int coverIndex = 0; coverIndex < covers.Length; coverIndex++) + { + token.ThrowIfCancellationRequested(); + ref readonly RleCoverInfo cover = ref covers[coverIndex]; + ValidateCover(cover, newPosition, newDataSize, InputStream!.Length); + + ProduceNewData(cover.CopyLength, + ref newPosition, + rleDecoder, + skipBuffer, + workBuilder, + token); + ProduceCover(cover, + ref newPosition, + rleDecoder, + workBuilder, + token); + } + + ProduceNewData(newDataSize - newPosition, + ref newPosition, + rleDecoder, + skipBuffer, + workBuilder, + token); + + if (newPosition != newDataSize || rleDecoder.HasPendingData) + { + throw new InvalidDataException("The decoded patch data does not match the declared output size."); + } + + workBuilder.Flush(); + } + finally + { + BigArrayPool.Shared.Return(skipBuffer); + } + } + + private void ProduceNewData(long length, + ref long newPosition, + RleDecoder rleDecoder, + byte[] skipBuffer, + PatchWorkBuilder workBuilder, + CancellationToken token) + { + while (length > 0) + { + token.ThrowIfCancellationRequested(); + Span destination = workBuilder.GetWritableSpan(newPosition, + length, + out int step); + _newDataReader.ReadBytes(destination); + rleDecoder.Skip(step, skipBuffer, token); + workBuilder.CommitNewData(step); + + newPosition += step; + length -= step; + } + } + + private static void ProduceCover(RleCoverInfo cover, + ref long newPosition, + RleDecoder rleDecoder, + PatchWorkBuilder workBuilder, + CancellationToken token) + { + long coverOffset = 0; + while (coverOffset < cover.RleLength) + { + token.ThrowIfCancellationRequested(); + Span destination = workBuilder.GetWritableSpan( + newPosition, + cover.RleLength - coverOffset, + out int step); + rleDecoder.Decode(destination, token); + workBuilder.CommitCover(step, cover.OldStreamPosition + coverOffset); + + newPosition += step; + coverOffset += step; + } + } + + private void ProcessWorkItem(PatchWorkItem item, + byte[] oldBuffer, + CancellationToken token) + { + try + { + token.ThrowIfCancellationRequested(); + if (item.CoverSegments is { } coverSegments) + { + for (int segmentIndex = 0; segmentIndex < coverSegments.Count; segmentIndex++) + { + token.ThrowIfCancellationRequested(); + CoverSegment segment = coverSegments[segmentIndex]; + Span oldData = oldBuffer.AsSpan(0, segment.Length); + int read = InputStream!.Read(oldData, segment.OldPosition); + if (read != segment.Length) + { + throw new EndOfStreamException("The old-data stream ended while processing a cover."); + } + +#if NET6_0_OR_GREATER + AddRle(oldBuffer, + item.Buffer, + segment.BufferOffset, + segment.Length, + Options.UseSIMD); +#else + AddRle(oldBuffer, + item.Buffer, + segment.BufferOffset, + segment.Length); +#endif + oldData.CopyTo(item.Buffer.AsSpan(segment.BufferOffset, segment.Length)); + } + } + + OutputStream!.Write(item.Buffer.AsSpan(0, item.Length), item.OutputPosition); + AdvanceProgress(item.Length); + } + finally + { + BigArrayPool.Shared.Return(item.Buffer); + } + } + +#if NET6_0_OR_GREATER + private static void AddRle(byte[] destination, + byte[] rle, + int rleOffset, + int length, + bool useSimd) +#else + private static void AddRle(byte[] destination, + byte[] rle, + int rleOffset, + int length) +#endif + { + int index = 0; +#if NET6_0_OR_GREATER + if (useSimd && Avx2.IsSupported) + { + const int vectorLength = 32; + int vectorEnd = length - length % vectorLength; + if (vectorEnd != 0) + { + ref byte destinationRef = ref destination[0]; + ref byte rleRef = ref rle[rleOffset]; + for (; index < vectorEnd; index += vectorLength) + { + var oldVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref destinationRef, index)); + var rleVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref rleRef, index)); + Vector256 result = Avx2.Add(oldVector, rleVector); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref destinationRef, index), result); + } + } + } + else if (useSimd && Sse2.IsSupported) + { + const int vectorLength = 16; + int vectorEnd = length - length % vectorLength; + if (vectorEnd != 0) + { + ref byte destinationRef = ref destination[0]; + ref byte rleRef = ref rle[rleOffset]; + for (; index < vectorEnd; index += vectorLength) + { + var oldVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref destinationRef, index)); + var rleVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref rleRef, index)); + Vector128 result = Sse2.Add(oldVector, rleVector); + Unsafe.WriteUnaligned(ref Unsafe.Add(ref destinationRef, index), result); + } + } + } + else if (useSimd && Vector.IsHardwareAccelerated) + { + int vectorLength = Vector.Count; + int vectorEnd = length - length % vectorLength; + for (; index < vectorEnd; index += vectorLength) + { + Vector oldVector = new(destination, index); + Vector rleVector = new(rle, rleOffset + index); + (oldVector + rleVector).CopyTo(destination, index); + } + } +#endif + for (; index < length; index++) + { + destination[index] = unchecked((byte)(destination[index] + rle[rleOffset + index])); + } + } + + private static void ValidateCover(RleCoverInfo cover, + long expectedNewPosition, + long newDataSize, + long oldDataSize) + { + if (cover.CopyLength < 0 || cover.RleLength < 0 || cover.OldStreamPosition < 0 || + cover.NewStreamPosition < expectedNewPosition || + cover.CopyLength != cover.NewStreamPosition - expectedNewPosition || + cover.NewStreamPosition > newDataSize || + cover.RleLength > newDataSize - cover.NewStreamPosition || + cover.OldStreamPosition > oldDataSize || + cover.RleLength > oldDataSize - cover.OldStreamPosition) + { + throw new InvalidDataException("A patch cover is outside the declared old or new data bounds."); + } + } + + private unsafe void ValidateDataReaders(PatchMetadata patchMetadata) + { + ValidateReaderOffset(_rleCtrlReader, patchMetadata.RleControlDataSizeP->Size, "RLE control"); + ValidateReaderOffset(_rleCodeReader, patchMetadata.RleCodeDataSizeP->Size, "RLE code"); + ValidateReaderOffset(_newDataReader, patchMetadata.NewDiffDataSizeP->Size, "new-data"); + } + + private static void ValidateReaderOffset(BittableStreamReader reader, + long expectedOffset, + string dataName) + { + if (reader.Offset != expectedOffset) + { + throw new InvalidDataException( + $"The consumed {dataName} size ({reader.Offset}) does not match its declared size ({expectedOffset})."); + } + } + + private readonly struct PatchWorkItem(byte[] buffer, + int length, + long outputPosition, + List? coverSegments) + { + public byte[] Buffer { get; } = buffer; + public int Length { get; } = length; + public long OutputPosition { get; } = outputPosition; + public List? CoverSegments { get; } = coverSegments; + } + + private readonly struct CoverSegment(int bufferOffset, + int length, + long oldPosition) + { + public int BufferOffset { get; } = bufferOffset; + public int Length { get; } = length; + public long OldPosition { get; } = oldPosition; + } + + private sealed class PatchWorkBuilder(int bufferSize, + Action emit) : IDisposable + { + private readonly int _bufferSize = bufferSize; + private readonly Action _emit = emit; + + private byte[]? _buffer; + private int _length; + private long _outputPosition; + private List? _coverSegments; + + public Span GetWritableSpan(long outputPosition, + long requestedLength, + out int writableLength) + { + if (_buffer is not null && _length == _bufferSize) + { + Flush(); + } + + if (_buffer is null) + { + _buffer = BigArrayPool.Shared.Rent(_bufferSize); + _outputPosition = outputPosition; + } + else if (outputPosition != _outputPosition + _length) + { + throw new InvalidOperationException("Patch batches must contain contiguous output ranges."); + } + + writableLength = (int)Math.Min(requestedLength, _bufferSize - _length); + return _buffer.AsSpan(_length, writableLength); + } + + public void CommitNewData(int length) + => _length += length; + + public void CommitCover(int length, long oldPosition) + { + _coverSegments ??= []; + + int segmentCount = _coverSegments.Count; + if (segmentCount > 0) + { + CoverSegment previous = _coverSegments[segmentCount - 1]; + if (previous.BufferOffset + previous.Length == _length && + previous.OldPosition + previous.Length == oldPosition) + { + _coverSegments[segmentCount - 1] = new CoverSegment(previous.BufferOffset, + previous.Length + length, + previous.OldPosition); + _length += length; + return; + } + } + + _coverSegments.Add(new CoverSegment(_length, length, oldPosition)); + _length += length; + } + + public void Flush() + { + if (_buffer is null || _length == 0) + { + return; + } + + PatchWorkItem item = new(_buffer, + _length, + _outputPosition, + _coverSegments); + _buffer = null; + _length = 0; + _coverSegments = null; + _emit(item); + } + + public void Dispose() + { + if (_buffer is not null) + { + BigArrayPool.Shared.Return(_buffer); + _buffer = null; + } + } + } + + private sealed class RleDecoder(BittableStreamReader controlReader, + BittableStreamReader codeReader) + { + private readonly BittableStreamReader _controlReader = controlReader; + private readonly BittableStreamReader _codeReader = codeReader; + + private long _remaining; + private byte _type; + private byte _value; + + public bool HasPendingData => _remaining != 0; + + public void Decode(Span destination, CancellationToken token) + { + while (!destination.IsEmpty) + { + token.ThrowIfCancellationRequested(); + EnsureRun(); + + int step = (int)Math.Min(_remaining, destination.Length); + Span target = destination[..step]; + switch (_type) + { + case 0: + target.Clear(); + break; + case 1: + target.Fill(byte.MaxValue); + break; + case 2: + target.Fill(_value); + break; + case 3: + _codeReader.ReadBytes(target); + break; + default: + throw new InvalidDataException("The RLE control stream contains an unknown run type."); + } + + _remaining -= step; + destination = destination[step..]; + } + } + + public void Skip(long length, byte[] scratchBuffer, CancellationToken token) + { + while (length > 0) + { + token.ThrowIfCancellationRequested(); + EnsureRun(); + + long step = Math.Min(_remaining, length); + if (_type == 3) + { + long rawRemaining = step; + while (rawRemaining > 0) + { + int readLength = (int)Math.Min(rawRemaining, scratchBuffer.Length); + _codeReader.ReadBytes(scratchBuffer.AsSpan(0, readLength)); + rawRemaining -= readLength; + } + } + + _remaining -= step; + length -= step; + } + } + + private void EnsureRun() + { + if (_remaining != 0) + { + return; + } + + byte firstByte = _controlReader.ReadByte(); + _type = (byte)(firstByte >> (8 - BittableStreamReader.KByteRleType)); + + long encodedLength = _controlReader.ReadLong7Bit(BittableStreamReader.KByteRleType, + firstByte); + if (encodedLength == long.MaxValue) + { + throw new InvalidDataException("An RLE run length exceeds the supported range."); + } + + _remaining = encodedLength + 1; + if (_type == 2) + { + _value = _codeReader.ReadByte(); + } + } + } } diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs index ee9e2a1..69f5173 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs @@ -104,7 +104,9 @@ private unsafe void InitializeInputOutputStream(string inputPath, string outputP inputFile.FullName, inputFile.Length, patchMetadata.DiffOldSize); InputStream = new RandomMergedStreamWrapper([inputFile.FullName], [inputFile.Length]); - OutputStream = new RandomMergedStreamWrapper([outputFile.FullName], [patchMetadata.DiffNewSize]); + OutputStream = new RandomMergedStreamWrapper([outputFile.FullName], + [patchMetadata.DiffNewSize], + createFiles: true); return; } @@ -117,6 +119,11 @@ private unsafe void InitializeInputOutputStream(string inputPath, string outputP ref DirectoryPatchMetadata dirMetadata = ref Info.MetadataAs(); if (Unsafe.IsNullRef(ref dirMetadata)) throw ExceptionHelper.ThrowHDiffInfoDirectoryPatchMetadataNotAllocated(); + // Directory progress includes both the core/reference output and files + // copied unchanged from the input tree. + TotalSize = checked(dirMetadata.OutputPathCountSizeInfoP->Size + + dirMetadata.SameFilePathCountSizeInfoP->Size); + // All input and output paths Utf16UnmanagedString[] allInputPaths = CopyToManagedStringList(dirMetadata.InputPathListP); Utf16UnmanagedString[] allOutputPaths = CopyToManagedStringList(dirMetadata.OutputPathListP); @@ -132,8 +139,8 @@ private unsafe void InitializeInputOutputStream(string inputPath, string outputP long[] refInputFilesSize = new long[refInputCount]; int refOutputCount = dirMetadata.OutputFileIndexListP->Length; - string[] refOutputFiles = new string[refInputCount]; - long[] refOutputFilesSize = new long[refInputCount]; + string[] refOutputFiles = new string[refOutputCount]; + long[] refOutputFilesSize = new long[refOutputCount]; // -- Reference Input Span refInputFileIndexSpan = dirMetadata.InputFileIndexListP->GetSpan(); @@ -161,17 +168,27 @@ private unsafe void InitializeInputOutputStream(string inputPath, string outputP Span refOutputFileIndexSpan = dirMetadata.OutputFileIndexListP->GetSpan(); Span refOutputFileSizeSpan = dirMetadata.OutputFileSizeListP->GetSpan(); + long outputSize = 0; for (int i = 0; i < refOutputCount; i++) { int fileIndex = refOutputFileIndexSpan[i]; long fileSize = refOutputFileSizeSpan[i]; refOutputFiles[i] = Path.GetFullPath(Path.Combine(outputDir.FullName, allOutputPaths[fileIndex])); - refOutputFilesSize[i] = fileSize; + outputSize += fileSize; + refOutputFilesSize[i] = outputSize; + } + + if (outputSize != patchMetadata.DiffNewSize) + { + throw new InvalidDataException( + $"The reference output size ({outputSize}) does not match the patch output size ({patchMetadata.DiffNewSize})."); } InputStream = new RandomMergedStreamWrapper(refInputFiles, refInputFilesSize); - OutputStream = new RandomMergedStreamWrapper(refOutputFiles, refOutputFilesSize); + OutputStream = new RandomMergedStreamWrapper(refOutputFiles, + refOutputFilesSize, + createFiles: true); _copySimilarFilesContext = new CopySimilarFilesContext(inputDir.FullName, similarInputFiles, outputDir.FullName, similarOutputFiles); } diff --git a/SharpHPatchZ/Patch/RleCoverInfo.cs b/SharpHPatchZ/Patch/RleCoverInfo.cs index 893eed4..3fceacd 100644 --- a/SharpHPatchZ/Patch/RleCoverInfo.cs +++ b/SharpHPatchZ/Patch/RleCoverInfo.cs @@ -44,6 +44,8 @@ internal static Span Read(BittableStreamReader reader, for (int i = 0; i < rleCoverCount; i++) { + token.ThrowIfCancellationRequested(); + long oldPosBack = lastOldPosBack; long newPosBack = lastNewPosBack; diff --git a/SharpHPatchZ/PatchOptions.cs b/SharpHPatchZ/PatchOptions.cs index 38864ba..4cb7a0b 100644 --- a/SharpHPatchZ/PatchOptions.cs +++ b/SharpHPatchZ/PatchOptions.cs @@ -5,8 +5,14 @@ namespace SharpHPatchZ; [StructLayout(LayoutKind.Sequential)] public struct PatchOptions() { - public uint ParallelThreads = 0; - public bool UseSIMD = true; - public int ReaderBufferSize = -1; - public int CopyBufferSize = -1; + public static readonly PatchOptions Default = new(); + +#if NET6_0_OR_GREATER + public bool UseSIMD = true; +#endif + + public uint ParallelThreads = 0; + public int ReaderBufferSize = 0; + public int CopyBufferSize = 0; + public int PatchWorkerBufferSize = 0; } diff --git a/Test/Program.cs b/Test/Program.cs index 283543c..4a49cf6 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using SharpHDiffPatch.Core; using SharpHPatchZ; using SharpHPatchZ.Header; @@ -22,23 +23,21 @@ public static async Task Main() // hPatchOld.Patch(TestPathInput, TestPathOutput, true); ProgressCallback progressCallback = ProgressCallback.CreateFromManaged(WriteProgress); + PatchOptions options = PatchOptions.Default; + Stopwatch sw = Stopwatch.StartNew(); using (HDiffInfo info1 = await HPatch.CreateInstanceAsync(CreateStreamAsync)) { - PatchResult result = await HPatch.PatchAsync(info1, CreateStreamAsync, TestPathInput, TestPathOutput, progressCallback: progressCallback); + PatchResult result = await HPatch.PatchAsync(info1, CreateStreamAsync, TestPathInput, TestPathOutput, options, progressCallback: progressCallback); } - Console.WriteLine(); - using (HDiffInfo info2 = HPatch.CreateInstance(CreateStream)) - { - PatchResult result = HPatch.Patch(info2, CreateStream, TestPathInput, TestPathOutput, progressCallback: progressCallback); - } Console.WriteLine(); + Console.WriteLine($"Completed in: {sw.ElapsedMilliseconds} ms"); } public static void WriteProgress(long totalProcessed, long totalSize, int written) { - // Console.Write($"{totalProcessed} / {totalSize} {(int)(totalProcessed / (double)totalSize * 100)}%\r"); + Console.Write($"{totalProcessed} / {totalSize} {(int)(totalProcessed / (double)totalSize * 100)}%\r"); } public static Stream CreateStream() diff --git a/Test/Test.csproj b/Test/Test.csproj index a54b2ff..10824ef 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -2,7 +2,7 @@ Exe - net472 + net10.0;net472 disable enable 14 From 28e0177d36a1ba5c6c50e99b431ab23d4924a90a Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 23 Aug 2026 21:35:50 +0700 Subject: [PATCH 17/72] Add PatchOptions presets --- SharpHPatchZ/PatchOptions.cs | 20 ++++++++++++++++++++ Test/Program.cs | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/SharpHPatchZ/PatchOptions.cs b/SharpHPatchZ/PatchOptions.cs index 4cb7a0b..def365c 100644 --- a/SharpHPatchZ/PatchOptions.cs +++ b/SharpHPatchZ/PatchOptions.cs @@ -7,6 +7,26 @@ public struct PatchOptions() { public static readonly PatchOptions Default = new(); + public static readonly PatchOptions BigBuffer = Default with + { + ReaderBufferSize = 1 << 20, + CopyBufferSize = 128 << 10, + PatchWorkerBufferSize = 16 << 20 + }; + + public static readonly PatchOptions SmallBuffer = Default with + { + ReaderBufferSize = 4 << 10, + CopyBufferSize = 4 << 10, + PatchWorkerBufferSize = 128 << 10 + }; + + public static readonly PatchOptions OptimizeForHDD = Default with + { + ParallelThreads = 2, + CopyBufferSize = BigBuffer.CopyBufferSize + }; + #if NET6_0_OR_GREATER public bool UseSIMD = true; #endif diff --git a/Test/Program.cs b/Test/Program.cs index 4a49cf6..5f48ca5 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -23,7 +23,7 @@ public static async Task Main() // hPatchOld.Patch(TestPathInput, TestPathOutput, true); ProgressCallback progressCallback = ProgressCallback.CreateFromManaged(WriteProgress); - PatchOptions options = PatchOptions.Default; + PatchOptions options = PatchOptions.BigBuffer; Stopwatch sw = Stopwatch.StartNew(); using (HDiffInfo info1 = await HPatch.CreateInstanceAsync(CreateStreamAsync)) From fa039d75af2e4ce4acb81fcc4e35b544df08da32 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 23 Aug 2026 22:06:57 +0700 Subject: [PATCH 18/72] Fix LZMA2 decoding --- SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs b/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs index e9e8153..1116f2d 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs @@ -133,11 +133,6 @@ public override int Read(byte[] buffer, int offset, int count) return 0; } - if (_decoder == null) - { - throw new NullReferenceException("Decoder is null"); - } - int total = 0; while (total < count) { @@ -168,7 +163,7 @@ public override int Read(byte[] buffer, int offset, int count) { _inputPosition += _outWindow.CopyStream(_inputStream, toProcess); } - else if (_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder) && _outputSize < 0) + else if (_decoder != null && _decoder.Code(_dictionarySize, _outWindow, _rangeDecoder) && _outputSize < 0) { _availableBytes = _outWindow.AvailableBytes; } @@ -186,7 +181,7 @@ public override int Read(byte[] buffer, int offset, int count) { // Stream might have End Of Stream marker _outWindow.SetLimit(toProcess + 1); - if (!_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder)) + if (_decoder != null && !_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder)) { _rangeDecoder.ReleaseStream(); throw new LzmaDataErrorException(); From 4f15f44cff309314dbc97421b0609dc72ad057bb Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 23 Aug 2026 22:08:31 +0700 Subject: [PATCH 19/72] Use native memory for buffer allocation --- SharpHPatchZ/Extension/MemoryAlloc.cs | 12 +- SharpHPatchZ/Extension/NativeMemoryBuffer.cs | 69 +++++ .../HDiff13DerivedPatcher.CorePatcher.cs | 250 ++++++++---------- SharpHPatchZ/Patch/RleCoverInfo.cs | 60 +++-- SharpHPatchZ/PatchOptions.cs | 13 +- Test/Program.cs | 31 ++- 6 files changed, 258 insertions(+), 177 deletions(-) create mode 100644 SharpHPatchZ/Extension/NativeMemoryBuffer.cs diff --git a/SharpHPatchZ/Extension/MemoryAlloc.cs b/SharpHPatchZ/Extension/MemoryAlloc.cs index 5be5330..fef5d85 100644 --- a/SharpHPatchZ/Extension/MemoryAlloc.cs +++ b/SharpHPatchZ/Extension/MemoryAlloc.cs @@ -14,7 +14,7 @@ internal static unsafe class MemoryAlloc return (T*)Alloc(elementCount, initializeAlloc); } - return (T*)Alloc(elementCount * sizeof(T), initializeAlloc); + return (T*)Alloc(checked((long)elementCount * sizeof(T)), initializeAlloc); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -77,6 +77,16 @@ public static void Free(void* ptr) ref byte asRef = ref Unsafe.AsRef(ptr); asRef.TryDisposeIfMetadataType(); + FreeRaw(ptr); + } + + public static void FreeRaw(void* ptr) + { + if (ptr == null) + { + return; + } + #if NET6_0_OR_GREATER NativeMemory.Free(ptr); #else diff --git a/SharpHPatchZ/Extension/NativeMemoryBuffer.cs b/SharpHPatchZ/Extension/NativeMemoryBuffer.cs new file mode 100644 index 0000000..8e6894e --- /dev/null +++ b/SharpHPatchZ/Extension/NativeMemoryBuffer.cs @@ -0,0 +1,69 @@ +using System; +using System.Threading; + +namespace SharpHPatchZ.Extension; + +internal sealed unsafe class NativeMemoryBuffer : IDisposable + where T : unmanaged +{ + private readonly int _length; + private long _pointer; + + public NativeMemoryBuffer(int length) + { + if (length < 0) + { + throw new ArgumentOutOfRangeException(nameof(length)); + } + + _length = length; + if (length == 0) + { + return; + } + + _pointer = (nint)MemoryAlloc.Alloc(length); + if (_pointer == 0) + { + throw new OutOfMemoryException(); + } + } + + ~NativeMemoryBuffer() + => Release(); + + public int Length => _length; + + public Span Span + { + get + { + nint pointer = (nint)_pointer; + if (pointer == 0) + { + return _length == 0 + ? Span.Empty + : throw new ObjectDisposedException(nameof(NativeMemoryBuffer)); + } + + return new Span((void*)pointer, _length); + } + } + + public void Dispose() + { + Release(); + GC.SuppressFinalize(this); + } + + private void Release() + { + nint pointer = (nint)Interlocked.Exchange(ref _pointer, 0); + if (pointer == 0) + { + return; + } + + MemoryAlloc.FreeRaw((void*)pointer); + } +} diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs index d0670f4..a9857be 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs @@ -24,44 +24,36 @@ internal sealed partial class HDiff13DerivedPatcher private unsafe void StartCorePatcher(CancellationToken token) { - ReadOnlySpan rleCoverSpan = RleCoverInfo.Read(_coverReader, - Info, - out RleCoverInfo[] rleCoverBackedBuffer, - token); - try + using NativeMemoryBuffer rleCoverBuffer = RleCoverInfo.Read(_coverReader, + Info, + token); + ReadOnlySpan rleCoverSpan = rleCoverBuffer.Span; + if (InputStream is null || OutputStream is null) { - if (InputStream is null || OutputStream is null) - { - throw new InvalidOperationException("The patch input and output streams have not been initialized."); - } + throw new InvalidOperationException("The patch input and output streams have not been initialized."); + } - PatchMetadata patchMetadata = Info.GetPatchMetadata(); - ValidateReaderOffset(_coverReader, - patchMetadata.CoverDataSizeP->Size, - "cover"); + PatchMetadata patchMetadata = Info.GetPatchMetadata(); + ValidateReaderOffset(_coverReader, + patchMetadata.CoverDataSizeP->Size, + "cover"); - int bufferSize = Options.PatchWorkerBufferSize > 0 - ? Options.PatchWorkerBufferSize - : DefaultPatchBufferSize; - int workerCount = GetWorkerCount(Options.ParallelThreads); + int bufferSize = Options.PatchWorkerBufferSize > 0 + ? Options.PatchWorkerBufferSize + : DefaultPatchBufferSize; + int workerCount = GetWorkerCount(Options.ParallelThreads); - if (workerCount == 1) - { - RunSequential(rleCoverSpan, patchMetadata, bufferSize, token); - } - else - { - RunParallel(rleCoverBackedBuffer, - rleCoverSpan.Length, - patchMetadata, - bufferSize, - workerCount, - token); - } + if (workerCount == 1) + { + RunSequential(rleCoverSpan, patchMetadata, bufferSize, token); } - finally + else { - BigArrayPool.Shared.Return(rleCoverBackedBuffer); + RunParallel(rleCoverBuffer, + patchMetadata, + bufferSize, + workerCount, + token); } } @@ -85,28 +77,20 @@ private void RunSequential(ReadOnlySpan covers, int bufferSize, CancellationToken token) { - byte[] oldBuffer = BigArrayPool.Shared.Rent(bufferSize); - try - { - ProduceWork(covers, - patchMetadata.DiffNewSize, - bufferSize, - item => ProcessWorkItem(item, oldBuffer, token), - token); - ValidateDataReaders(patchMetadata); - } - finally - { - BigArrayPool.Shared.Return(oldBuffer); - } + using NativeMemoryBuffer oldBuffer = new(bufferSize); + ProduceWork(covers, + patchMetadata.DiffNewSize, + bufferSize, + item => ProcessWorkItem(item, oldBuffer, token), + token); + ValidateDataReaders(patchMetadata); } - private void RunParallel(RleCoverInfo[] covers, - int coverCount, - PatchMetadata patchMetadata, - int bufferSize, - int workerCount, - CancellationToken token) + private void RunParallel(NativeMemoryBuffer covers, + PatchMetadata patchMetadata, + int bufferSize, + int workerCount, + CancellationToken token) { int queueCapacity = workerCount > int.MaxValue / 2 ? int.MaxValue @@ -125,7 +109,7 @@ private void RunParallel(RleCoverInfo[] covers, { try { - ProduceWork(covers.AsSpan(0, coverCount), + ProduceWork(covers.Span, patchMetadata.DiffNewSize, bufferSize, item => AddWorkItem(workQueue, item, linkedCancellation.Token), @@ -155,7 +139,7 @@ private void RunParallel(RleCoverInfo[] covers, CancellationToken = linkedCancellation.Token, MaxDegreeOfParallelism = workerCount }, - () => BigArrayPool.Shared.Rent(bufferSize), + () => new NativeMemoryBuffer(bufferSize), (item, _, oldBuffer) => { try @@ -174,7 +158,7 @@ private void RunParallel(RleCoverInfo[] covers, return oldBuffer; }, - oldBuffer => BigArrayPool.Shared.Return(oldBuffer)); + oldBuffer => oldBuffer.Dispose()); } catch (Exception exception) { @@ -187,7 +171,7 @@ private void RunParallel(RleCoverInfo[] covers, while (workQueue.TryTake(out PatchWorkItem abandonedItem)) { - BigArrayPool.Shared.Return(abandonedItem.Buffer); + abandonedItem.Buffer.Dispose(); } } @@ -214,7 +198,7 @@ private static void AddWorkItem(BlockingCollection queue, } catch { - BigArrayPool.Shared.Return(item.Buffer); + item.Buffer.Dispose(); throw; } } @@ -226,54 +210,47 @@ private void ProduceWork(ReadOnlySpan covers, CancellationToken token) { RleDecoder rleDecoder = new(_rleCtrlReader, _rleCodeReader); - byte[] skipBuffer = BigArrayPool.Shared.Rent(Math.Min(bufferSize, 64 << 10)); + using NativeMemoryBuffer skipBuffer = new(Math.Min(bufferSize, 64 << 10)); using PatchWorkBuilder workBuilder = new(bufferSize, emit); - try + long newPosition = 0; + for (int coverIndex = 0; coverIndex < covers.Length; coverIndex++) { - long newPosition = 0; - for (int coverIndex = 0; coverIndex < covers.Length; coverIndex++) - { - token.ThrowIfCancellationRequested(); - ref readonly RleCoverInfo cover = ref covers[coverIndex]; - ValidateCover(cover, newPosition, newDataSize, InputStream!.Length); - - ProduceNewData(cover.CopyLength, - ref newPosition, - rleDecoder, - skipBuffer, - workBuilder, - token); - ProduceCover(cover, - ref newPosition, - rleDecoder, - workBuilder, - token); - } + token.ThrowIfCancellationRequested(); + ref readonly RleCoverInfo cover = ref covers[coverIndex]; + ValidateCover(cover, newPosition, newDataSize, InputStream!.Length); - ProduceNewData(newDataSize - newPosition, + ProduceNewData(cover.CopyLength, ref newPosition, rleDecoder, - skipBuffer, + skipBuffer.Span, workBuilder, token); + ProduceCover(cover, + ref newPosition, + rleDecoder, + workBuilder, + token); + } - if (newPosition != newDataSize || rleDecoder.HasPendingData) - { - throw new InvalidDataException("The decoded patch data does not match the declared output size."); - } + ProduceNewData(newDataSize - newPosition, + ref newPosition, + rleDecoder, + skipBuffer.Span, + workBuilder, + token); - workBuilder.Flush(); - } - finally + if (newPosition != newDataSize || rleDecoder.HasPendingData) { - BigArrayPool.Shared.Return(skipBuffer); + throw new InvalidDataException("The decoded patch data does not match the declared output size."); } + + workBuilder.Flush(); } private void ProduceNewData(long length, ref long newPosition, RleDecoder rleDecoder, - byte[] skipBuffer, + Span skipBuffer, PatchWorkBuilder workBuilder, CancellationToken token) { @@ -314,9 +291,9 @@ private static void ProduceCover(RleCoverInfo cover, } } - private void ProcessWorkItem(PatchWorkItem item, - byte[] oldBuffer, - CancellationToken token) + private void ProcessWorkItem(PatchWorkItem item, + NativeMemoryBuffer oldBuffer, + CancellationToken token) { try { @@ -327,7 +304,7 @@ private void ProcessWorkItem(PatchWorkItem item, { token.ThrowIfCancellationRequested(); CoverSegment segment = coverSegments[segmentIndex]; - Span oldData = oldBuffer.AsSpan(0, segment.Length); + Span oldData = oldBuffer.Span[..segment.Length]; int read = InputStream!.Read(oldData, segment.OldPosition); if (read != segment.Length) { @@ -335,43 +312,42 @@ private void ProcessWorkItem(PatchWorkItem item, } #if NET6_0_OR_GREATER - AddRle(oldBuffer, - item.Buffer, - segment.BufferOffset, - segment.Length, - Options.UseSIMD); + Span rleData = item.Buffer.Span.Slice(segment.BufferOffset, + segment.Length); + AddRle(oldData, rleData, Options.UseSIMD); #else - AddRle(oldBuffer, - item.Buffer, - segment.BufferOffset, - segment.Length); + Span rleData = item.Buffer.Span.Slice(segment.BufferOffset, + segment.Length); + AddRle(oldData, rleData); #endif - oldData.CopyTo(item.Buffer.AsSpan(segment.BufferOffset, segment.Length)); + oldData.CopyTo(rleData); } } - OutputStream!.Write(item.Buffer.AsSpan(0, item.Length), item.OutputPosition); + OutputStream!.Write(item.Buffer.Span[..item.Length], item.OutputPosition); AdvanceProgress(item.Length); } finally { - BigArrayPool.Shared.Return(item.Buffer); + item.Buffer.Dispose(); } } #if NET6_0_OR_GREATER - private static void AddRle(byte[] destination, - byte[] rle, - int rleOffset, - int length, - bool useSimd) + private static void AddRle(Span destination, + ReadOnlySpan rle, + bool useSimd) #else - private static void AddRle(byte[] destination, - byte[] rle, - int rleOffset, - int length) + private static void AddRle(Span destination, + ReadOnlySpan rle) #endif { + if (destination.Length != rle.Length) + { + throw new ArgumentException("The old-data and RLE buffers must have the same length."); + } + + int length = destination.Length; int index = 0; #if NET6_0_OR_GREATER if (useSimd && Avx2.IsSupported) @@ -381,7 +357,7 @@ private static void AddRle(byte[] destination, if (vectorEnd != 0) { ref byte destinationRef = ref destination[0]; - ref byte rleRef = ref rle[rleOffset]; + ref byte rleRef = ref Unsafe.AsRef(in rle[0]); for (; index < vectorEnd; index += vectorLength) { var oldVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref destinationRef, index)); @@ -398,7 +374,7 @@ private static void AddRle(byte[] destination, if (vectorEnd != 0) { ref byte destinationRef = ref destination[0]; - ref byte rleRef = ref rle[rleOffset]; + ref byte rleRef = ref Unsafe.AsRef(in rle[0]); for (; index < vectorEnd; index += vectorLength) { var oldVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref destinationRef, index)); @@ -414,15 +390,15 @@ private static void AddRle(byte[] destination, int vectorEnd = length - length % vectorLength; for (; index < vectorEnd; index += vectorLength) { - Vector oldVector = new(destination, index); - Vector rleVector = new(rle, rleOffset + index); - (oldVector + rleVector).CopyTo(destination, index); + Vector oldVector = new(destination.Slice(index, vectorLength)); + Vector rleVector = new(rle.Slice(index, vectorLength)); + (oldVector + rleVector).CopyTo(destination.Slice(index, vectorLength)); } } #endif for (; index < length; index++) { - destination[index] = unchecked((byte)(destination[index] + rle[rleOffset + index])); + destination[index] = unchecked((byte)(destination[index] + rle[index])); } } @@ -461,15 +437,15 @@ private static void ValidateReaderOffset(BittableStreamReader reader, } } - private readonly struct PatchWorkItem(byte[] buffer, - int length, - long outputPosition, - List? coverSegments) + private readonly struct PatchWorkItem(NativeMemoryBuffer buffer, + int length, + long outputPosition, + List? coverSegments) { - public byte[] Buffer { get; } = buffer; - public int Length { get; } = length; - public long OutputPosition { get; } = outputPosition; - public List? CoverSegments { get; } = coverSegments; + public NativeMemoryBuffer Buffer { get; } = buffer; + public int Length { get; } = length; + public long OutputPosition { get; } = outputPosition; + public List? CoverSegments { get; } = coverSegments; } private readonly struct CoverSegment(int bufferOffset, @@ -487,10 +463,10 @@ private sealed class PatchWorkBuilder(int bufferSize, private readonly int _bufferSize = bufferSize; private readonly Action _emit = emit; - private byte[]? _buffer; - private int _length; - private long _outputPosition; - private List? _coverSegments; + private NativeMemoryBuffer? _buffer; + private int _length; + private long _outputPosition; + private List? _coverSegments; public Span GetWritableSpan(long outputPosition, long requestedLength, @@ -503,7 +479,7 @@ public Span GetWritableSpan(long outputPosition, if (_buffer is null) { - _buffer = BigArrayPool.Shared.Rent(_bufferSize); + _buffer = new NativeMemoryBuffer(_bufferSize); _outputPosition = outputPosition; } else if (outputPosition != _outputPosition + _length) @@ -512,7 +488,7 @@ public Span GetWritableSpan(long outputPosition, } writableLength = (int)Math.Min(requestedLength, _bufferSize - _length); - return _buffer.AsSpan(_length, writableLength); + return _buffer.Span.Slice(_length, writableLength); } public void CommitNewData(int length) @@ -562,7 +538,7 @@ public void Dispose() { if (_buffer is not null) { - BigArrayPool.Shared.Return(_buffer); + _buffer.Dispose(); _buffer = null; } } @@ -612,7 +588,7 @@ public void Decode(Span destination, CancellationToken token) } } - public void Skip(long length, byte[] scratchBuffer, CancellationToken token) + public void Skip(long length, Span scratchBuffer, CancellationToken token) { while (length > 0) { @@ -626,7 +602,7 @@ public void Skip(long length, byte[] scratchBuffer, CancellationToken token) while (rawRemaining > 0) { int readLength = (int)Math.Min(rawRemaining, scratchBuffer.Length); - _codeReader.ReadBytes(scratchBuffer.AsSpan(0, readLength)); + _codeReader.ReadBytes(scratchBuffer[..readLength]); rawRemaining -= readLength; } } diff --git a/SharpHPatchZ/Patch/RleCoverInfo.cs b/SharpHPatchZ/Patch/RleCoverInfo.cs index 3fceacd..6563318 100644 --- a/SharpHPatchZ/Patch/RleCoverInfo.cs +++ b/SharpHPatchZ/Patch/RleCoverInfo.cs @@ -29,46 +29,54 @@ public RleCoverInfo(long oldStreamPosition, CopyLength = copyLength; } - internal static Span Read(BittableStreamReader reader, - HDiffInfo info, - out RleCoverInfo[] backedBuffer, - CancellationToken token) + internal static NativeMemoryBuffer Read(BittableStreamReader reader, + HDiffInfo info, + CancellationToken token) { ref PatchMetadata patchMetadata = ref info.GetPatchMetadata(); int rleCoverCount = patchMetadata.CoverDataCount; - backedBuffer = BigArrayPool.Shared.Rent(rleCoverCount); + NativeMemoryBuffer backedBuffer = new(rleCoverCount); - long lastOldPosBack = 0; - long lastNewPosBack = 0; - - for (int i = 0; i < rleCoverCount; i++) + try { - token.ThrowIfCancellationRequested(); + Span covers = backedBuffer.Span; + long lastOldPosBack = 0; + long lastNewPosBack = 0; - long oldPosBack = lastOldPosBack; - long newPosBack = lastNewPosBack; + for (int i = 0; i < rleCoverCount; i++) + { + token.ThrowIfCancellationRequested(); - long incOldPos = reader.ReadLong7Bit(BittableStreamReader.KSignTagBit); + long oldPosBack = lastOldPosBack; + long newPosBack = lastNewPosBack; - byte incOldPosSign = (byte)(reader.PreviousByte >> (8 - BittableStreamReader.KSignTagBit)); - long oldPos = incOldPosSign == 0 ? oldPosBack + incOldPos : oldPosBack - incOldPos; + long incOldPos = reader.ReadLong7Bit(BittableStreamReader.KSignTagBit); - long copyLength = reader.ReadLong7Bit(); - long coverLength = reader.ReadLong7Bit(); + byte incOldPosSign = (byte)(reader.PreviousByte >> (8 - BittableStreamReader.KSignTagBit)); + long oldPos = incOldPosSign == 0 ? oldPosBack + incOldPos : oldPosBack - incOldPos; - oldPosBack = oldPos; - newPosBack += copyLength; - oldPosBack += coverLength; + long copyLength = reader.ReadLong7Bit(); + long coverLength = reader.ReadLong7Bit(); - backedBuffer[i] = new RleCoverInfo(oldPos, newPosBack, coverLength, copyLength); - newPosBack += coverLength; + oldPosBack = oldPos; + newPosBack += copyLength; + oldPosBack += coverLength; - lastOldPosBack = oldPosBack; - lastNewPosBack = newPosBack; - } + covers[i] = new RleCoverInfo(oldPos, newPosBack, coverLength, copyLength); + newPosBack += coverLength; + + lastOldPosBack = oldPosBack; + lastNewPosBack = newPosBack; + } - return backedBuffer.AsSpan(0, rleCoverCount); + return backedBuffer; + } + catch + { + backedBuffer.Dispose(); + throw; + } } public override string ToString() => $"RleLength: {RleLength} | CopyLength: {CopyLength} | OldPos: {OldStreamPosition} | NewPos: {NewStreamPosition}"; diff --git a/SharpHPatchZ/PatchOptions.cs b/SharpHPatchZ/PatchOptions.cs index def365c..e7673f3 100644 --- a/SharpHPatchZ/PatchOptions.cs +++ b/SharpHPatchZ/PatchOptions.cs @@ -1,11 +1,18 @@ -using System.Runtime.InteropServices; +using System; +using System.Runtime.InteropServices; namespace SharpHPatchZ; [StructLayout(LayoutKind.Sequential)] public struct PatchOptions() { - public static readonly PatchOptions Default = new(); + public static readonly PatchOptions Default = new() + { + ParallelThreads = (uint)Environment.ProcessorCount, +#if NET6_0_OR_GREATER + UseSIMD = true +#endif + }; public static readonly PatchOptions BigBuffer = Default with { @@ -23,7 +30,7 @@ public struct PatchOptions() public static readonly PatchOptions OptimizeForHDD = Default with { - ParallelThreads = 2, + ParallelThreads = 1, CopyBufferSize = BigBuffer.CopyBufferSize }; diff --git a/Test/Program.cs b/Test/Program.cs index 5f48ca5..fecc3a0 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -11,28 +11,39 @@ namespace Test; public class Program { - private static string TestPathInput = @"G:\Hi3SEA"; - private static string TestPathOutput = @"G:\Hi3CN-dotnet"; - private static string TestPathPatch = @"G:\Hi3SEAtoCNExecOnly.lzma2.diff"; - private static string TestPathPatchLzma = @"G:\Hi3SEAtoCNExecOnly.lzma.diff"; - private static string TestPathPatchNoComp = @"G:\Hi3SEAtoCNExecOnly.nocomp.diff"; + private static string TestPathInput = @"G:\UnityPlayer-SEA.dll"; + private static string TestPathOutput = @"G:\UnityPlayer-CN-Dotnet.dll"; + private static string TestPathPatch = @"G:\UnityPlayer.lzma2.diff"; + private static string TestPathPatchLzma = @"G:\UnityPlayer.lzma.diff"; + private static string TestPathPatchNoComp = @"G:\UnityPlayer.nocomp.diff"; public static async Task Main() { + Stopwatch sw = Stopwatch.StartNew(); HDiffPatch hPatchOld = new(); + + long oldImplNewSize = HDiffPatch.GetHDiffNewSize(TestPathPatchNoComp); + long oldImplTotalWritten = 0; + hPatchOld.Initialize(CreateStream); - // hPatchOld.Patch(TestPathInput, TestPathOutput, true); + hPatchOld.Patch(TestPathInput, TestPathOutput, true, (written) => + { + Interlocked.Add(ref oldImplTotalWritten, written); + Console.Write($"{oldImplTotalWritten} / {oldImplNewSize} {(int)(oldImplTotalWritten / (double)oldImplNewSize * 100)}%\r"); + }); + Console.WriteLine(); + Console.WriteLine($"Old Implementation completed in: {sw.ElapsedMilliseconds} ms"); ProgressCallback progressCallback = ProgressCallback.CreateFromManaged(WriteProgress); PatchOptions options = PatchOptions.BigBuffer; - Stopwatch sw = Stopwatch.StartNew(); + sw.Restart(); using (HDiffInfo info1 = await HPatch.CreateInstanceAsync(CreateStreamAsync)) { PatchResult result = await HPatch.PatchAsync(info1, CreateStreamAsync, TestPathInput, TestPathOutput, options, progressCallback: progressCallback); } Console.WriteLine(); - Console.WriteLine($"Completed in: {sw.ElapsedMilliseconds} ms"); + Console.WriteLine($"New Implementation completed in: {sw.ElapsedMilliseconds} ms"); } public static void WriteProgress(long totalProcessed, long totalSize, int written) @@ -48,14 +59,14 @@ public static Stream CreateStream() public static (Stream, bool) CreateStream(long position) { - FileStream stream = File.Open(TestPathPatchLzma, FileMode.Open, FileAccess.Read, FileShare.Read); + FileStream stream = File.Open(TestPathPatch, FileMode.Open, FileAccess.Read, FileShare.Read); stream.Position = position; return (stream, false); } public static ValueTask<(Stream, bool)> CreateStreamAsync(long position, CancellationToken token) { - FileStream stream = File.Open(TestPathPatchLzma, FileMode.Open, FileAccess.Read, FileShare.Read); + FileStream stream = File.Open(TestPathPatch, FileMode.Open, FileAccess.Read, FileShare.Read); stream.Position = position; return new ValueTask<(Stream, bool)>((stream, false)); } From 73b95ce053e7c1885fc81a8db9a2f15c2b1ae8c8 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 23 Aug 2026 23:08:23 +0700 Subject: [PATCH 20/72] Use native memory and parallel decompress in LZMA/LZMA2 --- SharpHPatchZ/Extension/NativeMemoryBuffer.cs | 13 + .../IO/Compression/Lzma/LZ/LzOutWindow.cs | 89 +++++-- .../Compression/Lzma/RangeCoder/RangeCoder.cs | 37 ++- .../IO/Reader/PrefetchedReadStream.cs | 234 ++++++++++++++++++ .../Patch/PatcherFactory.HDiff13Derived.cs | 74 +++++- 5 files changed, 408 insertions(+), 39 deletions(-) create mode 100644 SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs diff --git a/SharpHPatchZ/Extension/NativeMemoryBuffer.cs b/SharpHPatchZ/Extension/NativeMemoryBuffer.cs index 8e6894e..ca1f57c 100644 --- a/SharpHPatchZ/Extension/NativeMemoryBuffer.cs +++ b/SharpHPatchZ/Extension/NativeMemoryBuffer.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; using System.Threading; namespace SharpHPatchZ.Extension; @@ -50,6 +51,18 @@ public Span Span } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ref T GetReference() + { + nint pointer = (nint)_pointer; + if (pointer == 0) + { + throw new ObjectDisposedException(nameof(NativeMemoryBuffer)); + } + + return ref Unsafe.AsRef((void*)pointer); + } + public void Dispose() { Release(); diff --git a/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs b/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs index 86ff605..7e7bfdc 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs @@ -2,31 +2,35 @@ using System.Buffers; using System.IO; using System.Runtime.CompilerServices; +using SharpHPatchZ.Extension; namespace SharpHPatchZ.IO.Compression.Lzma.LZ; internal class OutWindow : IDisposable { - private byte[] _buffer = []; - private int _windowSize; - private int _pos; - private int _streamPos; - private int _pendingLen; - private int _pendingDist; - private Stream? _stream; + private NativeMemoryBuffer? _buffer; +#if !NET6_0_OR_GREATER + private byte[] _streamBuffer = []; +#endif + private int _windowSize; + private int _pos; + private int _streamPos; + private int _pendingLen; + private int _pendingDist; + private Stream? _stream; public long Total; public long Limit; public void Create(int windowSize) { - if (_buffer.Length < windowSize) + if (_buffer is null || _buffer.Length < windowSize) { - ReturnPooledBuffer(); - _buffer = ArrayPool.Shared.Rent(windowSize); + ReleaseBuffer(); + _buffer = new NativeMemoryBuffer(windowSize); } - _buffer[windowSize - 1] = 0; + Unsafe.Add(ref _buffer.GetReference(), windowSize - 1) = 0; _windowSize = windowSize; _pos = 0; _streamPos = 0; @@ -79,7 +83,21 @@ public void Flush() return; } - _stream.Write(_buffer, _streamPos, size); +#if NET6_0_OR_GREATER + _stream.Write(_buffer!.Span.Slice(_streamPos, size)); +#else + byte[] streamBuffer = GetStreamBuffer(); + int sourceOffset = _streamPos; + int remaining = size; + while (remaining > 0) + { + int step = Math.Min(remaining, streamBuffer.Length); + _buffer!.Span.Slice(sourceOffset, step).CopyTo(streamBuffer); + _stream.Write(streamBuffer, 0, step); + sourceOffset += step; + remaining -= step; + } +#endif if (_pos >= _windowSize) { _pos = 0; @@ -106,7 +124,7 @@ public void CopyBlock(int distance, int len) copySize = (int)available; } - ref byte buffer = ref _buffer[0]; + ref byte buffer = ref _buffer!.GetReference(); int beforeWrap = Math.Min(copySize, _windowSize - source); CopyBytes(ref buffer, source, _pos, beforeWrap); source += beforeWrap; @@ -161,7 +179,7 @@ private static unsafe void CopyBytes(ref byte buffer, int sourceOffset, int dest public void PutByte(byte b) { - _buffer[_pos++] = b; + Unsafe.Add(ref _buffer!.GetReference(), _pos++) = b; Total++; if (_pos >= _windowSize) @@ -177,7 +195,7 @@ public byte GetByte(int distance) { pos += _windowSize; } - return _buffer[pos]; + return Unsafe.Add(ref _buffer!.GetReference(), pos); } public int CopyStream(Stream stream, int len) @@ -196,7 +214,13 @@ public int CopyStream(Stream stream, int len) curSize = size; } - int numReadBytes = stream.Read(_buffer, _pos, curSize); +#if NET6_0_OR_GREATER + int numReadBytes = stream.Read(_buffer!.Span.Slice(_pos, curSize)); +#else + byte[] streamBuffer = GetStreamBuffer(); + int numReadBytes = stream.Read(streamBuffer, 0, Math.Min(curSize, streamBuffer.Length)); + streamBuffer.AsSpan(0, numReadBytes).CopyTo(_buffer!.Span.Slice(_pos, numReadBytes)); +#endif if (numReadBytes == 0) { throw new LzmaDataErrorException(); @@ -232,7 +256,7 @@ public int Read(byte[] buffer, int offset, int count) size = count; } - _buffer.AsSpan(_streamPos, size).CopyTo(buffer.AsSpan(offset, size)); + _buffer!.Span.Slice(_streamPos, size).CopyTo(buffer.AsSpan(offset, size)); _streamPos += size; if (_streamPos < _windowSize) return size; @@ -254,16 +278,33 @@ public void CopyPending() public void Dispose() { ReleaseStream(); - ReturnPooledBuffer(); + ReleaseBuffer(); +#if !NET6_0_OR_GREATER + byte[] streamBuffer = _streamBuffer; + _streamBuffer = []; + if (streamBuffer.Length != 0) + { + ArrayPool.Shared.Return(streamBuffer); + } +#endif } - private void ReturnPooledBuffer() + private void ReleaseBuffer() { - byte[] buffer = _buffer; - _buffer = []; - if (buffer.Length != 0) + NativeMemoryBuffer? buffer = _buffer; + _buffer = null; + buffer?.Dispose(); + } + +#if !NET6_0_OR_GREATER + private byte[] GetStreamBuffer() + { + if (_streamBuffer.Length == 0) { - ArrayPool.Shared.Return(buffer); + _streamBuffer = ArrayPool.Shared.Rent(64 << 10); } + + return _streamBuffer; } -} \ No newline at end of file +#endif +} diff --git a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs index 47746bb..c203b02 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs @@ -2,6 +2,9 @@ using System.Buffers; using System.IO; using System.Runtime.CompilerServices; +#if NET6_0_OR_GREATER +using SharpHPatchZ.Extension; +#endif namespace SharpHPatchZ.IO.Compression.Lzma.RangeCoder; @@ -15,11 +18,15 @@ internal class RangeDecoder : IDisposable public Stream Stream; public long Total; - private byte[] _inputBuffer = []; - private int _inputOffset; - private int _inputCount; - private long _inputLimit; - private bool _useInputBuffer; +#if NET6_0_OR_GREATER + private NativeMemoryBuffer? _inputBuffer; +#else + private byte[] _inputBuffer = []; +#endif + private int _inputOffset; + private int _inputCount; + private long _inputLimit; + private bool _useInputBuffer; public void Init(Stream stream, long inputLimit = -1) { @@ -96,7 +103,11 @@ internal uint ReadByte() } Total++; +#if NET6_0_OR_GREATER + return Unsafe.Add(ref _inputBuffer!.GetReference(), _inputOffset++); +#else return _inputBuffer[_inputOffset++]; +#endif } [MethodImpl(MethodImplOptions.NoInlining)] @@ -108,13 +119,19 @@ private void FillInputBuffer() throw new LzmaDataErrorException(); } +#if NET6_0_OR_GREATER + _inputBuffer ??= new NativeMemoryBuffer(InputBufferSize); + int requested = (int)Math.Min(_inputBuffer.Length, remaining); + _inputCount = Stream.Read(_inputBuffer.Span[..requested]); +#else if (_inputBuffer.Length == 0) { _inputBuffer = ArrayPool.Shared.Rent(InputBufferSize); } int requested = (int)Math.Min(_inputBuffer.Length, remaining); - _inputCount = Stream.Read(_inputBuffer, 0, requested); + _inputCount = Stream.Read(_inputBuffer, 0, requested); +#endif _inputOffset = 0; if (_inputCount <= 0) { @@ -125,6 +142,11 @@ private void FillInputBuffer() public void Dispose() { ReleaseStream(); +#if NET6_0_OR_GREATER + NativeMemoryBuffer? inputBuffer = _inputBuffer; + _inputBuffer = null; + inputBuffer?.Dispose(); +#else byte[] inputBuffer = _inputBuffer; _inputBuffer = []; @@ -132,5 +154,6 @@ public void Dispose() { ArrayPool.Shared.Return(inputBuffer); } +#endif } -} \ No newline at end of file +} diff --git a/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs b/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs new file mode 100644 index 0000000..9768b83 --- /dev/null +++ b/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs @@ -0,0 +1,234 @@ +using System; +using System.Collections.Concurrent; +using System.IO; +using System.Runtime.ExceptionServices; +using System.Threading; +using System.Threading.Tasks; +using SharpHPatchZ.Extension; + +namespace SharpHPatchZ.IO.Reader; + +internal sealed class PrefetchedReadStream : Stream +{ + private readonly Stream _source; + private readonly int _bufferSize; + private readonly BlockingCollection _queue; + private readonly CancellationTokenSource _disposeCancellation = new(); + private readonly Task _producer; + + private ExceptionDispatchInfo? _producerFailure; + private BufferChunk? _current; + private int _currentOffset; + private int _disposed; + + public PrefetchedReadStream(Stream source, + int bufferSize, + int queueCapacity = 2) + { + _source = source ?? throw new ArgumentNullException(nameof(source)); + if (!source.CanRead) + { + throw new ArgumentException("The source stream must be readable.", nameof(source)); + } + + _bufferSize = bufferSize > 0 + ? bufferSize + : throw new ArgumentOutOfRangeException(nameof(bufferSize)); + _queue = new BlockingCollection(queueCapacity > 0 + ? queueCapacity + : throw new ArgumentOutOfRangeException(nameof(queueCapacity))); + + _producer = Task.Factory.StartNew(Produce, + CancellationToken.None, + TaskCreationOptions.LongRunning, + TaskScheduler.Default); + } + + public override bool CanRead => Volatile.Read(ref _disposed) == 0; + public override bool CanSeek => false; + public override bool CanWrite => false; + public override long Length => throw new NotSupportedException(); + + public override long Position + { + get => throw new NotSupportedException(); + set => throw new NotSupportedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + if (buffer is null) throw new ArgumentNullException(nameof(buffer)); + if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset)); + if (count < 0 || buffer.Length - offset < count) throw new ArgumentOutOfRangeException(nameof(count)); + + return ReadCore(buffer.AsSpan(offset, count)); + } + +#if NET6_0_OR_GREATER + public override int Read(Span buffer) + => ReadCore(buffer); +#endif + + private int ReadCore(Span destination) + { + ThrowIfDisposed(); + int totalRead = 0; + + while (!destination.IsEmpty) + { + if (_current is null) + { + try + { + if (!_queue.TryTake(out BufferChunk? chunk, + Timeout.Infinite, + _disposeCancellation.Token)) + { + _producerFailure?.Throw(); + break; + } + + _current = chunk; + _currentOffset = 0; + } + catch (OperationCanceledException) when (Volatile.Read(ref _disposed) != 0) + { + throw new ObjectDisposedException(nameof(PrefetchedReadStream)); + } + } + + BufferChunk current = _current!; + int step = Math.Min(destination.Length, current.Length - _currentOffset); + current.Buffer.Span.Slice(_currentOffset, step).CopyTo(destination); + _currentOffset += step; + totalRead += step; + destination = destination[step..]; + + if (_currentOffset != current.Length) + { + continue; + } + + current.Dispose(); + _current = null; + _currentOffset = 0; + } + + return totalRead; + } + + private void Produce() + { +#if !NET6_0_OR_GREATER + byte[] streamBuffer = System.Buffers.ArrayPool.Shared.Rent(_bufferSize); +#endif + try + { + while (!_disposeCancellation.IsCancellationRequested) + { + NativeMemoryBuffer buffer = new(_bufferSize); + try + { +#if NET6_0_OR_GREATER + int read = _source.Read(buffer.Span); +#else + int read = _source.Read(streamBuffer, 0, streamBuffer.Length); + streamBuffer.AsSpan(0, read).CopyTo(buffer.Span); +#endif + if (read == 0) + { + buffer.Dispose(); + break; + } + + _queue.Add(new BufferChunk(buffer, read), _disposeCancellation.Token); + } + catch + { + buffer.Dispose(); + throw; + } + } + } + catch (OperationCanceledException) when (_disposeCancellation.IsCancellationRequested) { } + catch (ObjectDisposedException) when (_disposeCancellation.IsCancellationRequested) { } + catch (Exception exception) + { + Interlocked.CompareExchange(ref _producerFailure, + ExceptionDispatchInfo.Capture(exception), + null); + } + finally + { +#if !NET6_0_OR_GREATER + System.Buffers.ArrayPool.Shared.Return(streamBuffer); +#endif + try + { + _source.Dispose(); + } + catch (Exception exception) + { + if (!_disposeCancellation.IsCancellationRequested) + { + Interlocked.CompareExchange(ref _producerFailure, + ExceptionDispatchInfo.Capture(exception), + null); + } + } + finally + { + _queue.CompleteAdding(); + } + } + } + + protected override void Dispose(bool disposing) + { + if (Interlocked.Exchange(ref _disposed, 1) != 0) + { + return; + } + + if (disposing) + { + _disposeCancellation.Cancel(); + _source.Dispose(); + _producer.GetAwaiter().GetResult(); + + _current?.Dispose(); + _current = null; + while (_queue.TryTake(out BufferChunk? chunk)) + { + chunk.Dispose(); + } + + _queue.Dispose(); + _disposeCancellation.Dispose(); + } + + base.Dispose(disposing); + } + + public override void Flush() { } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); + public override void SetLength(long value) => throw new NotSupportedException(); + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); + + private void ThrowIfDisposed() + { + if (Volatile.Read(ref _disposed) != 0) + { + throw new ObjectDisposedException(nameof(PrefetchedReadStream)); + } + } + + private sealed class BufferChunk(NativeMemoryBuffer buffer, int length) : IDisposable + { + public NativeMemoryBuffer Buffer { get; } = buffer; + public int Length { get; } = length; + + public void Dispose() + => Buffer.Dispose(); + } +} diff --git a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs index 4278e4e..1497ca1 100644 --- a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs +++ b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs @@ -3,6 +3,7 @@ using SharpHPatchZ.IO.Compression; using SharpHPatchZ.IO.Reader; using System; +using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -82,19 +83,76 @@ private static unsafe DiffReadersContext CreateReaderContext(HDiffCompression { int bufferSize = options.ReaderBufferSize; - Stream decCoverStream = CreateDecompressionStream(compType, *patchMetadata.CoverDataSizeP, coverCtx); - Stream decRleControlStream = CreateDecompressionStream(compType, *patchMetadata.RleControlDataSizeP, rleCtrlCtx); - Stream decRleCodeStream = CreateDecompressionStream(compType, *patchMetadata.RleCodeDataSizeP, rleCodeCtx); - Stream decNewDataStream = CreateDecompressionStream(compType, *patchMetadata.NewDiffDataSizeP, newDataCtx); + ChunkSizeInfo coverSize = *patchMetadata.CoverDataSizeP; + ChunkSizeInfo controlSize = *patchMetadata.RleControlDataSizeP; + ChunkSizeInfo codeSize = *patchMetadata.RleCodeDataSizeP; + ChunkSizeInfo newDataSize = *patchMetadata.NewDiffDataSizeP; - BittableStreamReader coverReader = new(decCoverStream, bufferSize, coverCtx.Item2); - BittableStreamReader rleCtrlReader = new(decRleControlStream, bufferSize, rleCtrlCtx.Item2); - BittableStreamReader rleCodeReader = new(decRleCodeStream, bufferSize, rleCodeCtx.Item2); - BittableStreamReader newDataReader = new(decNewDataStream, bufferSize, newDataCtx.Item2); + Stream[] decompressedStreams = + [ + CreateDecompressionStream(compType, coverSize, coverCtx), + CreateDecompressionStream(compType, controlSize, rleCtrlCtx), + CreateDecompressionStream(compType, codeSize, rleCodeCtx), + CreateDecompressionStream(compType, newDataSize, newDataCtx) + ]; + + EnableParallelDecompression(compType, + options, + decompressedStreams, + [coverSize, controlSize, codeSize, newDataSize]); + + BittableStreamReader coverReader = new(decompressedStreams[0], bufferSize, coverCtx.Item2); + BittableStreamReader rleCtrlReader = new(decompressedStreams[1], bufferSize, rleCtrlCtx.Item2); + BittableStreamReader rleCodeReader = new(decompressedStreams[2], bufferSize, rleCodeCtx.Item2); + BittableStreamReader newDataReader = new(decompressedStreams[3], bufferSize, newDataCtx.Item2); return new DiffReadersContext(coverReader, rleCtrlReader, rleCodeReader, newDataReader); } + private static void EnableParallelDecompression(HDiffCompression compType, + PatchOptions options, + Stream[] streams, + ChunkSizeInfo[] sizes) + { + if (compType is not (HDiffCompression.Lzma or HDiffCompression.Lzma2)) + { + return; + } + + int requestedWorkers = options.ParallelThreads == 0 + ? Environment.ProcessorCount + : options.ParallelThreads > int.MaxValue + ? int.MaxValue + : (int)options.ParallelThreads; + int prefetchCount = Math.Min(streams.Length, Math.Max(0, requestedWorkers - 1)); + if (prefetchCount == 0) + { + return; + } + + List<(int Index, long CompressedSize)> candidates = new(streams.Length); + for (int index = 0; index < sizes.Length; index++) + { + if (sizes[index].CompressedSize > 0 && sizes[index].Size > 0) + { + candidates.Add((index, sizes[index].CompressedSize)); + } + } + + candidates.Sort(static (left, right) => right.CompressedSize.CompareTo(left.CompressedSize)); + prefetchCount = Math.Min(prefetchCount, candidates.Count); + + int prefetchBufferSize = options.ReaderBufferSize > 0 + ? Math.Max(64 << 10, options.ReaderBufferSize) + : 1 << 20; + for (int candidateIndex = 0; candidateIndex < prefetchCount; candidateIndex++) + { + int streamIndex = candidates[candidateIndex].Index; + streams[streamIndex] = new PrefetchedReadStream(streams[streamIndex], + prefetchBufferSize); + } + } + private static Stream CreateDecompressionStream( HDiffCompression compType, ChunkSizeInfo size, From 47707baefa91f32cbf75809d01e0a1b47e77b8e6 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 23 Aug 2026 23:26:26 +0700 Subject: [PATCH 21/72] Add reading support for Kuro Games HDiff format --- SharpHPatchZ/HPatch.UnmanagedExtern.cs | 17 +++-- SharpHPatchZ/HPatch.cs | 13 +++- SharpHPatchZ/Header/HDiffInfo.cs | 9 ++- SharpHPatchZ/Header/HeaderReader.cs | 76 +++++++++++++------ .../Header/Metadata/DirectoryPatchMetadata.cs | 4 + SharpHPatchZ/InitializeOptions.cs | 16 ++++ 6 files changed, 97 insertions(+), 38 deletions(-) create mode 100644 SharpHPatchZ/InitializeOptions.cs diff --git a/SharpHPatchZ/HPatch.UnmanagedExtern.cs b/SharpHPatchZ/HPatch.UnmanagedExtern.cs index 7ec7047..c18eb3a 100644 --- a/SharpHPatchZ/HPatch.UnmanagedExtern.cs +++ b/SharpHPatchZ/HPatch.UnmanagedExtern.cs @@ -52,11 +52,12 @@ public static unsafe int SharpHPatchZ_ReadHeaderSignatureStringAuto(void* signat } [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_init_from_memory")] - public static unsafe int SharpHPatchZ_InitializeFromMemory(byte* dataP, long dataLength, HDiffInfo* signP) + public static unsafe int SharpHPatchZ_InitializeFromMemory(byte* dataP, long dataLength, HDiffInfo* signP, InitializeOptions* initializeOptionsP) { try { - HDiffInfo thisInfo = CreateInstance(CreateUnmanagedStreamWrapper); + InitializeOptions initializeOptions = initializeOptionsP != null ? *initializeOptionsP : default; + HDiffInfo thisInfo = CreateInstance(CreateUnmanagedStreamWrapper, initializeOptions); thisInfo.CopyTo(signP); return 0; @@ -75,17 +76,18 @@ public static unsafe int SharpHPatchZ_InitializeFromMemory(byte* dataP, long dat } [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_init_from_filepath")] - public static unsafe int SharpHPatchZ_InitializeFromFilePathAuto(void* pathP, HDiffInfo* signP) + public static unsafe int SharpHPatchZ_InitializeFromFilePathAuto(void* pathP, HDiffInfo* signP, InitializeOptions* initializeOptionsP) { try { - string? filePath = StringExtension.GetManagedStringAuto(pathP); + string? filePath = StringExtension.GetManagedStringAuto(pathP); if (filePath == null) { throw ExceptionHelper.ThrowHDiffPathIsEmptyOrInvalid(); } - HDiffInfo thisInfo = CreateInstance(pos => CreateFileStreamWrapper(filePath, pos)); + InitializeOptions initializeOptions = initializeOptionsP != null ? *initializeOptionsP : default; + HDiffInfo thisInfo = CreateInstance(pos => CreateFileStreamWrapper(filePath, pos), initializeOptions); thisInfo.CopyTo(signP); return 0; @@ -97,7 +99,7 @@ public static unsafe int SharpHPatchZ_InitializeFromFilePathAuto(void* pathP, HD } [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_init_from_FILE")] - public static unsafe int SharpHPatchZ_InitializeFromFILE(void* FILEP, HDiffInfo* signP) + public static unsafe int SharpHPatchZ_InitializeFromFILE(void* FILEP, HDiffInfo* signP, InitializeOptions* initializeOptionsP) { try { @@ -106,7 +108,8 @@ public static unsafe int SharpHPatchZ_InitializeFromFILE(void* FILEP, HDiffInfo* throw ExceptionHelper.ThrowHDiffFILEDescriptorNull(); } - HDiffInfo thisInfo = CreateInstance(pos => CreateFileStreamWrapper(FILEP, pos)); + InitializeOptions initializeOptions = initializeOptionsP != null ? *initializeOptionsP : default; + HDiffInfo thisInfo = CreateInstance(pos => CreateFileStreamWrapper(FILEP, pos), initializeOptions); thisInfo.CopyTo(signP); return 0; diff --git a/SharpHPatchZ/HPatch.cs b/SharpHPatchZ/HPatch.cs index c836392..f4e771c 100644 --- a/SharpHPatchZ/HPatch.cs +++ b/SharpHPatchZ/HPatch.cs @@ -14,7 +14,8 @@ namespace SharpHPatchZ; public static partial class HPatch { - public static HDiffInfo CreateInstance(CreateStream createPatchStream) + public static HDiffInfo CreateInstance(CreateStream createPatchStream, + InitializeOptions initializeOptions = default) { try { @@ -24,7 +25,7 @@ public static HDiffInfo CreateInstance(CreateStream createPatchStream) string signature = reader.ReadStringToNull(); HDiffInfo info = default; HeaderReader.ReadHeaderSignature(signature, ref info); - HeaderReader.ReadHDiffHeaderMetadata(ref info, reader); + HeaderReader.ReadHDiffHeaderMetadata(ref info, reader, initializeOptions); return info; } @@ -34,8 +35,14 @@ public static HDiffInfo CreateInstance(CreateStream createPatchStream) } } + public static ValueTask CreateInstanceAsync( + CreateStreamAsync createPatchStreamAsync, + CancellationToken token = default) + => CreateInstanceAsync(createPatchStreamAsync, default, token); + public static async ValueTask CreateInstanceAsync( CreateStreamAsync createPatchStreamAsync, + InitializeOptions initializeOptions, CancellationToken token = default) { (Stream stream, bool leaveOpen) = await createPatchStreamAsync(0, token); @@ -47,7 +54,7 @@ public static async ValueTask CreateInstanceAsync( string signature = await reader.ReadStringToNullAsync(token: token); HDiffInfo info = default; HeaderReader.ReadHeaderSignature(signature, ref info); - info = await HeaderReader.ReadHDiffHeaderMetadataAsync(info, reader, token); + info = await HeaderReader.ReadHDiffHeaderMetadataAsync(info, reader, initializeOptions, token); return info; } diff --git a/SharpHPatchZ/Header/HDiffInfo.cs b/SharpHPatchZ/Header/HDiffInfo.cs index e03f2f1..e3609bc 100644 --- a/SharpHPatchZ/Header/HDiffInfo.cs +++ b/SharpHPatchZ/Header/HDiffInfo.cs @@ -9,10 +9,11 @@ namespace SharpHPatchZ.Header; [StructLayout(LayoutKind.Sequential)] public unsafe struct HDiffInfo : IDisposable { - public HDiffMagic MagicType; - public HDiffCompression CompressionType; - public HDiffChecksum ChecksumType; - public void* MetadataP; + public HDiffMagic MagicType; + public HDiffCompression CompressionType; + public HDiffChecksum ChecksumType; + public InitializeOptions InitializeOptions; + public void* MetadataP; public ref T MetadataAs() where T : unmanaged, IMetadataInit diff --git a/SharpHPatchZ/Header/HeaderReader.cs b/SharpHPatchZ/Header/HeaderReader.cs index 8b538fe..91c1c14 100644 --- a/SharpHPatchZ/Header/HeaderReader.cs +++ b/SharpHPatchZ/Header/HeaderReader.cs @@ -95,8 +95,10 @@ internal static void ReadBasicHeaderSignature( internal static void ReadHDiffHeaderMetadata( ref HDiffInfo info, - BittableStreamReader streamReader) + BittableStreamReader streamReader, + InitializeOptions initializeOptions) { + info.InitializeOptions = initializeOptions; PatchMetadataAllocator patchMetadataAllocator = DefaultPatchMetadataAllocator; switch (info.MagicType) { @@ -114,8 +116,10 @@ internal static void ReadHDiffHeaderMetadata( internal static async Task ReadHDiffHeaderMetadataAsync( HDiffInfo info, BittableStreamReader streamReader, + InitializeOptions initializeOptions, CancellationToken token) { + info.InitializeOptions = initializeOptions; PatchMetadataAllocator patchMetadataAllocator = DefaultPatchMetadataAllocator; switch (info.MagicType) { @@ -194,13 +198,23 @@ private static unsafe void ReadHDiff19HeaderInfoCore( long headDataStartOffset = streamReader.Offset; - UnmanagedArray* inputPathEntryArray = streamReader.CreateUnmanagedStringList(inputPathEntryCount, (int)inputPathEntryBufferSize); - UnmanagedArray* outputPathEntryArray = streamReader.CreateUnmanagedStringList(outputPathEntryCount, (int)outputPathEntryBufferSize); - UnmanagedArray* inputFilesIndexArray = streamReader.CreateUnmanagedInt64As32List(inputRefFileCount); - UnmanagedArray* outputFilesIndexArray = streamReader.CreateUnmanagedInt64As32List(outputRefFileCount); - UnmanagedArray* outputFilesSizesArray = streamReader.CreateUnmanagedInt64List(outputRefFileCount); - FileIndexPair* sameFilePathIndexPairArray = streamReader.CreateUnmanagedIndexPairList(sameFilePathEntryCount); - UnmanagedArray* newExecuteListArray = streamReader.CreateUnmanagedInt64As32List(newExecuteCount); + UnmanagedArray* inputPathEntryArray = streamReader.CreateUnmanagedStringList(inputPathEntryCount, (int)inputPathEntryBufferSize); + UnmanagedArray* outputPathEntryArray = streamReader.CreateUnmanagedStringList(outputPathEntryCount, (int)outputPathEntryBufferSize); + UnmanagedArray* inputFilesIndexArray = streamReader.CreateUnmanagedInt64As32List(inputRefFileCount); + UnmanagedArray* outputFilesIndexArray = streamReader.CreateUnmanagedInt64As32List(outputRefFileCount); + + UnmanagedArray* inputFilesSizesArray = null; + if (info.InitializeOptions.IsKuroGamesHDiff) + inputFilesSizesArray = streamReader.CreateUnmanagedInt64List(inputRefFileCount); + + UnmanagedArray* outputFilesSizesArray = streamReader.CreateUnmanagedInt64List(outputRefFileCount); + + UnmanagedArray* outputFilesHashesArray = null; + if (info.InitializeOptions.IsKuroGamesHDiff) + outputFilesHashesArray = streamReader.CreateUnmanagedInt64List(outputRefFileCount); + + FileIndexPair* sameFilePathIndexPairArray = streamReader.CreateUnmanagedIndexPairList(sameFilePathEntryCount); + UnmanagedArray* newExecuteListArray = streamReader.CreateUnmanagedInt64As32List(newExecuteCount); if (streamReader.Offset - headDataStartOffset != headDataSize) { @@ -231,11 +245,13 @@ private static unsafe void ReadHDiff19HeaderInfoCore( dirTypeMetadata.SameFilePathIndexPairP = sameFilePathIndexPairArray; dirTypeMetadata.NewExecuteListP = newExecuteListArray; - dirTypeMetadata.InputPathListP = inputPathEntryArray; - dirTypeMetadata.OutputPathListP = outputPathEntryArray; - dirTypeMetadata.InputFileIndexListP = inputFilesIndexArray; - dirTypeMetadata.OutputFileIndexListP = outputFilesIndexArray; - dirTypeMetadata.OutputFileSizeListP = outputFilesSizesArray; + dirTypeMetadata.InputPathListP = inputPathEntryArray; + dirTypeMetadata.OutputPathListP = outputPathEntryArray; + dirTypeMetadata.InputFileIndexListP = inputFilesIndexArray; + dirTypeMetadata.InputFileSizeListP = inputFilesSizesArray; + dirTypeMetadata.OutputFileIndexListP = outputFilesIndexArray; + dirTypeMetadata.OutputFileSizeListP = outputFilesSizesArray; + dirTypeMetadata.OutputFileHashesListP = outputFilesHashesArray; externSizeInfo->NewExecuteCount = newExecuteCount; externSizeInfo->PrivateReservedDataSize = privateReservedDataSize; @@ -292,13 +308,23 @@ private static async Task ReadHDiff19HeaderInfoAsyncCore( long headDataStartOffset = streamReader.Offset; - nint inputPathEntryArray = await streamReader.CreateUnmanagedStringListAsync(inputPathEntryCount, (int)inputPathEntryBufferSize, token); - nint outputPathEntryArray = await streamReader.CreateUnmanagedStringListAsync(outputPathEntryCount, (int)outputPathEntryBufferSize, token); - nint inputFilesIndexArray = await streamReader.CreateUnmanagedInt64As32ListAsync(inputRefFileCount, token); - nint outputFilesIndexArray = await streamReader.CreateUnmanagedInt64As32ListAsync(outputRefFileCount, token); - nint outputFilesSizesArray = await streamReader.CreateUnmanagedInt64ListAsync(outputRefFileCount, token); + nint inputPathEntryArray = await streamReader.CreateUnmanagedStringListAsync(inputPathEntryCount, (int)inputPathEntryBufferSize, token); + nint outputPathEntryArray = await streamReader.CreateUnmanagedStringListAsync(outputPathEntryCount, (int)outputPathEntryBufferSize, token); + nint inputFilesIndexArray = await streamReader.CreateUnmanagedInt64As32ListAsync(inputRefFileCount, token); + nint outputFilesIndexArray = await streamReader.CreateUnmanagedInt64As32ListAsync(outputRefFileCount, token); + + nint inputFilesSizesArray = 0; + if (info.InitializeOptions.IsKuroGamesHDiff) + inputFilesSizesArray = await streamReader.CreateUnmanagedInt64ListAsync(inputRefFileCount, token); + + nint outputFilesSizesArray = await streamReader.CreateUnmanagedInt64ListAsync(outputRefFileCount, token); + + nint outputFilesHashesArray = 0; + if (info.InitializeOptions.IsKuroGamesHDiff) + outputFilesHashesArray = await streamReader.CreateUnmanagedInt64ListAsync(outputRefFileCount, token); + nint sameFilePathIndexPairArray = await streamReader.CreateUnmanagedIndexPairListAsync(sameFilePathEntryCount, token); - nint newExecuteListArray = await streamReader.CreateUnmanagedInt64As32ListAsync(newExecuteCount, token); + nint newExecuteListArray = await streamReader.CreateUnmanagedInt64As32ListAsync(newExecuteCount, token); if (streamReader.Offset - headDataStartOffset != headDataSize) { @@ -333,11 +359,13 @@ private static async Task ReadHDiff19HeaderInfoAsyncCore( dirTypeMetadata.SameFilePathIndexPairP = (FileIndexPair*)sameFilePathIndexPairArray; dirTypeMetadata.NewExecuteListP = (UnmanagedArray*)newExecuteListArray; - dirTypeMetadata.InputPathListP = (UnmanagedArray*)inputPathEntryArray; - dirTypeMetadata.OutputPathListP = (UnmanagedArray*)outputPathEntryArray; - dirTypeMetadata.InputFileIndexListP = (UnmanagedArray*)inputFilesIndexArray; - dirTypeMetadata.OutputFileIndexListP = (UnmanagedArray*)outputFilesIndexArray; - dirTypeMetadata.OutputFileSizeListP = (UnmanagedArray*)outputFilesSizesArray; + dirTypeMetadata.InputPathListP = (UnmanagedArray*)inputPathEntryArray; + dirTypeMetadata.OutputPathListP = (UnmanagedArray*)outputPathEntryArray; + dirTypeMetadata.InputFileIndexListP = (UnmanagedArray*)inputFilesIndexArray; + dirTypeMetadata.InputFileSizeListP = (UnmanagedArray*)inputFilesSizesArray; + dirTypeMetadata.OutputFileIndexListP = (UnmanagedArray*)outputFilesIndexArray; + dirTypeMetadata.OutputFileSizeListP = (UnmanagedArray*)outputFilesSizesArray; + dirTypeMetadata.OutputFileHashesListP = (UnmanagedArray*)outputFilesHashesArray; externSizeInfo->NewExecuteCount = newExecuteCount; externSizeInfo->PrivateReservedDataSize = privateReservedDataSize; diff --git a/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs b/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs index d785682..bb9f26a 100644 --- a/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs +++ b/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs @@ -47,8 +47,10 @@ public void Dispose() MemoryAlloc.Free(InputPathListP); MemoryAlloc.Free(OutputPathListP); MemoryAlloc.Free(InputFileIndexListP); + MemoryAlloc.Free(InputFileSizeListP); MemoryAlloc.Free(OutputFileIndexListP); MemoryAlloc.Free(OutputFileSizeListP); + MemoryAlloc.Free(OutputFileHashesListP); MemoryAlloc.Free(ExternSizeInfoP); @@ -86,8 +88,10 @@ public bool IsDisposed public UnmanagedArray* InputPathListP; public UnmanagedArray* OutputPathListP; public UnmanagedArray* InputFileIndexListP; + public UnmanagedArray* InputFileSizeListP; public UnmanagedArray* OutputFileIndexListP; public UnmanagedArray* OutputFileSizeListP; + public UnmanagedArray* OutputFileHashesListP; // Seems unused. // TODO: See original code to see what it is. diff --git a/SharpHPatchZ/InitializeOptions.cs b/SharpHPatchZ/InitializeOptions.cs new file mode 100644 index 0000000..f858fed --- /dev/null +++ b/SharpHPatchZ/InitializeOptions.cs @@ -0,0 +1,16 @@ +using System.Runtime.InteropServices; +// ReSharper disable IdentifierTypo + +namespace SharpHPatchZ; + +[StructLayout(LayoutKind.Sequential)] +public struct InitializeOptions() +{ + private int _isKuroGamesHDiff = 0; + + public bool IsKuroGamesHDiff + { + get => _isKuroGamesHDiff > 0; + set => _isKuroGamesHDiff = value ? 1 : 0; + } +} From ebd84ed9fdfda5cb7ad0f3058e656f772721c541 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 23 Aug 2026 23:35:17 +0700 Subject: [PATCH 22/72] Add input size sanity test for Kuro HDiff format --- SharpHPatchZ/Extension/ExceptionHelper.cs | 8 ++++++++ SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/SharpHPatchZ/Extension/ExceptionHelper.cs b/SharpHPatchZ/Extension/ExceptionHelper.cs index 9227a0e..41f62cf 100644 --- a/SharpHPatchZ/Extension/ExceptionHelper.cs +++ b/SharpHPatchZ/Extension/ExceptionHelper.cs @@ -32,7 +32,9 @@ file static class Const { HDiffPathIsEmptyOrInvalid, 0x52 }, { HDiffIOException, 0x53 }, { HDiffPatchInputPathNotExist, 0x54 }, + { HDiffPatchKuroInputPathNotExist, 0x54 }, { HDiffPatchInputSizeMismatched, 0x55 }, + { HDiffPatchKuroInputSizeMismatched, 0x55 }, { HDiffPatchPathNotADirectory, 0x56 }, { HDiffPatchPathNotAFile, 0x57 }, { HDiffPatchInputFilesMismatched, 0x58 }, @@ -61,7 +63,9 @@ file static class Const public const string HDiffPathIsEmptyOrInvalid = "HDIFF_PathIsEmptyOrInvalid"; public const string HDiffIOException = "HDIFF_IOException"; public const string HDiffPatchInputPathNotExist = "HDIFF_PatchInputPathNotExist"; + public const string HDiffPatchKuroInputPathNotExist = "HDIFF_PatchKuroInputPathNotExist"; public const string HDiffPatchInputSizeMismatched = "HDIFF_PatchInputSizeMismatched"; + public const string HDiffPatchKuroInputSizeMismatched = "HDIFF_PatchKuroInputSizeMismatched"; public const string HDiffPatchPathNotADirectory = "HDIFF_PatchPathNotADirectory"; public const string HDiffPatchPathNotAFile = "HDIFF_PatchPathNotAFile"; public const string HDiffPatchInputFilesMismatched = "HDIFF_PatchInputFilesMismatched"; @@ -107,8 +111,12 @@ public static IOException ThrowHDiffIOException(Exception ex) => new($"[{Const.HDiffIOException}] An IO Error has occurred with message: {ex.Message}", ex); public static FileNotFoundException ThrowHDiffPatchInputPathNotExist(string filePath) => new($"[{Const.HDiffPatchInputPathNotExist}] Input path does not exist: {filePath}", filePath); + public static FileNotFoundException ThrowHDiffPatchKuroInputPathNotExist(string filePath) + => new($"[{Const.HDiffPatchKuroInputPathNotExist}] Kuro Games Patch input path does not exist: {filePath}", filePath); public static InvalidOperationException ThrowHDiffPatchInputSizeMismatched(string filePath, long existingSize, long expectingSize) => new($"[{Const.HDiffPatchInputSizeMismatched}] Input file size does not match: {filePath} (Expecting: {expectingSize} bytes, but got: {existingSize} instead)."); + public static InvalidOperationException ThrowHDiffPatchKuroInputSizeMismatched(string filePath, long existingSize, long expectingSize) + => new($"[{Const.HDiffPatchKuroInputSizeMismatched}] Kuro Games Patch input file size does not match: {filePath} (Expecting: {expectingSize} bytes, but got: {existingSize} instead)."); public static InvalidOperationException ThrowHDiffPatchPathNotADirectory(string path) => new($"[{Const.HDiffPatchPathNotADirectory}] Path is not a directory!: {path}"); public static InvalidOperationException ThrowHDiffPatchPathNotAFile(string path) diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs index 69f5173..9d80634 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs @@ -164,6 +164,25 @@ private unsafe void InitializeInputOutputStream(string inputPath, string outputP throw ExceptionHelper.ThrowHDiffPatchInputFilesMismatched(lastInputFileEnds, refInputTotalSize); } + // -- Reference Input Size sanity for Kuro Games HDiff format + if (Info.InitializeOptions.IsKuroGamesHDiff) + { + Span inputFileSizes = dirMetadata.InputFileSizeListP->GetSpan(); + for (int i = 0; i < refInputCount; i++) + { + ref long expectedOldRefSize = ref inputFileSizes[i]; + + string filePath = refInputFiles[i]; + FileInfo fileInfo = new(filePath); + + if (!fileInfo.Exists) + throw ExceptionHelper.ThrowHDiffPatchKuroInputPathNotExist(filePath); + + if (fileInfo.Length != expectedOldRefSize) + throw ExceptionHelper.ThrowHDiffPatchKuroInputSizeMismatched(filePath, fileInfo.Length, expectedOldRefSize); + } + } + // -- Reference Output Span refOutputFileIndexSpan = dirMetadata.OutputFileIndexListP->GetSpan(); Span refOutputFileSizeSpan = dirMetadata.OutputFileSizeListP->GetSpan(); From b7112dc04f779dab6ec854e2a5260e17991bf9e8 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 23 Aug 2026 23:36:36 +0700 Subject: [PATCH 23/72] Update ExceptionHelper.cs --- SharpHPatchZ/Extension/ExceptionHelper.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/SharpHPatchZ/Extension/ExceptionHelper.cs b/SharpHPatchZ/Extension/ExceptionHelper.cs index 41f62cf..ef27f10 100644 --- a/SharpHPatchZ/Extension/ExceptionHelper.cs +++ b/SharpHPatchZ/Extension/ExceptionHelper.cs @@ -4,7 +4,8 @@ using System.Text; using System.Threading; using SharpHPatchZ.Header; - +// ReSharper disable StringLiteralTypo +// ReSharper disable IdentifierTypo // ReSharper disable InconsistentNaming namespace SharpHPatchZ.Extension; From 15271bebdde8fb6168e49a32fa0e442e03d2a561 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sun, 23 Aug 2026 23:45:02 +0700 Subject: [PATCH 24/72] Inline input file size check for Kuro Games format --- SharpHPatchZ/Extension/ExceptionHelper.cs | 12 ++---- SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs | 45 +++++++++++---------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/SharpHPatchZ/Extension/ExceptionHelper.cs b/SharpHPatchZ/Extension/ExceptionHelper.cs index ef27f10..395ebd1 100644 --- a/SharpHPatchZ/Extension/ExceptionHelper.cs +++ b/SharpHPatchZ/Extension/ExceptionHelper.cs @@ -33,12 +33,11 @@ file static class Const { HDiffPathIsEmptyOrInvalid, 0x52 }, { HDiffIOException, 0x53 }, { HDiffPatchInputPathNotExist, 0x54 }, - { HDiffPatchKuroInputPathNotExist, 0x54 }, { HDiffPatchInputSizeMismatched, 0x55 }, - { HDiffPatchKuroInputSizeMismatched, 0x55 }, { HDiffPatchPathNotADirectory, 0x56 }, { HDiffPatchPathNotAFile, 0x57 }, { HDiffPatchInputFilesMismatched, 0x58 }, + { HDiffPatchKuroInputFileSizeMismatched, 0x59 }, // Decompression Initialization { HDiffCompLZMAPropertyMissing, 0xA0 }, @@ -64,12 +63,11 @@ file static class Const public const string HDiffPathIsEmptyOrInvalid = "HDIFF_PathIsEmptyOrInvalid"; public const string HDiffIOException = "HDIFF_IOException"; public const string HDiffPatchInputPathNotExist = "HDIFF_PatchInputPathNotExist"; - public const string HDiffPatchKuroInputPathNotExist = "HDIFF_PatchKuroInputPathNotExist"; public const string HDiffPatchInputSizeMismatched = "HDIFF_PatchInputSizeMismatched"; - public const string HDiffPatchKuroInputSizeMismatched = "HDIFF_PatchKuroInputSizeMismatched"; public const string HDiffPatchPathNotADirectory = "HDIFF_PatchPathNotADirectory"; public const string HDiffPatchPathNotAFile = "HDIFF_PatchPathNotAFile"; public const string HDiffPatchInputFilesMismatched = "HDIFF_PatchInputFilesMismatched"; + public const string HDiffPatchKuroInputFileSizeMismatched = "HDIFF_PatchKuroInputFileSizeMismatched"; public const string HDiffCompLZMAPropertyMissing = "HDIFF_CompLZMAPropertyMissing"; public const string HDiffCompLZMA2DictionaryInvalid = "HDIFF_CompLZMA2DictionaryInvalid"; @@ -112,18 +110,16 @@ public static IOException ThrowHDiffIOException(Exception ex) => new($"[{Const.HDiffIOException}] An IO Error has occurred with message: {ex.Message}", ex); public static FileNotFoundException ThrowHDiffPatchInputPathNotExist(string filePath) => new($"[{Const.HDiffPatchInputPathNotExist}] Input path does not exist: {filePath}", filePath); - public static FileNotFoundException ThrowHDiffPatchKuroInputPathNotExist(string filePath) - => new($"[{Const.HDiffPatchKuroInputPathNotExist}] Kuro Games Patch input path does not exist: {filePath}", filePath); public static InvalidOperationException ThrowHDiffPatchInputSizeMismatched(string filePath, long existingSize, long expectingSize) => new($"[{Const.HDiffPatchInputSizeMismatched}] Input file size does not match: {filePath} (Expecting: {expectingSize} bytes, but got: {existingSize} instead)."); - public static InvalidOperationException ThrowHDiffPatchKuroInputSizeMismatched(string filePath, long existingSize, long expectingSize) - => new($"[{Const.HDiffPatchKuroInputSizeMismatched}] Kuro Games Patch input file size does not match: {filePath} (Expecting: {expectingSize} bytes, but got: {existingSize} instead)."); public static InvalidOperationException ThrowHDiffPatchPathNotADirectory(string path) => new($"[{Const.HDiffPatchPathNotADirectory}] Path is not a directory!: {path}"); public static InvalidOperationException ThrowHDiffPatchPathNotAFile(string path) => new($"[{Const.HDiffPatchPathNotAFile}] Path is not a file!: {path}"); public static InvalidOperationException ThrowHDiffPatchInputFilesMismatched(long existingSize, long expectingSize) => new($"[{Const.HDiffPatchInputFilesMismatched}] Input file size mismatched! Expecting: {expectingSize} bytes but got: {expectingSize} bytes instead."); + public static InvalidOperationException ThrowHDiffPatchKuroInputFileSizeMismatched(string filePath, long existingSize, long expectingSize) + => new($"[{Const.HDiffPatchKuroInputFileSizeMismatched}] Kuro Games Patch input file size does not match: {filePath} (Expecting: {expectingSize} bytes, but got: {existingSize} instead)."); public static InvalidDataException ThrowHDiffCompLZMAPropertyMissing() => new($"[{Const.HDiffCompLZMAPropertyMissing}] The LZMA stream is missing its properties."); diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs index 9d80634..3f0919a 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs @@ -7,6 +7,7 @@ using SharpHPatchZ.Header; using SharpHPatchZ.Header.Metadata; using SharpHPatchZ.IO.Reader; +// ReSharper disable CommentTypo namespace SharpHPatchZ.Patch; @@ -46,7 +47,11 @@ public override void StartPatch(string inputPath, string outputPath, Cancellatio } catch (OperationCanceledException) when (token.IsCancellationRequested) { +#if NET6_0_OR_GREATER + copyOverTcs.SetCanceled(token); +#else copyOverTcs.SetCanceled(); +#endif } catch (Exception ex) { @@ -63,7 +68,11 @@ public override void StartPatch(string inputPath, string outputPath, Cancellatio } catch (OperationCanceledException) when (token.IsCancellationRequested) { - corePatcherTcs.SetCanceled(); +#if NET6_0_OR_GREATER + copyOverTcs.SetCanceled(token); +#else + copyOverTcs.SetCanceled(); +#endif } catch (Exception ex) { @@ -152,9 +161,20 @@ private unsafe void InitializeInputOutputStream(string inputPath, string outputP string filePath = refInputFiles[i]; FileInfo fileInfo = new(filePath); - long fileSize = fileInfo.Exists ? fileInfo.Length : 0; - lastInputFileEnds += fileSize; + if (!fileInfo.Exists) + throw ExceptionHelper.ThrowHDiffPatchInputPathNotExist(filePath); + + // -- Additional size check reference for Kuro Games HDiff format. + if (Info.InitializeOptions.IsKuroGamesHDiff && + dirMetadata.InputFileSizeListP != null) + { + ref long expectedOldRefSize = ref dirMetadata.InputFileSizeListP->GetSpan()[i]; + if (fileInfo.Length != expectedOldRefSize) + throw ExceptionHelper.ThrowHDiffPatchKuroInputFileSizeMismatched(filePath, fileInfo.Length, expectedOldRefSize); + } + + lastInputFileEnds += fileInfo.Length; refInputFilesSize[i] = lastInputFileEnds; } @@ -164,25 +184,6 @@ private unsafe void InitializeInputOutputStream(string inputPath, string outputP throw ExceptionHelper.ThrowHDiffPatchInputFilesMismatched(lastInputFileEnds, refInputTotalSize); } - // -- Reference Input Size sanity for Kuro Games HDiff format - if (Info.InitializeOptions.IsKuroGamesHDiff) - { - Span inputFileSizes = dirMetadata.InputFileSizeListP->GetSpan(); - for (int i = 0; i < refInputCount; i++) - { - ref long expectedOldRefSize = ref inputFileSizes[i]; - - string filePath = refInputFiles[i]; - FileInfo fileInfo = new(filePath); - - if (!fileInfo.Exists) - throw ExceptionHelper.ThrowHDiffPatchKuroInputPathNotExist(filePath); - - if (fileInfo.Length != expectedOldRefSize) - throw ExceptionHelper.ThrowHDiffPatchKuroInputSizeMismatched(filePath, fileInfo.Length, expectedOldRefSize); - } - } - // -- Reference Output Span refOutputFileIndexSpan = dirMetadata.OutputFileIndexListP->GetSpan(); Span refOutputFileSizeSpan = dirMetadata.OutputFileSizeListP->GetSpan(); From 522b43c4a3ff03ea00d6bd9dc90daad5fad726a2 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 00:33:00 +0700 Subject: [PATCH 25/72] Remove old project and full switch to SharpHPatchZ --- .../Binary/BinaryExtensions.cs | 282 ---- .../Compression/BZip2/BZip2Constants.cs | 159 -- .../Binary/Compression/BZip2/BZip2Crc32.cs | 421 ------ .../Compression/BZip2/BZip2Exception.cs | 54 - .../Compression/BZip2/BZip2InputStream.cs | 1321 ----------------- .../Binary/Compression/BZip2/LICENSE | 17 - .../Binary/Compression/BZip2/README.md | 23 - .../Compression/CompressionStreamHelper.cs | 140 -- .../Binary/Compression/Lzma/LICENSE.txt | 21 - .../Binary/Compression/Lzma/LZ/LzOutWindow.cs | 269 ---- .../Binary/Compression/Lzma/LzmaBase.cs | 70 - .../Binary/Compression/Lzma/LzmaDecoder.cs | 460 ------ .../Binary/Compression/Lzma/LzmaExceptions.cs | 13 - .../Compression/Lzma/LzmaInputStream.cs | 287 ---- .../Binary/Compression/Lzma/README.md | 18 - .../Compression/Lzma/RangeCoder/RangeCoder.cs | 136 -- .../Lzma/RangeCoder/RangeCoderBit.cs | 55 - .../Lzma/RangeCoder/RangeCoderBitTree.cs | 60 - .../Binary/Streams/ChunkStream.cs | 176 --- .../Binary/Streams/CombinedStream.cs | 672 --------- SharpHDiffPatch.Core/Event/PatchEvent.cs | 67 - SharpHDiffPatch.Core/Extern.cs | 58 - SharpHDiffPatch.Core/HDiffPatch.cs | 243 --- SharpHDiffPatch.Core/Patch/Header.cs | 273 ---- SharpHDiffPatch.Core/Patch/IPatch.cs | 8 - SharpHDiffPatch.Core/Patch/PatchCore.cs | 638 -------- .../Patch/PatchCoreFastBuffer.cs | 368 ----- SharpHDiffPatch.Core/Patch/PatchDir.cs | 348 ----- SharpHDiffPatch.Core/Patch/PatchSingle.cs | 93 -- SharpHDiffPatch.Core/Patch/PatchSizeHelper.cs | 58 - .../SharpHDiffPatch.Core.csproj | 48 - SharpHDiffPatch.sln | 70 +- SharpHDiffPatch/Program.cs | 211 --- .../Properties/launchSettings.json | 8 - SharpHPatchZ.Program/Program.cs | 185 +++ .../Properties/launchSettings.json | 8 + .../SharpHPatchZ.Program.csproj | 7 +- .../System.CommandLine/Argument.cs | 0 .../System.CommandLine/ArgumentArity.cs | 0 .../System.CommandLine/ArgumentExtensions.cs | 0 .../System.CommandLine/Argument{T}.cs | 0 .../Binding/ArgumentConversionResult.cs | 0 .../Binding/ArgumentConversionResultType.cs | 0 .../ArgumentConverter.DefaultValues.cs | 0 .../ArgumentConverter.StringConverters.cs | 0 .../Binding/ArgumentConverter.cs | 0 .../Binding/BinderBase{T}.cs | 0 .../Binding/BindingContext.cs | 0 .../System.CommandLine/Binding/BoundValue.cs | 0 .../Binding/IValueDescriptor.cs | 0 .../Binding/IValueDescriptor{T}.cs | 0 .../Binding/IValueSource.cs | 0 .../Binding/ServiceProviderExtensions.cs | 0 .../Binding/ServiceProviderValueSource.cs | 0 .../Binding/TryConvertArgument.cs | 0 .../Binding/TypeExtensions.cs | 0 .../ValueDescriptorDefaultValueSource.cs | 0 .../Builder/CommandLineBuilder.cs | 0 .../Builder/CommandLineBuilderExtensions.cs | 0 .../System.CommandLine/Command.cs | 0 .../System.CommandLine/CommandExtensions.cs | 0 .../CommandLineConfiguration.cs | 0 .../CommandLineConfigurationException.cs | 0 .../CompletionSourceExtensions.cs | 0 .../CompletionSourceList.cs | 0 .../Completions/AnonymousCompletionSource.cs | 0 .../Completions/CompletionContext.cs | 0 .../Completions/CompletionDelegate.cs | 0 .../Completions/CompletionItem.cs | 0 .../Completions/CompletionItemKind.cs | 0 .../Completions/CompletionSource.cs | 0 .../Completions/ICompletionSource.cs | 0 .../Completions/TextCompletionContext.cs | 0 .../Completions/TokenCompletionContext.cs | 0 .../System.CommandLine/ConsoleExtensions.cs | 0 .../System.CommandLine/DebugAssert.cs | 0 .../DictionaryExtensions.cs | 0 .../System.CommandLine/DirectiveCollection.cs | 0 .../EnumerableExtensions.cs | 0 .../System.CommandLine/Handler.Action.cs | 0 .../System.CommandLine/Handler.Func.cs | 0 .../System.CommandLine/Handler.cs | 0 .../Help/HelpBuilder.Default.cs | 0 .../System.CommandLine/Help/HelpBuilder.cs | 0 .../Help/HelpBuilderExtensions.cs | 0 .../System.CommandLine/Help/HelpContext.cs | 0 .../System.CommandLine/Help/HelpOption.cs | 0 .../System.CommandLine/Help/HelpResult.cs | 0 .../Help/HelpSectionDelegate.cs | 0 .../Help/TwoColumnHelpRow.cs | 0 .../System.CommandLine/Help/VersionOption.cs | 0 .../System.CommandLine/IConsole.cs | 0 .../IO/ConsoleExtensions.cs | 0 .../System.CommandLine/IO/IStandardError.cs | 0 .../System.CommandLine/IO/IStandardIn.cs | 0 .../System.CommandLine/IO/IStandardOut.cs | 0 .../IO/IStandardStreamWriter.cs | 0 .../IO/StandardStreamWriter.cs | 0 .../System.CommandLine/IO/SystemConsole.cs | 0 .../System.CommandLine/IO/TestConsole.cs | 0 .../System.CommandLine/IdentifierSymbol.cs | 0 .../Invocation/AnonymousCommandHandler.cs | 0 .../Invocation/FeatureRegistration.cs | 0 .../Invocation/ICommandHandler.cs | 0 .../Invocation/IInvocationResult.cs | 0 .../Invocation/InvocationContext.cs | 0 .../Invocation/InvocationMiddleware.cs | 0 .../Invocation/InvocationPipeline.cs | 0 .../Invocation/MiddlewareOrder.cs | 0 .../Invocation/ParseDirectiveResult.cs | 0 .../Invocation/ParseErrorResult.cs | 0 .../System.CommandLine/Invocation/Process.cs | 0 .../Invocation/ServiceProvider.cs | 0 .../Invocation/SuggestDirectiveResult.cs | 0 .../Invocation/TypoCorrection.cs | 0 .../LocalizationResources.cs | 0 .../System.CommandLine/Option.cs | 0 .../System.CommandLine/OptionExtensions.cs | 0 .../System.CommandLine/Option{T}.cs | 0 .../System.CommandLine/ParentNode.cs | 0 .../Parsing/ArgumentResult.cs | 0 .../Parsing/CommandArgumentNode.cs | 0 .../Parsing/CommandLineStringSplitter.cs | 0 .../System.CommandLine/Parsing/CommandNode.cs | 0 .../Parsing/CommandResult.cs | 0 .../Parsing/DirectiveNode.cs | 0 .../Parsing/NonterminalSyntaxNode.cs | 0 .../Parsing/OptionArgumentNode.cs | 0 .../System.CommandLine/Parsing/OptionNode.cs | 0 .../Parsing/OptionResult.cs | 0 .../Parsing/OptionResultExtensions.cs | 0 .../Parsing/ParseArgument{T}.cs | 0 .../System.CommandLine/Parsing/ParseError.cs | 0 .../Parsing/ParseOperation.cs | 0 .../System.CommandLine/Parsing/ParseResult.cs | 0 .../Parsing/ParseResultExtensions.cs | 0 .../Parsing/ParseResultVisitor.cs | 0 .../System.CommandLine/Parsing/Parser.cs | 0 .../Parsing/ParserExtensions.cs | 0 .../Parsing/RootCommandResult.cs | 0 .../Parsing/StringExtensions.cs | 0 .../Parsing/SymbolResult.cs | 0 .../Parsing/SymbolResultExtensions.cs | 0 .../Parsing/SymbolResultVisitor.cs | 0 .../System.CommandLine/Parsing/SyntaxNode.cs | 0 .../System.CommandLine/Parsing/Token.cs | 0 .../System.CommandLine/Parsing/TokenType.cs | 0 .../Parsing/TokenizeResult.cs | 0 .../Parsing/TryReplaceToken.cs | 0 .../Parsing/ValidateSymbolResult.cs | 0 .../System.CommandLine/Platform.cs | 0 .../Properties/Resources.Designer.cs | 0 .../System.CommandLine/RootCommand.cs | 0 .../System.CommandLine/StringBuilderPool.cs | 0 .../System.CommandLine/Symbol.cs | 0 .../System.CommandLine/SymbolExtensions.cs | 0 .../DynamicallyAccessedMemberTypes.cs | 0 .../DynamicallyAccessedMembersAttribute.cs | 0 .../UnconditionalSuppressMessageAttribute.cs | 0 .../IsExternalInit.cs | 0 .../System.CommandLine/Validate.cs | 0 .../win-x64/Lib/win-x64/libzstd-bmi2.dll | Bin 0 -> 1254833 bytes .../win-x64/Lib/win-x64/libzstd.dll | Bin 0 -> 661504 bytes Test/Program.cs | 73 - Test/Test.csproj | 17 - 165 files changed, 214 insertions(+), 7221 deletions(-) delete mode 100644 SharpHDiffPatch.Core/Binary/BinaryExtensions.cs delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/BZip2/BZip2Constants.cs delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/BZip2/BZip2Crc32.cs delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/BZip2/BZip2Exception.cs delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/BZip2/BZip2InputStream.cs delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/BZip2/LICENSE delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/BZip2/README.md delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/CompressionStreamHelper.cs delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/Lzma/LICENSE.txt delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/Lzma/LZ/LzOutWindow.cs delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/Lzma/LzmaBase.cs delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/Lzma/LzmaDecoder.cs delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/Lzma/LzmaExceptions.cs delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/Lzma/LzmaInputStream.cs delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/Lzma/README.md delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/Lzma/RangeCoder/RangeCoder.cs delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/Lzma/RangeCoder/RangeCoderBit.cs delete mode 100644 SharpHDiffPatch.Core/Binary/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs delete mode 100644 SharpHDiffPatch.Core/Binary/Streams/ChunkStream.cs delete mode 100644 SharpHDiffPatch.Core/Binary/Streams/CombinedStream.cs delete mode 100644 SharpHDiffPatch.Core/Event/PatchEvent.cs delete mode 100644 SharpHDiffPatch.Core/Extern.cs delete mode 100644 SharpHDiffPatch.Core/HDiffPatch.cs delete mode 100644 SharpHDiffPatch.Core/Patch/Header.cs delete mode 100644 SharpHDiffPatch.Core/Patch/IPatch.cs delete mode 100644 SharpHDiffPatch.Core/Patch/PatchCore.cs delete mode 100644 SharpHDiffPatch.Core/Patch/PatchCoreFastBuffer.cs delete mode 100644 SharpHDiffPatch.Core/Patch/PatchDir.cs delete mode 100644 SharpHDiffPatch.Core/Patch/PatchSingle.cs delete mode 100644 SharpHDiffPatch.Core/Patch/PatchSizeHelper.cs delete mode 100644 SharpHDiffPatch.Core/SharpHDiffPatch.Core.csproj delete mode 100644 SharpHDiffPatch/Program.cs delete mode 100644 SharpHDiffPatch/Properties/launchSettings.json create mode 100644 SharpHPatchZ.Program/Program.cs create mode 100644 SharpHPatchZ.Program/Properties/launchSettings.json rename SharpHDiffPatch/SharpHDiffPatch.csproj => SharpHPatchZ.Program/SharpHPatchZ.Program.csproj (67%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Argument.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/ArgumentArity.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/ArgumentExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Argument{T}.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Binding/ArgumentConversionResult.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Binding/ArgumentConversionResultType.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Binding/ArgumentConverter.DefaultValues.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Binding/ArgumentConverter.StringConverters.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Binding/ArgumentConverter.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Binding/BinderBase{T}.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Binding/BindingContext.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Binding/BoundValue.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Binding/IValueDescriptor.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Binding/IValueDescriptor{T}.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Binding/IValueSource.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Binding/ServiceProviderExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Binding/ServiceProviderValueSource.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Binding/TryConvertArgument.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Binding/TypeExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Binding/ValueDescriptorDefaultValueSource.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Builder/CommandLineBuilder.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Builder/CommandLineBuilderExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Command.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/CommandExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/CommandLineConfiguration.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/CommandLineConfigurationException.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/CompletionSourceExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/CompletionSourceList.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Completions/AnonymousCompletionSource.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Completions/CompletionContext.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Completions/CompletionDelegate.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Completions/CompletionItem.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Completions/CompletionItemKind.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Completions/CompletionSource.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Completions/ICompletionSource.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Completions/TextCompletionContext.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Completions/TokenCompletionContext.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/ConsoleExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/DebugAssert.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/DictionaryExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/DirectiveCollection.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/EnumerableExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Handler.Action.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Handler.Func.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Handler.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Help/HelpBuilder.Default.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Help/HelpBuilder.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Help/HelpBuilderExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Help/HelpContext.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Help/HelpOption.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Help/HelpResult.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Help/HelpSectionDelegate.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Help/TwoColumnHelpRow.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Help/VersionOption.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/IConsole.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/IO/ConsoleExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/IO/IStandardError.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/IO/IStandardIn.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/IO/IStandardOut.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/IO/IStandardStreamWriter.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/IO/StandardStreamWriter.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/IO/SystemConsole.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/IO/TestConsole.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/IdentifierSymbol.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Invocation/AnonymousCommandHandler.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Invocation/FeatureRegistration.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Invocation/ICommandHandler.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Invocation/IInvocationResult.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Invocation/InvocationContext.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Invocation/InvocationMiddleware.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Invocation/InvocationPipeline.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Invocation/MiddlewareOrder.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Invocation/ParseDirectiveResult.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Invocation/ParseErrorResult.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Invocation/Process.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Invocation/ServiceProvider.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Invocation/SuggestDirectiveResult.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Invocation/TypoCorrection.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/LocalizationResources.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Option.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/OptionExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Option{T}.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/ParentNode.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/ArgumentResult.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/CommandArgumentNode.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/CommandLineStringSplitter.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/CommandNode.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/CommandResult.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/DirectiveNode.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/NonterminalSyntaxNode.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/OptionArgumentNode.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/OptionNode.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/OptionResult.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/OptionResultExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/ParseArgument{T}.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/ParseError.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/ParseOperation.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/ParseResult.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/ParseResultExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/ParseResultVisitor.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/Parser.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/ParserExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/RootCommandResult.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/StringExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/SymbolResult.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/SymbolResultExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/SymbolResultVisitor.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/SyntaxNode.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/Token.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/TokenType.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/TokenizeResult.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/TryReplaceToken.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Parsing/ValidateSymbolResult.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Platform.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Properties/Resources.Designer.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/RootCommand.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/StringBuilderPool.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Symbol.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/SymbolExtensions.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/System.Diagnostics.CodeAnalysis/DynamicallyAccessedMemberTypes.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/System.Diagnostics.CodeAnalysis/DynamicallyAccessedMembersAttribute.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/System.Diagnostics.CodeAnalysis/UnconditionalSuppressMessageAttribute.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/System.Runtime.CompilerServices/IsExternalInit.cs (100%) rename {SharpHDiffPatch => SharpHPatchZ.Program}/System.CommandLine/Validate.cs (100%) create mode 100644 SharpHPatchZ.Program/compiledAot/win-x64/Lib/win-x64/libzstd-bmi2.dll create mode 100644 SharpHPatchZ.Program/compiledAot/win-x64/Lib/win-x64/libzstd.dll delete mode 100644 Test/Program.cs delete mode 100644 Test/Test.csproj diff --git a/SharpHDiffPatch.Core/Binary/BinaryExtensions.cs b/SharpHDiffPatch.Core/Binary/BinaryExtensions.cs deleted file mode 100644 index e0c5a05..0000000 --- a/SharpHDiffPatch.Core/Binary/BinaryExtensions.cs +++ /dev/null @@ -1,282 +0,0 @@ -using System; -using System.Buffers; -using System.IO; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Text; -using SharpHDiffPatch.Core.Patch; - -namespace SharpHDiffPatch.Core.Binary; - -internal static class BinaryExtensions -{ -#if NETSTANDARD2_0 || !NET7_0_OR_GREATER - public static int ReadExactly(this Stream stream, byte[] buffer, int offset, int count) - { - int totalRead = 0; - while (totalRead < count) - { - int read = stream.Read(buffer, offset + totalRead, count - totalRead); - if (read == 0) return totalRead; - - totalRead += read; - } - - return totalRead; - } -#endif - - public static string ReadStringToNull(this Stream reader, int bufferSize = 512) - { - int i = 0; - - ArrayPool pool = ArrayPool.Shared; - byte[] stringBuffer = pool.Rent(bufferSize); - - try - { - int currentValue; - while (stringBuffer.Length > i && (currentValue = reader.ReadByte()) > 0) - { - stringBuffer[i++] = (byte)currentValue; - } - - return Encoding.UTF8.GetString(stringBuffer, 0, i); - } - finally - { - pool.Return(stringBuffer); - } - } - - public static int ReadInt7Bit(this Stream inputStream, int tagBit = 0, byte prevTagBit = 0) - { - bool isUseTagBit = tagBit != 0; - - byte code = isUseTagBit ? prevTagBit : (byte)inputStream.ReadByte(); - int value = code & ((1 << (7 - tagBit)) - 1); - - if ((code & (1 << (7 - tagBit))) == 0) return value; - do - { - if (value >> (4 * 4 - 7) != 0) return 0; - code = (byte)inputStream.ReadByte(); - value = (value << 7) | (code & ((1 << 7) - 1)); - } - while ((code & (1 << 7)) != 0); - return value; - } - - public static long ReadLong7Bit(this Stream inputStream, int tagBit = 0, byte prevTagBit = 0) - { - bool isUseTagBit = tagBit != 0; - - byte code = isUseTagBit ? prevTagBit : (byte)inputStream.ReadByte(); - long value = code & ((1 << (7 - tagBit)) - 1); - - if ((code & (1 << (7 - tagBit))) == 0) return value; - do - { - if (value >> (8 * 8 - 7) != 0) return 0; - code = (byte)inputStream.ReadByte(); - value = (value << 7) | (code & (((long)1 << 7) - 1)); - } - while ((code & (1 << 7)) != 0); - return value; - } - - public static long ReadLong7Bit(this byte[] inputBuffer, ref int offset, int tagBit = 0, byte prevTagBit = 0) - { - bool isUseTagBit = tagBit != 0; - - byte code = isUseTagBit ? prevTagBit : inputBuffer[offset++]; - long value = code & ((1 << (7 - tagBit)) - 1); - - if ((code & (1 << (7 - tagBit))) == 0) return value; - - do - { - if (value >> (8 * 8 - 7) != 0) return 0; - code = inputBuffer[offset++]; - value = (value << 7) | (code & (((long)1 << 7) - 1)); - } - while ((code & (1 << 7)) != 0); - return value; - } - - public static long ReadLong7Bit(this ReadOnlySpan inputBuffer, ref int offset, int tagBit = 0, byte prevTagBit = 0) - { - bool isUseTagBit = tagBit != 0; - - byte code = isUseTagBit ? prevTagBit : inputBuffer[offset++]; - long value = code & ((1 << (7 - tagBit)) - 1); - - if ((code & (1 << (7 - tagBit))) == 0) return value; - - do - { - if (value >> (8 * 8 - 7) != 0) return 0; - code = inputBuffer[offset++]; - value = (value << 7) | (code & (((long)1 << 7) - 1)); - } - while ((code & (1 << 7)) != 0); - return value; - } - - public static ref byte ReadLong7Bit(this ref byte inputBuffer, out long value, int tagBit = 0, byte prevTagBit = 0) - { - byte code = tagBit == 0 ? inputBuffer : prevTagBit; - value = code & ((1 << (7 - tagBit)) - 1); - - if (tagBit == 0) - { - inputBuffer = ref Unsafe.AddByteOffset(ref inputBuffer, 1); - } - - if ((code & (1 << (7 - tagBit))) == 0) - { - return ref inputBuffer; - } - - Calc: - if (value >> (8 * 8 - 7) != 0) - { - value = 0; - return ref inputBuffer; - } - code = inputBuffer; - value = (value << 7) | (code & (((long)1 << 7) - 1)); - inputBuffer = ref Unsafe.AddByteOffset(ref inputBuffer, 1); - if ((code & (1 << 7)) != 0) - { - goto Calc; - } - - return ref inputBuffer; - } - - public static bool ReadBoolean(this Stream stream) => stream.ReadByte() != 0; - - public static ref T AsRef(this byte[] coverBuffer, int coverHeaderOffset = 0) - => ref Unsafe.As(ref coverBuffer[coverHeaderOffset]); - - public static void GetPathsFromStream(this Stream reader, out string[] outputPaths, int bufferSize, int count) - { - byte[] buffer = ArrayPool.Shared.Rent(bufferSize); - - try - { - reader.ReadExactly(buffer, 0, bufferSize); - buffer.AsSpan().GetPathsFromBuffer(out outputPaths, count); - } - finally - { - ArrayPool.Shared.Return(buffer); - } - } - - public static unsafe void GetPathsFromBuffer(this Span buffer, out string[] outputPaths, int count) - { - outputPaths = new string[count]; - - int idx = 0, strIdx = 0; -#if NETSTANDARD2_0 || NET461_OR_GREATER - int len = 0; -#endif - fixed (byte* inputPtr = &MemoryMarshal.GetReference(buffer)) - { - do - { -#if !(NETSTANDARD2_0 || NET461_OR_GREATER) - ReadOnlySpan inputSpanned = - MemoryMarshal.CreateReadOnlySpanFromNullTerminated(inputPtr + idx); - idx += inputSpanned.Length + 1; - outputPaths[strIdx++] = Encoding.UTF8.GetString(inputSpanned); -#else - if (*(inputPtr + idx++) == 0) - { - outputPaths[strIdx++] = Encoding.UTF8.GetString(inputPtr + (idx - len - 1), len); - len = 0; - } - else - { - len++; - } -#endif - } while (strIdx < count); - } - } - - public static void GetLongsFromStream(this Stream reader, out long[] outputLongs, long count, long checkCount) - { - outputLongs = new long[count]; - long backValue = -1; - - for (long i = 0; i < count; i++) - { - long num = reader.ReadLong7Bit(); - backValue += 1 + num; - if (backValue > checkCount) throw new InvalidDataException($"[PatchDir::GetLongsFromStream] Given back value for the reference list is invalid! Having {i} refs while expecting max: {checkCount}"); -#if DEBUG && SHOWDEBUGINFO - HDiffPatch.Event.PushLog($"[PatchDir::GetLongsFromStream] value {i} - {count}: {backValue}", Verbosity.Debug); -#endif - outputLongs[i] = backValue; - } - } - - public static void GetLongsFromStream(this Stream reader, out long[] outputLongs, long count) - { - outputLongs = new long[count]; - for (long i = 0; i < count; i++) - { - long num = reader.ReadLong7Bit(); - outputLongs[i] = num; -#if DEBUG && SHOWDEBUGINFO - HDiffPatch.Event.PushLog($"[PatchDir::GetLongsFromStream] value {i} - {count}: {num}", Verbosity.Debug); -#endif - } - } - - public static void GetPairIndexReferenceFromStream(this Stream reader, out PairIndexReference[] outPair, long pairCount, long checkEndNewValue, long checkEndOldValue) - { - outPair = new PairIndexReference[pairCount]; - long backNewValue = -1; - long backOldValue = -1; - - for (long i = 0; i < pairCount; ++i) - { - long incNewValue = reader.ReadLong7Bit(); - - backNewValue += 1 + incNewValue; - if (backNewValue > checkEndNewValue) throw new InvalidDataException($"[PatchDir::GetArrayOfSamePairULongTag] Given back new value for the list is invalid! Having {backNewValue} value while expecting max: {checkEndNewValue}"); - - byte pSign = (byte)reader.ReadByte(); - long incOldValue = reader.ReadLong7Bit(1, pSign); - - if (pSign >> (8 - 1) == 0) - backOldValue += 1 + incOldValue; - else - backOldValue = backOldValue + 1 - incOldValue; - - if (backOldValue > checkEndOldValue) throw new InvalidDataException($"[PatchDir::GetArrayOfSamePairULongTag] Given back old value for the list is invalid! Having {backOldValue} value while expecting max: {checkEndOldValue}"); -#if DEBUG && SHOWDEBUGINFO - HDiffPatch.Event.PushLog($"[PatchDir::GetArrayOfSamePairULongTag] value {i} - {pairCount}: newIndex -> {backNewValue} oldIndex -> {backOldValue}", Verbosity.Debug); -#endif - outPair[i] = new PairIndexReference { NewIndex = backNewValue, OldIndex = backOldValue }; - } - } - - public static int GetFileStreamBufferSize(this long fileSize) - => fileSize switch - { - // 128 KiB - <= 128 << 10 => 4 << 10, - // 1 MiB - <= 1 << 20 => 64 << 10, - // 32 MiB - <= 32 << 20 => 128 << 10, - // 100 MiB - <= 100 << 20 => 512 << 10, - _ => 1 << 20 - }; -} diff --git a/SharpHDiffPatch.Core/Binary/Compression/BZip2/BZip2Constants.cs b/SharpHDiffPatch.Core/Binary/Compression/BZip2/BZip2Constants.cs deleted file mode 100644 index 6e7a929..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/BZip2/BZip2Constants.cs +++ /dev/null @@ -1,159 +0,0 @@ -using System; - -namespace SharpHDiffPatch.Core.Binary.Compression.BZip2; - -/// -/// Defines internal values for both compression and decompression -/// -internal static class BZip2Constants -{ - internal enum DecodeState : byte - { - StartBlock, - RandPartA, - RandPartB, - RandPartC, - NoRandPartA, - NoRandPartB, - NoRandPartC - } - - /// - /// Random numbers used to randomise repetitive blocks - /// - public static readonly ushort[] RandomNumbers = - [ - 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, - 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, - 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, - 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, - 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, - 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, - 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, - 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, - 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, - 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, - 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, - 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, - 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, - 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, - 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, - 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, - 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, - 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, - 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, - 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, - 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, - 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, - 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, - 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, - 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, - 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, - 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, - 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, - 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, - 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, - 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, - 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, - 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, - 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, - 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, - 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, - 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, - 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, - 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, - 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, - 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, - 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, - 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, - 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, - 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, - 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, - 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, - 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, - 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, - 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, - 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, - 936, 638 - ]; - - /// - /// When multiplied by compression parameter (1-9) gives the block size for compression - /// 9 gives the best compression but uses the most memory. - /// - public const int BaseBlockSize = 100000; - - /// - /// Backend constant - /// - public const int MaximumAlphaSize = 258; - - /// - /// Backend constant - /// - public const int MaximumCodeLength = 23; - - /// - /// Backend constant - /// - public const int RunA = 0; - - /// - /// Backend constant - /// - public const int RunB = 1; - - /// - /// Backend constant - /// - public const int GroupCount = 6; - - /// - /// Backend constant - /// - public const int GroupSize = 50; - - /// - /// Backend constant - /// - public const int MaximumSelectors = 2 + 900000 / GroupSize; - - /// - /// Initial Identity MTF constant - /// - public static ReadOnlySpan IdentityMtf => - [ - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, - 248, 249, 250, 251, 252, 253, 254, 255 - ]; -} \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Binary/Compression/BZip2/BZip2Crc32.cs b/SharpHDiffPatch.Core/Binary/Compression/BZip2/BZip2Crc32.cs deleted file mode 100644 index 8517680..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/BZip2/BZip2Crc32.cs +++ /dev/null @@ -1,421 +0,0 @@ -using System; -using System.Buffers.Binary; -using System.IO.Hashing; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -#if NET6_0_OR_GREATER -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; -// ReSharper disable IdentifierTypo -// ReSharper disable InconsistentNaming -#endif - -namespace SharpHDiffPatch.Core.Binary.Compression.BZip2; - -file static class BZip2Crc32Premul -{ - internal const uint InitialState = uint.MaxValue; - internal const int HashSize = sizeof(uint); - private const uint Polynomial = 0x04C11DB7u; - - // Eight concatenated 256-entry tables. - private static readonly uint[] SCrcLookup = CreateSlicingBy8Lookup(); - -#if NET6_0_OR_GREATER - internal const int PclmulThreshold = 128; - - /* - * P(x) = x^32 + 0x04C11DB7 - * - * Folding constants: - * - * k1 = x^576 mod P = 0x8833794C - * k2 = x^512 mod P = 0xE6228B11 - * k3 = x^192 mod P = 0xC5B9CD4C - * k4 = x^128 mod P = 0xE8A45605 - * k5 = x^96 mod P = 0xF200AA66 - * k6 = x^64 mod P = 0x490D678D - * - * mu = floor(x^64 / P) over GF(2) = 0x104D101DF - * - * Vector128.Create() specifies the low 64-bit lane first. - */ - private static readonly Vector128 SK1K2 = - Vector128.Create(0xE6228B11UL, // k2 - 0x8833794CUL // k1 - ); - - private static readonly Vector128 SK3K4 = - Vector128.Create(0xE8A45605UL, // k4 - 0xC5B9CD4CUL // k3 - ); - - private static readonly Vector128 SFoldConstants = - Vector128.Create(0x04C11DB7UL, // x^32 mod P - 0xF200AA66UL // k5 - ); - - private static readonly Vector128 SReverseBytesMask = - Vector128.Create((byte)15, 14, 13, 12, - 11, 10, 9, 8, - 7, 6, 5, 4, - 3, 2, 1, 0); - - private static readonly Vector128 SLower64Mask = - Vector128.Create(ulong.MaxValue, 0UL); - - private static readonly Vector128 SLow32PerLaneMask = - Vector128.Create(0xFFFFFFFFUL, 0xFFFFFFFFUL); - - private const ulong K6 = 0x490D678DUL; - private const ulong Mu = 0x104D101DFUL; - - [MethodImpl(MethodImplOptions.NoInlining)] - internal static uint UpdatePclmul( - uint crc, - ReadOnlySpan source) - { - // The vector path processes complete 16-byte blocks. - int vectorLength = source.Length & -Vector128.Count; - - ref byte sourceRef = ref MemoryMarshal.GetReference(source); - - Vector128 x1; - int offset; - - if (vectorLength >= 4 * Vector128.Count) - { - // Start four independent 128-bit folding streams. - x1 = LoadReversed(ref sourceRef); - Vector128 x2 = LoadReversed(ref Unsafe.Add(ref sourceRef, 16)); - Vector128 x3 = LoadReversed(ref Unsafe.Add(ref sourceRef, 32)); - Vector128 x4 = LoadReversed(ref Unsafe.Add(ref sourceRef, 48)); - - offset = 64; - - /* - * The CRC occupies the most-significant 32 bits of the - * first reversed 128-bit input block. - */ - Vector128 initialCrc = Sse2.ShiftLeftLogical128BitLane(Vector128.CreateScalar((ulong)crc << 32), 8); - - x1 = Sse2.Xor(x1, initialCrc); - - while (vectorLength - offset >= 64) - { - Vector128 y1 = LoadReversed(ref Unsafe.Add(ref sourceRef, offset)); - Vector128 y2 = LoadReversed(ref Unsafe.Add(ref sourceRef, offset + 16)); - Vector128 y3 = LoadReversed(ref Unsafe.Add(ref sourceRef, offset + 32)); - Vector128 y4 = LoadReversed(ref Unsafe.Add(ref sourceRef, offset + 48)); - - x1 = FoldPolynomialPair(y1, x1, SK1K2); - x2 = FoldPolynomialPair(y2, x2, SK1K2); - x3 = FoldPolynomialPair(y3, x3, SK1K2); - x4 = FoldPolynomialPair(y4, x4, SK1K2); - - offset += 64; - } - - // Merge the four parallel streams. - x1 = FoldPolynomialPair(x2, x1, SK3K4); - x1 = FoldPolynomialPair(x3, x1, SK3K4); - x1 = FoldPolynomialPair(x4, x1, SK3K4); - } - else - { - x1 = LoadReversed(ref sourceRef); - Vector128 initialCrc = Sse2.ShiftLeftLogical128BitLane(Vector128.CreateScalar((ulong)crc << 32), 8); - x1 = Sse2.Xor(x1, initialCrc); - - offset = 16; - } - - // Fold remaining complete 16-byte blocks. - while (vectorLength - offset >= 16) - { - Vector128 next = LoadReversed(ref Unsafe.Add(ref sourceRef, offset)); - - x1 = FoldPolynomialPair(next, x1, SK3K4); - offset += 16; - } - - /* - * Fold 128 bits down toward 64 bits. - * - * SFoldConstants contains: - * low lane: x^32 mod P - * high lane: x^96 mod P - */ - x1 = FoldPolynomialPair(Vector128.Zero, x1, SFoldConstants); - - /* - * Fold 64 bits toward 32 bits: - * - * upper64(x1) * k6 XOR lower64(x1) - */ - Vector128 lower64 = Sse2.And(x1, SLower64Mask); - Vector128 folded64 = Pclmulqdq.CarrylessMultiply(x1, Vector128.CreateScalar(K6), 0x01); - - x1 = Sse2.Xor(folded64, lower64); - - // Barrett reduction from the remaining polynomial to 32 bits. - Vector128 temporary = x1; - - x1 = Sse2.ShiftRightLogical128BitLane(x1, 4); - x1 = Sse2.And(x1, SLow32PerLaneMask); - x1 = Pclmulqdq.CarrylessMultiply(x1, Vector128.CreateScalar(Mu), 0x00); - x1 = Sse2.ShiftRightLogical128BitLane(x1, 4); - x1 = Sse2.And(x1, SLow32PerLaneMask); - x1 = Pclmulqdq.CarrylessMultiply(x1, Vector128.CreateScalar((ulong)Polynomial), 0x00); - x1 = Sse2.Xor(x1, temporary); - uint reducedCrc = x1.AsUInt32().GetElement(0); - - // Process the final 0–15 bytes using the existing implementation. - return UpdateSlicingBy8(reducedCrc, source[vectorLength..]); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector128 LoadReversed(ref byte source) - { - var value = Unsafe.ReadUnaligned>(ref source); - return Ssse3.Shuffle(value, SReverseBytesMask).AsUInt64(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector128 FoldPolynomialPair( - Vector128 target, - Vector128 source, - Vector128 constants) - { - /* - * target XOR= - * CLMUL(source.low, constants.low) XOR - * CLMUL(source.high, constants.high) - */ - Vector128 lowerProduct = Pclmulqdq.CarrylessMultiply(source, constants, 0x00); - Vector128 upperProduct = Pclmulqdq.CarrylessMultiply(source, constants, 0x11); - Vector128 products = Sse2.Xor(lowerProduct, upperProduct); - return Sse2.Xor(target, products); - } -#endif - - internal static uint UpdateSlicingBy8( - uint crc, - ReadOnlySpan source) - // The JIT treats this as a platform constant. - => BitConverter.IsLittleEndian - ? UpdateSlicingBy8LittleEndian(crc, source) - : UpdateSlicingBy8Portable(crc, source); - - private static uint UpdateSlicingBy8LittleEndian( - uint crc, - ReadOnlySpan source) - { - ref byte sourceRef = ref MemoryMarshal.GetReference(source); - ref uint tableRef = ref SCrcLookup[0]; - - int offset = 0; - int length = source.Length; - - /* - * Two-block unrolling reduces loop bookkeeping. - * - * The two CRC operations are still dependent, so larger - * unrolling generally provides diminishing returns. - */ - while (length >= 16) - { - ulong block0 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref sourceRef, offset)); - ulong block1 = Unsafe.ReadUnaligned(ref Unsafe.Add(ref sourceRef, offset + 8)); - crc = UpdateSlicingBy8Block(crc, block0, ref tableRef); - crc = UpdateSlicingBy8Block(crc, block1, ref tableRef); - - offset += 16; - length -= 16; - } - - if (length >= 8) - { - ulong block = Unsafe.ReadUnaligned(ref Unsafe.Add(ref sourceRef, offset)); - crc = UpdateSlicingBy8Block(crc, block, ref tableRef); - offset += 8; - length -= 8; - } - - // Process the remaining 0–7 bytes. - while (length != 0) - { - byte value = Unsafe.Add(ref sourceRef, offset); - byte index = (byte)((crc >> 24) ^ value); - crc = (crc << 8) ^ Unsafe.Add(ref tableRef, index); - offset++; - length--; - } - - return crc; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static uint UpdateSlicingBy8Block( - uint crc, - ulong block, - ref uint table) - { - /* - * A little-endian ulong load gives: - * - * bits 0–7 = source[0] - * bits 8–15 = source[1] - * ... - * bits 56–63 = source[7] - * - * ReverseEndianness converts source[0..3] into the - * big-endian uint required by the non-reflected CRC. - */ - uint first = crc ^ BinaryPrimitives.ReverseEndianness((uint)block); - return Unsafe.Add(ref table, 0 * 256 + (byte)(block >> 56)) ^ - Unsafe.Add(ref table, 1 * 256 + (byte)(block >> 48)) ^ - Unsafe.Add(ref table, 2 * 256 + (byte)(block >> 40)) ^ - Unsafe.Add(ref table, 3 * 256 + (byte)(block >> 32)) ^ - Unsafe.Add(ref table, 4 * 256 + (byte)first) ^ - Unsafe.Add(ref table, 5 * 256 + (byte)(first >> 8)) ^ - Unsafe.Add(ref table, 6 * 256 + (byte)(first >> 16)) ^ - Unsafe.Add(ref table, 7 * 256 + (byte)(first >> 24)); - } - - private static uint UpdateSlicingBy8Portable( - uint crc, - ReadOnlySpan source) - { - ref byte sourceRef = ref MemoryMarshal.GetReference(source); - ref uint tableRef = ref SCrcLookup[0]; - - int offset = 0; - int length = source.Length; - - while (length >= 8) - { - uint first = crc ^ - ((uint)Unsafe.Add(ref sourceRef, offset) << 24) ^ - ((uint)Unsafe.Add(ref sourceRef, offset + 1) << 16) ^ - ((uint)Unsafe.Add(ref sourceRef, offset + 2) << 8) ^ - Unsafe.Add(ref sourceRef, offset + 3); - - crc = Unsafe.Add(ref tableRef, 0 * 256 + Unsafe.Add(ref sourceRef, offset + 7)) ^ - Unsafe.Add(ref tableRef, 1 * 256 + Unsafe.Add(ref sourceRef, offset + 6)) ^ - Unsafe.Add(ref tableRef, 2 * 256 + Unsafe.Add(ref sourceRef, offset + 5)) ^ - Unsafe.Add(ref tableRef, 3 * 256 + Unsafe.Add(ref sourceRef, offset + 4)) ^ - Unsafe.Add(ref tableRef, 4 * 256 + (byte)first) ^ - Unsafe.Add(ref tableRef, 5 * 256 + (byte)(first >> 8)) ^ - Unsafe.Add(ref tableRef, 6 * 256 + (byte)(first >> 16)) ^ - Unsafe.Add(ref tableRef, 7 * 256 + (byte)(first >> 24)); - - offset += 8; - length -= 8; - } - - while (length != 0) - { - byte index = (byte)((crc >> 24) ^ Unsafe.Add(ref sourceRef, offset)); - crc = (crc << 8) ^ Unsafe.Add(ref tableRef, index); - offset++; - length--; - } - - return crc; - } - - private static uint[] CreateSlicingBy8Lookup() - { - uint[] table = new uint[8 * 256]; - - // T0: CRC of one byte in the most-significant position. - for (uint value = 0; value < 256; value++) - { - uint crc = value << 24; - for (int bit = 0; bit < 8; bit++) - { - crc = (crc & 0x80000000u) != 0 ? (crc << 1) ^ Polynomial : crc << 1; - } - - table[value] = crc; - } - - /* - * For a non-reflected, left-shifting CRC: - * - * T[n][x] = advance T[n - 1][x] by one zero byte. - */ - for (int slice = 1; slice < 8; slice++) - { - int previousOffset = (slice - 1) * 256; - int currentOffset = slice * 256; - - for (int value = 0; value < 256; value++) - { - uint crc = table[previousOffset + value]; - table[currentOffset + value] = (crc << 8) ^ table[(byte)(crc >> 24)]; - } - } - - return table; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static uint UpdateByte(uint crc, byte value) - { - ref uint table = ref SCrcLookup[0]; - - byte index = (byte)((crc >> 24) ^ value); - return (crc << 8) ^ Unsafe.Add(ref table, index); - } -} - -public sealed class BZip2Crc32 : NonCryptographicHashAlgorithm -{ - private uint _crc = BZip2Crc32Premul.InitialState; - - public BZip2Crc32() - : base(BZip2Crc32Premul.HashSize) - { - } - - private BZip2Crc32(uint crc) - : base(BZip2Crc32Premul.HashSize) - { - _crc = crc; - } - - public BZip2Crc32 Clone() => new(_crc); - - public void AppendByte(byte value) => _crc = BZip2Crc32Premul.UpdateByte(_crc, value); - - public override void Append(ReadOnlySpan source) => _crc = Update(_crc, source); - - public override void Reset() => _crc = BZip2Crc32Premul.InitialState; - - protected override void GetCurrentHashCore(Span destination) => BinaryPrimitives.WriteUInt32BigEndian(destination, ~_crc); - - protected override void GetHashAndResetCore(Span destination) - { - BinaryPrimitives.WriteUInt32BigEndian(destination, ~_crc); - _crc = BZip2Crc32Premul.InitialState; - } - - public uint GetCurrentHashAsUInt32() => ~_crc; - - private static uint Update(uint crc, ReadOnlySpan source) - { -#if NET6_0_OR_GREATER - if (BitConverter.IsLittleEndian && - Pclmulqdq.IsSupported && - Ssse3.IsSupported && - source.Length >= BZip2Crc32Premul.PclmulThreshold) - { - return BZip2Crc32Premul.UpdatePclmul(crc, source); - } -#endif - - return BZip2Crc32Premul.UpdateSlicingBy8(crc, source); - } -} \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Binary/Compression/BZip2/BZip2Exception.cs b/SharpHDiffPatch.Core/Binary/Compression/BZip2/BZip2Exception.cs deleted file mode 100644 index 7e09d4c..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/BZip2/BZip2Exception.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Runtime.Serialization; - -namespace SharpHDiffPatch.Core.Binary.Compression.BZip2; - -/// -/// BZip2Exception represents exceptions specific to BZip2 classes and code. -/// -[Serializable] -public class BZip2Exception : Exception -{ - /// - /// Initialise a new instance of . - /// - public BZip2Exception() - { - } - - /// - /// Initialise a new instance of with its message string. - /// - /// A that describes the error. - public BZip2Exception(string message) - : base(message) - { - } - - /// - /// Initialise a new instance of . - /// - /// A that describes the error. - /// The that caused this exception. - public BZip2Exception(string message, Exception innerException) - : base(message, innerException) - { - } - - /// - /// Initializes a new instance of the BZip2Exception class with serialized data. - /// - /// - /// The System.Runtime.Serialization.SerializationInfo that holds the serialized - /// object data about the exception being thrown. - /// - /// - /// The System.Runtime.Serialization.StreamingContext that contains contextual information - /// about the source or destination. - /// - [Obsolete("Obsolete")] - protected BZip2Exception(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } -} \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Binary/Compression/BZip2/BZip2InputStream.cs b/SharpHDiffPatch.Core/Binary/Compression/BZip2/BZip2InputStream.cs deleted file mode 100644 index 5b2883c..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/BZip2/BZip2InputStream.cs +++ /dev/null @@ -1,1321 +0,0 @@ -using System; -using System.Buffers; -using System.IO; -using System.Numerics; -using System.Runtime.CompilerServices; - -// ReSharper disable CommentTypo - -namespace SharpHDiffPatch.Core.Binary.Compression.BZip2; - -/// -/// An input stream that decompresses files in the BZip2 format. -/// -public sealed class BZip2InputStream : Stream -{ - private const int InputBufferSize = 32 << 10; - private const int MaximumHuffmanLength = 20; - private const int AlphaTableStride = BZip2Constants.MaximumAlphaSize; - private const int CodeTableStride = BZip2Constants.MaximumCodeLength; - - private readonly bool _decompressConcatenated; - private readonly bool _leaveOpen; - private readonly Stream _baseStream; - - // Buffer compressed input. The original implementation called Stream.ReadByte() - // for every compressed byte, which is particularly expensive for unbuffered streams. - private readonly byte[] _inputBuffer; - private int _inputOffset; - private int _inputCount; - - private int _last; - private int _blockSize100K; - private bool _blockRandomised; - - private uint _bsBuff; - private int _bsLive; - - private readonly BZip2Crc32 _nCrc32 = new(); - - private readonly byte[] _seqToUnseq; - private byte[] _selector; - - // Reused per block. This removes the allocations previously made by - // ReceiveDecodingTables() and GetAndMoveToFrontDecode(). - private byte[] _yy; - private readonly byte[] _codeLengths; - - private int[] _tt = []; - private byte[] _ll8 = []; - private ushort[] _perm; - - private readonly int[] _unZfTab; - private readonly int[] _limit = new int[BZip2Constants.GroupCount * CodeTableStride]; - private readonly int[] _baseArray = new int[BZip2Constants.GroupCount * CodeTableStride]; - private readonly byte[] _minLens = new byte[BZip2Constants.GroupCount]; - - private bool _streamEnd; - private bool _blockEndPending; - private int _currentChar = -1; - - private BZip2Constants.DecodeState _currentState = BZip2Constants.DecodeState.StartBlock; - - private uint _storedBlockCrc; - private uint _computedCombinedCrc; - - private byte _count; - private ushort _chPrev; - private ushort _ch2; - private int _tPos; - private ushort _rNToGo; - private ushort _rTPos; - private int _i2; - private byte _j2; - private byte _z; - - private readonly int _inputBufferCapacity; - private bool _disposed; - - private static long TryGetStreamLength(Stream stream) - { - try - { - return stream.Length; - } - catch - { - return -1; - } - } - - public BZip2InputStream(Stream stream, bool decompressConcatenated, bool leaveOpen = false) - { - if (stream == null!) - { - throw new ArgumentNullException(nameof(stream)); - } - - _baseStream = stream; - _decompressConcatenated = decompressConcatenated; - _leaveOpen = leaveOpen; - - try - { - long streamLength = TryGetStreamLength(stream); - _inputBufferCapacity = - streamLength is > 0 and < InputBufferSize - ? (int)streamLength - : InputBufferSize; - - _yy = ArrayPool.Shared.Rent(256); - _seqToUnseq = ArrayPool.Shared.Rent(256); - _unZfTab = ArrayPool.Shared.Rent(256); - _inputBuffer = ArrayPool.Shared.Rent(_inputBufferCapacity); - _selector = ArrayPool.Shared.Rent(BZip2Constants.MaximumSelectors); - _codeLengths = ArrayPool.Shared.Rent(BZip2Constants.GroupCount * AlphaTableStride); - _perm = ArrayPool.Shared.Rent(BZip2Constants.GroupCount * AlphaTableStride); - - Initialize(); - - if (_streamEnd) - { - return; - } - - int origPtr = InitBlock(); - if (!_streamEnd) - { - SetupBlock(origPtr); - } - } - catch - { - ReturnPooledBuffers(); - throw; - } - } - - protected override void Dispose(bool disposing) - { - if (_disposed) - { - base.Dispose(disposing); - return; - } - - _disposed = true; - - ReturnPooledBuffers(); - - if (disposing && IsStreamOwner && !_leaveOpen) - { - _baseStream.Dispose(); - } - - base.Dispose(disposing); - } - - private void ReturnPooledBuffers() - { - if (_yy.Length != 0) ArrayPool.Shared.Return(_yy); - if (_inputBuffer.Length != 0) ArrayPool.Shared.Return(_inputBuffer); - if (_selector.Length != 0) ArrayPool.Shared.Return(_selector); - if (_codeLengths.Length != 0) ArrayPool.Shared.Return(_codeLengths); - if (_perm.Length != 0) ArrayPool.Shared.Return(_perm); - if (_ll8.Length != 0) ArrayPool.Shared.Return(_ll8); - if (_tt.Length != 0) ArrayPool.Shared.Return(_tt); - if (_unZfTab.Length != 0) ArrayPool.Shared.Return(_unZfTab); - if (_seqToUnseq.Length != 0) ArrayPool.Shared.Return(_seqToUnseq); - } - - public bool IsStreamOwner { get; set; } = true; - - public override bool CanRead => _baseStream.CanRead; - public override bool CanSeek => false; - public override bool CanWrite => false; - public override long Length => _baseStream.Length; - - public override long Position - { - get => throw new NotSupportedException("Cannot get the position of the compressed data"); - set => throw new NotSupportedException("BZip2InputStream position cannot be set"); - } - - public override void Flush() => _baseStream.Flush(); - - public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException("BZip2InputStream Seek not supported"); - - public override void SetLength(long value) => throw new NotSupportedException("BZip2InputStream SetLength not supported"); - - public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException("BZip2InputStream Write not supported"); - - public override void WriteByte(byte value) => throw new NotSupportedException("BZip2InputStream WriteByte not supported"); - - public override int Read(byte[] buffer, int offset, int count) - { - if (buffer == null) - { - throw new ArgumentNullException(nameof(buffer)); - } - - if ((uint)offset > (uint)buffer.Length) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - - return (uint)count > (uint)(buffer.Length - offset) - ? throw new ArgumentOutOfRangeException(nameof(count)) - : ReadCore(buffer.AsSpan(offset, count)); - } - -#if NET6_0_OR_GREATER - public override int Read(Span buffer) => ReadCore(buffer); -#endif - - private int ReadCore(Span destination) - { - int written = 0; - int crcStart = 0; - - // Huffman decoding and inverse-BWT traversal are inherently serial, but the - // second RLE stage frequently exposes byte runs. Emit those runs in bulk and - // feed the CRC one span at a time instead of one byte at a time. - while (written < destination.Length && !_streamEnd) - { - if (_blockEndPending) - { - AppendCrc(destination.Slice(crcStart, written - crcStart)); - crcStart = written; - FinishBlock(); - continue; - } - - if (_currentState is BZip2Constants.DecodeState.NoRandPartC - or BZip2Constants.DecodeState.RandPartC) - { - int available = _z - _j2 + 1; // Includes the already prepared current byte. - int toWrite = Math.Min(available, destination.Length - written); - - destination.Slice(written, toWrite).Fill((byte)_currentChar); - written += toWrite; - - if (toWrite < available) - { - // Leave the next repeated byte prepared for the following Read(). - _j2 += (byte)toWrite; - break; - } - - if (_currentState == BZip2Constants.DecodeState.RandPartC) - { - CompleteRandPartC(); - } - else - { - CompleteNoRandPartC(); - } - - continue; - } - - destination[written++] = (byte)_currentChar; - AdvanceState(); - } - - AppendCrc(destination.Slice(crcStart, written - crcStart)); - - // Match the old implementation's timing: consuming the final byte of a block - // also validates that block and prepares the next one before Read() returns. - if (_blockEndPending) - { - FinishBlock(); - } - - return written; - } - - public override int ReadByte() - { - if (_streamEnd) - { - return -1; - } - - int value = _currentChar; - _nCrc32.AppendByte((byte)value); - AdvanceState(); - - if (_blockEndPending) - { - FinishBlock(); - } - - return value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void AppendCrc(ReadOnlySpan source) - { - if (!source.IsEmpty) - { - _nCrc32.Append(source); - } - } - - private void FinishBlock() - { - _blockEndPending = false; - EndBlock(); - - int origPtr = InitBlock(); - if (!_streamEnd) - { - SetupBlock(origPtr); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void AdvanceState() - { - switch (_currentState) - { - case BZip2Constants.DecodeState.RandPartB: - SetupRandPartB(); - break; - - case BZip2Constants.DecodeState.RandPartC: - SetupRandPartC(); - break; - - case BZip2Constants.DecodeState.NoRandPartB: - SetupNoRandPartB(); - break; - - case BZip2Constants.DecodeState.NoRandPartC: - SetupNoRandPartC(); - break; - - case BZip2Constants.DecodeState.StartBlock: - case BZip2Constants.DecodeState.RandPartA: - case BZip2Constants.DecodeState.NoRandPartA: - break; - } - } - - private void Initialize() - { - int magic1 = BsR(8); - int magic2 = BsR(8); - int magic3 = BsR(8); - int magic4 = BsR(8); - - if (magic1 != 'B' || - magic2 != 'Z' || - magic3 != 'h' || - magic4 < '1' || - magic4 > '9') - { - _streamEnd = true; - return; - } - - SetDecompressStructureSizes(magic4 - '0'); - _computedCombinedCrc = 0; - } - - private int InitBlock() - { - int origPtr = 0; - while (true) - { - int magic1 = BsR(8); - int magic2 = BsR(8); - int magic3 = BsR(8); - int magic4 = BsR(8); - int magic5 = BsR(8); - int magic6 = BsR(8); - - if (magic1 == 0x17 && magic2 == 0x72 && magic3 == 0x45 && - magic4 == 0x38 && magic5 == 0x50 && magic6 == 0x90) - { - if (Complete()) - { - return origPtr; - } - - // Complete() consumed the next member's BZh header. Continue by - // reading that member's first block marker. - continue; - } - - if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59 || - magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) - { - BadBlockHeader(); - } - - _storedBlockCrc = unchecked((uint)BsGetInt32()); - _blockRandomised = BsR1() != 0; - - origPtr = GetAndMoveToFrontDecode(); - - _nCrc32.Reset(); - _currentState = BZip2Constants.DecodeState.StartBlock; - return origPtr; - } - } - - private void EndBlock() - { - uint computedBlockCrc = _nCrc32.GetCurrentHashAsUInt32(); - if (_storedBlockCrc != computedBlockCrc) - { - CrcError(); - } - - _computedCombinedCrc = - BitOperations.RotateLeft(_computedCombinedCrc, 1) ^ - computedBlockCrc; - } - - private bool Complete() - { - if (unchecked((uint)BsGetInt32()) != _computedCombinedCrc) - { - CrcError(); - } - - if (!_decompressConcatenated) - { - // Bulk input may have prefetched data following the first member. Restore - // the underlying position when possible so callers can continue reading it. - RewindUnreadInput(); - _streamEnd = true; - return true; - } - - // Each bzip2 member is padded to the next byte boundary. At this point the - // remaining bits in the cache are only that padding. - _bsBuff = 0; - _bsLive = 0; - - if (TryInitializeNextMember()) return false; - - _streamEnd = true; - return true; - } - - private bool TryInitializeNextMember() - { - if (!TryReadCompressedByte(out int magic1)) - { - return false; - } - - int magic2 = ReadCompressedByte(); - int magic3 = ReadCompressedByte(); - int magic4 = ReadCompressedByte(); - - if (magic1 != 'B' || - magic2 != 'Z' || - magic3 != 'h') - { - throw new BZip2Exception("Unexpected data after a valid BZip2 stream"); - } - - if (magic4 is < '1' or > '9') - { - throw new BZip2Exception("Invalid BZip2 block size"); - } - - SetDecompressStructureSizes(magic4 - '0'); - _computedCombinedCrc = 0; - return true; - } - - private void RewindUnreadInput() - { - int unread = _inputCount - _inputOffset; - if (unread != 0 && _baseStream.CanSeek) - { - _baseStream.Seek(-unread, SeekOrigin.Current); - } - - _inputOffset = 0; - _inputCount = 0; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void FillBuffer() - { - _bsBuff = (_bsBuff << 8) | (uint)ReadCompressedByte(); - _bsLive += 8; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int ReadCompressedByte() - { - if (!TryReadCompressedByte(out int value)) - { - CompressedStreamEof(); - } - - return value; - } - - private bool TryReadCompressedByte(out int value) - { - if (_inputOffset >= _inputCount) - { - // A non-seekable stream must not be read past the end of the first member - // when concatenation is disabled. Seekable streams are rewound in Complete(). - int requested = _blockSize100K == 0 || - (!_decompressConcatenated && !_baseStream.CanSeek) - ? 1 - : _inputBufferCapacity; - - _inputCount = _baseStream.Read(_inputBuffer, 0, requested); - _inputOffset = 0; - - if (_inputCount <= 0) - { - value = -1; - return false; - } - } - - value = _inputBuffer[_inputOffset++]; - return true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int BsR1() - { - if (_bsLive == 0) FillBuffer(); - return (int)((_bsBuff >> --_bsLive) & 1u); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int BsR(int bitCount) - { - while (_bsLive < bitCount) - { - FillBuffer(); - } - - int shift = _bsLive - bitCount; - uint mask = (1u << bitCount) - 1u; - int value = (int)((_bsBuff >> shift) & mask); - _bsLive = shift; - return value; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int BsGetInt32() => (BsR(16) << 16) | BsR(16); - -#if NET6_0_OR_GREATER - [SkipLocalsInit] -#endif - private void ReceiveDecodingTables(out int nInUse, - out int alphaSize, - out int selectorCount) - { - nInUse = 0; - - // The format stores sixteen group-presence bits followed by sixteen symbol - // bits for every present group. Reading them in 16-bit chunks removes up to - // 272 calls to BsR1() per block. - int inUse16 = BsR(16); - for (int group = 0; group < 16; group++) - { - if ((inUse16 & (0x8000 >> group)) == 0) - { - continue; - } - - int inUseGroup = BsR(16); - int symbolBase = group << 4; - - while (inUseGroup != 0) - { - int bit = BitOperations.LeadingZeroCount((uint)inUseGroup) - 16; - _seqToUnseq[nInUse++] = (byte)(symbolBase + bit); - - inUseGroup &= ~(0x8000 >> bit); - } - } - - int nGroups = BsR(3); - alphaSize = nInUse + 2; - selectorCount = BsR(15); - - if (nGroups < 2 || nGroups > BZip2Constants.GroupCount || - selectorCount < 1 || selectorCount > BZip2Constants.MaximumSelectors) - { - DataError(); - } - - Span selectorPositionInitial = [0, 1, 2, 3, 4, 5]; - - // Decode selector MTF values immediately, avoiding selectorMtf[] entirely. - for (int i = 0; i < selectorCount; i++) - { - int selectorMtf = 0; - while (BsR1() != 0) - { - selectorMtf++; - if (selectorMtf >= nGroups) - { - DataError(); - } - } - - ref byte selectorPosition = ref selectorPositionInitial[0]; - byte selected = Unsafe.Add(ref selectorPosition, selectorMtf); - - while (selectorMtf != 0) - { - Unsafe.Add(ref selectorPosition, selectorMtf) = - Unsafe.Add(ref selectorPosition, selectorMtf - 1); - - selectorMtf--; - } - - selectorPosition = selected; - _selector[i] = selected; - } - - for (int table = 0; table < nGroups; table++) - { - int alphaOffset = table * AlphaTableStride; - int currentLength = BsR(5); - - for (int symbol = 0; symbol < alphaSize; symbol++) - { - while (BsR1() != 0) - { - currentLength += BsR1() == 0 ? 1 : -1; - if ((uint)(currentLength - 1) >= MaximumHuffmanLength) - { - DataError(); - } - } - - if ((uint)(currentLength - 1) >= MaximumHuffmanLength) - { - DataError(); - } - - _codeLengths[alphaOffset + symbol] = (byte)currentLength; - } - } - - for (int table = 0; table < nGroups; table++) - { - int alphaOffset = table * AlphaTableStride; - int minLength = MaximumHuffmanLength; - int maxLength = 0; - - ref byte codeLength = - ref Unsafe.Add(ref _codeLengths[0], alphaOffset); - - int remaining = alphaSize; - - while (remaining != 0) - { - int length = codeLength; - - minLength = Math.Min(minLength, length); - maxLength = Math.Max(maxLength, length); - - codeLength = ref Unsafe.Add(ref codeLength, 1); - remaining--; - } - - HbCreateDecodeTables(table, minLength, maxLength, alphaSize); - - _minLens[table] = (byte)minLength; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int DecodeNextSymbol( - ref int groupNumber, - ref int groupPosition, - int selectorCount, - int alphaSize) - { - if (groupPosition == 0) - { - int nextGroup = groupNumber + 1; - if ((uint)nextGroup >= (uint)selectorCount) - { - DataError(); - } - - groupNumber = nextGroup; - groupPosition = BZip2Constants.GroupSize; - } - - groupPosition--; - - ref byte selectorRef = ref _selector[0]; - int table = Unsafe.Add(ref selectorRef, groupNumber); - - int codeOffset = table * CodeTableStride; - int alphaOffset = table * AlphaTableStride; - - ref int limitRef = ref _limit[0]; - ref int baseRef = ref _baseArray[0]; - ref ushort permRef = ref _perm[0]; - ref byte minRef = ref _minLens[0]; - - int codeLength = Unsafe.Add(ref minRef, table); - int codeBits = BsR(codeLength); - - while (codeBits > Unsafe.Add(ref limitRef, codeOffset + codeLength)) - { - if (codeLength >= MaximumHuffmanLength) - { - DataError(); - } - - codeLength++; - codeBits = (codeBits << 1) | BsR1(); - } - - int permIndex = codeBits - Unsafe.Add(ref baseRef, codeOffset + codeLength); - if ((uint)permIndex >= (uint)alphaSize) - { - DataError(); - } - - return Unsafe.Add(ref permRef, alphaOffset + permIndex); - } - - private int GetAndMoveToFrontDecode() - { - int blockCapacity = BZip2Constants.BaseBlockSize * _blockSize100K; - int origPtr = BsR(24); - - ReceiveDecodingTables(out int nInUse, - out int alphaSize, - out int selectorCount); - - int endOfBlock = nInUse + 1; - int groupNumber = -1; - int groupPosition = 0; - - BZip2Constants.IdentityMtf.CopyTo(_yy); - - _last = -1; - int nextSymbol = DecodeNextSymbol(ref groupNumber, ref groupPosition, selectorCount, alphaSize); - - while (nextSymbol != endOfBlock) - { - if (nextSymbol is BZip2Constants.RunA or BZip2Constants.RunB) - { - int runLength = -1; - int runPower = 1; - - do - { - if (runPower > blockCapacity) - { - BlockOverrun(); - } - - runLength += nextSymbol == BZip2Constants.RunA - ? runPower - : runPower << 1; - - runPower <<= 1; - nextSymbol = DecodeNextSymbol(ref groupNumber, ref groupPosition, selectorCount, alphaSize); - } - while (nextSymbol is BZip2Constants.RunA or BZip2Constants.RunB); - - runLength++; - int runStart = _last + 1; - - if (nInUse == 0 || runLength < 0 || runLength > blockCapacity - runStart) - { - BlockOverrun(); - } - - byte value = _seqToUnseq[_yy[0]]; - _unZfTab[value] += runLength; - - // Span.Fill is lowered to an optimized bulk fill by modern runtimes - // and uses SIMD when profitable. System.Memory supplies it on netstandard2.0. - _ll8.AsSpan(runStart, runLength).Fill(value); - _last += runLength; - continue; - } - - int mtfIndex = nextSymbol - 1; - if ((uint)mtfIndex >= (uint)nInUse) - { - DataError(); - } - - int nextIndex = _last + 1; - if (nextIndex >= blockCapacity) - { - BlockOverrun(); - } - - byte mtfValue = _yy[mtfIndex]; - byte valueAtIndex = _seqToUnseq[mtfValue]; - - _last = nextIndex; - _unZfTab[valueAtIndex]++; - _ll8[nextIndex] = valueAtIndex; - - if (mtfIndex != 0) - { - // Small MTF indexes dominate normal data, and a short scalar move avoids - // the fixed cost of entering the runtime copy helper. Larger moves use - // overlap-safe memmove, whose implementation selects the best CPU path. - if (mtfIndex <= 16) - { - ref byte yy = ref _yy[0]; - - int moveIndex = mtfIndex; - do - { - Unsafe.Add(ref yy, moveIndex) = Unsafe.Add(ref yy, moveIndex - 1); - } - while (--moveIndex != 0); - } - else - { - _yy.AsSpan(0, mtfIndex).CopyTo(_yy.AsSpan(1)); - } - - _yy[0] = mtfValue; - } - - nextSymbol = DecodeNextSymbol(ref groupNumber, ref groupPosition, selectorCount, alphaSize); - } - - return origPtr; - } - -#if NET6_0_OR_GREATER - [SkipLocalsInit] -#endif - private void SetupBlock(int origPtr) - { - int last = _last; - - if (last < 0 || (uint)origPtr > (uint)last) - { - DataError(); - } - - Span cumulativeFrequency = stackalloc int[257]; - - ref int frequency = ref cumulativeFrequency[0]; - ref int counts = ref _unZfTab[0]; - - frequency = 0; - int cumulative = 0; - - for (int symbol = 0; symbol < 256; symbol++) - { - ref int count = ref Unsafe.Add(ref counts, symbol); - - cumulative += count; - Unsafe.Add(ref frequency, symbol + 1) = cumulative; - - count = 0; - } - - int length = last + 1; - if (length >= 256 * 1024) - { - BuildTransformationTable4Way(cumulativeFrequency, length); - } - else - { - BuildTransformationTableScalar(cumulativeFrequency, length); - } - - _tPos = _tt[origPtr]; - _count = 0; - _i2 = 0; - _ch2 = 256; - - if (_blockRandomised) - { - _rNToGo = 0; - _rTPos = 0; - SetupRandPartA(); - } - else - { - SetupNoRandPartA(); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void BuildTransformationTableScalar( - Span cumulativeFrequency, - int length) - { - ref byte source = ref _ll8[0]; - ref int destination = ref _tt[0]; - ref int cursors = ref cumulativeFrequency[0]; - - ref byte current = ref source; - - int index = 0; - int remaining = length; - - while (remaining != 0) - { - byte value = current; - ref int cursor = ref Unsafe.Add(ref cursors, value); - - Unsafe.Add(ref destination, cursor) = index; - cursor++; - - current = ref Unsafe.Add(ref current, 1); - index++; - remaining--; - } - } - -#if NET6_0_OR_GREATER - [SkipLocalsInit] -#endif - private void BuildTransformationTable4Way( - Span cumulativeFrequency, - int length) - { - const int symbolCount = 256; - const int chunkCount = 4; - - // 4 × 256 local histograms and 4 × 256 independent cursors. - Span chunkCounts = stackalloc int[chunkCount * symbolCount]; - Span chunkCursors = stackalloc int[chunkCount * symbolCount]; -#if NET6_0_OR_GREATER - chunkCounts.Clear(); -#endif - - int chunkSize = length / chunkCount; - - const int start0 = 0; - int start2 = chunkSize * 2; - int start3 = chunkSize * 3; - - ref byte ll8 = ref _ll8[0]; - ref int counts = ref chunkCounts[0]; - - // First pass: calculate one histogram per contiguous chunk. - CountChunk(ref ll8, start0, chunkSize, ref Unsafe.Add(ref counts, 0 * symbolCount)); - CountChunk(ref ll8, chunkSize, start2, ref Unsafe.Add(ref counts, 1 * symbolCount)); - CountChunk(ref ll8, start2, start3, ref Unsafe.Add(ref counts, 2 * symbolCount)); - CountChunk(ref ll8, start3, length, ref Unsafe.Add(ref counts, 3 * symbolCount)); - - ref int globalStart = ref cumulativeFrequency[0]; - ref int cursors = ref chunkCursors[0]; - - // Assign a disjoint output range to each chunk for every symbol. - for (int symbol = 0; symbol < symbolCount; symbol++) - { - int position = Unsafe.Add(ref globalStart, symbol); - Unsafe.Add(ref cursors, 0 * symbolCount + symbol) = position; - position += Unsafe.Add(ref counts, 0 * symbolCount + symbol); - Unsafe.Add(ref cursors, 1 * symbolCount + symbol) = position; - position += Unsafe.Add(ref counts, 1 * symbolCount + symbol); - Unsafe.Add(ref cursors, 2 * symbolCount + symbol) = position; - position += Unsafe.Add(ref counts, 2 * symbolCount + symbol); - Unsafe.Add(ref cursors, 3 * symbolCount + symbol) = position; - } - - ref int tt = ref _tt[0]; - - // The four scatter loops no longer share cursor state. - ScatterChunk(ref ll8, ref tt, start0, chunkSize, ref Unsafe.Add(ref cursors, 0 * symbolCount)); - ScatterChunk(ref ll8, ref tt, chunkSize, start2, ref Unsafe.Add(ref cursors, 1 * symbolCount)); - ScatterChunk(ref ll8, ref tt, start2, start3, ref Unsafe.Add(ref cursors, 2 * symbolCount)); - ScatterChunk(ref ll8, ref tt, start3, length, ref Unsafe.Add(ref cursors, 3 * symbolCount)); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void CountChunk( - ref byte source, - int start, - int end, - ref int counts) - { - ref byte current = ref Unsafe.Add(ref source, start); - int remaining = end - start; - - while (remaining >= 4) - { - byte value0 = current; - byte value1 = Unsafe.Add(ref current, 1); - byte value2 = Unsafe.Add(ref current, 2); - byte value3 = Unsafe.Add(ref current, 3); - - Unsafe.Add(ref counts, value0)++; - Unsafe.Add(ref counts, value1)++; - Unsafe.Add(ref counts, value2)++; - Unsafe.Add(ref counts, value3)++; - - current = ref Unsafe.Add(ref current, 4); - remaining -= 4; - } - - while (remaining != 0) - { - Unsafe.Add(ref counts, current)++; - current = ref Unsafe.Add(ref current, 1); - remaining--; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ScatterChunk( - ref byte source, - ref int destination, - int start, - int end, - ref int cursors) - { - ref byte current = ref Unsafe.Add(ref source, start); - - int index = start; - int remaining = end - start; - - while (remaining != 0) - { - byte value = current; - ref int cursor = ref Unsafe.Add(ref cursors, value); - - Unsafe.Add(ref destination, cursor) = index; - cursor++; - - current = ref Unsafe.Add(ref current, 1); - index++; - remaining--; - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void SetupRandPartA() - { - if (_i2 <= _last) - { - _chPrev = _ch2; - _ch2 = _ll8[_tPos]; - _tPos = _tt[_tPos]; - - if (_rNToGo == 0) - { - _rNToGo = BZip2Constants.RandomNumbers[_rTPos++]; - if (_rTPos == 512) - { - _rTPos = 0; - } - } - - _rNToGo--; - _ch2 ^= (ushort)(_rNToGo == 1 ? 1 : 0); - _i2++; - - _currentChar = _ch2; - _currentState = BZip2Constants.DecodeState.RandPartB; - - return; - } - - _currentState = BZip2Constants.DecodeState.StartBlock; - _blockEndPending = true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void SetupNoRandPartA() - { - if (_i2 <= _last) - { - _chPrev = _ch2; - _ch2 = _ll8[_tPos]; - _tPos = _tt[_tPos]; - _i2++; - - _currentChar = _ch2; - _currentState = BZip2Constants.DecodeState.NoRandPartB; - return; - } - - _currentState = BZip2Constants.DecodeState.StartBlock; - _blockEndPending = true; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void SetupRandPartB() - { - if (_ch2 != _chPrev) - { - _currentState = BZip2Constants.DecodeState.RandPartA; - _count = 1; - SetupRandPartA(); - return; - } - - _count++; - if (_count < 4) - { - _currentState = BZip2Constants.DecodeState.RandPartA; - SetupRandPartA(); - return; - } - - _z = _ll8[_tPos]; - _tPos = _tt[_tPos]; - - if (_rNToGo == 0) - { - _rNToGo = BZip2Constants.RandomNumbers[_rTPos++]; - if (_rTPos == 512) - { - _rTPos = 0; - } - } - - _rNToGo--; - _z ^= (byte)(_rNToGo == 1 ? 1 : 0); - _j2 = 0; - _currentState = BZip2Constants.DecodeState.RandPartC; - SetupRandPartC(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void SetupRandPartC() - { - if (_j2 < _z) - { - _currentChar = _ch2; - _j2++; - return; - } - - CompleteRandPartC(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void CompleteRandPartC() - { - _currentState = BZip2Constants.DecodeState.RandPartA; - _i2++; - _count = 0; - SetupRandPartA(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void SetupNoRandPartB() - { - if (_ch2 != _chPrev) - { - _currentState = BZip2Constants.DecodeState.NoRandPartA; - _count = 1; - SetupNoRandPartA(); - return; - } - - _count++; - if (_count < 4) - { - _currentState = BZip2Constants.DecodeState.NoRandPartA; - SetupNoRandPartA(); - return; - } - - _z = _ll8[_tPos]; - _tPos = _tt[_tPos]; - _currentState = BZip2Constants.DecodeState.NoRandPartC; - _j2 = 0; - SetupNoRandPartC(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void SetupNoRandPartC() - { - if (_j2 < _z) - { - _currentChar = _ch2; - _j2++; - return; - } - - CompleteNoRandPartC(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void CompleteNoRandPartC() - { - _i2++; - _currentState = BZip2Constants.DecodeState.NoRandPartA; - _count = 0; - SetupNoRandPartA(); - } - - private void SetDecompressStructureSizes(int newSize100K) - { - if ((uint)(newSize100K - 1) >= 9) - { - throw new BZip2Exception("Invalid block size"); - } - - _blockSize100K = newSize100K; - int requiredLength = BZip2Constants.BaseBlockSize * newSize100K; - - if (_ll8.Length >= requiredLength && _tt.Length >= requiredLength) - { - return; - } - - byte[] newLl8 = ArrayPool.Shared.Rent(requiredLength); - int[] newTt = ArrayPool.Shared.Rent(requiredLength); - - byte[] oldLl8 = _ll8; - int[] oldTt = _tt; - - _ll8 = newLl8; - _tt = newTt; - - if (oldLl8.Length != 0) ArrayPool.Shared.Return(oldLl8); - if (oldTt.Length != 0) ArrayPool.Shared.Return(oldTt); - } - -#if NET6_0_OR_GREATER - [SkipLocalsInit] -#endif - private void HbCreateDecodeTables( - int table, - int minLength, - int maxLength, - int alphaSize) - { - int codeOffset = table * CodeTableStride; - int alphaOffset = table * AlphaTableStride; - - Span lengthCounts = stackalloc int[CodeTableStride]; -#if NET6_0_OR_GREATER - lengthCounts.Clear(); -#endif - - ref int countRef = ref lengthCounts[0]; - ref byte lengthsRef = ref Unsafe.Add(ref _codeLengths[0], alphaOffset); - - for (int symbol = 0; symbol < alphaSize; symbol++) - { - int length = Unsafe.Add(ref lengthsRef, symbol); - Unsafe.Add(ref countRef, length)++; - } - - Span positions = stackalloc int[CodeTableStride]; - - ref int positionRef = ref positions[0]; - int permutationIndex = alphaOffset; - - for (int length = minLength; length <= maxLength; length++) - { - Unsafe.Add(ref positionRef, length) = permutationIndex; - permutationIndex += Unsafe.Add(ref countRef, length); - } - - ref ushort permRef = ref _perm[0]; - - // Stable scatter preserves ascending symbol order within each length. - for (int symbol = 0; symbol < alphaSize; symbol++) - { - int length = Unsafe.Add(ref lengthsRef, symbol); - ref int position = ref Unsafe.Add(ref positionRef, length); - - Unsafe.Add(ref permRef, position++) = (ushort)symbol; - } - - // Build baseArray directly from the already available counts. - ref int baseRef = ref Unsafe.Add(ref _baseArray[0], codeOffset); - - baseRef = 0; - - for (int length = 1; length < CodeTableStride; length++) - { - Unsafe.Add(ref baseRef, length) = Unsafe.Add(ref baseRef, length - 1) + Unsafe.Add(ref countRef, length - 1); - } - - ref int limitRef = ref Unsafe.Add(ref _limit[0], codeOffset); - int code = 0; - for (int length = minLength; length <= maxLength; length++) - { - code += Unsafe.Add(ref baseRef, length + 1) - Unsafe.Add(ref baseRef, length); - Unsafe.Add(ref limitRef, length) = code - 1; - code <<= 1; - } - - for (int length = minLength + 1; length <= maxLength; length++) - { - Unsafe.Add(ref baseRef, length) = ((Unsafe.Add(ref limitRef, length - 1) + 1) << 1) - Unsafe.Add(ref baseRef, length); - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void CompressedStreamEof() => throw new EndOfStreamException("BZip2 input stream end of compressed stream"); - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void BlockOverrun() => throw new BZip2Exception("BZip2 input stream block overrun"); - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void BadBlockHeader() => throw new BZip2Exception("BZip2 input stream bad block header"); - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void CrcError() => throw new BZip2Exception("BZip2 input stream crc error"); - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void DataError() => throw new BZip2Exception("Bzip data error"); -} \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Binary/Compression/BZip2/LICENSE b/SharpHDiffPatch.Core/Binary/Compression/BZip2/LICENSE deleted file mode 100644 index 2021420..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/BZip2/LICENSE +++ /dev/null @@ -1,17 +0,0 @@ -Copyright © 2000-2018 SharpZipLib Contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy of this -software and associated documentation files (the "Software"), to deal in the Software -without restriction, including without limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Binary/Compression/BZip2/README.md b/SharpHDiffPatch.Core/Binary/Compression/BZip2/README.md deleted file mode 100644 index 402803f..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/BZip2/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# Attention -This implementation of BZip2InputStream has been heavily modified from the original SharpZipLib implementation and is more optimized. -The original implementation can be found [here](https://github.com/icsharpcode/SharpZipLib/tree/master/src/ICSharpCode.SharpZipLib/BZip2) - -## Benchmark result -File: UnityPlayer.dll.bz2 (The UnityPlayer.dll file was originated from Honkai Impact 3rd (Mainland China server) v8.9.0, compressed with BZip2) -Size: 12,869,917 bytes compressed (30,144,408 bytes uncompressed) -Uncompressed File Hash: 7D0B8178 (CRC32) - -| Method | Mean | Error | StdDev | Allocated | -|------------------------- |---------:|--------:|--------:|-----------:| -| BZip2InputStreamModified | 661.7 ms | 3.29 ms | 2.91 ms | 1.38 KB | -| BZip2InputStreamOld | 738.1 ms | 2.29 ms | 2.15 ms | 5481.11 KB | - -Hardware Bench: -- CPU: AMD Ryzen 7 9800X3D -- Memory: G.Skill Ripjaws M5 64GB (32x2) DDR5-6000 CL36-36-36-96 - -Big credits to the original authors of SharpZipLib for their work on BZip2 decompression. -- [Mike Krüger](http://www.icsharpcode.net/pub/relations/krueger.aspx) -- John Reilly -- David Pierson -- Neil McNeight \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Binary/Compression/CompressionStreamHelper.cs b/SharpHDiffPatch.Core/Binary/Compression/CompressionStreamHelper.cs deleted file mode 100644 index ff4fd0d..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/CompressionStreamHelper.cs +++ /dev/null @@ -1,140 +0,0 @@ -// ReSharper disable IdentifierTypo -// ReSharper disable ConvertSwitchStatementToSwitchExpression -// ReSharper disable CommentTypo -// ReSharper disable InconsistentNaming - -using System; -using System.IO; -using System.IO.Compression; -using System.Runtime.InteropServices; -using SharpHDiffPatch.Core.Binary.Compression.BZip2; -using SharpHDiffPatch.Core.Binary.Compression.Lzma; -using SharpHDiffPatch.Core.Binary.Streams; - -#if NET6_0_OR_GREATER -using System.Collections.Generic; -using ZstdNet; -#endif - -#if NETSTANDARD2_0_OR_GREATER || NET6_0_OR_GREATER -using ZstdManagedDecompressor = ZstdSharp.Decompressor; -using ZstdManagedDecompressorParameter = ZstdSharp.Unsafe.ZSTD_dParameter; -using ZstdManagedStream = ZstdSharp.DecompressionStream; -#endif - -#if !NETSTANDARD2_0_OR_GREATER -using ZstdNativeDecompressor = ZstdNet.DecompressionOptions; -using ZstdNativeDecompressorParameter = ZstdNet.ZSTD_dParameter; -using ZstdNativeStream = ZstdNet.DecompressionStream; -#endif - -namespace SharpHDiffPatch.Core.Binary.Compression -{ - public enum HDiffCompressionMode - { - nocomp, - zstd, - lzma, - lzma2, - zlib, - bz2, - pbz2 - } - - internal static class CompressionStreamHelper - { - private delegate Stream ZstdStreamFallback(Stream stream); - private static ZstdStreamFallback _createZstdStreamFallback; - private static readonly int ZstdWindowLogMax = Environment.Is64BitProcess ? 31 : 30; - - internal static void GetDecompressStreamPlugin( - HDiffCompressionMode type, - Stream sourceStream, - out Stream decompStream, - long length, - long compLength, - out long outLength, - bool isBuffered) - { - long toPosition = sourceStream.Position; - outLength = compLength > 0 ? compLength : length; - long toCompLength = sourceStream.Position + outLength; - - HDiffPatch.Event.PushLog($"[PatchCore::GetDecompressStreamPlugin] Assigning stream of compression: {type} at start pos: {toPosition} to end pos: {toCompLength}", Verbosity.Verbose); - Stream rawStream; - if (isBuffered) - rawStream = new ChunkStream(sourceStream, toPosition, toCompLength); - else - { - sourceStream.Position = toPosition; - rawStream = sourceStream; - } - - if (type != HDiffCompressionMode.nocomp && compLength == 0) - { - decompStream = rawStream; - return; - } - - decompStream = type switch - { - HDiffCompressionMode.nocomp => rawStream, - HDiffCompressionMode.zstd => CreateZstdStream(rawStream), - HDiffCompressionMode.zlib => new DeflateStream(rawStream, CompressionMode.Decompress, true), - HDiffCompressionMode.bz2 => new BZip2InputStream(rawStream, false, true), - HDiffCompressionMode.pbz2 => new BZip2InputStream(rawStream, true, true), - HDiffCompressionMode.lzma or HDiffCompressionMode.lzma2 => CreateLzmaStream(rawStream), - _ => throw new NotSupportedException($"[PatchCore::GetDecompressStreamPlugin] Compression Type: {type} is not supported") - }; - } - - private static Stream CreateZstdStream(Stream rawStream) - { - if (_createZstdStreamFallback != null) return _createZstdStreamFallback(rawStream); - -#if !(NETSTANDARD2_0_OR_GREATER || NET461_OR_GREATER) - if (DllUtils.IsLibraryExist(DllUtils.DllName)) - _createZstdStreamFallback = CreateZstdNativeStream; - else - _createZstdStreamFallback = CreateZstdManagedStream; -#else - _createZstdStreamFallback = CreateZstdManagedStream; -#endif - return _createZstdStreamFallback(rawStream); - } - - /* HACK: The default window log max size is 30. This is unacceptable since the native HPatch implementation - * always use 31 as the size_t, which is 8 bytes length. - * - * Code Snippets (decompress_plugin_demo.h:963): - * #define _ZSTD_WINDOWLOG_MAX ((sizeof(size_t)<=4)?30:31) - */ -#if !NETSTANDARD2_0_OR_GREATER - private static Stream CreateZstdNativeStream(Stream rawStream) => - new ZstdNativeStream(rawStream, new ZstdNativeDecompressor(null, new Dictionary - { - { ZstdNativeDecompressorParameter.ZSTD_d_windowLogMax, ZstdWindowLogMax } - })); -#endif - - private static Stream CreateZstdManagedStream(Stream rawStream) - { - ZstdManagedDecompressor decompressor = new(); - decompressor.SetParameter(ZstdManagedDecompressorParameter.ZSTD_d_windowLogMax, ZstdWindowLogMax); - return new ZstdManagedStream(rawStream, decompressor, 16 << 10); - } - - private static Stream CreateLzmaStream(Stream rawStream) - { - int propLen = rawStream.ReadByte(); - if (propLen != 5) return new LzmaInputStream([(byte)propLen], rawStream, true); // Get LZMA2 if propLen != 5 - - // Get LZMA if propLen == 5 - byte[] props = new byte[propLen]; - _ = rawStream.Read(props, 0, propLen); - int dicSize = MemoryMarshal.Read(props.AsSpan(1)); - HDiffPatch.Event.PushLog($"[PatchCore::CreateLzmaStream] Assigning LZMA stream with dictionary size: {dicSize}", Verbosity.Verbose); - return new LzmaInputStream(props, rawStream, -1, -1, rawStream, false, true); - } - } -} diff --git a/SharpHDiffPatch.Core/Binary/Compression/Lzma/LICENSE.txt b/SharpHDiffPatch.Core/Binary/Compression/Lzma/LICENSE.txt deleted file mode 100644 index 94e2f5b..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/Lzma/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Adam Hathcock - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/SharpHDiffPatch.Core/Binary/Compression/Lzma/LZ/LzOutWindow.cs b/SharpHDiffPatch.Core/Binary/Compression/Lzma/LZ/LzOutWindow.cs deleted file mode 100644 index 913c8d9..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/Lzma/LZ/LzOutWindow.cs +++ /dev/null @@ -1,269 +0,0 @@ -using System; -using System.Buffers; -using System.IO; -using System.Runtime.CompilerServices; - -namespace SharpHDiffPatch.Core.Binary.Compression.Lzma.LZ; - -internal class OutWindow : IDisposable -{ - private byte[] _buffer = []; - private int _windowSize; - private int _pos; - private int _streamPos; - private int _pendingLen; - private int _pendingDist; - private Stream _stream; - - public long Total; - public long Limit; - - public void Create(int windowSize) - { - if (_buffer.Length < windowSize) - { - ReturnPooledBuffer(); - _buffer = ArrayPool.Shared.Rent(windowSize); - } - - _buffer[windowSize - 1] = 0; - _windowSize = windowSize; - _pos = 0; - _streamPos = 0; - _pendingLen = 0; - Total = 0; - Limit = 0; - } - - public void Reset() => Create(_windowSize); - - public void Init(Stream stream) - { - ReleaseStream(); - _stream = stream; - } - - public void Train(Stream stream) - { - long len = stream.Length; - int size = len < _windowSize ? (int)len : _windowSize; - stream.Position = len - size; - - Total = 0; - Limit = size; - _pos = _windowSize - size; - CopyStream(stream, size); - - if (_pos == _windowSize) - { - _pos = 0; - } - _streamPos = _pos; - } - - public void ReleaseStream() - { - Flush(); - _stream = null; - } - - public void Flush() - { - if (_stream is null) - { - return; - } - int size = _pos - _streamPos; - if (size == 0) - { - return; - } - - _stream.Write(_buffer, _streamPos, size); - if (_pos >= _windowSize) - { - _pos = 0; - } - - _streamPos = _pos; - } - - public void CopyBlock(int distance, int len) - { - int remaining = len; - int source = _pos - distance - 1; - if (source < 0) - { - source += _windowSize; - } - - while (remaining > 0 && _pos < _windowSize && Total < Limit) - { - int copySize = Math.Min(remaining, _windowSize - _pos); - long available = Limit - Total; - if (copySize > available) - { - copySize = (int)available; - } - - ref byte buffer = ref _buffer[0]; - int beforeWrap = Math.Min(copySize, _windowSize - source); - CopyBytes(ref buffer, source, _pos, beforeWrap); - source += beforeWrap; - _pos += beforeWrap; - - int afterWrap = copySize - beforeWrap; - if (afterWrap > 0) - { - source = 0; - CopyBytes(ref buffer, source, _pos, afterWrap); - source += afterWrap; - _pos += afterWrap; - } - - remaining -= copySize; - Total += copySize; - if (_pos >= _windowSize) - { - Flush(); - } - } - - _pendingLen = remaining; - _pendingDist = distance; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static unsafe void CopyBytes(ref byte buffer, int sourceOffset, int destinationOffset, int count) - { - ref byte source = ref Unsafe.Add(ref buffer, sourceOffset); - ref byte destination = ref Unsafe.Add(ref buffer, destinationOffset); - - bool isNonOverlapping = sourceOffset + count <= destinationOffset || destinationOffset + count <= sourceOffset; - - if (count >= 16 && isNonOverlapping) - { - ReadOnlySpan sourceSpan = new(Unsafe.AsPointer(ref source), count); - Span destinationSpan = new(Unsafe.AsPointer(ref destination), count); - - sourceSpan.CopyTo(destinationSpan); - return; - } - - ref byte destinationEnd = ref Unsafe.Add(ref destination, count); - while (Unsafe.IsAddressLessThan(ref destination, ref destinationEnd)) - { - destination = source; - source = ref Unsafe.Add(ref source, 1); - destination = ref Unsafe.Add(ref destination, 1); - } - } - - public void PutByte(byte b) - { - _buffer[_pos++] = b; - Total++; - - if (_pos >= _windowSize) - { - Flush(); - } - } - - public byte GetByte(int distance) - { - int pos = _pos - distance - 1; - if (pos < 0) - { - pos += _windowSize; - } - return _buffer[pos]; - } - - public int CopyStream(Stream stream, int len) - { - int size = len; - while (size > 0 && _pos < _windowSize && Total < Limit) - { - int curSize = _windowSize - _pos; - if (curSize > Limit - Total) - { - curSize = (int)(Limit - Total); - } - - if (curSize > size) - { - curSize = size; - } - - int numReadBytes = stream.Read(_buffer, _pos, curSize); - if (numReadBytes == 0) - { - throw new LzmaDataErrorException(); - } - - size -= numReadBytes; - _pos += numReadBytes; - Total += numReadBytes; - if (_pos >= _windowSize) - { - Flush(); - } - } - return len - size; - } - - public void SetLimit(long size) => Limit = Total + size; - - public bool HasSpace => _pos < _windowSize && Total < Limit; - - public bool HasPending => _pendingLen > 0; - - public int Read(byte[] buffer, int offset, int count) - { - if (_streamPos >= _pos) - { - return 0; - } - - int size = _pos - _streamPos; - if (size > count) - { - size = count; - } - - _buffer.AsSpan(_streamPos, size).CopyTo(buffer.AsSpan(offset, size)); - _streamPos += size; - if (_streamPos < _windowSize) return size; - - _pos = 0; - _streamPos = 0; - return size; - } - - public void CopyPending() - { - if (_pendingLen > 0) - { - CopyBlock(_pendingDist, _pendingLen); - } - } - - public int AvailableBytes => _pos - _streamPos; - - public void Dispose() - { - ReleaseStream(); - ReturnPooledBuffer(); - } - - private void ReturnPooledBuffer() - { - byte[] buffer = _buffer; - _buffer = []; - if (buffer.Length != 0) - { - ArrayPool.Shared.Return(buffer); - } - } -} \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Binary/Compression/Lzma/LzmaBase.cs b/SharpHDiffPatch.Core/Binary/Compression/Lzma/LzmaBase.cs deleted file mode 100644 index 72f1650..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/Lzma/LzmaBase.cs +++ /dev/null @@ -1,70 +0,0 @@ -namespace SharpHDiffPatch.Core.Binary.Compression.Lzma; - -internal abstract class Base -{ - public const uint KNumStates = 12; - - public struct State - { - public uint Index; - - public void Init() => Index = 0; - - public void UpdateChar() - { - switch (Index) - { - case < 4: - Index = 0; - break; - case < 10: - Index -= 3; - break; - default: - Index -= 6; - break; - } - } - - public void UpdateMatch() => Index = (uint)(Index < 7 ? 7 : 10); - - public void UpdateRep() => Index = (uint)(Index < 7 ? 8 : 11); - - public void UpdateShortRep() => Index = (uint)(Index < 7 ? 9 : 11); - - public bool IsCharState() => Index < 7; - } - - public const int KNumPosSlotBits = 6; - - public const int KNumLenToPosStatesBits = 2; // it's for speed optimization - public const uint KNumLenToPosStates = 1 << KNumLenToPosStatesBits; - - public const uint KMatchMinLen = 2; - - public static uint GetLenToPosState(uint len) - { - len -= KMatchMinLen; - if (len < KNumLenToPosStates) - { - return len; - } - return KNumLenToPosStates - 1; - } - - public const int KNumAlignBits = 4; - - public const uint KStartPosModelIndex = 4; - public const uint KEndPosModelIndex = 14; - - public const uint KNumFullDistances = 1 << ((int)KEndPosModelIndex / 2); - - public const int KNumPosStatesBitsMax = 4; - public const uint KNumPosStatesMax = 1 << KNumPosStatesBitsMax; - - public const int KNumLowLenBits = 3; - public const int KNumMidLenBits = 3; - public const int KNumHighLenBits = 8; - public const uint KNumLowLenSymbols = 1 << KNumLowLenBits; - public const uint KNumMidLenSymbols = 1 << KNumMidLenBits; -} \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Binary/Compression/Lzma/LzmaDecoder.cs b/SharpHDiffPatch.Core/Binary/Compression/Lzma/LzmaDecoder.cs deleted file mode 100644 index 14bffdf..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/Lzma/LzmaDecoder.cs +++ /dev/null @@ -1,460 +0,0 @@ -using System; -using System.Buffers; -using System.IO; -using System.Runtime.CompilerServices; -using SharpHDiffPatch.Core.Binary.Compression.Lzma.LZ; -using SharpHDiffPatch.Core.Binary.Compression.Lzma.RangeCoder; - -namespace SharpHDiffPatch.Core.Binary.Compression.Lzma; - -internal class Decoder : IDisposable -{ - private class LenDecoder : IDisposable - { - private const int KLowModelsCount = (int)Base.KNumPosStatesMax << Base.KNumLowLenBits; - private const int KMidModelsOffset = KLowModelsCount; - private const int KHighModelsOffset = KMidModelsOffset + ((int)Base.KNumPosStatesMax << Base.KNumMidLenBits); - private const int KModelsCount = KHighModelsOffset + (1 << Base.KNumHighLenBits); - - private BitDecoder _choice; - private BitDecoder _choice2; - private BitDecoder[] _models = []; - private uint _numPosStates; - - public void Create(uint numPosStates) - { - if (_models.Length == 0) - { - _models = ArrayPool.Shared.Rent(KModelsCount); - } - _numPosStates = numPosStates; - } - - public void Init() - { - _choice.Init(); - _choice2.Init(); - - int activeLowModels = (int)_numPosStates << Base.KNumLowLenBits; - int activeMidModels = (int)_numPosStates << Base.KNumMidLenBits; - BitDecoder.Init(_models, 0, activeLowModels); - BitDecoder.Init(_models, KMidModelsOffset, activeMidModels); - BitDecoder.Init(_models, KHighModelsOffset, 1 << Base.KNumHighLenBits); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint Decode(RangeDecoder rangeDecoder, uint posState) - { - if (_choice.Decode(rangeDecoder) == 0) - { - int modelOffset = (int)posState << Base.KNumLowLenBits; - return BitTreeDecoder.Decode(_models, modelOffset, rangeDecoder, Base.KNumLowLenBits); - } - - uint symbol = Base.KNumLowLenSymbols; - if (_choice2.Decode(rangeDecoder) == 0) - { - int modelOffset = KMidModelsOffset + ((int)posState << Base.KNumMidLenBits); - symbol += BitTreeDecoder.Decode(_models, modelOffset, rangeDecoder, Base.KNumMidLenBits); - } - else - { - symbol += Base.KNumMidLenSymbols; - symbol += BitTreeDecoder.Decode(_models, KHighModelsOffset, rangeDecoder, Base.KNumHighLenBits); - } - return symbol; - } - - public void Dispose() - { - BitDecoder[] models = _models; - _models = []; - _numPosStates = 0; - - if (models.Length != 0) - { - ArrayPool.Shared.Return(models); - } - } - } - - private class LiteralDecoder : IDisposable - { - private const int KNumModelsPerState = 0x300; - - private BitDecoder[] _coders; - private int _modelCount; - private int _numPrevBits; - private int _numPosBits; - private uint _posMask; - - public void Create(int numPosBits, int numPrevBits) - { - if (_coders != null && _numPrevBits == numPrevBits && _numPosBits == numPosBits) - { - return; - } - - _numPosBits = numPosBits; - _posMask = ((uint)1 << numPosBits) - 1; - _numPrevBits = numPrevBits; - - int numStates = 1 << (_numPrevBits + _numPosBits); - int modelCount = checked(numStates * KNumModelsPerState); - - ReturnModels(); - _coders = ArrayPool.Shared.Rent(modelCount); - _modelCount = modelCount; - } - - public void Init() => BitDecoder.Init(_coders, 0, _modelCount); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private uint GetState(uint pos, byte prevByte) => ((pos & _posMask) << _numPrevBits) + (uint)(prevByte >> (8 - _numPrevBits)); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public byte DecodeNormal(RangeDecoder rangeDecoder, uint pos, byte prevByte) - { - ref BitDecoder decoders = ref Unsafe.Add( - ref _coders[0], - (int)GetState(pos, prevByte) * KNumModelsPerState); - uint symbol = 1; - do - { - symbol = (symbol << 1) | Unsafe.Add(ref decoders, (int)symbol).Decode(rangeDecoder); - } while (symbol < 0x100); - return unchecked((byte)symbol); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public byte DecodeWithMatchByte( - RangeDecoder rangeDecoder, - uint pos, - byte prevByte, - byte matchByte) - { - ref BitDecoder decoders = ref Unsafe.Add( - ref _coders[0], - (int)GetState(pos, prevByte) * KNumModelsPerState); - uint symbol = 1; - do - { - uint matchBit = (uint)(matchByte >> 7) & 1; - matchByte <<= 1; - - int modelIndex = (int)(((1 + matchBit) << 8) + symbol); - uint bit = Unsafe.Add(ref decoders, modelIndex).Decode(rangeDecoder); - symbol = (symbol << 1) | bit; - - if (matchBit == bit) continue; - - while (symbol < 0x100) - { - symbol = (symbol << 1) | Unsafe.Add(ref decoders, (int)symbol).Decode(rangeDecoder); - } - break; - } while (symbol < 0x100); - return unchecked((byte)symbol); - } - - public void Dispose() => ReturnModels(); - - private void ReturnModels() - { - if (_coders == null) return; - - ArrayPool.Shared.Return(_coders); - _coders = null; - _modelCount = 0; - } - } - - private OutWindow _outWindow; - - private const int KStatePosModelsCount = (int)Base.KNumStates << Base.KNumPosStatesBitsMax; - private const int KStateModelsCount = (int)Base.KNumStates; - private const int KIsMatchOffset = 0; - private const int KIsRepOffset = KIsMatchOffset + KStatePosModelsCount; - private const int KIsRepG0Offset = KIsRepOffset + KStateModelsCount; - private const int KIsRepG1Offset = KIsRepG0Offset + KStateModelsCount; - private const int KIsRepG2Offset = KIsRepG1Offset + KStateModelsCount; - private const int KIsRep0LongOffset = KIsRepG2Offset + KStateModelsCount; - private const int KPosDecodersOffset = KIsRep0LongOffset + KStatePosModelsCount; - private const int KPosDecodersCount = (int)(Base.KNumFullDistances - Base.KEndPosModelIndex); - private const int KPosSlotModelsOffset = KPosDecodersOffset + KPosDecodersCount; - private const int KPosSlotModelsCount = (int)Base.KNumLenToPosStates << Base.KNumPosSlotBits; - private const int KPosAlignModelsOffset = KPosSlotModelsOffset + KPosSlotModelsCount; - private const int KModelsCount = KPosAlignModelsOffset + (1 << Base.KNumAlignBits); - - private BitDecoder[] _models = ArrayPool.Shared.Rent(KModelsCount); - private readonly LenDecoder _lenDecoder = new(); - private readonly LenDecoder _repLenDecoder = new(); - private readonly LiteralDecoder _literalDecoder = new(); - - private int _dictionarySize = -1; - - private uint _posStateMask; - - private Base.State _state; - private uint _rep0, _rep1, _rep2, _rep3; - - private void CreateDictionary() - { - if (_dictionarySize < 0) - { - throw new LzmaInvalidParamException(); - } - _outWindow = new OutWindow(); - int blockSize = Math.Max(_dictionarySize, 1 << 12); - _outWindow.Create(blockSize); - } - - private void SetLiteralProperties(int lp, int lc) - { - if (lp > 8 || lc > 8) - { - throw new LzmaInvalidParamException(); - } - - _literalDecoder.Create(lp, lc); - } - - private void SetPosBitsProperties(int pb) - { - if (pb > Base.KNumPosStatesBitsMax) - { - throw new LzmaInvalidParamException(); - } - - uint numPosStates = (uint)1 << pb; - _lenDecoder.Create(numPosStates); - _repLenDecoder.Create(numPosStates); - _posStateMask = numPosStates - 1; - } - - private void Init() - { - BitDecoder.Init(_models, 0, KModelsCount); - - _literalDecoder.Init(); - _lenDecoder.Init(); - _repLenDecoder.Init(); - - _state.Init(); - _rep0 = 0; - _rep1 = 0; - _rep2 = 0; - _rep3 = 0; - } - - public void Code( - Stream inStream, - Stream outStream, - long inSize, - long outSize) - { - if (_outWindow is null) - { - CreateDictionary(); - } - - if (_outWindow != null) - { - _outWindow.Init(outStream); - if (outSize > 0) - { - _outWindow.SetLimit(outSize); - } - else - { - _outWindow.SetLimit(long.MaxValue - _outWindow.Total); - } - - RangeDecoder rangeDecoder = new(); - rangeDecoder.Init(inStream, inSize); - - Code(_dictionarySize, _outWindow, rangeDecoder); - - _outWindow.Dispose(); - rangeDecoder.Dispose(); - } - - _outWindow = null; - } - - internal bool Code(int dictionarySize, OutWindow outWindow, RangeDecoder rangeDecoder) - { - int dictionarySizeCheck = Math.Max(dictionarySize, 1); - - outWindow.CopyPending(); - - ref BitDecoder models = ref _models[0]; - ref BitDecoder isMatchDecoders = ref Unsafe.Add(ref models, KIsMatchOffset); - ref BitDecoder isRepDecoders = ref Unsafe.Add(ref models, KIsRepOffset); - ref BitDecoder isRepG0Decoders = ref Unsafe.Add(ref models, KIsRepG0Offset); - ref BitDecoder isRepG1Decoders = ref Unsafe.Add(ref models, KIsRepG1Offset); - ref BitDecoder isRepG2Decoders = ref Unsafe.Add(ref models, KIsRepG2Offset); - ref BitDecoder isRep0LongDecoders = ref Unsafe.Add(ref models, KIsRep0LongOffset); - - while (outWindow.HasSpace) - { - uint posState = (uint)outWindow.Total & _posStateMask; - int stateIndex = (int)_state.Index; - int statePosIndex = (stateIndex << Base.KNumPosStatesBitsMax) + (int)posState; - - if (Unsafe.Add(ref isMatchDecoders, statePosIndex).Decode(rangeDecoder) == 0) - { - byte prevByte = outWindow.GetByte(0); - byte b = !_state.IsCharState() - ? _literalDecoder.DecodeWithMatchByte(rangeDecoder, (uint)outWindow.Total, prevByte, outWindow.GetByte((int)_rep0)) - : _literalDecoder.DecodeNormal(rangeDecoder, (uint)outWindow.Total, prevByte); - - outWindow.PutByte(b); - _state.UpdateChar(); - } - else - { - uint len; - if (Unsafe.Add(ref isRepDecoders, stateIndex).Decode(rangeDecoder) == 1) - { - if (Unsafe.Add(ref isRepG0Decoders, stateIndex).Decode(rangeDecoder) == 0) - { - if (Unsafe.Add(ref isRep0LongDecoders, statePosIndex).Decode(rangeDecoder) == 0) - { - _state.UpdateShortRep(); - outWindow.PutByte(outWindow.GetByte((int)_rep0)); - continue; - } - } - else - { - uint distance; - if (Unsafe.Add(ref isRepG1Decoders, stateIndex).Decode(rangeDecoder) == 0) - { - distance = _rep1; - } - else - { - if (Unsafe.Add(ref isRepG2Decoders, stateIndex).Decode(rangeDecoder) == 0) - { - distance = _rep2; - } - else - { - distance = _rep3; - _rep3 = _rep2; - } - _rep2 = _rep1; - } - _rep1 = _rep0; - _rep0 = distance; - } - len = _repLenDecoder.Decode(rangeDecoder, posState) + Base.KMatchMinLen; - _state.UpdateRep(); - } - else - { - _rep3 = _rep2; - _rep2 = _rep1; - _rep1 = _rep0; - - len = Base.KMatchMinLen + _lenDecoder.Decode(rangeDecoder, posState); - _state.UpdateMatch(); - - int posSlotOffset = KPosSlotModelsOffset + ((int)Base.GetLenToPosState(len) << Base.KNumPosSlotBits); - uint posSlot = BitTreeDecoder.Decode(_models, posSlotOffset, rangeDecoder, Base.KNumPosSlotBits); - if (posSlot >= Base.KStartPosModelIndex) - { - int numDirectBits = (int)((posSlot >> 1) - 1); - _rep0 = (2 | (posSlot & 1)) << numDirectBits; - - if (posSlot < Base.KEndPosModelIndex) - { - _rep0 += BitTreeDecoder.ReverseDecode( - _models, - KPosDecodersOffset + _rep0 - posSlot - 1, - rangeDecoder, - numDirectBits - ); - } - else - { - _rep0 += rangeDecoder.DecodeDirectBits(numDirectBits - Base.KNumAlignBits) << Base.KNumAlignBits; - _rep0 += BitTreeDecoder.ReverseDecode( - _models, - KPosAlignModelsOffset, - rangeDecoder, - Base.KNumAlignBits); - } - } - else - { - _rep0 = posSlot; - } - } - if (_rep0 >= outWindow.Total || _rep0 >= dictionarySizeCheck) - { - return _rep0 == 0xFFFFFFFF - ? true - : throw new LzmaDataErrorException(); - } - outWindow.CopyBlock((int)_rep0, (int)len); - } - } - return false; - } - - public void SetDecoderProperties(byte[] properties) - { - if (properties.Length < 1) - { - throw new LzmaInvalidParamException(); - } - - int lc = properties[0] % 9; - int remainder = properties[0] / 9; - int lp = remainder % 5; - int pb = remainder / 5; - if (pb > Base.KNumPosStatesBitsMax) - { - throw new LzmaInvalidParamException(); - } - - SetLiteralProperties(lp, lc); - SetPosBitsProperties(pb); - Init(); - - if (properties.Length < 5) return; - - _dictionarySize = 0; - for (int i = 0; i < 4; i++) - { - _dictionarySize += properties[1 + i] << (i * 8); - } - } - - public void Train(Stream stream) - { - if (_outWindow is null) - { - CreateDictionary(); - } - - _outWindow?.Train(stream); - } - - public void Dispose() - { - BitDecoder[] models = _models; - _models = []; - - _lenDecoder.Dispose(); - _repLenDecoder.Dispose(); - _literalDecoder.Dispose(); - - if (models.Length != 0) - { - ArrayPool.Shared.Return(models); - } - } -} diff --git a/SharpHDiffPatch.Core/Binary/Compression/Lzma/LzmaExceptions.cs b/SharpHDiffPatch.Core/Binary/Compression/Lzma/LzmaExceptions.cs deleted file mode 100644 index 9f02974..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/Lzma/LzmaExceptions.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace SharpHDiffPatch.Core.Binary.Compression.Lzma; - -/// -/// The exception that is thrown when an error in input stream occurs during decoding. -/// -internal class LzmaDataErrorException() : Exception("Data Error"); - -/// -/// The exception that is thrown when the value of an argument is outside the allowable range. -/// -internal class LzmaInvalidParamException() : Exception("Invalid Parameter"); \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Binary/Compression/Lzma/LzmaInputStream.cs b/SharpHDiffPatch.Core/Binary/Compression/Lzma/LzmaInputStream.cs deleted file mode 100644 index 7b1b5c2..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/Lzma/LzmaInputStream.cs +++ /dev/null @@ -1,287 +0,0 @@ -using System; -using System.Buffers.Binary; -using System.IO; -using SharpHDiffPatch.Core.Binary.Compression.Lzma.LZ; -using SharpHDiffPatch.Core.Binary.Compression.Lzma.RangeCoder; - -namespace SharpHDiffPatch.Core.Binary.Compression.Lzma; - -public sealed class LzmaInputStream : Stream -{ - private readonly Stream _inputStream; - private readonly long _inputSize; - private readonly long _outputSize; - - private readonly int _dictionarySize; - private readonly OutWindow _outWindow = new(); - private readonly RangeDecoder _rangeDecoder = new(); - private Decoder _decoder; - - private long _position; - private bool _endReached; - private long _availableBytes; - private long _rangeDecoderLimit; - private long _inputPosition; - - // LZMA2 - private readonly bool _isLzma2; - private readonly bool _leaveOpen; - - private bool _uncompressedChunk; - private bool _needDictReset = true; - private bool _needProps = true; - private bool _isDisposed; - - public LzmaInputStream(byte[] properties, Stream inputStream, bool leaveOpen = false) - : this(properties, inputStream, -1, -1, null, properties.Length < 5, leaveOpen) { } - - public LzmaInputStream(byte[] properties, Stream inputStream, long inputSize, bool leaveOpen = false) - : this(properties, inputStream, inputSize, -1, null, properties.Length < 5, leaveOpen) { } - - public LzmaInputStream(byte[] properties, Stream inputStream, long inputSize, long outputSize, bool leaveOpen = false) - : this(properties, inputStream, inputSize, outputSize, null, properties.Length < 5, leaveOpen) { } - - public LzmaInputStream( - byte[] properties, - Stream inputStream, - long inputSize, - long outputSize, - Stream presetDictionary, - bool isLzma2, - bool leaveOpen = false) - { - _inputStream = inputStream; - _inputSize = inputSize; - _outputSize = outputSize; - _isLzma2 = isLzma2; - _leaveOpen = leaveOpen; - - if (!isLzma2) - { - _dictionarySize = BinaryPrimitives.ReadInt32LittleEndian(properties.AsSpan(1)); - _outWindow.Create(_dictionarySize); - if (presetDictionary != null) - { - _outWindow.Train(presetDictionary); - } - - _rangeDecoder.Init(inputStream, inputSize); - - _decoder = new Decoder(); - _decoder.SetDecoderProperties(properties); - Properties = properties; - - _availableBytes = outputSize < 0 ? long.MaxValue : outputSize; - _rangeDecoderLimit = inputSize; - } - else - { - _dictionarySize = 2 | (properties[0] & 1); - _dictionarySize <<= (properties[0] >> 1) + 11; - - _outWindow.Create(_dictionarySize); - if (presetDictionary != null) - { - _outWindow.Train(presetDictionary); - _needDictReset = false; - } - - Properties = new byte[1]; - _availableBytes = 0; - } - } - - public override bool CanRead => true; - - public override bool CanSeek => false; - - public override bool CanWrite => false; - - public override void Flush() { } - - protected override void Dispose(bool disposing) - { - if (_isDisposed) - { - return; - } - - _isDisposed = true; - _decoder?.Dispose(); - _rangeDecoder.Dispose(); - _outWindow.Dispose(); - - if (disposing && !_leaveOpen) - { - _inputStream?.Dispose(); - } - base.Dispose(disposing); - } - - public override long Length => _position + _availableBytes; - - public override long Position - { - get => _position; - set => throw new NotSupportedException(); - } - - public override int Read(byte[] buffer, int offset, int count) - { - if (_endReached) - { - return 0; - } - - int total = 0; - while (total < count) - { - if (_availableBytes == 0) - { - if (_isLzma2) - { - DecodeChunkHeader(); - } - else - { - _endReached = true; - } - if (_endReached) - { - break; - } - } - - int toProcess = count - total; - if (toProcess > _availableBytes) - { - toProcess = (int)_availableBytes; - } - - _outWindow.SetLimit(toProcess); - if (_uncompressedChunk) - { - _inputPosition += _outWindow.CopyStream(_inputStream, toProcess); - } - else if (_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder) && _outputSize < 0) - { - _availableBytes = _outWindow.AvailableBytes; - } - - int read = _outWindow.Read(buffer, offset, toProcess); - total += read; - offset += read; - _position += read; - _availableBytes -= read; - - if (_availableBytes != 0 || _uncompressedChunk) continue; - - // Check range corruption scenario - if (!_rangeDecoder.IsFinished || (_rangeDecoderLimit >= 0 && _rangeDecoder.Total != _rangeDecoderLimit)) - { - // Stream might have End Of Stream marker - _outWindow.SetLimit(toProcess + 1); - if (!_decoder.Code(_dictionarySize, _outWindow, _rangeDecoder)) - { - _rangeDecoder.ReleaseStream(); - throw new LzmaDataErrorException(); - } - } - - _rangeDecoder.ReleaseStream(); - _inputPosition += _rangeDecoder.Total; - if (_outWindow.HasPending) - { - throw new LzmaDataErrorException(); - } - } - - if (!_endReached) return total; - if ((_inputSize >= 0 && _inputPosition != _inputSize) || (_outputSize >= 0 && _position != _outputSize)) - { - throw new LzmaDataErrorException(); - } - - return total; - } - - private void DecodeChunkHeader() - { - int control = _inputStream.ReadByte(); - _inputPosition++; - - switch (control) - { - case 0x00: - _endReached = true; - return; - case >= 0xE0: - case 0x01: - _needProps = true; - _needDictReset = false; - _outWindow.Reset(); - break; - default: - { - if (_needDictReset) - { - throw new LzmaDataErrorException(); - } - - break; - } - } - - switch (control) - { - case >= 0x80: - { - _uncompressedChunk = false; - - _availableBytes = (control & 0x1F) << 16; - _availableBytes += (_inputStream.ReadByte() << 8) + _inputStream.ReadByte() + 1; - _inputPosition += 2; - - _rangeDecoderLimit = (_inputStream.ReadByte() << 8) + _inputStream.ReadByte() + 1; - _inputPosition += 2; - - if (control >= 0xC0) - { - _needProps = false; - Properties[0] = (byte)_inputStream.ReadByte(); - _inputPosition++; - - _decoder ??= new Decoder(); - _decoder.SetDecoderProperties(Properties); - } - else if (_needProps) - { - throw new LzmaDataErrorException(); - } - else if (control >= 0xA0) - { - _decoder ??= new Decoder(); - _decoder.SetDecoderProperties(Properties); - } - - _rangeDecoder.Init(_inputStream, _rangeDecoderLimit); - break; - } - case > 0x02: - throw new LzmaDataErrorException(); - default: - _uncompressedChunk = true; - _availableBytes = (_inputStream.ReadByte() << 8) + _inputStream.ReadByte() + 1; - _inputPosition += 2; - break; - } - } - - public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); - - public override void SetLength(long value) => throw new NotSupportedException(); - - public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - - public byte[] Properties { get; } -} \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Binary/Compression/Lzma/README.md b/SharpHDiffPatch.Core/Binary/Compression/Lzma/README.md deleted file mode 100644 index d0609ca..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/Lzma/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# Attention -This implementation of LzmaStream has been heavily modified from the original managed-lzma and sharpcompress implementation and is more optimized. -The original implementation can be found [here](https://github.com/adamhathcock/sharpcompress/tree/master/src/SharpCompress/Compressors/LZMA) - -## Benchmark result -| Method | Mean | Error | StdDev | Ratio | Gen0 | Gen1 | Allocated | Alloc Ratio | -|--------- |---------:|---------:|---------:|------:|-------:|-------:|----------:|------------:| -| Lzma2New | 23.75 us | 0.197 us | 0.165 us | 0.72 | 0.1526 | - | 8.23 KB | 0.17 | -| Lzma2Old | 33.17 us | 0.061 us | 0.054 us | 1.00 | 0.9766 | 0.1221 | 48.52 KB | 1.00 | - -Hardware Bench: -- CPU: AMD Ryzen 7 9800X3D -- Memory: G.Skill Ripjaws M5 64GB (32x2) DDR5-6000 CL36-36-36-96 - -Big credits to the original authors of LZMA compression, managed-lzma and sharpcompress for their work. -- [Adam Hathcock (sharpcompress)](https://github.com/adamhathcock) -- [Igor Pavlov (LZMA compression)](https://sourceforge.net/u/ipavlov/profile/) -- [Tobias Käs (managed-lzma)](https://github.com/weltkante/managed-lzma) \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Binary/Compression/Lzma/RangeCoder/RangeCoder.cs b/SharpHDiffPatch.Core/Binary/Compression/Lzma/RangeCoder/RangeCoder.cs deleted file mode 100644 index 784fc12..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/Lzma/RangeCoder/RangeCoder.cs +++ /dev/null @@ -1,136 +0,0 @@ -using System; -using System.Buffers; -using System.IO; -using System.Runtime.CompilerServices; - -namespace SharpHDiffPatch.Core.Binary.Compression.Lzma.RangeCoder; - -internal class RangeDecoder : IDisposable -{ - public const uint KTopValue = 1 << 24; - private const int InputBufferSize = 32 << 10; - public uint Range; - public uint Code; - - public Stream Stream; - public long Total; - - private byte[] _inputBuffer = []; - private int _inputOffset; - private int _inputCount; - private long _inputLimit; - private bool _useInputBuffer; - - public void Init(Stream stream, long inputLimit = -1) - { - Stream = stream; - _inputOffset = 0; - _inputCount = 0; - _inputLimit = inputLimit; - _useInputBuffer = inputLimit >= 0; - - Code = 0; - Range = 0xFFFFFFFF; - Total = 0; - for (int i = 0; i < 5; i++) - { - Code = (Code << 8) | ReadByte(); - } - } - - public void ReleaseStream() => Stream = null; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Normalize() - { - while (Range < KTopValue) - { - Code = (Code << 8) | ReadByte(); - Range <<= 8; - } - } - - public void Decode(uint start, uint size) - { - Code -= start * Range; - Range *= size; - Normalize(); - } - - public uint DecodeDirectBits(int numTotalBits) - { - uint range = Range; - uint code = Code; - uint result = 0; - for (int i = numTotalBits; i > 0; i--) - { - range >>= 1; - uint t = (code - range) >> 31; - code -= range & (t - 1); - result = (result << 1) | (1 - t); - - if (range >= KTopValue) continue; - code = (code << 8) | ReadByte(); - range <<= 8; - } - - Range = range; - Code = code; - return result; - } - - public bool IsFinished => Code == 0; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal uint ReadByte() - { - if (!_useInputBuffer) - { - Total++; - return (byte)Stream.ReadByte(); - } - - if (_inputOffset >= _inputCount) - { - FillInputBuffer(); - } - - Total++; - return _inputBuffer[_inputOffset++]; - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private void FillInputBuffer() - { - long remaining = _inputLimit - Total; - if (remaining <= 0) - { - throw new LzmaDataErrorException(); - } - - if (_inputBuffer.Length == 0) - { - _inputBuffer = ArrayPool.Shared.Rent(InputBufferSize); - } - - int requested = (int)Math.Min(_inputBuffer.Length, remaining); - _inputCount = Stream.Read(_inputBuffer, 0, requested); - _inputOffset = 0; - if (_inputCount <= 0) - { - throw new LzmaDataErrorException(); - } - } - - public void Dispose() - { - ReleaseStream(); - byte[] inputBuffer = _inputBuffer; - _inputBuffer = []; - - if (inputBuffer.Length != 0) - { - ArrayPool.Shared.Return(inputBuffer); - } - } -} \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Binary/Compression/Lzma/RangeCoder/RangeCoderBit.cs b/SharpHDiffPatch.Core/Binary/Compression/Lzma/RangeCoder/RangeCoderBit.cs deleted file mode 100644 index d643876..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/Lzma/RangeCoder/RangeCoderBit.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -namespace SharpHDiffPatch.Core.Binary.Compression.Lzma.RangeCoder; - -internal struct BitDecoder -{ - public const int KNumBitModelTotalBits = 11; - public const uint KBitModelTotal = 1 << KNumBitModelTotalBits; - private const int KNumMoveBits = 5; - - private uint _prob; - - public void Init() => _prob = KBitModelTotal >> 1; - - public static void Init(BitDecoder[] decoders) => Init(decoders, 0, decoders.Length); - - public static void Init(BitDecoder[] decoders, int start, int length) => decoders.AsSpan(start, length).Fill(new BitDecoder { _prob = KBitModelTotal >> 1 }); - - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint Decode(RangeDecoder rangeDecoder) - { - uint range = rangeDecoder.Range; - uint code = rangeDecoder.Code; - uint probability = _prob; - uint newBound = (range >> KNumBitModelTotalBits) * probability; - uint symbol; - - if (code < newBound) - { - range = newBound; - probability += (KBitModelTotal - probability) >> KNumMoveBits; - symbol = 0; - } - else - { - range -= newBound; - code -= newBound; - probability -= probability >> KNumMoveBits; - symbol = 1; - } - - if (range < RangeDecoder.KTopValue) - { - code = (code << 8) | rangeDecoder.ReadByte(); - range <<= 8; - } - - rangeDecoder.Range = range; - rangeDecoder.Code = code; - _prob = probability; - return symbol; - } -} \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Binary/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs b/SharpHDiffPatch.Core/Binary/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs deleted file mode 100644 index b536e46..0000000 --- a/SharpHDiffPatch.Core/Binary/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System.Runtime.CompilerServices; - -namespace SharpHDiffPatch.Core.Binary.Compression.Lzma.RangeCoder; - -internal readonly struct BitTreeDecoder(int numBitLevels) -{ - private readonly BitDecoder[] _models = new BitDecoder[1 << numBitLevels]; - - public void Init() => BitDecoder.Init(_models, 1, _models.Length - 1); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public uint Decode(RangeDecoder rangeDecoder) - { - ref BitDecoder models = ref _models[0]; - uint m = 1; - - for (int bitIndex = numBitLevels; bitIndex > 0; bitIndex--) - { - m = (m << 1) + Unsafe.Add(ref models, (int)m).Decode(rangeDecoder); - } - return m - ((uint)1 << numBitLevels); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint Decode( - BitDecoder[] models, - int startIndex, - RangeDecoder rangeDecoder, - int numBitLevels) - { - ref BitDecoder modelBase = ref Unsafe.Add(ref models[0], startIndex); - uint m = 1; - - for (int bitIndex = numBitLevels; bitIndex > 0; bitIndex--) - { - m = (m << 1) + Unsafe.Add(ref modelBase, (int)m).Decode(rangeDecoder); - } - return m - ((uint)1 << numBitLevels); - } - - public static uint ReverseDecode( - BitDecoder[] models, - uint startIndex, - RangeDecoder rangeDecoder, - int numBitLevels) - { - ref BitDecoder modelBase = ref models[0]; - uint m = 1; - uint symbol = 0; - - for (int bitIndex = 0; bitIndex < numBitLevels; bitIndex++) - { - int modelIndex = unchecked((int)(startIndex + m)); - uint bit = Unsafe.Add(ref modelBase, modelIndex).Decode(rangeDecoder); - m = (m << 1) + bit; - symbol |= bit << bitIndex; - } - return symbol; - } -} \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Binary/Streams/ChunkStream.cs b/SharpHDiffPatch.Core/Binary/Streams/ChunkStream.cs deleted file mode 100644 index 6c82271..0000000 --- a/SharpHDiffPatch.Core/Binary/Streams/ChunkStream.cs +++ /dev/null @@ -1,176 +0,0 @@ -using System; -using System.Buffers; -using System.IO; - -namespace SharpHDiffPatch.Core.Binary.Streams; - -public sealed class ChunkStream : Stream -{ - private readonly Stream _stream; - private long Start { get; } - private long End { get; } - private long Size => End - Start; - private long CurPos { get; set; } - private long Remain => Size - CurPos; - private bool IsDisposing { get; } - - public ChunkStream(Stream stream, long start, long end, bool isDisposing = false) - { - _stream = stream; - - if (_stream.Length == 0) - { - throw new Exception("The stream must not have 0 bytes!"); - } - - if (_stream.Length < start || end > _stream.Length) - { - throw new ArgumentOutOfRangeException(nameof(stream), "Offset is out of stream size range!"); - } - - _stream.Position = start; - Start = start; - End = end; - CurPos = 0; - IsDisposing = isDisposing; - } - - ~ChunkStream() => Dispose(IsDisposing); - -#if !(NETSTANDARD2_0 || NET461_OR_GREATER) - public override int Read(Span buffer) - { - if (Remain == 0) return 0; - - int toSlice = (int)(buffer.Length > Remain ? Remain : buffer.Length); - _stream.Position = Start + CurPos; - int read = _stream.Read(buffer[..toSlice]); - CurPos += read; - - return read; - } - - public override void Write(ReadOnlySpan buffer) - { - if (Remain == 0) return; - - int toSlice = (int)(buffer.Length > Remain ? Remain : buffer.Length); - CurPos += toSlice; - - _stream.Write(buffer[..toSlice]); - } -#endif - - public override int Read(byte[] buffer, int offset, int count) - { - if (Remain == 0) return 0; - - int toRead = (int)(Remain < count ? Remain : count); - _stream.Position = Start + CurPos; - int read = _stream.Read(buffer, offset, toRead); - CurPos += read; - return read; - } - - public override void Write(byte[] buffer, int offset, int count) - { - int toRead = (int)(Remain < count ? Remain : count); - int toOffset = offset > Remain ? 0 : offset; - _stream.Position += toOffset; - CurPos += toOffset + toRead; - - _stream.Write(buffer, offset, toRead); - } - -#if !(NETSTANDARD2_0 || NET461_OR_GREATER) - public override void CopyTo(Stream destination, int bufferSize) - { - if (bufferSize <= 0) bufferSize = 4 << 10; - - byte[] buffer = ArrayPool.Shared.Rent(bufferSize); - try - { - int read; - while ((read = Read(buffer.AsSpan(0, bufferSize))) > 0) - { - destination.Write(buffer.AsSpan(0, read)); - } - } - finally - { - ArrayPool.Shared.Return(buffer); - } - } -#endif - - public override bool CanRead => _stream.CanRead; - - public override bool CanSeek => _stream.CanSeek; - - public override bool CanWrite => _stream.CanWrite; - - public override void Flush() - { - _stream.Flush(); - } - - public override long Length => Size; - - public override long Position - { - get => CurPos; - set - { - if (value > Size) - { - throw new IndexOutOfRangeException(); - } - - CurPos = value; - _stream.Position = CurPos + Start; - } - } - - public override long Seek(long offset, SeekOrigin origin) - { - switch (origin) - { - case SeekOrigin.Begin: - { - if (offset > Size) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - return _stream.Seek(offset + Start, SeekOrigin.Begin) - Start; - } - case SeekOrigin.Current: - { - long pos = _stream.Position - Start; - if (pos + offset > Size) - { - throw new ArgumentOutOfRangeException(nameof(offset)); - } - return _stream.Seek(offset, SeekOrigin.Current) - Start; - } - case SeekOrigin.End: - default: - { - _stream.Position = End; - _stream.Position -= offset; - - return Position; - } - } - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - protected override void Dispose(bool disposing) - { - if (disposing) base.Dispose(true); - if (IsDisposing) _stream.Dispose(); - } -} \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Binary/Streams/CombinedStream.cs b/SharpHDiffPatch.Core/Binary/Streams/CombinedStream.cs deleted file mode 100644 index 7fc1e95..0000000 --- a/SharpHDiffPatch.Core/Binary/Streams/CombinedStream.cs +++ /dev/null @@ -1,672 +0,0 @@ -// ReSharper disable CommentTypo - -/* - * Original Code by lassevk - * https://raw.githubusercontent.com/lassevk/Streams/master/Streams/CombinedStream.cs - */ - -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace SharpHDiffPatch.Core.Binary.Streams; - -public class CombinedStreamSegment - where T : Stream -{ - public T Stream { get; set; } - public long Length { get; set; } -} - -/// -/// This class is a descendant that manages multiple underlying -/// streams which are considered to be chained together to one large stream. Only reading -/// and seeking is allowed, writing will throw exceptions. -/// -public sealed class CombinedStream : Stream - where T : Stream -{ - private readonly T[] _underlyingStreams; - private readonly long[] _streamEnds; - - private readonly bool _leaveOpen; - private readonly bool _canWrite; - - private long _position; - private int _index; - private bool _disposed; - - /// - /// Constructs a new on top of the specified array - /// of streams. - /// - /// - /// An array of objects that will be chained together and - /// considered to be one big stream. - /// - /// Keep all underlying streams opened while disposing this current stream. - public CombinedStream(T[] underlyingStreams, - bool leaveOpen = false) - { - if (underlyingStreams == null) - throw new ArgumentNullException(nameof(underlyingStreams), $"[{nameof(CombinedStream)}()] underlyingStreams"); - - if (underlyingStreams.Length == 0) - { - throw new ArgumentException($"[{nameof(CombinedStream)}()] At least one stream is required.", - nameof(underlyingStreams)); - } - - _underlyingStreams = underlyingStreams; - _streamEnds = new long[underlyingStreams.Length]; - _leaveOpen = leaveOpen; - - bool canWrite = true; - long totalLength = 0; - - for (int i = 0; i < _underlyingStreams.Length; i++) - { - Stream stream = _underlyingStreams[i]; - - if (stream == null) - { - throw new ArgumentException($"[{nameof(CombinedStream)}()] The array contains a null stream.", - nameof(underlyingStreams)); - } - - if (!stream.CanRead) - { - throw new ArgumentException($"[{nameof(CombinedStream)}()] Every underlying stream must be readable.", - nameof(underlyingStreams)); - } - - if (!stream.CanSeek) - { - throw new ArgumentException($"[{nameof(CombinedStream)}()] Every underlying stream must be seekable.", - nameof(underlyingStreams)); - } - - canWrite &= stream.CanWrite; - - totalLength = checked(totalLength + stream.Length); - _streamEnds[i] = totalLength; - } - - Length = totalLength; - _canWrite = canWrite; - -#if SHOWMOREDEBUGINFO - HDiffPatch.Event.PushLog($"[{nameof(CombinedStream)}()] Total length of the CombinedStream: {totalLength} bytes with total of {underlyingStreams.Length} streams", Verbosity.Debug); -#endif - } - - /// - /// Constructs a new on top of the specified array - /// of streams. - /// - /// - /// An array of objects that will be chained together and - /// considered to be one big stream. - /// - /// Keep all underlying streams opened while disposing this current stream. - public CombinedStream(CombinedStreamSegment[] underlyingStreams, - bool leaveOpen = false) - { - if (underlyingStreams == null) - throw new ArgumentNullException(nameof(underlyingStreams), $"[{nameof(CombinedStream)}()] underlyingStreams"); - - if (underlyingStreams.Length == 0) - { - throw new ArgumentException($"[{nameof(CombinedStream)}()] At least one stream is required.", - nameof(underlyingStreams)); - } - - _underlyingStreams = new T[underlyingStreams.Length]; - _streamEnds = new long[underlyingStreams.Length]; - _leaveOpen = leaveOpen; - - bool canWrite = true; - long totalLength = 0; - - for (int i = 0; i < underlyingStreams.Length; i++) - { - CombinedStreamSegment segment = underlyingStreams[i]; - - if (segment == null) - { - throw new ArgumentException($"[{nameof(CombinedStream)}()] The array contains a null segment.", nameof(underlyingStreams)); - } - - T stream = segment.Stream; - - if (stream == null) - { - throw new ArgumentException($"[{nameof(CombinedStream)}()] A segment contains a null stream.", nameof(underlyingStreams)); - } - - if (segment.Length < 0) - { - throw new ArgumentOutOfRangeException(nameof(underlyingStreams), $"[{nameof(CombinedStream)}()] Segment length cannot be negative."); - } - - if (!stream.CanRead) - { - throw new ArgumentException($"[{nameof(CombinedStream)}()] Every underlying stream must be readable.", nameof(underlyingStreams)); - } - - if (!stream.CanSeek) - { - throw new ArgumentException($"[{nameof(CombinedStream)}()] Every underlying stream must be seekable.", nameof(underlyingStreams)); - } - - canWrite &= stream.CanWrite; - - _underlyingStreams[i] = stream; - - totalLength = checked(totalLength + segment.Length); - _streamEnds[i] = totalLength; - } - - Length = totalLength; - _canWrite = canWrite; - -#if SHOWMOREDEBUGINFO - HDiffPatch.Event.PushLog($"[{nameof(CombinedStream)}()] Total length of the CombinedStream: {totalLength} bytes with total of {underlyingStreams.Length} streams", Verbosity.Debug); -#endif - } - - /// - public override bool CanRead => !_disposed; - - /// - public override bool CanSeek => !_disposed; - - /// - public override bool CanWrite => !_disposed && _canWrite; - - /// - public override void Flush() - { - foreach (T stream in _underlyingStreams) - stream.Flush(); - } - - /// - public override async Task FlushAsync(CancellationToken cancellationToken) - { - ThrowIfDisposed(); - - if (!_canWrite) - return; - - foreach (T stream in _underlyingStreams) - await stream.FlushAsync(cancellationToken).ConfigureAwait(false); - } - - /// - protected override void Dispose(bool disposing) - { - if (!_disposed) - { - _disposed = true; - - if (disposing && !_leaveOpen) - { - foreach (T stream in _underlyingStreams) - stream.Dispose(); - } - } - - base.Dispose(disposing); - } - - /// - public override long Length { get; } - - /// - public override long Position - { - get - { - ThrowIfDisposed(); - return _position; - } - set - { - ThrowIfDisposed(); - - if ((ulong)value > (ulong)Length) - throw new ArgumentOutOfRangeException(nameof(value)); - - _position = value; - _index = FindStreamIndex(_streamEnds, value, Length, _index); - } - } - - /// - public override void SetLength(long value) => throw new NotSupportedException($"[{nameof(CombinedStream)}::SetLength] The method or operation is not supported by CombinedStream."); - -#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER - /// - public override int Read(Span buffer) - { - ThrowIfDisposed(); - - if (buffer.IsEmpty || _position == Length) - return 0; - - int totalRead = 0; - - while (!buffer.IsEmpty && _position < Length) - { - SkipExhaustedStreams(); - - Stream stream = _underlyingStreams[_index]; - long streamStart = GetStreamStart(_streamEnds, _index); - long localPosition = _position - streamStart; - long available = _streamEnds[_index] - _position; - - if (available <= 0) - { - if (!MoveNextStream()) - break; - - continue; - } - - int requested = (int)Math.Min(buffer.Length, available); - - int read; -#if NET6_0_OR_GREATER - if (stream is FileStream { SafeFileHandle: not null } fileStream) - { - read = RandomAccess.Read(fileStream.SafeFileHandle, - buffer[..requested], - localPosition); - goto Advance; - } -#endif - - if (stream.Position != localPosition) - stream.Position = localPosition; - - read = stream.Read(buffer[..requested]); - - if (read == 0) - { - if (_position < _streamEnds[_index]) - { - throw new EndOfStreamException($"[{nameof(CombinedStream)}::ReadCore] An underlying stream ended before its expected length."); - } - - if (!MoveNextStream()) - break; - - continue; - } - - Advance: - totalRead += read; - _position += read; - buffer = buffer[read..]; - } - - return totalRead; - } -#endif - - /// - public override int Read(byte[] buffer, int offset, int count) - { - ValidateBufferArguments(buffer, offset, count); - ThrowIfDisposed(); - - return ReadCore(buffer, offset, count); - } - - private int ReadCore(byte[] buffer, int offset, int count) - { - if (count == 0 || _position == Length) - return 0; - - int totalRead = 0; - - while (count != 0 && _position < Length) - { - SkipExhaustedStreams(); - - Stream stream = _underlyingStreams[_index]; - long streamStart = GetStreamStart(_streamEnds, _index); - long localPosition = _position - streamStart; - long available = _streamEnds[_index] - _position; - - if (available <= 0) - { - if (!MoveNextStream()) - break; - - continue; - } - - int requested = (int)Math.Min(count, available); - - int read; -#if NET6_0_OR_GREATER - if (stream is FileStream { SafeFileHandle: not null } fileStream) - { - read = RandomAccess.Read(fileStream.SafeFileHandle, - buffer.AsSpan(offset, requested), - localPosition); - goto Advance; - } -#endif - if (stream.Position != localPosition) - stream.Position = localPosition; - - read = stream.Read(buffer, offset, requested); - - if (read == 0) - { - // The FileStream became shorter than the length captured - // by this CombinedStream, or another owner changed it. - if (_position < _streamEnds[_index]) - { - throw new EndOfStreamException($"[{nameof(CombinedStream)}::ReadCore] An underlying stream ended before its expected length."); - } - - if (!MoveNextStream()) - break; - - continue; - } - - Advance: - totalRead += read; - offset += read; - count -= read; - _position += read; - } - - return totalRead; - } - - /// - public override long Seek(long offset, SeekOrigin origin) - { - ThrowIfDisposed(); - long position = origin switch - { - SeekOrigin.Begin => offset, - SeekOrigin.Current => checked(_position + offset), - SeekOrigin.End => checked(Length + offset), - _ => throw new ArgumentOutOfRangeException(nameof(origin)) - }; - - Position = position; - return position; - } - -#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER - /// - public override void Write(ReadOnlySpan buffer) - { - ThrowIfDisposed(); - EnsureWritable(buffer.Length); - - while (!buffer.IsEmpty) - { - SkipExhaustedStreams(); - - Stream stream = _underlyingStreams[_index]; - long streamStart = GetStreamStart(_streamEnds, _index); - long localPosition = _position - streamStart; - long available = _streamEnds[_index] - _position; - - if (available <= 0) - { - if (!MoveNextStream()) - { - throw new EndOfStreamException($"[{nameof(CombinedStream)}::Write] The write exceeds the combined stream length."); - } - - continue; - } - - int writable = (int)Math.Min(buffer.Length, available); - -#if NET6_0_OR_GREATER - if (stream is FileStream { SafeFileHandle: not null } fileStream) - { - RandomAccess.Write(fileStream.SafeFileHandle, - buffer[..writable], - localPosition); - goto Advance; - } -#endif - - if (stream.Position != localPosition) - stream.Position = localPosition; - - stream.Write(buffer[..writable]); - - Advance: - _position += writable; - buffer = buffer[writable..]; - } - } -#endif - - /// - public override void Write(byte[] buffer, int offset, int count) - { - ValidateBufferArguments(buffer, offset, count); - ThrowIfDisposed(); - EnsureWritable(count); - - WriteCore(buffer, offset, count); - } - - private void WriteCore(byte[] buffer, int offset, int count) - { - while (count != 0) - { - SkipExhaustedStreams(); - - Stream stream = _underlyingStreams[_index]; - long streamStart = GetStreamStart(_streamEnds, _index); - long localPosition = _position - streamStart; - long available = _streamEnds[_index] - _position; - - if (available <= 0) - { - if (!MoveNextStream()) - { - throw new EndOfStreamException($"[{nameof(CombinedStream)}::WriteCore] The write exceeds the combined stream length."); - } - - continue; - } - - int writable = (int)Math.Min(count, available); - -#if NET6_0_OR_GREATER - if (stream is FileStream { SafeFileHandle: not null } fileStream) - { - RandomAccess.Write(fileStream.SafeFileHandle, - buffer.AsSpan(offset, writable), - localPosition); - goto Advance; - } -#endif - - if (stream.Position != localPosition) - stream.Position = localPosition; - - stream.Write(buffer, offset, writable); - - Advance: - offset += writable; - count -= writable; - _position += writable; - } - } - - private void ThrowIfDisposed() - { - if (_disposed) - throw new ObjectDisposedException(nameof(CombinedStream)); - } - -#if !NETSTANDARD2_1_OR_GREATER && !NETCOREAPP2_1_OR_GREATER - private static void ValidateBufferArguments( - byte[] buffer, - int offset, - int count) - { - if (buffer == null) - throw new ArgumentNullException(nameof(buffer)); - - if (offset < 0) - throw new ArgumentOutOfRangeException(nameof(offset)); - - if (count < 0) - throw new ArgumentOutOfRangeException(nameof(count)); - - if (buffer.Length - offset < count) - throw new ArgumentException($"[{nameof(CombinedStream)}::ValidateBufferArguments] Offset and count exceed the buffer length."); - } -#endif - - private void SkipExhaustedStreams() - { - while (_index < _underlyingStreams.Length - 1 && - _position >= _streamEnds[_index]) - { - _index++; - } - } - - private bool MoveNextStream() - { - if (_index >= _underlyingStreams.Length - 1) - return false; - - _index++; - return true; - } - - private void EnsureWritable(int count) - { - if (!_canWrite) - throw new NotSupportedException($"[{nameof(CombinedStream)}::EnsureWritable] The stream is not writable."); - - if (count > Length - _position) - { - throw new EndOfStreamException($"[{nameof(CombinedStream)}::EnsureWritable] The write exceeds the combined stream's fixed length."); - } - } - - private static long GetStreamStart(long[] streamEnds, int index) => index == 0 ? 0 : streamEnds[index - 1]; - - private static int FindStreamIndex(long[] streamEnds, long position, long length, int index) - { - int lastIndex = streamEnds.Length - 1; - - // Position == Length represents EOF. Keep the final stream selected, - // including when it is a zero-length trailing stream. - if (position == length) - return lastIndex; - - long currentStart = index == 0 ? 0 : streamEnds[index - 1]; - long currentEnd = streamEnds[index]; - - // Most common case: the new position remains in the current segment. - if (position >= currentStart && position < currentEnd) - return index; - - return position >= currentEnd - ? FindForward(streamEnds, position, index, lastIndex) - : FindBackward(streamEnds, position, index); - } - - private static int FindForward(long[] streamEnds, long position, int currentIndex, int lastIndex) - { - int nextIndex = currentIndex + 1; - - // Common when reading or seeking across one boundary. - if (nextIndex <= lastIndex && - position < streamEnds[nextIndex]) - { - return nextIndex; - } - - int low = nextIndex; - int high = nextIndex; - int step = 1; - - // Find an upper bound exponentially rather than searching the - // entire remaining range immediately. - while (high < lastIndex && position >= streamEnds[high]) - { - low = high + 1; - - int remaining = lastIndex - high; - int increment = step < remaining ? step : remaining; - - high += increment; - - if (step <= int.MaxValue / 2) - step <<= 1; - } - - return FindFirstEndGreaterThan(streamEnds, position, low, high); - } - - private static int FindBackward(long[] streamEnds, long position, int currentIndex) - { - int high = currentIndex - 1; - - // Adjacent segment fast path. - if (high >= 0) - { - long start = high == 0 ? 0 : streamEnds[high - 1]; - - if (position >= start && position < streamEnds[high]) - return high; - } - - int low = high; - int step = 1; - - while (low > 0 && position < streamEnds[low - 1]) - { - int decrement = Math.Min(step, low); - low -= decrement; - - if (step <= int.MaxValue / 2) - step <<= 1; - } - - return FindFirstEndGreaterThan(streamEnds, position, low, high); - } - - private static int FindFirstEndGreaterThan( - long[] streamEnds, - long position, - int low, - int high) - { - while (low < high) - { - int middle = low + ((high - low) >> 1); - - if (streamEnds[middle] > position) - high = middle; - else - low = middle + 1; - } - - return low; - } -} \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Event/PatchEvent.cs b/SharpHDiffPatch.Core/Event/PatchEvent.cs deleted file mode 100644 index 325d583..0000000 --- a/SharpHDiffPatch.Core/Event/PatchEvent.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Threading; - -namespace SharpHDiffPatch.Core.Event -{ - public class LoggerEvent(string message, Verbosity logLevel) - { - public Verbosity LogLevel = logLevel; - public string Message = message; - } - - public sealed class PatchEvent - { - private const double ScOneSecond = 1000; - private long _scLastTick = Environment.TickCount; - private long _scLastReceivedBytes; - private double _scLastSpeed; - - public void UpdateEvent(long currentSizePatched, long totalSizeToBePatched, long read, double totalSecond) - { - Speed = (long)(currentSizePatched / totalSecond); - CurrentSizePatched = currentSizePatched; - TotalSizeToBePatched = totalSizeToBePatched; - Read = read; - } - - private long _currentSizePatched; - public long CurrentSizePatched - { - get => _currentSizePatched; - private set - { - double speed = CalculateSpeed(value - _currentSizePatched); - Speed = (long)speed; - TimeLeft = TimeSpan.FromSeconds((TotalSizeToBePatched - value) / (double.IsInfinity(speed) || speed <= 0 ? 1 : speed)); - ProgressPercentage = Math.Round(value / (double)TotalSizeToBePatched * 100, 2); - _currentSizePatched = value; - } - } - - public long TotalSizeToBePatched { get; private set; } - public double ProgressPercentage { get; private set; } - public long Read { get; private set; } - public long Speed { get; private set; } - public TimeSpan TimeLeft { get; private set; } - - private double CalculateSpeed(long receivedBytes) => CalculateSpeed(receivedBytes, ref _scLastSpeed, ref _scLastReceivedBytes, ref _scLastTick); - - private static double CalculateSpeed(long receivedBytes, ref double lastSpeedToUse, ref long lastReceivedBytesToUse, ref long lastTickToUse) - { - long currentTick = Environment.TickCount - lastTickToUse + 1; - long totalReceivedInSecond = Interlocked.Add(ref lastReceivedBytesToUse, receivedBytes); - double speed = totalReceivedInSecond * ScOneSecond / currentTick; - - if (!(currentTick > ScOneSecond)) - { - return lastSpeedToUse; - } - - lastSpeedToUse = speed; - _ = Interlocked.Exchange(ref lastSpeedToUse, speed); - _ = Interlocked.Exchange(ref lastReceivedBytesToUse, 0); - _ = Interlocked.Exchange(ref lastTickToUse, Environment.TickCount); - return lastSpeedToUse; - } - } -} diff --git a/SharpHDiffPatch.Core/Extern.cs b/SharpHDiffPatch.Core/Extern.cs deleted file mode 100644 index 22ccd9e..0000000 --- a/SharpHDiffPatch.Core/Extern.cs +++ /dev/null @@ -1,58 +0,0 @@ -#if NET6_0_OR_GREATER -using System; -using System.IO; -using System.Reflection; -using System.Runtime.InteropServices; - -namespace SharpHDiffPatch.Core; - -internal class Extern -{ - private static readonly string CurrentProcPath = Environment.ProcessPath?.TrimEnd(Path.DirectorySeparatorChar); - private static readonly string LibArchitecturePrefix = GetLibArchitecturePrefix(); - private static readonly string LibPlatformNamePrefix = GetLibPlatformNamePrefix(); - private static readonly string LibExtensionPrefix = GetLibExtensionPrefix(); - private static readonly string LibFolderPath = Path.Combine("Lib", LibPlatformNamePrefix); - private static readonly string LibFullPath = Path.Combine(CurrentProcPath, LibFolderPath, "{0}" + LibExtensionPrefix); - - static Extern() - { - // Use custom Dll import resolver - NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), DllImportResolver); - } - - private static string GetLibPlatformNamePrefix() - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - return $"win-{LibArchitecturePrefix}"; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - return $"linux-{LibArchitecturePrefix}"; - return RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "osx" : "unknown"; - } - - private static string GetLibExtensionPrefix() - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - return ".dll"; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - return ".so"; - return RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? ".dylib" : string.Empty; - } - - private static string GetLibArchitecturePrefix() => RuntimeInformation.OSArchitecture.ToString().ToLower(); - - private static IntPtr DllImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) - { - libraryName = string.Format(LibFullPath, libraryName); - string searchPathName = searchPath == null ? "Default" : searchPath.ToString(); - HDiffPatch.Event.PushLog($"[Extern::DllImportResolver] Loading library from path: {libraryName} | Search path: {searchPathName}", Verbosity.Debug); - // Try load the library and if fails, then throw. - bool isLoadSuccessful = NativeLibrary.TryLoad(libraryName, assembly, searchPath, out IntPtr pResult); - if (!isLoadSuccessful || pResult == IntPtr.Zero) - throw new FileLoadException($"Failed while loading library from this path: {libraryName}\r\nMake sure that the library/.dll is exist or valid and not corrupted!"); - - // If success, then return the pointer to the library - return pResult; - } -} -#endif \ No newline at end of file diff --git a/SharpHDiffPatch.Core/HDiffPatch.cs b/SharpHDiffPatch.Core/HDiffPatch.cs deleted file mode 100644 index ab2afcd..0000000 --- a/SharpHDiffPatch.Core/HDiffPatch.cs +++ /dev/null @@ -1,243 +0,0 @@ -using SharpHDiffPatch.Core.Event; -using SharpHDiffPatch.Core.Patch; -using System; -using System.Diagnostics; -using System.IO; -using System.Threading; -using SharpHDiffPatch.Core.Binary.Compression; - -namespace SharpHDiffPatch.Core; - -public enum BufferMode { None, Partial, Full } -public enum Verbosity { Quiet, Info, Verbose, Debug } -public enum DirectoryPatchFormat { Standard, Kuro } - -public enum ChecksumMode -{ - NoChecksum, - Crc32, - FAdler64 -} - -public struct HeaderInfoExt -{ - public HeaderInfo HeaderInfo; - public DataReferenceInfo DataReferenceInfo; -} - -public struct HeaderInfo -{ - public HDiffCompressionMode CompMode; - public ChecksumMode ChecksumMode; - - public bool IsInputDir; - public bool IsOutputDir; - public bool IsSingleCompressedDiff; - public string PatchPath; - public Func PatchCreateStream; - public string HeaderMagic; - - public long StepMemSize; - - public bool DirDataIsCompressed; - - public long OldDataSize; - public long NewDataSize; - public long CompressedCount; - - public DiffSingleChunkInfo SingleChunkInfo; - public DiffChunkInfo ChunkInfo; -} - -public struct DataReferenceInfo -{ - public long InputDirCount; - public long InputRefFileCount; - public long InputRefFileSize; - public long InputSumSize; - - public long OutputDirCount; - public long OutputRefFileCount; - public long OutputRefFileSize; - public long OutputSumSize; - - public long SameFilePairCount; - public long SameFileSize; - - public int NewExecuteCount; - - public long PrivateReservedDataSize; - public long PrivateExternDataSize; - public long PrivateExternDataOffset; - - public long ExternDataOffset; - public long ExternDataSize; - - public long CompressSizeBeginPos; - - public byte ChecksumByteSize; - public long ChecksumOffset; - - public long HeadDataSize; - public long HeadDataOffset; - public long HeadDataCompressedSize; - - public long HDiffDataOffset; - public long HDiffDataSize; -} - -public struct DiffSingleChunkInfo -{ - public long UncompressedSize; - public long CompressedSize; - - public long DiffDataPos; -} - -public struct DiffChunkInfo -{ - public long TypesEndPos; - public long CoverCount; - public long CompressSizeBeginPos; - public long CoverBufSize; - public long CompressCoverBufSize; - public long RleCtrlBufSize; - public long CompressRleCtrlBufSize; - public long RleCodeBufSize; - public long CompressRleCodeBufSize; - public long NewDataDiffSize; - public long CompressNewDataDiffSize; - public long HeadEndPos; - public long CoverEndPos; -} - -public sealed class HDiffPatch -{ - private HeaderInfo _headerInfo; - private DataReferenceInfo ReferenceInfo { get; set; } - private Stream DiffStream { get; set; } - private bool IsPatchDir { get; set; } = true; - - internal static PatchEvent PatchEvent = new(); - public static EventListener Event = new(); - - public static Verbosity LogVerbosity { get; set; } = Verbosity.Quiet; - public DirectoryPatchFormat DirPatchFormat { get; set; } = DirectoryPatchFormat.Standard; - -#region Header Initialization - public void Initialize(string diff) - { - using (DiffStream = new FileStream(diff, FileMode.Open, FileAccess.Read)) - { - IsPatchDir = Header.TryParseHeaderInfo(DiffStream, diff, out HeaderInfo info, out DataReferenceInfo reference); - _headerInfo = info; - ReferenceInfo = reference; - } - } - - public void Initialize(Func diffCreateStream) - { - using (DiffStream = diffCreateStream()) - { - IsPatchDir = Header.TryParseHeaderInfo(DiffStream, null, out HeaderInfo info, out DataReferenceInfo reference); - _headerInfo = info; - ReferenceInfo = reference; - _headerInfo.PatchCreateStream = diffCreateStream; - } - } - - public void Patch(string inputPath, string outputPath, bool useBufferedPatch, CancellationToken token = default, bool useFullBuffer = false, bool useFastBuffer = false) - => Patch(inputPath, outputPath, useBufferedPatch, null, token, useFullBuffer, useFastBuffer); - - public void Patch(string inputPath, string outputPath, bool useBufferedPatch, Action writeBytesDelegate, CancellationToken token = default, bool useFullBuffer = false, bool useFastBuffer = false) - { - IPatch patcher; - if (IsPatchDir && _headerInfo is { IsInputDir: true, IsOutputDir: true }) - { - patcher = new PatchDir(_headerInfo, ReferenceInfo, _headerInfo.PatchPath, DirPatchFormat, token); - } - else - { - patcher = new PatchSingle(_headerInfo, token); - } - patcher.Patch(inputPath, outputPath, writeBytesDelegate, useBufferedPatch, useFullBuffer, useFastBuffer); - } -#endregion - - internal static void DisplayDirPatchInformation(long oldFileSize, long newFileSize, HeaderInfo headerInfo) - { - Event.PushLog("Patch Information:"); - Event.PushLog($" Size -> Old: {oldFileSize} bytes | New: {newFileSize} bytes"); - Event.PushLog("Technical Information:"); - if (!headerInfo.IsSingleCompressedDiff) - { - Event.PushLog($" Cover Data -> Count: {headerInfo.ChunkInfo.CoverCount} | Offset: {headerInfo.ChunkInfo.HeadEndPos} | Size: {headerInfo.ChunkInfo.CoverBufSize}"); - Event.PushLog($" RLE Data -> Offset: {headerInfo.ChunkInfo.CoverEndPos} | Control: {headerInfo.ChunkInfo.RleCtrlBufSize} | Code: {headerInfo.ChunkInfo.RleCodeBufSize}"); - Event.PushLog($" Diff Data -> Size: {headerInfo.ChunkInfo.NewDataDiffSize}"); - } - else - { - Event.PushLog($" Cover Data -> Count: {headerInfo.ChunkInfo.CoverCount} | DiffDataPos: {headerInfo.SingleChunkInfo.DiffDataPos}"); - Event.PushLog($" RLE Data -> Compressed Size: {headerInfo.SingleChunkInfo.CompressedSize} | Size: {headerInfo.SingleChunkInfo.UncompressedSize}"); - } - } - - internal static void UpdateEvent(long read, ref long currentSizePatched, ref long totalSizePatched, Stopwatch patchStopwatch) - { - lock (PatchEvent) - { - PatchEvent.UpdateEvent(currentSizePatched += read, totalSizePatched, read, patchStopwatch.Elapsed.TotalSeconds); - Event.PushEvent(PatchEvent); - } - } - - public static long GetHDiffNewSize(string diffFilePath) - { - HeaderInfoExt headerInfo = GetHDiffHeaderInfo(diffFilePath); - return headerInfo.HeaderInfo.NewDataSize; - } - - public static long GetHDiffOldSize(string diffFilePath) - { - HeaderInfoExt headerInfo = GetHDiffHeaderInfo(diffFilePath); - return headerInfo.HeaderInfo.OldDataSize; - } - - public static long GetHDiffNewSize(Stream diffStream) - { - HeaderInfoExt headerInfo = GetHDiffHeaderInfo(diffStream); - return headerInfo.HeaderInfo.NewDataSize; - } - - public static long GetHDiffOldSize(Stream diffStream) - { - HeaderInfoExt headerInfo = GetHDiffHeaderInfo(diffStream); - return headerInfo.HeaderInfo.OldDataSize; - } - - public static HeaderInfoExt GetHDiffHeaderInfo(string diffFilePath) - { - using FileStream fs = new(diffFilePath, FileMode.Open, FileAccess.Read); - _ = Header.TryParseHeaderInfo(fs, diffFilePath, out HeaderInfo headerInfo, out DataReferenceInfo headerInfoReference); - return new HeaderInfoExt { HeaderInfo = headerInfo, DataReferenceInfo = headerInfoReference }; - } - - public static HeaderInfoExt GetHDiffHeaderInfo(Stream diffStream) - { - _ = Header.TryParseHeaderInfo(diffStream, null, out HeaderInfo headerInfo, out DataReferenceInfo headerInfoReference); - return new HeaderInfoExt { HeaderInfo = headerInfo, DataReferenceInfo = headerInfoReference }; - } -} - -public class EventListener -{ - // Log for external listener - public static event EventHandler PatchEvent; - public static event EventHandler LoggerEvent; - public void PushEvent(PatchEvent patchEvent) => PatchEvent?.Invoke(this, patchEvent); - public void PushLog(in string message, Verbosity logLevel = Verbosity.Info) - { - if (logLevel != Verbosity.Quiet) - LoggerEvent?.Invoke(this, new LoggerEvent(message, logLevel)); - } -} diff --git a/SharpHDiffPatch.Core/Patch/Header.cs b/SharpHDiffPatch.Core/Patch/Header.cs deleted file mode 100644 index ec31044..0000000 --- a/SharpHDiffPatch.Core/Patch/Header.cs +++ /dev/null @@ -1,273 +0,0 @@ -using SharpHDiffPatch.Core.Binary; -using System; -using System.IO; - -namespace SharpHDiffPatch.Core.Patch -{ - internal sealed class Header - { -#if !(NETSTANDARD2_0 || NET461_OR_GREATER) - private static readonly char[] HdiffHead = ['H', 'D', 'I', 'F', 'F']; -#else - private const string HdiffHead = "HDIFF"; -#endif - - internal static bool TryParseHeaderInfo(Stream sr, string diffPath, - out HeaderInfo headerInfo, out DataReferenceInfo referenceInfo) - { - headerInfo = new HeaderInfo(); - referenceInfo = new DataReferenceInfo(); - - string headerInfoLine = sr.ReadStringToNull(); - bool isPatchDir = true; - HDiffPatch.Event.PushLog($"[Header::TryParseHeaderInfo] Signature info: {headerInfoLine}", Verbosity.Debug); - - if (headerInfoLine.Length > 64 || !headerInfoLine -#if !(NETSTANDARD2_0 || NET461_OR_GREATER) - .AsSpan() -#endif - .StartsWith(HdiffHead) - ) throw new FormatException("[Header::TryParseHeaderInfo] This is not a HDiff file format!"); - - string[] hInfoArr = headerInfoLine.Split('&'); - if (hInfoArr.Length == 2) - { - byte pFileVer = TryGetVersion(hInfoArr[0]); - if (pFileVer != 13) throw new FormatException("[Header::TryParseHeaderInfo] HDiff version is unsupported. This patcher only supports the single patch file with version: 13 only!"); - - isPatchDir = false; - - headerInfo.HeaderMagic = hInfoArr[0]; - - Enum.TryParse(hInfoArr[1], true, out headerInfo.CompMode); - HDiffPatch.Event.PushLog($"[Header::TryParseHeaderInfo] Version: {pFileVer} Compression: {headerInfo.CompMode}", Verbosity.Debug); - } - else if (hInfoArr.Length != 3) throw new IndexOutOfRangeException($"[Header::TryParseHeaderInfo] Header info is incomplete! Expecting 3 parts but got {hInfoArr.Length} part(s) instead (Raw: {headerInfoLine})"); - - if (isPatchDir) - { - byte hInfoVer = TryGetVersion(hInfoArr[0]); - if (hInfoVer != 19) throw new FormatException("[Header::TryParseHeaderInfo] HDiff version is unsupported. This patcher only supports the directory patch file with version: 19 only!"); - - if (hInfoArr[1] != "" && !Enum.TryParse(hInfoArr[1], true, out headerInfo.CompMode)) throw new FormatException($"[Header::TryParseHeaderInfo] This patcher doesn't support {hInfoArr[1]} compression!"); - if (string.IsNullOrEmpty(hInfoArr[2])) headerInfo.ChecksumMode = ChecksumMode.NoChecksum; - else if (!Enum.TryParse(hInfoArr[2], true, out headerInfo.ChecksumMode)) throw new FormatException($"[Header::TryParseHeaderInfo] This patcher doesn't support {hInfoArr[2]} checksum!"); - HDiffPatch.Event.PushLog($"[Header::TryParseHeaderInfo] Version: {hInfoVer} ChecksumMode: {headerInfo.ChecksumMode} Compression: {headerInfo.CompMode}", Verbosity.Debug); - - TryReadHeaderAndReferenceInfo(sr, ref headerInfo, ref referenceInfo); - TryReadExternReferenceInfo(sr, diffPath, ref headerInfo, ref referenceInfo); - } - else - { - TryReadNonSingleFileHeaderInfo(sr, diffPath, ref headerInfo); - } - - return isPatchDir; - } - - private static void TryReadExternReferenceInfo(Stream sr, string diffPath, ref HeaderInfo headerInfo, ref DataReferenceInfo referenceInfo) - { - long curPos = sr.Position; - referenceInfo.HeadDataOffset = curPos; - - curPos += referenceInfo.HeadDataCompressedSize > 0 ? referenceInfo.HeadDataCompressedSize : referenceInfo.HeadDataSize; - referenceInfo.PrivateExternDataOffset = curPos; - - curPos += referenceInfo.PrivateExternDataSize; - referenceInfo.ExternDataOffset = curPos; - - curPos += referenceInfo.ExternDataSize; - referenceInfo.HDiffDataOffset = curPos; - referenceInfo.HDiffDataSize = sr.Length - curPos; - - HDiffPatch.Event.PushLog($"[Header::TryReadExternReferenceInfo] headDataOffset: {referenceInfo.HeadDataOffset} | privateExternDataOffset: {referenceInfo.PrivateExternDataOffset} | externDataOffset: {referenceInfo.ExternDataOffset} | hdiffDataOffset: {referenceInfo.HDiffDataOffset} | hdiffDataSize: {referenceInfo.HDiffDataSize}", Verbosity.Debug); - - TryIdentifyDiffType(sr, diffPath, ref headerInfo, ref referenceInfo); - } - - private static void TryIdentifyDiffType(Stream sr, string diffPath, ref HeaderInfo headerInfo, ref DataReferenceInfo referenceInfo) - { - sr.Position = referenceInfo.HDiffDataOffset; - string singleCompressedHeaderLine = sr.ReadStringToNull(); - string[] singleCompressedHeaderArr = singleCompressedHeaderLine.Split('&'); - - // ReSharper disable once AssignmentInConditionalExpression - if (headerInfo.IsSingleCompressedDiff = -#if !(NETSTANDARD2_0 || NET461_OR_GREATER) - singleCompressedHeaderArr[0].AsSpan() is "HDIFFSF20") -#else - singleCompressedHeaderArr[0] == "HDIFFSF20") -#endif - { - TryReadSingleFileHeaderInfo(sr, diffPath, ref headerInfo, referenceInfo); - return; - } - - HDiffPatch.Event.PushLog($"[Header::TryIdentifyDiffType] HDIFF Dir Signature: {singleCompressedHeaderLine}", Verbosity.Debug); - - if (singleCompressedHeaderArr[1] != "" && !Enum.TryParse(singleCompressedHeaderArr[1], true, out headerInfo.CompMode)) throw new FormatException($"[Header::TryIdentifyDiffType] The compression chunk has unsupported compression: {singleCompressedHeaderArr[1]}"); - headerInfo.HeaderMagic = singleCompressedHeaderArr[0]; - - TryReadNonSingleFileHeaderInfo(sr, diffPath, ref headerInfo); - } - - private static void TryReadSingleFileHeaderInfo(Stream sr, string diffPath, ref HeaderInfo headerInfo, DataReferenceInfo referenceInfo) - { - headerInfo.PatchPath = diffPath; - headerInfo.SingleChunkInfo = new DiffSingleChunkInfo(); - - headerInfo.NewDataSize = sr.ReadLong7Bit(); - headerInfo.OldDataSize = sr.ReadLong7Bit(); - - HDiffPatch.Event.PushLog($"[Header::TryReadSingleFileHeaderInfo] oldDataSize: {headerInfo.OldDataSize} | newDataSize: {headerInfo.NewDataSize}", Verbosity.Debug); - - headerInfo.ChunkInfo.CoverCount = sr.ReadLong7Bit(); - headerInfo.StepMemSize = sr.ReadLong7Bit(); - headerInfo.SingleChunkInfo.UncompressedSize = sr.ReadLong7Bit(); - headerInfo.SingleChunkInfo.CompressedSize = sr.ReadLong7Bit(); - headerInfo.SingleChunkInfo.DiffDataPos = sr.Position - referenceInfo.HDiffDataOffset; - - headerInfo.CompressedCount = headerInfo.SingleChunkInfo.CompressedSize > 0 ? 1 : 0; - - HDiffPatch.Event.PushLog($"[Header::TryReadSingleFileHeaderInfo] compressedCount: {headerInfo.CompressedCount}", Verbosity.Debug); - } - - private static void TryReadNonSingleFileHeaderInfo(Stream sr, string diffPath, ref HeaderInfo headerInfo) - { - headerInfo.PatchPath = diffPath; - - long typeEndPos = sr.Position; - headerInfo.NewDataSize = sr.ReadLong7Bit(); - headerInfo.OldDataSize = sr.ReadLong7Bit(); - - HDiffPatch.Event.PushLog($"[Header::TryReadNonSingleFileHeaderInfo] oldDataSize: {headerInfo.OldDataSize} | newDataSize: {headerInfo.NewDataSize}", Verbosity.Debug); - - GetDiffChunkInfo(sr, out headerInfo.ChunkInfo, typeEndPos); - - headerInfo.CompressedCount = (headerInfo.ChunkInfo.CompressCoverBufSize > 1 ? 1 : 0) - + (headerInfo.ChunkInfo.CompressRleCtrlBufSize > 1 ? 1 : 0) - + (headerInfo.ChunkInfo.CompressRleCodeBufSize > 1 ? 1 : 0) - + (headerInfo.ChunkInfo.CompressNewDataDiffSize > 1 ? 1 : 0); - - HDiffPatch.Event.PushLog($"[Header::TryReadNonSingleFileHeaderInfo] compressedCount: {headerInfo.CompressedCount}", Verbosity.Debug); - } - - private static void GetDiffChunkInfo(Stream sr, out DiffChunkInfo chunkInfo, long typeEndPos) - { - chunkInfo = new DiffChunkInfo(); - - HDiffPatch.Event.PushLog($"[Header::GetDiffChunkInfo] typesEndPos: {typeEndPos}", Verbosity.Debug); - - chunkInfo.CoverCount = sr.ReadLong7Bit(); - chunkInfo.CompressSizeBeginPos = sr.Position; - - HDiffPatch.Event.PushLog($"[Header::GetDiffChunkInfo] coverCount: {chunkInfo.CoverCount} | compressSizeBeginPos: {chunkInfo.CompressSizeBeginPos}", Verbosity.Debug); - - chunkInfo.CoverBufSize = sr.ReadLong7Bit(); - chunkInfo.CompressCoverBufSize = sr.ReadLong7Bit(); - chunkInfo.RleCtrlBufSize = sr.ReadLong7Bit(); - chunkInfo.CompressRleCtrlBufSize = sr.ReadLong7Bit(); - chunkInfo.RleCodeBufSize = sr.ReadLong7Bit(); - chunkInfo.CompressRleCodeBufSize = sr.ReadLong7Bit(); - chunkInfo.NewDataDiffSize = sr.ReadLong7Bit(); - chunkInfo.CompressNewDataDiffSize = sr.ReadLong7Bit(); - - HDiffPatch.Event.PushLog($"[Header::GetDiffChunkInfo] cover_buf_size: {chunkInfo.CoverBufSize} | compress_cover_buf_size: {chunkInfo.CompressCoverBufSize}", Verbosity.Debug); - HDiffPatch.Event.PushLog($"[Header::GetDiffChunkInfo] rle_ctrlBuf_size: {chunkInfo.RleCtrlBufSize} | compress_rle_ctrlBuf_size: {chunkInfo.CompressRleCtrlBufSize}", Verbosity.Debug); - HDiffPatch.Event.PushLog($"[Header::GetDiffChunkInfo] rle_codeBuf_size: {chunkInfo.RleCodeBufSize} | compress_rle_codeBuf_size: {chunkInfo.CompressRleCodeBufSize}", Verbosity.Debug); - HDiffPatch.Event.PushLog($"[Header::GetDiffChunkInfo] newDataDiff_size: {chunkInfo.NewDataDiffSize} | compress_newDataDiff_size: {chunkInfo.CompressNewDataDiffSize}", Verbosity.Debug); - - chunkInfo.HeadEndPos = sr.Position; - chunkInfo.CoverEndPos = chunkInfo.HeadEndPos + - (chunkInfo.CompressCoverBufSize > 0 ? - chunkInfo.CompressCoverBufSize : - chunkInfo.CoverBufSize); - - HDiffPatch.Event.PushLog($"[Header::GetDiffChunkInfo] headEndPos: {chunkInfo.HeadEndPos} | coverEndPos: {chunkInfo.CoverEndPos}", Verbosity.Debug); - } - - private static void TryReadHeaderAndReferenceInfo(Stream sr, ref HeaderInfo headerInfo, ref DataReferenceInfo referenceInfo) - { - headerInfo.IsInputDir = sr.ReadBoolean(); - headerInfo.IsOutputDir = sr.ReadBoolean(); - - HDiffPatch.Event.PushLog($"[Header::TryReadHeaderAndReferenceInfo] Is In/Out a Dir -> Input: {headerInfo.IsInputDir} / Output: {headerInfo.IsOutputDir}", Verbosity.Debug); - - referenceInfo.InputDirCount = sr.ReadLong7Bit(); - referenceInfo.InputSumSize = sr.ReadLong7Bit(); - - referenceInfo.OutputDirCount = sr.ReadLong7Bit(); - referenceInfo.OutputSumSize = sr.ReadLong7Bit(); - - HDiffPatch.Event.PushLog($"[Header::TryReadHeaderAndReferenceInfo] InDir Count/SumSize: {referenceInfo.InputDirCount}/{referenceInfo.InputSumSize} | OutDir Count/SumSize: {referenceInfo.OutputSumSize}/{referenceInfo.InputSumSize}", Verbosity.Debug); - - referenceInfo.InputRefFileCount = sr.ReadLong7Bit(); - referenceInfo.InputRefFileSize = sr.ReadLong7Bit(); - - referenceInfo.OutputRefFileCount = sr.ReadLong7Bit(); - referenceInfo.OutputRefFileSize = sr.ReadLong7Bit(); - - HDiffPatch.Event.PushLog($"[Header::TryReadHeaderAndReferenceInfo] InRef Count/Size: {referenceInfo.InputRefFileCount}/{referenceInfo.InputRefFileSize} | OutRef Count/Size: {referenceInfo.OutputRefFileCount}/{referenceInfo.OutputRefFileSize}", Verbosity.Debug); - - referenceInfo.SameFilePairCount = sr.ReadLong7Bit(); - referenceInfo.SameFileSize = sr.ReadLong7Bit(); - - HDiffPatch.Event.PushLog($"[Header::TryReadHeaderAndReferenceInfo] IdenticalPair Count/Size: {referenceInfo.SameFilePairCount}/{referenceInfo.SameFileSize}", Verbosity.Debug); - - referenceInfo.NewExecuteCount = sr.ReadInt7Bit(); - referenceInfo.PrivateReservedDataSize = sr.ReadLong7Bit(); - referenceInfo.PrivateExternDataSize = sr.ReadLong7Bit(); - referenceInfo.ExternDataSize = sr.ReadLong7Bit(); - - HDiffPatch.Event.PushLog($"[Header::TryReadHeaderAndReferenceInfo] newExecuteCount: {referenceInfo.NewExecuteCount} | privateReservedDataSize: {referenceInfo.PrivateReservedDataSize} | privateExternDataSize: {referenceInfo.PrivateExternDataSize} | privateExternDataSize: {referenceInfo.ExternDataSize}", Verbosity.Debug); - - referenceInfo.CompressSizeBeginPos = sr.Position; - - referenceInfo.HeadDataSize = sr.ReadLong7Bit(); - referenceInfo.HeadDataCompressedSize = sr.ReadLong7Bit(); - referenceInfo.ChecksumByteSize = (byte)sr.ReadLong7Bit(); - headerInfo.DirDataIsCompressed = referenceInfo.HeadDataCompressedSize > 0; - referenceInfo.ChecksumOffset = sr.Position; - - HDiffPatch.Event.PushLog($"[Header::TryReadHeaderAndReferenceInfo] compressSizeBeginPos: {referenceInfo.CompressSizeBeginPos} | headDataSize: {referenceInfo.HeadDataSize} | headDataCompressedSize: {referenceInfo.HeadDataCompressedSize} | checksumByteSize: {referenceInfo.ChecksumByteSize}", Verbosity.Debug); - HDiffPatch.Event.PushLog($"[Header::TryReadHeaderAndReferenceInfo] checksumOffset: {referenceInfo.ChecksumOffset} | dirDataIsCompressed: {headerInfo.DirDataIsCompressed}", Verbosity.Debug); - - if (referenceInfo.ChecksumByteSize > 0) - { - HDiffPatch.Event.PushLog($"[Header::TryReadHeaderAndReferenceInfo] Seeking += {referenceInfo.ChecksumByteSize * 4} bytes from checksum bytes!", Verbosity.Debug); - TrySeekHeader(sr, referenceInfo.ChecksumByteSize * 4); - } - } - - private static void TrySeekHeader(Stream sr, int skipLongSize) - { - int len = Math.Min(4 << 10, skipLongSize); - HDiffPatch.Event.PushLog($"[Header::TrySeekHeader] Seeking from: {sr.Position} += {skipLongSize} to {sr.Position + skipLongSize}", Verbosity.Debug); - sr.Seek(len, SeekOrigin.Current); - } - -#if !(NETSTANDARD2_0 || NET461_OR_GREATER) - private static byte TryGetVersion(ReadOnlySpan str) - { - int lastIndexOf = str.IndexOf(HdiffHead); - if (lastIndexOf < 0) throw new IndexOutOfRangeException($"[Header::TryGetVersion] Version string is invalid! Cannot find the matching start of \"HDIFF\". Getting: {str.ToString()} instead"); - - ReadOnlySpan numSpan = str.Slice(lastIndexOf + HdiffHead.Length); - if (byte.TryParse(numSpan, out byte ret)) return ret; - - throw new InvalidDataException($"[Header::TryGetVersion] Version string is invalid! Value: {numSpan.ToString()} (Raw: {str.ToString()})"); - } -#else - private static byte TryGetVersion(string str) - { - int lastIndexOf = str.IndexOf(HdiffHead, StringComparison.OrdinalIgnoreCase); - if (lastIndexOf < 0) throw new IndexOutOfRangeException($"[Header::TryGetVersion] Version string is invalid! Cannot find the matching start of \"HDIFF\". Getting: {str} instead"); - - string numStr = str.Substring(lastIndexOf + HdiffHead.Length); - if (byte.TryParse(numStr, out byte ret)) return ret; - - throw new InvalidDataException($"[Header::TryGetVersion] Version string is invalid! Value: {numStr} (Raw: {str})"); - } -#endif - } -} diff --git a/SharpHDiffPatch.Core/Patch/IPatch.cs b/SharpHDiffPatch.Core/Patch/IPatch.cs deleted file mode 100644 index 26f1054..0000000 --- a/SharpHDiffPatch.Core/Patch/IPatch.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System; - -namespace SharpHDiffPatch.Core.Patch; - -public interface IPatch -{ - void Patch(string input, string output, Action writeBytesDelegate, bool useBufferedPatch, bool useFullBuffer, bool useFastBuffer); -} diff --git a/SharpHDiffPatch.Core/Patch/PatchCore.cs b/SharpHDiffPatch.Core/Patch/PatchCore.cs deleted file mode 100644 index 92e56d2..0000000 --- a/SharpHDiffPatch.Core/Patch/PatchCore.cs +++ /dev/null @@ -1,638 +0,0 @@ -using SharpHDiffPatch.Core.Binary; -using SharpHDiffPatch.Core.Binary.Compression; -using System; -using System.Buffers; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -#if !(NETSTANDARD2_0 || NET461_OR_GREATER) -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; -using System.Runtime.Intrinsics.X86; -#endif -using System.Threading; -using System.Threading.Tasks; -// ReSharper disable ForCanBeConvertedToForeach -// ReSharper disable ConvertIfStatementToSwitchStatement - -#nullable enable -namespace SharpHDiffPatch.Core.Patch -{ - internal struct RleRefClipStruct - { - public long MemCopyLength; - public long MemSetLength; - public byte MemSetValue; - } - - internal readonly struct CoverHeader - { - internal readonly long OldPos; - internal readonly long NewPos; - internal readonly long CoverLength; - internal readonly long NextCoverIndex; - - internal CoverHeader(long oldPos, long newPos, long coverLength, long nextCoverIndex) - { - OldPos = oldPos; - NewPos = newPos; - CoverLength = coverLength; - NextCoverIndex = nextCoverIndex; - } - } - - internal interface IPatchCore - { - void SetDirectoryReferencePair(DirectoryReferencePair pair); - - void SetSizeToBePatched(long sizeToBePatched, long sizeToPatch = 0); - - void UncoverBufferClipsStream(Stream[] clips, Stream inputStream, Stream outputStream, HeaderInfo headerInfo); - - Stream GetBufferStreamFromOffset(HDiffCompressionMode compMode, Stream sourceStream, - long start, long length, long compLength, out long outLength, bool isBuffered, bool isFastBufferUsed); - } - - internal sealed class PatchCore : IPatchCore - { - internal unsafe delegate void RleProc(ref RleRefClipStruct rleLoader, MemoryStream outCache, ref long copyLength, int decodeStep, byte* rlePtr, byte[] rleBuffer, int rleBufferIdx, byte* oldPtr); - internal static RleProc RleProcDelegate; - - internal const int KSignTagBit = 1; - internal const int KByteRleType = 2; - internal const int MaxMemBufferLen = 7 << 20; - internal const int MaxMemBufferLimit = 10 << 20; - internal const int MaxArrayCopyLen = 1 << 18; - internal const int MaxArrayPoolLen = 4 << 20; - internal const int MaxArrayPoolSecondOffset = MaxArrayPoolLen / 2; - - internal CancellationToken Token; - internal long SizeToBePatched; - internal long SizePatched; - internal Stopwatch Stopwatch; - internal string PathInput; - internal string PathOutput; - internal DirectoryReferencePair? DirReferencePair; - - private readonly Action? _writeBytesDelegate; - - static unsafe PatchCore() - { - RleProcDelegate = -#if !(NETSTANDARD2_0 || NET461_OR_GREATER) - Sse2.IsSupported ? - TBytesSetRleVectorSse2Simd : -#if NET7_0_OR_GREATER - AdvSimd.IsSupported && Vector128.IsHardwareAccelerated ? - TBytesSetRleVectorAdvSimd128 : - AdvSimd.IsSupported && Vector64.IsHardwareAccelerated ? - TBytesSetRleVectorAdvSimd64 : -#else - AdvSimd.IsSupported ? - TBytesSetRleVectorAdvSimd64 : -#endif -#endif - TBytesSetRleVectorSoftware; - } - - internal PatchCore(long sizeToBePatched, Stopwatch stopwatch, string inputPath, string outputPath, Action? writeBytesDelegate, CancellationToken token) - { - Token = token; - SizeToBePatched = sizeToBePatched; - Stopwatch = stopwatch; - SizePatched = 0; - PathInput = inputPath; - PathOutput = outputPath; - _writeBytesDelegate = writeBytesDelegate; - } - - public void SetDirectoryReferencePair(DirectoryReferencePair pair) => DirReferencePair = pair; - - public void SetSizeToBePatched(long sizeToBePatched, long sizeToPatch = 0) - { - SizeToBePatched = sizeToBePatched; - SizePatched = sizeToPatch; - } - - public Stream GetBufferStreamFromOffset(HDiffCompressionMode compMode, Stream sourceStream, - long start, long length, long compLength, out long outLength, bool isBuffered, bool isFastBufferUsed) - { - sourceStream.Position = start; - - CompressionStreamHelper.GetDecompressStreamPlugin(compMode, sourceStream, out Stream returnStream, length, compLength, out outLength, isBuffered); - - if (!isBuffered || isFastBufferUsed) return returnStream; - HDiffPatch.Event.PushLog($"[PatchCore::GetBufferStreamFromOffset] Caching stream from offset: {start} with length: {(compLength > 0 ? compLength : length)}"); - using (returnStream) - { - MemoryStream stream = CreateAndCopyToMemoryStream(returnStream); - stream.Position = 0; - return stream; - } - - } - - private MemoryStream CreateAndCopyToMemoryStream(Stream source) - { - MemoryStream returnStream = new(); - byte[] buffer = ArrayPool.Shared.Rent(MaxArrayPoolLen); - - try - { - int read; -#if !(NETSTANDARD2_0 || NET461_OR_GREATER) - while ((read = source.Read(buffer)) > 0) -#else - while ((read = source.Read(buffer, 0, buffer.Length)) > 0) -#endif - { - Token.ThrowIfCancellationRequested(); - returnStream.Write(buffer, 0, read); - } - - return returnStream; - } - finally - { - ArrayPool.Shared.Return(buffer); - } - } - - public void UncoverBufferClipsStream(Stream[] clips, Stream inputStream, Stream outputStream, HeaderInfo headerInfo) => WriteCoverStreamToOutput(clips, inputStream, outputStream, headerInfo.ChunkInfo.CoverCount, headerInfo.ChunkInfo.CoverBufSize, headerInfo.NewDataSize); - - internal static IEnumerable EnumerateCoverHeaders(Stream coverReader, long coverSize, long coverCount) - { - long lastOldPosBack = 0, - lastNewPosBack = 0; - - if (coverSize < MaxMemBufferLen) - { - HDiffPatch.Event.PushLog($"[PatchCore::EnumerateCoverHeaders] Enumerate cover counts from buffer with size: {coverSize}", Verbosity.Verbose); - byte[] buffer = new byte[coverSize]; - coverReader.ReadExactly(buffer, 0, buffer.Length); - - int offset = 0; - while (coverCount-- > 0) - { - long oldPosBack = lastOldPosBack; - long newPosBack = lastNewPosBack; - - byte pSign = buffer[offset++]; - - byte incOldPosSign = (byte)(pSign >> (8 - KSignTagBit)); - long incOldPos = buffer.ReadLong7Bit(ref offset, KSignTagBit, pSign); - long oldPos = incOldPosSign == 0 ? oldPosBack + incOldPos : oldPosBack - incOldPos; - - long copyLength = buffer.ReadLong7Bit(ref offset); - long coverLength = buffer.ReadLong7Bit(ref offset); - oldPosBack = oldPos; - newPosBack += copyLength; - - oldPosBack += coverLength; - - yield return new CoverHeader(oldPos, newPosBack, coverLength, coverCount); - newPosBack += coverLength; - - lastOldPosBack = oldPosBack; - lastNewPosBack = newPosBack; - } - } - else - { - HDiffPatch.Event.PushLog($"[PatchCore::EnumerateCoverHeaders] Enumerate cover counts directly from stream with size: {coverSize}", Verbosity.Verbose); - while (coverCount-- > 0) - { - long oldPosBack = lastOldPosBack; - long newPosBack = lastNewPosBack; - - byte pSign = (byte)coverReader.ReadByte(); - - byte incOldPosSign = (byte)(pSign >> (8 - KSignTagBit)); - long incOldPos = coverReader.ReadLong7Bit(KSignTagBit, pSign); - long oldPos = incOldPosSign == 0 ? oldPosBack + incOldPos : oldPosBack - incOldPos; - - long copyLength = coverReader.ReadLong7Bit(); - long coverLength = coverReader.ReadLong7Bit(); - newPosBack += copyLength; - oldPosBack = oldPos; - - oldPosBack += coverLength; - - yield return new CoverHeader(oldPos, newPosBack, coverLength, coverCount); - newPosBack += coverLength; - - lastOldPosBack = oldPosBack; - lastNewPosBack = newPosBack; - } - } - } - - internal void RunCopySimilarFilesRoutine() - { - if (DirReferencePair == null) return; - HDiffPatch.Event.PushLog("Start copying similar data"); - CopyOldSimilarToNewFiles(DirReferencePair); - - TimeSpan timeTaken = Stopwatch.Elapsed; - HDiffPatch.Event.PushLog($"Copying similar data has been finished in {timeTaken.TotalSeconds} seconds ({timeTaken.TotalMilliseconds} ms)"); - HDiffPatch.Event.PushLog("Starting patching process..."); - Stopwatch.Restart(); - } - - private void WriteCoverStreamToOutput(Stream[] clips, Stream inputStream, Stream outputStream, long coverCount, long coverSize, long newDataSize) - { - byte[] sharedBuffer = ArrayPool.Shared.Rent(MaxArrayPoolLen); - MemoryStream cacheOutputStream = new(); - - try - { - RunCopySimilarFilesRoutine(); - - long newPosBack = 0; - RleRefClipStruct rleStruct = new(); - CoverHeader[] headers = [.. EnumerateCoverHeaders(clips[0], coverSize, coverCount)]; - - for (int i = 0; i < headers.Length; i++) - { - CoverHeader cover = headers[i]; - - Token.ThrowIfCancellationRequested(); - - if (newPosBack < cover.NewPos) - { - long copyLength = cover.NewPos - newPosBack; - inputStream.Position = cover.OldPos; - - TBytesCopyStreamFromOldClip(cacheOutputStream, clips[3], copyLength, sharedBuffer); - TBytesDetermineRleType(ref rleStruct, cacheOutputStream, copyLength, sharedBuffer, clips[1], clips[2]); - } - - TBytesCopyOldClipPatch(cacheOutputStream, inputStream, ref rleStruct, cover.OldPos, cover.CoverLength, sharedBuffer, clips[1], clips[2]); - newPosBack = cover.NewPos + cover.CoverLength; - - if (cacheOutputStream.Length > MaxMemBufferLimit || cover.NextCoverIndex == 0) - WriteInMemoryOutputToStream(cacheOutputStream, outputStream); - } - - if (newPosBack < newDataSize) - { - long copyLength = newDataSize - newPosBack; - TBytesCopyStreamFromOldClip(cacheOutputStream, clips[3], copyLength, sharedBuffer); - TBytesDetermineRleType(ref rleStruct, cacheOutputStream, copyLength, sharedBuffer, clips[1], clips[2]); - WriteInMemoryOutputToStream(cacheOutputStream, outputStream); - } - - SpawnCorePatchFinishedMsg(); - } - finally - { - ArrayPool.Shared.Return(sharedBuffer); - Stopwatch.Stop(); - cacheOutputStream.Dispose(); - for (int i = 0; i < clips.Length; i++) clips[i].Dispose(); - inputStream.Dispose(); - outputStream.Dispose(); - } - } - - internal void WriteInMemoryOutputToStream(MemoryStream cacheOutputStream, Stream outputStream) - { - long oldPos = outputStream.Position; - - cacheOutputStream.Position = 0; - cacheOutputStream.CopyTo(outputStream); - cacheOutputStream.SetLength(0); - - long newPos = outputStream.Position; - long read = newPos - oldPos; - - _writeBytesDelegate?.Invoke(read); - HDiffPatch.UpdateEvent(read, ref SizePatched, ref SizeToBePatched, Stopwatch); - } - - internal void SpawnCorePatchFinishedMsg() - { - TimeSpan timeTaken = Stopwatch.Elapsed; - HDiffPatch.Event.PushLog($"Patching has been finished in {timeTaken.TotalSeconds} seconds ({timeTaken.TotalMilliseconds} ms)"); - } - - private static void TBytesCopyOldClipPatch(MemoryStream outCache, Stream inputStream, ref RleRefClipStruct rleLoader, long oldPos, long addLength, byte[] sharedBuffer, - Stream rleCtrlStream, Stream rleCodeStream) - { - long lastPos = outCache.Position; - inputStream.Position = oldPos; - - TBytesCopyStreamInner(inputStream, outCache, sharedBuffer, (int)addLength); - - outCache.Position = lastPos; - TBytesDetermineRleType(ref rleLoader, outCache, addLength, sharedBuffer, rleCtrlStream, rleCodeStream); - } - - internal static void TBytesCopyStreamFromOldClip(MemoryStream outCache, Stream copyReader, long copyLength, byte[] sharedBuffer) - { - long lastPos = outCache.Position; - TBytesCopyStreamInner(copyReader, outCache, sharedBuffer, (int)copyLength); - outCache.Position = lastPos; - } - - internal static void TBytesCopyStreamInner(Stream input, MemoryStream output, byte[] sharedBuffer, int readLen) - { - AddBytesCopy: - int toRead = Math.Min(sharedBuffer.Length, readLen); - input.ReadExactly(sharedBuffer, 0, toRead); - output.Write(sharedBuffer, 0, toRead); - readLen -= toRead; - if (toRead != 0) goto AddBytesCopy; - } - - private static void TBytesDetermineRleType(ref RleRefClipStruct rleLoader, MemoryStream outCache, long copyLength, byte[] sharedBuffer, - Stream rleCtrlStream, Stream rleCodeStream) - { - TBytesSetRle(ref rleLoader, outCache, ref copyLength, sharedBuffer, rleCodeStream); - - while (copyLength > 0) - { - byte pSign = (byte)rleCtrlStream.ReadByte(); - byte type = (byte)(pSign >> (8 - KByteRleType)); - long length = rleCtrlStream.ReadLong7Bit(KByteRleType, pSign); - ++length; - - if (type == 3) - { - rleLoader.MemCopyLength = length; - TBytesSetRle(ref rleLoader, outCache, ref copyLength, sharedBuffer, rleCodeStream); - continue; - } - - rleLoader.MemSetLength = length; - if (type == 2) - { - rleLoader.MemSetValue = (byte)rleCodeStream.ReadByte(); - TBytesSetRle(ref rleLoader, outCache, ref copyLength, sharedBuffer, rleCodeStream); - continue; - } - - /* If the type is 1, then 0 - 1. This should result -1 in int but since - * we cast it to byte, then it underflow and set it to 255. - * This method is the same as: - * if (type == 0) - * rleLoader.memSetValue = 0x00; // or 0 in byte - * else - * rleLoader.memSetValue = 0xFF; // or 255 in byte - */ - rleLoader.MemSetValue = (byte)(0x00 - type); - TBytesSetRle(ref rleLoader, outCache, ref copyLength, sharedBuffer, rleCodeStream); - } - } - - private static unsafe void TBytesSetRle(ref RleRefClipStruct rleLoader, MemoryStream outCache, ref long copyLength, byte[] sharedBuffer, Stream rleCodeStream) - { - TBytesSetRleSingle(ref rleLoader, outCache, ref copyLength, sharedBuffer); - - if (rleLoader.MemCopyLength == 0) return; - int decodeStep = (int)(rleLoader.MemCopyLength > copyLength ? copyLength : rleLoader.MemCopyLength); - - long lastPosCopy = outCache.Position; - rleCodeStream.ReadExactly(sharedBuffer, 0, decodeStep); - outCache.ReadExactly(sharedBuffer, MaxArrayPoolSecondOffset, decodeStep); - outCache.Position = lastPosCopy; - - fixed (byte* rlePtr = &sharedBuffer[0], oldPtr = &sharedBuffer[MaxArrayPoolSecondOffset]) - { - RleProcDelegate(ref rleLoader, outCache, ref copyLength, decodeStep, rlePtr, sharedBuffer, 0, oldPtr); - } - } - - internal static void TBytesSetRleSingle(ref RleRefClipStruct rleLoader, MemoryStream outCache, ref long copyLength, byte[] sharedBuffer) - { - if (rleLoader.MemSetLength == 0) return; - long memSetStep = rleLoader.MemSetLength <= copyLength ? rleLoader.MemSetLength : copyLength; - if (rleLoader.MemSetValue != 0) - { - int length = (int)memSetStep; - long lastPos = outCache.Position; - _ = outCache.Read(sharedBuffer, 0, length); - outCache.Position = lastPos; - - SetAddRLESingle: - sharedBuffer[--length] += rleLoader.MemSetValue; - if (length > 0) goto SetAddRLESingle; - - outCache.Write(sharedBuffer, 0, (int)memSetStep); - } - else - { - outCache.Position += memSetStep; - } - - copyLength -= memSetStep; - rleLoader.MemSetLength -= memSetStep; - } - - internal static unsafe void TBytesSetRleVectorSoftware(ref RleRefClipStruct rleLoader, MemoryStream outCache, ref long copyLength, int decodeStep, byte* rlePtr, byte[] rleBuffer, int rleBufferIdx, byte* oldPtr) - { - int index = 0; - - AddRleSoftware: - *(rlePtr + index) += *(oldPtr + index); - if (++index < decodeStep) goto AddRleSoftware; - - WriteRleResultToStream(ref rleLoader, outCache, rleBuffer, rleBufferIdx, ref copyLength, decodeStep); - } - -#if !(NETSTANDARD2_0 || NET461_OR_GREATER) - internal static unsafe void TBytesSetRleVectorAdvSimd128(ref RleRefClipStruct rleLoader, MemoryStream outCache, ref long copyLength, int decodeStep, byte* rlePtr, byte[] rleBuffer, int rleBufferIdx, byte* oldPtr) - { - int len = decodeStep; - - if (len >= Vector128.Count) - { - AddVectorArm64_128: - len -= Vector128.Count; - Vector128 resultVector = AdvSimd.Add(*(Vector128*)(rlePtr + len), *(Vector128*)(oldPtr + len)); - AdvSimd.Store(rlePtr + len, resultVector); - if (len >= Vector128.Count) goto AddVectorArm64_128; - } - - WriteRemainedRleSimdResultToStream(ref rleLoader, len, outCache, ref copyLength, decodeStep, rlePtr, rleBuffer, rleBufferIdx, oldPtr); - } - - - internal static unsafe void TBytesSetRleVectorAdvSimd64(ref RleRefClipStruct rleLoader, MemoryStream outCache, ref long copyLength, int decodeStep, byte* rlePtr, byte[] rleBuffer, int rleBufferIdx, byte* oldPtr) - { - int len = decodeStep; - - if (len >= Vector64.Count) - { - AddVectorArm64_64: - len -= Vector64.Count; - Vector64 resultVector = AdvSimd.Add(*(Vector64*)(rlePtr + len), *(Vector64*)(oldPtr + len)); - AdvSimd.Store(rlePtr + len, resultVector); - if (len >= Vector64.Count) goto AddVectorArm64_64; - } - - WriteRemainedRleSimdResultToStream(ref rleLoader, len, outCache, ref copyLength, decodeStep, rlePtr, rleBuffer, rleBufferIdx, oldPtr); - } - - internal static unsafe void TBytesSetRleVectorSse2Simd(ref RleRefClipStruct rleLoader, MemoryStream outCache, ref long copyLength, int decodeStep, byte* rlePtr, byte[] rleBuffer, int rleBufferIdx, byte* oldPtr) - { - int len = decodeStep; - - if (len >= Vector128.Count) - { - AddVectorSse2: - len -= Vector128.Count; - Vector128 resultVector = Sse2.Add(*(Vector128*)(rlePtr + len), *(Vector128*)(oldPtr + len)); - Sse2.Store(rlePtr + len, resultVector); - if (len >= Vector128.Count) goto AddVectorSse2; - } - - WriteRemainedRleSimdResultToStream(ref rleLoader, len, outCache, ref copyLength, decodeStep, rlePtr, rleBuffer, rleBufferIdx, oldPtr); - } - - private static unsafe void WriteRemainedRleSimdResultToStream(ref RleRefClipStruct rleLoader, int len, MemoryStream outCache, ref long copyLength, int decodeStep, byte* rlePtr, byte[] rleBuffer, int rleBufferIdx, byte* oldPtr) - { - if (len >= 4) - { - AddRemainsFourStep: - len -= 4; - *(rlePtr + len) += *(oldPtr + len); - *(rlePtr + 1 + len) += *(oldPtr + 1 + len); - *(rlePtr + 2 + len) += *(oldPtr + 2 + len); - *(rlePtr + 3 + len) += *(oldPtr + 3 + len); - if (len >= 4) goto AddRemainsFourStep; - } - - AddRemainsVectorRLE: - if (len == 0) goto WriteAllVectorRLE; - *(rlePtr + --len) += *(oldPtr + len); - goto AddRemainsVectorRLE; - - WriteAllVectorRLE: - WriteRleResultToStream(ref rleLoader, outCache, rleBuffer, rleBufferIdx, ref copyLength, decodeStep); - } -#endif - - private static void WriteRleResultToStream(ref RleRefClipStruct rleLoader, MemoryStream outCache, byte[] rleBuffer, int rleBufferIdx, ref long copyLength, int decodeStep) - { - outCache.Write(rleBuffer, rleBufferIdx, decodeStep); - - rleLoader.MemCopyLength -= decodeStep; - copyLength -= decodeStep; - } - - internal static bool IsPathADir( -#if !(NETSTANDARD2_0 || NET461_OR_GREATER) - ReadOnlySpan -#else - string -#endif - // ReSharper disable once UseIndexFromEndExpression - input) => input.Length == 0 || input[input.Length - 1] == '/'; - - internal static ref string NewPathByIndex(string[] source, long index) => ref source[index]; - - private void CopyOldSimilarToNewFiles(DirectoryReferencePair dirData) - { - int curNewRefIndex = 0; - int curPathIndex = 0; - int curSamePairIndex = 0; - int newRefCount = dirData.NewRefList.Length; - int samePairCount = dirData.DataSamePairList.Length; - int pathCount = dirData.NewUtf8PathList.Length; - - try - { - Parallel.ForEach(dirData.DataSamePairList, new ParallelOptions { CancellationToken = Token }, (pair) => - { - bool isPathADir = IsPathADir(dirData.NewUtf8PathList[pair.NewIndex]); - if (isPathADir) return; - - CopyFileByPairIndex(dirData.OldUtf8PathList, dirData.NewUtf8PathList, pair.OldIndex, pair.NewIndex); - }); - } - catch (AggregateException ex) - { - throw ex.Flatten().InnerExceptions.First(); - } - - while (curPathIndex < pathCount) - { - if (curNewRefIndex < newRefCount - && curPathIndex == (dirData.NewRefList.Length > 0 ? (int)dirData.NewRefList[curNewRefIndex] : curNewRefIndex)) - { - bool isPathADir = IsPathADir(dirData.NewUtf8PathList[(int)dirData.NewRefList[curNewRefIndex]]); - - if (isPathADir) ++curPathIndex; - ++curNewRefIndex; - } - else if (curSamePairIndex < samePairCount - && curPathIndex == (int)dirData.DataSamePairList[curSamePairIndex].NewIndex) - { - ++curSamePairIndex; - ++curPathIndex; - } - else - { -#if !(NETSTANDARD2_0 || NET461_OR_GREATER) - ReadOnlySpan -#else - string -#endif - pathByIndex = NewPathByIndex(dirData.NewUtf8PathList, curPathIndex); - string combinedNewPath = Path.Combine(PathOutput, pathByIndex.ToString()); - bool isPathADir = false; - - if (pathByIndex.Length > 0) - { - isPathADir = IsPathADir(pathByIndex); - - if (isPathADir && !Directory.Exists(combinedNewPath)) Directory.CreateDirectory(combinedNewPath); - else if (!isPathADir && !File.Exists(combinedNewPath)) File.Create(combinedNewPath).Dispose(); - } - - HDiffPatch.Event.PushLog($"[PatchCore::CopyOldSimilarToNewFiles] Created a new {(isPathADir ? "directory" : "empty file")}: {combinedNewPath}", Verbosity.Debug); - - ++curPathIndex; - } - } - } - - private void CopyFileByPairIndex(string[] oldList, string[] newList, long oldIndex, long newIndex) - { - ref string oldPath = ref oldList[oldIndex]; - ref string newPath = ref newList[newIndex]; - string oldFullPath = Path.Combine(PathInput, oldPath); - string newFullPath = Path.Combine(PathOutput, newPath); - string? newDirFullPath = Path.GetDirectoryName(newFullPath); - if (!string.IsNullOrEmpty(newDirFullPath)) - Directory.CreateDirectory(newDirFullPath); - - HDiffPatch.Event.PushLog($"[PatchCore::CopyFileByPairIndex] Copying similar file to target path: {oldFullPath} -> {newFullPath}", Verbosity.Debug); - CopyFile(oldFullPath, newFullPath); - } - - private void CopyFile(string inputPath, string outputPath) - { -#if NET6_0_OR_GREATER - byte[] buffer = GC.AllocateUninitializedArray(MaxArrayCopyLen); -#else - byte[] buffer = new byte[MaxArrayCopyLen]; -#endif - using FileStream ifs = new(inputPath, FileMode.Open, FileAccess.Read, FileShare.Read); - using FileStream ofs = new(outputPath, FileMode.Create, FileAccess.Write, FileShare.Write); - int read; -#if !(NETSTANDARD2_0 || NET461_OR_GREATER) - while ((read = ifs.Read(buffer)) > 0) -#else - while ((read = ifs.Read(buffer, 0, buffer.Length)) > 0) -#endif - { - Token.ThrowIfCancellationRequested(); - ofs.Write(buffer, 0, read); - HDiffPatch.UpdateEvent(read, ref SizePatched, ref SizeToBePatched, Stopwatch); - } - } - } -} diff --git a/SharpHDiffPatch.Core/Patch/PatchCoreFastBuffer.cs b/SharpHDiffPatch.Core/Patch/PatchCoreFastBuffer.cs deleted file mode 100644 index 8d28779..0000000 --- a/SharpHDiffPatch.Core/Patch/PatchCoreFastBuffer.cs +++ /dev/null @@ -1,368 +0,0 @@ -using SharpHDiffPatch.Core.Binary; -using SharpHDiffPatch.Core.Binary.Compression; -using System; -using System.Buffers; -using System.Diagnostics; -using System.IO; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Threading; -using System.Threading.Tasks; - -namespace SharpHDiffPatch.Core.Patch -{ - internal sealed class PatchCoreFastBuffer : IPatchCore - { - private const int MaxMemBufferLenBig = 32 << 20; - private const int MaxArrayPoolLen = 4 << 20; - private const int MaxArrayPoolSecondOffset = MaxArrayPoolLen / 2; -#if NET6_0_OR_GREATER - private const int MinUninitializedArrayLen = 2 << 10; -#endif - private readonly PatchCore _core; - - internal PatchCoreFastBuffer(long sizeToBePatched, Stopwatch stopwatch, string inputPath, string outputPath, Action writeBytesDelegate, CancellationToken token) - { - _core = new PatchCore(sizeToBePatched, stopwatch, inputPath, outputPath, writeBytesDelegate, token); - } - - public void SetDirectoryReferencePair(DirectoryReferencePair pair) => _core.SetDirectoryReferencePair(pair); - - public void SetSizeToBePatched(long sizeToBePatched, long sizeToPatch = 0) => _core.SetSizeToBePatched(sizeToBePatched, sizeToPatch); - - public Stream GetBufferStreamFromOffset(HDiffCompressionMode compMode, Stream sourceStream, - long start, long length, long compLength, out long outLength, bool isBuffered, bool isFastBufferUsed) => - _core.GetBufferStreamFromOffset(compMode, sourceStream, start, length, compLength, out outLength, isBuffered, isFastBufferUsed); - - public void UncoverBufferClipsStream(Stream[] clips, Stream inputStream, Stream outputStream, HeaderInfo headerInfo) - { - if (!PatchSizeHelper.CanUseFastBuffer(headerInfo)) - { - HDiffPatch.Event.PushLog("[PatchCoreFastBuffer::UncoverBufferClipsStream] Fast buffer requirements exceeded; delegating to streaming patch core."); - _core.UncoverBufferClipsStream(clips, inputStream, outputStream, headerInfo); - return; - } - - if (_core.DirReferencePair != null) - { - Task[] parallelTasks = - [ - Task.Run(() => WriteCoverStreamToOutputFast(clips, inputStream, outputStream, headerInfo)), - Task.Run(_core.RunCopySimilarFilesRoutine) - ]; - - Task.WaitAll(parallelTasks); - } - else - WriteCoverStreamToOutputFast(clips, inputStream, outputStream, headerInfo); - - _core.SpawnCorePatchFinishedMsg(); - } - - internal static void CreateCoverHeaderAsOutputBuffer(Stream coverStream, byte[] outputBuffer, long coverSize, long coverCount) - { - const int sizeOfLong = sizeof(long) * 4; - const int kSignTagBit = 1; - - if (coverSize == 0) - { - return; - } - - byte[] sevenBitCoverBuffer = ArrayPool.Shared.Rent(PatchSizeHelper.ToCheckedInt32(coverSize, nameof(coverSize))); - ref byte sevenBitBufferRef = ref sevenBitCoverBuffer[0]; - - try - { - int coverSizeInt = PatchSizeHelper.ToCheckedInt32(coverSize, nameof(coverSize)); - coverStream.ReadExactly(sevenBitCoverBuffer, 0, coverSizeInt); - - long lastOldPosBack = 0; - long lastNewPosBack = 0; - - ref long outBufferOldPosRef = ref outputBuffer.AsRef(); - ref long outBufferNewPosRef = ref outputBuffer.AsRef(8); - ref long outBufferCoverLengthRef = ref outputBuffer.AsRef(16); - ref long outBufferNextCoverPosRef = ref outputBuffer.AsRef(24); - - while (coverCount-- > 0) - { - long oldPosBack = lastOldPosBack; - long newPosBack = lastNewPosBack; - - byte pSign = sevenBitBufferRef; - sevenBitBufferRef = ref Unsafe.AddByteOffset(ref sevenBitBufferRef, 1); - - byte incOldPosSign = (byte)(pSign >> (8 - kSignTagBit)); - - sevenBitBufferRef = ref sevenBitBufferRef.ReadLong7Bit(out long incOldPos, kSignTagBit, pSign); - sevenBitBufferRef = ref sevenBitBufferRef.ReadLong7Bit(out long copyLength); - sevenBitBufferRef = ref sevenBitBufferRef.ReadLong7Bit(out long coverLength); - - long oldPos = incOldPosSign == 0 ? oldPosBack + incOldPos : oldPosBack - incOldPos; - - oldPosBack = oldPos + coverLength; - newPosBack += copyLength; - - outBufferOldPosRef = oldPos; - outBufferNewPosRef = newPosBack; - outBufferCoverLengthRef = coverLength; - outBufferNextCoverPosRef = coverCount; - - outBufferOldPosRef = ref Unsafe.AddByteOffset(ref outBufferOldPosRef, sizeOfLong); - outBufferNewPosRef = ref Unsafe.AddByteOffset(ref outBufferNewPosRef, sizeOfLong); - outBufferCoverLengthRef = ref Unsafe.AddByteOffset(ref outBufferCoverLengthRef, sizeOfLong); - outBufferNextCoverPosRef = ref Unsafe.AddByteOffset(ref outBufferNextCoverPosRef, sizeOfLong); - - newPosBack += coverLength; - lastOldPosBack = oldPosBack; - lastNewPosBack = newPosBack; - } - } - finally - { - ArrayPool.Shared.Return(sevenBitCoverBuffer); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static ulong GetRoundUpToPowerOf2(ulong value) - { -#if NET6_0_OR_GREATER - return BitOperations.RoundUpToPowerOf2(value); -#else - --value; - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; - value |= value >> 32; - return value + 1; -#endif - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static MemoryStream AllocCacheMemoryStream(long newDataSize) - { - ulong roundedSize = GetRoundUpToPowerOf2((ulong)newDataSize); - int bufferSizePow2 = roundedSize > int.MaxValue - ? MaxMemBufferLenBig - : PatchSizeHelper.ToCheckedInt32((long)roundedSize, nameof(newDataSize)); - if (bufferSizePow2 > MaxMemBufferLenBig) - bufferSizePow2 = MaxMemBufferLenBig; - - return new MemoryStream(bufferSizePow2); - } - - private unsafe void WriteCoverStreamToOutputFast(Stream[] clips, Stream inputStream, Stream outputStream, HeaderInfo headerInfo) - { - int rleCtrlIdx = 0, rleCodeIdx = 0; - -#if !NET6_0_OR_GREATER - byte[] sharedBuffer = ArrayPool.Shared.Rent(MaxArrayPoolSecondOffset); - MemoryStream cacheOutputStream = AllocCacheMemoryStream(headerInfo.NewDataSize); - int poolSizeRemained = MaxArrayPoolLen - sharedBuffer.Length; - - bool isCtrlUseArrayPool = headerInfo.ChunkInfo.RleCtrlBufSize <= poolSizeRemained; - int rleCtrlBufSize = PatchSizeHelper.ToCheckedInt32(headerInfo.ChunkInfo.RleCtrlBufSize, nameof(headerInfo.ChunkInfo.RleCtrlBufSize)); - byte[] rleCtrlBuffer = isCtrlUseArrayPool ? ArrayPool.Shared.Rent(rleCtrlBufSize) - : new byte[rleCtrlBufSize]; - poolSizeRemained -= rleCtrlBuffer.Length; - - bool isRleUseArrayPool = headerInfo.ChunkInfo.RleCodeBufSize <= poolSizeRemained; - int rleCodeBufSize = PatchSizeHelper.ToCheckedInt32(headerInfo.ChunkInfo.RleCodeBufSize, nameof(headerInfo.ChunkInfo.RleCodeBufSize)); - byte[] rleCodeBuffer = isRleUseArrayPool ? ArrayPool.Shared.Rent(rleCodeBufSize) - : new byte[rleCodeBufSize]; -#else - byte[] sharedBuffer = GC.AllocateUninitializedArray(MaxArrayPoolSecondOffset); - MemoryStream cacheOutputStream = AllocCacheMemoryStream(headerInfo.NewDataSize); - - int rleCtrlBufSize = PatchSizeHelper.ToCheckedInt32(headerInfo.ChunkInfo.RleCtrlBufSize, nameof(headerInfo.ChunkInfo.RleCtrlBufSize)); - bool isCtrlUseArrayPool = MinUninitializedArrayLen > rleCtrlBufSize; - byte[] rleCtrlBuffer = isCtrlUseArrayPool ? GC.AllocateUninitializedArray(rleCtrlBufSize) - : new byte[rleCtrlBufSize]; - - int rleCodeBufSize = PatchSizeHelper.ToCheckedInt32(headerInfo.ChunkInfo.RleCodeBufSize, nameof(headerInfo.ChunkInfo.RleCodeBufSize)); - bool isRleUseArrayPool = MinUninitializedArrayLen > rleCodeBufSize; - byte[] rleCodeBuffer = isRleUseArrayPool ? GC.AllocateUninitializedArray(rleCodeBufSize) - : new byte[rleCodeBufSize]; -#endif - - RleRefClipStruct rleStruct = new(); - int coverBufferLen = checked(sizeof(CoverHeader) * PatchSizeHelper.ToCheckedInt32(headerInfo.ChunkInfo.CoverCount, nameof(headerInfo.ChunkInfo.CoverCount))); - byte[] coverBuffer = -#if NET6_0_OR_GREATER - GC.AllocateUninitializedArray(coverBufferLen); -#else - new byte[coverBufferLen]; -#endif - - CreateCoverHeaderAsOutputBuffer(clips[0], coverBuffer, headerInfo.ChunkInfo.CoverBufSize, headerInfo.ChunkInfo.CoverCount); - - const int sizeOfCoverHeader = sizeof(long) * 4; - try - { - using (clips[1]) - using (clips[2]) - { - string ctrlStats = - isCtrlUseArrayPool ? -#if !NET6_0_OR_GREATER - "ArrayPool" -#else - "UninitializedArray" -#endif - : "heap buffer"; - string rleStats = - isRleUseArrayPool ? -#if !NET6_0_OR_GREATER - "ArrayPool" -#else - "UninitializedArray" -#endif - : "heap buffer"; - HDiffPatch.Event.PushLog($"[PatchCoreFastBuffer::WriteCoverStreamToOutputFast] Buffering RLE Ctrl clip to {ctrlStats}"); - clips[1].ReadExactly(rleCtrlBuffer, 0, rleCtrlBufSize); - HDiffPatch.Event.PushLog($"[PatchCoreFastBuffer::WriteCoverStreamToOutputFast] Buffering RLE Code clip to {rleStats}"); - clips[2].ReadExactly(rleCodeBuffer, 0, rleCodeBufSize); - } - - long copyLength; - long newPosBack = 0; - if (coverBuffer.Length == 0) - { - goto EndCoverRead; - } - - ref CoverHeader cover = ref coverBuffer.AsRef(); - ref CoverHeader lastCover = ref coverBuffer.AsRef(coverBufferLen - sizeOfCoverHeader); - - StartCoverRead: - if (Unsafe.IsAddressGreaterThan(ref cover, ref lastCover)) - goto EndCoverRead; - - _core.Token.ThrowIfCancellationRequested(); - - if (newPosBack < cover.NewPos) - { - copyLength = cover.NewPos - newPosBack; - inputStream.Position = cover.OldPos; - - PatchCore.TBytesCopyStreamFromOldClip(cacheOutputStream, clips[3], copyLength, sharedBuffer); - TBytesDetermineRleType(ref rleStruct, cacheOutputStream, copyLength, sharedBuffer, rleCtrlBuffer, ref rleCtrlIdx, rleCodeBuffer, ref rleCodeIdx); - } - - TBytesCopyOldClipPatch(cacheOutputStream, inputStream, ref rleStruct, cover.OldPos, cover.CoverLength, sharedBuffer, rleCtrlBuffer, ref rleCtrlIdx, rleCodeBuffer, ref rleCodeIdx); - newPosBack = cover.NewPos + cover.CoverLength; - - if (cacheOutputStream.Length > MaxMemBufferLenBig || cover.NextCoverIndex == 0) - { - _core.WriteInMemoryOutputToStream(cacheOutputStream, outputStream); - } - - cover = ref Unsafe.AddByteOffset(ref cover, sizeOfCoverHeader); - goto StartCoverRead; - - EndCoverRead: - if (newPosBack >= headerInfo.NewDataSize) return; - - copyLength = headerInfo.NewDataSize - newPosBack; - PatchCore.TBytesCopyStreamFromOldClip(cacheOutputStream, clips[3], copyLength, sharedBuffer); - TBytesDetermineRleType(ref rleStruct, cacheOutputStream, copyLength, sharedBuffer, rleCtrlBuffer, ref rleCtrlIdx, rleCodeBuffer, ref rleCodeIdx); - _core.WriteInMemoryOutputToStream(cacheOutputStream, outputStream); - } - finally - { -#if !NET6_0_OR_GREATER - if (sharedBuffer != null) ArrayPool.Shared.Return(sharedBuffer); - if (rleCtrlBuffer != null && isCtrlUseArrayPool) ArrayPool.Shared.Return(rleCtrlBuffer); - if (rleCodeBuffer != null && isRleUseArrayPool) ArrayPool.Shared.Return(rleCodeBuffer); -#endif - _core.Stopwatch.Stop(); - cacheOutputStream.Dispose(); - clips[0].Dispose(); - clips[3].Dispose(); - inputStream.Dispose(); - outputStream.Dispose(); - } - } - - private static void TBytesCopyOldClipPatch(MemoryStream outCache, Stream inputStream, ref RleRefClipStruct rleLoader, long oldPos, long addLength, byte[] sharedBuffer, - ReadOnlySpan rleCtrlBuffer, ref int rleCtrlIdx, byte[] rleCodeBuffer, ref int rleCodeIdx) - { - long lastPos = outCache.Position; - inputStream.Position = oldPos; - - PatchCore.TBytesCopyStreamInner(inputStream, outCache, sharedBuffer, (int)addLength); - - outCache.Position = lastPos; - TBytesDetermineRleType(ref rleLoader, outCache, addLength, sharedBuffer, rleCtrlBuffer, ref rleCtrlIdx, rleCodeBuffer, ref rleCodeIdx); - } - - private static void TBytesDetermineRleType(ref RleRefClipStruct rleLoader, MemoryStream outCache, long copyLength, byte[] sharedBuffer, - ReadOnlySpan rleCtrlBuffer, ref int rleCtrlIdx, byte[] rleCodeBuffer, ref int rleCodeIdx) - { - TBytesSetRle(ref rleLoader, outCache, ref copyLength, sharedBuffer, rleCodeBuffer, ref rleCodeIdx); - - while (copyLength > 0) - { - byte pSign = rleCtrlBuffer[rleCtrlIdx++]; - byte type = (byte)(pSign >> (8 - PatchCore.KByteRleType)); - long length = rleCtrlBuffer.ReadLong7Bit(ref rleCtrlIdx, PatchCore.KByteRleType, pSign); - ++length; - - if (type == 3) - { - rleLoader.MemCopyLength = length; - TBytesSetRleCopyOnly(ref rleLoader, outCache, ref copyLength, sharedBuffer, rleCodeBuffer, ref rleCodeIdx); - continue; - } - - rleLoader.MemSetLength = length; - if (type == 2) - { - rleLoader.MemSetValue = rleCodeBuffer[rleCodeIdx++]; - TBytesSetRle(ref rleLoader, outCache, ref copyLength, sharedBuffer, rleCodeBuffer, ref rleCodeIdx); - continue; - } - - /* If the type is 1, then 0 - 1. This should result -1 in int but since - * we cast it to byte, then it underflow and set it to 255. - * This method is the same as: - * if (type == 0) - * rleLoader.memSetValue = 0x00; // or 0 in byte - * else - * rleLoader.memSetValue = 0xFF; // or 255 in byte - */ - rleLoader.MemSetValue = (byte)(0x00 - type); - TBytesSetRle(ref rleLoader, outCache, ref copyLength, sharedBuffer, rleCodeBuffer, ref rleCodeIdx); - } - } - - private static void TBytesSetRle(ref RleRefClipStruct rleLoader, MemoryStream outCache, ref long copyLength, byte[] sharedBuffer, - byte[] rleCodeBuffer, ref int rleCodeIdx) - { - PatchCore.TBytesSetRleSingle(ref rleLoader, outCache, ref copyLength, sharedBuffer); - - if (rleLoader.MemCopyLength == 0) return; - TBytesSetRleCopyOnly(ref rleLoader, outCache, ref copyLength, sharedBuffer, rleCodeBuffer, ref rleCodeIdx); - } - - private static unsafe void TBytesSetRleCopyOnly(ref RleRefClipStruct rleLoader, MemoryStream outCache, ref long copyLength, byte[] sharedBuffer, - byte[] rleCodeBuffer, ref int rleCodeIdx) - { - int decodeStep = (int)(rleLoader.MemCopyLength > copyLength ? copyLength : rleLoader.MemCopyLength); - - long lastPosCopy = outCache.Position; - _ = outCache.Read(sharedBuffer, 0, decodeStep); - outCache.Position = lastPosCopy; - - fixed (byte* rlePtr = &rleCodeBuffer[rleCodeIdx], oldPtr = &sharedBuffer[0]) - { - PatchCore.RleProcDelegate(ref rleLoader, outCache, ref copyLength, decodeStep, rlePtr, rleCodeBuffer, rleCodeIdx, oldPtr); - } - rleCodeIdx += decodeStep; - } - } -} diff --git a/SharpHDiffPatch.Core/Patch/PatchDir.cs b/SharpHDiffPatch.Core/Patch/PatchDir.cs deleted file mode 100644 index 0af3501..0000000 --- a/SharpHDiffPatch.Core/Patch/PatchDir.cs +++ /dev/null @@ -1,348 +0,0 @@ -using SharpHDiffPatch.Core.Binary; -using SharpHDiffPatch.Core.Binary.Compression; -using SharpHDiffPatch.Core.Binary.Streams; -using System; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Threading; - -namespace SharpHDiffPatch.Core.Patch -{ - internal class PairIndexReference - { - public long OldIndex; - public long NewIndex; - - public override string ToString() => $"OldIndex: {OldIndex}, NewIndex: {NewIndex}"; - } - - internal class DirectoryReferencePair - { - internal string[] OldUtf8PathList; - internal string[] NewUtf8PathList; - internal long[] OldRefList; - internal long[] NewRefList; - internal long[] OldRefSizeList; - internal long[] NewRefSizeList; - internal long[] NewRefHashList; - internal PairIndexReference[] DataSamePairList; - internal long[] NewExecuteList; - } - - public sealed class PatchDir : IPatch - { - private HeaderInfo _headerInfo; - private readonly DataReferenceInfo _referenceInfo; - private readonly DirectoryPatchFormat _directoryPatchFormat; - private readonly Func _spawnPatchStream; - private string _basePathInput; - private string _basePathOutput; - private bool _useBufferedPatch; - private bool _useFullBuffer; - private bool _useFastBuffer; -#if USEEXPERIMENTALMULTITHREAD - private bool useMultiThread; -#endif - private int _padding; - private readonly CancellationToken _token; - - public PatchDir(HeaderInfo headerInfo, DataReferenceInfo referenceInfo, string patchPath, - DirectoryPatchFormat directoryPatchFormat, CancellationToken token -#if USEEXPERIMENTALMULTITHREAD - , bool useMultiThread -#endif - ) - { - _token = token; - _headerInfo = headerInfo; - _referenceInfo = referenceInfo; - _directoryPatchFormat = directoryPatchFormat; -#if USEEXPERIMENTALMULTITHREAD - useMultiThread = useMultiThread; -#endif - _spawnPatchStream = headerInfo.PatchCreateStream ?? (() => new FileStream(patchPath, FileMode.Open, FileAccess.Read, FileShare.Read)); - } - - public void Patch(string input, string output, Action writeBytesDelegate, bool useBufferedPatch, bool useFullBuffer, bool useFastBuffer) - { - _basePathInput = input; - _basePathOutput = output; - _useBufferedPatch = useBufferedPatch; - _useFullBuffer = useFullBuffer; - _useFastBuffer = useFastBuffer; - - using Stream patchStream = _spawnPatchStream(); - _padding = _headerInfo.CompMode == HDiffCompressionMode.zlib ? 1 : 0; - HDiffPatch.Event.PushLog($"[PatchDir::Patch] Padding applied: {_padding} byte(s)", Verbosity.Debug); - - int headerPadding = _referenceInfo.HeadDataCompressedSize > 0 ? _padding : 0; - patchStream.Position = _referenceInfo.HeadDataOffset + headerPadding; - HDiffPatch.Event.PushLog($"[PatchDir::Patch] Patch stream position moved from: {patchStream.Position - (_referenceInfo.HeadDataOffset + headerPadding)} to: {patchStream.Position}", Verbosity.Debug); - - HDiffPatch.Event.PushLog($"[PatchDir::Patch] Getting stream for header at size: {_referenceInfo.HeadDataSize} bytes ({_referenceInfo.HeadDataCompressedSize - headerPadding} bytes compressed)", Verbosity.Verbose); - - CompressionStreamHelper.GetDecompressStreamPlugin(_headerInfo.CompMode, patchStream, out Stream decompressedHeadStream, - _referenceInfo.HeadDataSize, _referenceInfo.HeadDataCompressedSize - headerPadding, out _, _useBufferedPatch); - - HDiffPatch.Event.PushLog("[PatchDir::Patch] Initializing stream to binary readers", Verbosity.Debug); - - using (patchStream) - using (decompressedHeadStream) - { - DirectoryReferencePair dirData = InitializeDirPatcher(decompressedHeadStream); - - long newPatchSize = GetNewPatchedFileSize(dirData); - long samePathSize = GetSameFileSize(dirData); - long totalSizePatched = newPatchSize + samePathSize; - - HDiffPatch.Event.PushLog($"[PatchDir::Patch] Total new size: {totalSizePatched} bytes ({newPatchSize} (new data) + {samePathSize} (same data))", Verbosity.Verbose); - - ValidateOldReferenceSizes(dirData); - FileStream[] mergedOldStream = GetRefOldStreams(dirData); - CombinedStreamSegment[] mergedNewStream = GetRefNewStreams(dirData); - HDiffPatch.Event.PushLog($"[PatchDir::Patch] Initialized {mergedOldStream.Length} old files and {mergedNewStream.Length} new files into combined stream", Verbosity.Verbose); - - HDiffPatch.Event.PushLog($"[PatchDir::Patch] Seek the patch stream to: {_referenceInfo.HDiffDataOffset}. Jump to read header for clip streams!", Verbosity.Verbose); - patchStream.Position = _referenceInfo.HDiffDataOffset; - if (!_headerInfo.IsSingleCompressedDiff) - _ = Header.TryParseHeaderInfo(patchStream, "", out _headerInfo, out _); - else - HDiffPatch.Event.PushLog("[PatchDir::Patch] This patch is a \"single diff\" type!"); - - _padding = _headerInfo.CompMode == HDiffCompressionMode.zlib ? 1 : 0; - - IPatchCore patchCore = CreatePatchCore(writeBytesDelegate, totalSizePatched); - patchCore.SetDirectoryReferencePair(dirData); - patchCore.SetSizeToBePatched(totalSizePatched); - - using (Stream newStream = new CombinedStream(mergedNewStream)) - using (Stream oldStream = new CombinedStream(mergedOldStream)) - { - long oldFileSize = GetOldFileSize(dirData); - if (oldStream.Length != _headerInfo.OldDataSize) - throw new InvalidDataException($"[PatchDir::Patch] The patch directory is expecting old size to be equivalent as: {_headerInfo.OldDataSize} bytes, but the input file has unmatch size: {oldStream.Length} bytes!"); - - HDiffPatch.Event.PushLog($"[PatchDir::Patch] Existing old directory size: {oldFileSize} is matched!", Verbosity.Verbose); - - long lastPos = patchStream.Position; - HDiffPatch.Event.PushLog($"[PatchDir::Patch] Staring patching routine at position: {lastPos}", Verbosity.Verbose); - - HDiffPatch.DisplayDirPatchInformation(oldFileSize, totalSizePatched, _headerInfo); - StartPatchRoutine(oldStream, newStream, _headerInfo.NewDataSize, lastPos, patchCore); - } - } - } - - private long GetOldFileSize(DirectoryReferencePair dirData) - { - long fileSize = 0; - for (int i = 0; i < dirData.OldUtf8PathList.Length; i++) - { - ref string basePath = ref dirData.OldUtf8PathList[i]; - if (basePath.Length == 0) continue; - - int baseIndexEoc = basePath.Length - 1; - char endOfChar = basePath[baseIndexEoc]; - if (endOfChar == '/') continue; - - string sourceFullPath = Path.Combine(_basePathInput, basePath); - if (!File.Exists(sourceFullPath)) continue; - - fileSize += new FileInfo(sourceFullPath).Length; - } - - return fileSize; - } - - private long GetSameFileSize(DirectoryReferencePair dirData) - { - long fileSize = 0; - foreach (PairIndexReference pair in dirData.DataSamePairList) - { - ref string basePath = ref dirData.NewUtf8PathList[pair.NewIndex]; - bool isPathADir = PatchCore.IsPathADir(basePath); - if (isPathADir) continue; - - string sourceFullPath = Path.Combine(_basePathInput, basePath); - if (!File.Exists(sourceFullPath)) continue; - - fileSize += new FileInfo(sourceFullPath).Length; - } - - return fileSize; - } - - private static long GetNewPatchedFileSize(DirectoryReferencePair dirData) => dirData.NewRefSizeList.Sum(); - - private void ValidateOldReferenceSizes(DirectoryReferencePair dirData) - { - if (_directoryPatchFormat != DirectoryPatchFormat.Kuro) - return; - - for (int i = 0; i < dirData.OldRefList.Length; i++) - { - ref string oldPath = ref PatchCore.NewPathByIndex(dirData.OldUtf8PathList, dirData.OldRefList[i]); - string fullPath = Path.Combine(_basePathInput, oldPath); - if (!File.Exists(fullPath)) - throw new FileNotFoundException("A Kuro directory patch source file was not found.", fullPath); - - long actualSize = new FileInfo(fullPath).Length; - long expectedSize = dirData.OldRefSizeList[i]; - if (actualSize != expectedSize) - throw new InvalidDataException($"[PatchDir::ValidateOldReferenceSizes] Source file size mismatch for {fullPath}: expected {expectedSize} bytes, got {actualSize} bytes."); - } - } - - private IPatchCore CreatePatchCore(Action writeBytesDelegate, long totalSizePatched) - { - bool wantFastBuffer = _useFastBuffer && _useBufferedPatch && !_headerInfo.IsSingleCompressedDiff; - switch (wantFastBuffer) - { - case true when PatchSizeHelper.CanUseFastBuffer(_headerInfo): - return new PatchCoreFastBuffer(totalSizePatched, Stopwatch.StartNew(), _basePathInput, _basePathOutput, writeBytesDelegate, _token); - case true: - HDiffPatch.Event.PushLog("[PatchDir::CreatePatchCore] Fast buffer disabled: patch chunk sizes exceed int32-safe limits; using streaming patch core."); - break; - } - - return new PatchCore(totalSizePatched, Stopwatch.StartNew(), _basePathInput, _basePathOutput, writeBytesDelegate, _token); - } - - private void StartPatchRoutine(Stream inputStream, Stream outputStream, long newDataSize, long offset, IPatchCore patchCore) - { - var clips = new Stream[_headerInfo.IsSingleCompressedDiff ? 1 : 4]; - Stream[] sourceClips = _headerInfo.IsSingleCompressedDiff ? - [ _spawnPatchStream() ] : - [ - _spawnPatchStream(), - _spawnPatchStream(), - _spawnPatchStream(), - _spawnPatchStream() - ]; - - try - { - if (_headerInfo.IsSingleCompressedDiff) - { - sourceClips[0].Position += _referenceInfo.HDiffDataOffset + _headerInfo.SingleChunkInfo.DiffDataPos; - int coverPadding = _headerInfo.SingleChunkInfo.CompressedSize > 0 ? _padding : 0; - offset += _headerInfo.SingleChunkInfo.DiffDataPos; - - clips[0] = patchCore.GetBufferStreamFromOffset(_headerInfo.CompMode, sourceClips[0], offset + coverPadding, - _headerInfo.SingleChunkInfo.UncompressedSize, _headerInfo.SingleChunkInfo.CompressedSize, out long _, - _useBufferedPatch, false); - } - else - { - int coverPadding = _headerInfo.ChunkInfo.CompressCoverBufSize > 0 ? _padding : 0; - clips[0] = patchCore.GetBufferStreamFromOffset(_headerInfo.CompMode, sourceClips[0], offset + coverPadding, - _headerInfo.ChunkInfo.CoverBufSize, _headerInfo.ChunkInfo.CompressCoverBufSize, out long nextLength, _useBufferedPatch, false); - - offset += nextLength; - int rleCtrlBufPadding = _headerInfo.ChunkInfo.CompressRleCtrlBufSize > 0 ? _padding : 0; - clips[1] = patchCore.GetBufferStreamFromOffset(_headerInfo.CompMode, sourceClips[1], offset + rleCtrlBufPadding, - _headerInfo.ChunkInfo.RleCtrlBufSize, _headerInfo.ChunkInfo.CompressRleCtrlBufSize, out nextLength, _useBufferedPatch, _useFastBuffer); - - offset += nextLength; - int rleCodeBufPadding = _headerInfo.ChunkInfo.CompressRleCodeBufSize > 0 ? _padding : 0; - clips[2] = patchCore.GetBufferStreamFromOffset(_headerInfo.CompMode, sourceClips[2], offset + rleCodeBufPadding, - _headerInfo.ChunkInfo.RleCodeBufSize, _headerInfo.ChunkInfo.CompressRleCodeBufSize, out nextLength, _useBufferedPatch, _useFastBuffer); - - offset += nextLength; - int newDataDiffPadding = _headerInfo.ChunkInfo.CompressNewDataDiffSize > 0 ? _padding : 0; - clips[3] = patchCore.GetBufferStreamFromOffset(_headerInfo.CompMode, sourceClips[3], offset + newDataDiffPadding, - _headerInfo.ChunkInfo.NewDataDiffSize, _headerInfo.ChunkInfo.CompressNewDataDiffSize - _padding, out _, _useBufferedPatch && _useFullBuffer, false); - - _headerInfo.NewDataSize = newDataSize; - } - patchCore.UncoverBufferClipsStream(clips, inputStream, outputStream, _headerInfo); - } - finally - { - foreach (Stream clip in clips) clip?.Dispose(); - foreach (Stream clip in sourceClips) clip?.Dispose(); - } - } - - private FileStream[] GetRefOldStreams(DirectoryReferencePair dirData) - { - FileStream[] streams = new FileStream[dirData.OldRefList.Length]; - for (int i = 0; i < dirData.OldRefList.Length; i++) - { - ref string oldPathByIndex = ref PatchCore.NewPathByIndex(dirData.OldUtf8PathList, dirData.OldRefList[i]); - string combinedOldPath = Path.Combine(_basePathInput, oldPathByIndex); - - HDiffPatch.Event.PushLog($"[PatchDir::GetRefOldStreams] Assigning stream to the old path: {combinedOldPath}", Verbosity.Debug); - streams[i] = File.Open(combinedOldPath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite); - } - - return streams; - } - - private CombinedStreamSegment[] GetRefNewStreams(DirectoryReferencePair dirData) - { - var streams = new CombinedStreamSegment[dirData.NewRefList.Length]; - for (int i = 0; i < dirData.NewRefList.Length; i++) - { - ref string newPathByIndex = ref PatchCore.NewPathByIndex(dirData.NewUtf8PathList, dirData.NewRefList[i]); - string combinedNewPath = Path.Combine(_basePathOutput, newPathByIndex); - string newPathDirectory = Path.GetDirectoryName(combinedNewPath); - - if (!string.IsNullOrEmpty(newPathDirectory)) - Directory.CreateDirectory(newPathDirectory); - - HDiffPatch.Event.PushLog($"[PatchDir::GetRefNewStreams] Assigning stream to the new path: {combinedNewPath}", Verbosity.Debug); - - var stream = new CombinedStreamSegment - { - Stream = new FileStream(combinedNewPath, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite), - Length = dirData.NewRefSizeList[i] - }; - streams[i] = stream; - } - - return streams; - } - - private DirectoryReferencePair InitializeDirPatcher(Stream reader) - { - HDiffPatch.Event.PushLog("[PatchDir::InitializeDirPatcher] Reading PatchDir header...", Verbosity.Verbose); - DirectoryReferencePair returnValue = new(); - - HDiffPatch.Event.PushLog($"[PatchDir::InitializeDirPatcher] Reading path string buffers -> OldPath: {(int)_referenceInfo.InputSumSize}", Verbosity.Verbose); - reader.GetPathsFromStream(out returnValue.OldUtf8PathList, (int)_referenceInfo.InputSumSize, (int)_referenceInfo.InputDirCount); - - HDiffPatch.Event.PushLog($"[PatchDir::InitializeDirPatcher] Reading path string buffers -> NewPath: {(int)_referenceInfo.OutputSumSize}", Verbosity.Verbose); - reader.GetPathsFromStream(out returnValue.NewUtf8PathList, (int)_referenceInfo.OutputSumSize, (int)_referenceInfo.OutputDirCount); - - HDiffPatch.Event.PushLog($"[PatchDir::InitializeDirPatcher] Path string counts -> OldPath: {returnValue.OldUtf8PathList.Length} paths & NewPath: {returnValue.NewUtf8PathList.Length} paths", Verbosity.Verbose); - reader.GetLongsFromStream(out returnValue.OldRefList, _referenceInfo.InputRefFileCount, _referenceInfo.InputDirCount); - reader.GetLongsFromStream(out returnValue.NewRefList, _referenceInfo.OutputRefFileCount, _referenceInfo.OutputDirCount); - if (_directoryPatchFormat == DirectoryPatchFormat.Kuro) - reader.GetLongsFromStream(out returnValue.OldRefSizeList, _referenceInfo.InputRefFileCount); - reader.GetLongsFromStream(out returnValue.NewRefSizeList, _referenceInfo.OutputRefFileCount); - if (_directoryPatchFormat == DirectoryPatchFormat.Kuro) - reader.GetLongsFromStream(out returnValue.NewRefHashList, _referenceInfo.OutputRefFileCount); - reader.GetPairIndexReferenceFromStream(out returnValue.DataSamePairList, _referenceInfo.SameFilePairCount, _referenceInfo.OutputDirCount, _referenceInfo.InputDirCount); - reader.GetLongsFromStream(out returnValue.NewExecuteList, _referenceInfo.NewExecuteCount, _referenceInfo.OutputDirCount); - - if (_directoryPatchFormat == DirectoryPatchFormat.Kuro) - { - long oldRefSize = returnValue.OldRefSizeList.Sum(); - if (oldRefSize != _referenceInfo.InputRefFileSize) - throw new InvalidDataException($"[PatchDir::InitializeDirPatcher] Kuro old reference size mismatch: expected {_referenceInfo.InputRefFileSize} bytes, parsed {oldRefSize} bytes."); - - long newRefSize = returnValue.NewRefSizeList.Sum(); - if (newRefSize != _referenceInfo.OutputRefFileSize) - throw new InvalidDataException($"[PatchDir::InitializeDirPatcher] Kuro new reference size mismatch: expected {_referenceInfo.OutputRefFileSize} bytes, parsed {newRefSize} bytes."); - - if (reader.CanSeek && reader.Length - reader.Position != _referenceInfo.PrivateReservedDataSize) - throw new InvalidDataException($"[PatchDir::InitializeDirPatcher] Directory header has {reader.Length - reader.Position} unparsed bytes; expected {_referenceInfo.PrivateReservedDataSize} private reserved bytes."); - } - HDiffPatch.Event.PushLog($"[PatchDir::InitializeDirPatcher] Path refs found! OldRef: {_referenceInfo.InputRefFileCount} paths, NewRef: {_referenceInfo.OutputRefFileCount} paths, IdenticalRef: {_referenceInfo.SameFilePairCount} paths", Verbosity.Verbose); - - return returnValue; - } - } -} diff --git a/SharpHDiffPatch.Core/Patch/PatchSingle.cs b/SharpHDiffPatch.Core/Patch/PatchSingle.cs deleted file mode 100644 index 34ef334..0000000 --- a/SharpHDiffPatch.Core/Patch/PatchSingle.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Threading; -using SharpHDiffPatch.Core.Binary; -using SharpHDiffPatch.Core.Binary.Compression; - -namespace SharpHDiffPatch.Core.Patch -{ - public sealed class PatchSingle(HeaderInfo headerInfo, CancellationToken token) : IPatch - { - private readonly Func _spawnPatchStream = headerInfo.PatchCreateStream ?? (() => new FileStream(headerInfo.PatchPath, FileMode.Open, FileAccess.Read, FileShare.Read)); - - private bool _isUseBufferedPatch; - private bool _isUseFullBuffer; - private bool _isUseFastBuffer; - - public void Patch(string input, string output, Action writeBytesDelegate, bool useBufferedPatch, bool useFullBuffer, bool useFastBuffer) - { - _isUseBufferedPatch = useBufferedPatch; - _isUseFullBuffer = useFullBuffer; - _isUseFastBuffer = useFastBuffer; - - using FileStream inputStream = new(input, FileMode.Open, FileAccess.Read, FileShare.Read, headerInfo.OldDataSize.GetFileStreamBufferSize()); - using FileStream outputStream = new(output, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite, headerInfo.NewDataSize.GetFileStreamBufferSize()); - if (inputStream.Length != headerInfo.OldDataSize) - throw new InvalidDataException($"[PatchSingle::Patch] The patch directory is expecting old size to be equivalent as: {headerInfo.OldDataSize} bytes, but the input file has unmatched size: {inputStream.Length} bytes!"); - - HDiffPatch.Event.PushLog($"[PatchSingle::Patch] Existing old file size: {inputStream.Length} is matched!", Verbosity.Verbose); - HDiffPatch.Event.PushLog($"[PatchSingle::Patch] Staring patching routine at position: {headerInfo.ChunkInfo.HeadEndPos}", Verbosity.Verbose); - - IPatchCore patchCore = CreatePatchCore(input, output, writeBytesDelegate); - - StartPatchRoutine(inputStream, outputStream, patchCore); - } - - private IPatchCore CreatePatchCore(string input, string output, Action writeBytesDelegate) - { - bool wantFastBuffer = _isUseFastBuffer && _isUseBufferedPatch; - if (wantFastBuffer && PatchSizeHelper.CanUseFastBuffer(headerInfo)) - return new PatchCoreFastBuffer(headerInfo.NewDataSize, Stopwatch.StartNew(), input, output, writeBytesDelegate, token); - - if (wantFastBuffer) - HDiffPatch.Event.PushLog("[PatchSingle::CreatePatchCore] Fast buffer disabled: patch chunk sizes exceed int32-safe limits; using streaming patch core."); - - return new PatchCore(headerInfo.NewDataSize, Stopwatch.StartNew(), input, output, writeBytesDelegate, token); - } - - private void StartPatchRoutine(Stream inputStream, Stream outputStream, IPatchCore patchCore) - { - Stream[] clips = new Stream[4]; - Stream[] sourceClips = - [ - _spawnPatchStream(), - _spawnPatchStream(), - _spawnPatchStream(), - _spawnPatchStream() - ]; - - int padding = headerInfo.CompMode == HDiffCompressionMode.zlib ? 1 : 0; - - try - { - long offset = headerInfo.ChunkInfo.HeadEndPos; - int coverPadding = headerInfo.ChunkInfo.CompressCoverBufSize > 0 ? padding : 0; - clips[0] = patchCore.GetBufferStreamFromOffset(headerInfo.CompMode, sourceClips[0], offset + coverPadding, - headerInfo.ChunkInfo.CoverBufSize, headerInfo.ChunkInfo.CompressCoverBufSize, out long nextLength, _isUseBufferedPatch, false); - - offset += nextLength; - int rleCtrlBufPadding = headerInfo.ChunkInfo.CompressRleCtrlBufSize > 0 ? padding : 0; - clips[1] = patchCore.GetBufferStreamFromOffset(headerInfo.CompMode, sourceClips[1], offset + rleCtrlBufPadding, - headerInfo.ChunkInfo.RleCtrlBufSize, headerInfo.ChunkInfo.CompressRleCtrlBufSize, out nextLength, _isUseBufferedPatch, _isUseFastBuffer); - - offset += nextLength; - int rleCodeBufPadding = headerInfo.ChunkInfo.CompressRleCodeBufSize > 0 ? padding : 0; - clips[2] = patchCore.GetBufferStreamFromOffset(headerInfo.CompMode, sourceClips[2], offset + rleCodeBufPadding, - headerInfo.ChunkInfo.RleCodeBufSize, headerInfo.ChunkInfo.CompressRleCodeBufSize, out nextLength, _isUseBufferedPatch, _isUseFastBuffer); - - offset += nextLength; - int newDataDiffPadding = headerInfo.ChunkInfo.CompressNewDataDiffSize > 0 ? padding : 0; - clips[3] = patchCore.GetBufferStreamFromOffset(headerInfo.CompMode, sourceClips[3], offset + newDataDiffPadding, - headerInfo.ChunkInfo.NewDataDiffSize, headerInfo.ChunkInfo.CompressNewDataDiffSize - padding, out _, _isUseBufferedPatch && _isUseFullBuffer, false); - - patchCore.UncoverBufferClipsStream(clips, inputStream, outputStream, headerInfo); - } - finally - { - foreach (Stream clip in clips) clip?.Dispose(); - foreach (Stream clip in sourceClips) clip?.Dispose(); - } - } - } -} diff --git a/SharpHDiffPatch.Core/Patch/PatchSizeHelper.cs b/SharpHDiffPatch.Core/Patch/PatchSizeHelper.cs deleted file mode 100644 index b8b3836..0000000 --- a/SharpHDiffPatch.Core/Patch/PatchSizeHelper.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; - -namespace SharpHDiffPatch.Core.Patch -{ - internal static class PatchSizeHelper - { - internal static bool FitsInInt32(long value) => value is >= 0 and <= int.MaxValue; - - internal static int ToCheckedInt32(long value, string paramName) - { - if (!FitsInInt32(value)) - throw new ArgumentOutOfRangeException(paramName, value, - $"Value exceeds maximum safe array length ({int.MaxValue})."); - - return (int)value; - } - - /// - /// Returns true when can allocate its working - /// buffers without overflowing -sized APIs (ArrayPool, byte[], etc.). - /// - internal static bool CanUseFastBuffer(HeaderInfo headerInfo) - { - if (headerInfo.IsSingleCompressedDiff) - return false; - - DiffChunkInfo chunk = headerInfo.ChunkInfo; - - if (!FitsInInt32(chunk.RleCtrlBufSize)) - return false; - - if (!FitsInInt32(chunk.RleCodeBufSize)) - return false; - - if (!FitsInInt32(chunk.CoverBufSize)) - return false; - - long allBufferSize = chunk.RleCtrlBufSize + chunk.RleCodeBufSize + chunk.CoverBufSize; - return IsMemorySufficient(allBufferSize); - } - - private static bool IsMemorySufficient(long bufferSize) - { -#if NET6_0_OR_GREATER - GCMemoryInfo info = GC.GetGCMemoryInfo(); - - // Get possible minimum free memory size. - // Let's say for a mid-end device with low memory capacity: - // Free Mem: 2 GiB * 0.50 = 1 GiB - // Divided by CPU threads: 1 GiB / 8 = 128 MiB - long thresholdPossibleFreeMemSize = (long)(info.TotalAvailableMemoryBytes * 0.50d / Environment.ProcessorCount); - return thresholdPossibleFreeMemSize >= bufferSize; -#else - return true; // We have no simple way to get memory info. So, just pass it in. -#endif - } - } -} diff --git a/SharpHDiffPatch.Core/SharpHDiffPatch.Core.csproj b/SharpHDiffPatch.Core/SharpHDiffPatch.Core.csproj deleted file mode 100644 index 5a26910..0000000 --- a/SharpHDiffPatch.Core/SharpHDiffPatch.Core.csproj +++ /dev/null @@ -1,48 +0,0 @@ - - - SharpHDiffPatch.Core - SharpHDiffPatch - A port of HPatchZ for HDiff file patching implementation written in C# - SharpHDiffPatch is a patching library for HDiffPatch format written in C#, purposedly as a port of HPatchZ implementation. Supporting file and directory patching with BZip2, Deflate, Zstd, LZMA2 (not LZMA) and No compression diff format. - https://github.com/CollapseLauncher/SharpHDiffPatch.Core - MIT - Copyright (c) 2025 Collapse Project Team, Kemal Setya Adhi (neon-nyan) - neon-nyan - netstandard2.0;net6.0;net7.0;net8.0;net9.0;net10.0 - icon.png - true - README.md - 2.4.1 - 2.4.1 - true - true - Debug;Release - true - hdiff - - AnyCPU;x64;x86;ARM64 - 12 - - - - - - - - - - - - - - - - - - - - - - - True - - diff --git a/SharpHDiffPatch.sln b/SharpHDiffPatch.sln index dd08966..c13cced 100644 --- a/SharpHDiffPatch.sln +++ b/SharpHDiffPatch.sln @@ -3,13 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 18 VisualStudioVersion = 18.7.11925.98 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpHDiffPatch.Core", "SharpHDiffPatch.Core\SharpHDiffPatch.Core.csproj", "{57CB7A6D-2474-4A01-BE1A-5D1488F81390}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpHDiffPatch", "SharpHDiffPatch\SharpHDiffPatch.csproj", "{506DDD1C-DD74-4FCE-A0C9-D90E904CF708}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpHPatchZ", "SharpHPatchZ\SharpHPatchZ.csproj", "{7CE06EE4-B691-464B-9AB1-9882CF83E48E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{3AE3BAA8-B233-4547-82C2-0DE8012B4F23}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpHPatchZ.Program", "SharpHPatchZ.Program\SharpHPatchZ.Program.csproj", "{BD9154E6-EAF5-5C39-79A2-690F8CBED254}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -23,38 +19,6 @@ Global Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {57CB7A6D-2474-4A01-BE1A-5D1488F81390}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {57CB7A6D-2474-4A01-BE1A-5D1488F81390}.Debug|Any CPU.Build.0 = Debug|Any CPU - {57CB7A6D-2474-4A01-BE1A-5D1488F81390}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {57CB7A6D-2474-4A01-BE1A-5D1488F81390}.Debug|ARM64.Build.0 = Debug|ARM64 - {57CB7A6D-2474-4A01-BE1A-5D1488F81390}.Debug|x64.ActiveCfg = Debug|x64 - {57CB7A6D-2474-4A01-BE1A-5D1488F81390}.Debug|x64.Build.0 = Debug|x64 - {57CB7A6D-2474-4A01-BE1A-5D1488F81390}.Debug|x86.ActiveCfg = Debug|x86 - {57CB7A6D-2474-4A01-BE1A-5D1488F81390}.Debug|x86.Build.0 = Debug|x86 - {57CB7A6D-2474-4A01-BE1A-5D1488F81390}.Release|Any CPU.ActiveCfg = Release|Any CPU - {57CB7A6D-2474-4A01-BE1A-5D1488F81390}.Release|Any CPU.Build.0 = Release|Any CPU - {57CB7A6D-2474-4A01-BE1A-5D1488F81390}.Release|ARM64.ActiveCfg = Release|ARM64 - {57CB7A6D-2474-4A01-BE1A-5D1488F81390}.Release|ARM64.Build.0 = Release|ARM64 - {57CB7A6D-2474-4A01-BE1A-5D1488F81390}.Release|x64.ActiveCfg = Release|x64 - {57CB7A6D-2474-4A01-BE1A-5D1488F81390}.Release|x64.Build.0 = Release|x64 - {57CB7A6D-2474-4A01-BE1A-5D1488F81390}.Release|x86.ActiveCfg = Release|x86 - {57CB7A6D-2474-4A01-BE1A-5D1488F81390}.Release|x86.Build.0 = Release|x86 - {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Debug|Any CPU.Build.0 = Debug|Any CPU - {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Debug|ARM64.Build.0 = Debug|ARM64 - {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Debug|x64.ActiveCfg = Debug|x64 - {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Debug|x64.Build.0 = Debug|x64 - {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Debug|x86.ActiveCfg = Debug|x86 - {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Debug|x86.Build.0 = Debug|x86 - {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Release|Any CPU.ActiveCfg = Release|Any CPU - {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Release|Any CPU.Build.0 = Release|Any CPU - {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Release|ARM64.ActiveCfg = Release|ARM64 - {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Release|ARM64.Build.0 = Release|ARM64 - {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Release|x64.ActiveCfg = Release|x64 - {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Release|x64.Build.0 = Release|x64 - {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Release|x86.ActiveCfg = Release|x86 - {506DDD1C-DD74-4FCE-A0C9-D90E904CF708}.Release|x86.Build.0 = Release|x86 {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|Any CPU.Build.0 = Debug|Any CPU {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Debug|ARM64.ActiveCfg = Debug|ARM64 @@ -71,22 +35,22 @@ Global {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|x64.Build.0 = Release|x64 {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|x86.ActiveCfg = Release|x86 {7CE06EE4-B691-464B-9AB1-9882CF83E48E}.Release|x86.Build.0 = Release|x86 - {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Debug|ARM64.Build.0 = Debug|ARM64 - {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Debug|x64.ActiveCfg = Debug|x64 - {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Debug|x64.Build.0 = Debug|x64 - {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Debug|x86.ActiveCfg = Debug|x86 - {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Debug|x86.Build.0 = Debug|x86 - {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Release|Any CPU.Build.0 = Release|Any CPU - {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Release|ARM64.ActiveCfg = Release|ARM64 - {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Release|ARM64.Build.0 = Release|ARM64 - {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Release|x64.ActiveCfg = Release|x64 - {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Release|x64.Build.0 = Release|x64 - {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Release|x86.ActiveCfg = Release|x86 - {3AE3BAA8-B233-4547-82C2-0DE8012B4F23}.Release|x86.Build.0 = Release|x86 + {BD9154E6-EAF5-5C39-79A2-690F8CBED254}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BD9154E6-EAF5-5C39-79A2-690F8CBED254}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BD9154E6-EAF5-5C39-79A2-690F8CBED254}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {BD9154E6-EAF5-5C39-79A2-690F8CBED254}.Debug|ARM64.Build.0 = Debug|ARM64 + {BD9154E6-EAF5-5C39-79A2-690F8CBED254}.Debug|x64.ActiveCfg = Debug|x64 + {BD9154E6-EAF5-5C39-79A2-690F8CBED254}.Debug|x64.Build.0 = Debug|x64 + {BD9154E6-EAF5-5C39-79A2-690F8CBED254}.Debug|x86.ActiveCfg = Debug|x86 + {BD9154E6-EAF5-5C39-79A2-690F8CBED254}.Debug|x86.Build.0 = Debug|x86 + {BD9154E6-EAF5-5C39-79A2-690F8CBED254}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BD9154E6-EAF5-5C39-79A2-690F8CBED254}.Release|Any CPU.Build.0 = Release|Any CPU + {BD9154E6-EAF5-5C39-79A2-690F8CBED254}.Release|ARM64.ActiveCfg = Release|ARM64 + {BD9154E6-EAF5-5C39-79A2-690F8CBED254}.Release|ARM64.Build.0 = Release|ARM64 + {BD9154E6-EAF5-5C39-79A2-690F8CBED254}.Release|x64.ActiveCfg = Release|x64 + {BD9154E6-EAF5-5C39-79A2-690F8CBED254}.Release|x64.Build.0 = Release|x64 + {BD9154E6-EAF5-5C39-79A2-690F8CBED254}.Release|x86.ActiveCfg = Release|x86 + {BD9154E6-EAF5-5C39-79A2-690F8CBED254}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SharpHDiffPatch/Program.cs b/SharpHDiffPatch/Program.cs deleted file mode 100644 index 1d8b68d..0000000 --- a/SharpHDiffPatch/Program.cs +++ /dev/null @@ -1,211 +0,0 @@ -using System; -using System.CommandLine; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using SharpHDiffPatch.Core; -using SharpHDiffPatch.Core.Event; -#if BENCHMARK -using System.Linq; -#endif -// ReSharper disable CommentTypo - -namespace SharpHDiffPatch -{ - public static class PatcherBin - { - private static readonly string[] SizeSuffixes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; - private static readonly Stopwatch RefreshStopwatch = Stopwatch.StartNew(); - private const int RefreshInterval = 100; - private static readonly RootCommand Command = new RootCommand(); - - public static int Main(params string[] args) - { - Argument inputPathArg, patchPathArg, outputPathArg; - Option bufferModeOpt; - Option bufferFastOpt; - // Option _multiThreadOpt; - Option logLevelOpt; - - string inputPath, patchPath, outputPath; - bool isUseBufferedPatch, isUseFullBuffer, isUseFastBuffer - //, isUseMultiThread - ; - - Command.AddArgument(inputPathArg = new Argument("Input File", "Input path of the old file/folder to patch")); - Command.AddArgument(patchPathArg = new Argument("Patch File", "Patch file path to produce the new version of the file/folder")); - Command.AddArgument(outputPathArg = new Argument("Output File", "Output path of the new version to be produced")); - Command.AddOption(bufferModeOpt = new Option(["-b", "--buffer-mode"], () => BufferMode.Partial, - """ - Determines the buffering mode for reading the clips of the patch files. - [None] - No buffering and read the clips directly from the disk stream - - [Partial] - Buffers only the Cover Code, RLE Control and RLE Code clips only into memory. Read the New Data clip directly from the disk stream. - - [Full] - Buffers all clips into memory. This option is the fastest but it requires more memory depending on the patch size. - """)); - Command.AddOption(bufferFastOpt = new Option(["-B", "--fast-buffer"], () => false, "Use array-based buffer for RLE Control and Code clips.")); - Command.AddOption(logLevelOpt = new Option(["-l", "--log-level"], () => Verbosity.Info, "Defines the verbosity of the info to be displayed.")); - - Command.SetHandler((context) => - { - inputPath = context.ParseResult.GetValueForArgument(inputPathArg); - patchPath = context.ParseResult.GetValueForArgument(patchPathArg); - outputPath = context.ParseResult.GetValueForArgument(outputPathArg); - - (isUseBufferedPatch, isUseFullBuffer) = context.ParseResult.GetValueForOption(bufferModeOpt) switch - { - BufferMode.Full => (true, true), - BufferMode.Partial => (true, false), - _ => (false, false) - }; - - isUseFastBuffer = context.ParseResult.GetValueForOption(bufferFastOpt); - // isUseMultiThread = context.ParseResult.GetValueForOption(_multiThreadOpt); - HDiffPatch.LogVerbosity = context.ParseResult.GetValueForOption(logLevelOpt); - - try - { - HDiffPatch patcher = new HDiffPatch(); - if (HDiffPatch.LogVerbosity != Verbosity.Quiet) - { - EventListener.LoggerEvent += EventListener_LoggerEvent; - EventListener.PatchEvent += EventListener_PatchEvent; - } -#if BENCHMARK - Stopwatch benchmarkSw = Stopwatch.StartNew(); - double[] warmUpAvgs = new double[5]; - Console.WriteLine($"Warming up {warmUpAvgs.Length} runtime attempts!"); - for (int h = 0; h < warmUpAvgs.Length; h++) - { - patcher.Initialize(patchPath); - patcher.Patch(inputPath, outputPath, isUseBufferedPatch, default, isUseFullBuffer, isUseFastBuffer); - warmUpAvgs[h] = benchmarkSw?.Elapsed.TotalMilliseconds ?? 0; - benchmarkSw?.Restart(); - Console.WriteLine($" Starting warm-up {h + 1}: {warmUpAvgs[h]} ms"); - } - Console.WriteLine($"Finished warming up runtime attempts in: {warmUpAvgs.Average()} ms"); - - double[] numAvgs = new double[5]; - Console.WriteLine($"Starting all {numAvgs.Length} runtime attempts!"); - for (int h = 0; h < numAvgs.Length; h++) - { - Console.WriteLine($" Starting Attempt {h + 1}: {numAvgs[h]} ms"); - int repeat = 20; - double[] num = new double[repeat]; - benchmarkSw?.Restart(); - for (int i = 0; i < num.Length; i++) - { -#endif - patcher.Initialize(patchPath); -#if !BENCHMARK - RefreshStopwatch?.Restart(); -#endif - patcher.Patch(inputPath, outputPath, isUseBufferedPatch, CancellationToken.None, isUseFullBuffer, isUseFastBuffer - // , isUseMultiThread - ); -#if BENCHMARK - num[i] = benchmarkSw?.Elapsed.TotalMilliseconds ?? 0; - benchmarkSw?.Restart(); - Console.WriteLine($" Finished on run {i + 1} - {repeat} Attempt {h + 1}: {num[i]} ms"); - } - - numAvgs[h] = num.Average(); - Console.WriteLine($" Runtime Attempt {h + 1}: {numAvgs[h]} ms"); - } - Console.WriteLine($"Average all {numAvgs.Length} runtime attempt: {numAvgs.Average()} ms"); -#endif - } - catch (Exception ex) - { - Console.WriteLine($"An error has occurred! [{ex.GetType().Name}]: {ex.Message}\r\nStack Trace:\r\n{ex.StackTrace}"); - context.ExitCode = int.MinValue; -#if DEBUG - throw; -#endif - } - finally - { - RefreshStopwatch?.Stop(); - if (HDiffPatch.LogVerbosity != Verbosity.Quiet) - { - EventListener.LoggerEvent -= EventListener_LoggerEvent; - EventListener.PatchEvent -= EventListener_PatchEvent; - } - } - }); - - return Command.Invoke(args); - } - - private static void EventListener_LoggerEvent(object? sender, LoggerEvent e) - { - if (HDiffPatch.LogVerbosity == Verbosity.Quiet - || (HDiffPatch.LogVerbosity == Verbosity.Debug - && e.LogLevel is not (Verbosity.Debug or Verbosity.Verbose or Verbosity.Info)) - || (HDiffPatch.LogVerbosity == Verbosity.Verbose - && e.LogLevel is not (Verbosity.Verbose or Verbosity.Info)) - || (HDiffPatch.LogVerbosity == Verbosity.Info - && e.LogLevel != Verbosity.Info)) return; - - PrintLog(e); - } - - private static void PrintLog(LoggerEvent e) - { - string label = e.LogLevel switch - { - Verbosity.Info => "[Info] ", - Verbosity.Verbose => "[Verbose] ", - Verbosity.Debug => "[Debug] ", - _ => "" - }; - - Console.WriteLine($"{label}{e.Message}"); - } - - private static async void EventListener_PatchEvent(object? sender, PatchEvent e) - { - try - { - if (await CheckIfNeedRefreshStopwatch()) - { - Console.Write( - $"Patching: {e.ProgressPercentage}% | " + - $"{SummarizeSizeSimple(e.CurrentSizePatched)}/{SummarizeSizeSimple(e.TotalSizeToBePatched)} " + - $"@{SummarizeSizeSimple(e.Speed)}/s " + - $"[{string.Format("{0:hh}h:{0:mm}m:{0:ss}s remaining", TimeSpan.FromSeconds((e.TotalSizeToBePatched - e.CurrentSizePatched) / UnZeroed(e.Speed)))}] \r"); - } - - return; - static double UnZeroed(double input) => Math.Max(input, 1); - } - catch - { - // ignored - } - } - - private static async Task CheckIfNeedRefreshStopwatch() - { - if (RefreshStopwatch.ElapsedMilliseconds > RefreshInterval) - { - RefreshStopwatch.Restart(); - return true; - } - - await Task.Delay(RefreshInterval); - return false; - } - - private static string SummarizeSizeSimple(double value, int decimalPlaces = 2) - { - byte mag = (byte)Math.Log(value, 1000); - - return $"{Math.Round(value / (1L << (mag * 10)), decimalPlaces)} {SizeSuffixes[mag]}"; - } - } -} diff --git a/SharpHDiffPatch/Properties/launchSettings.json b/SharpHDiffPatch/Properties/launchSettings.json deleted file mode 100644 index 365f845..0000000 --- a/SharpHDiffPatch/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "SharpHDiffPatch-bin": { - "commandName": "Project", - "commandLineArgs": "\"G:\\Hi3SEA\" \"G:\\Hi3CNRecipe.cookbook.bz2\" \"K:\\Hi3CN-dotnet\" -l Verbose -B -b partial" - } - } -} \ No newline at end of file diff --git a/SharpHPatchZ.Program/Program.cs b/SharpHPatchZ.Program/Program.cs new file mode 100644 index 0000000..92666ff --- /dev/null +++ b/SharpHPatchZ.Program/Program.cs @@ -0,0 +1,185 @@ +using System; +using System.CommandLine; +using System.Diagnostics; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using SharpHPatchZ.Header; + +// ReSharper disable InconsistentNaming +// ReSharper disable CommentTypo + +namespace SharpHPatchZ.Program +{ + public static class PatcherBin + { + private static readonly string[] SizeSuffixes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; + private const int RefreshInterval = 100; + private static readonly RootCommand Command = new(); + private static readonly Stopwatch Stopwatch = Stopwatch.StartNew(); + private static readonly Stopwatch RefreshStopwatch = Stopwatch.StartNew(); + + public enum BufferSize + { + BigBuffer, + MediumBuffer, + SmallBuffer, + OptimizedForHDD + } + + public static int Main(params string[] args) + { + Argument inputPathArg, patchPathArg, outputPathArg; + Option bufferModeOpt; + Option threadsOpt; + + string inputPath, patchPath, outputPath; + int threads; + + Command.AddArgument(inputPathArg = new Argument("Input File", "Input path of the old file/folder to patch")); + Command.AddArgument(patchPathArg = new Argument("Patch File", "Patch file path to produce the new version of the file/folder")); + Command.AddArgument(outputPathArg = new Argument("Output File", "Output path of the new version to be produced")); + Command.AddOption(bufferModeOpt = new Option(["-b", "--buffer-mode"], () => BufferSize.BigBuffer, + """ + Determines the buffering mode for reading the clips of the patch files. + [BigBuffer (Default)] + Buffer Size = Up to 16 MB per chunks + + [MediumBuffer] + Buffer Size = Up to 1 MB per chunks + + [SmallBuffer] + Buffer Size = Up to 1 MB per chunks + """)); + Command.AddOption(threadsOpt = new Option(["-p", "--parallel-threads"], () => Environment.ProcessorCount, + "Determines how much parallel threads to be run.")); + + Command.SetHandler((context) => + { + inputPath = context.ParseResult.GetValueForArgument(inputPathArg); + patchPath = context.ParseResult.GetValueForArgument(patchPathArg); + outputPath = context.ParseResult.GetValueForArgument(outputPathArg); + + BufferSize bufferSize = context.ParseResult.GetValueForOption(bufferModeOpt); + PatchOptions options = bufferSize switch + { + BufferSize.BigBuffer => PatchOptions.BigBuffer, + BufferSize.MediumBuffer => PatchOptions.Default, + BufferSize.SmallBuffer => PatchOptions.SmallBuffer, + BufferSize.OptimizedForHDD => PatchOptions.OptimizeForHDD, + _ => PatchOptions.BigBuffer + }; + + if (bufferSize != BufferSize.OptimizedForHDD) + { + threads = context.ParseResult.GetValueForOption(threadsOpt); + options = options with + { + ParallelThreads = (uint)threads + }; + } + + try + { + ProgressCallback progressCallback = ProgressCallback.CreateFromManaged(PatchProgress); + + using HDiffInfo info = HPatch.CreateInstance(CreatePatchStream); + HPatch.Patch(info, CreatePatchStream, inputPath, outputPath, options, progressCallback); + + Console.WriteLine(); + Console.WriteLine($"Patch completed in: {Stopwatch.Elapsed:c}"); + + (Stream, bool) CreatePatchStream(long position) + { + FileStream stream = File.Open(patchPath, FileMode.Open, FileAccess.Read, FileShare.Read); + stream.Position = position; + return (stream, false); + } + } + catch (Exception ex) + { + Console.WriteLine($"An error has occurred! [{ex.GetType().Name}]: {ex.Message}\r\nStack Trace:\r\n{ex.StackTrace}"); + context.ExitCode = int.MinValue; +#if DEBUG + throw; +#endif + } + finally + { + Stopwatch.Stop(); + RefreshStopwatch.Stop(); + } + }); + + return Command.Invoke(args); + } + + private static double lastSpeed; + private static TimeSpan lastRemainedTime = TimeSpan.Zero; + + public static void PatchProgress(long totalProcessed, long totalSize, int written) + { + double speed = CalculateSpeed(written); + double percent = Math.Round(totalProcessed / (double)totalSize * 100, 2); + + if (CheckIfNeedRefreshStopwatch()) + { + lastRemainedTime = TimeSpan.FromSeconds((totalSize - totalProcessed) / UnZeroed(speed)); + Interlocked.Exchange(ref lastSpeed, speed); + } + + Console.Write( + $"Patching: {percent}% | " + + $"{SummarizeSizeSimple(totalProcessed)}/{SummarizeSizeSimple(totalSize)} " + + $"@{SummarizeSizeSimple(lastSpeed)}/s " + + $"[{string.Format("{0:hh}h:{0:mm}m:{0:ss}s remaining", lastRemainedTime)}] \r"); + + return; + static double UnZeroed(double input) => Math.Max(input, 1); + } + private const double ScOneSecond = 1000; + private static long _scLastTick = Environment.TickCount; + private static long _scLastReceivedBytes; + private static double _scLastSpeed; + private static int _riLastTick = Environment.TickCount; + + private static double CalculateSpeed(long receivedBytes) => CalculateSpeed(receivedBytes, ref _scLastSpeed, ref _scLastReceivedBytes, ref _scLastTick); + + private static double CalculateSpeed(long receivedBytes, ref double lastSpeedToUse, ref long lastReceivedBytesToUse, ref long lastTickToUse) + { + long currentTick = Environment.TickCount - lastTickToUse + 1; + long totalReceivedInSecond = Interlocked.Add(ref lastReceivedBytesToUse, receivedBytes); + double speed = totalReceivedInSecond * ScOneSecond / currentTick; + + if (!(currentTick > ScOneSecond)) + { + return lastSpeedToUse; + } + + lastSpeedToUse = speed; + _ = Interlocked.Exchange(ref lastSpeedToUse, speed); + _ = Interlocked.Exchange(ref lastReceivedBytesToUse, 0); + _ = Interlocked.Exchange(ref lastTickToUse, Environment.TickCount); + return lastSpeedToUse; + } + + public static bool CheckIfNeedRefreshStopwatch() + { + int currentTick = Environment.TickCount - _riLastTick; + if (currentTick <= RefreshInterval) + { + return false; + } + + Interlocked.Exchange(ref _riLastTick, Environment.TickCount); + return true; + } + + private static string SummarizeSizeSimple(double value, int decimalPlaces = 2) + { + byte mag = (byte)Math.Log(value, 1000); + + return $"{Math.Round(value / (1L << (mag * 10)), decimalPlaces)} {SizeSuffixes[mag]}"; + } + } +} diff --git a/SharpHPatchZ.Program/Properties/launchSettings.json b/SharpHPatchZ.Program/Properties/launchSettings.json new file mode 100644 index 0000000..10c5aee --- /dev/null +++ b/SharpHPatchZ.Program/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "SharpHDiffPatch-bin": { + "commandName": "Project", + "commandLineArgs": "G:\\Hi3SEA G:\\Hi3SEAtoCNExecOnly.lzma2.diff G:\\Hi3CN-dotnet" + } + } +} \ No newline at end of file diff --git a/SharpHDiffPatch/SharpHDiffPatch.csproj b/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj similarity index 67% rename from SharpHDiffPatch/SharpHDiffPatch.csproj rename to SharpHPatchZ.Program/SharpHPatchZ.Program.csproj index d9b35e0..08b5b76 100644 --- a/SharpHDiffPatch/SharpHDiffPatch.csproj +++ b/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj @@ -3,16 +3,17 @@ Exe net10.0 - SharpHDiffPatch + SharpHPatchZ.Program + SharpHPatchZ.Program disable enable x64;ARM64;AnyCPU;x86 - 2.3.4 + 3.0.0 true Debug;Release - + diff --git a/SharpHDiffPatch/System.CommandLine/Argument.cs b/SharpHPatchZ.Program/System.CommandLine/Argument.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Argument.cs rename to SharpHPatchZ.Program/System.CommandLine/Argument.cs diff --git a/SharpHDiffPatch/System.CommandLine/ArgumentArity.cs b/SharpHPatchZ.Program/System.CommandLine/ArgumentArity.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/ArgumentArity.cs rename to SharpHPatchZ.Program/System.CommandLine/ArgumentArity.cs diff --git a/SharpHDiffPatch/System.CommandLine/ArgumentExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/ArgumentExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/ArgumentExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/ArgumentExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/Argument{T}.cs b/SharpHPatchZ.Program/System.CommandLine/Argument{T}.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Argument{T}.cs rename to SharpHPatchZ.Program/System.CommandLine/Argument{T}.cs diff --git a/SharpHDiffPatch/System.CommandLine/Binding/ArgumentConversionResult.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/ArgumentConversionResult.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Binding/ArgumentConversionResult.cs rename to SharpHPatchZ.Program/System.CommandLine/Binding/ArgumentConversionResult.cs diff --git a/SharpHDiffPatch/System.CommandLine/Binding/ArgumentConversionResultType.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/ArgumentConversionResultType.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Binding/ArgumentConversionResultType.cs rename to SharpHPatchZ.Program/System.CommandLine/Binding/ArgumentConversionResultType.cs diff --git a/SharpHDiffPatch/System.CommandLine/Binding/ArgumentConverter.DefaultValues.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/ArgumentConverter.DefaultValues.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Binding/ArgumentConverter.DefaultValues.cs rename to SharpHPatchZ.Program/System.CommandLine/Binding/ArgumentConverter.DefaultValues.cs diff --git a/SharpHDiffPatch/System.CommandLine/Binding/ArgumentConverter.StringConverters.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/ArgumentConverter.StringConverters.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Binding/ArgumentConverter.StringConverters.cs rename to SharpHPatchZ.Program/System.CommandLine/Binding/ArgumentConverter.StringConverters.cs diff --git a/SharpHDiffPatch/System.CommandLine/Binding/ArgumentConverter.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/ArgumentConverter.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Binding/ArgumentConverter.cs rename to SharpHPatchZ.Program/System.CommandLine/Binding/ArgumentConverter.cs diff --git a/SharpHDiffPatch/System.CommandLine/Binding/BinderBase{T}.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/BinderBase{T}.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Binding/BinderBase{T}.cs rename to SharpHPatchZ.Program/System.CommandLine/Binding/BinderBase{T}.cs diff --git a/SharpHDiffPatch/System.CommandLine/Binding/BindingContext.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/BindingContext.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Binding/BindingContext.cs rename to SharpHPatchZ.Program/System.CommandLine/Binding/BindingContext.cs diff --git a/SharpHDiffPatch/System.CommandLine/Binding/BoundValue.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/BoundValue.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Binding/BoundValue.cs rename to SharpHPatchZ.Program/System.CommandLine/Binding/BoundValue.cs diff --git a/SharpHDiffPatch/System.CommandLine/Binding/IValueDescriptor.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/IValueDescriptor.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Binding/IValueDescriptor.cs rename to SharpHPatchZ.Program/System.CommandLine/Binding/IValueDescriptor.cs diff --git a/SharpHDiffPatch/System.CommandLine/Binding/IValueDescriptor{T}.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/IValueDescriptor{T}.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Binding/IValueDescriptor{T}.cs rename to SharpHPatchZ.Program/System.CommandLine/Binding/IValueDescriptor{T}.cs diff --git a/SharpHDiffPatch/System.CommandLine/Binding/IValueSource.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/IValueSource.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Binding/IValueSource.cs rename to SharpHPatchZ.Program/System.CommandLine/Binding/IValueSource.cs diff --git a/SharpHDiffPatch/System.CommandLine/Binding/ServiceProviderExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/ServiceProviderExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Binding/ServiceProviderExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/Binding/ServiceProviderExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/Binding/ServiceProviderValueSource.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/ServiceProviderValueSource.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Binding/ServiceProviderValueSource.cs rename to SharpHPatchZ.Program/System.CommandLine/Binding/ServiceProviderValueSource.cs diff --git a/SharpHDiffPatch/System.CommandLine/Binding/TryConvertArgument.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/TryConvertArgument.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Binding/TryConvertArgument.cs rename to SharpHPatchZ.Program/System.CommandLine/Binding/TryConvertArgument.cs diff --git a/SharpHDiffPatch/System.CommandLine/Binding/TypeExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/TypeExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Binding/TypeExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/Binding/TypeExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/Binding/ValueDescriptorDefaultValueSource.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/ValueDescriptorDefaultValueSource.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Binding/ValueDescriptorDefaultValueSource.cs rename to SharpHPatchZ.Program/System.CommandLine/Binding/ValueDescriptorDefaultValueSource.cs diff --git a/SharpHDiffPatch/System.CommandLine/Builder/CommandLineBuilder.cs b/SharpHPatchZ.Program/System.CommandLine/Builder/CommandLineBuilder.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Builder/CommandLineBuilder.cs rename to SharpHPatchZ.Program/System.CommandLine/Builder/CommandLineBuilder.cs diff --git a/SharpHDiffPatch/System.CommandLine/Builder/CommandLineBuilderExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/Builder/CommandLineBuilderExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Builder/CommandLineBuilderExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/Builder/CommandLineBuilderExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/Command.cs b/SharpHPatchZ.Program/System.CommandLine/Command.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Command.cs rename to SharpHPatchZ.Program/System.CommandLine/Command.cs diff --git a/SharpHDiffPatch/System.CommandLine/CommandExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/CommandExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/CommandExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/CommandExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/CommandLineConfiguration.cs b/SharpHPatchZ.Program/System.CommandLine/CommandLineConfiguration.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/CommandLineConfiguration.cs rename to SharpHPatchZ.Program/System.CommandLine/CommandLineConfiguration.cs diff --git a/SharpHDiffPatch/System.CommandLine/CommandLineConfigurationException.cs b/SharpHPatchZ.Program/System.CommandLine/CommandLineConfigurationException.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/CommandLineConfigurationException.cs rename to SharpHPatchZ.Program/System.CommandLine/CommandLineConfigurationException.cs diff --git a/SharpHDiffPatch/System.CommandLine/CompletionSourceExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/CompletionSourceExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/CompletionSourceExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/CompletionSourceExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/CompletionSourceList.cs b/SharpHPatchZ.Program/System.CommandLine/CompletionSourceList.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/CompletionSourceList.cs rename to SharpHPatchZ.Program/System.CommandLine/CompletionSourceList.cs diff --git a/SharpHDiffPatch/System.CommandLine/Completions/AnonymousCompletionSource.cs b/SharpHPatchZ.Program/System.CommandLine/Completions/AnonymousCompletionSource.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Completions/AnonymousCompletionSource.cs rename to SharpHPatchZ.Program/System.CommandLine/Completions/AnonymousCompletionSource.cs diff --git a/SharpHDiffPatch/System.CommandLine/Completions/CompletionContext.cs b/SharpHPatchZ.Program/System.CommandLine/Completions/CompletionContext.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Completions/CompletionContext.cs rename to SharpHPatchZ.Program/System.CommandLine/Completions/CompletionContext.cs diff --git a/SharpHDiffPatch/System.CommandLine/Completions/CompletionDelegate.cs b/SharpHPatchZ.Program/System.CommandLine/Completions/CompletionDelegate.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Completions/CompletionDelegate.cs rename to SharpHPatchZ.Program/System.CommandLine/Completions/CompletionDelegate.cs diff --git a/SharpHDiffPatch/System.CommandLine/Completions/CompletionItem.cs b/SharpHPatchZ.Program/System.CommandLine/Completions/CompletionItem.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Completions/CompletionItem.cs rename to SharpHPatchZ.Program/System.CommandLine/Completions/CompletionItem.cs diff --git a/SharpHDiffPatch/System.CommandLine/Completions/CompletionItemKind.cs b/SharpHPatchZ.Program/System.CommandLine/Completions/CompletionItemKind.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Completions/CompletionItemKind.cs rename to SharpHPatchZ.Program/System.CommandLine/Completions/CompletionItemKind.cs diff --git a/SharpHDiffPatch/System.CommandLine/Completions/CompletionSource.cs b/SharpHPatchZ.Program/System.CommandLine/Completions/CompletionSource.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Completions/CompletionSource.cs rename to SharpHPatchZ.Program/System.CommandLine/Completions/CompletionSource.cs diff --git a/SharpHDiffPatch/System.CommandLine/Completions/ICompletionSource.cs b/SharpHPatchZ.Program/System.CommandLine/Completions/ICompletionSource.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Completions/ICompletionSource.cs rename to SharpHPatchZ.Program/System.CommandLine/Completions/ICompletionSource.cs diff --git a/SharpHDiffPatch/System.CommandLine/Completions/TextCompletionContext.cs b/SharpHPatchZ.Program/System.CommandLine/Completions/TextCompletionContext.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Completions/TextCompletionContext.cs rename to SharpHPatchZ.Program/System.CommandLine/Completions/TextCompletionContext.cs diff --git a/SharpHDiffPatch/System.CommandLine/Completions/TokenCompletionContext.cs b/SharpHPatchZ.Program/System.CommandLine/Completions/TokenCompletionContext.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Completions/TokenCompletionContext.cs rename to SharpHPatchZ.Program/System.CommandLine/Completions/TokenCompletionContext.cs diff --git a/SharpHDiffPatch/System.CommandLine/ConsoleExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/ConsoleExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/ConsoleExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/ConsoleExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/DebugAssert.cs b/SharpHPatchZ.Program/System.CommandLine/DebugAssert.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/DebugAssert.cs rename to SharpHPatchZ.Program/System.CommandLine/DebugAssert.cs diff --git a/SharpHDiffPatch/System.CommandLine/DictionaryExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/DictionaryExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/DictionaryExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/DictionaryExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/DirectiveCollection.cs b/SharpHPatchZ.Program/System.CommandLine/DirectiveCollection.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/DirectiveCollection.cs rename to SharpHPatchZ.Program/System.CommandLine/DirectiveCollection.cs diff --git a/SharpHDiffPatch/System.CommandLine/EnumerableExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/EnumerableExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/EnumerableExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/EnumerableExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/Handler.Action.cs b/SharpHPatchZ.Program/System.CommandLine/Handler.Action.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Handler.Action.cs rename to SharpHPatchZ.Program/System.CommandLine/Handler.Action.cs diff --git a/SharpHDiffPatch/System.CommandLine/Handler.Func.cs b/SharpHPatchZ.Program/System.CommandLine/Handler.Func.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Handler.Func.cs rename to SharpHPatchZ.Program/System.CommandLine/Handler.Func.cs diff --git a/SharpHDiffPatch/System.CommandLine/Handler.cs b/SharpHPatchZ.Program/System.CommandLine/Handler.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Handler.cs rename to SharpHPatchZ.Program/System.CommandLine/Handler.cs diff --git a/SharpHDiffPatch/System.CommandLine/Help/HelpBuilder.Default.cs b/SharpHPatchZ.Program/System.CommandLine/Help/HelpBuilder.Default.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Help/HelpBuilder.Default.cs rename to SharpHPatchZ.Program/System.CommandLine/Help/HelpBuilder.Default.cs diff --git a/SharpHDiffPatch/System.CommandLine/Help/HelpBuilder.cs b/SharpHPatchZ.Program/System.CommandLine/Help/HelpBuilder.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Help/HelpBuilder.cs rename to SharpHPatchZ.Program/System.CommandLine/Help/HelpBuilder.cs diff --git a/SharpHDiffPatch/System.CommandLine/Help/HelpBuilderExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/Help/HelpBuilderExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Help/HelpBuilderExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/Help/HelpBuilderExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/Help/HelpContext.cs b/SharpHPatchZ.Program/System.CommandLine/Help/HelpContext.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Help/HelpContext.cs rename to SharpHPatchZ.Program/System.CommandLine/Help/HelpContext.cs diff --git a/SharpHDiffPatch/System.CommandLine/Help/HelpOption.cs b/SharpHPatchZ.Program/System.CommandLine/Help/HelpOption.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Help/HelpOption.cs rename to SharpHPatchZ.Program/System.CommandLine/Help/HelpOption.cs diff --git a/SharpHDiffPatch/System.CommandLine/Help/HelpResult.cs b/SharpHPatchZ.Program/System.CommandLine/Help/HelpResult.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Help/HelpResult.cs rename to SharpHPatchZ.Program/System.CommandLine/Help/HelpResult.cs diff --git a/SharpHDiffPatch/System.CommandLine/Help/HelpSectionDelegate.cs b/SharpHPatchZ.Program/System.CommandLine/Help/HelpSectionDelegate.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Help/HelpSectionDelegate.cs rename to SharpHPatchZ.Program/System.CommandLine/Help/HelpSectionDelegate.cs diff --git a/SharpHDiffPatch/System.CommandLine/Help/TwoColumnHelpRow.cs b/SharpHPatchZ.Program/System.CommandLine/Help/TwoColumnHelpRow.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Help/TwoColumnHelpRow.cs rename to SharpHPatchZ.Program/System.CommandLine/Help/TwoColumnHelpRow.cs diff --git a/SharpHDiffPatch/System.CommandLine/Help/VersionOption.cs b/SharpHPatchZ.Program/System.CommandLine/Help/VersionOption.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Help/VersionOption.cs rename to SharpHPatchZ.Program/System.CommandLine/Help/VersionOption.cs diff --git a/SharpHDiffPatch/System.CommandLine/IConsole.cs b/SharpHPatchZ.Program/System.CommandLine/IConsole.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/IConsole.cs rename to SharpHPatchZ.Program/System.CommandLine/IConsole.cs diff --git a/SharpHDiffPatch/System.CommandLine/IO/ConsoleExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/IO/ConsoleExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/IO/ConsoleExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/IO/ConsoleExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/IO/IStandardError.cs b/SharpHPatchZ.Program/System.CommandLine/IO/IStandardError.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/IO/IStandardError.cs rename to SharpHPatchZ.Program/System.CommandLine/IO/IStandardError.cs diff --git a/SharpHDiffPatch/System.CommandLine/IO/IStandardIn.cs b/SharpHPatchZ.Program/System.CommandLine/IO/IStandardIn.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/IO/IStandardIn.cs rename to SharpHPatchZ.Program/System.CommandLine/IO/IStandardIn.cs diff --git a/SharpHDiffPatch/System.CommandLine/IO/IStandardOut.cs b/SharpHPatchZ.Program/System.CommandLine/IO/IStandardOut.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/IO/IStandardOut.cs rename to SharpHPatchZ.Program/System.CommandLine/IO/IStandardOut.cs diff --git a/SharpHDiffPatch/System.CommandLine/IO/IStandardStreamWriter.cs b/SharpHPatchZ.Program/System.CommandLine/IO/IStandardStreamWriter.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/IO/IStandardStreamWriter.cs rename to SharpHPatchZ.Program/System.CommandLine/IO/IStandardStreamWriter.cs diff --git a/SharpHDiffPatch/System.CommandLine/IO/StandardStreamWriter.cs b/SharpHPatchZ.Program/System.CommandLine/IO/StandardStreamWriter.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/IO/StandardStreamWriter.cs rename to SharpHPatchZ.Program/System.CommandLine/IO/StandardStreamWriter.cs diff --git a/SharpHDiffPatch/System.CommandLine/IO/SystemConsole.cs b/SharpHPatchZ.Program/System.CommandLine/IO/SystemConsole.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/IO/SystemConsole.cs rename to SharpHPatchZ.Program/System.CommandLine/IO/SystemConsole.cs diff --git a/SharpHDiffPatch/System.CommandLine/IO/TestConsole.cs b/SharpHPatchZ.Program/System.CommandLine/IO/TestConsole.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/IO/TestConsole.cs rename to SharpHPatchZ.Program/System.CommandLine/IO/TestConsole.cs diff --git a/SharpHDiffPatch/System.CommandLine/IdentifierSymbol.cs b/SharpHPatchZ.Program/System.CommandLine/IdentifierSymbol.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/IdentifierSymbol.cs rename to SharpHPatchZ.Program/System.CommandLine/IdentifierSymbol.cs diff --git a/SharpHDiffPatch/System.CommandLine/Invocation/AnonymousCommandHandler.cs b/SharpHPatchZ.Program/System.CommandLine/Invocation/AnonymousCommandHandler.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Invocation/AnonymousCommandHandler.cs rename to SharpHPatchZ.Program/System.CommandLine/Invocation/AnonymousCommandHandler.cs diff --git a/SharpHDiffPatch/System.CommandLine/Invocation/FeatureRegistration.cs b/SharpHPatchZ.Program/System.CommandLine/Invocation/FeatureRegistration.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Invocation/FeatureRegistration.cs rename to SharpHPatchZ.Program/System.CommandLine/Invocation/FeatureRegistration.cs diff --git a/SharpHDiffPatch/System.CommandLine/Invocation/ICommandHandler.cs b/SharpHPatchZ.Program/System.CommandLine/Invocation/ICommandHandler.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Invocation/ICommandHandler.cs rename to SharpHPatchZ.Program/System.CommandLine/Invocation/ICommandHandler.cs diff --git a/SharpHDiffPatch/System.CommandLine/Invocation/IInvocationResult.cs b/SharpHPatchZ.Program/System.CommandLine/Invocation/IInvocationResult.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Invocation/IInvocationResult.cs rename to SharpHPatchZ.Program/System.CommandLine/Invocation/IInvocationResult.cs diff --git a/SharpHDiffPatch/System.CommandLine/Invocation/InvocationContext.cs b/SharpHPatchZ.Program/System.CommandLine/Invocation/InvocationContext.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Invocation/InvocationContext.cs rename to SharpHPatchZ.Program/System.CommandLine/Invocation/InvocationContext.cs diff --git a/SharpHDiffPatch/System.CommandLine/Invocation/InvocationMiddleware.cs b/SharpHPatchZ.Program/System.CommandLine/Invocation/InvocationMiddleware.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Invocation/InvocationMiddleware.cs rename to SharpHPatchZ.Program/System.CommandLine/Invocation/InvocationMiddleware.cs diff --git a/SharpHDiffPatch/System.CommandLine/Invocation/InvocationPipeline.cs b/SharpHPatchZ.Program/System.CommandLine/Invocation/InvocationPipeline.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Invocation/InvocationPipeline.cs rename to SharpHPatchZ.Program/System.CommandLine/Invocation/InvocationPipeline.cs diff --git a/SharpHDiffPatch/System.CommandLine/Invocation/MiddlewareOrder.cs b/SharpHPatchZ.Program/System.CommandLine/Invocation/MiddlewareOrder.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Invocation/MiddlewareOrder.cs rename to SharpHPatchZ.Program/System.CommandLine/Invocation/MiddlewareOrder.cs diff --git a/SharpHDiffPatch/System.CommandLine/Invocation/ParseDirectiveResult.cs b/SharpHPatchZ.Program/System.CommandLine/Invocation/ParseDirectiveResult.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Invocation/ParseDirectiveResult.cs rename to SharpHPatchZ.Program/System.CommandLine/Invocation/ParseDirectiveResult.cs diff --git a/SharpHDiffPatch/System.CommandLine/Invocation/ParseErrorResult.cs b/SharpHPatchZ.Program/System.CommandLine/Invocation/ParseErrorResult.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Invocation/ParseErrorResult.cs rename to SharpHPatchZ.Program/System.CommandLine/Invocation/ParseErrorResult.cs diff --git a/SharpHDiffPatch/System.CommandLine/Invocation/Process.cs b/SharpHPatchZ.Program/System.CommandLine/Invocation/Process.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Invocation/Process.cs rename to SharpHPatchZ.Program/System.CommandLine/Invocation/Process.cs diff --git a/SharpHDiffPatch/System.CommandLine/Invocation/ServiceProvider.cs b/SharpHPatchZ.Program/System.CommandLine/Invocation/ServiceProvider.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Invocation/ServiceProvider.cs rename to SharpHPatchZ.Program/System.CommandLine/Invocation/ServiceProvider.cs diff --git a/SharpHDiffPatch/System.CommandLine/Invocation/SuggestDirectiveResult.cs b/SharpHPatchZ.Program/System.CommandLine/Invocation/SuggestDirectiveResult.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Invocation/SuggestDirectiveResult.cs rename to SharpHPatchZ.Program/System.CommandLine/Invocation/SuggestDirectiveResult.cs diff --git a/SharpHDiffPatch/System.CommandLine/Invocation/TypoCorrection.cs b/SharpHPatchZ.Program/System.CommandLine/Invocation/TypoCorrection.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Invocation/TypoCorrection.cs rename to SharpHPatchZ.Program/System.CommandLine/Invocation/TypoCorrection.cs diff --git a/SharpHDiffPatch/System.CommandLine/LocalizationResources.cs b/SharpHPatchZ.Program/System.CommandLine/LocalizationResources.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/LocalizationResources.cs rename to SharpHPatchZ.Program/System.CommandLine/LocalizationResources.cs diff --git a/SharpHDiffPatch/System.CommandLine/Option.cs b/SharpHPatchZ.Program/System.CommandLine/Option.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Option.cs rename to SharpHPatchZ.Program/System.CommandLine/Option.cs diff --git a/SharpHDiffPatch/System.CommandLine/OptionExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/OptionExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/OptionExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/OptionExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/Option{T}.cs b/SharpHPatchZ.Program/System.CommandLine/Option{T}.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Option{T}.cs rename to SharpHPatchZ.Program/System.CommandLine/Option{T}.cs diff --git a/SharpHDiffPatch/System.CommandLine/ParentNode.cs b/SharpHPatchZ.Program/System.CommandLine/ParentNode.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/ParentNode.cs rename to SharpHPatchZ.Program/System.CommandLine/ParentNode.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/ArgumentResult.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/ArgumentResult.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/ArgumentResult.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/ArgumentResult.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/CommandArgumentNode.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/CommandArgumentNode.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/CommandArgumentNode.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/CommandArgumentNode.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/CommandLineStringSplitter.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/CommandLineStringSplitter.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/CommandLineStringSplitter.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/CommandLineStringSplitter.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/CommandNode.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/CommandNode.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/CommandNode.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/CommandNode.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/CommandResult.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/CommandResult.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/CommandResult.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/CommandResult.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/DirectiveNode.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/DirectiveNode.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/DirectiveNode.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/DirectiveNode.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/NonterminalSyntaxNode.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/NonterminalSyntaxNode.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/NonterminalSyntaxNode.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/NonterminalSyntaxNode.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/OptionArgumentNode.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/OptionArgumentNode.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/OptionArgumentNode.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/OptionArgumentNode.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/OptionNode.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/OptionNode.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/OptionNode.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/OptionNode.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/OptionResult.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/OptionResult.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/OptionResult.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/OptionResult.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/OptionResultExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/OptionResultExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/OptionResultExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/OptionResultExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/ParseArgument{T}.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/ParseArgument{T}.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/ParseArgument{T}.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/ParseArgument{T}.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/ParseError.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/ParseError.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/ParseError.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/ParseError.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/ParseOperation.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/ParseOperation.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/ParseOperation.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/ParseOperation.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/ParseResult.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/ParseResult.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/ParseResult.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/ParseResult.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/ParseResultExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/ParseResultExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/ParseResultExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/ParseResultExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/ParseResultVisitor.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/ParseResultVisitor.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/ParseResultVisitor.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/ParseResultVisitor.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/Parser.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/Parser.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/Parser.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/Parser.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/ParserExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/ParserExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/ParserExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/ParserExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/RootCommandResult.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/RootCommandResult.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/RootCommandResult.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/RootCommandResult.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/StringExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/StringExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/StringExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/StringExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/SymbolResult.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/SymbolResult.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/SymbolResult.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/SymbolResult.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/SymbolResultExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/SymbolResultExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/SymbolResultExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/SymbolResultExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/SymbolResultVisitor.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/SymbolResultVisitor.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/SymbolResultVisitor.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/SymbolResultVisitor.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/SyntaxNode.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/SyntaxNode.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/SyntaxNode.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/SyntaxNode.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/Token.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/Token.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/Token.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/Token.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/TokenType.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/TokenType.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/TokenType.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/TokenType.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/TokenizeResult.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/TokenizeResult.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/TokenizeResult.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/TokenizeResult.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/TryReplaceToken.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/TryReplaceToken.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/TryReplaceToken.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/TryReplaceToken.cs diff --git a/SharpHDiffPatch/System.CommandLine/Parsing/ValidateSymbolResult.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/ValidateSymbolResult.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Parsing/ValidateSymbolResult.cs rename to SharpHPatchZ.Program/System.CommandLine/Parsing/ValidateSymbolResult.cs diff --git a/SharpHDiffPatch/System.CommandLine/Platform.cs b/SharpHPatchZ.Program/System.CommandLine/Platform.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Platform.cs rename to SharpHPatchZ.Program/System.CommandLine/Platform.cs diff --git a/SharpHDiffPatch/System.CommandLine/Properties/Resources.Designer.cs b/SharpHPatchZ.Program/System.CommandLine/Properties/Resources.Designer.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Properties/Resources.Designer.cs rename to SharpHPatchZ.Program/System.CommandLine/Properties/Resources.Designer.cs diff --git a/SharpHDiffPatch/System.CommandLine/RootCommand.cs b/SharpHPatchZ.Program/System.CommandLine/RootCommand.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/RootCommand.cs rename to SharpHPatchZ.Program/System.CommandLine/RootCommand.cs diff --git a/SharpHDiffPatch/System.CommandLine/StringBuilderPool.cs b/SharpHPatchZ.Program/System.CommandLine/StringBuilderPool.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/StringBuilderPool.cs rename to SharpHPatchZ.Program/System.CommandLine/StringBuilderPool.cs diff --git a/SharpHDiffPatch/System.CommandLine/Symbol.cs b/SharpHPatchZ.Program/System.CommandLine/Symbol.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Symbol.cs rename to SharpHPatchZ.Program/System.CommandLine/Symbol.cs diff --git a/SharpHDiffPatch/System.CommandLine/SymbolExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/SymbolExtensions.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/SymbolExtensions.cs rename to SharpHPatchZ.Program/System.CommandLine/SymbolExtensions.cs diff --git a/SharpHDiffPatch/System.CommandLine/System.Diagnostics.CodeAnalysis/DynamicallyAccessedMemberTypes.cs b/SharpHPatchZ.Program/System.CommandLine/System.Diagnostics.CodeAnalysis/DynamicallyAccessedMemberTypes.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/System.Diagnostics.CodeAnalysis/DynamicallyAccessedMemberTypes.cs rename to SharpHPatchZ.Program/System.CommandLine/System.Diagnostics.CodeAnalysis/DynamicallyAccessedMemberTypes.cs diff --git a/SharpHDiffPatch/System.CommandLine/System.Diagnostics.CodeAnalysis/DynamicallyAccessedMembersAttribute.cs b/SharpHPatchZ.Program/System.CommandLine/System.Diagnostics.CodeAnalysis/DynamicallyAccessedMembersAttribute.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/System.Diagnostics.CodeAnalysis/DynamicallyAccessedMembersAttribute.cs rename to SharpHPatchZ.Program/System.CommandLine/System.Diagnostics.CodeAnalysis/DynamicallyAccessedMembersAttribute.cs diff --git a/SharpHDiffPatch/System.CommandLine/System.Diagnostics.CodeAnalysis/UnconditionalSuppressMessageAttribute.cs b/SharpHPatchZ.Program/System.CommandLine/System.Diagnostics.CodeAnalysis/UnconditionalSuppressMessageAttribute.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/System.Diagnostics.CodeAnalysis/UnconditionalSuppressMessageAttribute.cs rename to SharpHPatchZ.Program/System.CommandLine/System.Diagnostics.CodeAnalysis/UnconditionalSuppressMessageAttribute.cs diff --git a/SharpHDiffPatch/System.CommandLine/System.Runtime.CompilerServices/IsExternalInit.cs b/SharpHPatchZ.Program/System.CommandLine/System.Runtime.CompilerServices/IsExternalInit.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/System.Runtime.CompilerServices/IsExternalInit.cs rename to SharpHPatchZ.Program/System.CommandLine/System.Runtime.CompilerServices/IsExternalInit.cs diff --git a/SharpHDiffPatch/System.CommandLine/Validate.cs b/SharpHPatchZ.Program/System.CommandLine/Validate.cs similarity index 100% rename from SharpHDiffPatch/System.CommandLine/Validate.cs rename to SharpHPatchZ.Program/System.CommandLine/Validate.cs diff --git a/SharpHPatchZ.Program/compiledAot/win-x64/Lib/win-x64/libzstd-bmi2.dll b/SharpHPatchZ.Program/compiledAot/win-x64/Lib/win-x64/libzstd-bmi2.dll new file mode 100644 index 0000000000000000000000000000000000000000..b9e9b109d9073c0cb6a58e996ed2c2c8e74fed70 GIT binary patch literal 1254833 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%0DpW%Tz5Gp2-WfatPt>n| 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%0AQ0^jW%fQp`N^-9y>>p+A^wd-S|CdNQaIkc8{Jv? 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

0GQuhAMkjqEhmd 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 &4zS44cPz3VCbtac| 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%0AU@~rKBgUj8x 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

SM*iXWE681+4`$+gQ3Hzdiy(E;Au-7GU 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�~7 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

QO%p5b!f7vW7Q1+9YT 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

0-T*JY+4!2&nQeeUtZQcZqPB|lhltSemn-7@ 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 bi2c+TaV68?{)jW&V921)@=1W00sQ|1AWeP@ literal 0 HcmV?d00001 diff --git a/SharpHPatchZ.Program/compiledAot/win-x64/Lib/win-x64/libzstd.dll b/SharpHPatchZ.Program/compiledAot/win-x64/Lib/win-x64/libzstd.dll new file mode 100644 index 0000000000000000000000000000000000000000..833f0d26887397cc38af7b7989b6c66281e8e31d GIT binary patch literal 661504 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 z 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

@yA-`9G-@(;YVFvp+A9@P8W_j&(d{xWi} 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 dccl{SM0F%ax8?I4nK=nM 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 ?3-Y6^DCm11pR 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 literal 0 HcmV?d00001 diff --git a/Test/Program.cs b/Test/Program.cs deleted file mode 100644 index fecc3a0..0000000 --- a/Test/Program.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Diagnostics; -using SharpHDiffPatch.Core; -using SharpHPatchZ; -using SharpHPatchZ.Header; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace Test; - -public class Program -{ - private static string TestPathInput = @"G:\UnityPlayer-SEA.dll"; - private static string TestPathOutput = @"G:\UnityPlayer-CN-Dotnet.dll"; - private static string TestPathPatch = @"G:\UnityPlayer.lzma2.diff"; - private static string TestPathPatchLzma = @"G:\UnityPlayer.lzma.diff"; - private static string TestPathPatchNoComp = @"G:\UnityPlayer.nocomp.diff"; - public static async Task Main() - { - Stopwatch sw = Stopwatch.StartNew(); - HDiffPatch hPatchOld = new(); - - long oldImplNewSize = HDiffPatch.GetHDiffNewSize(TestPathPatchNoComp); - long oldImplTotalWritten = 0; - - hPatchOld.Initialize(CreateStream); - hPatchOld.Patch(TestPathInput, TestPathOutput, true, (written) => - { - Interlocked.Add(ref oldImplTotalWritten, written); - Console.Write($"{oldImplTotalWritten} / {oldImplNewSize} {(int)(oldImplTotalWritten / (double)oldImplNewSize * 100)}%\r"); - }); - Console.WriteLine(); - Console.WriteLine($"Old Implementation completed in: {sw.ElapsedMilliseconds} ms"); - - ProgressCallback progressCallback = ProgressCallback.CreateFromManaged(WriteProgress); - PatchOptions options = PatchOptions.BigBuffer; - - sw.Restart(); - using (HDiffInfo info1 = await HPatch.CreateInstanceAsync(CreateStreamAsync)) - { - PatchResult result = await HPatch.PatchAsync(info1, CreateStreamAsync, TestPathInput, TestPathOutput, options, progressCallback: progressCallback); - } - - Console.WriteLine(); - Console.WriteLine($"New Implementation completed in: {sw.ElapsedMilliseconds} ms"); - } - - public static void WriteProgress(long totalProcessed, long totalSize, int written) - { - Console.Write($"{totalProcessed} / {totalSize} {(int)(totalProcessed / (double)totalSize * 100)}%\r"); - } - - public static Stream CreateStream() - { - FileStream stream = File.Open(TestPathPatch, FileMode.Open, FileAccess.Read, FileShare.Read); - return stream; - } - - public static (Stream, bool) CreateStream(long position) - { - FileStream stream = File.Open(TestPathPatch, FileMode.Open, FileAccess.Read, FileShare.Read); - stream.Position = position; - return (stream, false); - } - - public static ValueTask<(Stream, bool)> CreateStreamAsync(long position, CancellationToken token) - { - FileStream stream = File.Open(TestPathPatch, FileMode.Open, FileAccess.Read, FileShare.Read); - stream.Position = position; - return new ValueTask<(Stream, bool)>((stream, false)); - } -} \ No newline at end of file diff --git a/Test/Test.csproj b/Test/Test.csproj deleted file mode 100644 index 10824ef..0000000 --- a/Test/Test.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - Exe - net10.0;net472 - disable - enable - 14 - AnyCPU;x64;ARM64;x86 - - - - - - - - From d3c9186afa4620cdc2ea83620446d694656c3b01 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 00:41:37 +0700 Subject: [PATCH 26/72] Move assets --- README.md | 92 +----------------- .../Pack.cmd | 6 +- SharpHPatchZ/SharpHPatchZ.csproj | 6 +- .../icon.png | Bin 4 files changed, 13 insertions(+), 91 deletions(-) rename {SharpHDiffPatch.Core => SharpHPatchZ}/Pack.cmd (70%) rename {SharpHDiffPatch.Core => SharpHPatchZ}/icon.png (100%) diff --git a/README.md b/README.md index 6ed3f3a..7388f56 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![NuGet Downloads](https://img.shields.io/nuget/dt/SharpHDiffPatch.Core.svg?style=flat-square)](https://www.nuget.org/packages/SharpHDiffPatch.Core/) [![NuGet version](https://img.shields.io/nuget/v/SharpHDiffPatch.Core.svg?style=flat-square)](https://www.nuget.org/packages/SharpHDiffPatch.Core/) -**SharpHDiffPatch** is a patching library for HDiffPatch format written in C#, purposedly as a port of **HPatchZ** implementation (from [**HDiffPatch** by **housisong**](https://github.com/sisong/HDiffPatch)). This project doesn't support making diff file and only works for patching. +**SharpHPatchZ** (formerly SharpHDiffPatch) is a patching library for HDiffPatch format written in C#, purposedly as a port of **HPatchZ** implementation (from [**HDiffPatch** by **housisong**](https://github.com/sisong/HDiffPatch)). This project doesn't support making diff file and only works for patching. Supporting file and directory patching with these compression formats: - BZip2 @@ -11,94 +11,12 @@ Supporting file and directory patching with these compression formats: - LZMA and LZMA2 - No Compression. -Unfortunately, the **``HDIFFSF20``** (Single Compressed) format is still unsupported. But we are planning to add it in the future. +HDIFFSF20 format is planned to be supported in v3.0 branch on the General Public release. This project is used as a part submodule of our main project: [**Collapse Launcher**](https://github.com/CollapseLauncher). -# Usage Example -## Patching with a simple progress indicator -```CSharp -using SharpHDiffPatch.Core; -using SharpHDiffPatch.Core.Event; +# TODO: Usage Example -string oldPath = "C:\\test\\Music1.pck"; -string diffPath = "C:\\test\\Music1.pck.hdiff"; -string newPath = "C:\\test\\Music1.pck.new"; +## TODO: Patching Kuro directory diffs -// Initialize the patcher instance -HDiffPatch patcher = new HDiffPatch(); -// Set the verbosity of the logging -// Available Options: Quiet, Info (default), Verbose, Debug -HDiffPatch.LogVerbosity = Verbosity.Verbose; - -// Subscribe an event listener to logging -EventListener.LoggerEvent += EventListener_LoggerEvent; -// Subscribe an event listener to patching progress -EventListener.PatchEvent += EventListener_PatchEvent; - -// Initialize the diff file -patcher.Initialize(diffPath); -// Start the patching process -// This method has some arguments you can tweak as below: -// Patch(string inputPath, string outputPath, bool useBufferedPatch, -// CancellationToken token = default, bool useFullBuffer = false, -// bool useFastBuffer = false) -// -// Description: -// - inputPath -> Path of the old/source file/folder. -// - outputPath -> Path of the new/target file/folder. -// - useBufferedPatch -> Use array-based buffer for RLE Control and Code clips. -// - token -> Cancellation token. -// - useFullBuffer -> Buffer the RLE New Data to the MemoryStream. -// - useFastBuffer -> Buffer the RLE Control and Code clips to ArrayPool. -patcher.Patch(inputPath, outputPath, true, default, false, true); - -// Unsubscribe an event listener to logging -EventListener.LoggerEvent -= EventListener_LoggerEvent; -// Unsubscribe an event listener to patching progress -EventListener.PatchEvent -= EventListener_PatchEvent; - -// Implement logging listener -private void EventListener_LoggerEvent(object? sender, LoggerEvent e) -{ - string label = e.LogLevel switch - { - Verbosity.Info => $"[Info] ", - Verbosity.Verbose => $"[Verbose] ", - Verbosity.Debug => $"[Debug] ", - _ => "" - }; - Console.WriteLine($"{label}{e.Message}"); -} - -// Implement patching progress listener -private void EventListener_PatchEvent(object? sender, PatchEvent e) -{ - Console.Write($"Patching: {e.ProgressPercentage}% | {SummarizeSizeSimple(e.CurrentSizePatched)}/{SummarizeSizeSimple(e.TotalSizeToBePatched)} @{SummarizeSizeSimple(e.Speed)}/s \r"); -} -``` - -## Patching Kuro directory diffs - -Some Kuro Games directory diffs use an extended directory header containing old-reference sizes and new-reference hashes. Select the Kuro format after initializing the diff and before calling `Patch`: - -```CSharp -using SharpHDiffPatch.Core; - -HDiffPatch patcher = new HDiffPatch(); -patcher.Initialize(diffPath); -patcher.DirPatchFormat = DirectoryPatchFormat.Kuro; -patcher.Patch(inputPath, outputPath, true, default, false, true); -``` - -`DirectoryPatchFormat.Standard` remains the default. Use `Kuro` only for directory diffs produced with Kuro's extended header; the patcher also validates that each old reference file has the size recorded in that header. - -## Get the New file size from diff file. -```CSharp -using SharpHDiffPatch.Core; - -string diffPath = "C:\\test\\Music1.pck.hdiff"; -long newFileSize = HDiffPatch.GetHDiffNewSize(diffPath); - -Console.WriteLine($"The new file size is: {newFileSize} bytes"); -``` +## TODO: Get the New file size from diff file. \ No newline at end of file diff --git a/SharpHDiffPatch.Core/Pack.cmd b/SharpHPatchZ/Pack.cmd similarity index 70% rename from SharpHDiffPatch.Core/Pack.cmd rename to SharpHPatchZ/Pack.cmd index 1841033..8dc680c 100644 --- a/SharpHDiffPatch.Core/Pack.cmd +++ b/SharpHPatchZ/Pack.cmd @@ -1,10 +1,10 @@ @echo off if /i not exist "artifacts" mkdir "artifacts" dotnet restore || goto :Fail -dotnet clean -c Release SharpHDiffPatch.Core.csproj || goto :Fail +dotnet clean -c Release SharpHPatchZ.csproj || goto :Fail call :Clean -dotnet build -c Release SharpHDiffPatch.Core.csproj || goto :Fail -dotnet pack -c Release -o artifacts -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg SharpHDiffPatch.Core.csproj || goto :Fail +dotnet build -c Release SharpHPatchZ.csproj || goto :Fail +dotnet pack -c Release -o artifacts -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg SharpHPatchZ.csproj || goto :Fail goto :Success :Fail diff --git a/SharpHPatchZ/SharpHPatchZ.csproj b/SharpHPatchZ/SharpHPatchZ.csproj index ac8072c..85a0e19 100644 --- a/SharpHPatchZ/SharpHPatchZ.csproj +++ b/SharpHPatchZ/SharpHPatchZ.csproj @@ -8,7 +8,7 @@ MIT Copyright (c) 2025 Collapse Project Team, Kemal Setya Adhi (neon-nyan) neon-nyan - netstandard2.0;net6.0;net7.0;net8.0;net9.0;net10.0 + netstandard2.0;net6.0;net7.0;net8.0;net9.0;net10.0;net11.0 icon.png true README.md @@ -24,6 +24,10 @@ 14 + + + + diff --git a/SharpHDiffPatch.Core/icon.png b/SharpHPatchZ/icon.png similarity index 100% rename from SharpHDiffPatch.Core/icon.png rename to SharpHPatchZ/icon.png From 2fbd7d48720ad3f4d679f3f6a884fb1cdaae801a Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 04:56:56 +0700 Subject: [PATCH 27/72] Fix Zlib support --- SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs b/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs index 6ebb8ad..a4afe2c 100644 --- a/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs +++ b/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs @@ -69,6 +69,10 @@ internal static Stream Create(HDiffCompression type, if (type == HDiffCompression.Uncompressed || compressedSize == 0) return sourceStream; + // Advance one byte padding for Zlib / Libdeflate + if (type == HDiffCompression.Zlib) + sourceStream.ReadByte(); + return type switch { HDiffCompression.Zstd => CreateZstdStream(sourceStream, leaveOpen), From 4917b774dba386e1d4922e774146ce35b09149ec Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 04:57:16 +0700 Subject: [PATCH 28/72] Allow prefetched stream on any compressed streams --- SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs index 1497ca1..95f03f6 100644 --- a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs +++ b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs @@ -114,7 +114,7 @@ private static void EnableParallelDecompression(HDiffCompression compType, Stream[] streams, ChunkSizeInfo[] sizes) { - if (compType is not (HDiffCompression.Lzma or HDiffCompression.Lzma2)) + if (compType is HDiffCompression.Uncompressed) { return; } From aaca48c9490528bf331ad56e94d9ead38e4a8eb7 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 04:57:34 +0700 Subject: [PATCH 29/72] Add option to patch Kuro Games type HDiff --- SharpHPatchZ.Program/Program.cs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/SharpHPatchZ.Program/Program.cs b/SharpHPatchZ.Program/Program.cs index 92666ff..d569022 100644 --- a/SharpHPatchZ.Program/Program.cs +++ b/SharpHPatchZ.Program/Program.cs @@ -32,8 +32,10 @@ public static int Main(params string[] args) Argument inputPathArg, patchPathArg, outputPathArg; Option bufferModeOpt; Option threadsOpt; + Option isKuroTypeOpt; string inputPath, patchPath, outputPath; + bool isKuroType; int threads; Command.AddArgument(inputPathArg = new Argument("Input File", "Input path of the old file/folder to patch")); @@ -42,23 +44,30 @@ public static int Main(params string[] args) Command.AddOption(bufferModeOpt = new Option(["-b", "--buffer-mode"], () => BufferSize.BigBuffer, """ Determines the buffering mode for reading the clips of the patch files. - [BigBuffer (Default)] + [BigBuffer] Buffer Size = Up to 16 MB per chunks [MediumBuffer] Buffer Size = Up to 1 MB per chunks [SmallBuffer] - Buffer Size = Up to 1 MB per chunks + Buffer Size = Up to 128 KB per chunks + + [OptimizedForHDD] + Thread = 1, Buffer Size = Up to 16 MB per chunks + (Note: -p/--parallel-threads values will be ignored) """)); Command.AddOption(threadsOpt = new Option(["-p", "--parallel-threads"], () => Environment.ProcessorCount, "Determines how much parallel threads to be run.")); + Command.AddOption(isKuroTypeOpt = new Option(["-k", "--kuro"], () => false, + "Defining that the patch file is a Kuro Games HDiff format.")); Command.SetHandler((context) => { inputPath = context.ParseResult.GetValueForArgument(inputPathArg); patchPath = context.ParseResult.GetValueForArgument(patchPathArg); outputPath = context.ParseResult.GetValueForArgument(outputPathArg); + isKuroType = context.ParseResult.GetValueForOption(isKuroTypeOpt); BufferSize bufferSize = context.ParseResult.GetValueForOption(bufferModeOpt); PatchOptions options = bufferSize switch @@ -70,6 +79,11 @@ public static int Main(params string[] args) _ => PatchOptions.BigBuffer }; + InitializeOptions initializeOptions = new() + { + IsKuroGamesHDiff = isKuroType + }; + if (bufferSize != BufferSize.OptimizedForHDD) { threads = context.ParseResult.GetValueForOption(threadsOpt); @@ -83,8 +97,12 @@ public static int Main(params string[] args) { ProgressCallback progressCallback = ProgressCallback.CreateFromManaged(PatchProgress); - using HDiffInfo info = HPatch.CreateInstance(CreatePatchStream); - HPatch.Patch(info, CreatePatchStream, inputPath, outputPath, options, progressCallback); + using HDiffInfo info = HPatch.CreateInstance(CreatePatchStream, initializeOptions); + PatchResult result = HPatch.Patch(info, CreatePatchStream, inputPath, outputPath, options, progressCallback); + if (result.Exception != null) + { + throw result.Exception; + } Console.WriteLine(); Console.WriteLine($"Patch completed in: {Stopwatch.Elapsed:c}"); From 9d847214b62d2d3822fa0a45e6904802af54bf7e Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 06:19:53 +0700 Subject: [PATCH 30/72] Fix CreateUnmanagedIndexPairList reading --- SharpHPatchZ/Extension/StreamExtension.cs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/SharpHPatchZ/Extension/StreamExtension.cs b/SharpHPatchZ/Extension/StreamExtension.cs index da840fc..af11291 100644 --- a/SharpHPatchZ/Extension/StreamExtension.cs +++ b/SharpHPatchZ/Extension/StreamExtension.cs @@ -331,13 +331,25 @@ public async ValueTask CreateUnmanagedIndexPairListAsync(int count, Cancel return null; } - FileIndexPair* alloc = MemoryAlloc.Alloc(count); - long oldIndexNumber = -1; - long newIndexNumber = -1; + FileIndexPair* alloc = MemoryAlloc.Alloc(count); + Span allocSpan = new(alloc, count); + long oldIndexNumber = -1; + long newIndexNumber = -1; for (int i = 0; i < count; i++) { - alloc[i].OldIndex = (int)(oldIndexNumber += 1 + reader.ReadLong7Bit()); - alloc[i].NewIndex = (int)(newIndexNumber += 1 + reader.ReadLong7Bit()); + long incNewValue = reader.ReadLong7Bit(); + newIndexNumber += 1 + incNewValue; + + long incOldValue = reader.ReadLong7Bit(1); + int pSign = reader.PreviousByte; + + if (pSign >> (8 - 1) == 0) + oldIndexNumber += 1 + incOldValue; + else + oldIndexNumber = oldIndexNumber + 1 - incOldValue; + + allocSpan[i].OldIndex = (int)oldIndexNumber; + allocSpan[i].NewIndex = (int)newIndexNumber; } return alloc; From 6d6349e156ce61a6ce1470907d5b52436d40a959 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 08:02:34 +0700 Subject: [PATCH 31/72] Remove published files --- .gitignore | 1 + .../win-x64/Lib/win-x64/libzstd-bmi2.dll | Bin 1254833 -> 0 bytes .../win-x64/Lib/win-x64/libzstd.dll | Bin 661504 -> 0 bytes 3 files changed, 1 insertion(+) delete mode 100644 SharpHPatchZ.Program/compiledAot/win-x64/Lib/win-x64/libzstd-bmi2.dll delete mode 100644 SharpHPatchZ.Program/compiledAot/win-x64/Lib/win-x64/libzstd.dll diff --git a/.gitignore b/.gitignore index 588ce7f..a9aa3f4 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ mono_crash.* # Build results +*/compiledAot/* [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ diff --git a/SharpHPatchZ.Program/compiledAot/win-x64/Lib/win-x64/libzstd-bmi2.dll b/SharpHPatchZ.Program/compiledAot/win-x64/Lib/win-x64/libzstd-bmi2.dll deleted file mode 100644 index b9e9b109d9073c0cb6a58e996ed2c2c8e74fed70..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1254833 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%0DpW%Tz5Gp2-WfatPt>n| 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%0AQ0^jW%fQp`N^-9y>>p+A^wd-S|CdNQaIkc8{Jv? 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

0GQuhAMkjqEhmd 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 &4zS44cPz3VCbtac| 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%0AU@~rKBgUj8x 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

QO%p5b!f7vW7Q1+9YT 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

0-T*JY+4!2&nQeeUtZQcZqPB|lhltSemn-7@ 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 bi2c+TaV68?{)jW&V921)@=1W00sQ|1AWeP@ diff --git a/SharpHPatchZ.Program/compiledAot/win-x64/Lib/win-x64/libzstd.dll b/SharpHPatchZ.Program/compiledAot/win-x64/Lib/win-x64/libzstd.dll deleted file mode 100644 index 833f0d26887397cc38af7b7989b6c66281e8e31d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 661504 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 z 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

@yA-`9G-@(;YVFvp+A9@P8W_j&(d{xWi} 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 dccl{SM0F%ax8?I4nK=nM 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 ?3-Y6^DCm11pR z`ul3j2x3utmXwBu1y6qb@@ElAmjk!;LZTSsQ~mud`SpwVx1jF()|8{o+rTX&RbB*& z;RqCtIH49$D<<)vQG6&_7OuJ$X@YyR0psAmu2iuz=7jGvobR!QdzWDW|+1v zPal`BHB0Q;0bK4C5(uLQT|12ic^{UoLyO@4)9p&9D|C?WRh)c7 zRYc6|5+ww7;{?$(Ebo<;$rSACg1eX!V~D5S_ERT*syo zXLI?Q+GIrLk;UTKk02i6hrg}%0`b>lVMc!kNfktmEy^zyc@esSsoQFL`F>WsIexd6 zZbR(WJukUZcaBsYqCddRD;CRK0pGIT238ck2qmGnN`&nR;|RDE7QqyLR#KYYF0zBS z6hYa(PNcbmxW_5!dshU`aI0<&rpBxKx^zr${Qs!cM2rrOA2z>FSKdH+v@<^i1dE02 z&D5>Ba0fr63qs;n#}kyC!;SH$FF*>9lf6{3i*iBf1L0HLW&}ig0EiZt*59$HjDXmp zt}rp&=R6dB)f+wFjrO8={7{d+>Pd~$-``YFH-wF_p0mfhgWTjZGRZyB0|blo!X1?x zJrXt9ykYA@QK6!Hn^it1)cRVX1O;ThCd2mf@CZiYyU~i#Z-evVn ziFwQ9?F<2n%y4XiPxyO4@R`}Tg-nilhvG3o}6G zjybPOQyl5z3h+MN`3_>3^Svk~`masda*mYFzt-w(Ja7!;E!1g+xoO%9%9t^Q&B z3tXn&^J?_Si20?|{_lDpimXkBrwbmNdA6_1_jGk1u{LSH-DFQDQbk;gbfyB)BSrJa zP}GrZxf?Ko&GUf`JLUEqNpCtKQ}IM=xvI1Eu-EXvxL~yI-=S+$cK~#Rtq&YXxIgB& zvWO*iCBH=uO%XZ6af*>-;53yCKrbJ_8YG=*`mlUFrWn(gA$Oj(0#hfx_5l(t=0r=c9@C1p*0wcF3^uL)MPufgeI9 ztOf=Mks-j>iSdH6=djVw(3g?3z|1Xs*7dYT9ZPl2;?n%1LpT?CB!qvWrJN zZL*Og-y+0i@C!D>TEp4P>nEtQqFnh=lW_O(g(n%Y>)G)L7>+0Ik79Q*E)O{25~Ih5 z5tKqZrL>*dZ8i0*@S9BNF;E@MY(iCsu$u}pJDF{q#NRQiCj8#8$~Oc#xY}|sRm6}Z z!KhHxOUO6gpAe`iKWL3y%I_Zpt&*id%&{+`=b|1p_6?2xMTcx=KF87)Q{^@U=UH!*>f4VUw6;I#r5T>e=mUaa&b zOppWgnN|mwlz3JQ*b0TK4iPWz@r9q6fK*iQ`s+JP*dx@ zP}NXj#FO1+hK|UzFCGB}M>xmo;fu|x!I3Jz?jKJ1Q?{Dg)VC*E6E=W`MRos#*h0** z+9DQ~V_mv7WtZG3L%CHE1TybpeY}?h+}|CxUX~kMs{ElUIQ;Mplone!NJ%t^rDu`R ztm;OD`*(eO$qyG6S?7eU{bVCGf?uX2s%K$A_?%8)zM@Q%W}#1)(;?2lKeW9=!c|Gk zleqg%Bz!Uc8i`5PNbpGY%(~(Z$)I(4Ea(S39)!A0$SL)RG6Bvu4&^3IS-kKhMcR_Z zA#Lg*jD1KB$+Rhb;i{{EeFP57y60~9wgL4n6sU8F#E zdO+DD|3iiap_%u2+LRqkI*M!!jvvW1;|L%>C~_0Gxg0+ZGAPWj%(PSM8DEF_skt$-XBw#x9mknhOMOqe^aZ#S%-jI#KmP*rDGe1Z?4iheQTgHa4q8t9T@0RM>y^A19f23p;e#wn!(g@hC* z+6alej`|>|O%d=Pyu7Ld6Edf?ZDC)BRjSbbl6;~2@O)Egv*U{rvdxX*%=l2K57W<5 zc^o&{F1gnP0Ao(@Lijp-vrNB*rAuP>HE+T(9!PJ>Uy_j`!#)S}O-!PkongAePlW?K zi!__2;29As74{v3+DAjJ9|BLmi;ajF{|Vuf3gndg{nspD0aG3<`|ZAH#{5agTk*cIuZYK zH5V~|xNK)>*!C`E9uI{#oD9boy83t5d9aT$IckRd&(#utMU)k`Iz3}rwXb%fa~`T1 zin|sK^0^I?qNG7!o3Uch2OcqbIho57Blu@!O^dM@WeRCCK|73*jBldMOKv=M^ zTU#W;N8!z37pH4pg>)LW{;QPt%FOl0Blrb4rvy595Hg==04wG84K|LD533_|rZSHR zZXiz8v-PKCXe0xYREK!41;lI4E`0Lm1$o?rh%o;-{vgV08A*O*W3+8V>dLGLKe8p- zR+>5wHM67a#L-15bm3B@EJ_VVttr1n3^j#6V3ifLjsX|M{tN50=m)sODmO9NMoC2$9M#J{8VvXF)QYG<~D2>AEe z(hZnPlduQ)T~7XOHJqthL%vNJ%ddq~=r68ioagm4H=>FIODtTt3i21;&#A3&jXbU; zQ8vk}!bgMF-{6IXt6W;!S?MC5RBwze^o|o;`*A18=eG-uX`#{VvI1F&PA+|}x zMc`1jUyz0=vGCd0;+>ROQ;;_~R(JNQDX}}wUV{~ojO=LntA>^XnHRww9*OXIFGBhZtRDj^rd(qZ^ms^bL!Ev)5i7n|1c15$mALt{Iv0;4PW+;Ak~4 zGENBloJu&5G1so4aZUr&+)C~SGFJ)Zvr20hUPu}z@?WNDYThM(MOvUQ_wYzz#~#L+ zujzD%aY9|$hO23rypxQMDc53%K*lX(WbwGPnds7H1lSuW>4c`d3f_&aA%F#!!(=-AC7R>VD2;i!njCEYg=-9p=>ZRBZdl9> z>!!lBYE`SXo4k*roL-F?m;`FzC&%WWegBl$w6oV_M&-)PsGRN$!{&!F!%)&F^T2Rk z|Cf60p4UrSWInKgm@1(~z+qVc$SF+kpkOWyNN7^LHAyiF}?ma@<|GiOd9 z^e;)1C3M~SCzN*rrRQY|94HQ3HyP68&3tl}kAz}S)0b(Sq1Chut;z>-I^R1rxu-_CiTW4qMHkBmm_kWX6?Ri?LYO{1p_^8_Rm{658+-dT5K?h_VasCIi;53)`EGAWowilHE zdVQKjxDjwIdR5;1O9a4Y^Qp=U`Pcvu2I-m}D~a+xyyxd-<-YMXWq|Cl8eRtz(Q7hGIg>$*HVQ~DY9W%AmRee-BJ5xiIhrT zeBIK6dCnHg{o1vxlJ=ba5fcUWR^-qyLIh9*h$G2^a>p(Oh-53Knq7-Z3?I?&D!j=@ zX?f5ZDi%A<%lNJ5Usv*RgQ$d@*6db`S*x?)4*$D2q#b?=CY(-2GXwbz?rqAXc!3n3 zYEZvSDY{irjS{p`z^CU;}v<~|KyDm-c7mz)yM&n*$=PZtpq)~arT{ff8{ zW`~f{lC~6ry{ptLPG)xDU+yo+OE&OY&FX2$UZ08p6UZ4sli^E;uo((*E4a3DF=G?9 zZ(yB0U;E9>e2r9{8L}&maty>>>7k&NZ}`0T-u>C^e27(YR^zmrvUC|)R~R^xo;YLsYrsXTExlbF6}|!E3R-XL@3-gIUlFvw z1AoPn0j;p@MNPIvOqv+9V7^G`%0;1SB;STFs~BJM&;lYsjtIhptSvbn31=yJKWObR z1j}Ge?o6Zw$io}qpsMCP>vXpJCsc;aF_pZ!^>{TM`|8dWOXQR7ykZU z*-0`RZ}Lh&Q5CsFQDO@XwoVV*li&xiFGO?>;~HI&qvZ=gQHE8{S&fA*qRALZlq;|= zeOop(;TlvhCj^?{z-?jwVXf&GqVTRNQ0)kgFOSyUgbZ6wYh2zo`b6I5NUnahmpH7= zkz7Z!OMHZ}ImW&YV=GylDpZzvuGGJqT?~9!PHkf4&2a%|EoFs;k}WFtB0A@Th<{7% z=Va59{jJMQF4pkFuz$>^2O5y`K-~0Y&jZ>D;_yRNw0E4i!oE(&w(DivwI5UBzR zJBV$s>YvNe{~3XjaS`Ul^#YA;2-gei2nK1^i^;XTrz9zc#wr4;!<}?$jS!G-D>{h_ z@Ovt|lQ(%6Icb=-^4Ds#4(Bfn{VzsKRTd)1Ql`G-bsQ&E4~ZfUn{lcCF&#^mk)mm22jotMClQX-H!?(w4MVhmv0=b& zdz6t1#p*eJsg)u#)!!ilLBvp4L?9G9O-HXB^Oi4~A=78!6>e*oI`GCw)w?cPGgC*+ z6k3)ubCVY$m~+wTi34L;y~z?KvokeRu>-~BPV@PNYm(EUgW`wBFX@G6g{vT-2q?IH z9Vca`3f-0hWORzLfe+OacEutLVsCJ(DZN2RW^)^u{mwjdqy<@GcH!tBvX~sn;h@YF zHBplP$z5*ZSfs5uTg?AeA*?35@W?85`sMD|guXnHFnVQvAP1uj zMnWDCgukSoj}wG1V3U^QA14O`W2u9pg0a+~I{Znf&L*P-xARpb8(VNWQQEhGSEIBS z+-^W=e`6+0cNRZ&v}kfS9O&MnaW1-tFc=YF_g&m(E}}o!NoNkD7jb6FoJYkyYy_%u ztKOr6-kd@fK8aFYed2(QKE2f{S>ho+9%Hor`svfB%dZK2Nxg4x z#Qrxfo0sP?t%-9zU2yhsLH{7lCYS_#n5ZJq^pEO5z@ce23q^tvu!7_aRXNqZc*THx zG8QYAV`3nP-T2+;FMc`>*IkJ%2a!ieqFRL+yw{URX{PTOs%klpraYSQ5*l?m zW-XCxj;IGe)Po%L62oqvs4ky=RJ&akgknrT4;mD%EU| zv3_9{4a?|HZyEr{8D-%(BUDTR1&M>?HcBtV?){w&%njIHLMa{N5_|ewVvX|u0TrU2 zzl5I-1o)58QvsX=8znD44}ntW*Z+yoJnQo?=0J;`FrFs9WR;_(W^kunm5$hxSRs8u zdnz*Mws~`=*dw39o~~-Qp5A6{sz`HVS}2;xpC?u)!^io%79f9bn->x!+uGFHTa?}j zstedy+)2>k6~S0B`BaAU+zg9GkcyWondu~x1b4qeL3iJaG>)gO;d=|?F2hymV+@5I zDO#oMc|fIu5FjW79iO zWEOX$%Dk5&BD>bTtRw5FE_A_vaaMUH9-&+_KKya<7M`JRJSHun=-EP}gfyor`~>BB z$5Y;T*+eO?E2li$`z5kkM=b)(Z})XjN@Wh7tuOwNC7-9+qAr7+8|6t6^g~Dz^nED) zFO?>_FzaAN$%-uA!s>%?zO8cH41rfyZ8FA}JRY{akF&nC)vY8C(B-H^z#9iTA-+O@ zCDX9*`2IdwBorrc%@F{lCoGa)s>NUx{bcm*{Q7^#K2>!Nl~1Oh7_P6J!U_vlWsHv? zv~EYzocmkmOZKYn>Q&JR_vFoI$LBQD$U9zo?=jPz04Ys0k4yhRTax+n2J6uYBk~p; zfHxu@$BYr)=4}hFw7mC_=pJ%s=UZQw%ALowWpDM~6Qm$is0{1te2^!KyF12hIYd(o zSgrF+1PU!~ zKPuC=3ahEVAE%!n#ENch<}}0Y1tgRei$zUUB6D8nrUgtnWs+4P{kEIMdzcPEUkP;$ zX9;&>R=O0===r097L%~m@O4vGkdO!16-Y&v*D}-F1f#kREm_Bcw{@_;^sb=)&x;&;n?Nn03a|~(@JV9-XOa&jSkr@LMYj&iX776 zG|fj@5CQ2=xM~Q^rpX~;Z2cV4fteietGFFVV+BEmP#;cM8o{llwi^HZGgyXD5#!j{ z5Ke6iD;eY}Y@u{+_zeaSQt}OzX_5?E)K_#k=VL3KUH` z@M$q|XG&HuH&-af8+_Xpmbt5TwJfuMQc$LM2+^EI$He|t_M;-lMwAT;nS}U2Ve9g8 zZQV^5r43{wZJlw^F}B@%{TOnTJj`NV;X15L?7&iqwktI_*7-L_s?c-vNLLK*u@GKB zUq;o5>rz;H(pgJSdiq|Ho}9rZ8g}f(X*8mv|5Tww9#FvwFr2OV1=}Q- zSPTrJ7zT~Fo}nuh$izf!}4Bjkp>(`2Bq;Yn1tai>Gx z`8;w3(${#95Q6OKQwaB17iy0lIyFx=i@dS%_UPaF?d5ma+R+~E=RtN|x-8&Jw1@|^ zjAktQ7rw-zZ}4xTW42t?dML#`xm)8(2H2i>?paB=E3sMqr41sbfLM=F_PF$_Ow{IB zwh-_N3p_+~dE?q==0?f4A1$9F>LH@#%ZjxMfAIN?N_URZ6aCjA{zNb$Msf&n#*%$! zHr`A!+B4LaPtR~ZGHrVfzY>$5ARt`TuIVM>DJ+uxAR^WXn6qIy(v7pjGZD|0(Ad2C(;~iB zXTP(IQap?{6`5lT>fSZAr-^)-^bqqzaNy{X!L`pQ_LJqe>}C()f#rQD+b{$<#t73B6gG&9~0Y_qlAoN1QjLzFw+$y(UwID zH}?IU{amg>f6W35ByusPaj(>VhnVi`@N0utI{rZgoDDo}916>)iO6mm*1JSg7&*$g za$nuq2Eyz#tcon`n+^~ci0{ND+QU-bCnZCNbgPa73Xp3MhW0z&j1!Uu{GAPj7M4nz z4NH++$LEjI$PlzAU}J(6)?P(N8JFbs%y>{z8;CM9Lut0KN?JrbJAemjPCWd(e1c7t zT$(x~J6@`?oc`+R&CbmGRm8eXCLjC7rPs~BNe!#sh1 z0;>%Bt7y@;GPUoc9(Q(+P_w&{gb0J5IKKlmMU)TgNDa+YQR9L0HA7A!nEV)Z#F4?; zJ@Mv_`X9TLg%a49Y5l0Dv%*?k_yk!z-4(Irh3h4ywY=~#dDAH=VFtWeT_{QvCk-{KG;6bI z9(B_^l1;PLO|vGO<`Fl|1KBjG-cDYxM>=*X`0lVX@&EhiW=2pxNx4+Yl+%P*qg#S=j%N8>m286ojgJ36K@i$V}g)AH+IaXFc`%NM=RHLBc(%oW|-hAfK+BeCwJ+?!n7A>UiMG&!!gA2)a( zN)$dr`Sz)A{aRFK9o%X}G)lsU3!8%*TrRP5zi?NEW$gty7OrT*x)cp0!l=|O_mCcv zBfyLbt4TFXk9|RpeGk1SNR9u`T68ImRxJA(`|?q;Qz)56m|MwW@bY?`Y5zm$8RPj@|SH~J1#1m6OExw2%YNCDl z`CLuZFe>QZ$-RD@>xdYFc#b4#5elcF$iG!v`ZM|nzc>6lYW4=LmnD5o(7(U#He^$k zewyW#3|5I{dxw#&W(WeGw&Z>Cg>0`Dq5DKX3t2_x_@eqtQGkry9pN^{kzpU`1@eOg zUdqEyxtOR8=#_C8u6aXzn46|CP1!cMZ>?s9XudwdRh6sXFq+fz177X76-8_)eSg~T-F&otV=UKQ?*?W#q$lDFpWdJ#{12M6gfIarYwEvK{^j%(vet1bz zz98P0ilYd&q0s|q1>e_hc+>E`quubAjVyt@RdytwvE#siIcHIIg?1P1w|3z9a9y=_ z*G>1xWDLpcX;ClG0PPA@Yv1hVn_=++z0YuYu~+51hc{e5e#c8voXR9=JgNxEL@|aG zQ&6oPaLqCZ*)tMDuRrBcui-WEV)gcsc1BBUKhEZ@K@j2Eccs}_E>M`f!cV` zwS}(+t?d{@-ylL&+}9C3Tu^gq$gV8F;6!fkIX?an3p!BC!&64cwKHHZKARk9;Ejup_zs;}4joJWxK4{PJQ3=^vzwyu_dR zAmEP47p{Yrk24J*v{5|k(GLr1u5d)`N4PPUJp+9Hrk}FM*r#s)8DjAMf6MGCP0shk z-=C6n64Q1(See$;f-+csnp)EW(F+U6#8s915U_rxF+T^LZ(rHtvQzwnNn#MS{Whbu5Ht8Lq0NdO*Xi|3k zKsS6B?{|xv`;O`&XTc9uiR#w1KRVecwTx2PN|D_Y|ESJ%^rvpA#grNxi&E{=OkLZOHX9aMqsfj0v)ix6?0-@Oeb2O61{L!T207;aPizz@98?|&${;O1LIU=gX)ev#A^LZa4T%wXrPxB8 zw#qX8c+@ipVW}wQ{iC`N?{G~D*Dslm+>=n_UUd9frYU2|pge_XWult(?aYA^=R;yX z)ZnUv%yj(+Bw@X%`EH;3FnP!=XS|EEId_vprbh)iQ-d>!#bbX7d%iaMY2{YM?(*gS zN3cpoJc~nqncFkO0;F+5eqJ5$d3(}F@<~<+65sOjH6#%!C4hJX&m05V0nRG4e;ktu z3X>}#4ADb``A1zUP_GL4EB!UBnQVEh%Nr>~8-+plBg(57(*QC#&c+JQ+L@5}W!7F< zJtB}TwtcS%-*ZESns_d(4yFK=l)1aT}4WyNQ!DwzZ2I|2;7bdL$uMli@EMJ z-RXa+_AFly2tEEQxRP9s4M@p#;+;TS3*P&so(AIFn*w^;8^qXWsXI`~T4}}d@)2}G zAAhp)anLFT>2{@X{Of|_XRRorH7jbrhIyPPDg9VTFzv4Y;`q^^11 zEgqRgnj`6OHjB+#%8iqOd_6YE;7aQ|m?hehU(*>7K zvBBA+$EinQvuK+J&eUJ>spoCi?18?S|dj4ci9vfk;~KY2Wd-VnA1*V*y&N{i#d6 z;713sQ)~9~qm%u$)!l6W)FCwL#5u$u%n*!6WHsM5*i4|rq5}>6%Qj>v%P&kLnQLTY~^u`vqdru$A_YYtHjjaZhlOr zFzje1H7OOO@Ty84;`}Y+Ka`ji0scdY zSuxYJf7GawR~#Y>Z%X-3rF!o-T(d$tnrJ`9o{pZAZvnpLszIfsz)Y@5sHhyfo1b&E zVU1E?V&cQ<;u#Z}WleKjTysUf6mu&EV7nIV0+^L)%%yf=&FIIsFp>B05iVGAtJBvj z7wFP)*1Qq0m^r11cNli9^rZi+6{`W` zTzsSP8=v4+Y~yqM3+w#DX8vl!Y?H$#kIggqtBqzI@_-#(!v5BgG&NLDmO6PYg;au{ zX`^X?)O{0Q+_aaimzyZ|vi-25O_OCz;s6`Dy3c0C5MD?W=w|f;RzIH~U{ZOEwD=qR zmUcqN!zzZ82vq4{~qe)yI2N*xynXdsZHH#-XCh` zMh@njzh97aZBl@*hmk#~IFRhawU}`x_TQXgd`-@W#NT1I zNs-k|>mHe?YI0fD8}f#0H!;!DCU#+&r!AYq*RU07QBc0fBpy_YY?(Ad{*Dr+RF+si z*=dTlOk`grFg`3(!nW2kHA2?4fFpXTxCWlCf_sr@Db0&<)P?inAn|-`4HOFn(Jicb1SR1iM3nJo>@!6^DxrYnXxgf(m348di065qf#yKequ?1r zS$#vXkVBRTH^RtIXVE8)#$-~f+W@tt|A!AUgECUwtx}zRYJ$3?X=`rGwBu^GvFo@U zN#VS*2?~FcO;K2zvlCu=*AawHhsTQWDGXS2jl!iR=7I2TwPv=nEY0XsEy6vt=8f_+ z{-u2AW-JeY*2j6F}H+~$qE4-+XI6QaAb90wn7$_2d>&Feu)IvB>~2@{yl_Kq_= z9qbSy%gLcJ{zo|vi%o-~&nR}2Uw$_`4I9cFCiVz2mNV=3u4OpwQGK9=0^=#?7y3uqK$+Xuz@bc6m2&EUye8i&S|WXBYgb|qq?9kuGRf3?d714# zP*Q-sx`}U~>_r|d>g@om0_O9M;b~q&S%zIQG??2*)iT)>FDK6**$8Mx+cD{z zzW!r7w~Y?XQymInGE@H!m}6$7oIxwQfbtl$fZGfEkc`(qzVnfe{2jYarz4}Bj{NK% zIdP5MN5(9P10mm-^TT_={xo-+PcA#+_V=J0hKNUkh7zt_npz%*QXjyd%Kwk*UuPMc;JJ`EW|p7(_# zM|^K#$uC!$Z#aiuCq{fbTSI0s+=o?+L)`7ZRI_9`_P@!0<1NL7Wlfo$J}E2gdplE> zOudljSYq3^C{Cn<3uv~pw#;mC^PS@El;TG4))Z6WW*OtKFJXH6u?wbQ;%FdS#|D`U ziFqF_uN- zAg^MG#vm~r$V;w}BHOvTQti&jIt#L;{LU%m>zMB*BfLd(!~T*_Y7s=WB{Q-qmq|*s zKWxF+Gtn_E)A+lb4~hM2scMu|#b$E`7x|f1bPk&n5?geh`YY0-U^gYQ)6GHrOn0R? z6sub<=|e43o=o!Kn= zA&K~#TTSH&eu~8cTdK@w>=~8ZiqV4gc@eXa3>JDpMhs#&cWX<&CTSeAJZ(u>71PZk zpDFepA@=pXm50;T6wF!T#9=(&T%X^Vr~VIvl~7-=*?RDtZ*9tJOfT|vENC?5C&RYD3kUuV$z^!ug(PfiF0dc#!jkr1MvibW%3yn?F}Y zC2l4u9X%v1M=r-$4`ni_i84nqZ~zm@^N;;>m3cWzKpt%Dn4yVB@l%k=KKCxuo?T?x z-b=arxq(ofADF%mS)WBH80}yYFXslIkr`$B`cm8$PwecA@uLIK7)#vR#Aojn6&BG% zrg8BWh}x;@c`K(EhS>ZO=TqBzh3VNMHY@QzGQ9+zn<=ejpvP77ckyN!%A9lkjaaAr z^ZUuL$N`djL}6HJ2qT17KrX|E-g*b0+4AOnK@OZ=&Dfhu`i(!MDn=;RIkit-_Q3Q96!2XjxF>3d5C z!t=KHX|acoaYn$on93Q13vo(NgYa!)kLc}#WTKhekZjK@O58q$&}FQd|M_%dXs*y> zQ}AK?py3oydmKwJ1$sWQ7+p8-Os(P-?)3`WH%YMT8^?sK+i7NPAm(N(skGe!CD*s{fpZHWq8xOF=2%BIkPF;bI%L_9s;5-q-sT(uM%t)mC~w z53(=l&*YOU%xKDCNI*yG7-#iR9mh5xWhXA#*f(X6Il#&O5xb&&lH4(sP7M2-Ol!Ce zd86}+IEct{w9egd1~2?CViz+>Li&))NKAiSP9W?qM?E#SIcxlU#Q-}D6ma0L%(wqo z&V0LxXq?XX0_S_823`Ps;@*Dv2Bc&{OD?iJBw0phv+Qy{Caxljy8FZ!UsrBuOJ~ro zu>EhtH;kfXjsTpI7j%jys`Ljsik<%G2e1lOv|+u)eb0wY|GV0<*FA_GC1Xvw1olOK zW6@}OYOZqHcncMZNl$>bTtr)>Wnz8kEvMH?Tc5D7sdW-x=CNz#7Ste(@w#1lh(R-Y4iK~S@ zVzuw@t6Ap^uG3r>b^mR)i2o8ca43>#+P!Z6LFAY2aMmqJ#}&EgNWjk!YD>B~MarqH zgO-ZVg(*gkGi9R9eNBz-mm8%IOSstvLhNB*z;oz`7X2%48Tf)4_qOTL*;ZUiD-3I= z+*~{>+m@kjTfQg!#`dl=J@K$V!KGbNgmV*VsP)a^iB~a&f!@$#9K~QDoG8ndvDNvO z_!4D6fv~rM4T9a9Fy3yIT>~cOQu3D4HurZsVN@ZwEe1Ji(Q`pbk)Wfo= zS7uW;ODDUsNgLdxe`QS?7RSjw%E+P|Ba2ecX!b$>*10EPU=VFB!F9amjnq&;T(kkc zJ67Um{&abq9>h);MvZ@C!<9MbPXuF0$Rb+lo&=$abytz3dVg%_=2))_o`-a0acD znB0h6&kJH@y@ODe_-b(~U)=BN)vGF7j8&k$C6X9iM;!F&>Hhg_Sr| z;i2^8{kNXX-{C8Eo;y(pGm3{1d-t9D69G2I$jO@*BWJAteO}_=0IhCVt!SmfKPX6B zH1P1kIwmA9Mo+3?dkFRIowPE?%Fdgkg3~*8qmGMMR=r_?^#6T)73e1OV z8wF|6->snrZDU-b;ksacunPx8A085+A}OMj%*P1XABqh@1S*_6J8YkN`uQUBG%ab` zKZq0ArgX2iu3`|LCSy#_zp)`a74kGH`{d=REc@i)X+-u3&0cS5_Q~;A@wA2p+E`!Y z&hR$csq_u1u^{qREAbS39ePYJvP(K>wQ6(qstGjf^ZZxFf2Z)Dm;c^>c~G7ROo3cm z>cwxADc)arb$<4EQpy`vK+sBJ(W5JH8^=%GI->Xdb!;4f1*}RemaT))R*&AD#Is1Z zuTP8P3ChLlp1%c2y0||LJsUWN$9FR#$usj6UoBB@{v>aTcq6WGv#AaTr)nd1aXI_S zs%z|#rx@CkBYo96!L8~~3bssJJt(L>xi{UJI%({-YQz7Eu7$A)IIO2Pk?W?Br3TUd zJH$3jm1SR@&h?MFT6=cd&3SUm7~$&;>T0>EX^@y2T@c5nt9VuB=iK-46v?meRVG&Z z8#*`&4#{wqTk*N9yC%XU9Zcu35C|a4gv(2{Cx`1WLp-VixKHL+$MV<9G}1P9YC*zr zuG?`@M|IDu)w*ww-eMlD)?<~2#bUC4Bki7FUSN64#Vc2gxt5m;+2yS9+}HTKc(aU4 z4)e;H?+CbMO4J>=m1u07z{4U4%}^|BFA*yu63XBZHVO8GVHin*dfz34wuXp(+&HY? zqpxYvw!-KKTEpqW8OG698JB@N+w|C3h(=E_P7Kr?*gf~WhUs5x(yOnRWv<(|=L5B9 zE80mBw93mJye{bfySD7-ylPHsO`Vd?I##VO=IC92amc>mgJ}DRuzz=LY0#RCdJ%Zh z>dU0S$1PF`EC$)BjJ?LYH(nzcvKhW)K($$`{;c3&J?9(sUR_((wWvBM+RxBn@(y@)M z)-S-rrz3S*b$S=S4{Oi9U~Q^q2Kd{mweSno=}zt0P26la#S}@s z%6+9^Hm$;IWddUiFjyLMKT(%OKkVOx600@!6zNrx>?K<=i)H??^=6K0x!frFMnDjd zHH=u;R`?ttA_!(k6gu4s=CvkDtA%5W1t<~wWCfNbJ`_v`ctBhB_+TZljdFtW!7(Cv z2%GeyEPCK7gWin``VL4h5lsJbm28P)bbEMyn619&Ro!|n)O|42b1-@&Fn2N+*8nK= z*PM({)SB>cb#(OA!E#N{vAWM2ykm;-nqe?~gz?;2JBY13=-aAZ^kYA}MJAoE%d{@F zI!)_ksh?5md5v1k?v&Y+(xZn1b3>VGu(`s$Sk=Sj0E1JPNJT!bJf))6gB~h$tHEp@ zULw!^w)c6d#Ndl{DgMSEX5>*RT3fbAxQW|~&m3Po=~ESQ4^`87ESYRAVttUQ2n_56 zeLY|EGS%I_3FP8Z0A#FAwB`g~B4UmF3O^=V(|(N1_`J0V_wcK2Z;@cZSJ9EH;DFnp zEnd?QR(o<2bFuYcsop|^rag!w+si6TkXyOkEMy}wgi`;e$YOf-sw`j4|DRMt22xX* z%=(tE!dr6cx%!jpAsbbZM_sC#e3Fxsi#I#;ycA+&=y~FBjh5lMFiXfR6~U;o!v*~y zo(vU!H%$j18=2~ds=}Lg^Ek;eevBFFHps@*?b0n~&lVK6tp`Ui*GjFJwhfZD)m<61j0fFz!T#XNpWH5pNYj#Xg@_b_ z=I3yr{>%sg4NgTbSYJxGU%4y1ktQb#*hL^mGNINp5vpZ9U!nv&SV(gv zL6}AvK9&;}^^k#e%{o4y)-et@h}pQ3sfE0ag&bS0WNpv1@=*h8dJ=1T@4%Yg>#pfn z+%>&DcTMk-HQi?Twx~6|H+M~sC1#DapQ=N$ptl+9-6GeAx>GFjkh`{#Xr1Z?24t^V z+ZUS<_#!n~whyfBUA2WE&OX))irl3>mz>-#_n%3BqPQhA}1h32% zKCq;B)pEl{kF%uRTGWajn_1Cs(t`*)cl0m(aF-g4CbOcuKC+_SrKWhMT5YG1>p}Ry zem573+R5cCYKX<6CKq&qNMUzfU!PgmpRTg&3y!NzSO~kE;vRinRK;)VQH)2p2&}WK6i??!&pQ7XO)IV{oFZ*3 zR&6YdV1W1)+Lu}DB5hFrZkcEDSj!XovlhcUDo?46j^@~jx(9{o;nrcAQBMx zN`wc6v1~NqVruh@p4^3oy^T)+C9VZh3M!}&FtXTbV|E%Jz-@==Svt2;&b8JHBJ}OleO=ndO?>2E(j3xz{-%(tBlQ;%;NuUt8hVYE z%l%>qdmF$siOJMZ|onIg8yDIWmm@#A}1YvB{;e zuVZHU~CeHB4)?va!6aRQ3KRP5wMtI$u%_^Ul{0AA~Jx9ab zW3vnZ6*#NFK)>DhlC@oUR`k`Y6eB~*P2j+U|EvL|&?a7MEydR4B9hByExhiyB>9ry zn*5KZz-8X+ltPkV%fy0@Cdt<06yiv3FEg_Y32PMX4>Sx_inru)+AE|oT~cw-%!K~|tODVO3l_Z=BDSL}lg}6asDhv5Ut`-FJrP@J6 z$Or-%$%_tz1)0)$hA%Efs-oRuNsCoM7%$}S8rBZI??n+|zzwg2KI(ktkZ4;j6$zN> zkWmDy^I$T^>qCyG%W*jsU5Z6i1f+!r5T!mO5q$*v6b+cDh(w&q4M+b;=QI0`@7Fe+YlpJgu!~I~ zxT|x%)NhZ&m7}jlT!dCrSlp}$LA??B0s#P_#>M?0mm{#F8 zxY>x^iARR8FB|JG! z2O8I+UsdmsOkkka&3hFyeYJ02^tG!{yz~(GBT@;=G%E9hEF7x~?pcX@eoMZ%{lp?{ zdBUd6o>$$}VF_cf&U;;ukR;dTw~%W)^O8Wuq?T{ib0;LPB;~a0NcSgkpJ3sx^G;K^ zky{0R65MEZLZ*O9M$Vh2sXDkD=g#$R9RZ=UKvKf;q*YLgc2bLh$<;cqp?d(cW|hy& z_JJwl9FPYxz(S=#=uU;Qc3N2@}7A^g&=5vQ#=*m}r-$8|$>|AbZ@-}U3WAqrwLzz^=qSn>G*eFJw+VlI4sT1D6i5+=n?F8W90c(^znJDyUn#-BcXg;n3?4( zDdr(f%Ig7ej*(=w2eVvSap%ELDgO8ET&{cy&cecpU8X#CU&=2m8Lsm|;H-UIJ(}_p zGKljAm5<$*t(#N*9%nytYCfb6qI*qYdjtp0Fkr=ai=0pyDIA0c_%1-gW?{B2-zDB$ z>MCKoCrK7}he}P*)y;TR&G&5GCG4z@6NllNj5`G z-Apmb_vCbhFfo35M}2X0K|D}TAk?-LcQ9zBevjUyj?4A z*T~!LyyY%7v1w%gm|Z_Oil#bHS1@+p1utgK;8tYD1uyB%dri&gAc~zjzNo`FCvs)^ zws^CMdIJgobtuQa5uLe;#khX&d7Pzx!_;?<<@v8?kL8c?B_fBHgQybMmq0I6d>q%; zNP+9~%0$>&UM^}P@uKedHbrns4=D39uJ#q{r7&Wcp^n*dfUiW*2uPkal*Ml&@i;bV zVZt|vZQvQ&lTO*{1}+2jjuvX)`X_{C0Ena#Mt3BPcpH{SxDQ-`gq&*2KP*tVd zg0V9Q1L5Ca^B*Qg8Pa00=aC+S{r{*D{iL7{sq;e^9NP{Bh|;BqHr4iGri>ZGbBWQ+ zG(je0Pz0Iy)|dIac(aUNW^ixL0u%w%iqnzu$K*?8g_pdR9aABrR1XZpsP&8OObb7Q zVolssK8K%%Z+8&ko>+sU25F06`7RbB@~xM@5+7+40zXGH_B*lHs5C@#WRSju*>s3BgjsVgtWnBjDlub^D#rxz z9xUTIZ2e8#0!Q%Ev9MAmrv&i}GYQmLhFSj}V!uiv+wPX)eRy7t@6DCTup0Gp}_BrS9cQ zy{?+~M4@ZM21R_Y)c;!QEi-6MxrlM&RJ$bp)hMNDl!eMgcZ{R3?1n2s z(ai8U#Uh8_d?4-5NB|{;qTX?L?II^eD5{(gbk3wrD+n!thCrq zWZ0i+KU)4+KTB)z8kgEG>v#)s{1d4aa@Z5bO!m`4=AA1Szo{~qJN zIRABN!(bNj&rJDejy5dPs7KSK+A?v1mjyJ&<&5Yua0^&7z!q^u8iNWY@t>Sji9+Cj zXmOUN;UhfUV5wD<@S*1n0zXx$BO%BUJ_P>j(umSf$Q!uF4)Why{GKPbUtrO`d9y3-?Ygrw+j2A(L*I9d5iPH$;?-(6m-x2h0uep>M zyt?oG?D`~5%9OP3VLi5CtAW~VO;4|9FD&85hq&#u;T4tqU2H(gDG>lu8kIbS5ik+y{R6$pKYOSL7Kjgb@=r0HzP!+#L5iSJ@xgNbtI+##R^f9IO% z+BzIn!Hf<)1y(@kn)nxbbYQd~PFOacNxNI$)3rrj%f9C5iLb2fC%&P0?tVM*t?rLE z{6^;*zjGXV6Ci+NOgc_vP)GW>bR@G9eLNiN1t!b5u-z;a7F2j2xbjhdD%Q(6|0?+Ueu zWXflEk1SgM+;drjI#xIQnkY-MsRyu22*b2QZ_gl)BLu#%b1YH`%Q(NhXaL_NepOM( z{@w@zC6y|*hp86vxgo36v?l^#bOCd^>hdnM8pBUJX9mG&%uNG~WhYWrx7@gOL=`@2TDe3$2P~NBfv62_K0;Si!aa2hKRr#QNUMO6k=v5>u>a+`6GGN0>bNNI zd*6%d=Ru+1eL_LFMfkof4S6!|Q;na*98_g7SME9YKZsX zY(fvJ*Wj-blwnWeYuOJ?>Vv?q>ji!dWIx=_hvVSa&t^YWsyvZK6^>&;i@s49xab)h zP7we~V9sfBpiVaO567leIT&oKit6c1>VBnvN8xv*9*Z|JN*Tek_UW9iMbMlk(7u!5 zBOq)sAgllj(@sEPI}{2_Sw<|<2n-9*pqhcmv&VKeW+`B3-H;- zAsFOr5GeZnU^8n#U;#dFj&rE(Q20X@4XHJ)o4bUmx(F<|@NEMKEU@szu>Ufne7IMZ|$%k$q=nAz0907YmsyvL91b zrzr}8%>gC)0Yicq=L;AD6s*9INx&AItOXa?=c2F9VOLOTJ|MpPI#QSzMS4ZW)vs{r z-T~-U+Q7CmyZGkW#ZZ|4rfDkl1S=+yfnJ^cSI*C-7JZye72MSYAOS&odi(Y<+bUfI zmbIpK+>*uGlNf>)2-nrtU5i$y6D?{bY)&V{FQ~piUP|N@EM%O+Ult4hTMYlplWZWG zaBd*cd=dzMw1Vpus!NQ94EPnYxir+xr0OD5r~qpLA;S#NT)AGug>gk?lFfKrGu4)* zD!i7wz(!z33d!Ue8~AHauY!ATt90SnoDPZ-lq$dG)a`kRD`?=i;n;1Jvb3btVe2*) z|K?1CkE=JAJlk@+DcGlr2?}}O?#I=cOCHEd0!1FxV+HR>n?J6x`7T{U8M>No#(5yX zVMg(v)0OxeoTngOH*i-_}vNNz{U|Jb+!Cm3}@hrGI5#t^=)d}G4P{3WKa5@p$h4U*t zPL}g4j$fp!po{|;tMGa-RzjSy_~ zZg{x>FRR?uYdP#a7golt#DTblsprDV0JH)t3%Z*FD_;q$j3(^_SeadW09MW*yC<@8 zg(?qrkzJX~0}T8)RJk8@x-r1OGsrFs{L>-32L_Pc4F8tBvbfFJ&5O5y>^j7PWABk(&AVZnU=fzc2ZC$i`+M;(-OGF2XQJWdU zAK-&=A3qFh^#gJK5))G_4jcIihw;{gbgr)egf>E4cb;{`?s zMGO@X=sUkYl_3}CU)`~$@@~3d4S$FRmOmz>@$c56LkggG2CB6mD3|7HPi~3WmtQY- zh1NmC$2I5=D7=`hXpZ7XVy~&K!=%i9RFTuFYv$N+M>BNaCb;h^3c;8Mv{G9)NEAaY z9*N|_KHT$KH7byK9;1Z;pbcDpKw1*|TK&#gXv<|p07YaRIo5N}!(sYbrvM}3fN0_V z%!pSr{xhwn@S;P*rXiJ4SVER1LhCN1t1aq8LzY_@vkJaK_QJiM?dh^OqVMxWi%LD#`oeUiSk%y z`V(^t!;JBz(bq6iYV)C58!!|iXYzjpW9L2?v!6o*p@^y^MPlts6m%Vq7 zZ?e1_|I;R+0a_A-NyYg#3}&145R zx4DgH&kkB4<14igH!G~g0g9o?KHplZ_jv`cmciW6-JX-bUL_!~ z!jitOby31}-tlZ!`nmv7mAC^kyDKEFkl9|jMP#js2tp}j$q|vf_VTZve>M@h@^2mg z*7NTnOZ@sf4WAkD>tZ1{MEpvi<#1`#!cocO0)(8Z98NVSe*H0}#L8rG(D$zUE<$05 z`1O}Ph+qE@J3-4swZ1}pvAE}lZ{O?5$Y0wS1nNC-KqF6nEpFv}uFY;KCCpNPi z<}QG_qSrm>b`rtnVEG=48c1(K?c>|OWI~W@(aJy2;}J0| z0$GvA?o4+`tv!2Qv41#?y3mg7U-pvDdmt$C*gpcb!Vo2|^%{$IS@KxJ{(CKUuER9$ z4soA@n90dwxy3x_jU*jw2}o@k2uxAYYI$sF*tbRGv0I_)`kzKZkdw!XJoR30a@Jq8 zG!|j(*W;TkA*(l=VwyX()O9c+Im;36IyRTcwjU1o_AJM7(4VUx5u(UrH%&9^lHR}` zH7z00;rA@VZWM7f0@;%gRcQnf;Nm#J4n)<;6AVz#U>dbbjH9C)>8C%OY?0ZQGz7O1 zuZSTk^lV_MgU&^Wsud^zIc&?=4(vS?y8QDZD)}nD+YWVv9Uw=Vz(z;}xfa04fhJ%i z#?=B?A1lz6T_PLqGpFedC%cFZhxzrO@ikH@KjAzFLur(W)~}JSM3SF{y+*bxN-!Oj zLgcty%FAK;d+`Mg?Rg!`@L9>p59`o~0AEI4j<_LtbxAl`>%q9veb+k-EMks9yc#f%bd}_^s*Kpt7=BDn zIq|ZMuey@E69)P=fI74DsVDJgvLgTBBnFto=*oY60+(FIbd``U3RC*d}axeD5qD zODrNa5W!R)3W61<#S}h&o$58xcoBo(llgYMy(clp1qp?mudu6D%XT;T>4W(W^-IUn zOPWPOz1S#cUuZj9F}jU!F3W07=4+k%5LZY%9W28NNSYy*wwO@tvn*{FBI!k10iUG} zZ5I`6G#!JH#B3Gha@?Dy$i3n1N$#3z=|-oL&{&z%~L6hh>nP zoP05==@QE@7qeSexco(t8qEXs=3|^2vbP~kB;;30*iL=1mLav&Ya#G%Eud{jsN1N% zK%5&(2Hc@j;gTZjVf578+=rj*4krD zG_Nhv)kZL5otCbO_3eF@$ zYkcdMj)|G77~h7&R>vairFifpqLg+)U#%+jOUJbBtzYz5+Tc|T%yq{i<_^hHSI%*S zh%;+@8xh;v$a+L543~?m94rw5eak6{ zN!V~cm|f+&MDRP;CRfY9yy#iWB&?9o_-uFqiiKiOuozjvNS26ybx4W(DWIsreb)z^ z$KvAp8ozMq0|$zH66GV()0Qi^b)u){>Ei!SS>4D3_TKgB1x@6 zY~`rWn&V=bi#;x39^@0IEJIClt)dt|=&~S}It*>`Zn#2c$MD<|=Tb`YWDR+=);Kp?uHGuAv(nX*=VUt9!8J zj~Sno3E1~iK|QFLX2go_^Xr8blQHV~k@GZDG&{b*xzQyNQf7vknHlmi!AG@9|Bss1 z!um{6tameGv}RQg^wv5?}Q|^)zKHX9uU~=y5u-eYK`YhB{=N$Ij8w-5okd$BZ*;;G1psn1K$N zAv=ySU^r=%5sP)Oa8JihRCd4uxpM^&ubFGhPOMB9z7raBEnpJVG!!bVAybx8Rt-!Q zI3rtwwZs+-iw*G5vO|VUv$xK*1?_!$j}HQ+0I?j>IkdNiBjCQQH^iU~aDPrr{ED^# z?*IEXz&mnsT5N!yr#u+emazfu&w24?gtfV|!V=a#tq%tg)^5o9KpZQqO%D~;ra2Q* zLxi=&=>_+S{qaanQOhk*M8wAkYjX#IVE(KHFj!c;ar_$bk2X6pcE{jtvHz_RBiurL z66qr{RV@-?2}E#=_3sNuS^o}T{d+9R{~L(@DBItUMfBSC_jkwI{%S;z?eAtSmJtz; z*#5qpv;F-Dq8IEQ5aZv-`jK5=eIWphY7m9{P6Cl5?wYGC;>pyKVwc#F$x*2##+EU# zT+A*3)B9LnL9d1(x^GKT9D^8}+gNADdbMjK`vrzbb>*bLbJvru6GbZgpq1WFnYL`Y z1fcwul|CTSV)i&NoBgU*S>odRkpHd|W8k&g7`Q7dF5W=;Lt^&(fSCQhkdYSeCACLV zyCrpJR#?13PO`xcApPI= zzimF@6Z~&qodQ$w|A_zXPd5qV|J(o8g5Rus!?I`JU!8^GiI3)>SWKt?aeMXwA5|nF zFaH^P_6DTC|F&oUN9@@@{ft2GpgsGyN9mpZ3HI!N!(O-kk*vh{f74#~%S2Gm35@@3 zulsL%UHHnsW3PMD4uSZ8&0cpU7lm*Rev-ZJ5Pk2WerhBE;kY>59qu&y)9p7-O(wJ-2KdN}*hA!&}4?V*(oE z=;e{*G&r2hl|9!-BCc{@Wfu5<)nDx2^yk0*#r{cuu{Syd z;{P@J^UpTxgtyEKt~=JiUkg)@3EicFrWV)qCfBCy4j)jhW`Tn8Q*5@YH3h* zb*zo*NHw(_<`;C|z4T zeH5Y={~Rms+rG*z>Ees0F$3n-bn#g{q>C%`YxlBD+Us?|fS*dPEXcD70L>-!AW_^LhD6IHwEg zOilzA&KV?iIZq=+n(cC)#1j>fc4p>j150T$7PV1f(ReA@<;a76vkj)3MIUfwGu?D} zvx%sqio8sOPNbk*Fs;%UGOS}{RUHx+zDx%Iv_C!;(XFv3i^2x7syLlC6)r0L}fPiFqus!thV&QsJdq1aGx{GU|Rz0j+w1O7Oy1*P%6C6ES zCV!5{3q3kQi{JGksT~}DDX01YKki2bPRlw_jLL7Ho6bd0r{3GHUrPia85{r@m8*JI zVLS9G8t_`TB2{ita_dbqj_chNRL`IzY2CXPu=GEc7oT#@ZvZlP%QJlHa-P78teo=D zY;#+5mKq6Esw*g>zQiA{2)P4rVcF*JqegsA)Vi^A)Gzr)b}!#2S>Ml)??3shRJ!@s z`8EM$|D<&5R&^YJ=xm*JtQMD6+3-6wyVZQ%&1ebM0UMBQ4U@j!)n!cb?6;k)Q3@o{1bu0X>hfQZOh?n^GZ08pI9BhZQZtR9e50J{XB0t;V((lvo?kcYZO@=e~38p+==lXK|S5o#jB`x zja-89N5+j|G4T$T``KaFTR7Ppzz}^$CmH*hMVaB)-8`Q|t=@JzTtdZ@b#bE~L%=44`9iVdY5|pGOk+ z^EkO@HCB_W_TnKe664%-K5CV;dh5yNOBcU0HQVddu*&_?dyLpwy%j8gKX4r}0|wz& z7R!rjgUi~?_t+FMr#e-SrAtTZ8M5fC_x!%^(&x-Nm&`THw`8g5$+jPWnVy*R!T4}<$1F8oQ#xM?Tfiem3fvT(>ld8tD(UsCUKt89V#q2QVmR0Gws4gYez zuF^57EmfeNSZK37l&2e%G9Z)l02q+Ty;gnMx^`kq)Z7-6LdU7^EYdFpYCEZ^w}zBg zU+0s0l;liec8`iopY@2AmSh0nuxt=upilL%mjT)1G0BgO)-Y+9_&;~0i@&MY5sNC( z?PVZClaKb_7S_?xFY;Jv!zaT>Cz5Ba0l9rW71A@UjQUaOryesUlkTVXU5?d1XF zeXso3pKYqH587<8`5Q*k;~T33C9x~R<(u4(%^qvSH*v?xF85=BVT6or#DJJUE@Ml% zKQUTjUS3E%hb1G36N-zRuWbp$)TXl3OSrLspt}=pjf$^c^TQfKUQGeRs6MI=+$Bz*?GK+6kF@QsH1sztWaISB7%>X0?XL}3rr=Q zUqxHm5kK>*lH0;BbH%#dkDdURmNq8E+?OGN&PT;clMZw1_H%UfLbaK#AnrG4xi|FC zCAAV+q`an!w}=|b{GO7%mb`Z_AE7NZMe>+@p`My7g^=vkUv;KIDgh(Cq>>LpCuq#V z0}{=2@oHUlOSgQ4lBhQl`ceSth)xV_5Kk7125VU>tNNN(I%Aap^)J9cuD+N9mS22@ zgo?d`I?cV1Kai0%oyStH)zB6RhVK5JLXUOc+2&ni3ln6jHi z+5ItPHvznIMp!6fuAHG7*Ly14a6)21wzpA(%A9sUakw0C)_L2M%Vp9ymRXZupDT%F}VM^G5= z#x&jO0B%bfAIe~VPZ>&B**BE(q0ZO8YK%1#dxn1GC>+gLo&ftXuf0dQ zoWppP9(OryJTXkc8gC;oc5i%R?9!9S^lq2)W!^KNcJr7Rzt_rek~>~bVH(QoG1_18 z8Y6oMm+GbH$?o_;smly{Pw%*-!>s|=bgrk|uY2R&t}bViN3f^*e*Gd$Owv4#Hpl@5mG&9@~sNjI?Rl1;JG$a4{?@gg68{p8!9 z7=Ip*E*eq{8+}}l!JM^=ghRtVZ)_0 z;k=G})s3btWpXv{pW|Nb*4Kh_OdyTeVX`Y;%kX%cEf%`aO3BW`&oWJAUXO;=P2#k4zEz zOf6C9hJyAjT&r2P)q%0B z&h-33-h8U@tHV;&xPzbUZQSD_drpuy@#x;S2tbSu=Ml2 zF&M!qZ=lk*MNi?ZdXXnp4Icsm7-e}{m~c#8B!g`70(uK_fgyF8g&iULHYHb?)tRH@ zt6Xeob`nI#91Djt-5;|5PS8{t&#<0#!m~Yp5%qtXBIz!l&waB+loX~a5Y8&O_H66C7$8>a1Hg>AiA3HlWE;${$ z)aL?;=?1~LwiZ5|7qM>+qo}_c}8 zuWg-yW;G&;rpvCVt?i8-*K}EA7QZ8!E|Z}}Pfv|eAsUUZsIaYeDNM0!X#?H_?gxCJ zPegT&bSkmJYnWHN)XDl~UYY7zpaoxguAi`;1xIY#HYor4d+$P9fKRS0EfKF;PpGS1 zrngVftS+jNj#WwS9ejDAfKRgcE8+p@+Y~)x2v?ENq=(P&EE#6_3>RUZi>Pe-ITjxx zt1ud(>qo$g@E%Sz=?sPjm7Rr6v*>}ZfjJMSqvxydLs6SW_wf#C!{w9D^DY-6jHQOp z=^FM%U1Gua_UXD34Yn3MjiFHi4yUeLm1U;q82&Ln_RkGeMO4Q$=Rc6XdPjt^VSoB?eL|73@qGpDfx|yxau}EYXDq1U)to z>BCf_`Z?+07pWjVkcO{L7SH@4-R@QoQWT*6zg0u$}U7$#{Ww<+Ck6Co7lx3z1 z)mzjRFFKER@>9CeONB%Cm`OvK0tMMPS= zn5`6F(9M1@dXbkXRVV}~;Bp zRU%hJZAqtaA2%E#dzYL$ROyLQ=xCtH(8Jt2fK2JiK<2KKfVr69k3@BVT;SG|e!TD1 zvp_+_99s(gkQkS02sKRe;9P2QIaFc7NS?elWS{TyEpn_5`4+j>)JZ@H5wvQa=GF62 z0W{QlDz}8~Fc5X-jKVt8L%72z_t@4Kf-ggCp^-#5k8c_q@NHT0w)`2^axnJo6yfI` zu(pMXP(ygF$1n@?j0D%oUL&^pcwyd(Xcp+#1`1qGla&GG*6?T=$hyyl(a23SdI1<; z5E;RuLiHx(Ew^3beb@4~yZI$1IBd>$1<*Yh4Oep~B9S)VGM`I+nZ+-B8fPuD&KE9m ztS*orR^5Do>%?E?r12nm!wakt*Y9}PzBOf!2w}JzfAy0hg5UyXz)_vI`V@X$)d9zv z;yT~NRa}($CC8c(LEq*&-0R(SoAd?1V|~vpAtWBxEg+87hrB#t?|*d#Ipy;8fEyjDIsdAGxPpRa|W$az8xnt)(x+(DrJua_+es z93?iwL9Q#9yPRD)k&}nJZ!>rMRk%HdN3L@9_`UAYArG$=TyM31thUY8wH>8y4XEBAzzF{lcdm)2gWnRUQGn=ffAm@?+@5u^ZETL?^p5r znETP-8h*P%=2U-%$eUV*XVtf0kMMX2i??xAe)wx@g zNJqFv9hS70b|I#-`;r)lqty#?bD?kEyrm=6HhDCSdD>1pF~g;vkc7lMpig4U4ery- zS$yiudPyBte1tVO&-iyRRqHpvFvEW#GSH!L1i0y02Eowx`3h( z3|_tW)f}<&wzjJ5Q`i^jg{3foV#u7gAGcS%=HYO1%8Z{6q(ku?Y3^MLX|^R~Hm6Gt z47aTd`8qAhwP4JapR$G#E=p?VPGuVb!b9f$hisBf=6Phu_oBO{oiC|H5%bAIuCKW` zRK-VbgAKfyE-r!_wNB*N>U8m`XgcEqSH;fbHuC~$Z*fGq}XR+It*cJ`cn}uC$)a8)F>HsVbElTh6!-9> zOgRiG2maiu!2z-Hw`BAJ8a(fTlw@5pXYxL(d6;6zC%}bC=l86dzArTesEInLt1w%5 z=8%ehs4E&$&uvl<6u;DSgH_LsQqN(L{vTb>up#wauIm{}EB~HO)lpJnfEW9uR(J!c z^=zr`=W;fidssDkhNfd96O}@mG=h4plTYulLD)mrr8h3uBU7&f1MBj#~!TG27FDV!8n<#QsFJ|>C1}`9Ept#o0uU! ztL~su<}OFu%JB{pw^!Y)x0%ams6AOIaKBmSa_C9c{7AzUCsSEn!jV5j7Dh;PO6nTa zxyKaut#Ub5I}-dIIs_Vv+0U(!>5t#Ug4UNbet$t7^pJ?V?nFJ>Q>B1 z7H++~VeIITeYfHJ{Sp^pDS}+rq~shQBLP#kMx`#J z#=Pj|A#*Mn=;sHrxRT*59wH6X5bNwvHEuMJ@zrBp?iLZ57}b|@(}6sgqe96~xzy(O z1nUm#`wD4+>eVGtcc|gI66KVUCJXH-WVqYnB{~qB9IC#(%tCj%6_XO=9V^vHC)I6I zmD!_dza6S$6x+ZjWuiBeKYBfAakToSK1sSEbWOWqbh zZpLM#$WzzKicu*t9}Ri4O_kKe{D1GcCGN9ff|o zlDp9ia_!|4r?FYB{>|hVTe}HdvKV zhhcdS}laSrV|sFn=q= znGDYS_%aOWD)y-nWpi=MZsxcp^Q7`dK zB~|Kq9te$~kI4m9HZ_W|Am}1Sz)p2QKf9Z+r*xl>Kl;`x!<+`I7VIX{Y+H7K|HXl4 z4N!~%hV;OF7kUC)d`+RvePR9>Kvljxjm6yba(AH zx|i;C-RNH321y_3@dXKqzlI9xh=zA#$h{i+H?kHwxyLYxtXA)lTe#4$g--rvGhOyQtBSj$KGg=Li7VKdI0x5CkY(bXS#^(Yc;CBCb*o99E^0G zpvu?jHfP0;sJBVtHJNoyo4Eh1ZD-t^5>tegbsTu9gfh|_tkfCsdo_F!x=hhU*_3R@Vj)!}@MV2>TVGgbL222d7Rs4JN~Vhgj9c*LZEw zQR*Ubd~BHIWlXWt%;}|EvG+ipyLlfuGCcWPKw2{-Y$r*%3@zYmtBTR;eO6!QqG39< z^nivDc5PL+7YabSTkfG4;fWf>?A?4`@J%^8qBUvFMYo;=(vQGqB z)tAYmzRgWFY}P6ph}(={>ab0HZ7)epn+3NF;vgJWe~rX-t15ewugS;*>LyrlXs-LO z0Qbmyd=#{U`s)n&TPw9<1*0yJ2Xyrdk@1wNUj6aLu;!USfk=evGMCs7#nb3&=~`1Y z+m+n_dS-_q)_Kp}Jcga9Ugw?$37;g9&A3cNhjbF7O0R5!_zI6LdbOxlQ>O@>w^uzT z7Z6s@^F)J9muhkCl%`9y`1V2rR9!`(u(@5rgfLNX(R!wy7w30o%G%ee=IwM^SeI`| z3uX}9AqbTs3oNwoE$N9aA+}>wmq7>Y=eu=SOS}~k6?)_!4lulVf!ph(OlX{eF0yW`yNr748axy?t6Yg3e2Jl zwd-3$(1oB1YDQevN-(kbN{1~vG2GDLP~(9!G(*vof-SGHPeuv3(!iY#_I4pO8kzCf zHRA3qk>?KD{jpg?Ce|>&Q7Uv7a|_y^N4q=ttw%1z#x{~xKV|Oxl7dy`^`#YTXt~}* z1L;HvfNb5|C@Y7vC^PGPk61HyN3TAN?=M9crIpq)?D>R{&s=}3211&o&DdqJbPM69 z7sF4l$k@zP?nh>(!*3q0{RG@hnrW6HH=M&7C4GT7>rLH?h2s*^XPWU5j*Y?r* zTL9~&Z`kd&rcwR$4J6uAl?>aG;5~j0`*`D7{E4sd+hSE2ZAnG7JLZY6DRIX}8BJ>z zh|DK?a`iZ@O6(SbKAn^$BM#P<66Ek6dU|lW<3@M0(Axr=?&g)G#h=vs3%vJvD+em( z>T$7)!{#(EI93pr#1PPQ%_4I6YN2aB$AgaBg-y}(P~B<+$5tQGCL3Kkr4FG9PH7NA zaFYPq3`z*9L6}mO;=qFOr{3*qB#5w20vp6v7TRJ{v%QvMWy#q1N`0if3gTd^=p)6O z%^~A*-ys3h%-ZZB^B`~5yu`l1oY~?LlX92tX*yfdSbmMCy7{gfp#xA7O`;aiOYgFLb6i}m;Bt@7S9c+{My}W>QiTM2B_p*n;-3{mKIaOZ z9w58(TK&k0)IL8@|YoHy4G=5oqL zgPocgnc;N?{JkCv`_ta)E>#!8R47bbNuIELOkSq;k4p zPa`D64)w>Er8id1;bh2*+@i#s?J$R@io(g6yiO}IKjkn-rHe1%c5b=)ijH$4NZcHM zwmk_xT`v?~l@L;AF&sn&PpVI)ey0y!=7I767yKhQQJgb`LxuI5dB^HrIy z6<(F(A)HvqkOb_J1<9QY*yMA<&|iVY#e+wSD4{HQOxPq~*4{weYkORHr9k!Y*k=Qx zbva&IVpTZJul zf;#+4I^E^>OIE$%tWui62jJ+0<&w)vaHNGxT}MM-MbJbT+m8k-Y#vr~`((|PUN+6m zN<1262dSVTT}MM{e?=TRr8y-XBZ~J|Ug1GfzA}~$_*R1nNAeJEIHZPC7aXta@}#5R ztjW`7^#_9VGimWvdC(6htCxqQ84cIuIn+)`v3KYpuo9mp%CM$}cdG3Wi|U~v1+tag zKP1hnq;;^8zy_H}%>Z_*VbF{imZ-1sJq0TNQR!NSpu>3bE6g993#6UE6n!r3D`eE_ z8-PJZX`kQ`r9Fd=I+=nsrGwo&UufBQR*ZrO7{h+`?SRNlzAk@ra+92lTy&Di7qD#( z;h|t2P?c06f1T|1=UCqbtA33l{ushZp9HAS-{3eB4~}#% z=N}Qkxx0(WVwkv?0zSTu}aTZFN7Mto=5 zNOv{Xz(XD~lC$#EY{)4~*AhLM3v`g|f%d!As7oceBhWd`l^06j79a=KUuiUjmJNm= zzjG=xk_BG+G$__%a2BqW4nRYQt;lfIPFW*Prl4Lc@85e`5V0us z#vjc0L`x`a#QUg&e$4|w{r+@u&2i{p+5~jHqKG=tQ>PP=9u$o zoB!K+mf0Ivgn-szp^PxX(t_Z#mP!xHvUE zj6;kYJbnAEG;6FvDFef z9LIx@qBq=N8<~Bt^`#Y+X>AgM_f%}05=Ontc07%$3Q#t-Lc&fU2n9c@&uA2*jeQ8D zsRdBa%PO+G&Raxqgj`DBt*~8yBwhSNJ@6g@hzrxj-zd_v`!nj(GXy)vmfwN)B)^qQVH?C;tD~vCj&W^}F~<*&3b?1WakpAsyF<{8 z1!t(8pAPCZk70D^EciUeJ!pm6N-<9^QR^tpvV2c+B#U0Z)l$KLx(zRv>T2-G)WcTm zoLZHaxO}p@nnH=%37xeS8B@DV|F0U-&JU={YKL0DH!{A9hkRd|{qEJ@``*`LBRvmt zFjl0C157S}dbYe)0pErCmEA4m8y`j)3FlvLr^6&vr4S@{L+3eDl9F(~#Si;knzrhU zPuWXSI(l`c_Ayp=!C-Q?B!}%= zLQN=c(ream1qqjqNe^_3%!es{Vw_UP$|FqYr=@HAb!089kL-$4( zOPO#^CX=eXL~omf^L%;x9&bkV_|tigU0`LKQpAg}D#Nom9g=gYm2+SfIh}MWg^g>< zNM3lsqI@Kj7kc;!C1+NkKDP|St}>|Ebas=U&G6nDsq;Cb{X;HCn+%)w3}L?!h_qq- z(*saA&R_q&n-}}OrC$gALbV8}`-eL9ZR2jqWYJx> z(9)u|d5D?@;Z>h6st#GA93e%ObjmObN2=FJp_6A=?{@kCjJ!RZ4Jhsf@jsWuFybn5 z@L4UbCTsl6L!9XRYC2l7qg79mA9&Eu-`3AUON1eb#l)|J*)?X@Lw7iYCw`)gTvPoq4IQ+40qImO3tfn^y&@AgFm zyPM;S8KTkP9L5h95b9ICN^C5e6B<$3tpm?IUiQoBrZL$4;-TFirMvG+v#1@e)JDVn z6uqBG4~L2Ujuzwkr6xlt4)|3_JlS+!jXvcM0faarC9_`+R>byqYsy@G5AaC+jG?Wf z!y++ilzzoge~FV|7N-xL|9z0tGXFCu$p|rz7_Jt9*ClnNW$U1EXvRcmElkl|%XP#b zzo85y7A%Y3;AJ)74G#1L2uhK}>?b z)N!0ZoB$P?lP*XXAE1yNwxi@qEDiyLp(0XH7hNcXLgxHDil)`lls5r7S*vxx+ALr# zdb#N0i_L|p8;FkRkIxwE5iD?=Svz)} zR(nL9{qcsefBond9fUiP&w4U5y8u_qHk#WPpE3?zq^&d9!#~Bpe*O&r>~4?qj+=2* z3#vS{VL?vW{jrgF&Rxs2nggjxqEAyLY$@Q-2}POmT74P$K%SVkZ&mk!{^_&m7eI=C zsAMrzevBOxY>Tgd0A%~u#@qXC+~9rfTP$6hx}J*BKs4SypcDV36KCl}G)fR-G7H>f zBd{h5`EXv}E|FBRi=f@YfU8ikP#Jg_RuK z=2Y02lZ4IF1IQypI?)$tc`bIFI*1}YL!jMrG5wv?@^*AuAn896A2@y4l+Hj!9tJL5 zfeAv+a5`!AIdr4ehhcnu&qdN{=v}eq;1JPkTl*fkqTPGUWwhA$uPcR$q`Z|g~& zlAQK~niI0`KTC~DPJ5d7xz_hB!06?zqr=?L9ZuMjQy+NXrRX^=ZySk`8mG8}&zP!t zceJudXV~Z?%o=ZhtvHzQr~2a45|j+fx$f8QRJ2Z$20;_E%LzJt_>to>{3sf}s2dyIis3 z<;V&r&XB{z9!_|nuf;1J>7mWm7=%S3mm@k{3$o0esZ)5(i+(21oQ@U*ef`Vkrkr$P z*=%jYMgX@n(t*xkMP8sQIN@{|f45jl??_`S!l{d0kw-W>EPgOR9l=!tsdJBdZ%>^l zHQV(y#~2jRCo8Xukqf9U5XxhrP#%lfk{Rn5vF!Uq+N=UeBn;^QtQ$mIX;sZ|i zJzIE+o`>0$bz^n_TNrnCbFK9*ie|E-%lIu%=4_(oIJ888k8K0V%y376O#MB-1c9^^Q8o=J__Z8MtzPs7rsqX^*7+5HX zotYR{3Vs2($bOV$_97UM)A9OJuT9x1#e1Od-b_D179ZPBtmh{74WnXnVxL4Z!M1=S zaz=gpl|zi%XqZ!>Mu`tECgzTKL)lB6wP9Ob>oc4RA>R>Pqs-^kK_}a!fQJZ;n6+i? zs(^!Ie0-&06O+tZeNWDloEmLV?+BLgs->LqoT!ZikQagULh?GKxq@Mk3Gj8lwl#}jNO zz=ozSHPcop?tPqPWr@bIH!O=$L~<@Jn9W|1xUOdk@sFaz=t+1 zrsTP%>0uhnfCv>}yo|Cb)As)8^mKQC#y4z-UJM+1m8%C@H?{TVCks9KTk6i;7ijFD zV;zB3+~$8@Q@wg*YscigwqB>BAfFo_^RW@8!rA`RFM{O(x{2E)_|g?j1dNc?S(JD6 z!B+04X_C3YAAe{cCHz6IkD=u3kDH#|(TSPq*;MKdw7=qj^|FIZ=g4_TD#VYe zWgVMX%jWlm%`dsaCK}$Is^+tjIHLrkfv`E!-`Wom=nb1EM3Cj1m+%F37)~xTT#z1q z8-EP>6P7>qwj237PaYTA;y+$X^{_F>BZM*YVvba2S4D9}d<`?-FxL%e(kQ>K)zz9uSgoN`wdCW5d9w@KI*2z9^5;+z<|*ABO3dgFCFdxt#3lqD#+_gIk5B@#j9a4; zwMw0ZQB8ti7GgDpr53r`aHJ@32T*&=Y8&~#vI~TDZ9UQyZh1FQum|8VHw*Ue`O6kr{hy= zYfEcf?)XBXP`a@RZ5FE|?tXPQBW<=G9$~6UiC!mvX3L*b30M;ET4Z5(wzjOxY<}^4`pAX*0Xs#*V~{iqxdUqKdvdX-k(vH#cWO zs{82N2<}_jZW|t-QRXGEJIq@_#(VOoiU4pTB2BC-S#EdOCm4!`Y;9 zpu*iUMus<|%+<$y%7ddX&w9w~6WAxk+xM>Zkl*(@4@P298M9uMSXz--G?}Mx-%d$3 zSGwfIU-iYZ7%;L^jX|&xc0W~H9WlG>e4VRq#xe#r%C*7Ph~eYZ7DpiZDZ`8lAPHk( z)+6G2v+&?140$riM)g9M2${Yvd5ChZZoLM>Q`gEF)CP;@sasoH z9b_kdIa?fVR3xYEeT4_xkEwNB!2MJ=1VN^9b=)V^oHXF}XJo5(w|o~lQQ88=Cj>O} z-7U*V!YsY-HWqj&gja4EvMc1n5Ex%`rp#Ea>*I1*J47T%-pbtwapsV>??fusx|*ui zKy}Tu*zpJRaDcg$rRofn7Kr4k?K&KYhQm zo<*|N*KIvxqh-?}LIj~TR^5tmp{!cKBQ|~_NfCUV2u$v~&&m(qXzRP1KUV&QgZb&9 zE%lt%il=taVv)Sxz=JUUDGXi%oJ zv+U$sxU48u8UJu`^o00_OQS{c4`b0Sz87Ld=ueGPajB`eD^MXKF(yjp^4EE49w!mU zTLE&0mq3S&E2}UD-6QyQP8m`Ek=|DxTpN5PD^w|$hha25tTWhqUTU1+0eLJ>6`GrN zDLxG6&HI$Be(Q|tWB|!sY?Ks|{yGDQNA1B$ZOOpX54?n?9Xt?ofD2CQth=zcqVe#& zsI&2KAZGVJHqXCy)rBu(B$8ieuAER;ex$B^rEzdmVQfJdsl41RpI(jhT;ru7*aP9e zPQs8KlTSjPXru&z@wk^Bsohtxn8b(}XU^~IUwYNUDMx&U7vwO< z6;A#}keL{;C0BZf)-Op?cg&G@acZ3Q|HVZZ@p~^`k`f;B1?JhDp_j1ly!RjsG0_+_?LS8J{l&ynbCQNL8~|GP7WDW0{sAE1ws#XWk) zxVZkM%#4Y|im;TBmGAsS$V$wipedmxm-;jGB;rey8HPEV(|;-_K>!cY5yIxogp+d# zF&{K%Pp$*G%N{*Vc56xe!{N~}Ambv!9W<(jz`?e63I3BB2B;IPFAPW9+{R@Zqs>jx zlFmRlZny~|Y;!hX zsS$rd*kyFtA_hhv7|(F!$#wt9ftHw4k+PdY9^IAU;SG0P7e~2Y^ji>0fYX93wG=kL zE_EGndvH;^nuD#<{nVoB1Mbn}Vg6!;;p9EiE*2xH(y)1tO>Z*{H%w_WY&9L))fcfp zYwYR^?NY))7!t%p1|-P53iT*`d4V}96E?&vY{&w&6YZRa9YHj!MA{o$Ce%*jnlhV3 z>6`=BrN92LIje-5MhQ6eRSbflOqI!5jz0E*~X_8F$e377jx5q zbRao9U$_GZq}IH(`EUoV`GMB%I{jGJDnX{+X|1iEFdejaPPRL-Q;+V*dd4pu!LqAF z`Lxf|3_lFWc?1)jQRb%`5Hlo92-Tdqyu{de8V$=oeaNAiEIZU$TfJ1`@z8!_&1f+k zgE3ev@QsC3VvZrq!a~Rmv6RZ_KE-UPqE(-CW@vJ}FF(3O=;D(2VFBNjfbZuT-)uOz zNq`rO3~n7HfkC6PsDf9xGk!RFf*27`=G0pt1mBawz0(4kksmdK2D)f#%C&3hyRBWl^g=bbVkGAMtR`O*46 zJtn44I!% z{E40FeyrAeW1=8+c5AJ7Z9&Q#?;92!Yq1qf%2f?AGoGHvs|YL z=Y}sp(byxb6JVuNgVtf>hIwp{aP_qAJ^yS%@0Vw9x z>|Q8mKvr8l_J^&&CgDUrPiukBaALYQY)*HnBvyFxKwht?Li>0(?-U*L1NlIBcYZ>@ zbWSgWb=N9SHZ|+2?f-$&GO_7sSA}>Fwlq<(`tS3ou%SDgEPmb)JB;xU!aGLHb^=1? zqY_$%uX?*gxWS-i(2{14@Qo?%hu+=z}=+7Vr0}lfGVt)6VK6sr+-_Rtbv15 zr{qP)s^9!Rrn23M z%pd5ORbb+P{LO6N(K1kigX>9SCiR-lJfZZcL4$QL1P3Cvt4}FzH!f8i> zB>V#w2v1{Pu#${FlK19*oBr-OKZKlf+^8>!8MI9q5GICgd-q{?G&N>TvVk5 z<4HzN&&zqfK)wEwm_sz){)RSfh&&zt zkBn)cmpa1e!L>e9S-Qicw4N&SdGM(RAKlm*F3p zOFbYeqPFPJQCNa+i4jg>ceGgDyf+6)`3$q~XY7CoUTv?VtB*q3ewgpR<6b$F68D!H zf?gB9DD~^#M@p;o?~|n!{Du=xmX^sc@t7j+2akm9hnY<|`EDGvSC%*}U7_-4LWd3- zgg(b!%jLf7y9^}a`|GmUjO66=LnilW9|`#mEkBq0xG-={ym;NckHx;O!wBpQnVX3} z_PXFr!#(Szke!_AW&14AT*&uQv@}%y(vbGtkLGhV_?WehF>6N{$t&_gXl-L}M#_)S z-tupVX{Hw&VHTeU_u4xF9UKR?VY2Y#HZL!IVNjm2D;07-_~PZs$>l@4gKIB$tJ9tS zKT3C2U!cPR0M_qBOLO;?aXPbMdW`Zt?ng(g%@3?~p=%Ebvi{>>T}TzPb^XYyix3QI&zsbjPl;Dyz)S&Y@@-{$Er!xE`Na zpZSN7nZ9wI;d_5sdC2~v;d^oE8H0^z=eVu9kpr*k(eF>4BR92?l~q_i{$sOtWwILP zyP@(UhVRI-WAj<-`vaYC&0fRz=OyB)1{D=OC5-zx)9?x7H+;|*9gsX^?(dr>tLFP) zY1z6^`8$U1on@yU(;sW$F4pZt_ovPzTgdnJN4jHW^JKCipT-E%DBlYF8oqW7JgdsX zzPFbaW1+GQ`SC9_&}hO4cw!>l@$Vzg37e@tJHI3>E#|}mz7iIEWwTO=JHAwB{cGP| z5t!p|C7VioTJ$Ev6IyRNZ0BSX0-$=c8Rp%3V+*&?_8rP`IUJuY&sc~mi8JcU5h0v& zkg)jX>5$GICdK&ur@ndVdoAhW@>d19c1UpN*h|)VmpSSz8>Wmow=PbdXJ+acOC1$g zTsQq}=bm)&8?R`31`}LePikM*u*|AygZNDmL()!oQ?t8I=%-JxcRRo_e%uLS`-A9N z8z-GAwwGpmIN8)jF)s3s7FAb8*}H8XuAYv)pKS^HvPzB+zjaWf1&O{EHvRBKZPEQ9 z>^Nd0h*9W5p!=89cHX&$KuqG0+%4kBT?qND( z?>AK?ZMHUZr6>C3rYbDU+oFq_s_v2BYnrOa-xiHDRee={FKw#&n*3hSRE32MA#Iwf z9?9o-bW;_9DB8>yV*ZWPWlLSOQ7qI`7i?^ipR$du@^jk8X8AdBqfi&AF&pocpTdoC z`EhQ%gP+74S;NXb6|+vg-+WvoR!|M;;`uN0X{9H1q70P`OJArD-Pztr;6eS_&u8SW zuD*P>351jek7I2wF}+-MhBhum_DaR;u)2Jjgdw1z?aEoT?y6Iurz7@gq^S-T5UGeJwUN0>r zi|(9_@pz$7tVO)7<4xU!7aS&-C9p4Kj!PIC;qr_WwvMmqWgz==nQHTRd`Zumg?mf zvsCO&F-g_3$VBjWi6GIVBEPdNSLg2K`0r7(>C(FR?RaTm5-GM#@J`ouP$_#}`(Na2 z{m&)={%CZ%_=G>ms&$)e(BpX|^96hpmzQ^WmGy^~RWrs5ftE)MpY~~5+47BS5Pu12 zXW9N&2!rdDSpkQ@krQo1;)+rq4p89FDE&OJ?%O3HDp^vcg%_uael zekjdvkg4PZ78^_gF&DeYw$54=V6tfTOyc~D%o_KayuPbxmVN*sfn0y&g zMg7fh`yV~s@BYR!I6S2;38fv3XMePywP3B?NO!oOx|nnrhP$s5bQc|aY=%&BO}?1W zolHfspJQw2)fR`tW8ar*hIiIt?oCBI{gV#17KnD}dHPc0jXG+Ei<^H}YeDKgNtO^i zLWmWF5~oNPL+PMRdm~|x>Lg#ft<~Ll_?qaS8V{cyo7lW5RwAvAsG0>*lb#Rf9-HQa zjH44-&ggWvv_7oUehp)gE(6giX+JuRTrn3Nm{K!5TFsoCCpn#&!MfFtuGQllqsN)< z8afx5q`n(ur&!gaKhf3qc}bJ*6Vu=|6A_s1YCsePpN=JV6i)@u1D%If+0b5mmK> z9k-!6ZtB5`bPn)Rk{X z_Yma8jyHpT);uwO3;M%^^9lY|Zb{t?PlDm|?HrO@)qash^#j5Ppd(ePj=D*fud0e? z^GND4xZ;hE5=A%ZI(2P{;?MD-@`hCL0TO17q+nJuhL`j8 zUA2Sc2xiLFQ<|7i9n)f#YDJi=UPgJA8GRx1`zxxEBN{2mR)q|$ktp4U+zo#6 zpqR+o+XAf~E+=_`DbS8L>f6I|eHAnJeA;JoE(x3Ow+>@x%{SuP5q>?>SaZGzztYdt zOo?7-ITV`P)it{CfMCWm>471U9J=-WV3lH6JUx`SRJOhPh2*n;kotwpK&^%ZbsuS| zBu(C&Dnb_?PPwHImq?|_HBejyGTU!S!)NJ+ zL=KXp3pqE$$I@5ye267;4v*;F{sl2K$!27no$JjY?c8RRxV`!H)WFn9WJJmSmi%X|Qs(fT;$H2rV z%1M}v_Y6}Ek7F)iuTO$Qg-z$I3)%W&lQm#eULxen9{82LMkPUH_iQzi(;580U)^^J z6+|`|ZSruU7&u+UQ$krUnGfYcoYd&MA+c(&w1}S^4gS*?bTeu)BQ=Ln1?5q9(-Y{n zaODW2a;ht|XA7kwzMbHB-!svl=o=&s8)9F-H+7#O9_=jQPPH70fG*!})dlq&PB1Do zCp;j^%sz3?%CVrs@>;SNZAUT#y7#TBP*-g~NQvN&wJxy?v1pV!+!=9!h$Lr}M3S`_ z$IbC#S>jPQkyQ?I(QQKhIhaBK6w8z9ycoX8&I0Ka-I0!HF*Vfv#*lMK{qU#?bF>&l8T}RG{%nk~j>0c@aOp ztx!z`cIrxuuhG4iEkayhy$6bhlcW^%F~yuxEPmz(&@DFgJ1gxRE3HqbwOMK7t+XP3 zZ0Z-17C+M^FWGTJTYWV}att$`3i=+Cnlm(FZP8Kns6+aY^&_^mXuBLBzlh2{Wm64o z1mY!F^N1H8IHyq4TySHtlh&S~-g$Sy%0qaz-d`qTnm4>~Ud0P>^fW^RM>?$&fnfxgIZ z`#IK`yRq12^9PbfzN%(AbmUs~E#lrV=E464E@35aIn)lSw?)UJhq=TtB6ck& zLMYuGy#k~^)383qUJX6bnE5ZXF@41PFX zBg)$|_iAag6mc<+j)LY$PVF@gy${R0q!yXhUW@E#+0T);H&v`gura6=%)M2Og52Sm z$hJj44I|DrJM@vqJz2Y~nckHuQs-?J*`cOR1m3LuBW+!z?`g$mP3WAW8>t{&d>;kr z{_*MJnLVs^w>qfo*cO#5Yk$a2#|DXKYS1kU2X}ENJ}95q~k@4wxG6*Mqset`VOn)FG@Y)%h2>zzs5bz zu@|uMwb^4Yh&jNCbO1Lxu5xgyiC?#_BqKnabq|<&1LH7RtB5CaN!jxxhzHtYp&;S6 zA|B{IrU?X`E*?!s!{&cU_%(4x^P{GQ#!MIIkuE#)A|U{V+@tCjlU?MUB4gA#NqGU$ zQmIHmg^k;>L#C|7C4En{ST$R3T!+hq(T|n~fd5>cU?aAZQT%WzSh>X;^8IU^@<-A7W z_ZCQOv35m_Pq_!G0B-tY{188^80v?Z47O>HptxE-dKGNZ^M$7ajof zBGSyEkPHNjPwPBsKWhUJF^~8r-*=pC7DjReKApzXCF-QxmQg# zPJQxu$+|#9tFjI{>ambB;46NPnDaC*QNsE9(+TX?%DtL? z2<_P_HpuS5Rzk2v_lgPU0xFkQ03)v!=x$f1F(SdIK=t*dUXj0LL^5g(XF6l$NZ0r_ zgHpF|(@3H~UqzThspGf_8I+o*UWXZB-;)Wda-$?uMVa_tlk|zSn`5-5-3qkGuW2n^ z>QCFC;QXXp`wmPa{#!EVA4B_X_UQ6%K|RCOPXG`RUgaNC`jctLW~=;kP>M%;9z(MX zSJ!3g*~r(Sz4+vMYOH#!aU^6Mf*DU4LP;D4*>lVJLPB&$hpEj3m6o2)JEjHhg2>o| zB_fD{f_sq?;m{oMYEDArLmSvOwnWgIK!Rj_7im(jmL`d0C=uk2yx-B-4bx~WfvfXu zG8R49D?^d`T)e$}9^ZINtP^FFmA+PboxFUieoM|RyD_o$NmAsM$4wgLL;yMJh_7Ey zF`GIIK%sLz^ovf+rPWA@`lH4;+P6>UjkC5zm{ft2wi3tCs zs$yF&(#4}jDqjXRSR?GkeOsTVn;pJ2Vd${+2G3xbyDsn(I`V6Ir!ej9H>7J=qd1Krhutt3Z9qkDPe?@;&m<_=pyhkVaioOT!79GceK6$PMJtO0{5uekk{`*R@ zC4OL)+izXAR3m9ac;SqUu*geUIfBkrGc|9g1?}U_A{XhH@db3^R`q#VJ5ctSjLKRd zSwjooWzWuZ@yc$F%cAY)Q1qa=SE?Pa4zXCog%T_`0@et7^|~XeCD0S(60;EXA{jUt z2(Wo1^_h*`%$;@$RZ}6z&7wxhri;hKtngtn!|;BeZ>b%e_BuWtrH?aU^FCLq$<6y3UE4?J{eo=AZ?xL~$h<#GBdovf zy%g8IuO>6SKTCSA=UtS%R_|XtTlXHsPVY1GJ`=i!?1!W(=3V;tF;jlbILxB2OH~a2 zfHm_^Y80f0V9oq(GV@;`lLnk0^BJhRe#p#^(tQt0jzO5YoqTlW7QTtU`wQw;T~J`= zbgS=I>xMFY{~8#W>^`y^H@_(GXxLw}07cwAh6q1|j{;{-WU$IczJzo4SwIbT5poM| zvAR+=4U;6-1`Bzd>dSI&>>bLQML(4MKv|*c=46Q%eUoLf84!$d{oud@IRB8fdC07AkiQq zQKCiz8VzdV0A|9BoRNvf3ySqdi$yi3HxfXZ-*@dZlLW**Pk-jLiWmcKvI z4a~+lXrhxwRl8SPE^V#&EPFb?Ovha>(I+((wg63J)0xM%YtR*063C{txih?X1I z$i&Lp&>Ej3Q!0PKY7rq^9`Z$JJO>e~T-)VugSl;QHHO@*Zd|!yXjb^EpnhD=R zV96tU%M8uLM-sjK`xF(vMK!HAd`mS{1)YqI6?RPPib`rnOQxhl_%UVsr!D!L8V8HB z@x2UZmKNnN>|Z`j9K-@7UN1e#1a|o;_jEFNFWi(1sPPr4&f?9KY-wI6e!#b_^OtR& zw!|9#WF*5kkYFtxyTNHlGLe+HmUGWGwt|a!j0GP-@!%EPGU1)0Vy_A}w>=I7T3A-% zz%U%kPe4$Z-WM}_Cgm=Za^Z1Fxl65bevo_lb)0*@5= zSf{KNDUTcBFK{t~>GJX^FD>V#F+#%aV_dA`qj3C4h_?z&mpWlf`nuwv>%sel729Ph zHK^DwXGx7HBSrH^yh*<_8#V6(3(B}3P0jCYJ)>swvb#`SrZ3`dY!Q_whom2#YLTxM zR_{gWY5dZ=e&}Nj#5i;~QB9(`Z|;&$5_Gmz?xOjtxvYRfw3&BNZ$QCy@LH;V|MHq2 zjrs2nbR1kS<259+h}<9HRuSk8MfKc@l5nL(w{yz8M|tQLBEFP+p`g?O%fMf_7p(xJ zHI@G=W0O2X2-FScBr;&rf{*D2m6>wMS4?pv)bmn(#yK|KO;$!fhX$xls=lh@vayf8 z4O4wX(J+6YbV`J`^z%!EZRYQkeSM4&Z?DWbW5=aq2fX_+r)Gipanc|N-u33uH8M2) zP+gjTV+c5JpcF;=Q{t=KQ^_k*aCN%i0tzm^?5uUqPJD)elAQ~H*enfKyO@RhDCZYa zPJz|3h*eIrl;cX5bC7DnQtNvqhZGw9o$JSa#s9#-D92#jS1E;#nhBflo!ShDAZd zf%R4|ycvh{zqa^aia?I)P52q4k@$+K^;QInexx=0lF^XE@od@H8t##&S!mhMajvoz za_@MrqFf7^=}we%UAP8IXNa4eRG;XUGU|(BpeW9h6|S9jJoF5D>85w-h%IX!33;M`Wa@+7z6Iai;c! z*qBPw5ATax=<>t%7eP2S9avn<+Q_0QP!-2TfPsQ3aUxN&nFu}X-BpY}4bHz1f)1_^ z>?*HM7}V9~-BrHW*oaW`NKqgjj5@{&VrUS6V+C|lD(PAQWymo<@v4lRiOWD#EB4yw zjpr1W%HK&UeJ(^x9hKBw#p1?tpcG!2JU!gw2#u5bY-Deegj8r(F*6C>>#CA-F<%Zr z`*lEjr5HS>Qf(p-3mhn86A z1D#d1Ps_LYuYwRn;A@3WO~+yF;vhxGh{L)Ou#q^dLscABp%sg0$QdyUdi7aY`R3Gv zq2>u*i2@+RgL{QtHp5dlM&CmTDn{!iWa%HHbtm~!xjzxOJSawMZ<)vUmHDt$rrJmP z^HcUB-9is2n=V5|IP_UyUQ7z&0yY5fW_X(6_s<1tQR;NY_INj!+k<1xf655S)SD}1 z+!^rEsr;*`0#@(4&j_p6+{2~a2A|dzUZ27%+(r>ZA4FiYV?y`;t6ZP8CA{xIDA#Q5 z{UmvFFgER{zI8a7#Zl1{vvi_A;>Od6~E z$2p14{sVmA&2$!>qHYD<;t|qt*+w#}Dx@dM-d%x+Z&hH{7fKAPRF!{E0K;nIQ-Azh z{4f3lH$J(W%6n3via>N??0lmkvGnUfw(|{dPq7~HeS{0}YDZ@va{aH-k7ck4%2@^- zGyV6T@}Cxmi2AAMd)7;nD$6T^LsKni zc#BXZe89Ev6VyPodpjkM(U6opM70R?Og>M0?a7hPnS*SE4)PeQOInB&io(IK^^&&& zvtj{vi+10FECHrX=SN4R>v%xb(VW%f%|)_~Nqmdny>a1Z$VKir8kPzXOgN*yWnTB+ zLZD6mJ&pdw*&LLN?bD2VRMom;T~*VA zZB@lY|Dw|a(RucOJM?QUJck-2D6SIh3Nu*xx^lGI-L;00)Nkxbj;dyRG2SAhdjG4; z`{~jz=35*n$e&X5#EMIHjGTthgzRGb)cH|PLw<7egcGqqa>lfWOI5b&#z{Ldg zzP^H@m0wZPeX5inr%QQ?55kKcwrh9&j=R*9?9>#eafwq`{YO31f)@k8uU?t3t8>rR zJ5VRzlYtyStE$;~R#lUC@8ndw!1t_n;*2lcWxvFkoGuV}5^zQ&s&>9mU<#}?JI_de z0KoA9aImn`YoFpwj-AQ`P3~P0^~{zNO}7ZIveC!=D{I&x{2!zGDADeH{}$O6A64OZ z(DD_0B4YYX1e`ve95#8PXhYGt)B#aFce^D?P&l|mg~P3c3?|sk)aJ4 z56ZfJgQBNLMc=Ytjf!KZ#XCvmKS%cuGc-*yG&wIEW@uL3{O^Y5;IUD5=F8{MAhY11 z%=p|gymx$N@M&|w&HX!EGZ~+1M;9Rnl~^kSCf8YD;;44Fv88C?jcSMx zQR2R>ZoKxgria@ZqP>GdIj>m51C<_Qc-ZKnI-`V96pphyK6hiE#Iiy{oREW=0Q3fY!mrM8?2vM?Dpf7u@XmSu+e0ri2X$_4P)jvl`Qci^vk zONbdemBA!yfdk<%u(yG2proC3NW&8ogzU_J?D^i+cu$cGjX+|}P1bPBAOeX%;Z2nS ziLxp)anB2cHIOIN%w_#uV*1f2hE$&QdHBGA(0EUqr`+xd|8RnhJMo0*8K-C?NDt`B zIZze7ZVRtzh4|6jXI{!$tsAJ$h@#^NkyZ9RrO1kauD`D6AaP#c1Bji+k%$MdwTY)V z1?1X=At}^F5!8iqZ`B@eC)Cp)VAKutf@^Tk0wwx)*ipRgvEGLA#rJpn6xCcYCJfJ- zfb~A68a@VCgp+)o4;+B)x%+5}aL(EiCo-f$!yXjtQi-@0U@;FVGz-K8P5p&(wkYgT zQTsSsbr5RW6S-|d*;X}FWou=ygb))`0o7C4Ow6AU<^;+uaWCIua76FM(r|iLZG7a9 ze*=AUJrcBWbTnsoRkJry(d1ixpktza{vg`dy_w_X&*@>Jyik-TJjNzekh9FdRB8Su zHt@~n0)_xk|iXtdUN|_AzGr3%f?@K!mc1iNd zgVTm1a7!*#0|jxm8lR@L1RhPHP%gAI;_FD||JSoJfb32AyPi?)Hx_l!L|+UmZ=!KV z^YdsRqRY(^J(G-AaSIk0Cq^Pi9Rk;pDH9S;LlPL(n?-)}#WH+kKFYJ2!aZKIyb_NP zlaCILkp+@ zSX5Jdc_CfJP<4#IB+daA#-05ra$$9<%22&(^N_Iyh*}x7*{5u{AyOLxWIt!mg?# z^bdd3IV_n|Ut!Z4z|ByfafIlh&k|4a00Tq2r%`TpYs$4QJBQx=_Mz>2{5@LOTZSwc2*UywWJFkUByisYYefs9<5bL0=}1L|teYn(OqRbo#Fv z`X!y`B;9JbE*>J|37HjFLyBUA4c`p*Am$U!i{!lR?$8?ko26d1wzguh*6`Ay7`wy2C0Xs>R;^XNQ?_%XH{WCf2j7K>&@qw8|W&``FyJ$MVh4RU#`s+^@8=?j6=Rl<0{S=qBwU@jHw#L6;Cm9KH>Rzn~wGv z`>TyDn!iVR{{B2VbqL1s)$aKGG7*tr@^~TN#O#`VU0i4s;%gWZD00O(m|?$v z2gKQ$urp|AcC1JV!523t=wn$zam(mlWF%6Q97(}fIF;WD3al72QMJ!_lK=d}j zse?v2rFqC4RyEE7y}>Q0WV>J{1diF{#b>sL*!xpW9=*UG?#rCR}at zK`pPAkLQExieneK#J5IkvlU)15S?Y8VE3#_(R7a8re}F6**wN4y0nLXU3bR+>GH1t zqWGuT!fOWl8wZ36yiIrl7=Y@hE@(96S^UufN=Q1|9H;xE#E?RT&gE%t6Dyhd!ivYmZp`l3@x6}@3J^-v=t*lfdWxTv~usCIWVDbNX<{j#6)PlHNW zhtr>Ns`?gb!8Wtj{INJd8Y{Z9w zxq~^P6{x`m^ymet=3&vQSMV{CjW1@r7bZXRyI&6ut>0G>a#Uu$d7!0fSkiI8lcM6$ zDqg`xW7jGfsmkW<=5Cn*$Cs3rbg4vN`7uR)&HI%n_D`3meoc+H=~MynB_I6uSE~!F z#qgt>qwqcsoNy7%bMf;UbsmKRGSOcOL>TE1=nZkw+k4%@GJW}w?N7{^G$UX;hK|(z(T%J zC>%d(f^{LQxX>J>T79r9_jFK)8hHJdzsrOBZaE)C39~GQy9>?{zUD+g)O+`87p@7% z2I-Hmf6lKKOeABXRLOCN*-3}};aNL?;aGo6H2N*UL_$h2puGlcv|)DN;jFd(Z$wF_BL2Cr?36DXRK6&g`rQ7V3UF2dm`i_m5+XQ2~A;Bi>v-#Mo)ebZ9KKV*(YI@1rd zd(uOtl;#HEJ67PDDHPC#T?ufDW2Z{HP?m`>jTnHeDaNR7BVFq+&9xAx+&$C1M z8V7)uZ6e~j`h`U^`RHx`EWfkb_?-9|!BN;Jda!jrf)jAK0?3LHxUja}YfqIzd{>MQ zVcR)gj4x+-i0ie98NSmW%Jt(`i#ZKR#1H&@sd9sZ!OtA|>+H!f@)wN*3ospNz!b%b zjbdM)_kZzeM9>GT!ehC!5@W_6EEjMUU!DEI)dPg#e$?H) zL$xU6bgx;IB^;4=v0Sa6I2m)fKy)e=OK_rd%FG8p*}&mll#ihY`~55*4Y)xkj12QpJR=u2!`Kt_c9f(1KzvEZ8- zTnWg;Af^?r6nOEZHmQiMdiYzG-7z3IOSc2ic~gOizy-auXpe!mM3^QBV5U04J>M*x zOr&^e)S@%J?w&5paq%Hg{|n6g+U`tAaTwZmYl!Cvl`H#J85vOX zTqWZI-HO^lS{JsaT1?G_xh_mAMe9CAqoY4KQjxl8>h?Q`ZsjIL>)uM6(AN)*l6_mg zQ|3`>Qxxy6ks0HXtHse@XMp$hyccVvZRuSsyw?-Vje1rhW1r{3x*Ye!FR_FkRak9L zYqr+-Az$dmQ5MNzkxcp|A)K_v_42BhASH)qd5$EFjT5ACZF0Q6f+zlE3p4Jv!E%Uq z`SFg2c1DX(L=R4O5k$$4(*|sH|m7o+ZJ#@aIU)m zzgXtuYpu;p4zR3ITmwqLZ+f|{{)0l=;S9fT53kGGvvbtWu{h|a2jPTAYY^^qIN?lt zri3RoT^LhGgcC<=4Z?EcU9b)|Rd7;fCRjM?h{3?ihQXwZP#L$3TPvF&k!0Bigj}gM zTFpf;trUD`J|>rZ%rQhLoAmbwe=|~;T5~fW{3o@gV7^JjISXR`lP|}o8ALM$feI}n z>STxVigPwvdvM>`uT~*9kutFlS90hult(e71b}?LfTXzS)*1+UYm1CbjF$O8f5Z_U z1ctGwBz-ZcDs|_)!LJGTR=MXczqS}#HnxnDP+;Or5dinFaTt1zC36m)$%$o)hyrGd zFHga<*Rah~l?ixje<2TCclf-dW<8 zV7N}yDZ)Ff5ua2W&AE4Sm^(!#cIvpcso=-VjxGH6N+n*Bud?N<+k8zDwkJ5XeE?mv zVJ0t)k_M?smL@Kc_LX{+KD!VGWm^UN7Mf#`nKC}ZD##qVPYR*k*o-eF?&~iAyB?e$ zhZvc|v~cqsHrs2*OAF_ZgMblfCnsm2Q)#X|b9^@I2v`VlX)zAHsPo!T8}4$5frHSi<*xSsN-u5!mmSWj@QBj-RBkv z$U+%wg1+d7UgP|14{Pv_5|2Bv@I(pd)QAQ{+be@4Cy3lwC#z10ea&+?C9shkp^m(> z2<7Zf%+w&%y4+EU9ZTs@d5NfYxu@IyVi7$fUA+!1Sb&J zWO4S746o>IiD+Xp6ZbH-V8)XzTZnh8M~S+%-n{KyX1BxK$C;J^75A-Zn_G_m(t3*w ze#VC6ZSyxkfp`*GM!8mL_oPc3gksYiSUkxitxALG^xH_ENqWk)E;|cHr6ZR9A?9Rq zf7rEn+6amHr{n!LG-8DVJj83S=1Gy4TYB zyAvD|o>fSrX0a_Pjm|VL?RwpCo&e-A)cQt5|PS9os=2Ed9CyeuW8Q z0<*484^0nL%qV6%wBhdv8c3o*Oh{(x{u%zrIG`>hU(OT(62 zB&%3=e=*PFEw5AU$9~_PZV;sRS>}%p*B&|FAKW0Jbf)AtV)Te6NF3P7huBox#5_o!?p>p*Q|_ zgTEy`_}(VQUXj((bGgBFV7rCd|R?yP1Q}_+!`-4XQ9} z8Y=ru!;39eSLDF+_icx1*kNYDotXvIs5CH?8XII%P&Ws+6`IS~anrML^P#hG81@Ex zU)t8PzgC-NkqBWQFg_NYH8%dE%wy@0CwjGb&UqO#S$MbG8F`LYfyg=VA0;GcXCShu zOF_b8((UMUy|&$_pK>npAaB#6^Ud2YAeC5uK@ms1;@8K)TKsfJ<}b;2ys-HS}E z;axRyL(JwlqZ3A%+kLf(P(J;-1=Igd#` zfB1C}Tgb#2W5C#hlh2w!NjDlP{`dhX*EW0@25}k%cMZ#jxUYO-wzzp|L7^dAc!KV> z(EIXDn%TxY7Q9SLEz7Vo;Baq=$s@fvAW>C@m~nYl9eFSGnaB7_Hqd8CV@HqDB2?|V z(74kh)iVOdZuu&pm$W1C)T`kdbLRK6x7AO?*V!JJpgj0X-l&FDa!g0A^SWtFQ(NRU z2t9Swie_98!3f;(k?7P0+MFKTC*S9f@mOtD_6-0mrw(e&~iR&VUO!MG&El)y5j85@0j$IA86djc+op_yc8V z%hV)qs5VxcKTN+|&dY!?FV7oYfRf}qPEaxpdd1{W3G(Ww?ld2!eAxpBn66b)(*Phh zSfxkK%LWJvx#lIW4wRggIhm&J6vzp$DPHwyxM3t_oGB2Kz}4qu~M~p z{VF+snSbUXd4kM5mFN+|F-LPuu85z^pR0@{MMehfcMz7*tS7~2PrP?PgaL{~EL1Cq zS3b~5f1L|G`gBo@4HV^6gc(4)>();RO{|<0pz;jQyi@kJmEzOMR!9c-mf-QtS>sNd zIDY)mkszuA(w1?jF;%U6T=bX^7IK;7wtH1neL)^BBvCAg2hYAx< zP`anyJWcR8!DHslw7|_o->WQP0b@4mMv z!est;-=Ksbq&*z5O-fbEd=KMNG1{*|x3LqU7j0tGhs^hDKA0YB#WG{?ebOfEqp=M< zrT7qysO~ztD3iMJ(mIoF51^)WL7F zw<)y4oKJq%^dr5!K9aUSB`yMeOZ#>DEOYoe)#;Jnd7bX_i0{1U?Q(Rw)SqMCAhyj$ zi0N#Mact5x-@5vWQ$u5#J$5)$TKV)H!E@v|)eV7_$8r=ftf+mzI|$KB*G} zC?}LlbnNR`Vr+v0k{6gOSdY-o>X_8DRM1LBeF` zawELx8hbHJ1Hx`6W=*wl6-H}SIIG)#$Y$HynCce9=K*fO7jjFuL zrsCvl!VoVPx=3--p+&57FhIjip*eCWU7m%?jgY1jn-y7f(IUvA9sGeb4Ja@C?k)3j zD$8#w4o0Pt1QU5k%e3m-0Jh2gY?0rM<($!d#EuTSN_OrvT32<#EzPcvUXUnoGP zbWmg$oJ~I3CDQ_!h|53PS0jIBO2Q0ywsUOe3c_{!)SU5 zCo9a0+bpD2jxfVQYMGbm1$?CSox*pSSKuMRT7`nLbk=aanWRPvo(+IY$3&O0p~})_ zl%Au@SU~W)LL`iqzXpNvUe%;Z@gT44Lay2%+DX`j7|>P9PX}8ba3fLCv9ERtD*#6( zoQ{IG%4}S1X_xzq4qSNNfwGu3%&z6>dD<{Pf#WL+wPBt@o=bTy<++mQN}g+YuHktm z&oj}eCTR{yN|ytkUFfA|Ta!I`5_)>e?exa{!%z70!0o+G&Bx1XR(kDH?ZNGJjgs8HP9t$S{!((ZG*I}7LFTVsk`EYnkVN{kyF^?dKGph9hqz7A%t5b9ZjoH3fnM<& zDvh^+N5HetEZ@&5`h-XpQy<=cAT+$)^;7O?DK_0VQ*JUpy#L$Kh<4Yk-sEbM@i%u= zc>gz{;R;CGUB2{NV@3{8h^`kOQ?mRCtMH zl%u`e0$#sB79bk`IG@rZ_X`stdj5dgFaL!8+caKb?phLqGSZM4HG2v?P2TKMeQ`>l z0K1N;t5^oDWCuA0LrOF+mdS2v7;=WJ?#270hYLTDkx4Thq+R`RK|TCfa6vuXacHAU z{+YoAa|TGlUc>K9o5D0qr6gHhIAiiIQB-Ba1diuK7{U>6DYw@KPvA7CD26=N_(LFM()YNSg<~u@M!_tN6BG(vWP%Z zpIykK{Ubz?YuV}eMrnO9HsPc_v>|z}%>IQV)sUfc`)mAk7lwOA&d;tNlozckOu}HW zo;U(@iafJvu@u6Ii?Q7{_jNFunjSFPUnW@?P3G@ljMmFnm;-l4FAPK~CGZ+^^3(zg z{YwwL%{b^niOmmM$IMpTCa;EIqk?5rX!HaujOTF^gJ&Q({{X2g(5SSTr^7u-AMrHE z?oVN6v!)a8N@tBm`C7oD@)g)>OeLPjRag>l^!$Z_Z4^EPEebjmv?%CM(4wG2L5qS8 z1uY6X6tt+%@jK#z8Bwr7dV=v2DQ`zWW~!JzgIZsZY=Q|8HNQYv@3|41T5x|G$T#-Ei?Dl3Gj zV~tPAgvioRq`mSlB&)Mn;YQMn_!XNykW#c$PU+Sc;Oa>3|cRXzogj;Hj%Y4P5=fJqc`jj5C9Vl#Pl`MYDq#R}n6rtSX z$&o88>{s&-f0k;)|0=GZ6#9k%3Zc!FYx{^A@XJjC_5I}ox#aGYnTWW&k{HPy&&7NZ zi9g8ubnXeB{TI6sI4SdPR!^JjBoZa$P*{9MP`>$sFhrvHPWj&Gko3gsvI^-dqy%&# zQl^ZMxe`3Qeis?#jH-lbUzn$XrOS32J&mxrFJ<%t(GzCVPOtGL(J7)g*)i8{IFBB9 z9bZG85Vq)mYi@FJ%7oI=8cyJa_A>q?LW?c5EqeURg$i@`gihq}?$jfX3-XLyQ&1bZ z<`_MC2Rl>i3U&Y++fd?dvJ0>jicboEx{TGlME9+rmmn#)o@Ib6AuDo6raY|?RxG&! zMJJYDRdix-T=^CD;7Qs`9yWquC?<_4X^H;S9vx9!A2_?f>G)PJc{B7C8)a7c$Pga2 z&O3U=0lu%#hRZ}iiVdN!jSHNM6HjtH37#sF%ffIXH#pqAA?RXulgBe|WxoZeP!x0> zFEUBkQ*B}dgN~DXEMu3MsCSY9KnoLjGn*Gj$l}75(FlQ_Mm=MUMECxTQ$AN z!_IOykl=Yuuo?!cmHzlg&T0q#akqHNM+PUC|G*w3P?SVtsj_?BvH3;5XpJ4wk!;p= zM|qkZUdI|ww)czzuj9>ho_U?JIg}qALMc3+9dNuGDET_{X9kfLF8)k)_T=zq&fuu< zXSu;#_qQSXIeOZYRzF9dBRBMO^vQBVKSvjEp9tGE!2v%B&9%{-%AN4M0_>seE|;DyFpdbA)z0rGJ)@2%hCh90uJpOEl5+#6 zLdL@AQh3E&jb^_h`n8v~RW>Zl8W}2pLq&5zHqe3E%g&1$+Yr3t>0L>l4nt8{G#%$X z(MFKd48^Z-GW<%JHUWLf;ZN3BD*q)Uhb+=fJ$6XC=dFizJfs&Q?Op!#djNgM{0oEL zt=J99Z#3P7Nfj!g~em^@Iw`j!Z;({#j zE}k-b?3_7NBR$$fEoCX1>Ip9BYwAy|rq)_by;chSf&7^+O-0e(YU)(0sg)RkVOIq5oKdv18Vzh8?qwh zq6(lxx5~Mx(#OUNip{&0QK?!a2K>D=$ZU3ID_*)KOi$&XOa=*#DXx_iX(5Mj-AL9} zl;ZS)m52#NZAH*0Oy20tJ}9U)S+x}*Tj&GfLzL?!Nx4GPuF2B3d`lC&u>WC9F(+IK z*{^;Lf(*S+$TA@{sUELY$S-?z6-j!5M!9{Qs_sr4UuDlxLMDG^a>NB_;(e zg@v`rw95yB`LgE^QV^VScri06Uin@=7P6h z+uOKO;SZoj(Yp=GI#%oFcej&?h*J^QqnKhNcTMkKC)~p$tEkuiXNC`y7OZ1BF|MS5hQecp{Y`s?2+#o%{*9@w*i~gQOlkd^=7@kCx*c?Uuk9 z?kgsTe)o%q#Xakt(ws2J4PzbQxo%Ahfz?r_j{(&GoTV5&GzY(>Q}F5Xog&9&iX{9G zN?V)|6mAevEOV3l%vbib|JC%lZLfK%U>bZnTOOJUw;i)f`(z6+kjn4;soG4HcN^6t zMN?$t+yKYeR~1p?N+BIGR2&%aHZ|yFJ8+~&Ybn(v}% z#JtoRUQ{=zCka^?PGE~7+7ZNa)EYQp;yBJ8ysa#i5GukH-}wQUQ!K*Kpof0j(ji*n zy20|uy$yCJK{T8wm?sBS%y7adCW?~ibA7=EM)tPd)F_>hjkfQHI-HJm5I|j zk=aTtE?W3sm(KWbVABo`yQ0mPI$<C6AHx_p?u(I48>Kw7S>)=Q8 z;73I)W->=T<>`pd(fm5rt6ovlCDI9$#I{OtxExwwDt=K7P@GAM6{@o=gBB?SCK9*t z=dk+(ZR?TRMG74YqQR1T8Ha6|-JcL6xHH|bA4&+Qs|et0H5?!KVd8BLGcR~TaE&1) zm=6i(*f6ZV^yV1XFGsyFtqns8HAnPI&sO*0Ot+^>WmRNUzOxr64oLog{6^K3M?Y58 zlc1MuGB;ak1*FMi+6x2{#1QB)SN5V@STh;r@RXpTRa#^4wpGYy=g;8*Z-rFUdXrycCa)PWf!qad<{F0UQtMjv!KNyz3o z1D=`Z418vuGc#p9_lM9evaSR|;a@5Ul`QzL6%a+g#{$uGS{g>zreV}PGqZd2?Y-s} z;#KI;<$}m9ZiL~wY$r$m4q@hw;RqfYr^t3Q2evMFGC%e&8UQg>EE8?)uwG6Po-fCB zL`3Sip5|GasmB#Y=&Mi6dssu~$xL{3W2EkWC&VeR9nZ6o3MqEHu(2p9$&8y%3nsfA z*TL^H__uDAWwRs5Hoo5cIoXo!a^&e{kP6=6Tn^`>PlhkCl$83ngcJ=H#6-}e=9J(GAR&_og`<*H?XfI9}XR$Izzi+qsD<pRpO!U^qXa$R{8$?@A4g|@>%oE z5L*2f{k}qd*4ubFnd=^X3yr9|5sZhY-XBpG4m>2JTKrRtmnOzg3fQy9+k=x5+$}Eb zDNY5?HJ>Yk`h$yb5(w_dk{!Vz`1Krh7$M$}nynr5@;m&;;u58^Y`YiFQyR1`2 zEiUv|+@uF1(oX8cZ65TgcXM&_7<1({s#`TYEn@v#A4IuWAs0;aqd+|Kzvk z)bH~+lOD4<7EF4SkE)F0nqR>-{y%YCb3cnG`Iw@yGmdL?Si*;QTyw#0f_6@xlS6pJK_QrMF~xTlk};ay~0Glcx#h z>~YRN8r7dt#0WOq;(aOpYE!oe1>>lVAURP|WtkID2!09rpT$dc;~Xr9jNN|2#QHZN ztR!g1kC<3$QsxfNsY!misGe*2z)-eF5w^)=%BR}p0iL)msWnf{+Jim5I5+W!V-A#= zzIIDEmG zaTCGxhFZ^%7*4{Li?e{*u^q5~vXv!Rw}?$^y~?rUKj@tjywE%L!5iT7sD2g5;p$$Q4&qu8 z&&|=pUy$ZgQenD2g{9cjXUk@J(DD~PQY~HPz=6=`Q^t$Z#)!zRJT1p&*3I)uRXW~_ z5LdzZmeEV&B$+p%*{!pMY_Wdy)^i&+*(HWqC19oOeL%Hm0V!2h z%10{2P;=qVJ=03uY9%(w1i5pIt;AQYL^&^zILb#Dutdtp~EU{7oR?19L7Fj9hNQ$aW;W~@Lk51%Vz+rBa zrK)_S%F{|+yF#B?TO?m7exb~joOt^XrP|hCMG`OT&Un-OEl{jSrCZn$E6EriSr~9FTPvKlT_uDN5fdgqdCqh{wcXHwCs$wjprehZ)xXK-hyajQH); z9Y_k!0|vUpM00G1*6jfD48@y*kFVWMmTzXuTuEoV{{cFm#smFiIH-bk~JhkL+Z~tQ+q6y zh|nm|+ zfmWY*qHlQ#6S_cFX(`NcB`{eVI>WLYmR(g&oouLLENH=sMAgQWSS*UoDj=6_xWP3bptb%;bVk`SH81b52K`**2gwnJ*ej$eB|u7^0P0 z&MHzJ6maKr!eaomWtq42VzZ*`pKtLZI}tv8|R4e;bq);QtP6(rf_c1xL<+dkDO(n;04$oI?=d7DP4JyyE`MNGKlQ? zm9Mo@?+#0#eS*bmU%_+~3 zQxk8o=X+MknhO|T>&CY}_x7M0`a&DiKx=Ha^9=7pP8L-Bqe7o!dteBLCm$jKffD(g zLOZOxfa7!c415~m0IXUm8>=^Rs%k7Ud#9O4E1(-i10kNEfVRf9m=Z`!Qfp|&h0+Z7 z$J!DvH$J1qKWnSEWR1^Q=byDhcW+zhmpTX+Na2E{wo=j~PpcHK@wHSY z7-ZwNkB#-)I=y%@-u8iaNJpl)a4KtFL3HZ3@elM75fwRT zsliN}QxUc=p(Z@DKjH->uQMl|2o3_fdsfLVgZIUWV{jpaG>ij_%5L6I4sVm3xaf7w zDp@i{do_Cn#tA#47v^G-tyrI)h!agX6vOX6LE3_-OWGu!)>a5OiGwnIY)j}kz47f} zZnv+Va*)`ya`8ZVIMMfUb@7yhf^5+m|3o^4=s1pWdEgnHLS?rd+0T6hlE#6`;Uw)O zU)(I~-s~CM9`4BUp-|w&_ioTDf6kIW#U2FQS5m_tsX;d$oI%q>Q{nd*v4Te$#|%R> z^v^s|I&$49jer5|x2{ri_1iHht7iYRl9wW4u{+yo3M7Q8C}xxHnofz~|^RKW0wMk^K2W8`lxJ z`pM{Grn^4ec|eSV^?0&yY&>%HQ$R$i(Mr1UVX#dviQIi zEQOZsVYz#>hugf4FMN(JH1g`^-{grdz=G$p6l*o8dvHEd5{v37R{KC`hsGz94mLK- zvj-TLMxUh6t)8)O2(tH%T~CZN&$iv3AzP{d==`(jI)=F7p{5c_XjRq4VvHLH;sUw!|35q_?*l{vYnGKxN`|!B63D&e9sZ z48XsGks{uI7eGybiB zF&CLg#n2IX0EIi9tOeJT z2aSivojPPd=HXXr&ueG?Zw6z_IfomJ#HVap>7E2%`d{^844dYlLwayqx(BaWT2a?i zmsz6=3;KAvYbHRPUPBEsR7mOa4X~jh3YttB-n|=@foT32Z*(KKa)5|xj1HlhgvvXS z_nzf!Lr|9;&}iCJaj$_@meGU5y1TLx*?9bT@h%5f(eFA&4Q|vqlvbpnBGM=mY`#$; z6PmkWTX#y2f0(7c+_1vNM|$*UUAyF>AV~aCJ5X^SahG}BB*E8F`PS#&H2+FNp*8rd z*}k%WBno8q-R)Y#cy5H`Q=V!7@PHu{bd_cS9hGDOgg-g28I37 zlk0PU6xB2*^BJf!Fln`(2B$N4n%i+G(pUoK;C=cn=j|rE#Q8*hr;44Brm1#$qfc@~ zsAm`hQKx=hgl9%h4WN5tXqP$%3@3kh(Xu)%{7>i}!?z6Lh8@JdXj!701csTBl5zFm zsoI)mU7JG8A2p#Kt?F%|kY;EE9rRKx>_#eKqtu!{zWo>yQ zDX+?y@H3*yALnzwp*4QPJXRg|;)5f|;EVpqp3a;2hsmuU@g0c7Ky?wy#S z)Je3j9z5NL)(h*1eG{ucg3jRuvCJ5SVE5HQ|} zJfIR7T=~Y&Ztg*C1#S;5PyW)!aiLnO(i-kltGv?g0YKfWy+$lFH2kD$uFa~?Xi!h= zhJb729`%qeR!)3g1Cd(j1?a#DR)Lc#P)-yxR9&1cz2XJ>BU1ZNYZ|8>9(tv}=C>@% z4D_CU7753Ad!hHQ;a=#a9@JIxwawkBl0cDeVFaeFTxUkO|avJ>{XTBF^h^h0)m=#z(FI#PPk z+{VzmiHGF_cel0#$%W0h`pI4#_qjJxy-X0?IcWq}{Uolv`>@-)qBW7mZo}x6`HiO+ zJ|0{w;~QEgsO{1;YMV*>f>-uKZU1B21gV`U2&68*7kN;q&%t3bv@EHyy$TlN7D^Iw z!@^%{7z)8!;p>-ieJ^p3;4?R22c{Eg0KSIWPWs^)pTaZMOF=VU@C?8_{mDKgGXo@p zxjzy1Kr(-omCVZ38jd^&%eu z*F$g1lDR5F2OM<>{ObzVt@|a;+i-wuQD)HL7QO<+wuIi14xX)W!qDEyfS^c@ zJ)~3DA2RYu>ghl7&n9HnaQqYVmTdE=NTrJM^>lZ}KXx>)i|x)LwnJ9TdrHg`)ro7> zLiO_p*Y7P24)HX1qeX1Qn{o=^WqTbR_#F(Pgxju{wEEp`e(geNRd}n!*&f08NMB)> zi+@yCC3?S{Qb|km8?FP&XPb#5IQPTM5jPdW4KlAnL4l)@ZbXG;BvwhUWwEI*UM(!8 z4BrVi72k2l<6hX`FGNOtNx1|>3bGG&pRzo<3_&BxE&hq99>G2q)uY|F1Bo)_d@Ol3 zDG1p^M@8?l6{k|lx9L2;@~q~0zB5@MuRBwrvqg^}&o=)wrB>~E9<9W;n_J=^4=6e} zr+!M4^9aA#BY)xLWFYDyyNkG3OQBtH&x6L+3w@i_Euatt(eTq%)ovo^eYARJ}Kw)Yz@bry!k zAUX6kXZr{S{gIuzbSIEVYyjU*I zd@UJXdzD)$5BeqeHz+-J*ucJgw$A0+pK)VS;&Ecb(x=SunzxgU}&lY7$fIz}R;%5@Z)W;8C)N)_LPzsWrJY5= z%6Y>Qqo)T#=@aLPL{W`Pt2V~Abz-*dZGN5nKH~Q&zpwdy!_P4(+cucrFn$I6#_&6l z-*|o#_}$CzF@8_;Tgh)7zqk0k&+k)y`}hr*oNXJlN6~7Dkz0PkNzjyfU z=4bNzjNcx9-|}+;vP1X{=QomHA-|LOoyzY_eh|b7rqWVD63qy9Fl7S?ZX99GE0cqS z5F@5mCyKAhnWAj+kq|6jh>uz5t3tEzMT?tSwIW5~Y8n?2I0 z6uNa*ma#3o+fMuwG91=a8%&Kv37k`T?P2tSYS0U+L@!83FQ^6-`QhUky`XG;)}om> zM)Vn-mZMFm1ooZneghj@=s$Nmt_~NXfzRP~0jC$y6moctIcN&i(><@TNrl$ico<&^If8K2K%qLnAG~4bj zL|f*T;~4Ie-J&j3!)R&^EC23n+11Dg_dFSA$mhv!wyiF7x5p8P}1Z+bs;3- z<~4EoQZU@}WV85s1|GmK#cK!jCs!0-l#f%nFZ391nETmwsZ6Y#*@F2By-S+zYwQeO zWccPt>dmCOyR`eR{&!`fHbZfoXwcb02yZ^2%2mOO8%y{wF-E?Ih9cTc6gxS0M@Gl$ zL&l$|aP!anKK-g?g)(5BIxYzqFw{{t@J0JTrDK(Ee!R#UEv&ZsX<4>$oaj) zfUUPQSs7=4^;2u)g4fV#RFBhRhC?zT`HYQh0S0k{G!lkw;gn_m#`sa}zc1Ne*V+A--mH9jwZ=o!3mWQJpQC zTdqB9$Odb`U=0|of#~&l8K0tkKFE6MzB$-es|cYuROpe#T4UB>AA_PmOa_L888p9= zIHV+rycMFFgmO+QBs@m~Po=#M^QEh#FSF7M%`3k_%}hB2!~~4O({?RlSUU%Q4`4|m zEEyjtT}M%8-S!GyT??)EKpYV-M;K^3(uIT@X%0r~FpX=TxJ9V%v?4!rge->K^IvAI z^9`00Hz2gg&>(56stnFz7}uHGfxYAyA?gO24`ZTBY>V*z&Uxd_-ywj?7{e>lkOHAF z&2!q6p4~1XPA9Y6fh0)B-0d%kMW}UJOXcrH0wFNAMeLU#KRI|o*(u9V{Ou2}#vcaP zBhahJih5Szf5{v5<9=zCSDU()r|9{tx41TST}eDNg!5|9rs}E6H51*{S- z2bl$;`FsD2mi_K?Wh=CdTf|I*7)Bkm0|A3_-UoZ$3)C!7=N7qB?t~VoqmAGR7=&^{ z-v_TNIZo;peiGG}t(6AIVk^cBO*$d2J!P|5$$GFrV@7KR272Kgix|}UzA!eKP4pHT zgySz^(SE>IF^$%$<83%)4-KkpSl&UQpWB>THGNWqyEXV4 z#Z}0?9K=?`LT1wcn9BbPcTCeJ^M|j?JFz?X=$XUW9khA3l#4bNr14w8*Lx+Z14{Kp zO-8?y&g-v-{RLuQ5~1&&>v7c9?wwa^1 z$C#5;q8hAS>#O*|fY5Bb(r7r4VCmi&; zKTpJq13cR>TirzYfUw$y^%Tst2#puH76Ump_oWR5bB|Vo;)xvD{f$t#=Qo2mT! zc@19#-pULMd({ZxJyZH7`-;V5@o2Af9f2~;*ccj(XwLtk^P8@3f+xsPe~9Stnzu3X z5r_FZSX~(w-Q?MV50j&i6nc!cvhfZwFIL%-F4NBq%Md)t09tiWtT`EYrI=AnJz>u? z8Dx4aHj60j4>B+1wK2_UHh{O#&IZGw&kkeSd;!>E+>R0us2CE`xK5~;CVH;z=zm!b zj08ca86Q@?3{5#u^ETIsYRfJ+L4i_^;@K+esNw*qjW}X^epmm%`H*aE8h7+yJ8(bPV2>; zjLYaUl|CbPziR6hq^Uea@SZVxp!H7j|DEUclrz50%9mSWT|cFN2`bNX#$kni2>XIe zBU<=#LWPy%L%v+i?@fNxdMiWDx|q?bLUZ=&$MQjbvHIXDSE;(r*h~{?#x+!*cfvTU z8{@rPN$;XbpHtvk?zeC+zxVllOxg)u*7xJH)i=HGwx;uuColh=Ur9@6{FCO>z`QeW z=9#jX{GFq%@2_g*eJ5!!HHu$Pmruv8*vRia-btt8{CMBjDQ4)uRMA)E|5#n~KBmb0 z4Zoy#z==N9y$K^?-}oeNfts%qpTqg6T^c%;R^*;XHm~8jlMa~8IbeQ0!*7tcy7l&Y zd3&?GJ*BpH{B*Z#B(GUOZkJ7NHtIuMCvhX76suj@uZ>EdS}%*O*a*&pcsv!NY4z584whAh>3zMg0hS-C>o6*E)b$(VvKQ#Xw;xaC5aj|MnPO~2UlF8 zxI{-W32H=ez2{V&9)@}I{@?fezUR63KF_@cJ-`0dsrA&-)m7Eq@K`Cxt~Gm!ZeD)a zIRpLG_I}S1@}ro)gi9O#!9uv!_8H=>g zM;^dl7!2)kWkWAOsKlGM0e$-6iNi(7P`kk*1${mZEjsd2*)|K^zErx606cvA@s_qR zbmI0FVg-d&Fk5ftEEGuD-jc(&Z|yw=0W^$b$yd5<1U!8E__n$_+yUM=C=u zf@rU;p1BPk1U!+W6Qw$Utv4~xOB0^Bt`x)S_c z3+;Rc@lL2M<99;a?m+%B#+1i0?QN8F+B#tWfRyHAsbBYMRS zcu596^CCZpa}IF#R1~f4cu2cApfDOXKf`0C0ydMD(HS)w#^AzQ=@_l`JOrZ>UxhC$ z02OKX31Q&%7XfNH_%(F(5>$}9mR^Depdq;3i?PG&_bVI0_JB(Jy)a(G_cxx<;%f$r ziXK{Z#-Uut%Z@M(DC&3&Eb#GlrDG|aVFVqEwduFgz!Tb7!v2x>saLL2wUq5iz-~;xmT_`oQ{Px9au(#7s_Q9WtSBhn}d=de?<>n zVDtkK_N{g-W!hxA1HEA0O5kC{c3RJq@T$uaLj(9^+?mSe+Py*=D58;eFDOcYHQ2pa zDA|YDJB2~3OrNl41nz)ZffiAfg(>g?YE*Y+Q$X-m=>(_(w1F^>D)!xmN7mUVuV9M# z=QF@%NhrAiPwt)sW|aiiZ=xN~!nrk*Tms1nU^eimJH!rO@P=^Ud0w!xMaMVTENism zNgNizC!8E%Wf-zvQ1}*#6l+hkpJP$9Z^uGd1(SDHLvcVQDsjXwF3S}=pa@WJpr(f| zpc+)N?0I?iq1MMUDy%YYsh*d!FkmNYh0?Kvl>u%Rhf?88&Y6v4Ndcryz;wdKmW1F>rg+X`5In-O>e4I`DWkFzM@UP+s;~UZR`rkz@549;`^cp*4m6)O6>tw z4>3ZycEM4Iye#_!Bt)^V!U1+SLLJ7jHYP{Apa_Ie-%*F)M5bL(3@JK*tv$O;vG1Yt zf}`l*Al6@aio(#rvZFYbqDVi1ZK={u>v*Zs%JGsm{Wi7^(TsW0?j9k2U37Q>!s#r)48c2wOhCA4$sZy?O- zLOII?XvqPH4I~l;WpHlA1khICT!!{n9B+U&E1VTRSD+{8jEOUJ^gL>4t%V;Y+;(WZ z&@RPU>v*%$L9ws05hkUwAxgCA6__?Hd*_!7(_aJJ%AnvU)+x=vrJ~X?*xO|3N_5%$ zd+cx%rKx})oe_RQ;F~*|QsZE_GsHVRmGMV-0}R}`*ny5NLw$x&V1^aq3TF5B7Hiq~ zeEyS+JMFS-tBd4@rm&-Brh-jC87D)48F!vnj$^O2(#)@gd11xAd-ll=#y}=|Svgo! zeM|=L>I7?tWCh!HV{~V-HW|UZG`5pAl_M6CF&5i-VR0#OiE%r;q342g}Fxsk&?$9k7tzn)U z7XA9cd^=2uL99X9M|qstX8}J-%pNltox8KxUEvpQY>c?ct+EaD!EJ1zJYi&_V>vN? z1XN0K&|f%x^D%rnO5wVzQz<9`wi2N(@Y|>OwHxUk7?wL7VLAhbH_R)$7SZi1?|+qW zM~>4twg+Hp#t$BxhF(*#Aw}Lp9PlC z=|g^D@bwA!@6=#$13!gt5d@bA6d(?O%~2@F!*%Ep%oNym&Vyv`ZH;MWs)B66<>{~o zn+M8x6a&R+RJg)t)XU&rN{ibXy2HG%EG5=AOH-~G2e)92gG=GVB!HTdW17PD;QyGW z06Jlz(hX+AG|)%jckGx_J+y4X70zM$3a83Cple7m^bVk0Q)7Z}XXAsLsm9f~i0pb) z;mTWQ3|^?}8MFJPj7M;RZ__Cop2*8MEH6f7@e4k?r0<1gn78dscF~Gnwu8QdH=s4e zGY>eM?(jsXa4UhI?tEOD@dziOV7>}d!fO|t>A9Mq@}in_P_}Ho46b7QUBvkAv@tsN zjXx+1czHEEaC)$zAQWbeuz^J(WmYguwjek`m#)Ou;`u2LE(Ljp&PIkkK3RRit*o%) zCo9+lg|2MC%7(092P0a^!Aee6IowJK3q){O!kb79*3uzNo^Q z1oC!?{&u3(n!iJ}8&LjxHvDg^+#^p2!r6?%AfR+6lOD=BKo00m1T_M}|%%%b24P z@Ihlg<-S{3VS=F${oL{MGEio)ybF+_3xntB{gmy4!w|9?W$A(|b*Kq#!5#3EtyST` zyTmF>%RIA>)A&IJG50=3ne81$&b(PTx@`E&d2q1tF4Qbo+E^T#9q4 zMD@a=7&vbTKRp`3yYS$=5uP^$t)+K-yABp6P$72N+Tg4Ps7Y-weoK$dNWw)ygJW+U zUJY=se)CG_3xkJ@U`5~o-*ZXGnT$0p!yCf$bj$(naL%;16+sT zSpeMl*8$(fjoaDI8s|Z!!}(T4wx$z&jTb+AE2~>ff>h(B`cy&C2XJpbPzIkDj2JN( zzOk7;DA*51ii*C4dmW+4Mh^^d!EY^NGH8B#v2E`SSoPpRAsOygblB$tksB9c5t>R0 z%RMMt3oFF1d9%z2T^-+bD(OWt$}bx>Fjj79i0Lg>x2C$7UaIue#F%p}qpG~Le>T)*c z?AN+b`@G!Oy3lulkBtG|dI4{Wfr@bn-oI&F{uuiTTqlK92MEx-=Cc>tnF_An^$0$a z)3g&lAukWYw|kE6n z0{d#gFT@E8vWJyWfDfKJ)$KiI^@45Sykb0m_s!dCADifuhUuOW$?>qd1`Qlv5{&6( zrEk3O0MZX{7&D$^C#kN+>HaJ*Q@U{;2I9gBoLvO(WbuLZ9hjX^=rV4@bH*p$;-)#c z2|Irq_JmpCo-mkMfiH$<98!WrvV%JKhhjhMEkDF|y=8dqgzY0%ip4Oa4NG%y^LPSY zz!{WXUUW<1^@J;N^(T zo__uOtzyqP|6gQe0u?*2M*Axgiv2Tc6pBR|sQq?=zjev`*`Lh|i?J7itWRj)-U`eL zg@=$rYvD84p|5>2L*K#|7eb!^d4V=>Xgc3C9|%HtlSt@G<`TjK4)1gbeTBZB)eGaf z6j(J62prTD!+dpIAtXpO!wJ6PD0}LynCmO6D$alxz{mt^#k}93iw^X(T?lM?b2wQ5 zCo>vW+dhK6+X_CV0=EK(@62&2ltHHbGj6r>&w!V)^f>O{qb$g}$RF-x!ToSV&j_sDt;;L9qVmMh+~JO1HVVMs)7k;KPooP&GVRYtepN5Wn?Q=O4GLTgq zc{5iyQZs{>fV5t4|9wpVeN6v-O#gjK|9wjT{dAuG`|1B{=|60i{yF!h^y3*% zKc4aQ;~7u?ock>O2#|gR^Yklr)bK1w>4&1(G6M=1%G4#3m1%bv-1E{@Kxrz?OEV3$ zKYb`GK*>L>?ZF1yxmqRusPM-fe>C_Lj6Y%cqlYp>&roI@Y7mkSL771$x2kxV*@qUZ~$2}2z@hk4#lt$DLPADoRjSUe!XGpZcjjiEcBJ4vxpgpBS9fDaA`@Jt5<&0QB${1i2#d%SH}=r+)qIp`pfiaidQ zau8v9Szplt_98ogwi8ENp|o)Wavtcyh*fz#+DdoRY84+Vqq~<6kZ+wv2#%@gs~6{ z7lKnP@}lB0l@|o*0LMrb{CuE+pGnX@=i0+D0-EgHP-wDq!^6P-(=-SN@bg@bs|q=8 zs6c!@H!F?fvRsZ|7jj%*0Z3hvF8$EI_DqTlc*NoDKlDz)tQt}8l=zv0K>g2WQa=TD zyq$kC_cLnopMV{2@n}b9U>9ccOJ|9J4r$nL1+vZz7<2~65P-2hA&_?sab{gx4rt(C z^>rWgbszP0AN6(rztPuy(${^`*L~90{r`P^8U9gUbMF7EzR*s^HDb~i+F9xg?ds`k z&V6%zA*<6DGNv}tm#HhQ*B@fNg;^HtPfO;pioFVMNT9t~VS97=!l3;qaaTUCdP3fOuR8|)$3@*?s;8tyg5@a@w zwTi~}Fh~yUQ3%_i{EHsg8Kx<^$ts(((y8me72UK-MK^mEnnD@axI&ly0CfTOdPO(? zFciR7C<7a7;00S?84Q;2eM#TO@Ttnc#wxIJ2OAaIC>2Vl#wj~6ME{J6xv(9C$82M0 zWfos!873N22mz*4flC+zE5LJO8Q%YKQ|BHtn^7ZA>QG%|XJ{Io^Qml*P2-fF_{iSd z60l48lSg8m(hm3WD7f5-%Tpf1c7tMA@G5@`J$2CoE5iU?Hhi-lLKqK|1n_E8-^OzI z^kFvc>xK-Zc)_U)p1Q#1wTvPaCh;^Ru^mNXSS|T)4PrTp{{*pJWd>5ykqzIYRg~xy z$6*GD$1Y{;lx7UviK^fg(w_!t@V4ip2m8*!EuxvV%9sZ>IZO!mxRQJBxMi8-7;f?& zLSoSB{Jl-Z`LRJLEV#P5@U zlT=lEBsg1$qyvzYPR7^Q@U|2}fp4*b1Og3_8;xk072<0A!V@+NAM;Z|orAZ7s34oJ zxT6qKg?En{o-CNo3DOyNv49q*flCNWugm^*C7xzalpDY1!G%HiI!rX&P#YI;yBLUD z2d_=@fQp9`rSRhlo)+Y?V0=Mu_&@@C@ETqyhU+Hy31+8fZ{8YxFocXSy>QG=0~b;N ze2)?&6J8k!+xS>IP34mn6art%RY4d9;KumfbF)IMQ*m~XhfxD71{rfy0&az0i;n4z zcwolIpx3_XA9I~HffJ@rdpKdbgb9kFuEtyCZ*ZfxT4DN>KRnWtRJLV!JT_u<;`AzMFj=Js{FVS^@V;|WK7~!U&891EL)xx)TwV_ zdM(yKnEc7|Q}LQoFM76)#6x)=Y#u(_tjh&A>Ity2ND=p3Cwak!1#JgBxPSDZnaLUo z7TTL%h~(i5%b;Q;$;^5Z_Ayo-dssaItdz4X2h_7oo1=%f-?FEcjqV`%7cH}8HSSYs z@`-5%^<$3$iMEkRdEtqc@dj^jO800B4c}1r)kzjkUAGIplv$C<>h%=l6iV@b&6L8{ z8Zd1L`w<2c#t^0vt|8n;RV7!32n~t@LCb} zBMcy%K&U62Pxv|ER>FORw+a6wd`0MRp2yRaumfQ~!XboX31bLn6Mjaxif|9%DMBM* zHKEf59-j+gCqj2ZkuZ>OEMYX^bi(OUM7SzqIq*{onvDZ#tdQV;L~|qz{MKkaP!Vgt_9y{ z;Xcno{=Egyx8McDrSds!Auk~=rRS7|ywrkUuy9{)!LM8J3gXt3zq=N4qXmCt!K;W% z`uW>JUSlDDWg!(T=E}6yd(KfBi@R5E^!s{65{QM8;N%zu3W<7ll;3AhxKu0G{hzS`x1vc z9A<(o+=mgD(l?*D)F0&#m-L@Yyb*<$Ph3h*DRC+PRm3}!dzYm={hf$wh)ePq;yp;d zlDHIp0dW<{D~NX>F3;iNyAt;xjvF@7#1O}=GiWl2Oa1do;*Ggj$R{rKpO*b)p@sW$ z;!^lE#HISBT*lKU>BpUTON!4je9QjLvVXE{-W&dPZ|AQ(1W)%O#iIc*Uqar2s z2@@wqL`Fr#0qVn(Bf{gz8SrF7Byh=M;zUDCEIJ^Ii4&v4lMUv4dQ^lVF-fw4aN{I0 zabi^Xq*xv@ggYZP+Ay(?DLtIOYr*l+BQ%gMLsI{KfJsrwhNRdCgJhqQ5FQshIUy>N zSx8dMm?|M^26qMLkx_9`hA6=cEJRTd1`ig5_Hgb67VY5}{}FeYsEM-6us!VEL@QHjx#Ga)Q4 z5d^AaL%1O}LNz%hJSmdN!cb`mlk40~$MOfQfPD%U7)io-@o{y52TK=Wkx|j%DRBl> zL}G&ERTUAJn4FTt(i(B zj7`?Zg-1liMD68DXdQZKPD+GB2ho{-zg3Aof2tK zB}Exhk`h=kh56}(u#uxj`?FMloR_PqR@CSJ95B{@sb2E}iIS)gmKdK9tHL^z9E-Ig ztWHV1rI;5grq5D7{-b&>!s5dd!Y4;X{wJkcy8B0^VtjRa{TI#EX}_L3N&gmlHg^r~ zBWEUr$3xSIO^7wbLeDWPDoGWcn52^Gg(MF*M5V?W%&Nb+D+tF_dH%=fOz!@x#9_Yw zMUVd>{Ce%(5R()Y9%1*tz%b?Bgi;Olrq;>7S7;jz?>n(POAVJ`;#$=W!mYo-9;gzSeT zMMW`d;_pWp#)ikGa61%`{U~#Lystrfe^WE`NrDCm9nvT${n*3=zf|-p2vhidt09Kp z&sQXH9Fs6LA#p~6Dk?Q1N{{ZjYa#XDxSs^g!rU#!kMBvsG~j{bXhggpc7ekdj)rjH z_}Cr}J2;%+kQ1UEa=iaW8IBtz8HS5~5wZSZxVW7R?Qpz_V?;dA9>*YP56|B-t|jh6 zJQxuDj3oO}gyR4){7^VBZXAwbIPq|(;LyX-296{+Fs*5DU|Q1&=K-R91{@g9d^phm zGB~=y@eT3yfSAsWa9}*&!GZ36h6B@e1`d>8h6ClHpg;)BBVHu-4v_A#*l0jY$+?_1Y9rl+}FBv8D5+a#S1;HmV$q%mA z!AXe`QOU{w9G(=eicT>6e;04a_x6ITnLGLS_2&~uTX6S6E+0*(A-RMX4s*H35stYH z_;q1FAw?xDCw~R|xVygzL&*Pf!Z2&@UkZQCTkc*8M?y(1@#_}pUSp9?U*c^n?9;yH z@f8x*5W278_GyF_gzl@ky>#8v6VE5CB6MFv{s}7x-Pe*mp>*9`Nj#shkWl^&cQ56$ z{&nnMudk7Cr8B_Q&j8oictGhYDP3d#lYhKE$C>%Vt7|`q{C~&ayZ?p1I2aj3Ks1nWA0Ex<}pYu@jvHN4_6*caTJ7=4B^DEaZNb1 zR~+xujb||LX#SJlFpMO~dx9{zo_{Gt|Jnach#CDyL%O6CV5xDf{U`st1|>l%B)?cw zq}cy+`cs(}c%8!#c+7Pn{B!&mpVZsALD~&)4M_%_CPCahMUjx38UK)`e-01*MnD*- zNdt@!-5@m73zl;{XeI^XhycdxR{fHy%PW>wlmPGR2LJWPuk}+H3E^OkO@uO=1iz{O zkWLH>&3_Y~d5$s7sLlGVpsq}?rcI|>Wj?+&ANNiIIcfwArd+y~Apd9mp{*YBoCt1l zgSV>3o$-zQq+*xxG1eYHd#Atls_AKD8U}Dr-*?*LE-vQ zYz~Kwj7|25Fl3Gz2De0`69awxeZeWa_Kr-f8(B+sh$9onzyyPI>njM(XbDEE*9RxY z#YW78(K}s4M@J>a$0oo$Qer|-lp!WD65aii`_b&K(-a@`fwzz7{@-2y({|VkdFTKP zUe~ME^Zxs9!WzO?gu(_cw;_}hIuSM{R1vxodJy^&1`~cr7)BUL7(*CGs3$ZKrV`F3 zOe366m`RvJxRP)q;rE16_`8VjCp=78N?1W?B&;E{`IhTLPN*bQ5qc2f7zd4xcralI zVHjZyp`I|6FpV&WFqbf&u!OLJu!>N=k*7~d=t8I>bR~2r^dQs_>Ij1gLkPnNV+d0T za|m+@rSS8K7ZR2dRuI+@$~W=!stEfL4kpwQh7o2G<`RxdNf3hIE_5{9_l|?P=+QAL z!jPm`VN|$509j=COn96qkt3D|xJyP$aGSu-&=%}tQj(Ye&cQ$PhxQOoN)oYv@C0E< z)FdG&JPF!u65vcB0OAiwi4(LblZ8=HdSN(BkPl0oF8D@8pmzcMz+CW5^q0g=zz+OJ z!~jAVv3UOoVX!s};XrD^K4o%BGEERcn1-nMNl{5C00ZGCB7->0tua0m*9HkfFdS%t zf_g_r_MXYYMIH&Jrz!}H3QuN&L2E&$8x$Wu2uJYTjAH#O_=i3h@9{?i$3%{UU+j=Z z!^k29a0t7mfu7h^0TKIU9OdzFx&J!O!$~%|;NjtXNSz%7OX1@zOr2k}=ke9q@p$pd zT4#su0w4vL?jaEJB)}lxs6#DWM-Y)?3Iiygh*%a{z{!B4z@Hv)IJ+(j!Z6Uobl|>V zk0r~)Php{AI6NM_Dq%c4?_f>w;(QP{JboO*a>L_i#m_8wI_muM^x)NuR|uXiK5pRi zR6HD>P8>txC`C#yjxHn{?vAIwzP%Pwi6)p3&x7EvH|R7HerKBH2W{}Lr=VhP(4ER; zgD$yiouCs2LG1DHiz89VL_w*z31dLN+_-P%?O(!v#3l3~F5zI}5^5~u!4~o`3%TAx z?mujZ5StJ!4ATx15}@6HbA8;s&)SnDj7<%^3PXJ>zC7)HgR_D4Tym8!jIW?eG6L<{D5z?W_Oi3iAj2 zufF|1GaZcb{-?kBFhghgSKoa)%g3ivLfZr=`!! zn7?4*qRgyM;Uk+%mgX$`{EOvZuJ~%@*Q-{qS^Lep-1Qs2-MDG_vq=?tG9cfcl-8xum1p#frC6@%}1>X zp9C8Kq9@11PMI1PpOC1ZmXvHrnLZt|NqnR{~zmL z>+R#~H{^Ytf56bdpkc#YG2$}-oO*j<_iA(p*CB&POyp*`KFQ=S1uF0UOAdYKN zXpF>Law=32m-bE75SR8P3Hy0@;93wGIdNEDU`9#&9pWy;rG05C;wqB65^qo3op=Z0 z9>hBm*AVYSTt~b!@nGUzh=&mGN<56XG|-75j%!S4^u&8`Dx?zcNj#0X8}Uryy@}@# z?@xRs@d3nhiF**wBR-ILK5@Qk4&_f=P4YtG8sa6ywZuz_`w%ZD?n}Ia_z>bo;_nl$ zBJNMThIjyR;a6V%Ly60YOXE8w@!=$QAuf#vRm8`V+?BXA{&Oe(0m(gxOLr0);&Vx^ zBQB#3Aegun@i5}n#P!5&h)d&ETjFUXZ$LbUxE=9a;&S5o#O)2$FC@7W@lxUq ziB}MBM7)Z)g1B&i>sv`&NxU&}X*}M9xHKMjCaxm)O^Le`Z$?~0ygBh;;x5F)h_@uJ zC*F#98u8Y|bBMPgo=dzf@qFU%5HBR&j(90?74Zt?e?oYgmcmQ#si25JmO5%aURm6u8cPBoaxQ2Kz@nGU3iH8v% zOI%NU9Pu>b9}v$W9z{Ht_*CNg#N&t;5>F>yN?b+*kP6~9#HIUeJK|L&x0ePihqyi* zh%1RZ5mymc5_c!=Ok6{}De++9&54H*Z$(^Bye;ue;ysD4B<@K(pE!JqjG02>KEz9j zPbF?7E~5ce4RIUd@?xG}JK`?H?TNb*cOdRT+=;l3cq`%|#65}YiBBb-MqEY%v>f6# z#B+(;5zi-XPrQ)01MyPgPQ)vSw<2Ce+>^L)nCDkU13V>h8{#VBcEsI@+Y{FicOV{2 z+=+M?@m9q3#65{;5|`0{aV2qk;(5d!h!+rdB3?qg74dT7p2Vw&%cKG25uRUr;!5HU z#8t#w5qBrxc`-sf8u$Pf8qs_f8r&Qe^>6m zT=GxcDETK|Bf0O%-OGm>KYLnQb8xceB%J@Hh@J@HJ* zy$5%{Qj!zTljMWByg-r@FOlRLE-#nl#Ela7o}JmyPKmaLshwI^Ja6S|b&U>Ospl}n2>xskD%1n;C9MIs5I~v^QfF>D2;5dyC zXYJwThv0%EcZVwmXksBJXi~@@&X%J|Hsy=Q7sqD*alaqu(Ujill+PHNBM*m}S~O9V zu6PPJ95jJuD*40R5NKk^Kd$GanM&@bQh3R*%K%LZg=?Vr^%TxziU(Ka(csDenyH{c zH1Q_AaCto0Pp15#zENYi9|1Ljdk472&^NBfmjB`a*y>9^(W;&S(pY~YYIOZw2g8}A6QS_Ahp!YA$AOJv?)BSx0pUD zJgmQ%Kk6nRH5lI*v+_cHd9(ehr~$0k7@wqH+-rp8C&iET+znDE-FISrM=t3P>pjLN z8@QJ4Yq1?*{%H9TT+d?s1NaRDW}y0q?Zdp@U^{UGUsAr%og365soteBz0~np z%zqun_GRuK+nF2GQYl}2_t6kjxnaA*d`RhzXZZ{=nA!_pU#v?XUXL)g5OUA^6K_+w;PnUlE2+Kl z{-I8u!18b2KcM?yvwDL18wED?>o;%Lb^VxmJMdwBEx&H^dREu|c|G$s>D#>CnER9T z<_Bp z(lAd~psC&Pbd55llcy`tEFDf+_;df$|8DP2-|@&4A^ES>Q%mZ)pFJbqtO{o(Nk znfd`K{<{7U_STfbc6Sx-*Be|)6Cb_h(7(((5Vr->Vhe^0!I_;KR$a<1>siMtTrN8FY85#k=i zcM;bSzeGHQcq#E1;?g)dm3Se^Gl`!ko<{kzC%%&8WyJG{|3KY$WbNd^>Sh;x~zV5dVU>j(7#}5aPcOk0E}Bcq;K*#50LsBfgUO z4dQvkuMjUFew27Hwa1RcOGq9?Tw2$Z)oLwe<~jb;x!}>B%Vk9 zdl8pk<@!t}o>#nIJ&m_6D zE;@jCCds9B$d!~{Cz7uuxpaS#PxkXI4 zD$0)+@fwmZB(5a6Cvo|8u8;Y|3n)H!;w~g#OWc(>pS6R1IK)#(t|LB%xU?^&3Gon; zuOJ>nd^GV?;$IOj{e`E`nRq727ZW$`=kor*K@fzZJlAOYCPF(&QPj3kEDw4M#?m}`tn*h%{Q+W+0xhu&R5ceSd z9dRA;>BK{buOTk%=kd2B9z*i+l7EtSAf8I{NaC5q4-j8TyqI_%@qFS1#0!X*5I;%0 zocJ-~a*DqdaU;n;BreVC-yvQ@@^uO;^sUu)taBws~5hWJOs zOUZp-;;AH`MO@maq9LA1@=uA^kbe*2D@mS4T=oaFt8yO8`F;_k#h zCax#R9!orgcp~u_;?~4diQgukNj!)6O5*E@=Mn#rcmeUP#7l?|Azn^gPn^%o z;*+!7@cZ0wxPLe2lVEn&oJZ1XhjgDEMXOU1kA+!ubN5qdHARw7rBxG&$H6SWx%)Vn zfiveg*I~{RVfMkCPqUEYEUCF1XF1KeG|Mf;KhrF~INQl*10&4l0l5wTjRUz90qwon!eA=}x9KKG2vjW`kb(#p1o-r+Mpk+xgqXnKg(1P`Fsr4 ze#t$~zu?ok<~#z*tUkAt*Y}T4A)CAB&nBS_kFT!0IiGAQKh9%J^@j6!cvjdvyaZGE zak;eWD21;#(LO$IrJe+5bGUK@JfuV52*P&uf`sC|| z(yBAAJL5W?w93lYp;6yb{p9njb@fN$Qa{8w{z~!T{A--4K5}_Hdln2`@O6;7^zn6? zx^~IeE$g29;_FZ5att5aEjN5#TUyn|bz;oFw0e#l+iSR~{_=G|X*HX#uVcR;>5H#( z)U{X6rPX)7{_X}d)>6OC*Uu)K^u^b^rkdIZUstM2zqIZn*&ug=-b2zKUmu%l>c{!I zqO_Wh>*~1fD6O*Nx;3uP)wM^yJ}9lGqa4?rq}Y&SKZw8F@O3S7Id5-ua^&%*`p4J* z@Ru9DE-dXn;QJBG>knTil6EPe9OE~4kKxz#2Yel`E&eU#FIKN$`CV{Hb}KKfcaamma>3Q`detugeeT_$&Fx^-pQH zg|x1WZ+ejAeEmQQ0q67ank0oFt&f2ow;V|EN$m&U=7oD1 zxP-57{Ok3Q+b4tG|H(bKH@|-J^*kwd%rDkgDYeLPy%*ndAf*S>fG+rzo3GQ>>6^dd z!<^%~zqCsQ_i*^2R2Y|oa@O5Kp_Y2>@;s$j@>Oc5C0ln$^&1(<;HP?^1y?K85 zy8d)X1vh;Cy)Hd`y#V_Y-ow;!-hw19`R6>wlpfCUjSk#!o^0wLI5(KCpM1T)E`IVR z2zMPvTQQ=HaGP*!sx2329{yn%Qo5$+Iw$1e&-QLRxbef{$K4|MI6rdt>wdO}&n=4n zytbKVoG)aJVvM<&OYBwvr;UYR6A z4@GApyKaa$;j;0s&L5YZ*8g>LYCG}a+KGIieK+Av@#!f}`=j4&H?WtrmEQ-QYtBs@ z8*r%jsvW#nVrj2DxzCSVXSZs)W<{c+APy_Sxj-`^!e|{P|_K#Y@AMcgOgJ_D-Mv(qiM1onyDGd%r>dABTQaG4Xnu z!`3%dnk!54O4C|R?HB?3c{~E&U2$w&#zpUdyWt(ST=7y4{x#|8@5>C$LJJ#iZu=Z8{eJ8HXV>6}ucsZ~-26en64zex7KsV|trA+I zwl(i|(QLN~PI{;IV%hR;znmT)y`q=rhHGjN+11QmDzFbk$8uYM4N*?#UHuV=;V$6Y!jOM!nNw})9OvVTINo> zw11Ir>>OD_t#a+yRx?vJE)|4ZKkglzk~!~-=IYZ^2kpwbvFIE55Wk=pr_I-1FZ-g? zP3K23?p=L%ef_64eNXWTtB}VdVy%6pdpT#2X83LOw%WuQL0#_cbii7s>@#MY z{kagQ%_qBrk6o0}W=hfDi&CZ=eS4mLKUe#Wt^ByyU|+7W9qxSci1+w(@gT5HTr^58q&+8jQ%_1wks z>Bst)IgPpcMb6q|tMX0`?d&qWs-b;m-gASp-Jn;Eb-!<45)rDrfATA1?ByervnH z%_l!LrH5P3`QtV#|7uq%Xl5PzeNusON@lt8_m!thj*Q7tj@c7hdf~v!kUsMYtXuj8 zS`R!P)be}bNW0sGfiu^q9rrAA`{6-NhxiGrvOGR6Z#nZ!()6RL>-PRWbC~t=yR7RF zg!K

SM*iXWE681+4`$+gQ3Hzdiy(E;Au-7GU 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�~7 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 From 566e549f3ac8ffc77972458ab6e6ce96922a4ed5 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 08:02:50 +0700 Subject: [PATCH 32/72] Add seconds on the result output --- SharpHPatchZ.Program/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharpHPatchZ.Program/Program.cs b/SharpHPatchZ.Program/Program.cs index d569022..c2c7c14 100644 --- a/SharpHPatchZ.Program/Program.cs +++ b/SharpHPatchZ.Program/Program.cs @@ -105,7 +105,7 @@ public static int Main(params string[] args) } Console.WriteLine(); - Console.WriteLine($"Patch completed in: {Stopwatch.Elapsed:c}"); + Console.WriteLine($"Patch completed in: {Stopwatch.Elapsed:c} ({Stopwatch.Elapsed.TotalSeconds} seconds)"); (Stream, bool) CreatePatchStream(long position) { From 226f73dab080bf56a139313afea0345370e7530e Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 08:03:20 +0700 Subject: [PATCH 33/72] Use larger queueCapacity and switch to BigArrayPool for prefetch stream --- SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs b/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs index 9768b83..a17a768 100644 --- a/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs +++ b/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs @@ -17,13 +17,13 @@ internal sealed class PrefetchedReadStream : Stream private readonly Task _producer; private ExceptionDispatchInfo? _producerFailure; - private BufferChunk? _current; - private int _currentOffset; - private int _disposed; + private BufferChunk? _current; + private int _currentOffset; + private int _disposed; public PrefetchedReadStream(Stream source, int bufferSize, - int queueCapacity = 2) + int queueCapacity = 4) { _source = source ?? throw new ArgumentNullException(nameof(source)); if (!source.CanRead) @@ -120,7 +120,7 @@ private int ReadCore(Span destination) private void Produce() { #if !NET6_0_OR_GREATER - byte[] streamBuffer = System.Buffers.ArrayPool.Shared.Rent(_bufferSize); + byte[] streamBuffer = BigArrayPool.Shared.Rent(_bufferSize); #endif try { @@ -161,7 +161,7 @@ private void Produce() finally { #if !NET6_0_OR_GREATER - System.Buffers.ArrayPool.Shared.Return(streamBuffer); + BigArrayPool.Shared.Return(streamBuffer); #endif try { From a614f8c5d972342a7eb18ed3a6bbbf8a6e7b9bdf Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 08:03:59 +0700 Subject: [PATCH 34/72] Exclude Zstd from being used on PrefetchedStream Due to unknown crash. Need further check --- SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs index 95f03f6..90b5325 100644 --- a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs +++ b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs @@ -114,7 +114,7 @@ private static void EnableParallelDecompression(HDiffCompression compType, Stream[] streams, ChunkSizeInfo[] sizes) { - if (compType is HDiffCompression.Uncompressed) + if (compType is HDiffCompression.Uncompressed or HDiffCompression.Zstd) { return; } From ad08043c78a92c24b6da7e5afce87df471435260 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 08:04:14 +0700 Subject: [PATCH 35/72] Increase buffers on PatchOptions.BigBuffer --- SharpHPatchZ/PatchOptions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SharpHPatchZ/PatchOptions.cs b/SharpHPatchZ/PatchOptions.cs index e7673f3..360f3ed 100644 --- a/SharpHPatchZ/PatchOptions.cs +++ b/SharpHPatchZ/PatchOptions.cs @@ -16,9 +16,9 @@ public struct PatchOptions() public static readonly PatchOptions BigBuffer = Default with { - ReaderBufferSize = 1 << 20, + ReaderBufferSize = 4 << 20, CopyBufferSize = 128 << 10, - PatchWorkerBufferSize = 16 << 20 + PatchWorkerBufferSize = 32 << 20 }; public static readonly PatchOptions SmallBuffer = Default with From 2a39bb647a5251f70fd0e95f85355cb29939dfaa Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 08:04:45 +0700 Subject: [PATCH 36/72] Run CopySimilarFilesContext task in parallel + Also use native memory buffer on .NET 6 or above --- ...3DerivedPatcher.CopySimilarFilesContext.cs | 62 +++++++++++++++---- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs index 0f39cbd..8590604 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs @@ -1,5 +1,7 @@ -using System.IO; +using System; +using System.IO; using System.Threading; +using System.Threading.Tasks; using SharpHPatchZ.Extension; namespace SharpHPatchZ.Patch; @@ -24,15 +26,50 @@ public void RunCopy(PatcherBase patcher, int bufferSize = options.CopyBufferSize; if (bufferSize <= 0) bufferSize = 16 << 10; - byte[] buffer = BigArrayPool.Shared.Rent(bufferSize); - try + token.ThrowIfCancellationRequested(); + int count = InputPaths.Length; + + Parallel.For(0, count, new ParallelOptions + { + MaxDegreeOfParallelism = (int)options.ParallelThreads + }, i => { - int count = InputPaths.Length; token.ThrowIfCancellationRequested(); - for (int i = 0; i < count; i++) +#if NET6_0_OR_GREATER + unsafe + { + void* bufferP = MemoryAlloc.Alloc(bufferSize); + var buffer = new Span(bufferP, bufferSize); + try + { + string inputPath = Path.GetFullPath(Path.Combine(InputDir, InputPaths[i])); + string outputPath = Path.GetFullPath(Path.Combine(OutputDir, OutputPaths[i])); + + if (Path.GetDirectoryName(outputPath) is { } outputDir) + Directory.CreateDirectory(outputDir); + + using FileStream inputStream = File.Open(inputPath, FileMode.Open, FileAccess.Read); + using FileStream outputStream = File.Create(outputPath, bufferSize); + int read; + + while ((read = inputStream.Read(buffer)) > 0) + { + token.ThrowIfCancellationRequested(); + + outputStream.Write(buffer[..read]); + patcher.AdvanceProgress(read); + } + } + finally + { + MemoryAlloc.FreeRaw(bufferP); + } + } +#else + byte[] buffer = BigArrayPool.Shared.Rent(bufferSize); + try { - token.ThrowIfCancellationRequested(); string inputPath = Path.GetFullPath(Path.Combine(InputDir, InputPaths[i])); string outputPath = Path.GetFullPath(Path.Combine(OutputDir, OutputPaths[i])); @@ -42,18 +79,21 @@ public void RunCopy(PatcherBase patcher, using FileStream inputStream = File.Open(inputPath, FileMode.Open, FileAccess.Read); using FileStream outputStream = File.Create(outputPath, bufferSize); int read; + while ((read = inputStream.Read(buffer, 0, bufferSize)) > 0) { token.ThrowIfCancellationRequested(); + outputStream.Write(buffer, 0, read); patcher.AdvanceProgress(read); } } - } - finally - { - BigArrayPool.Shared.Return(buffer); - } + finally + { + BigArrayPool.Shared.Return(buffer); + } +#endif + }); } } } From 2bfdb39b30bfda77101f20defebe3fcce3e0895e Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 08:35:32 +0700 Subject: [PATCH 37/72] Revert PrefetchedReadStream queue capacity --- SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs b/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs index a17a768..6fdd5c4 100644 --- a/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs +++ b/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs @@ -23,7 +23,7 @@ internal sealed class PrefetchedReadStream : Stream public PrefetchedReadStream(Stream source, int bufferSize, - int queueCapacity = 4) + int queueCapacity = 2) { _source = source ?? throw new ArgumentNullException(nameof(source)); if (!source.CanRead) From b77cdfb5427bc0df4507b68da5533521a2984275 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 08:35:42 +0700 Subject: [PATCH 38/72] Update HDiff13DerivedPatcher.CorePatcher.cs --- SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs index a9857be..e5037f8 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs @@ -209,9 +209,10 @@ private void ProduceWork(ReadOnlySpan covers, Action emit, CancellationToken token) { - RleDecoder rleDecoder = new(_rleCtrlReader, _rleCodeReader); - using NativeMemoryBuffer skipBuffer = new(Math.Min(bufferSize, 64 << 10)); - using PatchWorkBuilder workBuilder = new(bufferSize, emit); + RleDecoder rleDecoder = new(_rleCtrlReader, _rleCodeReader); + using NativeMemoryBuffer skipBuffer = new(Math.Min(bufferSize, 64 << 10)); + using PatchWorkBuilder workBuilder = new(bufferSize, emit); + long newPosition = 0; for (int coverIndex = 0; coverIndex < covers.Length; coverIndex++) { From 30bda1f0b5db051dfabfe9a319c6eecba444c090 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 09:17:42 +0700 Subject: [PATCH 39/72] Reduce copy across buffers --- SharpHPatchZ/Extension/NativeMemoryBuffer.cs | 2 +- .../Extension/NativeMemoryBufferPool.cs | 71 ++++++ .../IO/Compression/Lzma/LZ/LzOutWindow.cs | 11 +- .../IO/Compression/Lzma/LzmaInputStream.cs | 19 +- .../Compression/Lzma/RangeCoder/RangeCoder.cs | 2 +- .../IO/Reader/BittableStreamReader.cs | 38 ++++ .../IO/Reader/PrefetchedReadStream.cs | 27 ++- .../IO/Reader/RandomMergedStreamWrapper.cs | 162 +++++++++----- ...3DerivedPatcher.CopySimilarFilesContext.cs | 106 ++++----- .../HDiff13DerivedPatcher.CorePatcher.cs | 202 +++++++++++------- SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs | 29 ++- .../Patch/PatcherFactory.HDiff13Derived.cs | 106 ++++++--- SharpHPatchZ/PatchOptions.cs | 2 +- 13 files changed, 554 insertions(+), 223 deletions(-) create mode 100644 SharpHPatchZ/Extension/NativeMemoryBufferPool.cs diff --git a/SharpHPatchZ/Extension/NativeMemoryBuffer.cs b/SharpHPatchZ/Extension/NativeMemoryBuffer.cs index ca1f57c..2fa1e19 100644 --- a/SharpHPatchZ/Extension/NativeMemoryBuffer.cs +++ b/SharpHPatchZ/Extension/NativeMemoryBuffer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.CompilerServices; using System.Threading; diff --git a/SharpHPatchZ/Extension/NativeMemoryBufferPool.cs b/SharpHPatchZ/Extension/NativeMemoryBufferPool.cs new file mode 100644 index 0000000..f2f983e --- /dev/null +++ b/SharpHPatchZ/Extension/NativeMemoryBufferPool.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; + +namespace SharpHPatchZ.Extension; + +internal sealed class NativeMemoryBufferPool(int bufferLength) : IDisposable + where T : unmanaged +{ + private readonly object _sync = new(); + private readonly Stack> _buffers = new(); + private bool _disposed; + + public NativeMemoryBuffer Rent() + { + lock (_sync) + { + if (_disposed) + { + throw new ObjectDisposedException(nameof(NativeMemoryBufferPool)); + } + if (_buffers.Count != 0) + { + return _buffers.Pop(); + } + } + + return new NativeMemoryBuffer(bufferLength); + } + + public void Return(NativeMemoryBuffer buffer) + { + if (buffer is null) + { + throw new ArgumentNullException(nameof(buffer)); + } + + if (buffer.Length != bufferLength) + { + buffer.Dispose(); + throw new ArgumentException("The buffer has a different length than this pool.", nameof(buffer)); + } + + lock (_sync) + { + if (!_disposed) + { + _buffers.Push(buffer); + return; + } + } + + buffer.Dispose(); + } + + public void Dispose() + { + lock (_sync) + { + if (_disposed) + { + return; + } + + _disposed = true; + while (_buffers.Count != 0) + { + _buffers.Pop().Dispose(); + } + } + } +} diff --git a/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs b/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs index 7e7bfdc..d49c340 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Buffers; using System.IO; using System.Runtime.CompilerServices; @@ -244,6 +244,9 @@ public int CopyStream(Stream stream, int len) public bool HasPending => _pendingLen > 0; public int Read(byte[] buffer, int offset, int count) + => Read(buffer.AsSpan(offset, count)); + + public int Read(Span buffer) { if (_streamPos >= _pos) { @@ -251,12 +254,12 @@ public int Read(byte[] buffer, int offset, int count) } int size = _pos - _streamPos; - if (size > count) + if (size > buffer.Length) { - size = count; + size = buffer.Length; } - _buffer!.Span.Slice(_streamPos, size).CopyTo(buffer.AsSpan(offset, size)); + _buffer!.Span.Slice(_streamPos, size).CopyTo(buffer); _streamPos += size; if (_streamPos < _windowSize) return size; diff --git a/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs b/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs index 1116f2d..98e300a 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Buffers.Binary; using System.IO; using SharpHPatchZ.IO.Compression.Lzma.LZ; @@ -127,6 +127,14 @@ public override long Position } public override int Read(byte[] buffer, int offset, int count) + => ReadCore(buffer.AsSpan(offset, count)); + +#if NET6_0_OR_GREATER + public override int Read(Span buffer) + => ReadCore(buffer); +#endif + + private int ReadCore(Span buffer) { if (_endReached) { @@ -134,7 +142,7 @@ public override int Read(byte[] buffer, int offset, int count) } int total = 0; - while (total < count) + while (total < buffer.Length) { if (_availableBytes == 0) { @@ -152,7 +160,7 @@ public override int Read(byte[] buffer, int offset, int count) } } - int toProcess = count - total; + int toProcess = buffer.Length - total; if (toProcess > _availableBytes) { toProcess = (int)_availableBytes; @@ -168,9 +176,8 @@ public override int Read(byte[] buffer, int offset, int count) _availableBytes = _outWindow.AvailableBytes; } - int read = _outWindow.Read(buffer, offset, toProcess); + int read = _outWindow.Read(buffer.Slice(total, toProcess)); total += read; - offset += read; _position += read; _availableBytes -= read; @@ -284,4 +291,4 @@ private void DecodeChunkHeader() public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); public byte[] Properties { get; } -} \ No newline at end of file +} diff --git a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs index c203b02..8fdbfbf 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Buffers; using System.IO; using System.Runtime.CompilerServices; diff --git a/SharpHPatchZ/IO/Reader/BittableStreamReader.cs b/SharpHPatchZ/IO/Reader/BittableStreamReader.cs index fe0cfb2..73fc5d1 100644 --- a/SharpHPatchZ/IO/Reader/BittableStreamReader.cs +++ b/SharpHPatchZ/IO/Reader/BittableStreamReader.cs @@ -200,6 +200,25 @@ public void ReadBytes(Span buffer) while (!buffer.IsEmpty) { +#if NET6_0_OR_GREATER + int available = _bufferedLength - _offset; + if (available == 0 && buffer.Length >= _backedBuffer.Length) + { + _consumedByteCount += _offset; + _offset = 0; + _bufferedLength = 0; + + int directRead = BackedStream.Read(buffer); + if (directRead == 0) + { + throw new EndOfStreamException("Unable to read beyond the end of the stream."); + } + + _consumedByteCount += directRead; + buffer = buffer[directRead..]; + continue; + } +#endif EnsureBuffered(1); int copyLength = Math.Min(buffer.Length, _bufferedLength - _offset); @@ -235,6 +254,25 @@ public async ValueTask ReadBytesAsync( while (!buffer.IsEmpty) { +#if NET6_0_OR_GREATER + int available = _bufferedLength - _offset; + if (available == 0 && buffer.Length >= _backedBuffer.Length) + { + _consumedByteCount += _offset; + _offset = 0; + _bufferedLength = 0; + + int directRead = await BackedStream.ReadAsync(buffer, token).ConfigureAwait(false); + if (directRead == 0) + { + throw new EndOfStreamException("Unable to read beyond the end of the stream."); + } + + _consumedByteCount += directRead; + buffer = buffer[directRead..]; + continue; + } +#endif await EnsureBufferedAsync(1, token).ConfigureAwait(false); int copyLength = Math.Min(buffer.Length, _bufferedLength - _offset); diff --git a/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs b/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs index 6fdd5c4..b8f896c 100644 --- a/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs +++ b/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.IO; using System.Runtime.ExceptionServices; @@ -13,6 +13,7 @@ internal sealed class PrefetchedReadStream : Stream private readonly Stream _source; private readonly int _bufferSize; private readonly BlockingCollection _queue; + private readonly NativeMemoryBufferPool _bufferPool; private readonly CancellationTokenSource _disposeCancellation = new(); private readonly Task _producer; @@ -34,6 +35,7 @@ public PrefetchedReadStream(Stream source, _bufferSize = bufferSize > 0 ? bufferSize : throw new ArgumentOutOfRangeException(nameof(bufferSize)); + _bufferPool = new NativeMemoryBufferPool(_bufferSize); _queue = new BlockingCollection(queueCapacity > 0 ? queueCapacity : throw new ArgumentOutOfRangeException(nameof(queueCapacity))); @@ -126,7 +128,7 @@ private void Produce() { while (!_disposeCancellation.IsCancellationRequested) { - NativeMemoryBuffer buffer = new(_bufferSize); + NativeMemoryBuffer buffer = _bufferPool.Rent(); try { #if NET6_0_OR_GREATER @@ -137,15 +139,16 @@ private void Produce() #endif if (read == 0) { - buffer.Dispose(); + _bufferPool.Return(buffer); break; } - _queue.Add(new BufferChunk(buffer, read), _disposeCancellation.Token); + _queue.Add(new BufferChunk(buffer, read, _bufferPool), + _disposeCancellation.Token); } catch { - buffer.Dispose(); + _bufferPool.Return(buffer); throw; } } @@ -203,6 +206,7 @@ protected override void Dispose(bool disposing) chunk.Dispose(); } + _bufferPool.Dispose(); _queue.Dispose(); _disposeCancellation.Dispose(); } @@ -223,12 +227,21 @@ private void ThrowIfDisposed() } } - private sealed class BufferChunk(NativeMemoryBuffer buffer, int length) : IDisposable + private sealed class BufferChunk(NativeMemoryBuffer buffer, + int length, + NativeMemoryBufferPool bufferPool) : IDisposable { + private int _disposed; + public NativeMemoryBuffer Buffer { get; } = buffer; public int Length { get; } = length; public void Dispose() - => Buffer.Dispose(); + { + if (Interlocked.Exchange(ref _disposed, 1) == 0) + { + bufferPool.Return(Buffer); + } + } } } diff --git a/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs b/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs index 162c259..0bcd62f 100644 --- a/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs +++ b/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs @@ -66,73 +66,94 @@ public RandomMergedStreamWrapper(string[] fileStreams, public void Write(Span buffer, long offset) { - _lifetimeLock.EnterReadLock(); - try - { - ThrowIfDisposed(); - ValidateOffset(offset); - - if (buffer.Length > Length - offset) - { - throw new EndOfStreamException("The write exceeds the merged stream length."); - } + StreamCursor cursor = default; + Write(buffer, offset, ref cursor); + } - while (!buffer.IsEmpty) - { - int streamIndex = FindStreamIndex(offset); - long streamStart = GetStreamStart(streamIndex); - int writeLength = (int)Math.Min(buffer.Length, _fileStreamEnds[streamIndex] - offset); + internal void Write(Span buffer, long offset, ref StreamCursor cursor) + { + using AccessScope access = AcquireAccess(); + access.Write(buffer, offset, ref cursor); + } - FileStream stream = GetFileStream(streamIndex); - RandomAccessCompat.Write(stream.SafeFileHandle!, - buffer[..writeLength], - offset - streamStart); + private void WriteCore(Span buffer, long offset, ref StreamCursor cursor) + { + ValidateOffset(offset); - buffer = buffer[writeLength..]; - offset += writeLength; - } + if (buffer.Length > Length - offset) + { + throw new EndOfStreamException("The write exceeds the merged stream length."); } - finally + + while (!buffer.IsEmpty) { - _lifetimeLock.ExitReadLock(); + int streamIndex = FindStreamIndex(offset, cursor.StreamIndex); + long streamStart = GetStreamStart(streamIndex); + int writeLength = (int)Math.Min(buffer.Length, _fileStreamEnds[streamIndex] - offset); + + FileStream stream = GetFileStream(streamIndex, ref cursor); + RandomAccessCompat.Write(stream.SafeFileHandle!, + buffer[..writeLength], + offset - streamStart); + + buffer = buffer[writeLength..]; + offset += writeLength; } } public int Read(Span buffer, long offset) { - _lifetimeLock.EnterReadLock(); - try - { - ThrowIfDisposed(); - ValidateOffset(offset); + StreamCursor cursor = default; + return Read(buffer, offset, ref cursor); + } - int totalRead = 0; - while (!buffer.IsEmpty && offset < Length) - { - int streamIndex = FindStreamIndex(offset); - long streamStart = GetStreamStart(streamIndex); - int readLength = (int)Math.Min(buffer.Length, _fileStreamEnds[streamIndex] - offset); + internal int Read(Span buffer, long offset, ref StreamCursor cursor) + { + using AccessScope access = AcquireAccess(); + return access.Read(buffer, offset, ref cursor); + } - FileStream stream = GetFileStream(streamIndex); - int read = RandomAccessCompat.Read(stream.SafeFileHandle!, - buffer[..readLength], - offset - streamStart); + private int ReadCore(Span buffer, long offset, ref StreamCursor cursor) + { + ValidateOffset(offset); - if (read == 0) - { - throw new EndOfStreamException("An underlying file ended before its declared length."); - } + int totalRead = 0; + while (!buffer.IsEmpty && offset < Length) + { + int streamIndex = FindStreamIndex(offset, cursor.StreamIndex); + long streamStart = GetStreamStart(streamIndex); + int readLength = (int)Math.Min(buffer.Length, _fileStreamEnds[streamIndex] - offset); - totalRead += read; - offset += read; - buffer = buffer[read..]; + FileStream stream = GetFileStream(streamIndex, ref cursor); + int read = RandomAccessCompat.Read(stream.SafeFileHandle!, + buffer[..readLength], + offset - streamStart); + + if (read == 0) + { + throw new EndOfStreamException("An underlying file ended before its declared length."); } - return totalRead; + totalRead += read; + offset += read; + buffer = buffer[read..]; } - finally + + return totalRead; + } + + internal AccessScope AcquireAccess() + { + _lifetimeLock.EnterReadLock(); + try + { + ThrowIfDisposed(); + return new AccessScope(this); + } + catch { _lifetimeLock.ExitReadLock(); + throw; } } @@ -177,6 +198,19 @@ private FileStream GetFileStream(int streamIndex) return lazyStream.Value; } + private FileStream GetFileStream(int streamIndex, ref StreamCursor cursor) + { + if (cursor.Stream is not null && cursor.StreamIndex == streamIndex) + { + return cursor.Stream; + } + + FileStream stream = GetFileStream(streamIndex); + cursor.StreamIndex = streamIndex; + cursor.Stream = stream; + return stream; + } + private void CreateOutputFiles() { long streamStart = 0; @@ -223,6 +257,20 @@ private int FindStreamIndex(long offset) return low; } + private int FindStreamIndex(long offset, int cachedStreamIndex) + { + if ((uint)cachedStreamIndex < (uint)_fileStreamEnds.Length) + { + long streamStart = GetStreamStart(cachedStreamIndex); + if (offset >= streamStart && offset < _fileStreamEnds[cachedStreamIndex]) + { + return cachedStreamIndex; + } + } + + return FindStreamIndex(offset); + } + private long GetStreamStart(int streamIndex) => streamIndex == 0 ? 0 : _fileStreamEnds[streamIndex - 1]; @@ -241,4 +289,22 @@ private void ThrowIfDisposed() throw new ObjectDisposedException(nameof(RandomMergedStreamWrapper)); } } + + internal struct StreamCursor + { + public int StreamIndex; + public FileStream? Stream; + } + + internal readonly ref struct AccessScope(RandomMergedStreamWrapper owner) + { + public int Read(Span buffer, long offset, ref StreamCursor cursor) + => owner.ReadCore(buffer, offset, ref cursor); + + public void Write(Span buffer, long offset, ref StreamCursor cursor) + => owner.WriteCore(buffer, offset, ref cursor); + + public void Dispose() + => owner._lifetimeLock.ExitReadLock(); + } } diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs index 8590604..498bb3a 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs @@ -21,6 +21,7 @@ private class CopySimilarFilesContext(string inputDir, public void RunCopy(PatcherBase patcher, PatchOptions options, + int workerCount, CancellationToken token) { int bufferSize = options.CopyBufferSize; @@ -29,71 +30,72 @@ public void RunCopy(PatcherBase patcher, token.ThrowIfCancellationRequested(); int count = InputPaths.Length; - Parallel.For(0, count, new ParallelOptions + ParallelOptions parallelOptions = new() { - MaxDegreeOfParallelism = (int)options.ParallelThreads - }, i => + CancellationToken = token, + MaxDegreeOfParallelism = workerCount + }; + +#if NET6_0_OR_GREATER + Parallel.For(0, + count, + parallelOptions, + () => new NativeMemoryBuffer(bufferSize), + (i, _, nativeBuffer) => { token.ThrowIfCancellationRequested(); + Span buffer = nativeBuffer.Span; + string inputPath = Path.GetFullPath(Path.Combine(InputDir, InputPaths[i])); + string outputPath = Path.GetFullPath(Path.Combine(OutputDir, OutputPaths[i])); -#if NET6_0_OR_GREATER - unsafe + if (Path.GetDirectoryName(outputPath) is { } outputDir) + Directory.CreateDirectory(outputDir); + + using FileStream inputStream = File.Open(inputPath, FileMode.Open, FileAccess.Read); + using FileStream outputStream = File.Create(outputPath, bufferSize); + int read; + + while ((read = inputStream.Read(buffer)) > 0) { - void* bufferP = MemoryAlloc.Alloc(bufferSize); - var buffer = new Span(bufferP, bufferSize); - try - { - string inputPath = Path.GetFullPath(Path.Combine(InputDir, InputPaths[i])); - string outputPath = Path.GetFullPath(Path.Combine(OutputDir, OutputPaths[i])); - - if (Path.GetDirectoryName(outputPath) is { } outputDir) - Directory.CreateDirectory(outputDir); - - using FileStream inputStream = File.Open(inputPath, FileMode.Open, FileAccess.Read); - using FileStream outputStream = File.Create(outputPath, bufferSize); - int read; - - while ((read = inputStream.Read(buffer)) > 0) - { - token.ThrowIfCancellationRequested(); - - outputStream.Write(buffer[..read]); - patcher.AdvanceProgress(read); - } - } - finally - { - MemoryAlloc.FreeRaw(bufferP); - } + token.ThrowIfCancellationRequested(); + + outputStream.Write(buffer[..read]); + patcher.AdvanceProgress(read); } -#else - byte[] buffer = BigArrayPool.Shared.Rent(bufferSize); - try - { - string inputPath = Path.GetFullPath(Path.Combine(InputDir, InputPaths[i])); - string outputPath = Path.GetFullPath(Path.Combine(OutputDir, OutputPaths[i])); - if (Path.GetDirectoryName(outputPath) is { } outputDir) - Directory.CreateDirectory(outputDir); + return nativeBuffer; + }, + nativeBuffer => nativeBuffer.Dispose()); +#else + Parallel.For(0, + count, + parallelOptions, + () => BigArrayPool.Shared.Rent(bufferSize), + (i, _, buffer) => + { + token.ThrowIfCancellationRequested(); + string inputPath = Path.GetFullPath(Path.Combine(InputDir, InputPaths[i])); + string outputPath = Path.GetFullPath(Path.Combine(OutputDir, OutputPaths[i])); - using FileStream inputStream = File.Open(inputPath, FileMode.Open, FileAccess.Read); - using FileStream outputStream = File.Create(outputPath, bufferSize); - int read; + if (Path.GetDirectoryName(outputPath) is { } outputDir) + Directory.CreateDirectory(outputDir); - while ((read = inputStream.Read(buffer, 0, bufferSize)) > 0) - { - token.ThrowIfCancellationRequested(); + using FileStream inputStream = File.Open(inputPath, FileMode.Open, FileAccess.Read); + using FileStream outputStream = File.Create(outputPath, bufferSize); + int read; - outputStream.Write(buffer, 0, read); - patcher.AdvanceProgress(read); - } - } - finally + while ((read = inputStream.Read(buffer, 0, bufferSize)) > 0) { - BigArrayPool.Shared.Return(buffer); + token.ThrowIfCancellationRequested(); + + outputStream.Write(buffer, 0, read); + patcher.AdvanceProgress(read); } + + return buffer; + }, + buffer => BigArrayPool.Shared.Return(buffer)); #endif - }); } } } diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs index e5037f8..613878b 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs @@ -1,6 +1,6 @@ -using System; +using System; +using System.Buffers; using System.Collections.Concurrent; -using System.Collections.Generic; using System.IO; #if NET6_0_OR_GREATER using System.Numerics; @@ -41,7 +41,7 @@ private unsafe void StartCorePatcher(CancellationToken token) int bufferSize = Options.PatchWorkerBufferSize > 0 ? Options.PatchWorkerBufferSize : DefaultPatchBufferSize; - int workerCount = GetWorkerCount(Options.ParallelThreads); + int workerCount = _coreWorkerCount; if (workerCount == 1) { @@ -57,31 +57,18 @@ private unsafe void StartCorePatcher(CancellationToken token) } } - private static int GetWorkerCount(uint requestedWorkerCount) - { - if (requestedWorkerCount == 0) - { - return Math.Max(1, Environment.ProcessorCount); - } - - if (requestedWorkerCount > int.MaxValue) - { - throw new ArgumentOutOfRangeException(nameof(PatchOptions.ParallelThreads)); - } - - return (int)requestedWorkerCount; - } - private void RunSequential(ReadOnlySpan covers, PatchMetadata patchMetadata, int bufferSize, CancellationToken token) { - using NativeMemoryBuffer oldBuffer = new(bufferSize); + using NativeMemoryBufferPool workBufferPool = new(bufferSize); + using PatchWorkerContext workerContext = new(bufferSize); ProduceWork(covers, patchMetadata.DiffNewSize, bufferSize, - item => ProcessWorkItem(item, oldBuffer, token), + workBufferPool, + item => ProcessWorkItem(item, workerContext, workBufferPool, token), token); ValidateDataReaders(patchMetadata); } @@ -99,6 +86,7 @@ private void RunParallel(NativeMemoryBuffer covers, using CancellationTokenSource linkedCancellation = CancellationTokenSource.CreateLinkedTokenSource(token); using BlockingCollection workQueue = new(queueCapacity); + using NativeMemoryBufferPool workBufferPool = new(bufferSize); ExceptionDispatchInfo? producerFailure = null; ExceptionDispatchInfo? workerFailure = null; @@ -112,7 +100,11 @@ private void RunParallel(NativeMemoryBuffer covers, ProduceWork(covers.Span, patchMetadata.DiffNewSize, bufferSize, - item => AddWorkItem(workQueue, item, linkedCancellation.Token), + workBufferPool, + item => AddWorkItem(workQueue, + item, + workBufferPool, + linkedCancellation.Token), linkedCancellation.Token); ValidateDataReaders(patchMetadata); } @@ -139,12 +131,15 @@ private void RunParallel(NativeMemoryBuffer covers, CancellationToken = linkedCancellation.Token, MaxDegreeOfParallelism = workerCount }, - () => new NativeMemoryBuffer(bufferSize), - (item, _, oldBuffer) => + () => new PatchWorkerContext(bufferSize), + (item, _, workerContext) => { try { - ProcessWorkItem(item, oldBuffer, linkedCancellation.Token); + ProcessWorkItem(item, + workerContext, + workBufferPool, + linkedCancellation.Token); } catch (Exception exception) { @@ -156,9 +151,9 @@ private void RunParallel(NativeMemoryBuffer covers, throw; } - return oldBuffer; + return workerContext; }, - oldBuffer => oldBuffer.Dispose()); + workerContext => workerContext.Dispose()); } catch (Exception exception) { @@ -171,7 +166,7 @@ private void RunParallel(NativeMemoryBuffer covers, while (workQueue.TryTake(out PatchWorkItem abandonedItem)) { - abandonedItem.Buffer.Dispose(); + ReleaseWorkItem(abandonedItem, workBufferPool); } } @@ -190,6 +185,7 @@ private void RunParallel(NativeMemoryBuffer covers, private static void AddWorkItem(BlockingCollection queue, PatchWorkItem item, + NativeMemoryBufferPool workBufferPool, CancellationToken token) { try @@ -198,7 +194,7 @@ private static void AddWorkItem(BlockingCollection queue, } catch { - item.Buffer.Dispose(); + ReleaseWorkItem(item, workBufferPool); throw; } } @@ -206,12 +202,13 @@ private static void AddWorkItem(BlockingCollection queue, private void ProduceWork(ReadOnlySpan covers, long newDataSize, int bufferSize, + NativeMemoryBufferPool workBufferPool, Action emit, CancellationToken token) { RleDecoder rleDecoder = new(_rleCtrlReader, _rleCodeReader); using NativeMemoryBuffer skipBuffer = new(Math.Min(bufferSize, 64 << 10)); - using PatchWorkBuilder workBuilder = new(bufferSize, emit); + using PatchWorkBuilder workBuilder = new(bufferSize, workBufferPool, emit); long newPosition = 0; for (int coverIndex = 0; coverIndex < covers.Length; coverIndex++) @@ -292,21 +289,25 @@ private static void ProduceCover(RleCoverInfo cover, } } - private void ProcessWorkItem(PatchWorkItem item, - NativeMemoryBuffer oldBuffer, - CancellationToken token) + private void ProcessWorkItem(PatchWorkItem item, + PatchWorkerContext workerContext, + NativeMemoryBufferPool workBufferPool, + CancellationToken token) { try { token.ThrowIfCancellationRequested(); if (item.CoverSegments is { } coverSegments) { - for (int segmentIndex = 0; segmentIndex < coverSegments.Count; segmentIndex++) + using RandomMergedStreamWrapper.AccessScope inputAccess = InputStream!.AcquireAccess(); + for (int segmentIndex = 0; segmentIndex < item.CoverSegmentCount; segmentIndex++) { token.ThrowIfCancellationRequested(); CoverSegment segment = coverSegments[segmentIndex]; - Span oldData = oldBuffer.Span[..segment.Length]; - int read = InputStream!.Read(oldData, segment.OldPosition); + Span oldData = workerContext.OldBuffer.Span[..segment.Length]; + int read = inputAccess.Read(oldData, + segment.OldPosition, + ref workerContext.InputCursor); if (read != segment.Length) { throw new EndOfStreamException("The old-data stream ended while processing a cover."); @@ -315,35 +316,46 @@ private void ProcessWorkItem(PatchWorkItem item, #if NET6_0_OR_GREATER Span rleData = item.Buffer.Span.Slice(segment.BufferOffset, segment.Length); - AddRle(oldData, rleData, Options.UseSIMD); + AddRle(rleData, oldData, Options.UseSIMD); #else Span rleData = item.Buffer.Span.Slice(segment.BufferOffset, segment.Length); - AddRle(oldData, rleData); + AddRle(rleData, oldData); #endif - oldData.CopyTo(rleData); } } - OutputStream!.Write(item.Buffer.Span[..item.Length], item.OutputPosition); + OutputStream!.Write(item.Buffer.Span[..item.Length], + item.OutputPosition, + ref workerContext.OutputCursor); AdvanceProgress(item.Length); } finally { - item.Buffer.Dispose(); + ReleaseWorkItem(item, workBufferPool); + } + } + + private static void ReleaseWorkItem(PatchWorkItem item, + NativeMemoryBufferPool workBufferPool) + { + workBufferPool.Return(item.Buffer); + if (item.CoverSegments is { } coverSegments) + { + ArrayPool.Shared.Return(coverSegments); } } #if NET6_0_OR_GREATER private static void AddRle(Span destination, - ReadOnlySpan rle, + ReadOnlySpan addend, bool useSimd) #else private static void AddRle(Span destination, - ReadOnlySpan rle) + ReadOnlySpan addend) #endif { - if (destination.Length != rle.Length) + if (destination.Length != addend.Length) { throw new ArgumentException("The old-data and RLE buffers must have the same length."); } @@ -358,12 +370,14 @@ private static void AddRle(Span destination, if (vectorEnd != 0) { ref byte destinationRef = ref destination[0]; - ref byte rleRef = ref Unsafe.AsRef(in rle[0]); + ref byte addendRef = ref Unsafe.AsRef(in addend[0]); for (; index < vectorEnd; index += vectorLength) { - var oldVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref destinationRef, index)); - var rleVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref rleRef, index)); - Vector256 result = Avx2.Add(oldVector, rleVector); + var destinationVector = Unsafe.ReadUnaligned>( + ref Unsafe.Add(ref destinationRef, index)); + var addendVector = Unsafe.ReadUnaligned>( + ref Unsafe.Add(ref addendRef, index)); + Vector256 result = Avx2.Add(destinationVector, addendVector); Unsafe.WriteUnaligned(ref Unsafe.Add(ref destinationRef, index), result); } } @@ -375,12 +389,14 @@ private static void AddRle(Span destination, if (vectorEnd != 0) { ref byte destinationRef = ref destination[0]; - ref byte rleRef = ref Unsafe.AsRef(in rle[0]); + ref byte addendRef = ref Unsafe.AsRef(in addend[0]); for (; index < vectorEnd; index += vectorLength) { - var oldVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref destinationRef, index)); - var rleVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref rleRef, index)); - Vector128 result = Sse2.Add(oldVector, rleVector); + var destinationVector = Unsafe.ReadUnaligned>( + ref Unsafe.Add(ref destinationRef, index)); + var addendVector = Unsafe.ReadUnaligned>( + ref Unsafe.Add(ref addendRef, index)); + Vector128 result = Sse2.Add(destinationVector, addendVector); Unsafe.WriteUnaligned(ref Unsafe.Add(ref destinationRef, index), result); } } @@ -391,15 +407,15 @@ private static void AddRle(Span destination, int vectorEnd = length - length % vectorLength; for (; index < vectorEnd; index += vectorLength) { - Vector oldVector = new(destination.Slice(index, vectorLength)); - Vector rleVector = new(rle.Slice(index, vectorLength)); - (oldVector + rleVector).CopyTo(destination.Slice(index, vectorLength)); + Vector destinationVector = new(destination.Slice(index, vectorLength)); + Vector addendVector = new(addend.Slice(index, vectorLength)); + (destinationVector + addendVector).CopyTo(destination.Slice(index, vectorLength)); } } #endif for (; index < length; index++) { - destination[index] = unchecked((byte)(destination[index] + rle[index])); + destination[index] = unchecked((byte)(destination[index] + addend[index])); } } @@ -441,12 +457,14 @@ private static void ValidateReaderOffset(BittableStreamReader reader, private readonly struct PatchWorkItem(NativeMemoryBuffer buffer, int length, long outputPosition, - List? coverSegments) + CoverSegment[]? coverSegments, + int coverSegmentCount) { public NativeMemoryBuffer Buffer { get; } = buffer; public int Length { get; } = length; public long OutputPosition { get; } = outputPosition; - public List? CoverSegments { get; } = coverSegments; + public CoverSegment[]? CoverSegments { get; } = coverSegments; + public int CoverSegmentCount { get; } = coverSegmentCount; } private readonly struct CoverSegment(int bufferOffset, @@ -458,16 +476,19 @@ private readonly struct CoverSegment(int bufferOffset, public long OldPosition { get; } = oldPosition; } - private sealed class PatchWorkBuilder(int bufferSize, - Action emit) : IDisposable + private sealed class PatchWorkBuilder(int bufferSize, + NativeMemoryBufferPool bufferPool, + Action emit) : IDisposable { private readonly int _bufferSize = bufferSize; + private readonly NativeMemoryBufferPool _bufferPool = bufferPool; private readonly Action _emit = emit; private NativeMemoryBuffer? _buffer; private int _length; private long _outputPosition; - private List? _coverSegments; + private CoverSegment[]? _coverSegments; + private int _coverSegmentCount; public Span GetWritableSpan(long outputPosition, long requestedLength, @@ -480,7 +501,7 @@ public Span GetWritableSpan(long outputPosition, if (_buffer is null) { - _buffer = new NativeMemoryBuffer(_bufferSize); + _buffer = _bufferPool.Rent(); _outputPosition = outputPosition; } else if (outputPosition != _outputPosition + _length) @@ -497,27 +518,45 @@ public void CommitNewData(int length) public void CommitCover(int length, long oldPosition) { - _coverSegments ??= []; - - int segmentCount = _coverSegments.Count; - if (segmentCount > 0) + if (_coverSegmentCount > 0) { - CoverSegment previous = _coverSegments[segmentCount - 1]; + CoverSegment previous = _coverSegments![_coverSegmentCount - 1]; if (previous.BufferOffset + previous.Length == _length && previous.OldPosition + previous.Length == oldPosition) { - _coverSegments[segmentCount - 1] = new CoverSegment(previous.BufferOffset, - previous.Length + length, - previous.OldPosition); + _coverSegments[_coverSegmentCount - 1] = new CoverSegment(previous.BufferOffset, + previous.Length + length, + previous.OldPosition); _length += length; return; } } - _coverSegments.Add(new CoverSegment(_length, length, oldPosition)); + EnsureCoverSegmentCapacity(); + _coverSegments![_coverSegmentCount++] = new CoverSegment(_length, length, oldPosition); _length += length; } + private void EnsureCoverSegmentCapacity() + { + if (_coverSegments is null) + { + _coverSegments = ArrayPool.Shared.Rent(16); + return; + } + + if (_coverSegmentCount != _coverSegments.Length) + { + return; + } + + CoverSegment[] replacement = ArrayPool.Shared.Rent( + checked(_coverSegments.Length * 2)); + _coverSegments.AsSpan(0, _coverSegmentCount).CopyTo(replacement); + ArrayPool.Shared.Return(_coverSegments); + _coverSegments = replacement; + } + public void Flush() { if (_buffer is null || _length == 0) @@ -528,10 +567,12 @@ public void Flush() PatchWorkItem item = new(_buffer, _length, _outputPosition, - _coverSegments); + _coverSegments, + _coverSegmentCount); _buffer = null; _length = 0; _coverSegments = null; + _coverSegmentCount = 0; _emit(item); } @@ -539,12 +580,29 @@ public void Dispose() { if (_buffer is not null) { - _buffer.Dispose(); + _bufferPool.Return(_buffer); _buffer = null; } + + if (_coverSegments is not null) + { + ArrayPool.Shared.Return(_coverSegments); + _coverSegments = null; + _coverSegmentCount = 0; + } } } + private sealed class PatchWorkerContext(int bufferSize) : IDisposable + { + public NativeMemoryBuffer OldBuffer { get; } = new(bufferSize); + public RandomMergedStreamWrapper.StreamCursor InputCursor; + public RandomMergedStreamWrapper.StreamCursor OutputCursor; + + public void Dispose() + => OldBuffer.Dispose(); + } + private sealed class RleDecoder(BittableStreamReader controlReader, BittableStreamReader codeReader) { diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs index 3f0919a..eff6256 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs @@ -18,13 +18,21 @@ internal sealed partial class HDiff13DerivedPatcher( BittableStreamReader newDataReader, HDiffInfo info, PatchOptions options, - ProgressCallback progressCallback) + ProgressCallback progressCallback, + int coreWorkerCount, + int copyWorkerCount, + bool runCopyConcurrently) : PatcherBase(info, options, progressCallback) { private readonly BittableStreamReader _coverReader = coverReader; private readonly BittableStreamReader _rleCtrlReader = rleCtrlReader; private readonly BittableStreamReader _rleCodeReader = rleCodeReader; private readonly BittableStreamReader _newDataReader = newDataReader; + private readonly int _coreWorkerCount = coreWorkerCount > 0 + ? coreWorkerCount + : throw new ArgumentOutOfRangeException(nameof(coreWorkerCount)); + private readonly int _copyWorkerCount = copyWorkerCount; + private readonly bool _runCopyConcurrently = runCopyConcurrently; private CopySimilarFilesContext? _copySimilarFilesContext; @@ -35,6 +43,16 @@ public override void StartPatch(string inputPath, string outputPath, Cancellatio // Start both CopyOver and CorePatch routine if context is not null. if (_copySimilarFilesContext != null) { + if (!_runCopyConcurrently) + { + _copySimilarFilesContext.RunCopy(this, + Options, + _copyWorkerCount, + token); + StartCorePatcher(token); + return; + } + TaskCompletionSource copyOverTcs = new(null!, TaskCreationOptions.RunContinuationsAsynchronously); TaskCompletionSource corePatcherTcs = new(null!, TaskCreationOptions.RunContinuationsAsynchronously); @@ -42,7 +60,10 @@ public override void StartPatch(string inputPath, string outputPath, Cancellatio { try { - _copySimilarFilesContext.RunCopy(this, Options, token); + _copySimilarFilesContext.RunCopy(this, + Options, + _copyWorkerCount, + token); copyOverTcs.SetResult(true); } catch (OperationCanceledException) when (token.IsCancellationRequested) @@ -69,9 +90,9 @@ public override void StartPatch(string inputPath, string outputPath, Cancellatio catch (OperationCanceledException) when (token.IsCancellationRequested) { #if NET6_0_OR_GREATER - copyOverTcs.SetCanceled(token); + corePatcherTcs.SetCanceled(token); #else - copyOverTcs.SetCanceled(); + corePatcherTcs.SetCanceled(); #endif } catch (Exception ex) diff --git a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs index 90b5325..4ce530b 100644 --- a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs +++ b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs @@ -20,6 +20,7 @@ public static HDiff13DerivedPatcher Create( PatchOptions options, ProgressCallback progressCallback) { + ExecutionPlan executionPlan = CreateExecutionPlan(info.MagicType, options); GetPatchContextInfos(ref info, out long coverDataOffset, out long rleCtrlDataOffset, @@ -32,7 +33,8 @@ public static HDiff13DerivedPatcher Create( createPatchStream(coverDataOffset), createPatchStream(rleCtrlDataOffset), createPatchStream(rleCodeDataOffset), - createPatchStream(newDataOffset)); + createPatchStream(newDataOffset), + executionPlan.MaxDecompressionWorkers); return new HDiff13DerivedPatcher(context.Cover, context.RleCtrl, @@ -40,7 +42,10 @@ public static HDiff13DerivedPatcher Create( context.NewData, info, options, - progressCallback); + progressCallback, + executionPlan.PatchWorkerBudget - context.DecompressionWorkers, + executionPlan.CopyWorkers, + executionPlan.RunCopyConcurrently); } public static async Task CreateAsync( @@ -50,6 +55,7 @@ public static async Task CreateAsync( ProgressCallback progressCallback, CancellationToken token) { + ExecutionPlan executionPlan = CreateExecutionPlan(info.MagicType, options); GetPatchContextInfos(ref info, out long coverDataOffset, out long rleCtrlDataOffset, @@ -62,7 +68,8 @@ public static async Task CreateAsync( await createPatchStreamAsync(coverDataOffset, token), await createPatchStreamAsync(rleCtrlDataOffset, token), await createPatchStreamAsync(rleCodeDataOffset, token), - await createPatchStreamAsync(newDataOffset, token)); + await createPatchStreamAsync(newDataOffset, token), + executionPlan.MaxDecompressionWorkers); return new HDiff13DerivedPatcher(context.Cover, context.RleCtrl, @@ -70,7 +77,10 @@ await createPatchStreamAsync(rleCodeDataOffset, token), context.NewData, info, options, - progressCallback); + progressCallback, + executionPlan.PatchWorkerBudget - context.DecompressionWorkers, + executionPlan.CopyWorkers, + executionPlan.RunCopyConcurrently); } private static unsafe DiffReadersContext CreateReaderContext(HDiffCompression compType, @@ -79,7 +89,8 @@ private static unsafe DiffReadersContext CreateReaderContext(HDiffCompression ValueTuple coverCtx, ValueTuple rleCtrlCtx, ValueTuple rleCodeCtx, - ValueTuple newDataCtx) + ValueTuple newDataCtx, + int maxDecompressionWorkers) { int bufferSize = options.ReaderBufferSize; @@ -96,39 +107,38 @@ private static unsafe DiffReadersContext CreateReaderContext(HDiffCompression CreateDecompressionStream(compType, newDataSize, newDataCtx) ]; - EnableParallelDecompression(compType, - options, - decompressedStreams, - [coverSize, controlSize, codeSize, newDataSize]); + int decompressionWorkers = EnableParallelDecompression( + compType, + options, + decompressedStreams, + [coverSize, controlSize, codeSize, newDataSize], + maxDecompressionWorkers); BittableStreamReader coverReader = new(decompressedStreams[0], bufferSize, coverCtx.Item2); BittableStreamReader rleCtrlReader = new(decompressedStreams[1], bufferSize, rleCtrlCtx.Item2); BittableStreamReader rleCodeReader = new(decompressedStreams[2], bufferSize, rleCodeCtx.Item2); BittableStreamReader newDataReader = new(decompressedStreams[3], bufferSize, newDataCtx.Item2); - return new DiffReadersContext(coverReader, rleCtrlReader, rleCodeReader, newDataReader); + return new DiffReadersContext(coverReader, + rleCtrlReader, + rleCodeReader, + newDataReader, + decompressionWorkers); } - private static void EnableParallelDecompression(HDiffCompression compType, - PatchOptions options, - Stream[] streams, - ChunkSizeInfo[] sizes) + private static int EnableParallelDecompression(HDiffCompression compType, + PatchOptions options, + Stream[] streams, + ChunkSizeInfo[] sizes, + int maxWorkers) { - if (compType is HDiffCompression.Uncompressed or HDiffCompression.Zstd) + if (maxWorkers == 0 || + compType is HDiffCompression.Uncompressed or HDiffCompression.Zstd) { - return; + return 0; } - int requestedWorkers = options.ParallelThreads == 0 - ? Environment.ProcessorCount - : options.ParallelThreads > int.MaxValue - ? int.MaxValue - : (int)options.ParallelThreads; - int prefetchCount = Math.Min(streams.Length, Math.Max(0, requestedWorkers - 1)); - if (prefetchCount == 0) - { - return; - } + int prefetchCount = Math.Min(streams.Length, maxWorkers); List<(int Index, long CompressedSize)> candidates = new(streams.Length); for (int index = 0; index < sizes.Length; index++) @@ -151,6 +161,42 @@ private static void EnableParallelDecompression(HDiffCompression compType, streams[streamIndex] = new PrefetchedReadStream(streams[streamIndex], prefetchBufferSize); } + + return prefetchCount; + } + + private static ExecutionPlan CreateExecutionPlan(HDiffMagic magicType, + PatchOptions options) + { + int totalWorkers; + if (options.ParallelThreads == 0) + { + totalWorkers = Math.Max(1, Environment.ProcessorCount); + } + else if (options.ParallelThreads > int.MaxValue) + { + throw new ArgumentOutOfRangeException(nameof(PatchOptions.ParallelThreads)); + } + else + { + totalWorkers = (int)options.ParallelThreads; + } + + bool hasCopyStage = magicType != HDiffMagic.HDiff13; + int copyWorkers = hasCopyStage + ? totalWorkers == 1 + ? 1 + : Math.Max(1, totalWorkers / 4) + : 0; + int patchWorkerBudget = hasCopyStage && totalWorkers > 1 + ? totalWorkers - copyWorkers + : totalWorkers; + int maxDecompressionWorkers = Math.Min(4, patchWorkerBudget / 2); + + return new ExecutionPlan(patchWorkerBudget, + copyWorkers, + maxDecompressionWorkers, + hasCopyStage && totalWorkers > 1); } private static Stream CreateDecompressionStream( @@ -186,6 +232,12 @@ private record struct DiffReadersContext( BittableStreamReader Cover, BittableStreamReader RleCtrl, BittableStreamReader RleCode, - BittableStreamReader NewData); + BittableStreamReader NewData, + int DecompressionWorkers); + + private readonly record struct ExecutionPlan(int PatchWorkerBudget, + int CopyWorkers, + int MaxDecompressionWorkers, + bool RunCopyConcurrently); } } diff --git a/SharpHPatchZ/PatchOptions.cs b/SharpHPatchZ/PatchOptions.cs index 360f3ed..9d5b7cc 100644 --- a/SharpHPatchZ/PatchOptions.cs +++ b/SharpHPatchZ/PatchOptions.cs @@ -18,7 +18,7 @@ public struct PatchOptions() { ReaderBufferSize = 4 << 20, CopyBufferSize = 128 << 10, - PatchWorkerBufferSize = 32 << 20 + PatchWorkerBufferSize = 16 << 20 }; public static readonly PatchOptions SmallBuffer = Default with From a9e4b813aa588933178e4ae8bb1736c732d61bf9 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 09:19:34 +0700 Subject: [PATCH 40/72] Update HDiff13DerivedPatcher.CorePatcher.cs --- SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs index 613878b..b25a434 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs @@ -41,9 +41,8 @@ private unsafe void StartCorePatcher(CancellationToken token) int bufferSize = Options.PatchWorkerBufferSize > 0 ? Options.PatchWorkerBufferSize : DefaultPatchBufferSize; - int workerCount = _coreWorkerCount; - if (workerCount == 1) + if (_coreWorkerCount == 1) { RunSequential(rleCoverSpan, patchMetadata, bufferSize, token); } @@ -52,7 +51,7 @@ private unsafe void StartCorePatcher(CancellationToken token) RunParallel(rleCoverBuffer, patchMetadata, bufferSize, - workerCount, + _coreWorkerCount, token); } } From 9562c11818cb9466b35b1b0818bd9f0597e90769 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 21:20:36 +0700 Subject: [PATCH 41/72] Revert "Update HDiff13DerivedPatcher.CorePatcher.cs" This reverts commit a9e4b813aa588933178e4ae8bb1736c732d61bf9. --- SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs index b25a434..613878b 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs @@ -41,8 +41,9 @@ private unsafe void StartCorePatcher(CancellationToken token) int bufferSize = Options.PatchWorkerBufferSize > 0 ? Options.PatchWorkerBufferSize : DefaultPatchBufferSize; + int workerCount = _coreWorkerCount; - if (_coreWorkerCount == 1) + if (workerCount == 1) { RunSequential(rleCoverSpan, patchMetadata, bufferSize, token); } @@ -51,7 +52,7 @@ private unsafe void StartCorePatcher(CancellationToken token) RunParallel(rleCoverBuffer, patchMetadata, bufferSize, - _coreWorkerCount, + workerCount, token); } } From 7a7826fc447063e37f9a3781486540508b9381b9 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 21:20:41 +0700 Subject: [PATCH 42/72] Revert "Reduce copy across buffers" This reverts commit 30bda1f0b5db051dfabfe9a319c6eecba444c090. --- SharpHPatchZ/Extension/NativeMemoryBuffer.cs | 2 +- .../Extension/NativeMemoryBufferPool.cs | 71 ------ .../IO/Compression/Lzma/LZ/LzOutWindow.cs | 11 +- .../IO/Compression/Lzma/LzmaInputStream.cs | 19 +- .../Compression/Lzma/RangeCoder/RangeCoder.cs | 2 +- .../IO/Reader/BittableStreamReader.cs | 38 ---- .../IO/Reader/PrefetchedReadStream.cs | 27 +-- .../IO/Reader/RandomMergedStreamWrapper.cs | 162 +++++--------- ...3DerivedPatcher.CopySimilarFilesContext.cs | 106 +++++---- .../HDiff13DerivedPatcher.CorePatcher.cs | 202 +++++++----------- SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs | 29 +-- .../Patch/PatcherFactory.HDiff13Derived.cs | 106 +++------ SharpHPatchZ/PatchOptions.cs | 2 +- 13 files changed, 223 insertions(+), 554 deletions(-) delete mode 100644 SharpHPatchZ/Extension/NativeMemoryBufferPool.cs diff --git a/SharpHPatchZ/Extension/NativeMemoryBuffer.cs b/SharpHPatchZ/Extension/NativeMemoryBuffer.cs index 2fa1e19..ca1f57c 100644 --- a/SharpHPatchZ/Extension/NativeMemoryBuffer.cs +++ b/SharpHPatchZ/Extension/NativeMemoryBuffer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.CompilerServices; using System.Threading; diff --git a/SharpHPatchZ/Extension/NativeMemoryBufferPool.cs b/SharpHPatchZ/Extension/NativeMemoryBufferPool.cs deleted file mode 100644 index f2f983e..0000000 --- a/SharpHPatchZ/Extension/NativeMemoryBufferPool.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace SharpHPatchZ.Extension; - -internal sealed class NativeMemoryBufferPool(int bufferLength) : IDisposable - where T : unmanaged -{ - private readonly object _sync = new(); - private readonly Stack> _buffers = new(); - private bool _disposed; - - public NativeMemoryBuffer Rent() - { - lock (_sync) - { - if (_disposed) - { - throw new ObjectDisposedException(nameof(NativeMemoryBufferPool)); - } - if (_buffers.Count != 0) - { - return _buffers.Pop(); - } - } - - return new NativeMemoryBuffer(bufferLength); - } - - public void Return(NativeMemoryBuffer buffer) - { - if (buffer is null) - { - throw new ArgumentNullException(nameof(buffer)); - } - - if (buffer.Length != bufferLength) - { - buffer.Dispose(); - throw new ArgumentException("The buffer has a different length than this pool.", nameof(buffer)); - } - - lock (_sync) - { - if (!_disposed) - { - _buffers.Push(buffer); - return; - } - } - - buffer.Dispose(); - } - - public void Dispose() - { - lock (_sync) - { - if (_disposed) - { - return; - } - - _disposed = true; - while (_buffers.Count != 0) - { - _buffers.Pop().Dispose(); - } - } - } -} diff --git a/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs b/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs index d49c340..7e7bfdc 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Buffers; using System.IO; using System.Runtime.CompilerServices; @@ -244,9 +244,6 @@ public int CopyStream(Stream stream, int len) public bool HasPending => _pendingLen > 0; public int Read(byte[] buffer, int offset, int count) - => Read(buffer.AsSpan(offset, count)); - - public int Read(Span buffer) { if (_streamPos >= _pos) { @@ -254,12 +251,12 @@ public int Read(Span buffer) } int size = _pos - _streamPos; - if (size > buffer.Length) + if (size > count) { - size = buffer.Length; + size = count; } - _buffer!.Span.Slice(_streamPos, size).CopyTo(buffer); + _buffer!.Span.Slice(_streamPos, size).CopyTo(buffer.AsSpan(offset, size)); _streamPos += size; if (_streamPos < _windowSize) return size; diff --git a/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs b/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs index 98e300a..1116f2d 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Buffers.Binary; using System.IO; using SharpHPatchZ.IO.Compression.Lzma.LZ; @@ -127,14 +127,6 @@ public override long Position } public override int Read(byte[] buffer, int offset, int count) - => ReadCore(buffer.AsSpan(offset, count)); - -#if NET6_0_OR_GREATER - public override int Read(Span buffer) - => ReadCore(buffer); -#endif - - private int ReadCore(Span buffer) { if (_endReached) { @@ -142,7 +134,7 @@ private int ReadCore(Span buffer) } int total = 0; - while (total < buffer.Length) + while (total < count) { if (_availableBytes == 0) { @@ -160,7 +152,7 @@ private int ReadCore(Span buffer) } } - int toProcess = buffer.Length - total; + int toProcess = count - total; if (toProcess > _availableBytes) { toProcess = (int)_availableBytes; @@ -176,8 +168,9 @@ private int ReadCore(Span buffer) _availableBytes = _outWindow.AvailableBytes; } - int read = _outWindow.Read(buffer.Slice(total, toProcess)); + int read = _outWindow.Read(buffer, offset, toProcess); total += read; + offset += read; _position += read; _availableBytes -= read; @@ -291,4 +284,4 @@ private void DecodeChunkHeader() public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); public byte[] Properties { get; } -} +} \ No newline at end of file diff --git a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs index 8fdbfbf..c203b02 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Buffers; using System.IO; using System.Runtime.CompilerServices; diff --git a/SharpHPatchZ/IO/Reader/BittableStreamReader.cs b/SharpHPatchZ/IO/Reader/BittableStreamReader.cs index 73fc5d1..fe0cfb2 100644 --- a/SharpHPatchZ/IO/Reader/BittableStreamReader.cs +++ b/SharpHPatchZ/IO/Reader/BittableStreamReader.cs @@ -200,25 +200,6 @@ public void ReadBytes(Span buffer) while (!buffer.IsEmpty) { -#if NET6_0_OR_GREATER - int available = _bufferedLength - _offset; - if (available == 0 && buffer.Length >= _backedBuffer.Length) - { - _consumedByteCount += _offset; - _offset = 0; - _bufferedLength = 0; - - int directRead = BackedStream.Read(buffer); - if (directRead == 0) - { - throw new EndOfStreamException("Unable to read beyond the end of the stream."); - } - - _consumedByteCount += directRead; - buffer = buffer[directRead..]; - continue; - } -#endif EnsureBuffered(1); int copyLength = Math.Min(buffer.Length, _bufferedLength - _offset); @@ -254,25 +235,6 @@ public async ValueTask ReadBytesAsync( while (!buffer.IsEmpty) { -#if NET6_0_OR_GREATER - int available = _bufferedLength - _offset; - if (available == 0 && buffer.Length >= _backedBuffer.Length) - { - _consumedByteCount += _offset; - _offset = 0; - _bufferedLength = 0; - - int directRead = await BackedStream.ReadAsync(buffer, token).ConfigureAwait(false); - if (directRead == 0) - { - throw new EndOfStreamException("Unable to read beyond the end of the stream."); - } - - _consumedByteCount += directRead; - buffer = buffer[directRead..]; - continue; - } -#endif await EnsureBufferedAsync(1, token).ConfigureAwait(false); int copyLength = Math.Min(buffer.Length, _bufferedLength - _offset); diff --git a/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs b/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs index b8f896c..6fdd5c4 100644 --- a/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs +++ b/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.IO; using System.Runtime.ExceptionServices; @@ -13,7 +13,6 @@ internal sealed class PrefetchedReadStream : Stream private readonly Stream _source; private readonly int _bufferSize; private readonly BlockingCollection _queue; - private readonly NativeMemoryBufferPool _bufferPool; private readonly CancellationTokenSource _disposeCancellation = new(); private readonly Task _producer; @@ -35,7 +34,6 @@ public PrefetchedReadStream(Stream source, _bufferSize = bufferSize > 0 ? bufferSize : throw new ArgumentOutOfRangeException(nameof(bufferSize)); - _bufferPool = new NativeMemoryBufferPool(_bufferSize); _queue = new BlockingCollection(queueCapacity > 0 ? queueCapacity : throw new ArgumentOutOfRangeException(nameof(queueCapacity))); @@ -128,7 +126,7 @@ private void Produce() { while (!_disposeCancellation.IsCancellationRequested) { - NativeMemoryBuffer buffer = _bufferPool.Rent(); + NativeMemoryBuffer buffer = new(_bufferSize); try { #if NET6_0_OR_GREATER @@ -139,16 +137,15 @@ private void Produce() #endif if (read == 0) { - _bufferPool.Return(buffer); + buffer.Dispose(); break; } - _queue.Add(new BufferChunk(buffer, read, _bufferPool), - _disposeCancellation.Token); + _queue.Add(new BufferChunk(buffer, read), _disposeCancellation.Token); } catch { - _bufferPool.Return(buffer); + buffer.Dispose(); throw; } } @@ -206,7 +203,6 @@ protected override void Dispose(bool disposing) chunk.Dispose(); } - _bufferPool.Dispose(); _queue.Dispose(); _disposeCancellation.Dispose(); } @@ -227,21 +223,12 @@ private void ThrowIfDisposed() } } - private sealed class BufferChunk(NativeMemoryBuffer buffer, - int length, - NativeMemoryBufferPool bufferPool) : IDisposable + private sealed class BufferChunk(NativeMemoryBuffer buffer, int length) : IDisposable { - private int _disposed; - public NativeMemoryBuffer Buffer { get; } = buffer; public int Length { get; } = length; public void Dispose() - { - if (Interlocked.Exchange(ref _disposed, 1) == 0) - { - bufferPool.Return(Buffer); - } - } + => Buffer.Dispose(); } } diff --git a/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs b/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs index 0bcd62f..162c259 100644 --- a/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs +++ b/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs @@ -66,94 +66,73 @@ public RandomMergedStreamWrapper(string[] fileStreams, public void Write(Span buffer, long offset) { - StreamCursor cursor = default; - Write(buffer, offset, ref cursor); - } + _lifetimeLock.EnterReadLock(); + try + { + ThrowIfDisposed(); + ValidateOffset(offset); - internal void Write(Span buffer, long offset, ref StreamCursor cursor) - { - using AccessScope access = AcquireAccess(); - access.Write(buffer, offset, ref cursor); - } + if (buffer.Length > Length - offset) + { + throw new EndOfStreamException("The write exceeds the merged stream length."); + } - private void WriteCore(Span buffer, long offset, ref StreamCursor cursor) - { - ValidateOffset(offset); + while (!buffer.IsEmpty) + { + int streamIndex = FindStreamIndex(offset); + long streamStart = GetStreamStart(streamIndex); + int writeLength = (int)Math.Min(buffer.Length, _fileStreamEnds[streamIndex] - offset); - if (buffer.Length > Length - offset) - { - throw new EndOfStreamException("The write exceeds the merged stream length."); - } + FileStream stream = GetFileStream(streamIndex); + RandomAccessCompat.Write(stream.SafeFileHandle!, + buffer[..writeLength], + offset - streamStart); - while (!buffer.IsEmpty) + buffer = buffer[writeLength..]; + offset += writeLength; + } + } + finally { - int streamIndex = FindStreamIndex(offset, cursor.StreamIndex); - long streamStart = GetStreamStart(streamIndex); - int writeLength = (int)Math.Min(buffer.Length, _fileStreamEnds[streamIndex] - offset); - - FileStream stream = GetFileStream(streamIndex, ref cursor); - RandomAccessCompat.Write(stream.SafeFileHandle!, - buffer[..writeLength], - offset - streamStart); - - buffer = buffer[writeLength..]; - offset += writeLength; + _lifetimeLock.ExitReadLock(); } } public int Read(Span buffer, long offset) { - StreamCursor cursor = default; - return Read(buffer, offset, ref cursor); - } - - internal int Read(Span buffer, long offset, ref StreamCursor cursor) - { - using AccessScope access = AcquireAccess(); - return access.Read(buffer, offset, ref cursor); - } - - private int ReadCore(Span buffer, long offset, ref StreamCursor cursor) - { - ValidateOffset(offset); - - int totalRead = 0; - while (!buffer.IsEmpty && offset < Length) + _lifetimeLock.EnterReadLock(); + try { - int streamIndex = FindStreamIndex(offset, cursor.StreamIndex); - long streamStart = GetStreamStart(streamIndex); - int readLength = (int)Math.Min(buffer.Length, _fileStreamEnds[streamIndex] - offset); - - FileStream stream = GetFileStream(streamIndex, ref cursor); - int read = RandomAccessCompat.Read(stream.SafeFileHandle!, - buffer[..readLength], - offset - streamStart); + ThrowIfDisposed(); + ValidateOffset(offset); - if (read == 0) + int totalRead = 0; + while (!buffer.IsEmpty && offset < Length) { - throw new EndOfStreamException("An underlying file ended before its declared length."); - } + int streamIndex = FindStreamIndex(offset); + long streamStart = GetStreamStart(streamIndex); + int readLength = (int)Math.Min(buffer.Length, _fileStreamEnds[streamIndex] - offset); - totalRead += read; - offset += read; - buffer = buffer[read..]; - } + FileStream stream = GetFileStream(streamIndex); + int read = RandomAccessCompat.Read(stream.SafeFileHandle!, + buffer[..readLength], + offset - streamStart); - return totalRead; - } + if (read == 0) + { + throw new EndOfStreamException("An underlying file ended before its declared length."); + } - internal AccessScope AcquireAccess() - { - _lifetimeLock.EnterReadLock(); - try - { - ThrowIfDisposed(); - return new AccessScope(this); + totalRead += read; + offset += read; + buffer = buffer[read..]; + } + + return totalRead; } - catch + finally { _lifetimeLock.ExitReadLock(); - throw; } } @@ -198,19 +177,6 @@ private FileStream GetFileStream(int streamIndex) return lazyStream.Value; } - private FileStream GetFileStream(int streamIndex, ref StreamCursor cursor) - { - if (cursor.Stream is not null && cursor.StreamIndex == streamIndex) - { - return cursor.Stream; - } - - FileStream stream = GetFileStream(streamIndex); - cursor.StreamIndex = streamIndex; - cursor.Stream = stream; - return stream; - } - private void CreateOutputFiles() { long streamStart = 0; @@ -257,20 +223,6 @@ private int FindStreamIndex(long offset) return low; } - private int FindStreamIndex(long offset, int cachedStreamIndex) - { - if ((uint)cachedStreamIndex < (uint)_fileStreamEnds.Length) - { - long streamStart = GetStreamStart(cachedStreamIndex); - if (offset >= streamStart && offset < _fileStreamEnds[cachedStreamIndex]) - { - return cachedStreamIndex; - } - } - - return FindStreamIndex(offset); - } - private long GetStreamStart(int streamIndex) => streamIndex == 0 ? 0 : _fileStreamEnds[streamIndex - 1]; @@ -289,22 +241,4 @@ private void ThrowIfDisposed() throw new ObjectDisposedException(nameof(RandomMergedStreamWrapper)); } } - - internal struct StreamCursor - { - public int StreamIndex; - public FileStream? Stream; - } - - internal readonly ref struct AccessScope(RandomMergedStreamWrapper owner) - { - public int Read(Span buffer, long offset, ref StreamCursor cursor) - => owner.ReadCore(buffer, offset, ref cursor); - - public void Write(Span buffer, long offset, ref StreamCursor cursor) - => owner.WriteCore(buffer, offset, ref cursor); - - public void Dispose() - => owner._lifetimeLock.ExitReadLock(); - } } diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs index 498bb3a..8590604 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs @@ -21,7 +21,6 @@ private class CopySimilarFilesContext(string inputDir, public void RunCopy(PatcherBase patcher, PatchOptions options, - int workerCount, CancellationToken token) { int bufferSize = options.CopyBufferSize; @@ -30,72 +29,71 @@ public void RunCopy(PatcherBase patcher, token.ThrowIfCancellationRequested(); int count = InputPaths.Length; - ParallelOptions parallelOptions = new() + Parallel.For(0, count, new ParallelOptions { - CancellationToken = token, - MaxDegreeOfParallelism = workerCount - }; - -#if NET6_0_OR_GREATER - Parallel.For(0, - count, - parallelOptions, - () => new NativeMemoryBuffer(bufferSize), - (i, _, nativeBuffer) => + MaxDegreeOfParallelism = (int)options.ParallelThreads + }, i => { token.ThrowIfCancellationRequested(); - Span buffer = nativeBuffer.Span; - string inputPath = Path.GetFullPath(Path.Combine(InputDir, InputPaths[i])); - string outputPath = Path.GetFullPath(Path.Combine(OutputDir, OutputPaths[i])); - - if (Path.GetDirectoryName(outputPath) is { } outputDir) - Directory.CreateDirectory(outputDir); - - using FileStream inputStream = File.Open(inputPath, FileMode.Open, FileAccess.Read); - using FileStream outputStream = File.Create(outputPath, bufferSize); - int read; - while ((read = inputStream.Read(buffer)) > 0) +#if NET6_0_OR_GREATER + unsafe { - token.ThrowIfCancellationRequested(); - - outputStream.Write(buffer[..read]); - patcher.AdvanceProgress(read); + void* bufferP = MemoryAlloc.Alloc(bufferSize); + var buffer = new Span(bufferP, bufferSize); + try + { + string inputPath = Path.GetFullPath(Path.Combine(InputDir, InputPaths[i])); + string outputPath = Path.GetFullPath(Path.Combine(OutputDir, OutputPaths[i])); + + if (Path.GetDirectoryName(outputPath) is { } outputDir) + Directory.CreateDirectory(outputDir); + + using FileStream inputStream = File.Open(inputPath, FileMode.Open, FileAccess.Read); + using FileStream outputStream = File.Create(outputPath, bufferSize); + int read; + + while ((read = inputStream.Read(buffer)) > 0) + { + token.ThrowIfCancellationRequested(); + + outputStream.Write(buffer[..read]); + patcher.AdvanceProgress(read); + } + } + finally + { + MemoryAlloc.FreeRaw(bufferP); + } } - - return nativeBuffer; - }, - nativeBuffer => nativeBuffer.Dispose()); #else - Parallel.For(0, - count, - parallelOptions, - () => BigArrayPool.Shared.Rent(bufferSize), - (i, _, buffer) => - { - token.ThrowIfCancellationRequested(); - string inputPath = Path.GetFullPath(Path.Combine(InputDir, InputPaths[i])); - string outputPath = Path.GetFullPath(Path.Combine(OutputDir, OutputPaths[i])); + byte[] buffer = BigArrayPool.Shared.Rent(bufferSize); + try + { + string inputPath = Path.GetFullPath(Path.Combine(InputDir, InputPaths[i])); + string outputPath = Path.GetFullPath(Path.Combine(OutputDir, OutputPaths[i])); - if (Path.GetDirectoryName(outputPath) is { } outputDir) - Directory.CreateDirectory(outputDir); + if (Path.GetDirectoryName(outputPath) is { } outputDir) + Directory.CreateDirectory(outputDir); - using FileStream inputStream = File.Open(inputPath, FileMode.Open, FileAccess.Read); - using FileStream outputStream = File.Create(outputPath, bufferSize); - int read; + using FileStream inputStream = File.Open(inputPath, FileMode.Open, FileAccess.Read); + using FileStream outputStream = File.Create(outputPath, bufferSize); + int read; - while ((read = inputStream.Read(buffer, 0, bufferSize)) > 0) - { - token.ThrowIfCancellationRequested(); + while ((read = inputStream.Read(buffer, 0, bufferSize)) > 0) + { + token.ThrowIfCancellationRequested(); - outputStream.Write(buffer, 0, read); - patcher.AdvanceProgress(read); + outputStream.Write(buffer, 0, read); + patcher.AdvanceProgress(read); + } + } + finally + { + BigArrayPool.Shared.Return(buffer); } - - return buffer; - }, - buffer => BigArrayPool.Shared.Return(buffer)); #endif + }); } } } diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs index 613878b..e5037f8 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs @@ -1,6 +1,6 @@ -using System; -using System.Buffers; +using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.IO; #if NET6_0_OR_GREATER using System.Numerics; @@ -41,7 +41,7 @@ private unsafe void StartCorePatcher(CancellationToken token) int bufferSize = Options.PatchWorkerBufferSize > 0 ? Options.PatchWorkerBufferSize : DefaultPatchBufferSize; - int workerCount = _coreWorkerCount; + int workerCount = GetWorkerCount(Options.ParallelThreads); if (workerCount == 1) { @@ -57,18 +57,31 @@ private unsafe void StartCorePatcher(CancellationToken token) } } + private static int GetWorkerCount(uint requestedWorkerCount) + { + if (requestedWorkerCount == 0) + { + return Math.Max(1, Environment.ProcessorCount); + } + + if (requestedWorkerCount > int.MaxValue) + { + throw new ArgumentOutOfRangeException(nameof(PatchOptions.ParallelThreads)); + } + + return (int)requestedWorkerCount; + } + private void RunSequential(ReadOnlySpan covers, PatchMetadata patchMetadata, int bufferSize, CancellationToken token) { - using NativeMemoryBufferPool workBufferPool = new(bufferSize); - using PatchWorkerContext workerContext = new(bufferSize); + using NativeMemoryBuffer oldBuffer = new(bufferSize); ProduceWork(covers, patchMetadata.DiffNewSize, bufferSize, - workBufferPool, - item => ProcessWorkItem(item, workerContext, workBufferPool, token), + item => ProcessWorkItem(item, oldBuffer, token), token); ValidateDataReaders(patchMetadata); } @@ -86,7 +99,6 @@ private void RunParallel(NativeMemoryBuffer covers, using CancellationTokenSource linkedCancellation = CancellationTokenSource.CreateLinkedTokenSource(token); using BlockingCollection workQueue = new(queueCapacity); - using NativeMemoryBufferPool workBufferPool = new(bufferSize); ExceptionDispatchInfo? producerFailure = null; ExceptionDispatchInfo? workerFailure = null; @@ -100,11 +112,7 @@ private void RunParallel(NativeMemoryBuffer covers, ProduceWork(covers.Span, patchMetadata.DiffNewSize, bufferSize, - workBufferPool, - item => AddWorkItem(workQueue, - item, - workBufferPool, - linkedCancellation.Token), + item => AddWorkItem(workQueue, item, linkedCancellation.Token), linkedCancellation.Token); ValidateDataReaders(patchMetadata); } @@ -131,15 +139,12 @@ private void RunParallel(NativeMemoryBuffer covers, CancellationToken = linkedCancellation.Token, MaxDegreeOfParallelism = workerCount }, - () => new PatchWorkerContext(bufferSize), - (item, _, workerContext) => + () => new NativeMemoryBuffer(bufferSize), + (item, _, oldBuffer) => { try { - ProcessWorkItem(item, - workerContext, - workBufferPool, - linkedCancellation.Token); + ProcessWorkItem(item, oldBuffer, linkedCancellation.Token); } catch (Exception exception) { @@ -151,9 +156,9 @@ private void RunParallel(NativeMemoryBuffer covers, throw; } - return workerContext; + return oldBuffer; }, - workerContext => workerContext.Dispose()); + oldBuffer => oldBuffer.Dispose()); } catch (Exception exception) { @@ -166,7 +171,7 @@ private void RunParallel(NativeMemoryBuffer covers, while (workQueue.TryTake(out PatchWorkItem abandonedItem)) { - ReleaseWorkItem(abandonedItem, workBufferPool); + abandonedItem.Buffer.Dispose(); } } @@ -185,7 +190,6 @@ private void RunParallel(NativeMemoryBuffer covers, private static void AddWorkItem(BlockingCollection queue, PatchWorkItem item, - NativeMemoryBufferPool workBufferPool, CancellationToken token) { try @@ -194,7 +198,7 @@ private static void AddWorkItem(BlockingCollection queue, } catch { - ReleaseWorkItem(item, workBufferPool); + item.Buffer.Dispose(); throw; } } @@ -202,13 +206,12 @@ private static void AddWorkItem(BlockingCollection queue, private void ProduceWork(ReadOnlySpan covers, long newDataSize, int bufferSize, - NativeMemoryBufferPool workBufferPool, Action emit, CancellationToken token) { RleDecoder rleDecoder = new(_rleCtrlReader, _rleCodeReader); using NativeMemoryBuffer skipBuffer = new(Math.Min(bufferSize, 64 << 10)); - using PatchWorkBuilder workBuilder = new(bufferSize, workBufferPool, emit); + using PatchWorkBuilder workBuilder = new(bufferSize, emit); long newPosition = 0; for (int coverIndex = 0; coverIndex < covers.Length; coverIndex++) @@ -289,25 +292,21 @@ private static void ProduceCover(RleCoverInfo cover, } } - private void ProcessWorkItem(PatchWorkItem item, - PatchWorkerContext workerContext, - NativeMemoryBufferPool workBufferPool, - CancellationToken token) + private void ProcessWorkItem(PatchWorkItem item, + NativeMemoryBuffer oldBuffer, + CancellationToken token) { try { token.ThrowIfCancellationRequested(); if (item.CoverSegments is { } coverSegments) { - using RandomMergedStreamWrapper.AccessScope inputAccess = InputStream!.AcquireAccess(); - for (int segmentIndex = 0; segmentIndex < item.CoverSegmentCount; segmentIndex++) + for (int segmentIndex = 0; segmentIndex < coverSegments.Count; segmentIndex++) { token.ThrowIfCancellationRequested(); CoverSegment segment = coverSegments[segmentIndex]; - Span oldData = workerContext.OldBuffer.Span[..segment.Length]; - int read = inputAccess.Read(oldData, - segment.OldPosition, - ref workerContext.InputCursor); + Span oldData = oldBuffer.Span[..segment.Length]; + int read = InputStream!.Read(oldData, segment.OldPosition); if (read != segment.Length) { throw new EndOfStreamException("The old-data stream ended while processing a cover."); @@ -316,46 +315,35 @@ private void ProcessWorkItem(PatchWorkItem item, #if NET6_0_OR_GREATER Span rleData = item.Buffer.Span.Slice(segment.BufferOffset, segment.Length); - AddRle(rleData, oldData, Options.UseSIMD); + AddRle(oldData, rleData, Options.UseSIMD); #else Span rleData = item.Buffer.Span.Slice(segment.BufferOffset, segment.Length); - AddRle(rleData, oldData); + AddRle(oldData, rleData); #endif + oldData.CopyTo(rleData); } } - OutputStream!.Write(item.Buffer.Span[..item.Length], - item.OutputPosition, - ref workerContext.OutputCursor); + OutputStream!.Write(item.Buffer.Span[..item.Length], item.OutputPosition); AdvanceProgress(item.Length); } finally { - ReleaseWorkItem(item, workBufferPool); - } - } - - private static void ReleaseWorkItem(PatchWorkItem item, - NativeMemoryBufferPool workBufferPool) - { - workBufferPool.Return(item.Buffer); - if (item.CoverSegments is { } coverSegments) - { - ArrayPool.Shared.Return(coverSegments); + item.Buffer.Dispose(); } } #if NET6_0_OR_GREATER private static void AddRle(Span destination, - ReadOnlySpan addend, + ReadOnlySpan rle, bool useSimd) #else private static void AddRle(Span destination, - ReadOnlySpan addend) + ReadOnlySpan rle) #endif { - if (destination.Length != addend.Length) + if (destination.Length != rle.Length) { throw new ArgumentException("The old-data and RLE buffers must have the same length."); } @@ -370,14 +358,12 @@ private static void AddRle(Span destination, if (vectorEnd != 0) { ref byte destinationRef = ref destination[0]; - ref byte addendRef = ref Unsafe.AsRef(in addend[0]); + ref byte rleRef = ref Unsafe.AsRef(in rle[0]); for (; index < vectorEnd; index += vectorLength) { - var destinationVector = Unsafe.ReadUnaligned>( - ref Unsafe.Add(ref destinationRef, index)); - var addendVector = Unsafe.ReadUnaligned>( - ref Unsafe.Add(ref addendRef, index)); - Vector256 result = Avx2.Add(destinationVector, addendVector); + var oldVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref destinationRef, index)); + var rleVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref rleRef, index)); + Vector256 result = Avx2.Add(oldVector, rleVector); Unsafe.WriteUnaligned(ref Unsafe.Add(ref destinationRef, index), result); } } @@ -389,14 +375,12 @@ private static void AddRle(Span destination, if (vectorEnd != 0) { ref byte destinationRef = ref destination[0]; - ref byte addendRef = ref Unsafe.AsRef(in addend[0]); + ref byte rleRef = ref Unsafe.AsRef(in rle[0]); for (; index < vectorEnd; index += vectorLength) { - var destinationVector = Unsafe.ReadUnaligned>( - ref Unsafe.Add(ref destinationRef, index)); - var addendVector = Unsafe.ReadUnaligned>( - ref Unsafe.Add(ref addendRef, index)); - Vector128 result = Sse2.Add(destinationVector, addendVector); + var oldVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref destinationRef, index)); + var rleVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref rleRef, index)); + Vector128 result = Sse2.Add(oldVector, rleVector); Unsafe.WriteUnaligned(ref Unsafe.Add(ref destinationRef, index), result); } } @@ -407,15 +391,15 @@ private static void AddRle(Span destination, int vectorEnd = length - length % vectorLength; for (; index < vectorEnd; index += vectorLength) { - Vector destinationVector = new(destination.Slice(index, vectorLength)); - Vector addendVector = new(addend.Slice(index, vectorLength)); - (destinationVector + addendVector).CopyTo(destination.Slice(index, vectorLength)); + Vector oldVector = new(destination.Slice(index, vectorLength)); + Vector rleVector = new(rle.Slice(index, vectorLength)); + (oldVector + rleVector).CopyTo(destination.Slice(index, vectorLength)); } } #endif for (; index < length; index++) { - destination[index] = unchecked((byte)(destination[index] + addend[index])); + destination[index] = unchecked((byte)(destination[index] + rle[index])); } } @@ -457,14 +441,12 @@ private static void ValidateReaderOffset(BittableStreamReader reader, private readonly struct PatchWorkItem(NativeMemoryBuffer buffer, int length, long outputPosition, - CoverSegment[]? coverSegments, - int coverSegmentCount) + List? coverSegments) { public NativeMemoryBuffer Buffer { get; } = buffer; public int Length { get; } = length; public long OutputPosition { get; } = outputPosition; - public CoverSegment[]? CoverSegments { get; } = coverSegments; - public int CoverSegmentCount { get; } = coverSegmentCount; + public List? CoverSegments { get; } = coverSegments; } private readonly struct CoverSegment(int bufferOffset, @@ -476,19 +458,16 @@ private readonly struct CoverSegment(int bufferOffset, public long OldPosition { get; } = oldPosition; } - private sealed class PatchWorkBuilder(int bufferSize, - NativeMemoryBufferPool bufferPool, - Action emit) : IDisposable + private sealed class PatchWorkBuilder(int bufferSize, + Action emit) : IDisposable { private readonly int _bufferSize = bufferSize; - private readonly NativeMemoryBufferPool _bufferPool = bufferPool; private readonly Action _emit = emit; private NativeMemoryBuffer? _buffer; private int _length; private long _outputPosition; - private CoverSegment[]? _coverSegments; - private int _coverSegmentCount; + private List? _coverSegments; public Span GetWritableSpan(long outputPosition, long requestedLength, @@ -501,7 +480,7 @@ public Span GetWritableSpan(long outputPosition, if (_buffer is null) { - _buffer = _bufferPool.Rent(); + _buffer = new NativeMemoryBuffer(_bufferSize); _outputPosition = outputPosition; } else if (outputPosition != _outputPosition + _length) @@ -518,45 +497,27 @@ public void CommitNewData(int length) public void CommitCover(int length, long oldPosition) { - if (_coverSegmentCount > 0) + _coverSegments ??= []; + + int segmentCount = _coverSegments.Count; + if (segmentCount > 0) { - CoverSegment previous = _coverSegments![_coverSegmentCount - 1]; + CoverSegment previous = _coverSegments[segmentCount - 1]; if (previous.BufferOffset + previous.Length == _length && previous.OldPosition + previous.Length == oldPosition) { - _coverSegments[_coverSegmentCount - 1] = new CoverSegment(previous.BufferOffset, - previous.Length + length, - previous.OldPosition); + _coverSegments[segmentCount - 1] = new CoverSegment(previous.BufferOffset, + previous.Length + length, + previous.OldPosition); _length += length; return; } } - EnsureCoverSegmentCapacity(); - _coverSegments![_coverSegmentCount++] = new CoverSegment(_length, length, oldPosition); + _coverSegments.Add(new CoverSegment(_length, length, oldPosition)); _length += length; } - private void EnsureCoverSegmentCapacity() - { - if (_coverSegments is null) - { - _coverSegments = ArrayPool.Shared.Rent(16); - return; - } - - if (_coverSegmentCount != _coverSegments.Length) - { - return; - } - - CoverSegment[] replacement = ArrayPool.Shared.Rent( - checked(_coverSegments.Length * 2)); - _coverSegments.AsSpan(0, _coverSegmentCount).CopyTo(replacement); - ArrayPool.Shared.Return(_coverSegments); - _coverSegments = replacement; - } - public void Flush() { if (_buffer is null || _length == 0) @@ -567,12 +528,10 @@ public void Flush() PatchWorkItem item = new(_buffer, _length, _outputPosition, - _coverSegments, - _coverSegmentCount); + _coverSegments); _buffer = null; _length = 0; _coverSegments = null; - _coverSegmentCount = 0; _emit(item); } @@ -580,29 +539,12 @@ public void Dispose() { if (_buffer is not null) { - _bufferPool.Return(_buffer); + _buffer.Dispose(); _buffer = null; } - - if (_coverSegments is not null) - { - ArrayPool.Shared.Return(_coverSegments); - _coverSegments = null; - _coverSegmentCount = 0; - } } } - private sealed class PatchWorkerContext(int bufferSize) : IDisposable - { - public NativeMemoryBuffer OldBuffer { get; } = new(bufferSize); - public RandomMergedStreamWrapper.StreamCursor InputCursor; - public RandomMergedStreamWrapper.StreamCursor OutputCursor; - - public void Dispose() - => OldBuffer.Dispose(); - } - private sealed class RleDecoder(BittableStreamReader controlReader, BittableStreamReader codeReader) { diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs index eff6256..3f0919a 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs @@ -18,21 +18,13 @@ internal sealed partial class HDiff13DerivedPatcher( BittableStreamReader newDataReader, HDiffInfo info, PatchOptions options, - ProgressCallback progressCallback, - int coreWorkerCount, - int copyWorkerCount, - bool runCopyConcurrently) + ProgressCallback progressCallback) : PatcherBase(info, options, progressCallback) { private readonly BittableStreamReader _coverReader = coverReader; private readonly BittableStreamReader _rleCtrlReader = rleCtrlReader; private readonly BittableStreamReader _rleCodeReader = rleCodeReader; private readonly BittableStreamReader _newDataReader = newDataReader; - private readonly int _coreWorkerCount = coreWorkerCount > 0 - ? coreWorkerCount - : throw new ArgumentOutOfRangeException(nameof(coreWorkerCount)); - private readonly int _copyWorkerCount = copyWorkerCount; - private readonly bool _runCopyConcurrently = runCopyConcurrently; private CopySimilarFilesContext? _copySimilarFilesContext; @@ -43,16 +35,6 @@ public override void StartPatch(string inputPath, string outputPath, Cancellatio // Start both CopyOver and CorePatch routine if context is not null. if (_copySimilarFilesContext != null) { - if (!_runCopyConcurrently) - { - _copySimilarFilesContext.RunCopy(this, - Options, - _copyWorkerCount, - token); - StartCorePatcher(token); - return; - } - TaskCompletionSource copyOverTcs = new(null!, TaskCreationOptions.RunContinuationsAsynchronously); TaskCompletionSource corePatcherTcs = new(null!, TaskCreationOptions.RunContinuationsAsynchronously); @@ -60,10 +42,7 @@ public override void StartPatch(string inputPath, string outputPath, Cancellatio { try { - _copySimilarFilesContext.RunCopy(this, - Options, - _copyWorkerCount, - token); + _copySimilarFilesContext.RunCopy(this, Options, token); copyOverTcs.SetResult(true); } catch (OperationCanceledException) when (token.IsCancellationRequested) @@ -90,9 +69,9 @@ public override void StartPatch(string inputPath, string outputPath, Cancellatio catch (OperationCanceledException) when (token.IsCancellationRequested) { #if NET6_0_OR_GREATER - corePatcherTcs.SetCanceled(token); + copyOverTcs.SetCanceled(token); #else - corePatcherTcs.SetCanceled(); + copyOverTcs.SetCanceled(); #endif } catch (Exception ex) diff --git a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs index 4ce530b..90b5325 100644 --- a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs +++ b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs @@ -20,7 +20,6 @@ public static HDiff13DerivedPatcher Create( PatchOptions options, ProgressCallback progressCallback) { - ExecutionPlan executionPlan = CreateExecutionPlan(info.MagicType, options); GetPatchContextInfos(ref info, out long coverDataOffset, out long rleCtrlDataOffset, @@ -33,8 +32,7 @@ public static HDiff13DerivedPatcher Create( createPatchStream(coverDataOffset), createPatchStream(rleCtrlDataOffset), createPatchStream(rleCodeDataOffset), - createPatchStream(newDataOffset), - executionPlan.MaxDecompressionWorkers); + createPatchStream(newDataOffset)); return new HDiff13DerivedPatcher(context.Cover, context.RleCtrl, @@ -42,10 +40,7 @@ public static HDiff13DerivedPatcher Create( context.NewData, info, options, - progressCallback, - executionPlan.PatchWorkerBudget - context.DecompressionWorkers, - executionPlan.CopyWorkers, - executionPlan.RunCopyConcurrently); + progressCallback); } public static async Task CreateAsync( @@ -55,7 +50,6 @@ public static async Task CreateAsync( ProgressCallback progressCallback, CancellationToken token) { - ExecutionPlan executionPlan = CreateExecutionPlan(info.MagicType, options); GetPatchContextInfos(ref info, out long coverDataOffset, out long rleCtrlDataOffset, @@ -68,8 +62,7 @@ public static async Task CreateAsync( await createPatchStreamAsync(coverDataOffset, token), await createPatchStreamAsync(rleCtrlDataOffset, token), await createPatchStreamAsync(rleCodeDataOffset, token), - await createPatchStreamAsync(newDataOffset, token), - executionPlan.MaxDecompressionWorkers); + await createPatchStreamAsync(newDataOffset, token)); return new HDiff13DerivedPatcher(context.Cover, context.RleCtrl, @@ -77,10 +70,7 @@ await createPatchStreamAsync(newDataOffset, token), context.NewData, info, options, - progressCallback, - executionPlan.PatchWorkerBudget - context.DecompressionWorkers, - executionPlan.CopyWorkers, - executionPlan.RunCopyConcurrently); + progressCallback); } private static unsafe DiffReadersContext CreateReaderContext(HDiffCompression compType, @@ -89,8 +79,7 @@ private static unsafe DiffReadersContext CreateReaderContext(HDiffCompression ValueTuple coverCtx, ValueTuple rleCtrlCtx, ValueTuple rleCodeCtx, - ValueTuple newDataCtx, - int maxDecompressionWorkers) + ValueTuple newDataCtx) { int bufferSize = options.ReaderBufferSize; @@ -107,38 +96,39 @@ private static unsafe DiffReadersContext CreateReaderContext(HDiffCompression CreateDecompressionStream(compType, newDataSize, newDataCtx) ]; - int decompressionWorkers = EnableParallelDecompression( - compType, - options, - decompressedStreams, - [coverSize, controlSize, codeSize, newDataSize], - maxDecompressionWorkers); + EnableParallelDecompression(compType, + options, + decompressedStreams, + [coverSize, controlSize, codeSize, newDataSize]); BittableStreamReader coverReader = new(decompressedStreams[0], bufferSize, coverCtx.Item2); BittableStreamReader rleCtrlReader = new(decompressedStreams[1], bufferSize, rleCtrlCtx.Item2); BittableStreamReader rleCodeReader = new(decompressedStreams[2], bufferSize, rleCodeCtx.Item2); BittableStreamReader newDataReader = new(decompressedStreams[3], bufferSize, newDataCtx.Item2); - return new DiffReadersContext(coverReader, - rleCtrlReader, - rleCodeReader, - newDataReader, - decompressionWorkers); + return new DiffReadersContext(coverReader, rleCtrlReader, rleCodeReader, newDataReader); } - private static int EnableParallelDecompression(HDiffCompression compType, - PatchOptions options, - Stream[] streams, - ChunkSizeInfo[] sizes, - int maxWorkers) + private static void EnableParallelDecompression(HDiffCompression compType, + PatchOptions options, + Stream[] streams, + ChunkSizeInfo[] sizes) { - if (maxWorkers == 0 || - compType is HDiffCompression.Uncompressed or HDiffCompression.Zstd) + if (compType is HDiffCompression.Uncompressed or HDiffCompression.Zstd) { - return 0; + return; } - int prefetchCount = Math.Min(streams.Length, maxWorkers); + int requestedWorkers = options.ParallelThreads == 0 + ? Environment.ProcessorCount + : options.ParallelThreads > int.MaxValue + ? int.MaxValue + : (int)options.ParallelThreads; + int prefetchCount = Math.Min(streams.Length, Math.Max(0, requestedWorkers - 1)); + if (prefetchCount == 0) + { + return; + } List<(int Index, long CompressedSize)> candidates = new(streams.Length); for (int index = 0; index < sizes.Length; index++) @@ -161,42 +151,6 @@ private static int EnableParallelDecompression(HDiffCompression compType, streams[streamIndex] = new PrefetchedReadStream(streams[streamIndex], prefetchBufferSize); } - - return prefetchCount; - } - - private static ExecutionPlan CreateExecutionPlan(HDiffMagic magicType, - PatchOptions options) - { - int totalWorkers; - if (options.ParallelThreads == 0) - { - totalWorkers = Math.Max(1, Environment.ProcessorCount); - } - else if (options.ParallelThreads > int.MaxValue) - { - throw new ArgumentOutOfRangeException(nameof(PatchOptions.ParallelThreads)); - } - else - { - totalWorkers = (int)options.ParallelThreads; - } - - bool hasCopyStage = magicType != HDiffMagic.HDiff13; - int copyWorkers = hasCopyStage - ? totalWorkers == 1 - ? 1 - : Math.Max(1, totalWorkers / 4) - : 0; - int patchWorkerBudget = hasCopyStage && totalWorkers > 1 - ? totalWorkers - copyWorkers - : totalWorkers; - int maxDecompressionWorkers = Math.Min(4, patchWorkerBudget / 2); - - return new ExecutionPlan(patchWorkerBudget, - copyWorkers, - maxDecompressionWorkers, - hasCopyStage && totalWorkers > 1); } private static Stream CreateDecompressionStream( @@ -232,12 +186,6 @@ private record struct DiffReadersContext( BittableStreamReader Cover, BittableStreamReader RleCtrl, BittableStreamReader RleCode, - BittableStreamReader NewData, - int DecompressionWorkers); - - private readonly record struct ExecutionPlan(int PatchWorkerBudget, - int CopyWorkers, - int MaxDecompressionWorkers, - bool RunCopyConcurrently); + BittableStreamReader NewData); } } diff --git a/SharpHPatchZ/PatchOptions.cs b/SharpHPatchZ/PatchOptions.cs index 9d5b7cc..360f3ed 100644 --- a/SharpHPatchZ/PatchOptions.cs +++ b/SharpHPatchZ/PatchOptions.cs @@ -18,7 +18,7 @@ public struct PatchOptions() { ReaderBufferSize = 4 << 20, CopyBufferSize = 128 << 10, - PatchWorkerBufferSize = 16 << 20 + PatchWorkerBufferSize = 32 << 20 }; public static readonly PatchOptions SmallBuffer = Default with From 865334e1e0e53753c79341e93ac81a24e52c6da2 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 21:52:51 +0700 Subject: [PATCH 43/72] Avoid buffer copy routine in RLE Adder --- .../HDiff13DerivedPatcher.CorePatcher.cs | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs index e5037f8..61305f0 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs @@ -315,13 +315,12 @@ private void ProcessWorkItem(PatchWorkItem item, #if NET6_0_OR_GREATER Span rleData = item.Buffer.Span.Slice(segment.BufferOffset, segment.Length); - AddRle(oldData, rleData, Options.UseSIMD); + AddRle(rleData, oldData, Options.UseSIMD); #else Span rleData = item.Buffer.Span.Slice(segment.BufferOffset, segment.Length); - AddRle(oldData, rleData); + AddRle(rleData, oldData); #endif - oldData.CopyTo(rleData); } } @@ -336,14 +335,14 @@ private void ProcessWorkItem(PatchWorkItem item, #if NET6_0_OR_GREATER private static void AddRle(Span destination, - ReadOnlySpan rle, + ReadOnlySpan addend, bool useSimd) #else private static void AddRle(Span destination, - ReadOnlySpan rle) + ReadOnlySpan addend) #endif { - if (destination.Length != rle.Length) + if (destination.Length != addend.Length) { throw new ArgumentException("The old-data and RLE buffers must have the same length."); } @@ -358,12 +357,12 @@ private static void AddRle(Span destination, if (vectorEnd != 0) { ref byte destinationRef = ref destination[0]; - ref byte rleRef = ref Unsafe.AsRef(in rle[0]); + ref byte addendRef = ref Unsafe.AsRef(in addend[0]); for (; index < vectorEnd; index += vectorLength) { - var oldVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref destinationRef, index)); - var rleVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref rleRef, index)); - Vector256 result = Avx2.Add(oldVector, rleVector); + var destinationVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref destinationRef, index)); + var addendVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref addendRef, index)); + Vector256 result = Avx2.Add(destinationVector, addendVector); Unsafe.WriteUnaligned(ref Unsafe.Add(ref destinationRef, index), result); } } @@ -375,12 +374,12 @@ private static void AddRle(Span destination, if (vectorEnd != 0) { ref byte destinationRef = ref destination[0]; - ref byte rleRef = ref Unsafe.AsRef(in rle[0]); + ref byte addendRef = ref Unsafe.AsRef(in addend[0]); for (; index < vectorEnd; index += vectorLength) { - var oldVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref destinationRef, index)); - var rleVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref rleRef, index)); - Vector128 result = Sse2.Add(oldVector, rleVector); + var destinationVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref destinationRef, index)); + var addendVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref addendRef, index)); + Vector128 result = Sse2.Add(destinationVector, addendVector); Unsafe.WriteUnaligned(ref Unsafe.Add(ref destinationRef, index), result); } } @@ -389,17 +388,23 @@ private static void AddRle(Span destination, { int vectorLength = Vector.Count; int vectorEnd = length - length % vectorLength; - for (; index < vectorEnd; index += vectorLength) + if (vectorEnd != 0) { - Vector oldVector = new(destination.Slice(index, vectorLength)); - Vector rleVector = new(rle.Slice(index, vectorLength)); - (oldVector + rleVector).CopyTo(destination.Slice(index, vectorLength)); + ref byte destinationRef = ref destination[0]; + ref byte addendRef = ref Unsafe.AsRef(in addend[0]); + for (; index < vectorEnd; index += vectorLength) + { + var destinationVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref destinationRef, index)); + var addendVector = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref addendRef, index)); + Vector result = destinationVector + addendVector; + Unsafe.WriteUnaligned(ref Unsafe.Add(ref destinationRef, index), result); + } } } #endif for (; index < length; index++) { - destination[index] = unchecked((byte)(destination[index] + rle[index])); + destination[index] = unchecked((byte)(destination[index] + addend[index])); } } From 95bc90c87604988f21e8d3b043055c55446cc95f Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 23:55:13 +0700 Subject: [PATCH 44/72] Use preloaded buffer to create string list --- SharpHPatchZ/Extension/ExceptionHelper.cs | 8 +++ SharpHPatchZ/Extension/StreamExtension.cs | 71 +++++++++++++------ .../Header/Metadata/Utf16UnmanagedString.cs | 50 ++++++++++++- 3 files changed, 108 insertions(+), 21 deletions(-) diff --git a/SharpHPatchZ/Extension/ExceptionHelper.cs b/SharpHPatchZ/Extension/ExceptionHelper.cs index 395ebd1..56af553 100644 --- a/SharpHPatchZ/Extension/ExceptionHelper.cs +++ b/SharpHPatchZ/Extension/ExceptionHelper.cs @@ -38,6 +38,8 @@ file static class Const { HDiffPatchPathNotAFile, 0x57 }, { HDiffPatchInputFilesMismatched, 0x58 }, { HDiffPatchKuroInputFileSizeMismatched, 0x59 }, + { HDiffStreamReadOutOfBound, 0x5A }, + { HDiffStringEncodingFailed, 0x5B }, // Decompression Initialization { HDiffCompLZMAPropertyMissing, 0xA0 }, @@ -68,6 +70,8 @@ file static class Const public const string HDiffPatchPathNotAFile = "HDIFF_PatchPathNotAFile"; public const string HDiffPatchInputFilesMismatched = "HDIFF_PatchInputFilesMismatched"; public const string HDiffPatchKuroInputFileSizeMismatched = "HDIFF_PatchKuroInputFileSizeMismatched"; + public const string HDiffStreamReadOutOfBound = "HDIFF_StreamReadOutOfBound"; + public const string HDiffStringEncodingFailed = "HDIFF_StringEncodingFailed"; public const string HDiffCompLZMAPropertyMissing = "HDIFF_CompLZMAPropertyMissing"; public const string HDiffCompLZMA2DictionaryInvalid = "HDIFF_CompLZMA2DictionaryInvalid"; @@ -120,6 +124,10 @@ public static InvalidOperationException ThrowHDiffPatchInputFilesMismatched(long => new($"[{Const.HDiffPatchInputFilesMismatched}] Input file size mismatched! Expecting: {expectingSize} bytes but got: {expectingSize} bytes instead."); public static InvalidOperationException ThrowHDiffPatchKuroInputFileSizeMismatched(string filePath, long existingSize, long expectingSize) => new($"[{Const.HDiffPatchKuroInputFileSizeMismatched}] Kuro Games Patch input file size does not match: {filePath} (Expecting: {expectingSize} bytes, but got: {existingSize} instead)."); + public static IndexOutOfRangeException ThrowHDiffStreamReadOutOfBound() + => new($"[{Const.HDiffStreamReadOutOfBound}] Stream Read is out of bound!"); + public static InvalidDataException ThrowHDiffStringEncodingFailed(Exception? innerException) + => new($"[{Const.HDiffStringEncodingFailed}] Error while trying to encode a string!", innerException); public static InvalidDataException ThrowHDiffCompLZMAPropertyMissing() => new($"[{Const.HDiffCompLZMAPropertyMissing}] The LZMA stream is missing its properties."); diff --git a/SharpHPatchZ/Extension/StreamExtension.cs b/SharpHPatchZ/Extension/StreamExtension.cs index af11291..06b531e 100644 --- a/SharpHPatchZ/Extension/StreamExtension.cs +++ b/SharpHPatchZ/Extension/StreamExtension.cs @@ -145,6 +145,31 @@ public async ValueTask ReadAtLeastAsync( #endif } + public static unsafe UnmanagedArray* CreateUnmanagedStringList( + scoped ReadOnlySpan buffer, int count) + { + UnmanagedArray* unmanagedStringArray = UnmanagedArray.CreateAllocUnsafe(count); + Span unmanagedStringSpan = unmanagedStringArray->GetSpan(); + int index = 0; + do + { + int indexOfNull = buffer.IndexOf((byte)0); + if (indexOfNull < 0) + { + throw ExceptionHelper.ThrowHDiffStreamReadOutOfBound(); + } + + ReadOnlySpan currentSlice = buffer[..indexOfNull]; + unmanagedStringSpan[index++] = Utf16UnmanagedString.CreateFromManaged(currentSlice); + + buffer = buffer[(indexOfNull + 1)..]; + } while (!buffer.IsEmpty); + + return index != count + ? throw ExceptionHelper.ThrowHDiffStreamReadOutOfBound() + : unmanagedStringArray; + } + extension(BittableStreamReader reader) { public async ValueTask CreateUnmanagedStringListAsync(int count, int bufferSize, CancellationToken token) @@ -155,21 +180,23 @@ public async ValueTask CreateUnmanagedStringListAsync(int count, int buffe } long readerOffset = reader.Offset; - UnmanagedArray unmanagedBuffer = UnmanagedArray.CreateAlloc(count); + byte[] buffer = ArrayPool.Shared.Rent(bufferSize); - for (int i = 0; i < count; i++) + try { - string readString = await reader.ReadStringToNullAsync(token); - - ref Utf16UnmanagedString current = ref unmanagedBuffer[i]; - current = Utf16UnmanagedString.CreateFromManaged(readString); - if (reader.Offset - readerOffset > bufferSize) + // Preload string buffer + await reader.ReadBytesAsync(buffer.AsMemory(0, bufferSize), token); + unsafe { - throw new IndexOutOfRangeException("Read is out of index!"); + return reader.Offset != readerOffset + bufferSize + ? throw ExceptionHelper.ThrowHDiffStreamReadOutOfBound() + : (nint)CreateUnmanagedStringList(buffer.AsSpan(0, bufferSize), count); } } - - return unmanagedBuffer.CopyToUnmanaged(); + finally + { + ArrayPool.Shared.Return(buffer); + } } public unsafe UnmanagedArray* CreateUnmanagedStringList(int count, int bufferSize) @@ -179,19 +206,23 @@ public async ValueTask CreateUnmanagedStringListAsync(int count, int buffe return null; } - long readerOffset = reader.Offset; - UnmanagedArray* readOnlyArraySpan = UnmanagedArray.CreateAllocUnsafe(count); + long readerOffset = reader.Offset; - for (int i = 0; i < count; i++) + byte[]? buffer = bufferSize > 4 << 10 ? ArrayPool.Shared.Rent(bufferSize) : null; + Span bufferSpan = (buffer ?? stackalloc byte[bufferSize])[..bufferSize]; + + try { - readOnlyArraySpan[0][i] = Utf16UnmanagedString.CreateFromManaged(reader.ReadStringToNull()); - if (reader.Offset - readerOffset > bufferSize) - { - throw new IndexOutOfRangeException("Read is out of index!"); - } + // Preload string buffer + reader.ReadBytes(bufferSpan); + return reader.Offset != readerOffset + bufferSize + ? throw ExceptionHelper.ThrowHDiffStreamReadOutOfBound() + : CreateUnmanagedStringList(bufferSpan, count); + } + finally + { + if (buffer != null) ArrayPool.Shared.Return(buffer); } - - return readOnlyArraySpan; } public async ValueTask CreateUnmanagedInt64ListAsync(int count, CancellationToken token) diff --git a/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs b/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs index 320bca2..3b6b45d 100644 --- a/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs +++ b/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs @@ -1,5 +1,8 @@ using System; +using System.Buffers; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Text; using SharpHPatchZ.Extension; namespace SharpHPatchZ.Header.Metadata; @@ -57,7 +60,31 @@ public bool IsDisposed private byte _isDisposed; public NativeStringW Native; - public static Utf16UnmanagedString CreateFromManaged(ReadOnlySpan source) +#if NET6_0_OR_GREATER + [SkipLocalsInit] +#endif + public static Utf16UnmanagedString CreateFromManaged(ReadOnlySpan source) + { + int maxLenTransform = Encoding.Unicode.GetMaxByteCount(source.Length); + char[]? tempCharsBuffer = maxLenTransform <= 1024 + ? null + : ArrayPool.Shared.Rent(maxLenTransform); + + Span tempCharsSpan = tempCharsBuffer ?? stackalloc char[maxLenTransform]; + try + { + return TransformUtf8ToUnicode(source, tempCharsSpan); + } + finally + { + if (tempCharsBuffer != null) ArrayPool.Shared.Return(tempCharsBuffer); + } + } + +#if NET6_0_OR_GREATER + [SkipLocalsInit] +#endif + public static Utf16UnmanagedString CreateFromManaged(scoped ReadOnlySpan source) { int lengthToAlloc = source.Length + 1; char* nativeChar = MemoryAlloc.Alloc(lengthToAlloc, true); @@ -82,6 +109,27 @@ public static implicit operator string(Utf16UnmanagedString unmanaged) public override string ToString() => Native.ToString(); + private static Utf16UnmanagedString TransformUtf8ToUnicode( + ReadOnlySpan source, + Span target) + { + try + { + ref byte sourceRef = ref MemoryMarshal.GetReference(source); + ref char targetRef = ref MemoryMarshal.GetReference(target); + + byte* sourceP = (byte*)Unsafe.AsPointer(ref sourceRef); + char* targetP = (char*)Unsafe.AsPointer(ref targetRef); + + int written = Encoding.UTF8.GetChars(sourceP, source.Length, targetP, target.Length); + return CreateFromManaged(target[..written]); + } + catch (Exception ex) + { + throw ExceptionHelper.ThrowHDiffStringEncodingFailed(ex); + } + } + [StructLayout(LayoutKind.Sequential)] public readonly struct NativeStringW(char* chars, int length) { From 55e493d952a222aaee833d91782e2dece5b42245 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 23:56:13 +0700 Subject: [PATCH 45/72] Optimize PatchOptions.BigBuffer --- SharpHPatchZ/PatchOptions.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SharpHPatchZ/PatchOptions.cs b/SharpHPatchZ/PatchOptions.cs index 360f3ed..e7673f3 100644 --- a/SharpHPatchZ/PatchOptions.cs +++ b/SharpHPatchZ/PatchOptions.cs @@ -16,9 +16,9 @@ public struct PatchOptions() public static readonly PatchOptions BigBuffer = Default with { - ReaderBufferSize = 4 << 20, + ReaderBufferSize = 1 << 20, CopyBufferSize = 128 << 10, - PatchWorkerBufferSize = 32 << 20 + PatchWorkerBufferSize = 16 << 20 }; public static readonly PatchOptions SmallBuffer = Default with From f08d862c557694ec09a72e4627d422948fc09747 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 24 Aug 2026 23:56:38 +0700 Subject: [PATCH 46/72] Fix throw from PatchResult not returning error code --- SharpHPatchZ.Program/Program.cs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/SharpHPatchZ.Program/Program.cs b/SharpHPatchZ.Program/Program.cs index c2c7c14..f5699dd 100644 --- a/SharpHPatchZ.Program/Program.cs +++ b/SharpHPatchZ.Program/Program.cs @@ -3,7 +3,6 @@ using System.Diagnostics; using System.IO; using System.Threading; -using System.Threading.Tasks; using SharpHPatchZ.Header; // ReSharper disable InconsistentNaming @@ -55,7 +54,9 @@ public static int Main(params string[] args) [OptimizedForHDD] Thread = 1, Buffer Size = Up to 16 MB per chunks - (Note: -p/--parallel-threads values will be ignored) + (Note: -p/--parallel-threads will be ignored with this mode) + + """)); Command.AddOption(threadsOpt = new Option(["-p", "--parallel-threads"], () => Environment.ProcessorCount, "Determines how much parallel threads to be run.")); @@ -98,13 +99,15 @@ public static int Main(params string[] args) ProgressCallback progressCallback = ProgressCallback.CreateFromManaged(PatchProgress); using HDiffInfo info = HPatch.CreateInstance(CreatePatchStream, initializeOptions); - PatchResult result = HPatch.Patch(info, CreatePatchStream, inputPath, outputPath, options, progressCallback); + PatchResult? result = HPatch.Patch(info, CreatePatchStream, inputPath, outputPath, options, progressCallback); + Console.WriteLine(); + if (result.Exception != null) { - throw result.Exception; + Console.WriteLine($"Patching process throws an error: {result.Exception}"); + context.ExitCode = result; + return; } - - Console.WriteLine(); Console.WriteLine($"Patch completed in: {Stopwatch.Elapsed:c} ({Stopwatch.Elapsed.TotalSeconds} seconds)"); (Stream, bool) CreatePatchStream(long position) From ff414825e2d4779274e0dfc43334af3448c254cb Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Tue, 25 Aug 2026 00:14:54 +0700 Subject: [PATCH 47/72] Code cleanup --- .../IO/Reader/BittableStreamReader.cs | 2 +- .../Reader/DecompressionTransitionStream.cs | 2 +- .../IO/Reader/PrefetchedReadStream.cs | 6 +- .../IO/Reader/RandomMergedStreamWrapper.cs | 6 +- ...3DerivedPatcher.CopySimilarFilesContext.cs | 4 +- .../HDiff13DerivedPatcher.CorePatcher.cs | 128 ++++++++++-------- SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs | 34 +++-- SharpHPatchZ/Patch/PatcherBase.cs | 18 ++- 8 files changed, 118 insertions(+), 82 deletions(-) diff --git a/SharpHPatchZ/IO/Reader/BittableStreamReader.cs b/SharpHPatchZ/IO/Reader/BittableStreamReader.cs index fe0cfb2..152323f 100644 --- a/SharpHPatchZ/IO/Reader/BittableStreamReader.cs +++ b/SharpHPatchZ/IO/Reader/BittableStreamReader.cs @@ -64,7 +64,7 @@ public long OffsetUnderlyingStream } } - public BittableStreamReader(Stream stream, int bufferSize = -1, bool leaveOpen = false) + internal BittableStreamReader(Stream stream, int bufferSize = -1, bool leaveOpen = false) { if (stream is null) { diff --git a/SharpHPatchZ/IO/Reader/DecompressionTransitionStream.cs b/SharpHPatchZ/IO/Reader/DecompressionTransitionStream.cs index 511ea35..55cc880 100644 --- a/SharpHPatchZ/IO/Reader/DecompressionTransitionStream.cs +++ b/SharpHPatchZ/IO/Reader/DecompressionTransitionStream.cs @@ -16,7 +16,7 @@ internal sealed class BufferedRemainderStream : Stream private readonly int _end; private bool _isDisposed; - public BufferedRemainderStream( + internal BufferedRemainderStream( Stream stream, byte[] buffer, int offset, diff --git a/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs b/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs index 6fdd5c4..5723de1 100644 --- a/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs +++ b/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs @@ -21,9 +21,9 @@ internal sealed class PrefetchedReadStream : Stream private int _currentOffset; private int _disposed; - public PrefetchedReadStream(Stream source, - int bufferSize, - int queueCapacity = 2) + internal PrefetchedReadStream(Stream source, + int bufferSize, + int queueCapacity = 2) { _source = source ?? throw new ArgumentNullException(nameof(source)); if (!source.CanRead) diff --git a/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs b/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs index 162c259..fc6dc82 100644 --- a/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs +++ b/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs @@ -17,9 +17,9 @@ internal sealed class RandomMergedStreamWrapper : IDisposable public long Length => _fileStreamEnds.Length == 0 ? 0 : _fileStreamEnds[^1]; - public RandomMergedStreamWrapper(string[] fileStreams, - long[] fileStreamEnds, - bool createFiles = false) + internal RandomMergedStreamWrapper(string[] fileStreams, + long[] fileStreamEnds, + bool createFiles = false) { if (fileStreams is null) { diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs index 8590604..b37f966 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CopySimilarFilesContext.cs @@ -8,9 +8,9 @@ namespace SharpHPatchZ.Patch; internal sealed partial class HDiff13DerivedPatcher { - private class CopySimilarFilesContext(string inputDir, + private class CopySimilarFilesContext(string inputDir, string[] inputPaths, - string outputDir, + string outputDir, string[] outputPaths) { private string InputDir { get; } = inputDir; diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs index 61305f0..0c045c0 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs @@ -59,17 +59,12 @@ private unsafe void StartCorePatcher(CancellationToken token) private static int GetWorkerCount(uint requestedWorkerCount) { - if (requestedWorkerCount == 0) + return requestedWorkerCount switch { - return Math.Max(1, Environment.ProcessorCount); - } - - if (requestedWorkerCount > int.MaxValue) - { - throw new ArgumentOutOfRangeException(nameof(PatchOptions.ParallelThreads)); - } - - return (int)requestedWorkerCount; + 0 => Math.Max(1, Environment.ProcessorCount), + > int.MaxValue => throw new ArgumentOutOfRangeException(nameof(PatchOptions.ParallelThreads)), + _ => (int)requestedWorkerCount + }; } private void RunSequential(ReadOnlySpan covers, @@ -258,9 +253,10 @@ private void ProduceNewData(long length, while (length > 0) { token.ThrowIfCancellationRequested(); - Span destination = workBuilder.GetWritableSpan(newPosition, - length, - out int step); + Span destination = workBuilder + .GetWritableSpan(newPosition, + length, + out int step); _newDataReader.ReadBytes(destination); rleDecoder.Skip(step, skipBuffer, token); workBuilder.CommitNewData(step); @@ -292,9 +288,9 @@ private static void ProduceCover(RleCoverInfo cover, } } - private void ProcessWorkItem(PatchWorkItem item, + private void ProcessWorkItem(PatchWorkItem item, NativeMemoryBuffer oldBuffer, - CancellationToken token) + CancellationToken token) { try { @@ -313,12 +309,10 @@ private void ProcessWorkItem(PatchWorkItem item, } #if NET6_0_OR_GREATER - Span rleData = item.Buffer.Span.Slice(segment.BufferOffset, - segment.Length); + Span rleData = item.Buffer.Span.Slice(segment.BufferOffset, segment.Length); AddRle(rleData, oldData, Options.UseSIMD); #else - Span rleData = item.Buffer.Span.Slice(segment.BufferOffset, - segment.Length); + Span rleData = item.Buffer.Span.Slice(segment.BufferOffset, segment.Length); AddRle(rleData, oldData); #endif } @@ -402,9 +396,10 @@ private static void AddRle(Span destination, } } #endif - for (; index < length; index++) + + while (index < length) { - destination[index] = unchecked((byte)(destination[index] + addend[index])); + destination[index] = unchecked((byte)(destination[index] + addend[index++])); } } @@ -443,36 +438,56 @@ private static void ValidateReaderOffset(BittableStreamReader reader, } } - private readonly struct PatchWorkItem(NativeMemoryBuffer buffer, - int length, - long outputPosition, - List? coverSegments) + private readonly struct PatchWorkItem { - public NativeMemoryBuffer Buffer { get; } = buffer; - public int Length { get; } = length; - public long OutputPosition { get; } = outputPosition; - public List? CoverSegments { get; } = coverSegments; + internal PatchWorkItem(NativeMemoryBuffer buffer, + int length, + long outputPosition, + List? coverSegments) + { + Buffer = buffer; + Length = length; + OutputPosition = outputPosition; + CoverSegments = coverSegments; + } + + public readonly NativeMemoryBuffer Buffer; + public readonly int Length; + public readonly long OutputPosition; + public readonly List? CoverSegments; } - private readonly struct CoverSegment(int bufferOffset, - int length, - long oldPosition) + private readonly struct CoverSegment { - public int BufferOffset { get; } = bufferOffset; - public int Length { get; } = length; - public long OldPosition { get; } = oldPosition; + internal CoverSegment(int bufferOffset, + int length, + long oldPosition) + { + BufferOffset = bufferOffset; + Length = length; + OldPosition = oldPosition; + } + + public readonly int BufferOffset; + public readonly int Length; + public readonly long OldPosition; } - private sealed class PatchWorkBuilder(int bufferSize, - Action emit) : IDisposable + private sealed class PatchWorkBuilder : IDisposable { - private readonly int _bufferSize = bufferSize; - private readonly Action _emit = emit; - - private NativeMemoryBuffer? _buffer; - private int _length; - private long _outputPosition; - private List? _coverSegments; + private NativeMemoryBuffer? _buffer; + private int _length; + private long _outputPosition; + private List? _coverSegments; + private readonly int _bufferSize; + private readonly Action _emit; + + internal PatchWorkBuilder(int bufferSize, + Action emit) + { + _bufferSize = bufferSize; + _emit = emit; + } public Span GetWritableSpan(long outputPosition, long requestedLength, @@ -542,24 +557,29 @@ public void Flush() public void Dispose() { - if (_buffer is not null) - { - _buffer.Dispose(); - _buffer = null; - } + if (_buffer is null) return; + + _buffer.Dispose(); + _buffer = null; } } - private sealed class RleDecoder(BittableStreamReader controlReader, - BittableStreamReader codeReader) + private sealed class RleDecoder { - private readonly BittableStreamReader _controlReader = controlReader; - private readonly BittableStreamReader _codeReader = codeReader; - private long _remaining; private byte _type; private byte _value; + private readonly BittableStreamReader _controlReader; + private readonly BittableStreamReader _codeReader; + + internal RleDecoder(BittableStreamReader controlReader, + BittableStreamReader codeReader) + { + _controlReader = controlReader; + _codeReader = codeReader; + } + public bool HasPendingData => _remaining != 0; public void Decode(Span destination, CancellationToken token) diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs index 3f0919a..b6db368 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs @@ -11,20 +11,28 @@ namespace SharpHPatchZ.Patch; -internal sealed partial class HDiff13DerivedPatcher( - BittableStreamReader coverReader, - BittableStreamReader rleCtrlReader, - BittableStreamReader rleCodeReader, - BittableStreamReader newDataReader, - HDiffInfo info, - PatchOptions options, - ProgressCallback progressCallback) - : PatcherBase(info, options, progressCallback) +internal sealed partial class HDiff13DerivedPatcher : PatcherBase { - private readonly BittableStreamReader _coverReader = coverReader; - private readonly BittableStreamReader _rleCtrlReader = rleCtrlReader; - private readonly BittableStreamReader _rleCodeReader = rleCodeReader; - private readonly BittableStreamReader _newDataReader = newDataReader; + private readonly BittableStreamReader _coverReader; + private readonly BittableStreamReader _rleCtrlReader; + private readonly BittableStreamReader _rleCodeReader; + private readonly BittableStreamReader _newDataReader; + + internal HDiff13DerivedPatcher( + BittableStreamReader coverReader, + BittableStreamReader rleCtrlReader, + BittableStreamReader rleCodeReader, + BittableStreamReader newDataReader, + HDiffInfo info, + PatchOptions options, + ProgressCallback progressCallback) + : base(info, options, progressCallback) + { + _coverReader = coverReader; + _rleCtrlReader = rleCtrlReader; + _rleCodeReader = rleCodeReader; + _newDataReader = newDataReader; + } private CopySimilarFilesContext? _copySimilarFilesContext; diff --git a/SharpHPatchZ/Patch/PatcherBase.cs b/SharpHPatchZ/Patch/PatcherBase.cs index cfc4c74..cd2a8c4 100644 --- a/SharpHPatchZ/Patch/PatcherBase.cs +++ b/SharpHPatchZ/Patch/PatcherBase.cs @@ -6,7 +6,7 @@ namespace SharpHPatchZ.Patch; -internal abstract class PatcherBase(HDiffInfo info, PatchOptions options, ProgressCallback progressCallback) +internal abstract class PatcherBase : IDisposable #if NET6_0_OR_GREATER , IAsyncDisposable @@ -15,12 +15,20 @@ internal abstract class PatcherBase(HDiffInfo info, PatchOptions options, Progre protected RandomMergedStreamWrapper? InputStream { get; set; } protected RandomMergedStreamWrapper? OutputStream { get; set; } - protected HDiffInfo Info { get; set; } = info; - protected PatchOptions Options { get; set; } = options; - protected ProgressCallback ProgressCallback { get; } = !progressCallback.IsAllocated ? new ProgressCallback() : progressCallback; + protected HDiffInfo Info { get; set; } + protected PatchOptions Options { get; set; } + protected ProgressCallback ProgressCallback { get; } protected long TotalWritten; - protected long TotalSize = info.GetPatchMetadata().DiffNewSize; + protected long TotalSize; + + protected PatcherBase(HDiffInfo info, PatchOptions options, ProgressCallback progressCallback) + { + Info = info; + Options = options; + ProgressCallback = !progressCallback.IsAllocated ? new ProgressCallback() : progressCallback; + TotalSize = info.GetPatchMetadata().DiffNewSize; + } public abstract void StartPatch(string inputPath, string outputPath, CancellationToken token); public abstract Task StartPatchAsync(string inputPath, string outputPath, CancellationToken token); From 87bbcb7ed9af38819282f26221784b790b7bd489 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Tue, 25 Aug 2026 03:44:52 +0700 Subject: [PATCH 48/72] Fix double disposal on compression stream + Reenable PrefetchedReadStream for Zstd --- SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs | 2 +- SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs b/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs index 5723de1..b0e721a 100644 --- a/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs +++ b/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs @@ -193,7 +193,7 @@ protected override void Dispose(bool disposing) if (disposing) { _disposeCancellation.Cancel(); - _source.Dispose(); + // Produce owns _source and disposes it after its final read. _producer.GetAwaiter().GetResult(); _current?.Dispose(); diff --git a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs index 90b5325..95f03f6 100644 --- a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs +++ b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs @@ -114,7 +114,7 @@ private static void EnableParallelDecompression(HDiffCompression compType, Stream[] streams, ChunkSizeInfo[] sizes) { - if (compType is HDiffCompression.Uncompressed or HDiffCompression.Zstd) + if (compType is HDiffCompression.Uncompressed) { return; } From 69cdadfd916979ae612c922182452dff9f8e74ab Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Tue, 25 Aug 2026 05:49:28 +0700 Subject: [PATCH 49/72] Update projects --- SharpHPatchZ.Program/SharpHPatchZ.Program.csproj | 4 ++-- SharpHPatchZ/SharpHPatchZ.csproj | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj b/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj index 08b5b76..a3bb18e 100644 --- a/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj +++ b/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj @@ -2,8 +2,8 @@ Exe - net10.0 - SharpHPatchZ.Program + net11.0 + SharpHPatchZ.Program SharpHPatchZ.Program disable enable diff --git a/SharpHPatchZ/SharpHPatchZ.csproj b/SharpHPatchZ/SharpHPatchZ.csproj index 85a0e19..41cdda5 100644 --- a/SharpHPatchZ/SharpHPatchZ.csproj +++ b/SharpHPatchZ/SharpHPatchZ.csproj @@ -24,10 +24,10 @@ 14 - - - - + + + + @@ -46,7 +46,7 @@ - + From b5e50fb153d0c517a888ba5ec2c0c817aff828dd Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Tue, 25 Aug 2026 06:06:54 +0700 Subject: [PATCH 50/72] Make SharpHPatchZ.Program compile-able on older .NET Framework 4.7.x --- SharpHPatchZ.Program/SharpHPatchZ.Program.csproj | 3 ++- .../System.CommandLine/Binding/BindingContext.cs | 5 ++++- .../System.CommandLine/Binding/TypeExtensions.cs | 5 ++++- .../System.CommandLine/DirectiveCollection.cs | 6 +++++- .../System.CommandLine/Parsing/OptionResult.cs | 2 ++ 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj b/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj index a3bb18e..76167ca 100644 --- a/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj +++ b/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj @@ -2,7 +2,7 @@ Exe - net11.0 + net472;net11.0 SharpHPatchZ.Program SharpHPatchZ.Program disable @@ -11,6 +11,7 @@ 3.0.0 true Debug;Release + 14 diff --git a/SharpHPatchZ.Program/System.CommandLine/Binding/BindingContext.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/BindingContext.cs index 7f2cbb5..bdb33a4 100644 --- a/SharpHPatchZ.Program/System.CommandLine/Binding/BindingContext.cs +++ b/SharpHPatchZ.Program/System.CommandLine/Binding/BindingContext.cs @@ -72,7 +72,10 @@ public void AddService(Func factory) internal bool TryGetValueSource( IValueDescriptor valueDescriptor, - [MaybeNullWhen(false)] out IValueSource valueSource) +#if NET6_0_OR_GREATER + [MaybeNullWhen(false)] +#endif + out IValueSource valueSource) { if (ServiceProvider.AvailableServiceTypes.Contains(valueDescriptor.ValueType)) { diff --git a/SharpHPatchZ.Program/System.CommandLine/Binding/TypeExtensions.cs b/SharpHPatchZ.Program/System.CommandLine/Binding/TypeExtensions.cs index b0b680a..79f0156 100644 --- a/SharpHPatchZ.Program/System.CommandLine/Binding/TypeExtensions.cs +++ b/SharpHPatchZ.Program/System.CommandLine/Binding/TypeExtensions.cs @@ -51,7 +51,10 @@ internal static bool IsEnumerable(this Type type) internal static bool TryGetNullableType( this Type type, - [NotNullWhen(true)] out Type? nullableType) +#if NET6_0_OR_GREATER + [NotNullWhen(true)] +#endif + out Type? nullableType) { nullableType = Nullable.GetUnderlyingType(type); return nullableType is not null; diff --git a/SharpHPatchZ.Program/System.CommandLine/DirectiveCollection.cs b/SharpHPatchZ.Program/System.CommandLine/DirectiveCollection.cs index 45a469d..636d8d8 100644 --- a/SharpHPatchZ.Program/System.CommandLine/DirectiveCollection.cs +++ b/SharpHPatchZ.Program/System.CommandLine/DirectiveCollection.cs @@ -52,7 +52,11 @@ public bool Contains(string name) /// The name of the directive. /// The values provided for the specified directive. /// if a directive with the specified name was parsed; otherwise, . - public bool TryGetValues(string name, [NotNullWhen(true)] out IReadOnlyList? values) + public bool TryGetValues(string name, +#if NET6_0_OR_GREATER + [NotNullWhen(true)] +#endif + out IReadOnlyList? values) { if (_directives is not null && _directives.TryGetValue(name, out var v)) diff --git a/SharpHPatchZ.Program/System.CommandLine/Parsing/OptionResult.cs b/SharpHPatchZ.Program/System.CommandLine/Parsing/OptionResult.cs index e1c2b95..38143d5 100644 --- a/SharpHPatchZ.Program/System.CommandLine/Parsing/OptionResult.cs +++ b/SharpHPatchZ.Program/System.CommandLine/Parsing/OptionResult.cs @@ -50,7 +50,9 @@ internal OptionResult( /// Gets the parsed value or the default value for . ///
/// The parsed value or the default value for +#if NET6_0_OR_GREATER [return: MaybeNull] +#endif public T GetValueOrDefault() => this.ConvertIfNeeded(typeof(T)) .GetValueOrDefault(); From 15603894017c4062f60f8108de13856ed03be25e Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Tue, 25 Aug 2026 06:10:16 +0700 Subject: [PATCH 51/72] [Program] Downgrade to .NET Framework 4.6.1 For compatibility testing. As per Microsoft documentation, .NET Standard should support down to .NET Framework 4.6.1 https://learn.microsoft.com/en-us/dotnet/standard/net-standard?tabs=net-standard-2-0 --- SharpHPatchZ.Program/SharpHPatchZ.Program.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj b/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj index 76167ca..ec69bed 100644 --- a/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj +++ b/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj @@ -2,7 +2,7 @@ Exe - net472;net11.0 + net461;net11.0 SharpHPatchZ.Program SharpHPatchZ.Program disable From cbf5a2ee830b334bcf5fb4cba9f5483f5b9bd91c Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Tue, 25 Aug 2026 06:47:04 +0700 Subject: [PATCH 52/72] Update ZstdNet usage --- SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs b/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs index a4afe2c..69198b8 100644 --- a/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs +++ b/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs @@ -15,13 +15,11 @@ using SharpHPatchZ.Header; using SharpHPatchZ.IO.Compression.BZip2; using SharpHPatchZ.IO.Compression.Lzma; -#if NETSTANDARD2_0_OR_GREATER || NET6_0_OR_GREATER using ZstdManagedDecompressor = ZstdSharp.Decompressor; using ZstdManagedDecompressorParameter = ZstdSharp.Unsafe.ZSTD_dParameter; using ZstdManagedStream = ZstdSharp.DecompressionStream; -#endif -#if !NETSTANDARD2_0_OR_GREATER +#if NET6_0_OR_GREATER using ZstdNativeDecompressor = ZstdNet.DecompressionOptions; using ZstdNativeDecompressorParameter = ZstdNet.ZSTD_dParameter; using ZstdNativeStream = ZstdNet.DecompressionStream; @@ -88,7 +86,7 @@ private static Stream CreateZstdStream(Stream rawStream, bool leaveOpen) { if (_createZstdStreamFallback != null) return _createZstdStreamFallback(rawStream, leaveOpen); -#if !(NETSTANDARD2_0_OR_GREATER || NET461_OR_GREATER) +#if NET6_0_OR_GREATER if (DllUtils.IsLibraryExist(DllUtils.DllName)) _createZstdStreamFallback = CreateZstdNativeStream; else @@ -105,12 +103,12 @@ private static Stream CreateZstdStream(Stream rawStream, bool leaveOpen) * Code Snippets (decompress_plugin_demo.h:963): * #define _ZSTD_WINDOWLOG_MAX ((sizeof(size_t)<=4)?30:31) */ -#if !NETSTANDARD2_0_OR_GREATER +#if NET6_0_OR_GREATER private static Stream CreateZstdNativeStream(Stream rawStream, bool leaveOpen) => new ZstdNativeStream(rawStream, new ZstdNativeDecompressor(null, new Dictionary { { ZstdNativeDecompressorParameter.ZSTD_d_windowLogMax, ZstdWindowLogMax } - })); + }), 0, leaveOpen); #endif private static Stream CreateZstdManagedStream(Stream rawStream, bool leaveOpen) From d3ff3c99ce7f8974e2b67edfcab7c753131a8a96 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Tue, 25 Aug 2026 06:47:11 +0700 Subject: [PATCH 53/72] Update SharpHPatchZ.Program.csproj --- SharpHPatchZ.Program/SharpHPatchZ.Program.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj b/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj index ec69bed..fd6f127 100644 --- a/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj +++ b/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj @@ -11,10 +11,10 @@ 3.0.0 true Debug;Release - 14 + 14 - + - + \ No newline at end of file From b46bd9916a410163d51b784ea48fe330defbecfb Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Tue, 25 Aug 2026 17:07:50 +0700 Subject: [PATCH 54/72] Add utility function + HPatch.TryGetHDiff13PatchMetadata (Extern: shpz_util_get_hdiff13_patch_metadata) + HPatch.TryGetHDiff19DirectoryPatchMetadata (Extern: shpz_util_get_hdiff19_patch_metadata) --- SharpHPatchZ/HPatch.UnmanagedExtern.cs | 9 ++++++ SharpHPatchZ/HPatch.Utility.cs | 45 ++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 SharpHPatchZ/HPatch.Utility.cs diff --git a/SharpHPatchZ/HPatch.UnmanagedExtern.cs b/SharpHPatchZ/HPatch.UnmanagedExtern.cs index c18eb3a..acb2746 100644 --- a/SharpHPatchZ/HPatch.UnmanagedExtern.cs +++ b/SharpHPatchZ/HPatch.UnmanagedExtern.cs @@ -7,6 +7,7 @@ using Microsoft.Win32.SafeHandles; using SharpHPatchZ.Extension; using SharpHPatchZ.Header; +using SharpHPatchZ.Header.Metadata; using SharpHPatchZ.Native; // ReSharper disable InconsistentNaming @@ -212,6 +213,14 @@ public static unsafe int SharpHPatchZ_FreeDiffInfo(HDiffInfo* ptr) } } + [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_util_get_hdiff13_patch_metadata")] + public static unsafe PatchMetadata* SharpHPatchZ_TryGetHDiff13PatchMetadata(HDiffInfo* infoP) + => (PatchMetadata*)Unsafe.AsPointer(ref infoP[0].GetPatchMetadata()); + + [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_util_get_hdiff19_patch_metadata")] + public static unsafe DirectoryPatchMetadata* SharpHPatchZ_TryGetHDiff19DirectoryPatchMetadata(HDiffInfo* infoP) + => (DirectoryPatchMetadata*)Unsafe.AsPointer(ref infoP[0].MetadataAs()); + [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_get_last_errorA")] public static unsafe int SharpHPatchZ_GetLastErrorUtf8(byte* bufferA, int bufferLength, ExceptionHelper.LastErrorMessageType messageType) => ExceptionHelper.TryGetLastErrorMessageUtf8(new Span(bufferA, bufferLength), messageType); diff --git a/SharpHPatchZ/HPatch.Utility.cs b/SharpHPatchZ/HPatch.Utility.cs new file mode 100644 index 0000000..be53fd4 --- /dev/null +++ b/SharpHPatchZ/HPatch.Utility.cs @@ -0,0 +1,45 @@ +using System; +using System.Runtime.CompilerServices; +using SharpHPatchZ.Header; +using SharpHPatchZ.Header.Metadata; + +namespace SharpHPatchZ; + +public static partial class HPatch +{ + public static bool TryGetHDiff13PatchMetadata( + ref HDiffInfo info, + out PatchMetadata patchMetadata) + { + Unsafe.SkipInit(out patchMetadata); + + ref PatchMetadata patchMetadataRef = ref info.GetPatchMetadata(); + if (Unsafe.IsNullRef(ref patchMetadataRef)) + { + return false; + } + + patchMetadata = patchMetadataRef; + return true; + } + + public static bool TryGetHDiff19DirectoryPatchMetadata( + ref HDiffInfo info, + out DirectoryPatchMetadata patchMetadata) + { + Unsafe.SkipInit(out patchMetadata); + + ref DirectoryPatchMetadata patchMetadataRef = ref info.MetadataAs(); + if (Unsafe.IsNullRef(ref patchMetadataRef)) + { + return false; + } + + patchMetadata = patchMetadataRef; + return true; + } + + public static unsafe Span TryGetUnmanagedArraySpan(UnmanagedArray* array) + where T : unmanaged + => array == null ? Span.Empty : array->GetSpan(); +} \ No newline at end of file From 722913357c321a9a447720964af935092bbbed65 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Tue, 25 Aug 2026 17:08:19 +0700 Subject: [PATCH 55/72] [Program] Print patch info --- SharpHPatchZ.Program/Program.cs | 66 ++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/SharpHPatchZ.Program/Program.cs b/SharpHPatchZ.Program/Program.cs index f5699dd..e2ae671 100644 --- a/SharpHPatchZ.Program/Program.cs +++ b/SharpHPatchZ.Program/Program.cs @@ -2,8 +2,10 @@ using System.CommandLine; using System.Diagnostics; using System.IO; +using System.Text; using System.Threading; using SharpHPatchZ.Header; +using SharpHPatchZ.Header.Metadata; // ReSharper disable InconsistentNaming // ReSharper disable CommentTypo @@ -99,7 +101,8 @@ public static int Main(params string[] args) ProgressCallback progressCallback = ProgressCallback.CreateFromManaged(PatchProgress); using HDiffInfo info = HPatch.CreateInstance(CreatePatchStream, initializeOptions); - PatchResult? result = HPatch.Patch(info, CreatePatchStream, inputPath, outputPath, options, progressCallback); + PrintFileInfo(info, inputPath, patchPath, outputPath, bufferSize); + PatchResult result = HPatch.Patch(info, CreatePatchStream, inputPath, outputPath, options, progressCallback); Console.WriteLine(); if (result.Exception != null) @@ -135,6 +138,67 @@ public static int Main(params string[] args) return Command.Invoke(args); } + private static unsafe void PrintFileInfo(HDiffInfo info, + string inputPath, + string patchPath, + string outputPath, + BufferSize bufferSizeType) + { + StringBuilder sb = new(); + sb.AppendLine($""" + Input Path : {inputPath} + Patch Path : {patchPath} + Output Path : {outputPath} + Buffer Type : {bufferSizeType} + Diff Type : {info.MagicType} + Diff File Size : {new FileInfo(patchPath).Length} + Compression Type : {info.CompressionType} + + """); + + if (HPatch.TryGetHDiff19DirectoryPatchMetadata(ref info, out DirectoryPatchMetadata dirPatchMetadata)) + { + sb.AppendLine($""" + Directory Patch Info (HDiff19 Extension): + Checksum Type : {info.ChecksumType} + New Path Count : {dirPatchMetadata.OutputPathListP->Length} (File Count: {dirPatchMetadata.SameFilePathCountSizeInfoP->Count + dirPatchMetadata.OutputFileIndexListP->Length}) + Identical File Count : {dirPatchMetadata.SameFilePathCountSizeInfoP->Count} (Total Size: {dirPatchMetadata.SameFilePathCountSizeInfoP->Size}) + Input Reference File Count : {dirPatchMetadata.InputFileIndexListP->Length} (Total Size: {dirPatchMetadata.InputPathCountSizeInfoP->Size}) + Output Reference File Count : {dirPatchMetadata.OutputFileIndexListP->Length} (Total Size: {dirPatchMetadata.OutputPathCountSizeInfoP->Size}) + Input Total File Size : {dirPatchMetadata.InputPathCountSizeInfoP->Size + dirPatchMetadata.SameFilePathCountSizeInfoP->Size} + Output Total File Size : {dirPatchMetadata.OutputPathCountSizeInfoP->Size + dirPatchMetadata.SameFilePathCountSizeInfoP->Size} + + """); + + if (dirPatchMetadata.InputFileSizeListP != null && + dirPatchMetadata.OutputFileHashesListP != null) + { + sb.AppendLine($""" + Kuro Games HDiff Extension Info: + Input File Asserted Count : {dirPatchMetadata.InputFileSizeListP->Length} + Output File Hashes Count : {dirPatchMetadata.OutputFileHashesListP->Length} + + """); + } + } + + if (HPatch.TryGetHDiff13PatchMetadata(ref info, out PatchMetadata patchMetadata)) + { + sb.AppendLine($""" + Generic Patch Info: + Input Size : {patchMetadata.DiffOldSize} + Output Size : {patchMetadata.DiffNewSize} + RLE Cover Info Count : {patchMetadata.CoverDataCount} + RLE Cover Info Size : {patchMetadata.CoverDataSizeP->Size} (Compressed Size: {patchMetadata.CoverDataSizeP->CompressedSize}) + RLE Control Size : {patchMetadata.RleControlDataSizeP->Size} (Compressed Size: {patchMetadata.RleControlDataSizeP->CompressedSize}) + RLE Code Size : {patchMetadata.RleCodeDataSizeP->Size} (Compressed Size: {patchMetadata.RleCodeDataSizeP->CompressedSize}) + RLE New Data Size : {patchMetadata.NewDiffDataSizeP->Size} (Compressed Size: {patchMetadata.NewDiffDataSizeP->CompressedSize}) + """); + } + + Console.WriteLine(sb.ToString()); + } + private static double lastSpeed; private static TimeSpan lastRemainedTime = TimeSpan.Zero; From 7f0508a83749c0f4b3229eae3497eb52e7b2a7f1 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sat, 29 Aug 2026 02:24:35 +0700 Subject: [PATCH 56/72] Code QA and fix read logic --- SharpHPatchZ/Extension/StreamExtension.cs | 6 +++--- SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs | 5 +++-- SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/SharpHPatchZ/Extension/StreamExtension.cs b/SharpHPatchZ/Extension/StreamExtension.cs index 06b531e..1073f01 100644 --- a/SharpHPatchZ/Extension/StreamExtension.cs +++ b/SharpHPatchZ/Extension/StreamExtension.cs @@ -30,7 +30,7 @@ public void ReadExactly( #if !NET6_0_OR_GREATER _ = stream.ReadAtLeast(buffer, offset, count, count, true); #else - _ = stream.ReadAtLeast(buffer.AsSpan(offset, count), count, true); + _ = stream.ReadAtLeast(buffer.AsSpan(offset, count), count); #endif } @@ -61,7 +61,7 @@ public int ReadAtLeast( int totalRead = offset; while (totalRead < minimumBytes) { - int read = stream.Read(buffer, totalRead, count - totalRead); + int read = stream.Read(buffer, offset + totalRead, count - totalRead); if (read == 0) { return throwOnEndOfStream ? throw new EndOfStreamException() : totalRead; @@ -86,7 +86,7 @@ public async ValueTask ReadAtLeastAsync( int totalRead = offset; while (totalRead < minimumBytes) { - int read = await stream.ReadAsync(buffer, totalRead, count - totalRead, cancellationToken).ConfigureAwait(false); + int read = await stream.ReadAsync(buffer, offset + totalRead, count - totalRead, cancellationToken).ConfigureAwait(false); if (read == 0) { return throwOnEndOfStream ? throw new EndOfStreamException() : totalRead; diff --git a/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs b/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs index fc6dc82..d1a36b4 100644 --- a/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs +++ b/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs @@ -84,7 +84,7 @@ public void Write(Span buffer, long offset) int writeLength = (int)Math.Min(buffer.Length, _fileStreamEnds[streamIndex] - offset); FileStream stream = GetFileStream(streamIndex); - RandomAccessCompat.Write(stream.SafeFileHandle!, + RandomAccessCompat.Write(stream.SafeFileHandle, buffer[..writeLength], offset - streamStart); @@ -114,7 +114,7 @@ public int Read(Span buffer, long offset) int readLength = (int)Math.Min(buffer.Length, _fileStreamEnds[streamIndex] - offset); FileStream stream = GetFileStream(streamIndex); - int read = RandomAccessCompat.Read(stream.SafeFileHandle!, + int read = RandomAccessCompat.Read(stream.SafeFileHandle, buffer[..readLength], offset - streamStart); @@ -158,6 +158,7 @@ public void Dispose() finally { _lifetimeLock.ExitWriteLock(); + _lifetimeLock.Dispose(); } } diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs index b6db368..c835360 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.cs @@ -99,7 +99,7 @@ public override void StartPatch(string inputPath, string outputPath, Cancellatio } public override Task StartPatchAsync(string inputPath, string outputPath, CancellationToken token) - => Task.Factory.StartNew(_ => StartPatch(inputPath, outputPath, token), + => Task.Factory.StartNew(state => StartPatch(inputPath, outputPath, (CancellationToken)state!), token, TaskCreationOptions.LongRunning); From c005bdff046b5b33abea7792888d741a0ed26ef9 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sat, 29 Aug 2026 03:30:59 +0700 Subject: [PATCH 57/72] [Program] Adjust options --- SharpHPatchZ.Program/Program.cs | 482 ++++++++++++++++++-------------- 1 file changed, 273 insertions(+), 209 deletions(-) diff --git a/SharpHPatchZ.Program/Program.cs b/SharpHPatchZ.Program/Program.cs index e2ae671..63c6a04 100644 --- a/SharpHPatchZ.Program/Program.cs +++ b/SharpHPatchZ.Program/Program.cs @@ -2,6 +2,8 @@ using System.CommandLine; using System.Diagnostics; using System.IO; +using System.Numerics; +using System.Runtime.Intrinsics.X86; using System.Text; using System.Threading; using SharpHPatchZ.Header; @@ -10,261 +12,323 @@ // ReSharper disable InconsistentNaming // ReSharper disable CommentTypo -namespace SharpHPatchZ.Program +namespace SharpHPatchZ.Program; + +public static class PatcherBin { - public static class PatcherBin + private static readonly string[] SizeSuffixes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; + private const int RefreshInterval = 100; + private static readonly RootCommand Command = new(); + private static readonly Stopwatch Stopwatch = Stopwatch.StartNew(); + private static readonly Stopwatch RefreshStopwatch = Stopwatch.StartNew(); + + public enum PatchPreset { - private static readonly string[] SizeSuffixes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; - private const int RefreshInterval = 100; - private static readonly RootCommand Command = new(); - private static readonly Stopwatch Stopwatch = Stopwatch.StartNew(); - private static readonly Stopwatch RefreshStopwatch = Stopwatch.StartNew(); + Performance, + Balanced, + MemoryOptimized, + OptimizedForHDD + } - public enum BufferSize - { - BigBuffer, - MediumBuffer, - SmallBuffer, - OptimizedForHDD - } + private static Argument RegisterTo(this Argument argument, Command command) + { + command.AddArgument(argument); + return argument; + } - public static int Main(params string[] args) + private static Option RegisterTo(this Option option, Command command) + { + command.AddOption(option); + return option; + } + + public static int Main(params string[] args) + { + Argument inputPathArg = new Argument("Input File", "Input path of the old file/folder to patch").RegisterTo(Command); + Argument patchPathArg = new Argument("Patch File", "Patch file path to produce the new version of the file/folder").RegisterTo(Command); + Argument outputPathArg = new Argument("Output File", "Output path of the new version to be produced").RegisterTo(Command); + + Option bufferModeOpt = new Option(["-p", "--preset"], () => PatchPreset.Performance, + """ + Determines the preset of the patching mode and also set its buffer size. + [Performance] + Buffer Size = Up to 16 MB per chunks + Threads = Automatic + + [Balanced] + Buffer Size = Up to 1 MB per chunks + Threads = Automatic + + [MemoryOptimized] + Buffer Size = Up to 128 KB per chunks + Threads = Automatic + + [OptimizedForHDD] + Buffer Size = Up to 16 MB per chunks + Threads = 1 + (Note: -p/--parallel-threads will be ignored with this mode) + + + """).RegisterTo(Command); + + Option threadsOpt = new Option(["-t", "--parallel-threads"], () => (uint)Environment.ProcessorCount, + "Determines how much parallel threads to be run.").RegisterTo(Command); + Option isKuroTypeOpt = new Option(["-k", "--kuro"], + "Defining that the patch file is a Kuro Games HDiff format.").RegisterTo(Command); + +#if NET6_0_OR_GREATER + Option useSimdOpt = new Option(["--simd"], + () => true, + "Whether to use SIMD calculation while performing RLE additions.").RegisterTo(Command); +#endif + + Option bufferCopyBufferSizeOpt = new Option(["--buffer-copy"], + "Determines how big the buffer size while performing copy routines to similar files.").RegisterTo(Command); + Option bufferPatchWorkerBufferSizeOpt = new Option(["--buffer-patch"], + "Determines how big the buffer size used by the patch worker.").RegisterTo(Command); + Option bufferReaderBufferSizeOpt = new Option(["--buffer-reader"], + "Determines how big the buffer size used by the RLE Stream Reader.").RegisterTo(Command); + + Command.SetHandler((context) => { - Argument inputPathArg, patchPathArg, outputPathArg; - Option bufferModeOpt; - Option threadsOpt; - Option isKuroTypeOpt; - - string inputPath, patchPath, outputPath; - bool isKuroType; - int threads; - - Command.AddArgument(inputPathArg = new Argument("Input File", "Input path of the old file/folder to patch")); - Command.AddArgument(patchPathArg = new Argument("Patch File", "Patch file path to produce the new version of the file/folder")); - Command.AddArgument(outputPathArg = new Argument("Output File", "Output path of the new version to be produced")); - Command.AddOption(bufferModeOpt = new Option(["-b", "--buffer-mode"], () => BufferSize.BigBuffer, - """ - Determines the buffering mode for reading the clips of the patch files. - [BigBuffer] - Buffer Size = Up to 16 MB per chunks - - [MediumBuffer] - Buffer Size = Up to 1 MB per chunks - - [SmallBuffer] - Buffer Size = Up to 128 KB per chunks - - [OptimizedForHDD] - Thread = 1, Buffer Size = Up to 16 MB per chunks - (Note: -p/--parallel-threads will be ignored with this mode) - - - """)); - Command.AddOption(threadsOpt = new Option(["-p", "--parallel-threads"], () => Environment.ProcessorCount, - "Determines how much parallel threads to be run.")); - Command.AddOption(isKuroTypeOpt = new Option(["-k", "--kuro"], () => false, - "Defining that the patch file is a Kuro Games HDiff format.")); - - Command.SetHandler((context) => + string inputPath = context.ParseResult.GetValueForArgument(inputPathArg); + string patchPath = context.ParseResult.GetValueForArgument(patchPathArg); + string outputPath = context.ParseResult.GetValueForArgument(outputPathArg); + bool isKuroType = context.ParseResult.GetValueForOption(isKuroTypeOpt); + uint threads = context.ParseResult.GetValueForOption(threadsOpt); + +#if NET6_0_OR_GREATER + bool useSimd = context.ParseResult.GetValueForOption(useSimdOpt); +#endif + + uint bufferCopyBufferSize = context.ParseResult.GetValueForOption(bufferCopyBufferSizeOpt); + uint bufferPatchWorkerBufferSize = context.ParseResult.GetValueForOption(bufferPatchWorkerBufferSizeOpt); + uint bufferReaderBufferSize = context.ParseResult.GetValueForOption(bufferReaderBufferSizeOpt); + + PatchPreset patchPreset = context.ParseResult.GetValueForOption(bufferModeOpt); + PatchOptions options = patchPreset switch + { + PatchPreset.Performance => PatchOptions.BigBuffer, + PatchPreset.Balanced => PatchOptions.Default, + PatchPreset.MemoryOptimized => PatchOptions.SmallBuffer, + PatchPreset.OptimizedForHDD => PatchOptions.OptimizeForHDD, + _ => PatchOptions.BigBuffer + }; + + if (bufferCopyBufferSize != 0) options.CopyBufferSize = (int)bufferCopyBufferSize; + if (bufferPatchWorkerBufferSize != 0) options.PatchWorkerBufferSize = (int)bufferPatchWorkerBufferSize; + if (bufferReaderBufferSize != 0) options.ReaderBufferSize = (int)bufferReaderBufferSize; + + InitializeOptions initializeOptions = new() { - inputPath = context.ParseResult.GetValueForArgument(inputPathArg); - patchPath = context.ParseResult.GetValueForArgument(patchPathArg); - outputPath = context.ParseResult.GetValueForArgument(outputPathArg); - isKuroType = context.ParseResult.GetValueForOption(isKuroTypeOpt); + IsKuroGamesHDiff = isKuroType + }; - BufferSize bufferSize = context.ParseResult.GetValueForOption(bufferModeOpt); - PatchOptions options = bufferSize switch - { - BufferSize.BigBuffer => PatchOptions.BigBuffer, - BufferSize.MediumBuffer => PatchOptions.Default, - BufferSize.SmallBuffer => PatchOptions.SmallBuffer, - BufferSize.OptimizedForHDD => PatchOptions.OptimizeForHDD, - _ => PatchOptions.BigBuffer - }; +#if NET6_0_OR_GREATER + if (useSimd) options.UseSIMD = useSimd; +#endif - InitializeOptions initializeOptions = new() + if (patchPreset != PatchPreset.OptimizedForHDD) + { + threads = context.ParseResult.GetValueForOption(threadsOpt); + options = options with { - IsKuroGamesHDiff = isKuroType + ParallelThreads = threads }; + } + + try + { + ProgressCallback progressCallback = ProgressCallback.CreateFromManaged(PatchProgress); + + using HDiffInfo info = HPatch.CreateInstance(CreatePatchStream, initializeOptions); + PrintFileInfo(info, inputPath, patchPath, outputPath, options, patchPreset); + PatchResult result = HPatch.Patch(info, CreatePatchStream, inputPath, outputPath, options, progressCallback); + Console.WriteLine(); - if (bufferSize != BufferSize.OptimizedForHDD) + if (result.Exception != null) { - threads = context.ParseResult.GetValueForOption(threadsOpt); - options = options with - { - ParallelThreads = (uint)threads - }; + Console.WriteLine($"Patching process throws an error: {result.Exception}"); + context.ExitCode = result; + return; } + Console.WriteLine($"Patch completed in: {Stopwatch.Elapsed:c} ({Stopwatch.Elapsed.TotalSeconds} seconds)"); - try + (Stream, bool) CreatePatchStream(long position) { - ProgressCallback progressCallback = ProgressCallback.CreateFromManaged(PatchProgress); - - using HDiffInfo info = HPatch.CreateInstance(CreatePatchStream, initializeOptions); - PrintFileInfo(info, inputPath, patchPath, outputPath, bufferSize); - PatchResult result = HPatch.Patch(info, CreatePatchStream, inputPath, outputPath, options, progressCallback); - Console.WriteLine(); - - if (result.Exception != null) - { - Console.WriteLine($"Patching process throws an error: {result.Exception}"); - context.ExitCode = result; - return; - } - Console.WriteLine($"Patch completed in: {Stopwatch.Elapsed:c} ({Stopwatch.Elapsed.TotalSeconds} seconds)"); - - (Stream, bool) CreatePatchStream(long position) - { - FileStream stream = File.Open(patchPath, FileMode.Open, FileAccess.Read, FileShare.Read); - stream.Position = position; - return (stream, false); - } + FileStream stream = File.Open(patchPath, FileMode.Open, FileAccess.Read, FileShare.Read); + stream.Position = position; + return (stream, false); } - catch (Exception ex) - { - Console.WriteLine($"An error has occurred! [{ex.GetType().Name}]: {ex.Message}\r\nStack Trace:\r\n{ex.StackTrace}"); - context.ExitCode = int.MinValue; + } + catch (Exception ex) + { + Console.WriteLine($"An error has occurred! [{ex.GetType().Name}]: {ex.Message}\r\nStack Trace:\r\n{ex.StackTrace}"); + context.ExitCode = int.MinValue; #if DEBUG - throw; + throw; #endif - } - finally - { - Stopwatch.Stop(); - RefreshStopwatch.Stop(); - } - }); + } + finally + { + Stopwatch.Stop(); + RefreshStopwatch.Stop(); + } + }); - return Command.Invoke(args); - } + return Command.Invoke(args); + } - private static unsafe void PrintFileInfo(HDiffInfo info, - string inputPath, - string patchPath, - string outputPath, - BufferSize bufferSizeType) +#if NET6_0_OR_GREATER + private static string DetermineSIMDCapability(PatchOptions options) + { + return options.UseSIMD switch + { + true when Avx2.IsSupported => "true (AVX2)", + true when Sse2.IsSupported => "true (SSE2)", + true when Vector.IsHardwareAccelerated => "true {Runtime-determined}", + _ => "false (Scalar)" + }; + } +#endif + + private static unsafe void PrintFileInfo(HDiffInfo info, + string inputPath, + string patchPath, + string outputPath, + PatchOptions options, + PatchPreset patchPresetType) + { + StringBuilder sb = new(); + sb.AppendLine($""" + Input Path : {inputPath} + Patch Path : {patchPath} + Output Path : {outputPath} + Buffer Type : {patchPresetType} + Diff Type : {info.MagicType} + Diff File Size : {new FileInfo(patchPath).Length} + Compression Type : {info.CompressionType} + + Options: + Max. Parallel Threads : {options.ParallelThreads} + Copy Buffer Size : {options.CopyBufferSize} + RLE Reader Buffer Size : {options.ReaderBufferSize} + Patch Worker Buffer Size : {options.PatchWorkerBufferSize} + """); + +#if NET6_0_OR_GREATER + sb.AppendLine($" Use SIMD? : {DetermineSIMDCapability(options)}"); +#endif + + if (HPatch.TryGetDirectoryPatchMetadata(ref info, out DirectoryPatchMetadata dirPatchMetadata)) { - StringBuilder sb = new(); sb.AppendLine($""" - Input Path : {inputPath} - Patch Path : {patchPath} - Output Path : {outputPath} - Buffer Type : {bufferSizeType} - Diff Type : {info.MagicType} - Diff File Size : {new FileInfo(patchPath).Length} - Compression Type : {info.CompressionType} + Directory Patch Info (HDiff19 Extension): + Checksum Type : {info.ChecksumType} + New Path Count : {dirPatchMetadata.OutputPathListP->Length} (File Count: {dirPatchMetadata.SameFilePathCountSizeInfoP->Count + dirPatchMetadata.OutputFileIndexListP->Length}) + Identical File Count : {dirPatchMetadata.SameFilePathCountSizeInfoP->Count} (Total Size: {dirPatchMetadata.SameFilePathCountSizeInfoP->Size}) + Input Reference File Count : {dirPatchMetadata.InputFileIndexListP->Length} (Total Size: {dirPatchMetadata.InputPathCountSizeInfoP->Size}) + Output Reference File Count : {dirPatchMetadata.OutputFileIndexListP->Length} (Total Size: {dirPatchMetadata.OutputPathCountSizeInfoP->Size}) + Input Total File Size : {dirPatchMetadata.InputPathCountSizeInfoP->Size + dirPatchMetadata.SameFilePathCountSizeInfoP->Size} + Output Total File Size : {dirPatchMetadata.OutputPathCountSizeInfoP->Size + dirPatchMetadata.SameFilePathCountSizeInfoP->Size} """); - if (HPatch.TryGetHDiff19DirectoryPatchMetadata(ref info, out DirectoryPatchMetadata dirPatchMetadata)) - { - sb.AppendLine($""" - Directory Patch Info (HDiff19 Extension): - Checksum Type : {info.ChecksumType} - New Path Count : {dirPatchMetadata.OutputPathListP->Length} (File Count: {dirPatchMetadata.SameFilePathCountSizeInfoP->Count + dirPatchMetadata.OutputFileIndexListP->Length}) - Identical File Count : {dirPatchMetadata.SameFilePathCountSizeInfoP->Count} (Total Size: {dirPatchMetadata.SameFilePathCountSizeInfoP->Size}) - Input Reference File Count : {dirPatchMetadata.InputFileIndexListP->Length} (Total Size: {dirPatchMetadata.InputPathCountSizeInfoP->Size}) - Output Reference File Count : {dirPatchMetadata.OutputFileIndexListP->Length} (Total Size: {dirPatchMetadata.OutputPathCountSizeInfoP->Size}) - Input Total File Size : {dirPatchMetadata.InputPathCountSizeInfoP->Size + dirPatchMetadata.SameFilePathCountSizeInfoP->Size} - Output Total File Size : {dirPatchMetadata.OutputPathCountSizeInfoP->Size + dirPatchMetadata.SameFilePathCountSizeInfoP->Size} - - """); - - if (dirPatchMetadata.InputFileSizeListP != null && - dirPatchMetadata.OutputFileHashesListP != null) - { - sb.AppendLine($""" - Kuro Games HDiff Extension Info: - Input File Asserted Count : {dirPatchMetadata.InputFileSizeListP->Length} - Output File Hashes Count : {dirPatchMetadata.OutputFileHashesListP->Length} - - """); - } - } - - if (HPatch.TryGetHDiff13PatchMetadata(ref info, out PatchMetadata patchMetadata)) + if (dirPatchMetadata.InputFileSizeListP != null && + dirPatchMetadata.OutputFileHashesListP != null) { sb.AppendLine($""" - Generic Patch Info: - Input Size : {patchMetadata.DiffOldSize} - Output Size : {patchMetadata.DiffNewSize} - RLE Cover Info Count : {patchMetadata.CoverDataCount} - RLE Cover Info Size : {patchMetadata.CoverDataSizeP->Size} (Compressed Size: {patchMetadata.CoverDataSizeP->CompressedSize}) - RLE Control Size : {patchMetadata.RleControlDataSizeP->Size} (Compressed Size: {patchMetadata.RleControlDataSizeP->CompressedSize}) - RLE Code Size : {patchMetadata.RleCodeDataSizeP->Size} (Compressed Size: {patchMetadata.RleCodeDataSizeP->CompressedSize}) - RLE New Data Size : {patchMetadata.NewDiffDataSizeP->Size} (Compressed Size: {patchMetadata.NewDiffDataSizeP->CompressedSize}) + + Kuro Games HDiff Extension Info: + Input File Asserted Count : {dirPatchMetadata.InputFileSizeListP->Length} + Output File Hashes Count : {dirPatchMetadata.OutputFileHashesListP->Length} """); } - - Console.WriteLine(sb.ToString()); } - private static double lastSpeed; - private static TimeSpan lastRemainedTime = TimeSpan.Zero; - - public static void PatchProgress(long totalProcessed, long totalSize, int written) + if (HPatch.TryGetPatchMetadata(ref info, out PatchMetadata patchMetadata)) { - double speed = CalculateSpeed(written); - double percent = Math.Round(totalProcessed / (double)totalSize * 100, 2); + sb.AppendLine($""" + + Generic Patch Info: + Input Size : {patchMetadata.DiffOldSize} + Output Size : {patchMetadata.DiffNewSize} + RLE Cover Info Count : {patchMetadata.CoverDataCount} + RLE Cover Info Size : {patchMetadata.CoverDataSizeP->Size} (Compressed Size: {patchMetadata.CoverDataSizeP->CompressedSize}) + RLE Control Size : {patchMetadata.RleControlDataSizeP->Size} (Compressed Size: {patchMetadata.RleControlDataSizeP->CompressedSize}) + RLE Code Size : {patchMetadata.RleCodeDataSizeP->Size} (Compressed Size: {patchMetadata.RleCodeDataSizeP->CompressedSize}) + RLE New Data Size : {patchMetadata.NewDiffDataSizeP->Size} (Compressed Size: {patchMetadata.NewDiffDataSizeP->CompressedSize}) + """); + } - if (CheckIfNeedRefreshStopwatch()) - { - lastRemainedTime = TimeSpan.FromSeconds((totalSize - totalProcessed) / UnZeroed(speed)); - Interlocked.Exchange(ref lastSpeed, speed); - } + Console.WriteLine(sb.ToString()); + } - Console.Write( - $"Patching: {percent}% | " + - $"{SummarizeSizeSimple(totalProcessed)}/{SummarizeSizeSimple(totalSize)} " + - $"@{SummarizeSizeSimple(lastSpeed)}/s " + - $"[{string.Format("{0:hh}h:{0:mm}m:{0:ss}s remaining", lastRemainedTime)}] \r"); + private static double lastSpeed; + private static TimeSpan lastRemainedTime = TimeSpan.Zero; - return; - static double UnZeroed(double input) => Math.Max(input, 1); + public static void PatchProgress(long totalProcessed, long totalSize, int written) + { + double speed = CalculateSpeed(written); + double percent = Math.Round(totalProcessed / (double)totalSize * 100, 2); + + if (CheckIfNeedRefreshStopwatch()) + { + lastRemainedTime = TimeSpan.FromSeconds((totalSize - totalProcessed) / UnZeroed(speed)); + Interlocked.Exchange(ref lastSpeed, speed); } - private const double ScOneSecond = 1000; - private static long _scLastTick = Environment.TickCount; - private static long _scLastReceivedBytes; - private static double _scLastSpeed; - private static int _riLastTick = Environment.TickCount; - private static double CalculateSpeed(long receivedBytes) => CalculateSpeed(receivedBytes, ref _scLastSpeed, ref _scLastReceivedBytes, ref _scLastTick); + Console.Write( + $"Patching: {percent}% | " + + $"{SummarizeSizeSimple(totalProcessed)}/{SummarizeSizeSimple(totalSize)} " + + $"@{SummarizeSizeSimple(lastSpeed)}/s " + + $"[{string.Format("{0:hh}h:{0:mm}m:{0:ss}s remaining", lastRemainedTime)}] \r"); - private static double CalculateSpeed(long receivedBytes, ref double lastSpeedToUse, ref long lastReceivedBytesToUse, ref long lastTickToUse) - { - long currentTick = Environment.TickCount - lastTickToUse + 1; - long totalReceivedInSecond = Interlocked.Add(ref lastReceivedBytesToUse, receivedBytes); - double speed = totalReceivedInSecond * ScOneSecond / currentTick; + return; + static double UnZeroed(double input) => Math.Max(input, 1); + } + private const double ScOneSecond = 1000; + private static long _scLastTick = Environment.TickCount; + private static long _scLastReceivedBytes; + private static double _scLastSpeed; + private static int _riLastTick = Environment.TickCount; - if (!(currentTick > ScOneSecond)) - { - return lastSpeedToUse; - } + private static double CalculateSpeed(long receivedBytes) => CalculateSpeed(receivedBytes, ref _scLastSpeed, ref _scLastReceivedBytes, ref _scLastTick); + + private static double CalculateSpeed(long receivedBytes, ref double lastSpeedToUse, ref long lastReceivedBytesToUse, ref long lastTickToUse) + { + long currentTick = Environment.TickCount - lastTickToUse + 1; + long totalReceivedInSecond = Interlocked.Add(ref lastReceivedBytesToUse, receivedBytes); + double speed = totalReceivedInSecond * ScOneSecond / currentTick; - lastSpeedToUse = speed; - _ = Interlocked.Exchange(ref lastSpeedToUse, speed); - _ = Interlocked.Exchange(ref lastReceivedBytesToUse, 0); - _ = Interlocked.Exchange(ref lastTickToUse, Environment.TickCount); + if (!(currentTick > ScOneSecond)) + { return lastSpeedToUse; } - public static bool CheckIfNeedRefreshStopwatch() - { - int currentTick = Environment.TickCount - _riLastTick; - if (currentTick <= RefreshInterval) - { - return false; - } + lastSpeedToUse = speed; + _ = Interlocked.Exchange(ref lastSpeedToUse, speed); + _ = Interlocked.Exchange(ref lastReceivedBytesToUse, 0); + _ = Interlocked.Exchange(ref lastTickToUse, Environment.TickCount); + return lastSpeedToUse; + } - Interlocked.Exchange(ref _riLastTick, Environment.TickCount); - return true; + public static bool CheckIfNeedRefreshStopwatch() + { + int currentTick = Environment.TickCount - _riLastTick; + if (currentTick <= RefreshInterval) + { + return false; } - private static string SummarizeSizeSimple(double value, int decimalPlaces = 2) - { - byte mag = (byte)Math.Log(value, 1000); + Interlocked.Exchange(ref _riLastTick, Environment.TickCount); + return true; + } - return $"{Math.Round(value / (1L << (mag * 10)), decimalPlaces)} {SizeSuffixes[mag]}"; - } + private static string SummarizeSizeSimple(double value, int decimalPlaces = 2) + { + byte mag = (byte)Math.Log(value, 1000); + + return $"{Math.Round(value / (1L << (mag * 10)), decimalPlaces)} {SizeSuffixes[mag]}"; } } From 4bfc2f4ccf98b2da34054cd6bbfa326281182f04 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sat, 29 Aug 2026 05:28:56 +0700 Subject: [PATCH 58/72] [Program] Split commands for patch and info --- SharpHPatchZ.Program/Program.cs | 329 ++++++++++++++---- .../Header/Metadata/Utf16UnmanagedString.cs | 4 + 2 files changed, 257 insertions(+), 76 deletions(-) diff --git a/SharpHPatchZ.Program/Program.cs b/SharpHPatchZ.Program/Program.cs index 63c6a04..335c18b 100644 --- a/SharpHPatchZ.Program/Program.cs +++ b/SharpHPatchZ.Program/Program.cs @@ -1,13 +1,18 @@ -using System; +using SharpHPatchZ.Header; +using SharpHPatchZ.Header.Metadata; +using System; using System.CommandLine; using System.Diagnostics; using System.IO; -using System.Numerics; -using System.Runtime.Intrinsics.X86; using System.Text; using System.Threading; -using SharpHPatchZ.Header; -using SharpHPatchZ.Header.Metadata; + +#if NET6_0_OR_GREATER +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; +#endif // ReSharper disable InconsistentNaming // ReSharper disable CommentTypo @@ -42,11 +47,14 @@ private static Option RegisterTo(this Option option, Command command) return option; } - public static int Main(params string[] args) + private static void AddCommandPatch(RootCommand command) { - Argument inputPathArg = new Argument("Input File", "Input path of the old file/folder to patch").RegisterTo(Command); - Argument patchPathArg = new Argument("Patch File", "Patch file path to produce the new version of the file/folder").RegisterTo(Command); - Argument outputPathArg = new Argument("Output File", "Output path of the new version to be produced").RegisterTo(Command); + Command patchCommand = new("patch", "Perform patch using provided Input, Patch and Output files"); + command.AddCommand(patchCommand); + + Argument inputPathArg = new Argument("Input File", "Input path of the old file/folder to patch").RegisterTo(patchCommand); + Argument patchPathArg = new Argument("Patch File", "Patch file path to produce the new version of the file/folder").RegisterTo(patchCommand); + Argument outputPathArg = new Argument("Output File", "Output path of the new version to be produced").RegisterTo(patchCommand); Option bufferModeOpt = new Option(["-p", "--preset"], () => PatchPreset.Performance, """ @@ -69,55 +77,55 @@ Determines the preset of the patching mode and also set its buffer size. (Note: -p/--parallel-threads will be ignored with this mode) - """).RegisterTo(Command); + """).RegisterTo(patchCommand); Option threadsOpt = new Option(["-t", "--parallel-threads"], () => (uint)Environment.ProcessorCount, - "Determines how much parallel threads to be run.").RegisterTo(Command); + "Determines how much parallel threads to be run.").RegisterTo(patchCommand); Option isKuroTypeOpt = new Option(["-k", "--kuro"], - "Defining that the patch file is a Kuro Games HDiff format.").RegisterTo(Command); + "Defining that the patch file is a Kuro Games HDiff format.").RegisterTo(patchCommand); #if NET6_0_OR_GREATER Option useSimdOpt = new Option(["--simd"], () => true, - "Whether to use SIMD calculation while performing RLE additions.").RegisterTo(Command); + "Whether to use SIMD calculation while performing RLE additions.").RegisterTo(patchCommand); #endif Option bufferCopyBufferSizeOpt = new Option(["--buffer-copy"], - "Determines how big the buffer size while performing copy routines to similar files.").RegisterTo(Command); + "Determines how big the buffer size while performing copy routines to similar files.").RegisterTo(patchCommand); Option bufferPatchWorkerBufferSizeOpt = new Option(["--buffer-patch"], - "Determines how big the buffer size used by the patch worker.").RegisterTo(Command); + "Determines how big the buffer size used by the patch worker.").RegisterTo(patchCommand); Option bufferReaderBufferSizeOpt = new Option(["--buffer-reader"], - "Determines how big the buffer size used by the RLE Stream Reader.").RegisterTo(Command); + "Determines how big the buffer size used by the RLE Stream Reader.").RegisterTo(patchCommand); - Command.SetHandler((context) => + patchCommand.SetHandler(context => { - string inputPath = context.ParseResult.GetValueForArgument(inputPathArg); - string patchPath = context.ParseResult.GetValueForArgument(patchPathArg); + string inputPath = context.ParseResult.GetValueForArgument(inputPathArg); + string patchPath = context.ParseResult.GetValueForArgument(patchPathArg); string outputPath = context.ParseResult.GetValueForArgument(outputPathArg); - bool isKuroType = context.ParseResult.GetValueForOption(isKuroTypeOpt); - uint threads = context.ParseResult.GetValueForOption(threadsOpt); + bool isKuroType = context.ParseResult.GetValueForOption(isKuroTypeOpt); + uint threads = context.ParseResult.GetValueForOption(threadsOpt); #if NET6_0_OR_GREATER bool useSimd = context.ParseResult.GetValueForOption(useSimdOpt); #endif - uint bufferCopyBufferSize = context.ParseResult.GetValueForOption(bufferCopyBufferSizeOpt); + uint bufferCopyBufferSize = context.ParseResult.GetValueForOption(bufferCopyBufferSizeOpt); uint bufferPatchWorkerBufferSize = context.ParseResult.GetValueForOption(bufferPatchWorkerBufferSizeOpt); - uint bufferReaderBufferSize = context.ParseResult.GetValueForOption(bufferReaderBufferSizeOpt); + uint bufferReaderBufferSize = context.ParseResult.GetValueForOption(bufferReaderBufferSizeOpt); PatchPreset patchPreset = context.ParseResult.GetValueForOption(bufferModeOpt); PatchOptions options = patchPreset switch { - PatchPreset.Performance => PatchOptions.BigBuffer, - PatchPreset.Balanced => PatchOptions.Default, + PatchPreset.Performance => PatchOptions.BigBuffer, + PatchPreset.Balanced => PatchOptions.Default, PatchPreset.MemoryOptimized => PatchOptions.SmallBuffer, PatchPreset.OptimizedForHDD => PatchOptions.OptimizeForHDD, - _ => PatchOptions.BigBuffer + _ => PatchOptions.BigBuffer }; - if (bufferCopyBufferSize != 0) options.CopyBufferSize = (int)bufferCopyBufferSize; + if (bufferCopyBufferSize != 0) options.CopyBufferSize = (int)bufferCopyBufferSize; if (bufferPatchWorkerBufferSize != 0) options.PatchWorkerBufferSize = (int)bufferPatchWorkerBufferSize; - if (bufferReaderBufferSize != 0) options.ReaderBufferSize = (int)bufferReaderBufferSize; + if (bufferReaderBufferSize != 0) options.ReaderBufferSize = (int)bufferReaderBufferSize; InitializeOptions initializeOptions = new() { @@ -141,9 +149,9 @@ Determines the preset of the patching mode and also set its buffer size. { ProgressCallback progressCallback = ProgressCallback.CreateFromManaged(PatchProgress); - using HDiffInfo info = HPatch.CreateInstance(CreatePatchStream, initializeOptions); + using HDiffInfo info = HPatch.CreateInstance(pos => CreatePatchStream(patchPath, pos), initializeOptions); PrintFileInfo(info, inputPath, patchPath, outputPath, options, patchPreset); - PatchResult result = HPatch.Patch(info, CreatePatchStream, inputPath, outputPath, options, progressCallback); + PatchResult result = HPatch.Patch(info, pos => CreatePatchStream(patchPath, pos), inputPath, outputPath, options, progressCallback); Console.WriteLine(); if (result.Exception != null) @@ -153,13 +161,6 @@ Determines the preset of the patching mode and also set its buffer size. return; } Console.WriteLine($"Patch completed in: {Stopwatch.Elapsed:c} ({Stopwatch.Elapsed.TotalSeconds} seconds)"); - - (Stream, bool) CreatePatchStream(long position) - { - FileStream stream = File.Open(patchPath, FileMode.Open, FileAccess.Read, FileShare.Read); - stream.Position = position; - return (stream, false); - } } catch (Exception ex) { @@ -175,7 +176,178 @@ Determines the preset of the patching mode and also set its buffer size. RefreshStopwatch.Stop(); } }); + } + + private static (Stream, bool) CreatePatchStream(string patchPath, long position) + { + FileStream stream = File.Open(patchPath, FileMode.Open, FileAccess.Read, FileShare.Read); + stream.Position = position; + return (stream, false); + } + + private static void AddCommandInfo(RootCommand command) + { + Command infoCommand = new("info", "Prints information about the patch file"); + command.AddCommand(infoCommand); + + Argument patchFileArg = new Argument("Patch File", "The path of the patch file in which to get the info from.").RegisterTo(infoCommand); + + Option verbosePrint = new Option("--verbose", + () => false, + "Prints more verbose information about the patch file. If the patch file is a directory patch, this will print the reference file paths as well.") + .RegisterTo(infoCommand); + + infoCommand.SetHandler(context => + { + string patchFilePath = context.ParseResult.GetValueForArgument(patchFileArg); + bool isVerbosePrint = context.ParseResult.GetValueForOption(verbosePrint); + + HDiffInfo info = new(); + try + { + info = HPatch.CreateInstance(pos => CreatePatchStream(patchFilePath, pos)); + PrintFileInfo(info); + if (isVerbosePrint && + HPatch.TryGetDirectoryPatchMetadata(ref info, out DirectoryPatchMetadata directoryPatch)) + { + unsafe + { + if (directoryPatch.InputPathListP != null) + { + PrintPathList("Input Path List:", + directoryPatch.InputPathListP, + directoryPatch.InputFileSizeListP, + directoryPatch.InputFileIndexListP, + null); + } + + if (directoryPatch.OutputPathListP != null) + { + PrintPathList("Output Path List:", + directoryPatch.OutputPathListP, + directoryPatch.OutputFileSizeListP, + directoryPatch.OutputFileIndexListP, + directoryPatch.OutputFileHashesListP); + } + + if (directoryPatch.SameFilePathIndexPairP != null && + directoryPatch.SameFilePathCountSizeInfoP != null && + directoryPatch.InputPathListP != null && + directoryPatch.OutputPathListP != null) + { + Console.WriteLine("Same File Copy List:"); + + void* p = directoryPatch.SameFilePathIndexPairP; + int count = directoryPatch.SameFilePathCountSizeInfoP->Count; + var sameFileIndexPairSpan = new Span(p, count); + + Span inputPathList = directoryPatch.InputPathListP->GetSpan(); + Span outputPathList = directoryPatch.OutputPathListP->GetSpan(); + for (int i = 0; i < count; i++) + { + ref FileIndexPair pair = ref sameFileIndexPairSpan[i]; + ref Utf16UnmanagedString inputPath = ref inputPathList[pair.OldIndex]; + ref Utf16UnmanagedString outputPath = ref outputPathList[pair.NewIndex]; + + Console.WriteLine($" {inputPath} ->> {outputPath}"); + } + + Console.WriteLine(); + } + } + } + + static unsafe void PrintPathList( + string msgType, + UnmanagedArray* pathList, + UnmanagedArray* pathSizeList, + UnmanagedArray* pathFileIndexList, + UnmanagedArray* pathFileHashList) + { + Console.WriteLine(msgType); + Span pathArray = pathList->GetSpan(); + Span fileSizeArray = pathSizeList == null ? + Span.Empty : pathSizeList->GetSpan(); + + Span fileHashArray = pathFileHashList == null ? + Span.Empty : pathFileHashList->GetSpan(); + + for (int i = 0; i < pathArray.Length; i++) + { + ref Utf16UnmanagedString pathStr = ref pathArray[i]; + string pathType = GetPathType(ref pathStr, out bool isDirectory); + + if (isDirectory) + { + Console.WriteLine($" {pathType}: {(pathStr == "" ? "(root)" : pathStr)}"); + } + } + + Span fileIndexList = pathFileIndexList->GetSpan(); + for (int i = 0; i < fileIndexList.Length; i++) + { + ref int index = ref fileIndexList[i]; + ref Utf16UnmanagedString pathStr = ref pathArray[index]; + + string tail = ""; + if (!fileSizeArray.IsEmpty) + { + ref long pathSize = ref fileSizeArray[i]; + tail = $" ({pathSize} bytes)"; + } + +#if NET6_0_OR_GREATER + if (!fileHashArray.IsEmpty) + { + ref long fileHash = ref fileHashArray[i]; + Span hashBytes = MemoryMarshal.AsBytes(new Span(Unsafe.AsPointer(ref fileHash), sizeof(long))); + + string hexString = Convert.ToHexString(hashBytes); + tail += $" (Hash: {hexString})"; + } +#endif + + Console.WriteLine($" File: {(pathStr == "" ? "(root)" : pathStr)}{tail}"); + } + + Console.WriteLine(); + } + + static string GetPathType(ref Utf16UnmanagedString inputPathStr, out bool isDirectory) + { + ReadOnlySpan inputPathSpan = inputPathStr; + if (inputPathSpan.IsEmpty) + { + isDirectory = true; + return "Directory"; + } + + // ReSharper disable once AssignmentInConditionalExpression + return (isDirectory = !inputPathSpan.IsEmpty && inputPathSpan[^1] is '/' or '\\') + ? "Directory" + : "File"; + } + } + catch (Exception ex) + { + Console.WriteLine( + $"An error has occurred! [{ex.GetType().Name}]: {ex.Message}\r\nStack Trace:\r\n{ex.StackTrace}"); + context.ExitCode = int.MinValue; +#if DEBUG + throw; +#endif + } + finally + { + info.Dispose(); + } + }); + } + public static int Main(params string[] args) + { + AddCommandPatch(Command); + AddCommandInfo(Command); return Command.Invoke(args); } @@ -192,33 +364,24 @@ private static string DetermineSIMDCapability(PatchOptions options) } #endif - private static unsafe void PrintFileInfo(HDiffInfo info, - string inputPath, - string patchPath, - string outputPath, - PatchOptions options, - PatchPreset patchPresetType) + private static unsafe void PrintFileInfo(HDiffInfo info) { StringBuilder sb = new(); - sb.AppendLine($""" - Input Path : {inputPath} - Patch Path : {patchPath} - Output Path : {outputPath} - Buffer Type : {patchPresetType} - Diff Type : {info.MagicType} - Diff File Size : {new FileInfo(patchPath).Length} - Compression Type : {info.CompressionType} - - Options: - Max. Parallel Threads : {options.ParallelThreads} - Copy Buffer Size : {options.CopyBufferSize} - RLE Reader Buffer Size : {options.ReaderBufferSize} - Patch Worker Buffer Size : {options.PatchWorkerBufferSize} - """); - -#if NET6_0_OR_GREATER - sb.AppendLine($" Use SIMD? : {DetermineSIMDCapability(options)}"); -#endif + if (HPatch.TryGetPatchMetadata(ref info, out PatchMetadata patchMetadata)) + { + sb.AppendLine($""" + Generic Patch Info: + Diff Type : {info.MagicType} + Compression Type : {info.CompressionType} + Input Size : {patchMetadata.DiffOldSize} + Output Size : {patchMetadata.DiffNewSize} + RLE Cover Info Count : {patchMetadata.CoverDataCount} + RLE Cover Info Size : {patchMetadata.CoverDataSizeP->Size} (Compressed Size: {patchMetadata.CoverDataSizeP->CompressedSize}) + RLE Control Size : {patchMetadata.RleControlDataSizeP->Size} (Compressed Size: {patchMetadata.RleControlDataSizeP->CompressedSize}) + RLE Code Size : {patchMetadata.RleCodeDataSizeP->Size} (Compressed Size: {patchMetadata.RleCodeDataSizeP->CompressedSize}) + RLE New Data Size : {patchMetadata.NewDiffDataSizeP->Size} (Compressed Size: {patchMetadata.NewDiffDataSizeP->CompressedSize}) + """); + } if (HPatch.TryGetDirectoryPatchMetadata(ref info, out DirectoryPatchMetadata dirPatchMetadata)) { @@ -246,22 +409,36 @@ Directory Patch Info (HDiff19 Extension): } } - if (HPatch.TryGetPatchMetadata(ref info, out PatchMetadata patchMetadata)) - { - sb.AppendLine($""" - - Generic Patch Info: - Input Size : {patchMetadata.DiffOldSize} - Output Size : {patchMetadata.DiffNewSize} - RLE Cover Info Count : {patchMetadata.CoverDataCount} - RLE Cover Info Size : {patchMetadata.CoverDataSizeP->Size} (Compressed Size: {patchMetadata.CoverDataSizeP->CompressedSize}) - RLE Control Size : {patchMetadata.RleControlDataSizeP->Size} (Compressed Size: {patchMetadata.RleControlDataSizeP->CompressedSize}) - RLE Code Size : {patchMetadata.RleCodeDataSizeP->Size} (Compressed Size: {patchMetadata.RleCodeDataSizeP->CompressedSize}) - RLE New Data Size : {patchMetadata.NewDiffDataSizeP->Size} (Compressed Size: {patchMetadata.NewDiffDataSizeP->CompressedSize}) - """); - } + Console.WriteLine(sb.ToString()); + } + private static void PrintFileInfo(HDiffInfo info, + string inputPath, + string patchPath, + string outputPath, + PatchOptions options, + PatchPreset patchPresetType) + { + StringBuilder sb = new(); + sb.AppendLine($""" + Input Path : {inputPath} + Output Path : {outputPath} + Patch Path : {patchPath} + + Options: + Preset : {patchPresetType} + Max. Parallel Threads : {options.ParallelThreads} + Copy Buffer Size : {options.CopyBufferSize} + RLE Reader Buffer Size : {options.ReaderBufferSize} + Patch Worker Buffer Size : {options.PatchWorkerBufferSize} + """); + +#if NET6_0_OR_GREATER + sb.AppendLine($" Use SIMD? : {DetermineSIMDCapability(options)}"); +#endif Console.WriteLine(sb.ToString()); + + PrintFileInfo(info); } private static double lastSpeed; diff --git a/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs b/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs index 3b6b45d..e1291af 100644 --- a/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs +++ b/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs @@ -99,6 +99,8 @@ public static Utf16UnmanagedString CreateFromManaged(scoped ReadOnlySpan s return thisStruct; } + public ReadOnlySpan GetSpan() => Native.GetSpan(); + public static implicit operator ReadOnlySpan(Utf16UnmanagedString unmanaged) => unmanaged.Native; @@ -147,5 +149,7 @@ public static implicit operator string(NativeStringW unmanaged) => unmanaged.Length == 0 ? "" : unmanaged.ToString(); + + public ReadOnlySpan GetSpan() => this; } } From f1507b03056fff39d13718fb1d8e76e7150b3f3f Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sat, 29 Aug 2026 05:29:43 +0700 Subject: [PATCH 59/72] Rename extern - shpz_util_get_hdiff13_patch_metadata -> shpz_util_get_patch_metadata - shpz_util_get_hdiff19_patch_metadata -> shpz_util_get_directory_patch_metadata --- SharpHPatchZ/HPatch.UnmanagedExtern.cs | 10 ++--- SharpHPatchZ/HPatch.Utility.cs | 55 +++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/SharpHPatchZ/HPatch.UnmanagedExtern.cs b/SharpHPatchZ/HPatch.UnmanagedExtern.cs index acb2746..233ac1d 100644 --- a/SharpHPatchZ/HPatch.UnmanagedExtern.cs +++ b/SharpHPatchZ/HPatch.UnmanagedExtern.cs @@ -81,7 +81,7 @@ public static unsafe int SharpHPatchZ_InitializeFromFilePathAuto(void* pathP, HD { try { - string? filePath = StringExtension.GetManagedStringAuto(pathP); + string? filePath = StringExtension.GetManagedStringAuto(pathP); if (filePath == null) { throw ExceptionHelper.ThrowHDiffPathIsEmptyOrInvalid(); @@ -213,12 +213,12 @@ public static unsafe int SharpHPatchZ_FreeDiffInfo(HDiffInfo* ptr) } } - [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_util_get_hdiff13_patch_metadata")] - public static unsafe PatchMetadata* SharpHPatchZ_TryGetHDiff13PatchMetadata(HDiffInfo* infoP) + [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_util_get_patch_metadata")] + public static unsafe PatchMetadata* SharpHPatchZ_TryGetPatchMetadata(HDiffInfo* infoP) => (PatchMetadata*)Unsafe.AsPointer(ref infoP[0].GetPatchMetadata()); - [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_util_get_hdiff19_patch_metadata")] - public static unsafe DirectoryPatchMetadata* SharpHPatchZ_TryGetHDiff19DirectoryPatchMetadata(HDiffInfo* infoP) + [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_util_get_directory_patch_metadata")] + public static unsafe DirectoryPatchMetadata* SharpHPatchZ_TryGetDirectoryPatchMetadata(HDiffInfo* infoP) => (DirectoryPatchMetadata*)Unsafe.AsPointer(ref infoP[0].MetadataAs()); [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_get_last_errorA")] diff --git a/SharpHPatchZ/HPatch.Utility.cs b/SharpHPatchZ/HPatch.Utility.cs index be53fd4..186371d 100644 --- a/SharpHPatchZ/HPatch.Utility.cs +++ b/SharpHPatchZ/HPatch.Utility.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Runtime.CompilerServices; using SharpHPatchZ.Header; using SharpHPatchZ.Header.Metadata; @@ -7,7 +8,7 @@ namespace SharpHPatchZ; public static partial class HPatch { - public static bool TryGetHDiff13PatchMetadata( + public static bool TryGetPatchMetadata( ref HDiffInfo info, out PatchMetadata patchMetadata) { @@ -23,7 +24,7 @@ public static bool TryGetHDiff13PatchMetadata( return true; } - public static bool TryGetHDiff19DirectoryPatchMetadata( + public static bool TryGetDirectoryPatchMetadata( ref HDiffInfo info, out DirectoryPatchMetadata patchMetadata) { @@ -39,6 +40,56 @@ public static bool TryGetHDiff19DirectoryPatchMetadata( return true; } + public static bool TryGetDiffSizeInfo(ref HDiffInfo info, + out long totalInputSize, + out long totalOutputSize) + { + Unsafe.SkipInit(out totalInputSize); + Unsafe.SkipInit(out totalOutputSize); + + ref PatchMetadata patchMetadata = ref info.GetPatchMetadata(); + if (Unsafe.IsNullRef(ref patchMetadata)) + { + return false; + } + + totalInputSize = patchMetadata.DiffOldSize; + totalOutputSize = patchMetadata.DiffNewSize; + return true; + } + + public static bool TryGetDiffSizeInfo(CreateStream createStream, + out long totalInputSize, + out long totalOutputSize) + { + HDiffInfo info = CreateInstance(createStream); + try + { + return TryGetDiffSizeInfo(ref info, + out totalInputSize, + out totalOutputSize); + } + finally + { + info.Dispose(); + } + } + + public static bool TryGetDiffSizeInfo(Stream stream, + out long totalInputSize, + out long totalOutputSize) + { + return TryGetDiffSizeInfo(CreateStream, + out totalInputSize, + out totalOutputSize); + + (Stream, bool) CreateStream(long pos) + { + stream.Position = pos; + return (stream, true); + } + } + public static unsafe Span TryGetUnmanagedArraySpan(UnmanagedArray* array) where T : unmanaged => array == null ? Span.Empty : array->GetSpan(); From 76818a4034ea4860515ce532bbaa0209d9a84217 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sat, 29 Aug 2026 05:30:27 +0700 Subject: [PATCH 60/72] Add experimental C header for native library support WARNING: Fully Vibe-coded. Further test is required --- SharpHPatchZ/SharpHPatchZ.h | 443 ++++++++++++++++++++++++++++++++++++ 1 file changed, 443 insertions(+) create mode 100644 SharpHPatchZ/SharpHPatchZ.h diff --git a/SharpHPatchZ/SharpHPatchZ.h b/SharpHPatchZ/SharpHPatchZ.h new file mode 100644 index 0000000..6cf2bcf --- /dev/null +++ b/SharpHPatchZ/SharpHPatchZ.h @@ -0,0 +1,443 @@ +/* + * SharpHPatchZ native API + * + * This header describes the exports in HPatch.UnmanagedExtern.cs. The exports + * are available when SharpHPatchZ is published as a .NET 8+ NativeAOT shared + * library. + * + * SPDX-License-Identifier: MIT + */ + +#ifndef SHARP_HPATCH_Z_H +#define SHARP_HPATCH_Z_H + +#include +#include +#include + +/* + * Define SHPZ_STATIC when no import/export decoration is required. + * Define SHPZ_BUILD only while building the shared library itself. + */ +#ifndef SHPZ_API +# if defined(_WIN32) && !defined(SHPZ_STATIC) +# if defined(SHPZ_BUILD) +# define SHPZ_API __declspec(dllexport) +# else +# define SHPZ_API __declspec(dllimport) +# endif +# elif defined(__GNUC__) && defined(SHPZ_BUILD) +# define SHPZ_API __attribute__((visibility("default"))) +# else +# define SHPZ_API +# endif +#endif + +/* + * HPatch.UnmanagedExtern.cs uses cdecl unless its USEWINDOWS compilation + * symbol is defined. Define SHPZ_USE_STDCALL when consuming such a build. + */ +#ifndef SHPZ_CALL +# if defined(_WIN32) && defined(SHPZ_USE_STDCALL) +# define SHPZ_CALL __stdcall +# elif defined(_MSC_VER) +# define SHPZ_CALL __cdecl +# elif defined(__i386__) && (defined(__GNUC__) || defined(__clang__)) +# define SHPZ_CALL __attribute__((cdecl)) +# else +# define SHPZ_CALL +# endif +#endif + +/* Progress callbacks are always cdecl, including in stdcall API builds. */ +#ifndef SHPZ_CALLBACK +# if defined(_MSC_VER) +# define SHPZ_CALLBACK __cdecl +# elif defined(__i386__) && (defined(__GNUC__) || defined(__clang__)) +# define SHPZ_CALLBACK __attribute__((cdecl)) +# else +# define SHPZ_CALLBACK +# endif +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/* .NET char is always a 16-bit UTF-16 code unit; wchar_t is not portable. */ +typedef uint16_t shpz_char16_t; + +/* Fixed-width representations of the C# enums used by the ABI. */ +typedef int32_t shpz_hdiff_magic; +enum { + SHPZ_HDIFF_MAGIC_UNKNOWN = 0, + SHPZ_HDIFF_MAGIC_HDIFF13 = 1, + SHPZ_HDIFF_MAGIC_HDIFF19 = 2 +}; + +typedef int32_t shpz_hdiff_compression; +enum { + SHPZ_HDIFF_COMPRESSION_UNCOMPRESSED = 0, + SHPZ_HDIFF_COMPRESSION_LZMA = 1, + SHPZ_HDIFF_COMPRESSION_LZMA2 = 2, + SHPZ_HDIFF_COMPRESSION_ZLIB = 3, + SHPZ_HDIFF_COMPRESSION_PBZ2 = 4, + SHPZ_HDIFF_COMPRESSION_BZ2 = 5, + SHPZ_HDIFF_COMPRESSION_ZSTD = 6 +}; + +typedef int32_t shpz_hdiff_checksum; +enum { + SHPZ_HDIFF_CHECKSUM_NONE = 0, + SHPZ_HDIFF_CHECKSUM_FADLER64 = 1, + SHPZ_HDIFF_CHECKSUM_CRC32 = 2 +}; + +typedef int16_t shpz_metadata_type; +#define SHPZ_METADATA_MARKER ((shpz_metadata_type)(uint16_t)0x8080u) +#define SHPZ_METADATA_PATCH ((shpz_metadata_type)(uint16_t)0xC080u) +#define SHPZ_METADATA_DIRECTORY_PATCH ((shpz_metadata_type)(uint16_t)0xA080u) +#define SHPZ_METADATA_CHECKSUM_DATA ((shpz_metadata_type)(uint16_t)0x9080u) +#define SHPZ_METADATA_ARRAY ((shpz_metadata_type)(uint16_t)0x8880u) +#define SHPZ_METADATA_UTF16_STRING ((shpz_metadata_type)(uint16_t)0x8480u) + +typedef int32_t shpz_last_error_message_type; +enum { + SHPZ_LAST_ERROR_MESSAGE = 1, + SHPZ_LAST_ERROR_STACK_TRACE = 2, + SHPZ_LAST_ERROR_MESSAGE_AND_TRACE = 3 +}; + +/* Values returned by the exported functions. */ +enum { + SHPZ_SUCCESS = 0, + SHPZ_ERROR_UNKNOWN = -1, + + SHPZ_ERROR_HEADER_MAGIC_NOT_SUPPORTED = 0x10, + SHPZ_ERROR_COMPRESSION_NOT_SUPPORTED = 0x11, + SHPZ_ERROR_CHECKSUM_NOT_SUPPORTED = 0x12, + SHPZ_ERROR_PATCH_FACTORY_NOT_SUPPORTED = 0x13, + + SHPZ_ERROR_INFO_NOT_ALLOCATED = 0x30, + SHPZ_ERROR_DIRECTORY_METADATA_NOT_ALLOCATED = 0x31, + SHPZ_ERROR_PATCH_METADATA_NOT_ALLOCATED = 0x32, + SHPZ_ERROR_FILE_DESCRIPTOR_NULL = 0x33, + SHPZ_ERROR_ARGUMENT_NULL = 0x34, + + SHPZ_ERROR_HEADER_SIGNATURE_UNREADABLE = 0x50, + SHPZ_ERROR_END_OF_FILE_OR_DATA = 0x51, + SHPZ_ERROR_PATH_INVALID = 0x52, + SHPZ_ERROR_IO = 0x53, + SHPZ_ERROR_INPUT_PATH_NOT_FOUND = 0x54, + SHPZ_ERROR_INPUT_SIZE_MISMATCH = 0x55, + SHPZ_ERROR_PATH_NOT_DIRECTORY = 0x56, + SHPZ_ERROR_PATH_NOT_FILE = 0x57, + SHPZ_ERROR_INPUT_FILES_MISMATCH = 0x58, + SHPZ_ERROR_KURO_INPUT_SIZE_MISMATCH = 0x59, + SHPZ_ERROR_STREAM_READ_OUT_OF_BOUNDS = 0x5A, + SHPZ_ERROR_STRING_ENCODING = 0x5B, + + SHPZ_ERROR_LZMA_PROPERTY_MISSING = 0xA0, + SHPZ_ERROR_LZMA2_DICTIONARY_INVALID = 0xA1, + SHPZ_ERROR_LZMA2_NO_COMPRESSED_PAYLOAD = 0xA2, + SHPZ_ERROR_LZMA_DICTIONARY_LENGTH_INVALID = 0xA3, + SHPZ_ERROR_LZMA_DATA_TOO_SMALL = 0xA4 +}; + +/* Match StructLayout(LayoutKind.Sequential), whose default packing is 8. */ +#if defined(_MSC_VER) || defined(__GNUC__) || defined(__clang__) +# pragma pack(push, 8) +#endif + +typedef struct shpz_initialize_options { + int32_t is_kuro_games_hdiff; +} shpz_initialize_options; + +typedef struct shpz_patch_options { + uint8_t use_simd; + uint8_t _padding0[3]; + uint32_t parallel_threads; + int32_t reader_buffer_size; + int32_t copy_buffer_size; + int32_t patch_worker_buffer_size; +} shpz_patch_options; + +typedef void (SHPZ_CALLBACK *shpz_processed_bytes_callback)( + int64_t total_processed, + int64_t total_size, + int32_t written); + +typedef struct shpz_progress_callback { + shpz_processed_bytes_callback processed_bytes; +} shpz_progress_callback; + +typedef struct shpz_hdiff_info { + shpz_hdiff_magic magic_type; + shpz_hdiff_compression compression_type; + shpz_hdiff_checksum checksum_type; + shpz_initialize_options initialize_options; + void *metadata; +} shpz_hdiff_info; + +typedef struct shpz_chunk_size_info { + int64_t size; + int64_t compressed_size; +} shpz_chunk_size_info; + +typedef struct shpz_entry_count_size_info { + int32_t count; + int64_t size; +} shpz_entry_count_size_info; + +typedef struct shpz_file_index_pair { + int32_t old_index; + int32_t new_index; +} shpz_file_index_pair; + +typedef struct shpz_extern_size_info { + int32_t new_execute_count; + int64_t private_reserved_data_size; + int64_t private_extern_data_size; + int64_t extern_data_size; +} shpz_extern_size_info; + +typedef struct shpz_native_string_utf16 { + shpz_char16_t *chars; + int32_t length; +} shpz_native_string_utf16; + +typedef struct shpz_utf16_string { + shpz_metadata_type metadata_type; + uint8_t is_initialized; + uint8_t is_disposed; + shpz_native_string_utf16 native; +} shpz_utf16_string; + +/* These three structs mirror different closed forms of UnmanagedArray. */ +typedef struct shpz_utf16_string_array { + shpz_metadata_type metadata_type; + uint8_t is_initialized; + uint8_t is_disposed; + int32_t length; + int32_t element_size; + shpz_utf16_string *data; +} shpz_utf16_string_array; + +typedef struct shpz_int32_array { + shpz_metadata_type metadata_type; + uint8_t is_initialized; + uint8_t is_disposed; + int32_t length; + int32_t element_size; + int32_t *data; +} shpz_int32_array; + +typedef struct shpz_int64_array { + shpz_metadata_type metadata_type; + uint8_t is_initialized; + uint8_t is_disposed; + int32_t length; + int32_t element_size; + int64_t *data; +} shpz_int64_array; + +typedef struct shpz_checksum_data_info { + shpz_metadata_type metadata_type; + uint8_t is_initialized; + uint8_t is_disposed; + int32_t element_size; + int32_t element_count; + uint8_t *data; +} shpz_checksum_data_info; + +typedef struct shpz_patch_metadata { + shpz_metadata_type metadata_type; + uint8_t is_initialized; + uint8_t is_disposed; + int64_t diff_new_size; + int64_t diff_old_size; + int64_t diff_data_offset; + int32_t cover_data_count; + shpz_chunk_size_info *cover_data_size; + shpz_chunk_size_info *rle_control_data_size; + shpz_chunk_size_info *rle_code_data_size; + shpz_chunk_size_info *new_diff_data_size; +} shpz_patch_metadata; + +typedef struct shpz_directory_patch_metadata { + shpz_metadata_type metadata_type; + uint8_t is_initialized; + uint8_t is_disposed; + uint8_t is_input_directory; + uint8_t is_output_directory; + + shpz_entry_count_size_info *input_path_count_size; + shpz_entry_count_size_info *output_path_count_size; + shpz_entry_count_size_info *same_file_path_count_size; + shpz_file_index_pair *same_file_path_index_pairs; + + shpz_utf16_string_array *input_paths; + shpz_utf16_string_array *output_paths; + shpz_int32_array *input_file_indices; + shpz_int64_array *input_file_sizes; + shpz_int32_array *output_file_indices; + shpz_int64_array *output_file_sizes; + shpz_int64_array *output_file_hashes; + + shpz_extern_size_info *extern_size; + shpz_chunk_size_info *head_data_size; + shpz_patch_metadata *patch_metadata; + shpz_checksum_data_info *checksum_data; + shpz_int32_array *new_execute_indices; +} shpz_directory_patch_metadata; + +#if defined(_MSC_VER) || defined(__GNUC__) || defined(__clang__) +# pragma pack(pop) +#endif + +/* Convenient initializers matching the unmanaged entry points' defaults. */ +static inline shpz_initialize_options shpz_make_initialize_options(void) +{ + shpz_initialize_options value = { 0 }; + return value; +} + +static inline shpz_patch_options shpz_make_patch_options(void) +{ + shpz_patch_options value = { 0 }; + value.use_simd = 1; + return value; +} + +static inline shpz_progress_callback shpz_make_progress_callback( + shpz_processed_bytes_callback callback) +{ + shpz_progress_callback value; + value.processed_bytes = callback; + return value; +} + +/* + * String arguments documented as "auto string" accept a null-terminated UTF-8 + * string or a null-terminated UTF-16LE string. UTF-16 must use shpz_char16_t, + * not wchar_t on platforms where wchar_t is 32 bits. + */ + +SHPZ_API int32_t SHPZ_CALL shpz_read_header_signature_string( + const void *signature, + shpz_hdiff_magic *magic_type, + shpz_hdiff_compression *compression_type, + shpz_hdiff_checksum *checksum_type); + +/* + * On success, info owns metadata allocated by SharpHPatchZ. Release it exactly + * once with shpz_free_diff_info. The memory buffer only needs to remain valid + * for the duration of this call. + */ +SHPZ_API int32_t SHPZ_CALL shpz_init_from_memory( + const uint8_t *data, + int64_t data_length, + shpz_hdiff_info *info, + const shpz_initialize_options *options); + +SHPZ_API int32_t SHPZ_CALL shpz_init_from_filepath( + const void *patch_path, + shpz_hdiff_info *info, + const shpz_initialize_options *options); + +/* The FILE remains owned by the caller and is not closed by SharpHPatchZ. */ +SHPZ_API int32_t SHPZ_CALL shpz_init_from_FILE( + FILE *patch_file, + shpz_hdiff_info *info, + const shpz_initialize_options *options); + +SHPZ_API int32_t SHPZ_CALL shpz_patch_from_filepath( + const void *patch_path, + const void *input_path, + const void *output_path, + const shpz_hdiff_info *info, + const shpz_patch_options *options, + const shpz_progress_callback *progress); + +/* The FILE remains owned by the caller and is not closed by SharpHPatchZ. */ +SHPZ_API int32_t SHPZ_CALL shpz_patch_from_FILE( + FILE *patch_file, + const void *input_path, + const void *output_path, + const shpz_hdiff_info *info, + const shpz_patch_options *options, + const shpz_progress_callback *progress); + +SHPZ_API int32_t SHPZ_CALL shpz_free_diff_info(shpz_hdiff_info *info); + +/* Returned pointers are borrowed and become invalid after free_diff_info. */ +SHPZ_API const shpz_patch_metadata *SHPZ_CALL +shpz_util_get_patch_metadata(const shpz_hdiff_info *info); + +SHPZ_API const shpz_directory_patch_metadata *SHPZ_CALL +shpz_util_get_directory_patch_metadata(const shpz_hdiff_info *info); + +/* + * buffer_length is measured in bytes for A and in UTF-16 code units for W. + * The return value excludes the terminating NUL. A return value of -1 means + * that the supplied buffer was too small or conversion failed. Last-error + * state is shared by the process rather than stored per thread. + */ +SHPZ_API int32_t SHPZ_CALL shpz_get_last_errorA( + uint8_t *buffer, + int32_t buffer_length, + shpz_last_error_message_type message_type); + +SHPZ_API int32_t SHPZ_CALL shpz_get_last_errorW( + shpz_char16_t *buffer, + int32_t buffer_length, + shpz_last_error_message_type message_type); + +#if defined(__cplusplus) +} /* extern "C" */ +#endif + +/* Fail compilation early if consumer options changed an ABI-sensitive layout. */ +#if defined(__cplusplus) && __cplusplus >= 201103L +# define SHPZ_STATIC_ASSERT(condition, message) static_assert(condition, message) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +# define SHPZ_STATIC_ASSERT(condition, message) _Static_assert(condition, message) +#endif + +#if defined(SHPZ_STATIC_ASSERT) +SHPZ_STATIC_ASSERT(sizeof(shpz_hdiff_magic) == 4, "shpz_hdiff_magic must be 4 bytes"); +SHPZ_STATIC_ASSERT(sizeof(shpz_metadata_type) == 2, "shpz_metadata_type must be 2 bytes"); +SHPZ_STATIC_ASSERT(sizeof(shpz_initialize_options) == 4, "shpz_initialize_options layout mismatch"); +SHPZ_STATIC_ASSERT(sizeof(shpz_patch_options) == 20, "shpz_patch_options layout mismatch"); +SHPZ_STATIC_ASSERT(sizeof(shpz_progress_callback) == sizeof(void *), "shpz_progress_callback layout mismatch"); +SHPZ_STATIC_ASSERT(sizeof(shpz_hdiff_info) == (sizeof(void *) == 8 ? 24 : 20), + "shpz_hdiff_info size mismatch"); +SHPZ_STATIC_ASSERT(offsetof(shpz_hdiff_info, metadata) == 16, "shpz_hdiff_info layout mismatch"); +SHPZ_STATIC_ASSERT(sizeof(shpz_chunk_size_info) == 16, "shpz_chunk_size_info layout mismatch"); +SHPZ_STATIC_ASSERT(sizeof(shpz_entry_count_size_info) == 16, "shpz_entry_count_size_info layout mismatch"); +SHPZ_STATIC_ASSERT(offsetof(shpz_entry_count_size_info, size) == 8, "8-byte field alignment mismatch"); +SHPZ_STATIC_ASSERT(sizeof(shpz_file_index_pair) == 8, "shpz_file_index_pair layout mismatch"); +SHPZ_STATIC_ASSERT(sizeof(shpz_extern_size_info) == 32, "shpz_extern_size_info layout mismatch"); +SHPZ_STATIC_ASSERT(sizeof(shpz_native_string_utf16) == sizeof(void *) * 2, + "shpz_native_string_utf16 layout mismatch"); +SHPZ_STATIC_ASSERT(sizeof(shpz_utf16_string) == (sizeof(void *) == 8 ? 24 : 12), + "shpz_utf16_string layout mismatch"); +SHPZ_STATIC_ASSERT(sizeof(shpz_utf16_string_array) == (sizeof(void *) == 8 ? 24 : 16), + "shpz_utf16_string_array layout mismatch"); +SHPZ_STATIC_ASSERT(sizeof(shpz_int32_array) == (sizeof(void *) == 8 ? 24 : 16), + "shpz_int32_array layout mismatch"); +SHPZ_STATIC_ASSERT(sizeof(shpz_int64_array) == (sizeof(void *) == 8 ? 24 : 16), + "shpz_int64_array layout mismatch"); +SHPZ_STATIC_ASSERT(sizeof(shpz_checksum_data_info) == (sizeof(void *) == 8 ? 24 : 16), + "shpz_checksum_data_info layout mismatch"); +SHPZ_STATIC_ASSERT(sizeof(shpz_patch_metadata) == (sizeof(void *) == 8 ? 72 : 56), + "shpz_patch_metadata size mismatch"); +SHPZ_STATIC_ASSERT(offsetof(shpz_patch_metadata, diff_new_size) == 8, "shpz_patch_metadata layout mismatch"); +SHPZ_STATIC_ASSERT(sizeof(shpz_directory_patch_metadata) == (sizeof(void *) == 8 ? 136 : 72), + "shpz_directory_patch_metadata size mismatch"); +SHPZ_STATIC_ASSERT(offsetof(shpz_directory_patch_metadata, input_path_count_size) == 8, + "shpz_directory_patch_metadata layout mismatch"); +# undef SHPZ_STATIC_ASSERT +#endif + +#endif /* SHARP_HPATCH_Z_H */ From 776b31df184316920fc5e154755fa628e8f96193 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sat, 29 Aug 2026 05:30:56 +0700 Subject: [PATCH 61/72] [Program] Add few property groups for AOT publish --- .../SharpHPatchZ.Program.csproj | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj b/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj index fd6f127..ab95c1e 100644 --- a/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj +++ b/SharpHPatchZ.Program/SharpHPatchZ.Program.csproj @@ -17,4 +17,41 @@ + + + + + $(DefineConstants);AOT + + + true + Speed + Speed + true + true + false + false + true + true + true + true + true + + + false + false + true + true + false + false + + + false + false + false + false + false + false + false + \ No newline at end of file From 71037d50b4142725f17a15354a6c650c49909b0b Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sat, 29 Aug 2026 05:31:54 +0700 Subject: [PATCH 62/72] Explicitly use Hi3Helper.ZstdNet 1.6.7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Btw, 6 🤷 7 --- SharpHPatchZ/SharpHPatchZ.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharpHPatchZ/SharpHPatchZ.csproj b/SharpHPatchZ/SharpHPatchZ.csproj index 41cdda5..59c8481 100644 --- a/SharpHPatchZ/SharpHPatchZ.csproj +++ b/SharpHPatchZ/SharpHPatchZ.csproj @@ -35,7 +35,7 @@ - + From 500a599bd0219eb5f324753626405aa1eb2e2da7 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Sat, 29 Aug 2026 20:06:16 +0700 Subject: [PATCH 63/72] Docs --- SharpHPatchZ/HPatch.Utility.cs | 101 ++++++++++++++++++++++++++++-- SharpHPatchZ/HPatch.cs | 72 +++++++++++++++++++++ SharpHPatchZ/InitializeOptions.cs | 7 +++ SharpHPatchZ/PatchOptions.cs | 42 ++++++++++++- SharpHPatchZ/PatchResult.cs | 9 +++ 5 files changed, 224 insertions(+), 7 deletions(-) diff --git a/SharpHPatchZ/HPatch.Utility.cs b/SharpHPatchZ/HPatch.Utility.cs index 186371d..8cf2843 100644 --- a/SharpHPatchZ/HPatch.Utility.cs +++ b/SharpHPatchZ/HPatch.Utility.cs @@ -1,13 +1,22 @@ -using System; +using SharpHPatchZ.Header; +using SharpHPatchZ.Header.Metadata; +using System; using System.IO; using System.Runtime.CompilerServices; -using SharpHPatchZ.Header; -using SharpHPatchZ.Header.Metadata; +using SharpHPatchZ.Extension; namespace SharpHPatchZ; public static partial class HPatch { + /// + /// Try retrieve a struct from a patch context. + /// + /// A context and information struct for the to be retrieved from. + /// A retrieved struct of containing the main information about the patch file. + /// + /// Returns if is successfully retrieved. Otherwise, if the context struct is invalid or corrupted. + /// public static bool TryGetPatchMetadata( ref HDiffInfo info, out PatchMetadata patchMetadata) @@ -24,6 +33,15 @@ public static bool TryGetPatchMetadata( return true; } + /// + /// Try retrieve a struct from a patch context. + /// + /// A context and information struct for the to be retrieved from. + /// A retrieved struct of containing the main information about the patch file. + /// + /// Returns if is successfully retrieved. + /// Otherwise, if the patch context does not contain struct. + /// public static bool TryGetDirectoryPatchMetadata( ref HDiffInfo info, out DirectoryPatchMetadata patchMetadata) @@ -40,6 +58,16 @@ public static bool TryGetDirectoryPatchMetadata( return true; } + /// + /// Try retrieves both total Input and Output size from a patch context. + /// + /// A context and information struct for the total Input and Output size to be retrieved from. + /// The total size of an Input File/Directory. + /// The total size of an Output File/Directory. + /// + /// Returns if both and are successfully retrieved. + /// Otherwise, if the patch context is invalid or corrupted. + /// public static bool TryGetDiffSizeInfo(ref HDiffInfo info, out long totalInputSize, out long totalOutputSize) @@ -58,6 +86,50 @@ public static bool TryGetDiffSizeInfo(ref HDiffInfo info, return true; } + /// + /// Try retrieves both total Input and Output size from a path of the patch file. + /// + /// The path of the patch file. + /// The total size of an Input File/Directory. + /// The total size of an Output File/Directory. + /// + /// Returns if both and are successfully retrieved. + /// Otherwise, if the patch context or the file is invalid or corrupted. + /// + public static bool TryGetDiffSizeInfo(string patchFilePath, + out long totalInputSize, + out long totalOutputSize) + { + HDiffInfo info = CreateInstance(CreateStream); + try + { + return TryGetDiffSizeInfo(ref info, + out totalInputSize, + out totalOutputSize); + } + finally + { + info.Dispose(); + } + + (Stream, bool) CreateStream(long pos) + { + FileStream fileStream = File.Open(patchFilePath, FileMode.Open, FileAccess.Read, FileShare.Read); + fileStream.Position = pos; + return (fileStream, false); + } + } + + /// + /// Try retrieves both total Input and Output size from a of the patch data. + /// + /// A factory delegate which creates the instance of the patch file. + /// The total size of an Input File/Directory. + /// The total size of an Output File/Directory. + /// + /// Returns if both and are successfully retrieved. + /// Otherwise, if the patch context or the file stream is invalid or corrupted. + /// public static bool TryGetDiffSizeInfo(CreateStream createStream, out long totalInputSize, out long totalOutputSize) @@ -75,6 +147,16 @@ public static bool TryGetDiffSizeInfo(CreateStream createStream, } } + /// + /// Try retrieves both total Input and Output size from a of the patch data. + /// + /// A source instance of the patch data. + /// The total size of an Input File/Directory. + /// The total size of an Output File/Directory. + /// + /// Returns if both and are successfully retrieved. + /// Otherwise, if the patch context or the file stream is invalid or corrupted. + /// public static bool TryGetDiffSizeInfo(Stream stream, out long totalInputSize, out long totalOutputSize) @@ -90,7 +172,18 @@ public static bool TryGetDiffSizeInfo(Stream stream, } } + /// + /// Try gets the from an instance. + /// + /// The type of the content struct + /// The unmanaged array to get the from. + /// + /// Returns a non-empty if the array is valid. + /// Otherwise, returns an empty if the array is invalid. + /// public static unsafe Span TryGetUnmanagedArraySpan(UnmanagedArray* array) where T : unmanaged - => array == null ? Span.Empty : array->GetSpan(); + => array == null || + (MetadataExtension.TryGetMetadataType(array, out MetadataTypeConst metadataType) && metadataType != MetadataTypeConst.UnmanagedArrayType) + ? Span.Empty : array->GetSpan(); } \ No newline at end of file diff --git a/SharpHPatchZ/HPatch.cs b/SharpHPatchZ/HPatch.cs index f4e771c..d085368 100644 --- a/SharpHPatchZ/HPatch.cs +++ b/SharpHPatchZ/HPatch.cs @@ -9,11 +9,40 @@ namespace SharpHPatchZ; +/// +/// A factory delegate which creates an instance of a of the patch from specified . +/// +/// The offset position of the to begin from. +/// +/// Returns both as Stream property and as LeaveOpen property. +/// Return LeaveOpen == if you want to keep the source opened.
+/// Otherwise, set LeaveOpen == to dispose the returned instance after use. +///
public delegate (Stream Stream, bool LeaveOpen) CreateStream(long position); + +/// +/// A factory delegate which creates an instance of a of the patch from specified asynchronously. +/// +/// The offset position of the to begin from. +/// A cancellation token for the cancellation event while async operation is happening. +/// +/// Returns both as Stream property and as LeaveOpen property. +/// Return LeaveOpen == if you want to keep the source opened.
+/// Otherwise, set LeaveOpen == to dispose the returned instance after use. +///
public delegate ValueTask<(Stream Stream, bool LeaveOpen)> CreateStreamAsync(long position, CancellationToken token); +/// +/// A static class containing main functionality of the SharpHPatchZ library. +/// public static partial class HPatch { + /// + /// Creates a context for the patch processing. + /// + /// A factory delegate which creates a instance of the patch file. + /// Options during the initialization process. For more usage information, see . + /// Returns a context and information struct about the patch file. public static HDiffInfo CreateInstance(CreateStream createPatchStream, InitializeOptions initializeOptions = default) { @@ -35,11 +64,24 @@ public static HDiffInfo CreateInstance(CreateStream createPatchStream, } } + /// + /// Creates a context for the patch processing asynchronously. + /// + /// A factory delegate creates a instance of the patch file from specified position/offset. + /// A cancellation token for the cancellation event while async operation is happening. + /// Returns a context and information struct about the patch file. public static ValueTask CreateInstanceAsync( CreateStreamAsync createPatchStreamAsync, CancellationToken token = default) => CreateInstanceAsync(createPatchStreamAsync, default, token); + /// + /// Creates a context for the patch processing asynchronously. + /// + /// A factory delegate creates a instance of the patch file from specified position/offset asynchronously. + /// Options during the initialization process. For more usage information, see . + /// A cancellation token for the cancellation event while async operation is happening. + /// Returns a context and information struct about the patch file. public static async ValueTask CreateInstanceAsync( CreateStreamAsync createPatchStreamAsync, InitializeOptions initializeOptions, @@ -59,6 +101,21 @@ public static async ValueTask CreateInstanceAsync( return info; } + /// + /// Performs patch routines to the specified Input and Output paths. + /// + /// The struct containing context and information about the patch file. + /// A factory delegate which creates a instance of the patch file. + /// The specified Input path of a file or directory. + /// The specified Output path of a file or directory to be written to + /// Options during the patching process. For more usage information, see . + /// A struct containing the specified delegated method to be used to report the progress of the patch process. Use to create the struct and pass the callback. + /// A cancellation token for the cancellation event while patching operation is happening. + /// + /// Returns a result of the patching process. The returned result can be implicitly cast into a nullable or .
+ /// If cast into a , the means that the patching process has been successful. Otherwise, failed and would be not .
+ /// If cast into a nullable and the result is , meaning that the patching process has been successful. Otherwise, failed. + ///
public static PatchResult Patch(HDiffInfo info, CreateStream createPatchStream, string inputPath, @@ -79,6 +136,21 @@ public static PatchResult Patch(HDiffInfo info, } } + /// + /// Performs patch routines to the specified Input and Output paths asynchronously + /// + /// The struct containing context and information about the patch file. + /// A factory delegate which creates a instance of the patch file asynchronously. + /// The specified Input path of a file or directory. + /// The specified Output path of a file or directory to be written to + /// Options during the patching process. For more usage information, see . + /// A struct containing the specified delegated method to be used to report the progress of the patch process. Use to create the struct and pass the callback. + /// A cancellation token for the cancellation event while patching operation is happening. + /// + /// Returns a result of the patching process. The returned result can be implicitly cast into a nullable or .
+ /// If cast into a , the means that the patching process has been successful. Otherwise, failed and would be not .
+ /// If cast into a nullable and the result is , meaning that the patching process has been successful. Otherwise, failed. + ///
public static async Task PatchAsync( HDiffInfo info, CreateStreamAsync createPatchStreamAsync, diff --git a/SharpHPatchZ/InitializeOptions.cs b/SharpHPatchZ/InitializeOptions.cs index f858fed..a257d48 100644 --- a/SharpHPatchZ/InitializeOptions.cs +++ b/SharpHPatchZ/InitializeOptions.cs @@ -1,13 +1,20 @@ using System.Runtime.InteropServices; // ReSharper disable IdentifierTypo +// ReSharper disable CommentTypo namespace SharpHPatchZ; +/// +/// Specifies the options during Patch context initialization. +/// [StructLayout(LayoutKind.Sequential)] public struct InitializeOptions() { private int _isKuroGamesHDiff = 0; + /// + /// Specifies whether the patch file is a Kuro Games DirHDiff format. + /// public bool IsKuroGamesHDiff { get => _isKuroGamesHDiff > 0; diff --git a/SharpHPatchZ/PatchOptions.cs b/SharpHPatchZ/PatchOptions.cs index e7673f3..ea64b1b 100644 --- a/SharpHPatchZ/PatchOptions.cs +++ b/SharpHPatchZ/PatchOptions.cs @@ -3,9 +3,15 @@ namespace SharpHPatchZ; +/// +/// Specifies options during patching operations. This options contains some essential settings to determine the buffer size and parallelization. +/// [StructLayout(LayoutKind.Sequential)] public struct PatchOptions() { + /// + /// Default and optimal for both performance and memory allocation. + /// public static readonly PatchOptions Default = new() { ParallelThreads = (uint)Environment.ProcessorCount, @@ -14,6 +20,9 @@ public struct PatchOptions() #endif }; + /// + /// Prioritizes performance by allocating much bigger sequential buffer for the reader, patch workers and the copy routine + /// public static readonly PatchOptions BigBuffer = Default with { ReaderBufferSize = 1 << 20, @@ -21,6 +30,9 @@ public struct PatchOptions() PatchWorkerBufferSize = 16 << 20 }; + /// + /// Maintaining smaller memory allocation possible while impacting the performance. + /// public static readonly PatchOptions SmallBuffer = Default with { ReaderBufferSize = 4 << 10, @@ -28,6 +40,9 @@ public struct PatchOptions() PatchWorkerBufferSize = 128 << 10 }; + /// + /// Optimized for Hard Drives where it requires sequential read/write routines and avoiding random seek by reducing the amount of patch workers. + /// public static readonly PatchOptions OptimizeForHDD = Default with { ParallelThreads = 1, @@ -35,11 +50,32 @@ public struct PatchOptions() }; #if NET6_0_OR_GREATER + /// + /// Whether to use SIMD on the RLE addition functions.
+ /// If enabled, AVX2 will be used by default on supported CPUs.
+ /// Otherwise, falling back to SSE2 for supported x86-64-v2 CPUs.
+ /// If none of the above are available, fallback to Runtime-Vectorization or Scalar on ARM or unsupported CPUs + ///
public bool UseSIMD = true; #endif - public uint ParallelThreads = 0; - public int ReaderBufferSize = 0; - public int CopyBufferSize = 0; + /// + /// Determines how much the maximum parallel threads being used to produce the patch workers. + /// + public uint ParallelThreads = 0; + + /// + /// Determines how much buffer to be allocated for the RLE Stream Readers. + /// + public int ReaderBufferSize = 0; + + /// + /// Determines how much buffer to be allocated for the same-file copy operation. + /// + public int CopyBufferSize = 0; + + /// + /// Determines how much buffer to be allocated for each of the patch workers. + /// public int PatchWorkerBufferSize = 0; } diff --git a/SharpHPatchZ/PatchResult.cs b/SharpHPatchZ/PatchResult.cs index 6e6b877..2d4449b 100644 --- a/SharpHPatchZ/PatchResult.cs +++ b/SharpHPatchZ/PatchResult.cs @@ -3,10 +3,19 @@ namespace SharpHPatchZ; +/// +/// Determines whether the patch process has been successful or not. +/// public class PatchResult { + /// + /// Containing an error if the patching process is faulty. + /// public Exception? Exception { get; init; } + /// + /// Whether the patching process is successful or faulty. + /// public bool IsSuccessful { get; init; } public static implicit operator bool(PatchResult result) => result.IsSuccessful; From 27414f82f8471cf057d10d0a56698ffe27c75faf Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 31 Aug 2026 12:50:45 +0700 Subject: [PATCH 64/72] Add overload for receiving Patch File path --- SharpHPatchZ/HPatch.UnmanagedExtern.cs | 33 ++++-- SharpHPatchZ/HPatch.cs | 147 +++++++++++++++++++++++++ SharpHPatchZ/Patch/PatcherBase.cs | 6 +- SharpHPatchZ/PatchResult.cs | 2 +- 4 files changed, 176 insertions(+), 12 deletions(-) diff --git a/SharpHPatchZ/HPatch.UnmanagedExtern.cs b/SharpHPatchZ/HPatch.UnmanagedExtern.cs index 233ac1d..f384ba8 100644 --- a/SharpHPatchZ/HPatch.UnmanagedExtern.cs +++ b/SharpHPatchZ/HPatch.UnmanagedExtern.cs @@ -1,7 +1,9 @@ -#if NET8_0_OR_GREATER +using System.IO; +using System.Threading.Tasks; + +#if NET8_0_OR_GREATER using System; using System.Buffers; -using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; @@ -9,21 +11,25 @@ using SharpHPatchZ.Header; using SharpHPatchZ.Header.Metadata; using SharpHPatchZ.Native; +#endif // ReSharper disable InconsistentNaming // ReSharper disable IdentifierTypo // ReSharper disable StringLiteralTypo +#if NET8_0_OR_GREATER #if USEWINDOWS using ConventionCall = System.Runtime.CompilerServices.CallConvStdcall; #else using ConventionCall = System.Runtime.CompilerServices.CallConvCdecl; #endif +#endif namespace SharpHPatchZ; public static partial class HPatch { +#if NET8_0_OR_GREATER [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_read_header_signature_string")] public static unsafe int SharpHPatchZ_ReadHeaderSignatureStringAuto(void* signatureP, HDiffMagic* magicTypeP, HDiffCompression* compressionTypeP, HDiffChecksum* checksumTypeP) { @@ -229,13 +235,6 @@ public static unsafe int SharpHPatchZ_GetLastErrorUtf8(byte* bufferA, int buffer public static unsafe int SharpHPatchZ_GetLastErrorUnicode(char* bufferW, int bufferLength, ExceptionHelper.LastErrorMessageType messageType) => ExceptionHelper.TryGetLastErrorMessageUnicode(new Span(bufferW, bufferLength), messageType); - private static (Stream Stream, bool LeaveOpen) CreateFileStreamWrapper(string filePath, long position) - { - FileStream stream = new(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); - stream.Position = position; - return (stream, false); - } - private static unsafe (Stream Stream, bool LeaveOpen) CreateFileStreamWrapper(void* FILEP, long position) { try @@ -250,5 +249,19 @@ private static unsafe (Stream Stream, bool LeaveOpen) CreateFileStreamWrapper(vo throw ExceptionHelper.ThrowHDiffIOException(ex); } } -} #endif + + private static (Stream Stream, bool LeaveOpen) CreateFileStreamWrapper(string filePath, long position) + { + FileStream stream = new(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); + stream.Position = position; + return (stream, false); + } + + private static ValueTask<(Stream Stream, bool LeaveOpen)> CreateFileStreamWrapperAsync(string filePath, long position) + { + FileStream stream = new(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); + stream.Position = position; + return new ValueTask<(Stream Stream, bool LeaveOpen)>((stream, false)); + } +} diff --git a/SharpHPatchZ/HPatch.cs b/SharpHPatchZ/HPatch.cs index d085368..df1705b 100644 --- a/SharpHPatchZ/HPatch.cs +++ b/SharpHPatchZ/HPatch.cs @@ -64,6 +64,33 @@ public static HDiffInfo CreateInstance(CreateStream createPatchStream, } } + /// + /// Creates a context for the patch processing. + /// + /// A path to the patch file. + /// Options during the initialization process. For more usage information, see . + /// Returns a context and information struct about the patch file. + public static HDiffInfo CreateInstance(string patchPath, + InitializeOptions initializeOptions = default) + { + try + { + (Stream stream, bool leaveOpen) = CreateFileStreamWrapper(patchPath, 0); + using BittableStreamReader reader = new(stream, leaveOpen: leaveOpen); + + string signature = reader.ReadStringToNull(); + HDiffInfo info = default; + HeaderReader.ReadHeaderSignature(signature, ref info); + HeaderReader.ReadHDiffHeaderMetadata(ref info, reader, initializeOptions); + + return info; + } + catch (EndOfStreamException eofStream) + { + throw ExceptionHelper.ThrowHDiffEndOfFileOrData(eofStream); + } + } + /// /// Creates a context for the patch processing asynchronously. /// @@ -75,6 +102,17 @@ public static ValueTask CreateInstanceAsync( CancellationToken token = default) => CreateInstanceAsync(createPatchStreamAsync, default, token); + /// + /// Creates a context for the patch processing asynchronously. + /// + /// A path to the patch file. + /// A cancellation token for the cancellation event while async operation is happening. + /// Returns a context and information struct about the patch file. + public static ValueTask CreateInstanceAsync( + string patchPath, + CancellationToken token = default) + => CreateInstanceAsync(patchPath, default, token); + /// /// Creates a context for the patch processing asynchronously. /// @@ -101,6 +139,32 @@ public static async ValueTask CreateInstanceAsync( return info; } + /// + /// Creates a context for the patch processing asynchronously. + /// + /// A path to the patch file. + /// Options during the initialization process. For more usage information, see . + /// A cancellation token for the cancellation event while async operation is happening. + /// Returns a context and information struct about the patch file. + public static async ValueTask CreateInstanceAsync( + string patchPath, + InitializeOptions initializeOptions, + CancellationToken token = default) + { + (Stream stream, bool leaveOpen) = CreateFileStreamWrapper(patchPath, 0); +#if NET6_0_OR_GREATER + await +#endif + using BittableStreamReader reader = new(stream, leaveOpen: leaveOpen); + + string signature = await reader.ReadStringToNullAsync(token: token); + HDiffInfo info = default; + HeaderReader.ReadHeaderSignature(signature, ref info); + info = await HeaderReader.ReadHDiffHeaderMetadataAsync(info, reader, initializeOptions, token); + + return info; + } + /// /// Performs patch routines to the specified Input and Output paths. /// @@ -136,6 +200,46 @@ public static PatchResult Patch(HDiffInfo info, } } + + + /// + /// Performs patch routines to the specified Input and Output paths. + /// + /// The struct containing context and information about the patch file. + /// The specified Patch file path. + /// The specified Input path of a file or directory. + /// The specified Output path of a file or directory to be written to + /// Options during the patching process. For more usage information, see . + /// A struct containing the specified delegated method to be used to report the progress of the patch process. Use to create the struct and pass the callback. + /// A cancellation token for the cancellation event while patching operation is happening. + /// + /// Returns a result of the patching process. The returned result can be implicitly cast into a nullable or .
+ /// If cast into a , the means that the patching process has been successful. Otherwise, failed and would be not .
+ /// If cast into a nullable and the result is , meaning that the patching process has been successful. Otherwise, failed. + ///
+ public static PatchResult Patch(HDiffInfo info, + string patchPath, + string inputPath, + string outputPath, + PatchOptions options = default, + ProgressCallback progressCallback = default, + CancellationToken token = default) + { + try + { + using PatcherBase patcher = PatcherFactory.CreateFromInfo(ref info, + pos => CreateFileStreamWrapper(patchPath, pos), + options, + progressCallback); + patcher.StartPatch(inputPath, outputPath, token); + return true; + } + catch (Exception ex) + { + return ex; + } + } + /// /// Performs patch routines to the specified Input and Output paths asynchronously /// @@ -174,4 +278,47 @@ public static async Task PatchAsync( return ex; } } + + /// + /// Performs patch routines to the specified Input and Output paths asynchronously + /// + /// The struct containing context and information about the patch file. + /// The specified Patch file path. + /// The specified Input path of a file or directory. + /// The specified Output path of a file or directory to be written to + /// Options during the patching process. For more usage information, see . + /// A struct containing the specified delegated method to be used to report the progress of the patch process. Use to create the struct and pass the callback. + /// A cancellation token for the cancellation event while patching operation is happening. + /// + /// Returns a result of the patching process. The returned result can be implicitly cast into a nullable or .
+ /// If cast into a , the means that the patching process has been successful. Otherwise, failed and would be not .
+ /// If cast into a nullable and the result is , meaning that the patching process has been successful. Otherwise, failed. + ///
+ public static async Task PatchAsync( + HDiffInfo info, + string patchPath, + string inputPath, + string outputPath, + PatchOptions options = default, + ProgressCallback progressCallback = default, + CancellationToken token = default) + { + try + { +#if NET6_0_OR_GREATER + await +#endif + using PatcherBase patcher = await PatcherFactory.CreateFromInfoAsync(info, + (pos, _) => CreateFileStreamWrapperAsync(patchPath, pos), + options, + progressCallback, + token); + await patcher.StartPatchAsync(inputPath, outputPath, token); + return true; + } + catch (Exception ex) + { + return ex; + } + } } diff --git a/SharpHPatchZ/Patch/PatcherBase.cs b/SharpHPatchZ/Patch/PatcherBase.cs index cd2a8c4..788e83a 100644 --- a/SharpHPatchZ/Patch/PatcherBase.cs +++ b/SharpHPatchZ/Patch/PatcherBase.cs @@ -33,7 +33,11 @@ protected PatcherBase(HDiffInfo info, PatchOptions options, ProgressCallback pro public abstract void StartPatch(string inputPath, string outputPath, CancellationToken token); public abstract Task StartPatchAsync(string inputPath, string outputPath, CancellationToken token); - internal unsafe void AdvanceProgress(int written) + internal +#if NET6_0_OR_GREATER + unsafe +#endif + void AdvanceProgress(int written) { Interlocked.Add(ref TotalWritten, written); ProgressCallback.ProcessedBytesCallback(TotalWritten, TotalSize, written); diff --git a/SharpHPatchZ/PatchResult.cs b/SharpHPatchZ/PatchResult.cs index 2d4449b..506688d 100644 --- a/SharpHPatchZ/PatchResult.cs +++ b/SharpHPatchZ/PatchResult.cs @@ -22,6 +22,6 @@ public class PatchResult public static implicit operator Exception?(PatchResult result) => result.Exception; public static implicit operator int(PatchResult result) => ExceptionHelper.TryGetReturnCodeFromError(result); - public static implicit operator PatchResult(Exception ex) => new() { Exception = ex, IsSuccessful = false }; + public static implicit operator PatchResult(Exception? ex) => new() { Exception = ex, IsSuccessful = ex == null }; public static implicit operator PatchResult(bool value) => new() { Exception = !value ? new Exception() : null, IsSuccessful = value }; } From 77a856452e48fd43de9289df4a827bd42fd18fb7 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 31 Aug 2026 12:51:09 +0700 Subject: [PATCH 65/72] Add docs to ProgressCallback --- SharpHPatchZ/ProgressCallback.cs | 36 ++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/SharpHPatchZ/ProgressCallback.cs b/SharpHPatchZ/ProgressCallback.cs index 08c1f22..e219009 100644 --- a/SharpHPatchZ/ProgressCallback.cs +++ b/SharpHPatchZ/ProgressCallback.cs @@ -5,8 +5,17 @@ namespace SharpHPatchZ; +/// +/// A callback delegate for the progress of the patching. +/// +/// Determines how many bytes already processed. +/// Determines how many bytes to be processed in total. +/// How many bytes is currently being written into the disk. public delegate void ProcessedBytesManagedCallback(long totalProcessed, long totalSize, int written); +/// +/// Sets progress callback for the patching process. +/// [StructLayout(LayoutKind.Sequential)] public readonly #if NET6_0_OR_GREATER @@ -14,16 +23,29 @@ public readonly #endif struct ProgressCallback { + /// + /// The delegate callback for the progress method. + /// #if NET6_0_OR_GREATER - public readonly delegate* unmanaged[Cdecl] ProcessedBytesCallback; + internal readonly delegate* unmanaged[Cdecl] ProcessedBytesCallback; #else - public readonly ProcessedBytesManagedCallback ProcessedBytesCallback; + internal readonly ProcessedBytesManagedCallback ProcessedBytesCallback; #endif + /// + /// Whether the callback pointer is allocated or not. + /// internal bool IsAllocated => ProcessedBytesCallback != null; + /// + /// Creates a new default struct with a NOP callback. + /// public ProgressCallback() : this(null) { } + /// + /// Creates a new with specified callback method. + /// + /// #if NET6_0_OR_GREATER public ProgressCallback(ProcessedBytesManagedCallback? callback) { @@ -49,11 +71,21 @@ public ProgressCallback(ProcessedBytesManagedCallback? callback) } #endif + /// + /// This method is expected to be exists as a NOP method as a placeholder. + /// The field on .NET 6 uses an unmanaged delegate pointer to the method since it cannot be null. + /// So the field is pointing to this method if no callback delegate is set. + /// #if NET6_0_OR_GREATER [UnmanagedCallersOnly(CallConvs = [typeof(CallConvCdecl)])] [SkipLocalsInit] #endif private static void NopProcessedBytesCallback(long totalProcessed, long totalSize, int written) { } + /// + /// Creates a new with specified callback method. + /// + /// A method used for the callback of the progress + /// A new struct. public static ProgressCallback CreateFromManaged(ProcessedBytesManagedCallback callback) => new(callback); } From 4371551b9cad99bd63f2a3a5cd8b7192c60bdf4a Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 31 Aug 2026 12:51:27 +0700 Subject: [PATCH 66/72] Update HPatch.cs --- SharpHPatchZ/HPatch.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SharpHPatchZ/HPatch.cs b/SharpHPatchZ/HPatch.cs index df1705b..6f104c3 100644 --- a/SharpHPatchZ/HPatch.cs +++ b/SharpHPatchZ/HPatch.cs @@ -1,10 +1,10 @@ using System; -using SharpHPatchZ.Extension; -using SharpHPatchZ.Header; -using SharpHPatchZ.IO.Reader; using System.IO; using System.Threading; using System.Threading.Tasks; +using SharpHPatchZ.Extension; +using SharpHPatchZ.Header; +using SharpHPatchZ.IO.Reader; using SharpHPatchZ.Patch; namespace SharpHPatchZ; From d5a6436cf97af695cd5e68e9ab2f20e2daa5929c Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 31 Aug 2026 12:53:44 +0700 Subject: [PATCH 67/72] Update HPatch.cs --- SharpHPatchZ/HPatch.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharpHPatchZ/HPatch.cs b/SharpHPatchZ/HPatch.cs index 6f104c3..eedd445 100644 --- a/SharpHPatchZ/HPatch.cs +++ b/SharpHPatchZ/HPatch.cs @@ -151,7 +151,7 @@ public static async ValueTask CreateInstanceAsync( InitializeOptions initializeOptions, CancellationToken token = default) { - (Stream stream, bool leaveOpen) = CreateFileStreamWrapper(patchPath, 0); + (Stream stream, bool leaveOpen) = await CreateFileStreamWrapperAsync(patchPath, 0); #if NET6_0_OR_GREATER await #endif From f101388f2e075ced8ded408b77ad910a7f1c75db Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 31 Aug 2026 17:13:27 +0700 Subject: [PATCH 68/72] Adjust usages and docs --- README.md | 408 +++++++++++++++++- SharpHPatchZ.Program/Program.cs | 15 +- SharpHPatchZ/HPatch.Utility.cs | 152 +++---- SharpHPatchZ/Header/HDiffChecksum.cs | 3 + SharpHPatchZ/Header/HDiffCompression.cs | 3 + SharpHPatchZ/Header/HDiffInfo.cs | 6 +- SharpHPatchZ/Header/HDiffMagic.cs | 14 + .../Header/Metadata/UnmanagedArray.cs | 2 +- .../IO/Reader/RandomMergedStreamWrapper.cs | 3 + .../Patch/PatcherFactory.HDiff13Derived.cs | 2 +- 10 files changed, 515 insertions(+), 93 deletions(-) diff --git a/README.md b/README.md index 7388f56..1c14b88 100644 --- a/README.md +++ b/README.md @@ -2,21 +2,415 @@ [![NuGet Downloads](https://img.shields.io/nuget/dt/SharpHDiffPatch.Core.svg?style=flat-square)](https://www.nuget.org/packages/SharpHDiffPatch.Core/) [![NuGet version](https://img.shields.io/nuget/v/SharpHDiffPatch.Core.svg?style=flat-square)](https://www.nuget.org/packages/SharpHDiffPatch.Core/) -**SharpHPatchZ** (formerly SharpHDiffPatch) is a patching library for HDiffPatch format written in C#, purposedly as a port of **HPatchZ** implementation (from [**HDiffPatch** by **housisong**](https://github.com/sisong/HDiffPatch)). This project doesn't support making diff file and only works for patching. +**SharpHPatchZ** (formerly SharpHDiffPatch) is a patching library for HDiffPatch format written in C#, purposedly as a port of **HPatchZ** implementation (from [**HDiffPatch** by **housisong**](https://github.com/sisong/HDiffPatch)). This project doesn't support making a diff file and only works for patching. Supporting file and directory patching with these compression formats: - BZip2 - Deflate -- Zstd -- LZMA and LZMA2 +- ZStandard +- LZMA +- LZMA2 - No Compression. -HDIFFSF20 format is planned to be supported in v3.0 branch on the General Public release. +HDIFFSF20 format is planned to be supported later v3.0 releases. This project is used as a part submodule of our main project: [**Collapse Launcher**](https://github.com/CollapseLauncher). -# TODO: Usage Example +# Usage Examples +## A. Basic Patching Usage with Progress Output +```CSharp +using System; +using SharpHPatchZ; +using SharpHPatchZ.Header; -## TODO: Patching Kuro directory diffs +namespace Example; -## TODO: Get the New file size from diff file. \ No newline at end of file +public class Program +{ + private const string InputPath = @"G:\HDiffTest\Hi3SEA"; + private const string PatchPath = @"G:\HDiffTest\Hi3SEAtoCNExecOnly.lzma.diff"; + private const string OutputPath = @"G:\HDiffTest\Hi3CN-dotnet"; + + public static void Main() + { + // Create a callback struct and pass the `UpdateProgress` method to the create method. + ProgressCallback progressCallback = ProgressCallback.CreateFromManaged(UpdateProgress); + + // The `HDiffInfo` info context must be used within `using` scope or by disposing the struct manually. + // Undisposed info context will cause a memory leak as it uses unmanaged memory under the hood. + + // Pass the patch file path into the `HPatch.CreateInstance()` method to create the info context. + using HDiffInfo info = HPatch.CreateInstance(PatchPath); + + // Pass the `HDiffInfo` info context to the `HPatch.Patch()` method to start the patching process. Also pass the Input and Output Path, and the `progressCallback` + PatchResult patchResult = HPatch.Patch(info, PatchPath, InputPath, OutputPath, progressCallback: progressCallback); + + // If the patch process is not successful, throw the exception. + if (!patchResult) + throw patchResult.Exception ?? new Exception(); + } + + private static void UpdateProgress(long totalProcessed, long totalSize, int written) + { + double percent = Math.Round(totalProcessed / (double)totalSize * 100, 2); + Console.Write( + $"Patching: {percent}% | " + + $"{SummarizeSizeSimple(totalProcessed)}/{SummarizeSizeSimple(totalSize)} \r"); + } + + private static readonly string[] SizeSuffixes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"]; + + private static string SummarizeSizeSimple(double value, int decimalPlaces = 2) + { + byte mag = (byte)Math.Log(value, 1000); + + return $"{Math.Round(value / (1L << (mag * 10)), decimalPlaces)} {SizeSuffixes[mag]}"; + } +} +``` + +## B. Basic Patching Usage with Adjusted Options +```CSharp +// There are few `PatchOptions` templates you can use. +// - PatchOptions.BigBuffer +// Generally the fastest, but uses numerous amount of buffer to process the patch. +// ParallelThreads = (Auto) determines the max. amount of patch worker used per thread. +// ReaderBufferSize = 1 MiB/reader +// CopyBufferSize = 128 KiB/copy file job (Only being used if the patch is a directory patch (HDiff19 type)) +// PatchWorkerBufferSize = 16 MiB/patch worker +// UseSIMD = true (only available for .NET 6 or above) +// +// - PatchOptions.Default +// Moderately faster, sometimes better for small patch. Uses modest amount of buffer to process the patch. +// ParallelThreads = (Auto) determines the max. amount of patch worker used per thread. +// ReaderBufferSize = 64 KiB/reader +// CopyBufferSize = 16 KiB/copy file job (Only being used if the patch is a directory patch (HDiff19 type)) +// PatchWorkerBufferSize = 1 MiB/patch worker +// UseSIMD = true (only available for .NET 6 or above) +// +// - PatchOptions.SmallBuffer +// Slower but uses the smallest buffer size possible. +// ParallelThreads = (Auto) determines the max. amount of patch worker used per thread. +// ReaderBufferSize = 4 KiB/reader +// CopyBufferSize = 4 KiB/copy file job (Only being used if the patch is a directory patch (HDiff19 type)) +// PatchWorkerBufferSize = 128 KiB/patch worker +// UseSIMD = true (only available for .NET 6 or above) +// +// - PatchOptions.OptimizeForHDD +// Equally the same as Default but spawn only one patch worker for better sequential write performance on HDD and to avoid +// heavy random seek. +// ParallelThreads = 1 (Spawn only one patch worker at a time for sequential write to the output.) +// ReaderBufferSize = 64 KiB/reader +// CopyBufferSize = 16 KiB/copy file job (Only being used if the patch is a directory patch (HDiff19 type)) +// PatchWorkerBufferSize = 1 MiB/patch worker +// UseSIMD = true (only available for .NET 6 or above) +PatchOptions patchOptions = PatchOptions.BigBuffer; + +// Create the info context from the patch file path. +using HDiffInfo info = HPatch.CreateInstance(PatchPath); + +// Pass the info context, patch patch, input path and output path, as well as the `patchOptions`. +PatchResult patchResult = HPatch.Patch(info, PatchPath, InputPath, OutputPath, options: patchOptions); +``` + +## C. Uses asychronous version of the method. +```CSharp +private static async Task ProcessPatch( + string patchPath, + string inputPath, + string outputPath, + PatchOptions options, + CancellationToken token) +{ + // Creates the info context asynchronously from the patch path. + using HDiffInfo info = await HPatch.CreateInstanceAsync(patchPath, token); + + // Starts the patch process asynchronously, pass the arguments as usual. + PatchResult patchResult = await HPatch.PatchAsync(info, patchPath, inputPath, outputPath, options: options, token: token); +} +``` + +## D. Uses a `Stream` Factory method to for the patch file. +### Synchronous version: +```CSharp +private static void ProcessPatch(string patchPath, string inputPath, string outputPath, PatchOptions options) +{ + // Create the info context from a `Stream` factory method by `CreateStream()`. + using HDiffInfo info = HPatch.CreateInstance(CreateStream); + + // Start the patch process by passing the `CreateStream()` factory method to the `HPatch.Patch()`. + PatchResult patchResult = HPatch.Patch(info, CreateStream, inputPath, outputPath, options: options); + + if (!patchResult) + throw patchResult.Exception ?? new Exception(); + + return; + + // This method is used to produce the `Stream` of the patch file starting from the specified position/offset of the file. + // The `position` argument here is necessary as it's used to specify where the data will start to be read by the patching methods. + (Stream stream, bool leaveOpen) CreateStream(long position) + { + // Open the patch `Stream` with shared Read operation. The `Stream` must be created with `FileShare.Read` as this method + // will be called to produce multiple `Stream` instances with shared Read operations. + // + // This is important to note that we don't use `using` keyword here as we don't want to dispose the `Stream` instance + // after leaving this method. We want the callee to dispose the `Stream` instance instead later by setting `leaveOpen` + // to `false` under the returned value below. + FileStream stream = File.Open(patchPath, FileMode.Open, FileAccess.Read, FileShare.Read); + + // The `Stream` instance must be seek-ed to the certain offset provided by the `position` argument. + stream.Position = position; + + // Return the `Stream` instance and set the `leaveOpen` to `false` to tell the callee to + // dispose this created `Stream` instance after use. + return (stream, false); + } +} +``` + +### Asynchronous version: +The `async` version is basically the same as the sychronous version but with a few adjustments onto the `Stream` factory method where it receives `CancellationToken` from the callee method within the patch processing method. +```CSharp +private static async Task ProcessPatch(string patchPath, string inputPath, string outputPath, PatchOptions options, CancellationToken token) +{ + // Create the info context from a `Stream` factory method by `CreateStreamAsync()`. + using HDiffInfo info = await HPatch.CreateInstanceAsync(CreateStreamAsync, token); + + // Start the patch process by passing the `CreateStreamAsync()` factory method to the `HPatch.PatchAsync()`. + PatchResult patchResult = await HPatch.PatchAsync(info, CreateStreamAsync, inputPath, outputPath, options: options, token: token); + + if (!patchResult) + throw patchResult.Exception ?? new Exception(); + + return; + + // This method is used to produce the `Stream` of the patch file starting from the specified position/offset of the file. + // The `position` argument here is necessary as it's used to specify where the data will start to be read by the patching methods. + ValueTask<(Stream stream, bool leaveOpen)> CreateStreamAsync(long position, CancellationToken calleeToken) + { + // Open the patch `Stream` with shared Read operation. The `Stream` must be created with `FileShare.Read` as this method + // will be called to produce multiple `Stream` instances with shared Read operations. + // + // This is important to note that we don't use `using` keyword here as we don't want to dispose the `Stream` instance + // after leaving this method. We want the callee to dispose the `Stream` instance instead later by setting `leaveOpen` + // to `false` under the returned value below. + FileStream stream = File.Open(patchPath, FileMode.Open, FileAccess.Read, FileShare.Read); + + // The `Stream` instance must be seek-ed to the certain offset provided by the `position` argument. + stream.Position = position; + + // Return the `Stream` instance and set the `leaveOpen` to `false` to tell the callee to + // dispose this created `Stream` instance after use. + // + // Another thing to note on this asynchronous version that since we don't await any method here, we can + // just pass the result of the `ValueTask` instead. For the fully asynchronous example, you can go to + // the next example below. + return new ValueTask<(Stream stream, bool leaveOpen)>((stream, false)); + } +} +``` + +## E. Uses a `Stream` Factory to open Patch file from a remote URL (HTTP). +**Yes, you heard it right.** Thanks to the power of "re-writing the code instead of fixing the existing ones", we re-think to make the read of the patch from a remote `Stream` possible. In this example, we utilizes a fully asynchronous method version of the methods. This demo is basically identical as previous one but we adjust the inner `CreateStreamAsync` method to produce the `Stream` instance from an `HttpClient` as the methods under the `HttpClient` are mostly asynchronous. + +```CSharp +private static async Task ProcessPatchFromRemote(HttpClient client, + string patchUrl, + string inputPath, + string outputPath, + PatchOptions options, + CancellationToken token) +{ + // Create the info context from a `Stream` factory method by `CreateStreamAsync()`. + using HDiffInfo info = await HPatch.CreateInstanceAsync(CreateStreamAsync, token); + + // Start the patch process by passing the `CreateStreamAsync()` factory method to the `HPatch.PatchAsync()`. + PatchResult patchResult = await HPatch.PatchAsync(info, CreateStreamAsync, inputPath, outputPath, options: options, token: token); + + if (!patchResult) + throw patchResult.Exception ?? new Exception(); + + return; + + // This factory method produces a remote `Stream` instance from a remote URL with specified position/offset. + // This method is now fully asynchronous than the previous demos. + async ValueTask<(Stream stream, bool leaveOpen)> CreateStreamAsync(long position, CancellationToken calleeToken) + { + // Creates a `GET` request message to the HTTP server with specified URL. + // Also, the request message must provide a `content-range` header by specifying `RangeHeaderValue` + // to the `HttpRequestMessage.Headers.Range` property. The `null` after the `position` here means + // to: "Get a slice of the remote `Stream` starting from this `position` to the rest of the file." + HttpRequestMessage request = new(HttpMethod.Get, patchUrl); + request.Headers.Range = new RangeHeaderValue(position, null); + + // Send the `GET` request message to the HTTP server, then get the response of the request. + // The `HttpCompletionOption.ResponseHeadersRead` here is important as we don't want to pre-cache + // the entire response data to the memory temporarily (which took much longer). Instead, we just + // want it on-demand and read the rest of the data we only wanted. + HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, calleeToken); + + // This method is actually optional to call, but it's better for us to call it upfront to + // ensure that the response produces `2xx` response (OK/Continue) and return the actual patch data + // instead of an error message. + // + // If non-`2xx` response is returned, then throw for us. + response.EnsureSuccessStatusCode(); + + // Open the remote `Stream` instance and pass the `leaveOpen` to `false` to tell the callee to + // dispose the `Stream` instance after use (and so, disposing the `HttpRequestMessage` and + // `HttpResponseMessage` for us automatically). + return (await response.Content.ReadAsStreamAsync(calleeToken), false); + } +} +``` + +## F. Initialize Kuro Games HDiff19 Patch Format +Kuro Games recently produces a slightly modified version of HDiff19 to be used on the patching process of their game, Wuthering Waves. This format slighty changes how the Directory Patch Information is structurized. + +Instead of using this regular format: +``` +... previous struct +- Input Path Entry Array (string) +- Output Path Entry Array (string) +- Input Files Index Array (int) +- Output Files Index Array (int) +- Output Files Sizes Array (long) +- Same File Path Index Pair Array (int, int) +... next struct +``` +They added two additional structs: +``` +... previous struct +- Input Path Entry Array (string) +- Output Path Entry Array (string) +- Input Files Index Array (int) +- Output Files Index Array (int) +- Input Files Sizes Array (long) < Exists on Kuro Games format, used for input file size sanity > +- Output Files Sizes Array (long) +- Output Files Hashes Array (long) < Exists on Kuro Games format, used for final output file integrity > +- Same File Path Index Pair Array (int, int) +... next struct +``` + +Another to mention that the Kuro Games format still uses the same signature magic, which is `HDiff19`, we can't make it distinctly different from normal ones. So in order to initialize the patch file, you have to manually create an additional `InitializeOptions` and set the `IsKuroGamesHDiff` field to `true`, then pass the struct into the `HPatch.CreateInstance()` or `HPatch.CreateInstanceAsync` method (depends on your use case). + +Here's the example of the usage: +```CSharp +private static void ProcessPatch(string patchPath, + string inputPath, + string outputPath, + PatchOptions options) +{ + // Create the initialization option and set `IsKuroGamesHDiff` to `true`. + InitializeOptions initializeOptions = new() + { + IsKuroGamesHDiff = true + }; + + // Pass the initialization option to the `CreateInstance()` method. + using HDiffInfo info = HPatch.CreateInstance(patchPath, initializeOptions); + + // Start the patching process as usual. + PatchResult patchResult = HPatch.Patch(info, patchPath, inputPath, outputPath, options: options); + + if (!patchResult) + throw patchResult.Exception ?? new Exception(); +} +``` +_Thanks to @Cryotechnic for the initial implementaion on the V2 codebase._ + +### For Kuro Games developer: + +_I think it's better for you to make a different signature magic (for example: `HDiff19Kuro` or something) instead of just adding an arbitrary structs inside of the file so it's easier for us to automatically parse your format. Also, don't forget to ask the permission to the original developer of the format (housisong) that you slightly changed their format for your own purposes (**And... don't forget to give them a credit on your launcher license file or something**)_😉 + +~ @neon-nyan + +### G. Use Miscellaneous Utilities +We have few utility methods which enables you to play with the `HDiffInfo` info context struct and gets some information about the patch file. + +#### Example 1: Get the PatchMetadata using `HPatch.TryGetPatchMetadata()` +```CSharp +// Creates an `HDiffInfo` info context from a patch file path. +HDiffInfo info = HPatch.CreateInstance(PatchPath); + +try +{ + // Try to get the `PatchMetadata` out of `HDiffInfo` info context. + if (!HPatch.TryGetPatchMetadata(ref info, out PatchMetadata patchMetadata)) + { + throw new InvalidOperationException("Cannot get PatchMetadata"); + } + + // Prints some info from the `PatchMetadata` struct. + Console.WriteLine($""" + Old Data Size: {patchMetadata.DiffOldSize} + New Data Size: {patchMetadata.DiffNewSize} + RLE Cover Info Count: {patchMetadata.CoverDataCount} + """); +} +finally +{ + // Dispose the info context struct to release the unmanaged resources + info.Dispose(); +} +``` + +#### Example 2: Get the DirectoryPatchMetadata and prints the Input and Output Path List +```CSharp +// Creates an `HDiffInfo` info context from a patch file path. +HDiffInfo info = HPatch.CreateInstance(PatchPath); + +try +{ + // Try to get the `PatchMetadata` out of `HDiffInfo` info context. + if (!HPatch.TryGetDirectoryPatchMetadata(ref info, out DirectoryPatchMetadata directoryPatchMetadata)) + { + Console.WriteLine("File is not an HDiff19 Directory patch format."); + return; + } + + // Print data from DirectoryPatchMetadata. + // NOTE: As some of these methods are unsafe, you must enable to true in your project file. + unsafe + { + // Creates a `Span` from an unmanaged `InputPathListP` field + Span inputPaths = HPatch.TryGetUnmanagedArraySpan(directoryPatchMetadata.InputPathListP); + Console.WriteLine("Input paths:"); + for (int i = 0; i < inputPaths.Length; i++) + { + // Prints the `Utf16UnmanagedString` directly as it implicitly converts itself to a managed `string` type. + Console.WriteLine($" - {inputPaths[i]}"); + } + + // Creates a `Span` from an unmanaged `OutputPathListP` field + Span outputPaths = HPatch.TryGetUnmanagedArraySpan(directoryPatchMetadata.OutputPathListP); + Console.WriteLine("Output paths:"); + for (int i = 0; i < outputPaths.Length; i++) + { + // Prints the `Utf16UnmanagedString` directly as it implicitly converts itself to a managed `string` type. + Console.WriteLine($" - {outputPaths[i]}"); + } + } +} +finally +{ + // Dispose the info context struct to release the unmanaged resources + info.Dispose(); +} +``` + +#### Example 3: Get the total Input/Output size from the patch path. +```CSharp +// Try to get the total size of the input or output files from a patch file path. +if (!HPatch.TryGetDiffSizeInfo(PatchPath, out long totalInputSize, out long totalOutputSize)) +{ + // If failed, throw. + throw new InvalidOperationException("Patch file might be invalid or unsupported"); +} + +// Print the total size info. +Console.WriteLine($""" + Total Old/Input File Size: {totalInputSize} + Total New/Output File Size: {totalOutputSize} + """); +``` \ No newline at end of file diff --git a/SharpHPatchZ.Program/Program.cs b/SharpHPatchZ.Program/Program.cs index 335c18b..7f38349 100644 --- a/SharpHPatchZ.Program/Program.cs +++ b/SharpHPatchZ.Program/Program.cs @@ -241,8 +241,8 @@ private static void AddCommandInfo(RootCommand command) int count = directoryPatch.SameFilePathCountSizeInfoP->Count; var sameFileIndexPairSpan = new Span(p, count); - Span inputPathList = directoryPatch.InputPathListP->GetSpan(); - Span outputPathList = directoryPatch.OutputPathListP->GetSpan(); + Span inputPathList = HPatch.TryGetUnmanagedArraySpan(directoryPatch.InputPathListP); + Span outputPathList = HPatch.TryGetUnmanagedArraySpan(directoryPatch.OutputPathListP); for (int i = 0; i < count; i++) { ref FileIndexPair pair = ref sameFileIndexPairSpan[i]; @@ -265,12 +265,9 @@ static unsafe void PrintPathList( UnmanagedArray* pathFileHashList) { Console.WriteLine(msgType); - Span pathArray = pathList->GetSpan(); - Span fileSizeArray = pathSizeList == null ? - Span.Empty : pathSizeList->GetSpan(); - - Span fileHashArray = pathFileHashList == null ? - Span.Empty : pathFileHashList->GetSpan(); + Span pathArray = HPatch.TryGetUnmanagedArraySpan(pathList); + Span fileSizeArray = HPatch.TryGetUnmanagedArraySpan(pathSizeList); + Span fileHashArray = HPatch.TryGetUnmanagedArraySpan(pathFileHashList); for (int i = 0; i < pathArray.Length; i++) { @@ -283,7 +280,7 @@ static unsafe void PrintPathList( } } - Span fileIndexList = pathFileIndexList->GetSpan(); + Span fileIndexList = HPatch.TryGetUnmanagedArraySpan(pathFileIndexList); for (int i = 0; i < fileIndexList.Length; i++) { ref int index = ref fileIndexList[i]; diff --git a/SharpHPatchZ/HPatch.Utility.cs b/SharpHPatchZ/HPatch.Utility.cs index 8cf2843..3e6b922 100644 --- a/SharpHPatchZ/HPatch.Utility.cs +++ b/SharpHPatchZ/HPatch.Utility.cs @@ -9,81 +9,77 @@ namespace SharpHPatchZ; public static partial class HPatch { - /// - /// Try retrieve a struct from a patch context. - /// /// A context and information struct for the to be retrieved from. - /// A retrieved struct of containing the main information about the patch file. - /// - /// Returns if is successfully retrieved. Otherwise, if the context struct is invalid or corrupted. - /// - public static bool TryGetPatchMetadata( - ref HDiffInfo info, - out PatchMetadata patchMetadata) + extension(ref HDiffInfo info) { - Unsafe.SkipInit(out patchMetadata); - - ref PatchMetadata patchMetadataRef = ref info.GetPatchMetadata(); - if (Unsafe.IsNullRef(ref patchMetadataRef)) + /// + /// Try retrieve a struct from a patch context. + /// + /// A retrieved struct of containing the main information about the patch file. + /// + /// Returns if is successfully retrieved. Otherwise, if the context struct is invalid or corrupted. + /// + public bool TryGetPatchMetadata(out PatchMetadata patchMetadata) { - return false; - } + Unsafe.SkipInit(out patchMetadata); - patchMetadata = patchMetadataRef; - return true; - } + ref PatchMetadata patchMetadataRef = ref info.GetPatchMetadata(); + if (Unsafe.IsNullRef(ref patchMetadataRef)) + { + return false; + } - /// - /// Try retrieve a struct from a patch context. - /// - /// A context and information struct for the to be retrieved from. - /// A retrieved struct of containing the main information about the patch file. - /// - /// Returns if is successfully retrieved. - /// Otherwise, if the patch context does not contain struct. - /// - public static bool TryGetDirectoryPatchMetadata( - ref HDiffInfo info, - out DirectoryPatchMetadata patchMetadata) - { - Unsafe.SkipInit(out patchMetadata); + patchMetadata = patchMetadataRef; + return true; + } - ref DirectoryPatchMetadata patchMetadataRef = ref info.MetadataAs(); - if (Unsafe.IsNullRef(ref patchMetadataRef)) + /// + /// Try retrieve a struct from a patch context. + /// + /// A retrieved struct of containing the main information about the patch file. + /// + /// Returns if is successfully retrieved. + /// Otherwise, if the patch context does not contain struct. + /// + public bool TryGetDirectoryPatchMetadata(out DirectoryPatchMetadata patchMetadata) { - return false; - } + Unsafe.SkipInit(out patchMetadata); - patchMetadata = patchMetadataRef; - return true; - } + ref DirectoryPatchMetadata patchMetadataRef = ref info.MetadataAs(); + if (Unsafe.IsNullRef(ref patchMetadataRef)) + { + return false; + } - /// - /// Try retrieves both total Input and Output size from a patch context. - /// - /// A context and information struct for the total Input and Output size to be retrieved from. - /// The total size of an Input File/Directory. - /// The total size of an Output File/Directory. - /// - /// Returns if both and are successfully retrieved. - /// Otherwise, if the patch context is invalid or corrupted. - /// - public static bool TryGetDiffSizeInfo(ref HDiffInfo info, - out long totalInputSize, - out long totalOutputSize) - { - Unsafe.SkipInit(out totalInputSize); - Unsafe.SkipInit(out totalOutputSize); + patchMetadata = patchMetadataRef; + return true; + } - ref PatchMetadata patchMetadata = ref info.GetPatchMetadata(); - if (Unsafe.IsNullRef(ref patchMetadata)) + /// + /// Try retrieves both total Input and Output size from a patch context. + /// + /// The total size of an Input File/Directory. + /// The total size of an Output File/Directory. + /// + /// Returns if both and are successfully retrieved. + /// Otherwise, if the patch context is invalid or corrupted. + /// + public bool TryGetDiffSizeInfo(out long totalInputSize, + out long totalOutputSize) { - return false; + Unsafe.SkipInit(out totalInputSize); + Unsafe.SkipInit(out totalOutputSize); + + ref PatchMetadata patchMetadata = ref info.GetPatchMetadata(); + if (Unsafe.IsNullRef(ref patchMetadata)) + { + return false; + } + + totalInputSize = patchMetadata.DiffOldSize; + totalOutputSize = patchMetadata.DiffNewSize; + return true; } - - totalInputSize = patchMetadata.DiffOldSize; - totalOutputSize = patchMetadata.DiffNewSize; - return true; } /// @@ -96,16 +92,16 @@ public static bool TryGetDiffSizeInfo(ref HDiffInfo info, /// Returns if both and are successfully retrieved. /// Otherwise, if the patch context or the file is invalid or corrupted. /// - public static bool TryGetDiffSizeInfo(string patchFilePath, - out long totalInputSize, - out long totalOutputSize) + public static bool TryGetDiffSizeInfo( + string patchFilePath, + out long totalInputSize, + out long totalOutputSize) { HDiffInfo info = CreateInstance(CreateStream); try { - return TryGetDiffSizeInfo(ref info, - out totalInputSize, - out totalOutputSize); + return info.TryGetDiffSizeInfo(out totalInputSize, + out totalOutputSize); } finally { @@ -137,9 +133,8 @@ public static bool TryGetDiffSizeInfo(CreateStream createStream, HDiffInfo info = CreateInstance(createStream); try { - return TryGetDiffSizeInfo(ref info, - out totalInputSize, - out totalOutputSize); + return info.TryGetDiffSizeInfo(out totalInputSize, + out totalOutputSize); } finally { @@ -186,4 +181,17 @@ public static unsafe Span TryGetUnmanagedArraySpan(UnmanagedArray* arra => array == null || (MetadataExtension.TryGetMetadataType(array, out MetadataTypeConst metadataType) && metadataType != MetadataTypeConst.UnmanagedArrayType) ? Span.Empty : array->GetSpan(); + + /// + /// Try gets the from an instance. + /// + /// The type of the content struct + /// The unmanaged array to get the from. + /// + /// Returns a non-empty if the array is valid. + /// Otherwise, returns an empty if the array is invalid. + /// + public static unsafe Span TryGetUnmanagedArraySpan(this ref UnmanagedArray array) + where T : unmanaged + => TryGetUnmanagedArraySpan((UnmanagedArray*)Unsafe.AsPointer(ref array)); } \ No newline at end of file diff --git a/SharpHPatchZ/Header/HDiffChecksum.cs b/SharpHPatchZ/Header/HDiffChecksum.cs index 515d171..d326049 100644 --- a/SharpHPatchZ/Header/HDiffChecksum.cs +++ b/SharpHPatchZ/Header/HDiffChecksum.cs @@ -1,5 +1,8 @@ namespace SharpHPatchZ.Header; +/// +/// Determines the type of the Checksum used within the HDiff file. +/// public enum HDiffChecksum { NoChecksum, diff --git a/SharpHPatchZ/Header/HDiffCompression.cs b/SharpHPatchZ/Header/HDiffCompression.cs index b42c79f..d05858d 100644 --- a/SharpHPatchZ/Header/HDiffCompression.cs +++ b/SharpHPatchZ/Header/HDiffCompression.cs @@ -3,6 +3,9 @@ // ReSharper disable InconsistentNaming namespace SharpHPatchZ.Header; +/// +/// Determines the Compression Type of the HDiff file. +/// public enum HDiffCompression { Uncompressed, diff --git a/SharpHPatchZ/Header/HDiffInfo.cs b/SharpHPatchZ/Header/HDiffInfo.cs index e3609bc..f920bd4 100644 --- a/SharpHPatchZ/Header/HDiffInfo.cs +++ b/SharpHPatchZ/Header/HDiffInfo.cs @@ -15,13 +15,13 @@ public unsafe struct HDiffInfo : IDisposable public InitializeOptions InitializeOptions; public void* MetadataP; - public ref T MetadataAs() + internal ref T MetadataAs() where T : unmanaged, IMetadataInit => ref MetadataP == null ? ref Unsafe.NullRef() : ref Unsafe.AsRef(MetadataP); - public ref T AllocMetadata() + internal ref T AllocMetadata() where T : unmanaged, IMetadataInit { if (MetadataP != null) MemoryAlloc.Free(MetadataP); @@ -31,7 +31,7 @@ public ref T AllocMetadata() return ref Unsafe.AsRef(MetadataP); } - public ref PatchMetadata GetPatchMetadata() + internal ref PatchMetadata GetPatchMetadata() { void* patchMetadataP; if (MetadataExtension.TryGetMetadataType(MetadataP, out MetadataTypeConst rootMetadataType) && diff --git a/SharpHPatchZ/Header/HDiffMagic.cs b/SharpHPatchZ/Header/HDiffMagic.cs index 44e4f48..82c70aa 100644 --- a/SharpHPatchZ/Header/HDiffMagic.cs +++ b/SharpHPatchZ/Header/HDiffMagic.cs @@ -1,8 +1,22 @@ namespace SharpHPatchZ.Header; +/// +/// The signature type of the HDiff patch format. +/// public enum HDiffMagic { + /// + /// Whether to indicate that the file is not an HDiff Patch or unsupported format. + /// Unknown, + + /// + /// Patch is a single HDiff format (HDiff13). + /// HDiff13, + + /// + /// Patch is a Directory HDiff extension for HDiff13 format (HDiff19+HDiff13 aka DirHDiff). + /// HDiff19 } diff --git a/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs b/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs index b639666..4630dcb 100644 --- a/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs +++ b/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs @@ -78,7 +78,7 @@ public bool IsDisposed public int TypeSize; public T* Data; - public Span GetSpan() => Data == null ? Span.Empty : new Span(Data, Length); + internal Span GetSpan() => Data == null ? Span.Empty : new Span(Data, Length); public static UnmanagedArray* CreateAllocUnsafe(int count, bool initialize = false) { diff --git a/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs b/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs index d1a36b4..891f7b2 100644 --- a/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs +++ b/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs @@ -138,6 +138,9 @@ public int Read(Span buffer, long offset) public void Dispose() { + if (Volatile.Read(ref _disposed) != 0) + return; + _lifetimeLock.EnterWriteLock(); try { diff --git a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs index 95f03f6..f9785dd 100644 --- a/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs +++ b/SharpHPatchZ/Patch/PatcherFactory.HDiff13Derived.cs @@ -83,7 +83,7 @@ private static unsafe DiffReadersContext CreateReaderContext(HDiffCompression { int bufferSize = options.ReaderBufferSize; - ChunkSizeInfo coverSize = *patchMetadata.CoverDataSizeP; + ChunkSizeInfo coverSize = *patchMetadata.CoverDataSizeP; ChunkSizeInfo controlSize = *patchMetadata.RleControlDataSizeP; ChunkSizeInfo codeSize = *patchMetadata.RleCodeDataSizeP; ChunkSizeInfo newDataSize = *patchMetadata.NewDiffDataSizeP; From 56fc3cba04d0c0765169a59bd9e8ba6a77c27714 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 31 Aug 2026 20:36:31 +0700 Subject: [PATCH 69/72] Add docs WARNING: Vibe-coded --- SharpHPatchZ/Extension/ExceptionHelper.cs | 75 +++++++++++-------- SharpHPatchZ/Extension/NativeMemoryBuffer.cs | 2 +- SharpHPatchZ/Extension/StringExtension.cs | 3 + SharpHPatchZ/HPatch.UnmanagedExtern.cs | 57 ++++++++++++++ SharpHPatchZ/Header/HDiffChecksum.cs | 3 + SharpHPatchZ/Header/HDiffChecksumResult.cs | 6 ++ SharpHPatchZ/Header/HDiffCompression.cs | 7 ++ SharpHPatchZ/Header/HDiffInfo.cs | 9 +++ SharpHPatchZ/Header/HeaderReader.cs | 6 ++ .../Header/Metadata/ChecksumDataInfo.cs | 15 ++++ SharpHPatchZ/Header/Metadata/ChunkSizeInfo.cs | 3 + .../Header/Metadata/DirectoryPatchMetadata.cs | 27 ++++++- .../Header/Metadata/EntryCountSizeInfo.cs | 5 +- .../Header/Metadata/ExternSizeInfo.cs | 5 ++ SharpHPatchZ/Header/Metadata/FileIndexPair.cs | 4 + SharpHPatchZ/Header/Metadata/IMetadataInit.cs | 5 ++ .../Header/Metadata/MetadataTypeConst.cs | 7 ++ SharpHPatchZ/Header/Metadata/PatchMetadata.cs | 15 ++++ .../Header/Metadata/UnmanagedArray.cs | 23 ++++++ .../Header/Metadata/Utf16UnmanagedString.cs | 26 +++++++ .../IO/Compression/BZip2/BZip2Constants.cs | 2 +- .../IO/Compression/BZip2/BZip2Crc32.cs | 14 +++- .../IO/Compression/BZip2/BZip2InputStream.cs | 21 +++++- .../IO/Compression/Lzma/LZ/LzOutWindow.cs | 2 +- SharpHPatchZ/IO/Compression/Lzma/LzmaBase.cs | 2 +- .../IO/Compression/Lzma/LzmaDecoder.cs | 2 +- .../IO/Compression/Lzma/LzmaExceptions.cs | 2 +- .../IO/Compression/Lzma/LzmaInputStream.cs | 40 +++++++++- .../Compression/Lzma/RangeCoder/RangeCoder.cs | 2 +- .../Lzma/RangeCoder/RangeCoderBit.cs | 2 +- .../Lzma/RangeCoder/RangeCoderBitTree.cs | 2 +- SharpHPatchZ/IO/RandomAccessCompat.cs | 2 +- .../Reader/DecompressionTransitionStream.cs | 2 +- .../IO/Reader/PrefetchedReadStream.cs | 2 +- .../HDiff13DerivedPatcher.CorePatcher.cs | 2 +- 35 files changed, 352 insertions(+), 50 deletions(-) diff --git a/SharpHPatchZ/Extension/ExceptionHelper.cs b/SharpHPatchZ/Extension/ExceptionHelper.cs index 56af553..707340c 100644 --- a/SharpHPatchZ/Extension/ExceptionHelper.cs +++ b/SharpHPatchZ/Extension/ExceptionHelper.cs @@ -80,67 +80,68 @@ file static class Const public const string HDiffCompLZMASizeTooSmallForDictionaryRead = "HDIFF_CompLZMASizeToSmallForDictionaryRead"; } +/// Creates library-specific exceptions and translates them for unmanaged callers. public static class ExceptionHelper { - private static Exception? LastException; + internal static Exception? LastException; - public static NotSupportedException ThrowHDiffHeaderMagicNotSupported(ReadOnlySpan magic) + internal static NotSupportedException ThrowHDiffHeaderMagicNotSupported(ReadOnlySpan magic) => new($"[{Const.HDiffHeaderMagicNotSupported}] Header magic: {magic.ToString()} is not supported!"); - public static NotSupportedException ThrowHDiffHeaderCompressionNotSupported(ReadOnlySpan enumString) + internal static NotSupportedException ThrowHDiffHeaderCompressionNotSupported(ReadOnlySpan enumString) => new($"[{Const.HDiffHeaderCompressionNotSupported}] HDIFF compression: {enumString.ToString()} is not supported!"); - public static NotSupportedException ThrowHDiffHeaderChecksumNotSupported(ReadOnlySpan enumString) + internal static NotSupportedException ThrowHDiffHeaderChecksumNotSupported(ReadOnlySpan enumString) => new($"[{Const.HDiffHeaderChecksumNotSupported}] HDIFF checksum: {enumString.ToString()} is not supported!"); - public static NotSupportedException ThrowHDiffPatchFactoryNotSupported(HDiffMagic type) + internal static NotSupportedException ThrowHDiffPatchFactoryNotSupported(HDiffMagic type) => new($"[{Const.HDiffPatchFactoryNotSupported}] No factory supported for type: {type}!"); - - public static NullReferenceException ThrowHDiffInfoNotAllocated() + internal static NullReferenceException ThrowHDiffInfoNotAllocated() => new($"[{Const.HDiffInfoNotAllocated}] HDiffInfo pointer is not allocated!"); - public static NullReferenceException ThrowHDiffInfoDirectoryPatchMetadataNotAllocated() + internal static NullReferenceException ThrowHDiffInfoDirectoryPatchMetadataNotAllocated() => new($"[{Const.HDiffInfoDirectoryPatchMetadataNotAllocated}] HDiffInfo directory patch metadata is not allocated!"); - public static NullReferenceException ThrowHDiffInfoPatchMetadataNotAllocated() + internal static NullReferenceException ThrowHDiffInfoPatchMetadataNotAllocated() => new($"[{Const.HDiffInfoPatchMetadataNotAllocated}] HDiffInfo patch metadata is not allocated!"); - public static NullReferenceException ThrowHDiffFILEDescriptorNull() + internal static NullReferenceException ThrowHDiffFILEDescriptorNull() => new($"[{Const.HDiffFILEDescriptorNull}] FILE descriptor cannot be null!"); - public static NullReferenceException ThrowHDiffArgumentNull(string nameOfArg) + internal static NullReferenceException ThrowHDiffArgumentNull(string nameOfArg) => new($"[{Const.HDiffArgumentNull}] Argument: {nameOfArg} cannot be null!"); - - public static InvalidOperationException ThrowHDiffHeaderSignatureEmptyOrUnreadable() + internal static InvalidOperationException ThrowHDiffHeaderSignatureEmptyOrUnreadable() => new($"[{Const.HDiffHeaderSignatureEmptyOrUnreadable}] Header signature is empty or unreadable!"); - public static EndOfStreamException ThrowHDiffEndOfFileOrData(Exception innerException) + internal static EndOfStreamException ThrowHDiffEndOfFileOrData(Exception innerException) => new($"[{Const.HDiffHeaderEndOfFileOrData}] HDiff Data has reached End-of-File or Data", innerException); - public static InvalidOperationException ThrowHDiffPathIsEmptyOrInvalid() + internal static InvalidOperationException ThrowHDiffPathIsEmptyOrInvalid() => new($"[{Const.HDiffPathIsEmptyOrInvalid}] File or Directory path is empty or invalid"); - public static IOException ThrowHDiffIOException(Exception ex) + internal static IOException ThrowHDiffIOException(Exception ex) => new($"[{Const.HDiffIOException}] An IO Error has occurred with message: {ex.Message}", ex); - public static FileNotFoundException ThrowHDiffPatchInputPathNotExist(string filePath) + internal static FileNotFoundException ThrowHDiffPatchInputPathNotExist(string filePath) => new($"[{Const.HDiffPatchInputPathNotExist}] Input path does not exist: {filePath}", filePath); - public static InvalidOperationException ThrowHDiffPatchInputSizeMismatched(string filePath, long existingSize, long expectingSize) + internal static InvalidOperationException ThrowHDiffPatchInputSizeMismatched(string filePath, long existingSize, long expectingSize) => new($"[{Const.HDiffPatchInputSizeMismatched}] Input file size does not match: {filePath} (Expecting: {expectingSize} bytes, but got: {existingSize} instead)."); - public static InvalidOperationException ThrowHDiffPatchPathNotADirectory(string path) + internal static InvalidOperationException ThrowHDiffPatchPathNotADirectory(string path) => new($"[{Const.HDiffPatchPathNotADirectory}] Path is not a directory!: {path}"); - public static InvalidOperationException ThrowHDiffPatchPathNotAFile(string path) + internal static InvalidOperationException ThrowHDiffPatchPathNotAFile(string path) => new($"[{Const.HDiffPatchPathNotAFile}] Path is not a file!: {path}"); - public static InvalidOperationException ThrowHDiffPatchInputFilesMismatched(long existingSize, long expectingSize) + internal static InvalidOperationException ThrowHDiffPatchInputFilesMismatched(long existingSize, long expectingSize) => new($"[{Const.HDiffPatchInputFilesMismatched}] Input file size mismatched! Expecting: {expectingSize} bytes but got: {expectingSize} bytes instead."); - public static InvalidOperationException ThrowHDiffPatchKuroInputFileSizeMismatched(string filePath, long existingSize, long expectingSize) + internal static InvalidOperationException ThrowHDiffPatchKuroInputFileSizeMismatched(string filePath, long existingSize, long expectingSize) => new($"[{Const.HDiffPatchKuroInputFileSizeMismatched}] Kuro Games Patch input file size does not match: {filePath} (Expecting: {expectingSize} bytes, but got: {existingSize} instead)."); - public static IndexOutOfRangeException ThrowHDiffStreamReadOutOfBound() + internal static IndexOutOfRangeException ThrowHDiffStreamReadOutOfBound() => new($"[{Const.HDiffStreamReadOutOfBound}] Stream Read is out of bound!"); - public static InvalidDataException ThrowHDiffStringEncodingFailed(Exception? innerException) + internal static InvalidDataException ThrowHDiffStringEncodingFailed(Exception? innerException) => new($"[{Const.HDiffStringEncodingFailed}] Error while trying to encode a string!", innerException); - - public static InvalidDataException ThrowHDiffCompLZMAPropertyMissing() + internal static InvalidDataException ThrowHDiffCompLZMAPropertyMissing() => new($"[{Const.HDiffCompLZMAPropertyMissing}] The LZMA stream is missing its properties."); - public static InvalidDataException ThrowHDiffCompLZMA2DictionaryInvalid(int property) + internal static InvalidDataException ThrowHDiffCompLZMA2DictionaryInvalid(int property) => new($"[{Const.HDiffCompLZMA2DictionaryInvalid}] The LZMA2 dictionary property must be at most 40, but was {property}."); - public static InvalidDataException ThrowHDiffCompLZMA2NoCompressedPayload() + internal static InvalidDataException ThrowHDiffCompLZMA2NoCompressedPayload() => new($"[{Const.HDiffCompLZMA2NoCompressedPayload}] The LZMA2 stream has no compressed payload."); - public static InvalidDataException ThrowHDiffCompLZMADictionaryInvalidLength(int lzmaPropertySize, int property) + internal static InvalidDataException ThrowHDiffCompLZMADictionaryInvalidLength(int lzmaPropertySize, int property) => new($"[{Const.HDiffCompLZMADictionaryInvalidLength}] The LZMA property length must be {lzmaPropertySize}, but was {property}."); - public static InvalidDataException ThrowHDiffCompLZMASizeTooSmallForDictionaryRead() + internal static InvalidDataException ThrowHDiffCompLZMASizeTooSmallForDictionaryRead() => new($"[{Const.HDiffCompLZMASizeTooSmallForDictionaryRead}] The LZMA compressed size is too small to contain its headers and payload."); + /// Maps a library exception to the numeric code used by the unmanaged API. + /// The to record and translate, or for success. + /// 0 if is . A defined positive error code if the exception is recognized. Otherwise, -1. public static int TryGetReturnCodeFromError(Exception? ex) { if (ex == null) @@ -187,6 +188,10 @@ public static int TryGetReturnCodeFromError(Exception? ex) } #if NET8_0_OR_GREATER + /// Writes the most recently recorded error to a zero-terminated UTF-8 buffer. + /// The destination buffer, including space for a zero terminator. + /// The error details to include. + /// The number of bytes written. 0 when no error is available. Otherwise, -1 when is too small. public static int TryGetLastErrorMessageUtf8(Span spanByte, LastErrorMessageType lastErrorMessageType) { Exception? thisException = Volatile.Read(ref LastException); @@ -226,6 +231,10 @@ public static int TryGetLastErrorMessageUtf8(Span spanByte, LastErrorMessa return written; } + /// Writes the most recently recorded error to a zero-terminated UTF-16 buffer. + /// The destination buffer, including space for a zero terminator. + /// The error details to include. + /// The number of characters written. 0 when no error is available. Otherwise, -1 when is too small. public static int TryGetLastErrorMessageUnicode(Span spanChar, LastErrorMessageType lastErrorMessageType) { Exception? thisException = Volatile.Read(ref LastException); @@ -266,12 +275,16 @@ public static int TryGetLastErrorMessageUnicode(Span spanChar, LastErrorMe return written; } + /// Specifies which portions of the last error are returned to an unmanaged caller. [Flags] public enum LastErrorMessageType { + /// Include the exception message. Message = 1, + /// Include the exception stack trace. StackTrace = 2, + /// Include both the exception message and stack trace. MessageAndStackTrace = Message | StackTrace } #endif -} \ No newline at end of file +} diff --git a/SharpHPatchZ/Extension/NativeMemoryBuffer.cs b/SharpHPatchZ/Extension/NativeMemoryBuffer.cs index ca1f57c..2fa1e19 100644 --- a/SharpHPatchZ/Extension/NativeMemoryBuffer.cs +++ b/SharpHPatchZ/Extension/NativeMemoryBuffer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.CompilerServices; using System.Threading; diff --git a/SharpHPatchZ/Extension/StringExtension.cs b/SharpHPatchZ/Extension/StringExtension.cs index b075ade..1563f64 100644 --- a/SharpHPatchZ/Extension/StringExtension.cs +++ b/SharpHPatchZ/Extension/StringExtension.cs @@ -172,8 +172,11 @@ public static unsafe NativeStringEncoding GuessStringEncoding( #endif } +/// Identifies an encoding used by a zero-terminated native character sequence. public enum NativeStringEncoding { + /// UTF-8 encoding. Utf8, + /// UTF-16 encoding in the platform's native little-endian representation. Unicode } diff --git a/SharpHPatchZ/HPatch.UnmanagedExtern.cs b/SharpHPatchZ/HPatch.UnmanagedExtern.cs index f384ba8..0cf420d 100644 --- a/SharpHPatchZ/HPatch.UnmanagedExtern.cs +++ b/SharpHPatchZ/HPatch.UnmanagedExtern.cs @@ -30,6 +30,12 @@ namespace SharpHPatchZ; public static partial class HPatch { #if NET8_0_OR_GREATER + /// Parses a zero-terminated UTF-8 or UTF-16 patch signature for an unmanaged caller. + /// A pointer to the zero-terminated signature . + /// A pointer that receives the . + /// A pointer that receives the . + /// A pointer that receives the . + /// 0 if is parsed successfully. Otherwise, a library error code. [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_read_header_signature_string")] public static unsafe int SharpHPatchZ_ReadHeaderSignatureStringAuto(void* signatureP, HDiffMagic* magicTypeP, HDiffCompression* compressionTypeP, HDiffChecksum* checksumTypeP) { @@ -58,6 +64,12 @@ public static unsafe int SharpHPatchZ_ReadHeaderSignatureStringAuto(void* signat } } + /// Initializes an from an unmanaged memory buffer. + /// A pointer to the patch data. + /// The patch-data length, in bytes. + /// A pointer that receives the initialized . + /// A pointer to , or to use defaults. + /// 0 if initialization succeeds. Otherwise, a library error code. [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_init_from_memory")] public static unsafe int SharpHPatchZ_InitializeFromMemory(byte* dataP, long dataLength, HDiffInfo* signP, InitializeOptions* initializeOptionsP) { @@ -82,6 +94,11 @@ public static unsafe int SharpHPatchZ_InitializeFromMemory(byte* dataP, long dat } } + /// Initializes an from a zero-terminated UTF-8 or UTF-16 file path. + /// A pointer to the zero-terminated patch path. + /// A pointer that receives the initialized . + /// A pointer to , or to use defaults. + /// 0 if initialization succeeds. Otherwise, a library error code. [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_init_from_filepath")] public static unsafe int SharpHPatchZ_InitializeFromFilePathAuto(void* pathP, HDiffInfo* signP, InitializeOptions* initializeOptionsP) { @@ -105,6 +122,11 @@ public static unsafe int SharpHPatchZ_InitializeFromFilePathAuto(void* pathP, HD } } + /// Initializes an from a native FILE descriptor. + /// A pointer to the native FILE descriptor. + /// A pointer that receives the initialized . + /// A pointer to , or to use defaults. + /// 0 if initialization succeeds. Otherwise, a library error code. [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_init_from_FILE")] public static unsafe int SharpHPatchZ_InitializeFromFILE(void* FILEP, HDiffInfo* signP, InitializeOptions* initializeOptionsP) { @@ -127,6 +149,14 @@ public static unsafe int SharpHPatchZ_InitializeFromFILE(void* FILEP, HDiffInfo* } } + /// Applies a patch identified by zero-terminated UTF-8 or UTF-16 file-system paths. + /// A pointer to the zero-terminated patch-file path. + /// A pointer to the zero-terminated input path. + /// A pointer to the zero-terminated output path. + /// A pointer to an initialized . + /// A pointer to , or to use defaults. + /// A pointer to a , or for no callback. + /// 0 if patching succeeds. Otherwise, a library error code. [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_patch_from_filepath")] public static unsafe int SharpHPatchZ_PatchFromFilePathAuto( void* patchPathP, @@ -164,6 +194,14 @@ public static unsafe int SharpHPatchZ_PatchFromFilePathAuto( } } + /// Applies a patch read from a native FILE descriptor. + /// A pointer to the native patch-file descriptor. + /// A pointer to the zero-terminated input path. + /// A pointer to the zero-terminated output path. + /// A pointer to an initialized . + /// A pointer to , or to use defaults. + /// A pointer to a , or for no callback. + /// 0 if patching succeeds. Otherwise, a library error code. [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_patch_from_FILE")] public static unsafe int SharpHPatchZ_PatchFromFILE( void* FILEP, @@ -200,6 +238,9 @@ public static unsafe int SharpHPatchZ_PatchFromFILE( } } + /// Releases metadata allocated for an . + /// A pointer to the to release. + /// 0 if the metadata is released. Otherwise, a library error code. [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_free_diff_info")] public static unsafe int SharpHPatchZ_FreeDiffInfo(HDiffInfo* ptr) { @@ -219,18 +260,34 @@ public static unsafe int SharpHPatchZ_FreeDiffInfo(HDiffInfo* ptr) } } + /// Gets the associated with an . + /// A pointer to an initialized . + /// A pointer to the . [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_util_get_patch_metadata")] public static unsafe PatchMetadata* SharpHPatchZ_TryGetPatchMetadata(HDiffInfo* infoP) => (PatchMetadata*)Unsafe.AsPointer(ref infoP[0].GetPatchMetadata()); + /// Gets the associated with an . + /// A pointer to an initialized . + /// A pointer to the , or when it is unavailable. [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_util_get_directory_patch_metadata")] public static unsafe DirectoryPatchMetadata* SharpHPatchZ_TryGetDirectoryPatchMetadata(HDiffInfo* infoP) => (DirectoryPatchMetadata*)Unsafe.AsPointer(ref infoP[0].MetadataAs()); + /// Writes the last recorded error to a zero-terminated UTF-8 buffer. + /// A pointer to the destination buffer. + /// The buffer length, in bytes. + /// The details to include. + /// The number of bytes written. Otherwise, -1 if is too small. [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_get_last_errorA")] public static unsafe int SharpHPatchZ_GetLastErrorUtf8(byte* bufferA, int bufferLength, ExceptionHelper.LastErrorMessageType messageType) => ExceptionHelper.TryGetLastErrorMessageUtf8(new Span(bufferA, bufferLength), messageType); + /// Writes the last recorded error to a zero-terminated UTF-16 buffer. + /// A pointer to the destination buffer. + /// The buffer length, in characters. + /// The details to include. + /// The number of characters written. Otherwise, -1 if is too small. [UnmanagedCallersOnly(CallConvs = [typeof(ConventionCall)], EntryPoint = "shpz_get_last_errorW")] public static unsafe int SharpHPatchZ_GetLastErrorUnicode(char* bufferW, int bufferLength, ExceptionHelper.LastErrorMessageType messageType) => ExceptionHelper.TryGetLastErrorMessageUnicode(new Span(bufferW, bufferLength), messageType); diff --git a/SharpHPatchZ/Header/HDiffChecksum.cs b/SharpHPatchZ/Header/HDiffChecksum.cs index d326049..47faca2 100644 --- a/SharpHPatchZ/Header/HDiffChecksum.cs +++ b/SharpHPatchZ/Header/HDiffChecksum.cs @@ -5,7 +5,10 @@ /// public enum HDiffChecksum { + /// The patch does not include checksums. NoChecksum, + /// The patch uses the fast Adler-64 checksum. FAdler64, + /// The patch uses the CRC-32 checksum. Crc32 } diff --git a/SharpHPatchZ/Header/HDiffChecksumResult.cs b/SharpHPatchZ/Header/HDiffChecksumResult.cs index 8f41e97..74da483 100644 --- a/SharpHPatchZ/Header/HDiffChecksumResult.cs +++ b/SharpHPatchZ/Header/HDiffChecksumResult.cs @@ -2,11 +2,17 @@ namespace SharpHPatchZ.Header; +/// +/// Describes the result of validating a patch checksum. +/// [StructLayout(LayoutKind.Sequential)] public struct HDiffChecksumResult { + /// Indicates whether the patch's checksum algorithm is supported. public bool HasChecksumSupport; + /// Indicates whether checksum validation succeeded. public bool IsSuccessful; + /// Contains the parsed associated with the validation. public HDiffInfo DiffInfo; public static implicit operator bool(HDiffChecksumResult result) diff --git a/SharpHPatchZ/Header/HDiffCompression.cs b/SharpHPatchZ/Header/HDiffCompression.cs index d05858d..a87ef9a 100644 --- a/SharpHPatchZ/Header/HDiffCompression.cs +++ b/SharpHPatchZ/Header/HDiffCompression.cs @@ -8,11 +8,18 @@ namespace SharpHPatchZ.Header; ///
public enum HDiffCompression { + /// The patch data is not compressed. Uncompressed, + /// The patch data uses LZMA compression. Lzma, + /// The patch data uses LZMA2 compression. Lzma2, + /// The patch data uses Zlib compression. Zlib, + /// The patch data uses parallel BZip2 compression. PBZ2, + /// The patch data uses BZip2 compression. BZ2, + /// The patch data uses Zstandard compression. Zstd } diff --git a/SharpHPatchZ/Header/HDiffInfo.cs b/SharpHPatchZ/Header/HDiffInfo.cs index f920bd4..ffc7ed8 100644 --- a/SharpHPatchZ/Header/HDiffInfo.cs +++ b/SharpHPatchZ/Header/HDiffInfo.cs @@ -6,13 +6,21 @@ namespace SharpHPatchZ.Header; +/// +/// Holds the parsed header, initialization options, and unmanaged metadata for an HDiff patch. +/// [StructLayout(LayoutKind.Sequential)] public unsafe struct HDiffInfo : IDisposable { + /// Identifies the patch format. public HDiffMagic MagicType; + /// Identifies the compression algorithm used by the patch. public HDiffCompression CompressionType; + /// Identifies the checksum algorithm used by the patch. public HDiffChecksum ChecksumType; + /// Contains the used to initialize this . public InitializeOptions InitializeOptions; + /// Points to format-specific unmanaged metadata owned by this instance. public void* MetadataP; internal ref T MetadataAs() @@ -58,6 +66,7 @@ internal ref PatchMetadata GetPatchMetadata() return ref Unsafe.AsRef(patchMetadataP); } + /// Releases the unmanaged metadata owned by this instance. public void Dispose() { if (MetadataP == null) return; diff --git a/SharpHPatchZ/Header/HeaderReader.cs b/SharpHPatchZ/Header/HeaderReader.cs index 91c1c14..faef2ce 100644 --- a/SharpHPatchZ/Header/HeaderReader.cs +++ b/SharpHPatchZ/Header/HeaderReader.cs @@ -11,10 +11,16 @@ namespace SharpHPatchZ.Header; +/// +/// Provides operations for parsing HDiff patch headers. +/// public class HeaderReader { private delegate ref PatchMetadata PatchMetadataAllocator(ref HDiffInfo info); + /// Parses a patch header signature into an existing value. + /// The header signature to parse. + /// The patch information to populate. public static void ReadHeaderSignature(ReadOnlySpan signature, ref HDiffInfo info) { ReadBasicHeaderSignature(signature, diff --git a/SharpHPatchZ/Header/Metadata/ChecksumDataInfo.cs b/SharpHPatchZ/Header/Metadata/ChecksumDataInfo.cs index e7f1dee..ec867da 100644 --- a/SharpHPatchZ/Header/Metadata/ChecksumDataInfo.cs +++ b/SharpHPatchZ/Header/Metadata/ChecksumDataInfo.cs @@ -4,13 +4,16 @@ namespace SharpHPatchZ.Header.Metadata; +/// Owns the unmanaged checksum blocks stored in a directory-patch header. public unsafe struct ChecksumDataInfo : IMetadataInit { + /// Initializes a new . public ChecksumDataInfo() { Init(); } + /// public void Init() { if (IsDisposed || IsInitialized) @@ -23,6 +26,7 @@ public void Init() MetadataType = MetadataTypeConst.ChecksumDataInfoType; } + /// public void Dispose() { if (IsDisposed) @@ -37,14 +41,17 @@ public void Dispose() _byte = null; } + /// public MetadataTypeConst MetadataType { get; private set; } + /// public bool IsInitialized { get => _isInitialized == 1; private set => _isInitialized = value ? (byte)1 : (byte)0; } + /// public bool IsDisposed { get => _isDisposed == 1; @@ -58,12 +65,20 @@ public bool IsDisposed private int _dataCount; private void* _byte; + /// Allocates zero-initialized unmanaged storage for checksum elements. + /// The size of each checksum element, in bytes. + /// The number of checksum elements. public void AllocBytes(int dataSize, int elementCount) => _byte = MemoryAlloc.Alloc((_dataSize = dataSize) * (_dataCount = elementCount), true); + /// Gets a covering all allocated checksum bytes. + /// A over the complete checksum buffer. public Span GetAllSpan() => new(_byte, _dataCount * _dataSize); + /// Gets the checksum element at the specified index. + /// The zero-based checksum element index. + /// A over the requested checksum element. public Span GetSpan(int index) => new(Unsafe.Add(_byte, index * _dataSize), _dataSize); } diff --git a/SharpHPatchZ/Header/Metadata/ChunkSizeInfo.cs b/SharpHPatchZ/Header/Metadata/ChunkSizeInfo.cs index 9de7bc1..739f21b 100644 --- a/SharpHPatchZ/Header/Metadata/ChunkSizeInfo.cs +++ b/SharpHPatchZ/Header/Metadata/ChunkSizeInfo.cs @@ -2,9 +2,12 @@ namespace SharpHPatchZ.Header.Metadata; +/// Stores the uncompressed and compressed sizes of a patch data chunk. [StructLayout(LayoutKind.Sequential)] public struct ChunkSizeInfo { + /// The uncompressed chunk size, in bytes. public long Size; + /// The compressed chunk size, in bytes, or zero when the chunk is not compressed. public long CompressedSize; } diff --git a/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs b/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs index bb9f26a..09d5ca8 100644 --- a/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs +++ b/SharpHPatchZ/Header/Metadata/DirectoryPatchMetadata.cs @@ -3,14 +3,17 @@ namespace SharpHPatchZ.Header.Metadata; +/// Contains file lists, index mappings, and chunk information for a directory patch. [StructLayout(LayoutKind.Sequential)] public unsafe struct DirectoryPatchMetadata : IMetadataInit { + /// Initializes a new and its owned records. public DirectoryPatchMetadata() { Init(); } + /// public void Init() { if (IsDisposed || IsInitialized) @@ -30,6 +33,7 @@ public void Init() ChecksumDataInfoP = MemoryAlloc.Alloc(1, true); } + /// public void Dispose() { if (IsDisposed || !IsInitialized) @@ -60,14 +64,17 @@ public void Dispose() MemoryAlloc.Free(NewExecuteListP); } + /// public MetadataTypeConst MetadataType { get; private set; } + /// public bool IsInitialized { get => _isInitialized == 1; private set => _isInitialized = value ? (byte)1 : (byte)0; } + /// public bool IsDisposed { get => _isDisposed == 1; @@ -77,31 +84,49 @@ public bool IsDisposed private byte _isInitialized; private byte _isDisposed; + /// Indicates whether the patch input is a directory. public byte IsInputDir; + /// Indicates whether the patch output is a directory. public byte IsOutputDir; + /// Points to input-path count and size information. public EntryCountSizeInfo* InputPathCountSizeInfoP; + /// Points to output-path count and size information. public EntryCountSizeInfo* OutputPathCountSizeInfoP; + /// Points to unchanged-path count and size information. public EntryCountSizeInfo* SameFilePathCountSizeInfoP; + /// Points to mappings between unchanged input and output paths. public FileIndexPair* SameFilePathIndexPairP; + /// Points to the input path list. public UnmanagedArray* InputPathListP; + /// Points to the output path list. public UnmanagedArray* OutputPathListP; + /// Points to indexes of referenced input files. public UnmanagedArray* InputFileIndexListP; + /// Points to sizes of referenced input files, when present. public UnmanagedArray* InputFileSizeListP; + /// Points to indexes of referenced output files. public UnmanagedArray* OutputFileIndexListP; + /// Points to sizes of referenced output files. public UnmanagedArray* OutputFileSizeListP; + /// Points to hashes of referenced output files, when present. public UnmanagedArray* OutputFileHashesListP; // Seems unused. // TODO: See original code to see what it is. + /// Points to external-data size information. public ExternSizeInfo* ExternSizeInfoP; // File Reference Chunk Info, including: // - Filename string chunks // - Checksum chunks + /// Points to directory header-data size information. public ChunkSizeInfo* HeadDataSizeP; + /// Points to the embedded single-file patch metadata. public PatchMetadata* PatchMetadataP; + /// Points to the directory-patch checksum data. public ChecksumDataInfo* ChecksumDataInfoP; + /// Points to indexes of output entries that should be executable. public UnmanagedArray* NewExecuteListP; -} \ No newline at end of file +} diff --git a/SharpHPatchZ/Header/Metadata/EntryCountSizeInfo.cs b/SharpHPatchZ/Header/Metadata/EntryCountSizeInfo.cs index 3b862e1..2dc1b48 100644 --- a/SharpHPatchZ/Header/Metadata/EntryCountSizeInfo.cs +++ b/SharpHPatchZ/Header/Metadata/EntryCountSizeInfo.cs @@ -2,9 +2,12 @@ namespace SharpHPatchZ.Header.Metadata; +/// Stores the number and total byte size of a group of patch entries. [StructLayout(LayoutKind.Sequential)] public struct EntryCountSizeInfo { + /// The number of entries. public int Count; + /// The total size of the entries, in bytes. public long Size; -} \ No newline at end of file +} diff --git a/SharpHPatchZ/Header/Metadata/ExternSizeInfo.cs b/SharpHPatchZ/Header/Metadata/ExternSizeInfo.cs index 1b778e3..91badf6 100644 --- a/SharpHPatchZ/Header/Metadata/ExternSizeInfo.cs +++ b/SharpHPatchZ/Header/Metadata/ExternSizeInfo.cs @@ -2,11 +2,16 @@ namespace SharpHPatchZ.Header.Metadata; +/// Stores size information for executable and external directory-patch data. [StructLayout(LayoutKind.Sequential)] public struct ExternSizeInfo { + /// The number of new executable entries. public int NewExecuteCount; + /// The size of the private reserved data, in bytes. public long PrivateReservedDataSize; + /// The size of the private external data, in bytes. public long PrivateExternDataSize; + /// The size of the external data, in bytes. public long ExternDataSize; } diff --git a/SharpHPatchZ/Header/Metadata/FileIndexPair.cs b/SharpHPatchZ/Header/Metadata/FileIndexPair.cs index b8f9fc5..8737523 100644 --- a/SharpHPatchZ/Header/Metadata/FileIndexPair.cs +++ b/SharpHPatchZ/Header/Metadata/FileIndexPair.cs @@ -2,11 +2,15 @@ namespace SharpHPatchZ.Header.Metadata; +/// Maps an input-file index to its corresponding output-file index. [StructLayout(LayoutKind.Sequential)] public struct FileIndexPair { + /// The input-file index. public int OldIndex; + /// The output-file index. public int NewIndex; + /// public override string ToString() => $"Old: {OldIndex} - New: {NewIndex}"; } diff --git a/SharpHPatchZ/Header/Metadata/IMetadataInit.cs b/SharpHPatchZ/Header/Metadata/IMetadataInit.cs index 0e5a959..b68b595 100644 --- a/SharpHPatchZ/Header/Metadata/IMetadataInit.cs +++ b/SharpHPatchZ/Header/Metadata/IMetadataInit.cs @@ -2,11 +2,16 @@ namespace SharpHPatchZ.Header.Metadata; +/// Defines lifecycle information and initialization for unmanaged patch metadata. public interface IMetadataInit : IDisposable { + /// Gets the discriminator for this metadata type. public MetadataTypeConst MetadataType { get; } + /// Gets whether the metadata has been initialized. public bool IsInitialized { get; } + /// Gets whether the metadata has been disposed. public bool IsDisposed { get; } + /// Initializes the metadata and any resources it owns. void Init(); } diff --git a/SharpHPatchZ/Header/Metadata/MetadataTypeConst.cs b/SharpHPatchZ/Header/Metadata/MetadataTypeConst.cs index 85ce765..7036837 100644 --- a/SharpHPatchZ/Header/Metadata/MetadataTypeConst.cs +++ b/SharpHPatchZ/Header/Metadata/MetadataTypeConst.cs @@ -2,14 +2,21 @@ namespace SharpHPatchZ.Header.Metadata; +/// Identifies the concrete kind of unmanaged patch metadata. [Flags] public enum MetadataTypeConst : short { + /// Mask applied to values that identify metadata. IsMetadataType = unchecked((short)0b_10000000_10000000), + /// Identifies . PatchMetadataType = IsMetadataType | 0b_01000000_00000000, + /// Identifies . DirectoryPatchMetadataType = IsMetadataType | 0b_00100000_00000000, + /// Identifies . ChecksumDataInfoType = IsMetadataType | 0b_00010000_00000000, + /// Identifies . UnmanagedArrayType = IsMetadataType | 0b_00001000_00000000, + /// Identifies . Utf16UnmanagedStringType = IsMetadataType | 0b_00000100_00000000 } diff --git a/SharpHPatchZ/Header/Metadata/PatchMetadata.cs b/SharpHPatchZ/Header/Metadata/PatchMetadata.cs index 2b92ce1..c72e025 100644 --- a/SharpHPatchZ/Header/Metadata/PatchMetadata.cs +++ b/SharpHPatchZ/Header/Metadata/PatchMetadata.cs @@ -3,14 +3,17 @@ namespace SharpHPatchZ.Header.Metadata; +/// Contains the size and offset metadata required to apply a single-file patch. [StructLayout(LayoutKind.Sequential)] public unsafe struct PatchMetadata : IMetadataInit { + /// Initializes a new and its records. public PatchMetadata() { Init(); } + /// public void Init() { if (IsDisposed || IsInitialized) @@ -27,6 +30,7 @@ public void Init() NewDiffDataSizeP = MemoryAlloc.Alloc(1, true); } + /// public void Dispose() { if (IsDisposed || !IsInitialized) @@ -46,14 +50,17 @@ public void Dispose() NewDiffDataSizeP = null; } + /// public MetadataTypeConst MetadataType { get; private set; } + /// public bool IsInitialized { get => _isInitialized == 1; private set => _isInitialized = value ? (byte)1 : (byte)0; } + /// public bool IsDisposed { get => _isDisposed == 1; @@ -63,14 +70,22 @@ public bool IsDisposed private byte _isInitialized; private byte _isDisposed; + /// The expected output size, in bytes. public long DiffNewSize; + /// The expected input size, in bytes. public long DiffOldSize; + /// The byte offset at which patch data begins. public long DiffDataOffset; + /// The number of cover-data entries in the patch. public int CoverDataCount; + /// Points to the cover-data size record. public ChunkSizeInfo* CoverDataSizeP; + /// Points to the RLE control-data size record. public ChunkSizeInfo* RleControlDataSizeP; + /// Points to the RLE code-data size record. public ChunkSizeInfo* RleCodeDataSizeP; + /// Points to the new-difference-data size record. public ChunkSizeInfo* NewDiffDataSizeP; } diff --git a/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs b/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs index 4630dcb..2927810 100644 --- a/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs +++ b/SharpHPatchZ/Header/Metadata/UnmanagedArray.cs @@ -5,15 +5,19 @@ namespace SharpHPatchZ.Header.Metadata; +/// Owns a contiguous unmanaged array of values. +/// The unmanaged element type. [StructLayout(LayoutKind.Sequential)] public unsafe struct UnmanagedArray : IMetadataInit where T : unmanaged { + /// Initializes a new empty . public UnmanagedArray() { Init(); } + /// public void Init() { if (IsDisposed || IsInitialized) @@ -27,6 +31,7 @@ public void Init() MetadataType = MetadataTypeConst.UnmanagedArrayType; } + /// public void Dispose() { if (IsDisposed || !IsInitialized || Data == null) @@ -57,14 +62,17 @@ public void Dispose() MemoryAlloc.Free(oldData); } + /// public MetadataTypeConst MetadataType { get; private set; } + /// public bool IsInitialized { get => _isInitialized == 1; private set => _isInitialized = value ? (byte)1 : (byte)0; } + /// public bool IsDisposed { get => _isDisposed == 1; @@ -74,12 +82,19 @@ public bool IsDisposed private byte _isInitialized; private byte _isDisposed; + /// The number of elements in the array. public int Length; + /// The size of each element, in bytes. public int TypeSize; + /// Points to the first element in the unmanaged allocation. public T* Data; internal Span GetSpan() => Data == null ? Span.Empty : new Span(Data, Length); + /// Allocates an unmanaged array descriptor and its element storage. + /// The number of elements to allocate. + /// Whether to zero-initialize the element storage. + /// A pointer to the allocated array descriptor. public static UnmanagedArray* CreateAllocUnsafe(int count, bool initialize = false) { UnmanagedArray* alloc = MemoryAlloc.Alloc>(); @@ -90,6 +105,10 @@ public bool IsDisposed return alloc; } + /// Creates an array value backed by newly allocated unmanaged storage. + /// The number of elements to allocate. + /// Whether to zero-initialize the element storage. + /// The initialized . public static UnmanagedArray CreateAlloc(int count, bool initialize = false) { var array = new UnmanagedArray @@ -104,6 +123,10 @@ public static UnmanagedArray CreateAlloc(int count, bool initialize = false) public static implicit operator Span(UnmanagedArray unmanagedSpan) => unmanagedSpan.GetSpan(); + /// Gets a reference to the element at the specified index. + /// The zero-based element index. + /// A reference to the requested element. + /// is outside the array bounds. public ref T this[int index] { get diff --git a/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs b/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs index e1291af..3b6cb7d 100644 --- a/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs +++ b/SharpHPatchZ/Header/Metadata/Utf16UnmanagedString.cs @@ -7,14 +7,17 @@ namespace SharpHPatchZ.Header.Metadata; +/// Owns a UTF-16 string stored in unmanaged memory. [StructLayout(LayoutKind.Sequential)] public unsafe struct Utf16UnmanagedString : IMetadataInit { + /// Initializes a new empty . public Utf16UnmanagedString() { Init(); } + /// public void Init() { if (IsDisposed || IsInitialized) @@ -27,6 +30,7 @@ public void Init() MetadataType = MetadataTypeConst.Utf16UnmanagedStringType; } + /// public void Dispose() { if (IsDisposed || !IsInitialized || Native is { Chars: 0, Length: 0 }) @@ -42,14 +46,17 @@ public void Dispose() MemoryAlloc.Free((char*)old.Chars); } + /// public MetadataTypeConst MetadataType { get; private set; } + /// public bool IsInitialized { get => _isInitialized == 1; private set => _isInitialized = value ? (byte)1 : (byte)0; } + /// public bool IsDisposed { get => _isDisposed == 1; @@ -58,8 +65,12 @@ public bool IsDisposed private byte _isInitialized; private byte _isDisposed; + /// The native string pointer and length. public NativeStringW Native; + /// Creates an unmanaged UTF-16 string from UTF-8 bytes. + /// The UTF-8 bytes to convert. + /// A newly allocated . #if NET6_0_OR_GREATER [SkipLocalsInit] #endif @@ -81,6 +92,9 @@ public static Utf16UnmanagedString CreateFromManaged(ReadOnlySpan source) } } + /// Creates an unmanaged UTF-16 string from managed characters. + /// The characters to copy. + /// A newly allocated . #if NET6_0_OR_GREATER [SkipLocalsInit] #endif @@ -99,6 +113,8 @@ public static Utf16UnmanagedString CreateFromManaged(scoped ReadOnlySpan s return thisStruct; } + /// Gets a over the string's characters. + /// A over the unmanaged UTF-16 characters. public ReadOnlySpan GetSpan() => Native.GetSpan(); public static implicit operator ReadOnlySpan(Utf16UnmanagedString unmanaged) @@ -109,6 +125,7 @@ public static implicit operator string(Utf16UnmanagedString unmanaged) ? "" : unmanaged.Native.ToString(); + /// public override string ToString() => Native.ToString(); private static Utf16UnmanagedString TransformUtf8ToUnicode( @@ -132,17 +149,24 @@ private static Utf16UnmanagedString TransformUtf8ToUnicode( } } + /// Represents a non-owning pointer and length for a UTF-16 string. + /// A pointer to the UTF-16 characters. + /// The number of characters. [StructLayout(LayoutKind.Sequential)] public readonly struct NativeStringW(char* chars, int length) { + /// Gets an empty . public static NativeStringW Empty => default; + /// The address of the first UTF-16 character. public readonly nint Chars = (nint)chars; + /// The number of UTF-16 characters. public readonly int Length = length; public static implicit operator ReadOnlySpan(NativeStringW unmanaged) => new((char*)unmanaged.Chars, unmanaged.Length); + /// public override string ToString() => new((char*)Chars, 0, Length); public static implicit operator string(NativeStringW unmanaged) @@ -150,6 +174,8 @@ public static implicit operator string(NativeStringW unmanaged) ? "" : unmanaged.ToString(); + /// Gets a over the native characters. + /// A over the native characters. public ReadOnlySpan GetSpan() => this; } } diff --git a/SharpHPatchZ/IO/Compression/BZip2/BZip2Constants.cs b/SharpHPatchZ/IO/Compression/BZip2/BZip2Constants.cs index 7e746b6..734e8ba 100644 --- a/SharpHPatchZ/IO/Compression/BZip2/BZip2Constants.cs +++ b/SharpHPatchZ/IO/Compression/BZip2/BZip2Constants.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace SharpHPatchZ.IO.Compression.BZip2; diff --git a/SharpHPatchZ/IO/Compression/BZip2/BZip2Crc32.cs b/SharpHPatchZ/IO/Compression/BZip2/BZip2Crc32.cs index 151166d..21ea110 100644 --- a/SharpHPatchZ/IO/Compression/BZip2/BZip2Crc32.cs +++ b/SharpHPatchZ/IO/Compression/BZip2/BZip2Crc32.cs @@ -371,10 +371,12 @@ internal static uint UpdateByte(uint crc, byte value) } } +/// Computes the big-endian CRC-32 variant used by BZip2 streams. public sealed class BZip2Crc32 : NonCryptographicHashAlgorithm { private uint _crc = BZip2Crc32Premul.InitialState; + /// Initializes a new . public BZip2Crc32() : base(BZip2Crc32Premul.HashSize) { @@ -386,22 +388,32 @@ private BZip2Crc32(uint crc) _crc = crc; } + /// Creates a copy with the same accumulated CRC state. + /// A new accumulator containing the current state. public BZip2Crc32 Clone() => new(_crc); + /// Appends a single byte to the CRC calculation. + /// The to append. public void AppendByte(byte value) => _crc = BZip2Crc32Premul.UpdateByte(_crc, value); + /// public override void Append(ReadOnlySpan source) => _crc = Update(_crc, source); + /// public override void Reset() => _crc = BZip2Crc32Premul.InitialState; + /// protected override void GetCurrentHashCore(Span destination) => BinaryPrimitives.WriteUInt32BigEndian(destination, ~_crc); + /// protected override void GetHashAndResetCore(Span destination) { BinaryPrimitives.WriteUInt32BigEndian(destination, ~_crc); _crc = BZip2Crc32Premul.InitialState; } + /// Gets the current CRC as an unsigned 32-bit integer without resetting the accumulator. + /// The current CRC value. public uint GetCurrentHashAsUInt32() => ~_crc; private static uint Update(uint crc, ReadOnlySpan source) @@ -418,4 +430,4 @@ private static uint Update(uint crc, ReadOnlySpan source) return BZip2Crc32Premul.UpdateSlicingBy8(crc, source); } -} \ No newline at end of file +} diff --git a/SharpHPatchZ/IO/Compression/BZip2/BZip2InputStream.cs b/SharpHPatchZ/IO/Compression/BZip2/BZip2InputStream.cs index 85aa82c..83fdad5 100644 --- a/SharpHPatchZ/IO/Compression/BZip2/BZip2InputStream.cs +++ b/SharpHPatchZ/IO/Compression/BZip2/BZip2InputStream.cs @@ -88,6 +88,10 @@ private static long TryGetStreamLength(Stream stream) } } + /// Initializes a new . + /// The containing BZip2-compressed data. + /// Whether to decompress concatenated BZip2 streams. + /// Whether to leave open when this stream is disposed. public BZip2InputStream(Stream stream, bool decompressConcatenated, bool leaveOpen = false) { if (stream == null!) @@ -135,6 +139,7 @@ streamLength is > 0 and < InputBufferSize } } + /// protected override void Dispose(bool disposing) { if (_disposed) @@ -168,29 +173,41 @@ private void ReturnPooledBuffers() if (_seqToUnseq.Length != 0) ArrayPool.Shared.Return(_seqToUnseq); } + /// Gets or sets whether this instance may dispose the underlying . public bool IsStreamOwner { get; set; } = true; + /// public override bool CanRead => _baseStream.CanRead; + /// public override bool CanSeek => false; + /// public override bool CanWrite => false; + /// public override long Length => _baseStream.Length; + /// public override long Position { get => throw new NotSupportedException("Cannot get the position of the compressed data"); set => throw new NotSupportedException("BZip2InputStream position cannot be set"); } + /// public override void Flush() => _baseStream.Flush(); + /// public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException("BZip2InputStream Seek not supported"); + /// public override void SetLength(long value) => throw new NotSupportedException("BZip2InputStream SetLength not supported"); + /// public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException("BZip2InputStream Write not supported"); + /// public override void WriteByte(byte value) => throw new NotSupportedException("BZip2InputStream WriteByte not supported"); + /// public override int Read(byte[] buffer, int offset, int count) { if (buffer == null) @@ -209,6 +226,7 @@ public override int Read(byte[] buffer, int offset, int count) } #if NET6_0_OR_GREATER + /// public override int Read(Span buffer) => ReadCore(buffer); #endif @@ -274,6 +292,7 @@ private int ReadCore(Span destination) return written; } + /// public override int ReadByte() { if (_streamEnd) @@ -1318,4 +1337,4 @@ private void HbCreateDecodeTables( [MethodImpl(MethodImplOptions.NoInlining)] private static void DataError() => throw new BZip2Exception("Bzip data error"); -} \ No newline at end of file +} diff --git a/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs b/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs index 7e7bfdc..340cf8b 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LZ/LzOutWindow.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Buffers; using System.IO; using System.Runtime.CompilerServices; diff --git a/SharpHPatchZ/IO/Compression/Lzma/LzmaBase.cs b/SharpHPatchZ/IO/Compression/Lzma/LzmaBase.cs index 972676b..21885fa 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LzmaBase.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LzmaBase.cs @@ -1,4 +1,4 @@ -namespace SharpHPatchZ.IO.Compression.Lzma; +namespace SharpHPatchZ.IO.Compression.Lzma; internal abstract class Base { diff --git a/SharpHPatchZ/IO/Compression/Lzma/LzmaDecoder.cs b/SharpHPatchZ/IO/Compression/Lzma/LzmaDecoder.cs index 505577f..6572f83 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LzmaDecoder.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LzmaDecoder.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Buffers; using System.Runtime.CompilerServices; using SharpHPatchZ.IO.Compression.Lzma.LZ; diff --git a/SharpHPatchZ/IO/Compression/Lzma/LzmaExceptions.cs b/SharpHPatchZ/IO/Compression/Lzma/LzmaExceptions.cs index e17a855..fc87f87 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LzmaExceptions.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LzmaExceptions.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace SharpHPatchZ.IO.Compression.Lzma; diff --git a/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs b/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs index 1116f2d..ab75a4a 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/LzmaInputStream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Buffers.Binary; using System.IO; using SharpHPatchZ.IO.Compression.Lzma.LZ; @@ -6,6 +6,7 @@ namespace SharpHPatchZ.IO.Compression.Lzma; +/// Provides a forward-only that decompresses LZMA or LZMA2 data while it is read. public sealed class LzmaInputStream : Stream { private readonly Stream _inputStream; @@ -32,15 +33,38 @@ public sealed class LzmaInputStream : Stream private bool _needProps = true; private bool _isDisposed; + /// Initializes a new whose compressed and decompressed sizes are unknown. + /// The LZMA or LZMA2 property bytes. + /// The containing compressed data. + /// Whether to leave open when this stream is disposed. public LzmaInputStream(byte[] properties, Stream inputStream, bool leaveOpen = false) : this(properties, inputStream, -1, -1, null, properties.Length < 5, leaveOpen) { } + /// Initializes a new with a known compressed size. + /// The LZMA or LZMA2 property bytes. + /// The containing compressed data. + /// The compressed data size, in bytes. + /// Whether to leave open when this stream is disposed. public LzmaInputStream(byte[] properties, Stream inputStream, long inputSize, bool leaveOpen = false) : this(properties, inputStream, inputSize, -1, null, properties.Length < 5, leaveOpen) { } + /// Initializes a new with known compressed and decompressed sizes. + /// The LZMA or LZMA2 property bytes. + /// The containing compressed data. + /// The compressed data size, in bytes. + /// The decompressed data size, in bytes. + /// Whether to leave open when this stream is disposed. public LzmaInputStream(byte[] properties, Stream inputStream, long inputSize, long outputSize, bool leaveOpen = false) : this(properties, inputStream, inputSize, outputSize, null, properties.Length < 5, leaveOpen) { } + /// Initializes a new with explicit format and dictionary settings. + /// The decoder property bytes. + /// The containing compressed data. + /// The compressed data size, in bytes, or a negative value when unknown. + /// The decompressed data size, in bytes, or a negative value when unknown. + /// An optional preset dictionary . + /// Whether the compressed data uses the LZMA2 container format. + /// Whether to leave open when this stream is disposed. public LzmaInputStream( byte[] properties, Stream inputStream, @@ -91,14 +115,19 @@ public LzmaInputStream( } } + /// public override bool CanRead => true; + /// public override bool CanSeek => false; + /// public override bool CanWrite => false; + /// public override void Flush() { } + /// protected override void Dispose(bool disposing) { if (_isDisposed) @@ -118,14 +147,17 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } + /// public override long Length => _position + _availableBytes; + /// public override long Position { get => _position; set => throw new NotSupportedException(); } + /// public override int Read(byte[] buffer, int offset, int count) { if (_endReached) @@ -277,11 +309,15 @@ private void DecodeChunkHeader() } } + /// public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); + /// public override void SetLength(long value) => throw new NotSupportedException(); + /// public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); + /// Gets the decoder property bytes used by this stream. public byte[] Properties { get; } -} \ No newline at end of file +} diff --git a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs index c203b02..8fdbfbf 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoder.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Buffers; using System.IO; using System.Runtime.CompilerServices; diff --git a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs index 0d2bdc0..2669635 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBit.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.CompilerServices; namespace SharpHPatchZ.IO.Compression.Lzma.RangeCoder; diff --git a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs index f8ec21e..42c25a6 100644 --- a/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs +++ b/SharpHPatchZ/IO/Compression/Lzma/RangeCoder/RangeCoderBitTree.cs @@ -1,4 +1,4 @@ -using System.Runtime.CompilerServices; +using System.Runtime.CompilerServices; namespace SharpHPatchZ.IO.Compression.Lzma.RangeCoder; diff --git a/SharpHPatchZ/IO/RandomAccessCompat.cs b/SharpHPatchZ/IO/RandomAccessCompat.cs index 514ad6c..1960d59 100644 --- a/SharpHPatchZ/IO/RandomAccessCompat.cs +++ b/SharpHPatchZ/IO/RandomAccessCompat.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using Microsoft.Win32.SafeHandles; diff --git a/SharpHPatchZ/IO/Reader/DecompressionTransitionStream.cs b/SharpHPatchZ/IO/Reader/DecompressionTransitionStream.cs index 55cc880..34a53cb 100644 --- a/SharpHPatchZ/IO/Reader/DecompressionTransitionStream.cs +++ b/SharpHPatchZ/IO/Reader/DecompressionTransitionStream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Buffers; using System.IO; using System.Threading; diff --git a/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs b/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs index b0e721a..6806849 100644 --- a/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs +++ b/SharpHPatchZ/IO/Reader/PrefetchedReadStream.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.IO; using System.Runtime.ExceptionServices; diff --git a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs index 0c045c0..440d7e2 100644 --- a/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs +++ b/SharpHPatchZ/Patch/HDiff13DerivedPatcher.CorePatcher.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; From c5f9965ada2e45d6b7eaec093c891deef32c1822 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Mon, 31 Aug 2026 20:37:01 +0700 Subject: [PATCH 70/72] Avoid double dispose on RandomMergedStreamWrapper --- SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs b/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs index 891f7b2..48b6435 100644 --- a/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs +++ b/SharpHPatchZ/IO/Reader/RandomMergedStreamWrapper.cs @@ -138,17 +138,14 @@ public int Read(Span buffer, long offset) public void Dispose() { - if (Volatile.Read(ref _disposed) != 0) + if (Interlocked.Exchange(ref _disposed, 1) == 1) + { return; + } _lifetimeLock.EnterWriteLock(); try { - if (Interlocked.Exchange(ref _disposed, 1) == 1) - { - return; - } - foreach (KeyValuePair> kvp in _fileStreams) { if (kvp.Value.IsValueCreated) From 4ffcf1d5995fa1603a16b8f462ec00f0483c3a1d Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Wed, 2 Sep 2026 01:54:58 +0700 Subject: [PATCH 71/72] Update README and use built-in Zstd decompression stream on .NET 11 --- README.md | 23 +++++++++++--- .../IO/Compression/CompressionStreamHelper.cs | 31 +++++++++++++------ SharpHPatchZ/SharpHPatchZ.csproj | 4 +-- 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 1c14b88..4da281c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# SharpHDiffPatch +# SharpHPatchZ [![NuGet Downloads](https://img.shields.io/nuget/dt/SharpHDiffPatch.Core.svg?style=flat-square)](https://www.nuget.org/packages/SharpHDiffPatch.Core/) [![NuGet version](https://img.shields.io/nuget/v/SharpHDiffPatch.Core.svg?style=flat-square)](https://www.nuget.org/packages/SharpHDiffPatch.Core/) @@ -12,9 +12,24 @@ Supporting file and directory patching with these compression formats: - LZMA2 - No Compression. -HDIFFSF20 format is planned to be supported later v3.0 releases. +HDIFFSF20 and HDIFFW26 format is planned to be supported in later v3.0 releases. -This project is used as a part submodule of our main project: [**Collapse Launcher**](https://github.com/CollapseLauncher). +This project is used as a part of a submodule, widely used within our main project: [**Collapse Launcher**](https://github.com/CollapseLauncher) and [**Hi3Helper.Sophon**](https://github.com/CollapseLauncher/Hi3Helper.Sophon). + +# Supported Target Frameworks +Currently, SharpHPatchZ supports for a broad .NET Target Frameworks (TFM) and .NET Standard 2.0 compatible frameworks below: + +| TFM | Version | +|-----|-------| +| .NET Framework | 4.6.1 or above [1][2] | +| .NET Core | 6 or above [3] | +| Mono | 5.4 or above, 6.4 or above (Untested) [1][2] | +| Unity | 2018.1 or above (Untested) [1][2] | + +### Sidenotes: +- **[1]** SIMD-based RLE Addition is not supported +- **[2]** ZStandard decompression uses managed-port instead. This applies for any **non .NET Core TFMs** and **any platform other than:** **Linux x64/arm64** and **Windows x64/arm64**. +- **[3]** For .NET 11 or above, the built-in ZStandard decompression stream will be used instead. This should be supported for any platform (including Android, Windows, Linux, macOS, iOS, etc.) # Usage Examples ## A. Basic Patching Usage with Progress Output @@ -321,7 +336,7 @@ _Thanks to @Cryotechnic for the initial implementaion on the V2 codebase._ ### For Kuro Games developer: -_I think it's better for you to make a different signature magic (for example: `HDiff19Kuro` or something) instead of just adding an arbitrary structs inside of the file so it's easier for us to automatically parse your format. Also, don't forget to ask the permission to the original developer of the format (housisong) that you slightly changed their format for your own purposes (**And... don't forget to give them a credit on your launcher license file or something**)_😉 +*I think it's better for you to make a different signature magic (for example: `HDiff19Kuro` or something) instead of just adding an arbitrary structs inside of the file so it's easier for us to automatically parse your format. Also, don't forget to ask the permission to the original developer of the format (housisong) that you slightly changed their format for your own purposes (**And... don't forget to give them a credit on your launcher license file or something**)* 😉 ~ @neon-nyan diff --git a/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs b/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs index 69198b8..6947eaa 100644 --- a/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs +++ b/SharpHPatchZ/IO/Compression/CompressionStreamHelper.cs @@ -3,23 +3,26 @@ // ReSharper disable CommentTypo // ReSharper disable InconsistentNaming -#if NET6_0_OR_GREATER +#if NET6_0_OR_GREATER && !NET11_0_OR_GREATER using System.Collections.Generic; using ZstdNet; #endif -using System; -using System.IO; -using System.IO.Compression; using SharpHPatchZ.Extension; using SharpHPatchZ.Header; using SharpHPatchZ.IO.Compression.BZip2; using SharpHPatchZ.IO.Compression.Lzma; +using System; +using System.IO; +using System.IO.Compression; + +#if !NET11_0_OR_GREATER using ZstdManagedDecompressor = ZstdSharp.Decompressor; using ZstdManagedDecompressorParameter = ZstdSharp.Unsafe.ZSTD_dParameter; using ZstdManagedStream = ZstdSharp.DecompressionStream; +#endif -#if NET6_0_OR_GREATER +#if NET6_0_OR_GREATER && !NET11_0_OR_GREATER using ZstdNativeDecompressor = ZstdNet.DecompressionOptions; using ZstdNativeDecompressorParameter = ZstdNet.ZSTD_dParameter; using ZstdNativeStream = ZstdNet.DecompressionStream; @@ -86,37 +89,47 @@ private static Stream CreateZstdStream(Stream rawStream, bool leaveOpen) { if (_createZstdStreamFallback != null) return _createZstdStreamFallback(rawStream, leaveOpen); -#if NET6_0_OR_GREATER +#if NET6_0_OR_GREATER && !NET11_0_OR_GREATER if (DllUtils.IsLibraryExist(DllUtils.DllName)) _createZstdStreamFallback = CreateZstdNativeStream; else _createZstdStreamFallback = CreateZstdManagedStream; +#elif NET11_0_OR_GREATER + _createZstdStreamFallback = CreateZstdNativeStream; #else - _createZstdStreamFallback = CreateZstdManagedStream; + _createZstdStreamFallback = CreateZstdManagedStream; #endif return _createZstdStreamFallback(rawStream, leaveOpen); } /* HACK: The default window log max size is 30. This is unacceptable since the native HPatch implementation * always use 31 as the size_t, which is 8 bytes length. - * + * * Code Snippets (decompress_plugin_demo.h:963): * #define _ZSTD_WINDOWLOG_MAX ((sizeof(size_t)<=4)?30:31) */ -#if NET6_0_OR_GREATER +#if NET6_0_OR_GREATER && !NET11_0_OR_GREATER private static Stream CreateZstdNativeStream(Stream rawStream, bool leaveOpen) => new ZstdNativeStream(rawStream, new ZstdNativeDecompressor(null, new Dictionary { { ZstdNativeDecompressorParameter.ZSTD_d_windowLogMax, ZstdWindowLogMax } }), 0, leaveOpen); +#elif NET11_0_OR_GREATER + private static Stream CreateZstdNativeStream(Stream rawStream, bool leaveOpen) => + new ZstandardStream(rawStream, new ZstandardDecompressionOptions + { + MaxWindowLog2 = ZstdWindowLogMax + }, leaveOpen); #endif +#if !NET11_0_OR_GREATER private static Stream CreateZstdManagedStream(Stream rawStream, bool leaveOpen) { ZstdManagedDecompressor decompressor = new(); decompressor.SetParameter(ZstdManagedDecompressorParameter.ZSTD_d_windowLogMax, ZstdWindowLogMax); return new ZstdManagedStream(rawStream, decompressor, 16 << 10, leaveOpen: leaveOpen); } +#endif private static Stream CreateLzmaStream( HDiffCompression type, diff --git a/SharpHPatchZ/SharpHPatchZ.csproj b/SharpHPatchZ/SharpHPatchZ.csproj index 59c8481..87d85a6 100644 --- a/SharpHPatchZ/SharpHPatchZ.csproj +++ b/SharpHPatchZ/SharpHPatchZ.csproj @@ -31,10 +31,10 @@ - + - + From 0b61fa1ae1aa4886cc6339c90c9ebdc2da7b0586 Mon Sep 17 00:00:00 2001 From: Kemal Setya Adhi Date: Wed, 2 Sep 2026 01:56:45 +0700 Subject: [PATCH 72/72] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4da281c..e33f389 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Currently, SharpHPatchZ supports for a broad .NET Target Frameworks (TFM) and .N ### Sidenotes: - **[1]** SIMD-based RLE Addition is not supported - **[2]** ZStandard decompression uses managed-port instead. This applies for any **non .NET Core TFMs** and **any platform other than:** **Linux x64/arm64** and **Windows x64/arm64**. -- **[3]** For .NET 11 or above, the built-in ZStandard decompression stream will be used instead. This should be supported for any platform (including Android, Windows, Linux, macOS, iOS, etc.) +- **[3]** For .NET 11 or above, the built-in `ZstandardStream` will be used for decompression instead. This should be supported for any platform (including Android, Windows, Linux, macOS, iOS, etc.) # Usage Examples ## A. Basic Patching Usage with Progress Output