From 9c68cfc0c1cc4f9bf18f3d0262efe250a6b1cab1 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Fri, 22 Sep 2023 11:54:48 -0400 Subject: [PATCH] Fix issues found during MSZIP research --- Compression/MSZIP/Block.cs | 41 +++++++++++++++++++ Compression/MSZIP/BlockHeader.cs | 12 ------ Compression/MSZIP/CompressedBlockHeader.cs | 28 +++++++++++++ .../DynamicHuffmanCompressedBlockHeader.cs | 20 +-------- .../FixedHuffmanCompressedBlockHeader.cs | 10 ++--- Compression/MSZIP/RFC1951Block.cs | 24 +++++++++++ 6 files changed, 100 insertions(+), 35 deletions(-) create mode 100644 Compression/MSZIP/Block.cs create mode 100644 Compression/MSZIP/CompressedBlockHeader.cs create mode 100644 Compression/MSZIP/RFC1951Block.cs diff --git a/Compression/MSZIP/Block.cs b/Compression/MSZIP/Block.cs new file mode 100644 index 0000000..3a36f93 --- /dev/null +++ b/Compression/MSZIP/Block.cs @@ -0,0 +1,41 @@ +namespace SabreTools.Models.Compression.MSZIP +{ + /// + /// Each MSZIP block MUST consist of a 2-byte MSZIP signature and one or more RFC 1951 blocks. The + /// 2-byte MSZIP signature MUST consist of the bytes 0x43 and 0x4B. The MSZIP signature MUST be + /// the first 2 bytes in the MSZIP block. The MSZIP signature is shown in the following packet diagram. + /// + /// Each MSZIP block is the result of a single deflate compression operation, as defined in [RFC1951]. + /// The compressor that performs the compression operation MUST generate one or more RFC 1951 + /// blocks, as defined in [RFC1951]. The number, deflation mode, and type of RFC 1951 blocks in each + /// MSZIP block is determined by the compressor, as defined in [RFC1951]. The last RFC 1951 block in + /// each MSZIP block MUST be marked as the "end" of the stream(1), as defined by [RFC1951] + /// section 3.2.3. Decoding trees MUST be discarded after each RFC 1951 block, but the history buffer + /// MUST be maintained.Each MSZIP block MUST represent no more than 32 KB of uncompressed data. + /// + /// The maximum compressed size of each MSZIP block is 32 KB + 12 bytes. This enables the MSZIP + /// block to contain 32 KB of data split between two noncompressed RFC 1951 blocks, each of which + /// has a value of BTYPE = 00. + /// + /// + public class Block + { + /// + /// Block header + /// +#if NET48 + public BlockHeader BlockHeader { get; set; } +#else + public BlockHeader? BlockHeader { get; set; } +#endif + + /// + /// Compressed blocks + /// +#if NET48 + public RFC1951Block CompressedBlocks { get; set; } +#else + public RFC1951Block? CompressedBlocks { get; set; } +#endif + } +} \ No newline at end of file diff --git a/Compression/MSZIP/BlockHeader.cs b/Compression/MSZIP/BlockHeader.cs index 0336aec..657fcbc 100644 --- a/Compression/MSZIP/BlockHeader.cs +++ b/Compression/MSZIP/BlockHeader.cs @@ -4,18 +4,6 @@ namespace SabreTools.Models.Compression.MSZIP /// Each MSZIP block MUST consist of a 2-byte MSZIP signature and one or more RFC 1951 blocks. The /// 2-byte MSZIP signature MUST consist of the bytes 0x43 and 0x4B. The MSZIP signature MUST be /// the first 2 bytes in the MSZIP block. The MSZIP signature is shown in the following packet diagram. - /// - /// Each MSZIP block is the result of a single deflate compression operation, as defined in [RFC1951]. - /// The compressor that performs the compression operation MUST generate one or more RFC 1951 - /// blocks, as defined in [RFC1951]. The number, deflation mode, and type of RFC 1951 blocks in each - /// MSZIP block is determined by the compressor, as defined in [RFC1951]. The last RFC 1951 block in - /// each MSZIP block MUST be marked as the "end" of the stream(1), as defined by [RFC1951] - /// section 3.2.3. Decoding trees MUST be discarded after each RFC 1951 block, but the history buffer - /// MUST be maintained.Each MSZIP block MUST represent no more than 32 KB of uncompressed data. - /// - /// The maximum compressed size of each MSZIP block is 32 KB + 12 bytes. This enables the MSZIP - /// block to contain 32 KB of data split between two noncompressed RFC 1951 blocks, each of which - /// has a value of BTYPE = 00. /// /// public class BlockHeader diff --git a/Compression/MSZIP/CompressedBlockHeader.cs b/Compression/MSZIP/CompressedBlockHeader.cs new file mode 100644 index 0000000..cb1fc6d --- /dev/null +++ b/Compression/MSZIP/CompressedBlockHeader.cs @@ -0,0 +1,28 @@ +namespace SabreTools.Models.Compression.MSZIP +{ + /// + /// Compression with Huffman codes (BTYPE=01 or BTYPE=02) + /// + /// + /// + public abstract class CompressedBlockHeader + { + /// + /// Huffman code lengths for the literal / length alphabet + /// +#if NET48 + public virtual uint[] LiteralLengths { get; set; } +#else + public virtual uint[]? LiteralLengths { get; set; } +#endif + + /// + /// Huffman distance codes for the literal / length alphabet + /// +#if NET48 + public virtual uint[] DistanceCodes { get; set; } +#else + public virtual uint[]? DistanceCodes { get; set; } +#endif + } +} \ No newline at end of file diff --git a/Compression/MSZIP/DynamicHuffmanCompressedBlockHeader.cs b/Compression/MSZIP/DynamicHuffmanCompressedBlockHeader.cs index e398ab0..14c3838 100644 --- a/Compression/MSZIP/DynamicHuffmanCompressedBlockHeader.cs +++ b/Compression/MSZIP/DynamicHuffmanCompressedBlockHeader.cs @@ -4,24 +4,8 @@ namespace SabreTools.Models.Compression.MSZIP /// Compression with dynamic Huffman codes (BTYPE=10) /// /// - public class DynamicHuffmanCompressedBlockHeader + public class DynamicHuffmanCompressedBlockHeader : CompressedBlockHeader { - /// - /// Huffman code lengths for the literal / length alphabet - /// -#if NET48 - public int[] LiteralLengths { get; set; } -#else - public int[]? LiteralLengths { get; set; } -#endif - - /// - /// Huffman distance codes for the literal / length alphabet - /// -#if NET48 - public int[] DistanceCodes { get; set; } -#else - public int[]? DistanceCodes { get; set; } -#endif + // Codes are provided externally } } \ No newline at end of file diff --git a/Compression/MSZIP/FixedHuffmanCompressedBlockHeader.cs b/Compression/MSZIP/FixedHuffmanCompressedBlockHeader.cs index 27b7dc4..69f901d 100644 --- a/Compression/MSZIP/FixedHuffmanCompressedBlockHeader.cs +++ b/Compression/MSZIP/FixedHuffmanCompressedBlockHeader.cs @@ -7,7 +7,7 @@ namespace SabreTools.Models.Compression.MSZIP /// /// /// - public class FixedHuffmanCompressedBlockHeader + public class FixedHuffmanCompressedBlockHeader : CompressedBlockHeader { #region Properties @@ -15,9 +15,9 @@ namespace SabreTools.Models.Compression.MSZIP /// Huffman code lengths for the literal / length alphabet /// #if NET48 - public uint[] LiteralLengths + public override uint[] LiteralLengths #else - public uint[]? LiteralLengths + public override uint[]? LiteralLengths #endif { get @@ -57,9 +57,9 @@ namespace SabreTools.Models.Compression.MSZIP /// Huffman distance codes for the literal / length alphabet /// #if NET48 - public uint[] DistanceCodes + public override uint[] DistanceCodes #else - public uint[]? DistanceCodes + public override uint[]? DistanceCodes #endif { get diff --git a/Compression/MSZIP/RFC1951Block.cs b/Compression/MSZIP/RFC1951Block.cs new file mode 100644 index 0000000..817b618 --- /dev/null +++ b/Compression/MSZIP/RFC1951Block.cs @@ -0,0 +1,24 @@ +namespace SabreTools.Models.Compression.MSZIP +{ + /// + /// Each MSZIP block is the result of a single deflate compression operation, as defined in [RFC1951]. + /// The compressor that performs the compression operation MUST generate one or more RFC 1951 + /// blocks, as defined in [RFC1951]. The number, deflation mode, and type of RFC 1951 blocks in each + /// MSZIP block is determined by the compressor, as defined in [RFC1951]. The last RFC 1951 block in + /// each MSZIP block MUST be marked as the "end" of the stream(1), as defined by [RFC1951] + /// section 3.2.3. Decoding trees MUST be discarded after each RFC 1951 block, but the history buffer + /// MUST be maintained.Each MSZIP block MUST represent no more than 32 KB of uncompressed data. + /// + /// + public class RFC1951Block + { + /// + /// Compressed MSZIP data block + /// +#if NET48 + public byte[] Data { get; set; } +#else + public byte[]? Data { get; set; } +#endif + } +} \ No newline at end of file