From 456a7dfd588da6d5856ca54d8978e56db253bd64 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 1 Apr 2026 13:12:49 +0000 Subject: [PATCH] Revert default buffer to 80KB; add ZStandard minimumRewindBufferSize (DStreamInSize=131075) Agent-Logs-Url: https://github.com/adamhathcock/sharpcompress/sessions/d5a696df-2906-4262-acf9-06cc174e91fc Co-authored-by: adamhathcock <527620+adamhathcock@users.noreply.github.com> --- src/SharpCompress/Common/Constants.cs | 10 ++++++---- .../Compressors/ZStandard/ZstandardConstants.cs | 13 +++++++++++++ src/SharpCompress/Factories/TarWrapper.cs | 6 +++++- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/SharpCompress/Common/Constants.cs b/src/SharpCompress/Common/Constants.cs index 9812501d..edd81e08 100644 --- a/src/SharpCompress/Common/Constants.cs +++ b/src/SharpCompress/Common/Constants.cs @@ -22,9 +22,11 @@ public static class Constants /// by rewinding and re-reading the same data. /// /// - /// Default: 163840 bytes (160KB) - sized to cover ZStandard's worst-case - /// first block on a tar archive (~131KB including frame header overhead). - /// ZStandard blocks can be up to 128KB, exceeding the previous 81KB default. + /// Default: 81920 bytes (80KB) — sufficient for most formats. + /// Formats that require larger buffers (e.g. BZip2, ZStandard) declare their + /// own minimum via TarWrapper.MinimumRewindBufferSize, and + /// TarWrapper.MaximumRewindBufferSize is used at stream construction + /// to ensure the correct capacity is allocated upfront. /// /// /// Typical usage: 500-1000 bytes for most archives @@ -41,7 +43,7 @@ public static class Constants /// /// /// - public static int RewindableBufferSize { get; set; } = 163840; + public static int RewindableBufferSize { get; set; } = 81920; public static CultureInfo DefaultCultureInfo { get; set; } = CultureInfo.InvariantCulture; } diff --git a/src/SharpCompress/Compressors/ZStandard/ZstandardConstants.cs b/src/SharpCompress/Compressors/ZStandard/ZstandardConstants.cs index ac4756d4..a43b2ef1 100644 --- a/src/SharpCompress/Compressors/ZStandard/ZstandardConstants.cs +++ b/src/SharpCompress/Compressors/ZStandard/ZstandardConstants.cs @@ -6,4 +6,17 @@ internal class ZstandardConstants /// Magic number found at start of ZStandard frame: 0xFD 0x2F 0xB5 0x28 /// public const uint MAGIC = 0xFD2FB528; + + /// + /// Maximum uncompressed size of a single ZStandard block: ZSTD_BLOCKSIZE_MAX = 128 KB. + /// + public const int BlockSizeMax = 1 << 17; // 131072 bytes + + /// + /// Recommended input (compressed) buffer size for streaming decompression: + /// ZSTD_DStreamInSize = ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize (3 bytes). + /// The ring buffer must be at least this large to hold the compressed bytes read + /// during format detection before the first rewind. + /// + public const int DStreamInSize = BlockSizeMax + 3; } diff --git a/src/SharpCompress/Factories/TarWrapper.cs b/src/SharpCompress/Factories/TarWrapper.cs index 013debaf..465cf836 100644 --- a/src/SharpCompress/Factories/TarWrapper.cs +++ b/src/SharpCompress/Factories/TarWrapper.cs @@ -88,7 +88,11 @@ public class TarWrapper( ZStandardStream.IsZStandardAsync, (stream) => new ZStandardStream(stream), (stream, _) => new ValueTask(new ZStandardStream(stream)), - ["tar.zst", "tar.zstd", "tzst", "tzstd"] + ["tar.zst", "tar.zstd", "tzst", "tzstd"], + // ZStandard decompresses in blocks; the compressed size of the first block + // can be up to ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize = 131075 bytes. + // The ring buffer must hold all compressed bytes read during format detection. + minimumRewindBufferSize: ZstandardConstants.DStreamInSize ), new( CompressionType.LZip,