Bläddra i källkod

LibCompress: Only require new LZMA2 properties after dictionary reset

Tim Schumacher 2 år sedan
förälder
incheckning
9ccb0fc1d8
2 ändrade filer med 63 tillägg och 3 borttagningar
  1. 59 0
      Tests/LibCompress/TestXz.cpp
  2. 4 3
      Userland/Libraries/LibCompress/Lzma2.cpp

+ 59 - 0
Tests/LibCompress/TestXz.cpp

@@ -9,6 +9,65 @@
 #include <AK/MemoryStream.h>
 #include <LibCompress/Xz.h>
 
+TEST_CASE(lzma2_compressed_without_settings_after_uncompressed)
+{
+    Array<u8, 72> const compressed {
+        // Stream Header
+        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, // Magic
+        0x00, 0x00,                         // Stream Flags (Check: None)
+        0xFF, 0x12, 0xD9, 0x41,             // CRC32
+
+        // Block Header
+        0x02, // Block Header Size [(0x02 + 1) * 4, i.e. 12 bytes]
+        0x00, // Block Flags (one filter, no compressed or uncompressed size present)
+        //   Filter 0 Flags
+        0x21,                   // Filter ID (0x21 for LZMA2, encoded as a multibyte integer)
+        0x01,                   // Size of Properties (0x01, encoded as a multibyte integer)
+        0x00,                   // Filter Properties (LZMA2 encoded dictionary size byte; 0x00 = 4 KiB)
+        0x00, 0x00, 0x00,       // Header Padding
+        0x37, 0x27, 0x97, 0xD6, // CRC32
+
+        // Compressed Data (LZMA2)
+        //   LZMA chunk with dictionary reset
+        0xe0,       // Control Byte
+        0x00, 0x00, // Low 16 bits of uncompressed size minus one (big-endian)
+        0x00, 0x05, // Compressed size minus one (big-endian)
+        0x31,       // LZMA properties byte (lc = 1; lp = 1; pb = 1)
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        //  Uncompressed chunk without dictionary reset
+        0x02,       // Control Byte
+        0x00, 0x00, // 16-bit data size minus one (big-endian)
+        0x00,
+        //  LZMA chunk with state reset
+        0xa0,       // Control Byte
+        0x00, 0x00, // Low 16 bits of uncompressed size minus one (big-endian)
+        0x00, 0x05, // Compressed size minus one (big-endian)
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+        //  End of LZMA2 stream
+        0x00,
+
+        // Index
+        0x00, // Index Indicator
+        0x01, // Number of Records (multibyte integer)
+        //   Record 0
+        0x28, // Unpadded Size (multibyte integer)
+        0x03, // Uncompressed Size (multibyte integer)
+        //   CRC32
+        0x3B, 0x4A, 0xD2, 0xE4,
+
+        // Stream Footer
+        0x06, 0x72, 0x9E, 0x7A, // CRC32
+        0x01, 0x00, 0x00, 0x00, // Backward Size
+        0x00, 0x00,             // Stream Flags
+        0x59, 0x5A,             // Footer Magic Bytes
+    };
+
+    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
+    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
+    auto buffer = MUST(decompressor->read_until_eof(PAGE_SIZE));
+    EXPECT_EQ("\x00\x00\x00"sv.bytes(), buffer.span());
+}
+
 // The following tests are based on test files from the XZ utils package, which have been placed in the public domain:
 // https://tukaani.org/xz/xz-5.4.1.tar.xz (subdirectory /xz-5.4.1/tests/files)
 // Test descriptions have been taken from the README file in the test files directory.

+ 4 - 3
Userland/Libraries/LibCompress/Lzma2.cpp

@@ -39,6 +39,10 @@ ErrorOr<Bytes> Lzma2Decompressor::read_some(Bytes bytes)
             // " - 1 denotes a dictionary reset followed by an uncompressed chunk"
             m_dictionary.clear();
             m_dictionary_initialized = true;
+
+            // The XZ utils test files (bad-1-lzma2-8.xz) check that the decompressor
+            // requires a new set of properties after a dictionary reset.
+            m_last_lzma_options = {};
         }
 
         if (control_byte == 1 || control_byte == 2) {
@@ -52,9 +56,6 @@ ErrorOr<Bytes> Lzma2Decompressor::read_some(Bytes bytes)
             //   - The data to be copied verbatim into the dictionary and the output"
             u16 data_size = TRY(m_stream->read_value<BigEndian<u16>>()) + 1;
 
-            // The test files denote an LZMA chunk without its own settings following an uncompressed chunk as invalid.
-            m_last_lzma_options = {};
-
             m_in_uncompressed_chunk = true;
             m_current_chunk_stream = TRY(try_make<ConstrainedStream>(MaybeOwned { *m_stream }, data_size));
         }