/*
 * Copyright (c) 2023, Tim Schumacher <timschumi@gmx.de>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <LibTest/TestCase.h>

#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 = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ("\x00\x00\x00"sv.bytes(), buffer.span());
}

TEST_CASE(lzma2_uncompressed_size_overflow)
{
    Array<u8, 48> 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)
        //  Uncompressed chunk with dictionary reset
        0x01,       // Control Byte
        0xFF, 0xFF, // 16-bit data size minus one (big-endian)
                    // Note: The following data should be handled as verbatim data if handled correctly.
                    //       If the size overflows, no bytes will be copied and it will be interpreted as the remainder of the XZ stream.
        //  End of LZMA2 stream
        0x00,

        // Index
        0x00, // Index Indicator
        0x01, // Number of Records (multibyte integer)
        //   Record 0
        0x10, // Unpadded Size (multibyte integer)
        0x00, // Uncompressed Size (multibyte integer)
        //   CRC32
        0x7A, 0xA7, 0x44, 0x6A,

        // 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_or_error = decompressor->read_until_eof(PAGE_SIZE);

    // If the size overflows (and the uncompressed size being 0 doesn't get caught otherwise), the data payload will be interpreted as stream metadata, resulting in a valid stream.
    // If the size doesn't overflow, the stream ends in the middle unexpectedly, which should result in an error.
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(lzma2_literal_context_bits_after_state_reset)
{
    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)
        0x01,       // LZMA properties byte (lc = 1; lp = 0; pb = 0)
        0x00, 0x3F, 0xFF, 0xFC, 0x00, 0x00,
        //  LZMA chunk with state reset
        0xA0,       // Control Byte
        0x00, 0x01, // Low 16 bits of uncompressed size minus one (big-endian)
        0x00, 0x06, // Compressed size minus one (big-endian)
        0x00, 0x40, 0x1F, 0xF4, 0x00, 0x00, 0x00,
        //  End of LZMA2 stream
        0x00,

        // Block Padding
        0x00, 0x00, 0x00,

        // Index
        0x00, // Index Indicator
        0x01, // Number of Records (multibyte integer)
        //   Record 0
        0x25, // Unpadded Size (multibyte integer)
        0x03, // Uncompressed Size (multibyte integer)
        //   CRC32
        0x76, 0x34, 0x7C, 0x51,

        // 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 = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ("\x80\x80\x80"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.

TEST_CASE(xz_utils_bad_0_backward_size)
{
    // "bad-0-backward_size.xz has wrong Backward Size in Stream Footer."
    Array<u8, 32> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x00, 0x00, 0x00, 0x00,
        0x1C, 0xDF, 0x44, 0x21, 0x35, 0x91, 0xC5, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_0cat_alone)
{
    // "bad-0cat-alone.xz is good-0-empty.xz concatenated with an empty LZMA_Alone file."
    Array<u8, 55> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x00, 0x00, 0x00, 0x00,
        0x1C, 0xDF, 0x44, 0x21, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A,
        0x5D, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x83, 0xFF,
        0xFB, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_0cat_header_magic)
{
    // "bad-0cat-header_magic.xz is good-0cat-empty.xz but with one byte
    //  wrong in the Header Magic Bytes field of the second Stream."
    Array<u8, 64> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x00, 0x00, 0x00, 0x00,
        0x1C, 0xDF, 0x44, 0x21, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A,
        0xFD, 0x37, 0x7A, 0x58, 0x59, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x00, 0x00, 0x00, 0x00,
        0x1C, 0xDF, 0x44, 0x21, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_0catpad_empty)
{
    // "bad-0catpad-empty.xz has two zero-Block Streams concatenated with
    //  five-byte Stream Padding between the Streams."
    Array<u8, 69> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x00, 0x00, 0x00, 0x00,
        0x1C, 0xDF, 0x44, 0x21, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A,
        0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE,
        0x36, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xDF, 0x44, 0x21, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00,
        0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_0_empty_truncated)
{
    // "bad-0-empty-truncated.xz is good-0-empty.xz without the last byte
    //  of the file."
    Array<u8, 31> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x00, 0x00, 0x00, 0x00,
        0x1C, 0xDF, 0x44, 0x21, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_0_footer_magic)
{
    // "bad-0-footer_magic.xz is good-0-empty.xz but with one byte wrong
    //  in the Footer Magic Bytes field."
    Array<u8, 32> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x00, 0x00, 0x00, 0x00,
        0x1C, 0xDF, 0x44, 0x21, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x58
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_0_header_magic)
{
    // "bad-0-header_magic.xz is good-0-empty.xz but with one byte wrong
    //  in the Header Magic Bytes field."
    Array<u8, 32> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x59, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x00, 0x00, 0x00, 0x00,
        0x1C, 0xDF, 0x44, 0x21, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_0_nonempty_index)
{
    // "bad-0-nonempty_index.xz has no Blocks but Index claims that there is
    //  one Block."
    Array<u8, 32> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x00, 0x01, 0x00, 0x00,
        0x2B, 0xB5, 0x86, 0x20, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_0pad_empty)
{
    // "bad-0pad-empty.xz has one Stream with no Blocks followed by
    //  five-byte Stream Padding. Stream Padding must be a multiple of four
    //  bytes, thus this file is corrupt."
    Array<u8, 37> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x00, 0x00, 0x00, 0x00,
        0x1C, 0xDF, 0x44, 0x21, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A,
        0x00, 0x00, 0x00, 0x00, 0x00
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_block_header_1)
{
    // "bad-1-block_header-1.xz has Block Header that ends in the middle of
    //  the Filter Flags field."
    Array<u8, 64> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x01, 0x00, 0x21, 0x01,
        0x0C, 0x9D, 0x60, 0x62, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x02, 0x00, 0x06,
        0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x43, 0xA3, 0xA2, 0x15, 0x00, 0x01, 0x24, 0x0D,
        0x30, 0x28, 0xDF, 0xAF, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_block_header_2)
{
    // "bad-1-block_header-2.xz has Block Header that has Compressed Size and
    //  Uncompressed Size but no List of Filter Flags field."
    Array<u8, 64> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x01, 0xC0, 0x04, 0x0D,
        0x80, 0x97, 0x8A, 0x12, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x02, 0x00, 0x06,
        0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x43, 0xA3, 0xA2, 0x15, 0x00, 0x01, 0x24, 0x0D,
        0x30, 0x28, 0xDF, 0xAF, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_block_header_3)
{
    // "bad-1-block_header-3.xz has wrong CRC32 in Block Header."
    Array<u8, 68> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x33, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x43, 0xA3, 0xA2, 0x15,
        0x00, 0x01, 0x24, 0x0D, 0x30, 0x28, 0xDF, 0xAF, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_block_header_4)
{
    // "bad-1-block_header-4.xz has too big Compressed Size in Block Header
    //  (2^63 - 1 bytes while maximum is a little less, because the whole
    //  Block must stay smaller than 2^63). It's important that the file
    //  gets rejected due to invalid Compressed Size value; the decoder
    //  must not try decoding the Compressed Data field."
    Array<u8, 76> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x04, 0x40, 0xFF, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x21, 0x01, 0x08, 0x00, 0x00, 0x63, 0xE2, 0x3A, 0x70,
        0x01, 0x00, 0x0C, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A,
        0x00, 0x00, 0x00, 0x00, 0x43, 0xA3, 0xA2, 0x15, 0x00, 0x01, 0x29, 0x0D, 0x7D, 0x56, 0x71, 0x1A,
        0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    // TODO: The specification apparently doesn't mention that a block has to be smaller than 2^63, investigate.
    (void)decompressor->read_until_eof(PAGE_SIZE);
}

TEST_CASE(xz_utils_bad_1_block_header_5)
{
    // "bad-1-block_header-5.xz has zero as Compressed Size in Block Header."
    Array<u8, 72> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x03, 0xC0, 0x00, 0x0D,
        0x21, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA9, 0x34, 0x55, 0x23, 0x01, 0x00, 0x0C, 0x48,
        0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x00, 0x00, 0x00,
        0x43, 0xA3, 0xA2, 0x15, 0x00, 0x01, 0x25, 0x0D, 0x71, 0x19, 0xC4, 0xB6, 0x90, 0x42, 0x99, 0x0D,
        0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_block_header_6)
{
    // "bad-1-block_header-6.xz has corrupt Block Header which may crash
    //  xz -lvv in XZ Utils 5.0.3 and earlier."
    Array<u8, 72> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x00, 0xC0, 0x11, 0x0D,
        0x21, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xDE, 0x39, 0xEB, 0x01, 0x00, 0x0C, 0x48,
        0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x00, 0x00, 0x00,
        0x43, 0xA3, 0xA2, 0x15, 0x00, 0x01, 0x25, 0x0D, 0x71, 0x19, 0xC4, 0xB6, 0x90, 0x42, 0x99, 0x0D,
        0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_check_crc32)
{
    // "bad-1-check-crc32.xz has wrong Check (CRC32)."
    Array<u8, 68> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x43, 0xA3, 0xA2, 0x14,
        0x00, 0x01, 0x24, 0x0D, 0x30, 0x28, 0xDF, 0xAF, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    // TODO: We currently don't check the uncompressed data against the check value.
    (void)decompressor->read_until_eof(PAGE_SIZE);
}

TEST_CASE(xz_utils_bad_1_check_crc32_2)
{
    // "bad-1-check-crc32-2.xz has Compressed Size and Uncompressed Size in
    //  Block Header but wrong Check (CRC32) in the actual data."
    Array<u8, 72> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x03, 0xC0, 0x11, 0x0D,
        0x21, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xDE, 0x39, 0xEB, 0x01, 0x00, 0x0C, 0x48,
        0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x00, 0x00, 0x00,
        0x43, 0xA3, 0xA2, 0xFF, 0x00, 0x01, 0x25, 0x0D, 0x71, 0x19, 0xC4, 0xB6, 0x90, 0x42, 0x99, 0x0D,
        0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    // TODO: We currently don't check the uncompressed data against the check value.
    (void)decompressor->read_until_eof(PAGE_SIZE);
}

TEST_CASE(xz_utils_bad_1_check_crc64)
{
    // "bad-1-check-crc64.xz has wrong Check (CRC64)."
    Array<u8, 72> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x04, 0xE6, 0xD6, 0xB4, 0x46, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0xEF, 0x2E, 0x88, 0x11,
        0x9D, 0x3F, 0x96, 0xCB, 0x00, 0x01, 0x28, 0x0D, 0x3C, 0x67, 0x6A, 0x03, 0x1F, 0xB6, 0xF3, 0x7D,
        0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    // TODO: We currently don't check the uncompressed data against the check value.
    (void)decompressor->read_until_eof(PAGE_SIZE);
}

TEST_CASE(xz_utils_bad_1_check_sha256)
{
    // "bad-1-check-sha256.xz has wrong Check (SHA-256)."
    Array<u8, 96> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x0A, 0xE1, 0xFB, 0x0C, 0xA1, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x8E, 0x59, 0x35, 0xE7,
        0xE1, 0x33, 0x68, 0xCD, 0x96, 0x88, 0xFE, 0x8F, 0x48, 0xA0, 0x95, 0x52, 0x93, 0x67, 0x6A, 0x02,
        0x15, 0x62, 0x58, 0x2C, 0x7E, 0x84, 0x8D, 0xAF, 0xE1, 0x3F, 0xB0, 0x47, 0x00, 0x01, 0x40, 0x0D,
        0x93, 0x86, 0x4E, 0xAE, 0x18, 0x9B, 0x4B, 0x9A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    // TODO: We currently don't check the uncompressed data against the check value.
    (void)decompressor->read_until_eof(PAGE_SIZE);
}

TEST_CASE(xz_utils_bad_1_lzma2_1)
{
    // "bad-1-lzma2-1.xz has LZMA2 stream whose first chunk (uncompressed)
    //  doesn't reset the dictionary."
    Array<u8, 64> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x00, 0xFF, 0x12, 0xD9, 0x41, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x02, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x00, 0x01, 0x20, 0x0D,
        0x34, 0xED, 0xB3, 0xCB, 0x06, 0x72, 0x9E, 0x7A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_lzma2_2)
{
    // "bad-1-lzma2-2.xz has two LZMA2 chunks, of which the second chunk
    //  indicates dictionary reset, but the LZMA compressed data tries to
    //  repeat data from the previous chunk."
    Array<u8, 424> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0xE0, 0x00, 0xE2, 0x00, 0xB6, 0x5D, 0x00, 0x26,
        0x1B, 0xCA, 0x46, 0x67, 0x5A, 0xF2, 0x77, 0xB8, 0x7D, 0x86, 0xD8, 0x41, 0xDB, 0x05, 0x35, 0xCD,
        0x83, 0xA5, 0x7C, 0x12, 0xA5, 0x05, 0xDB, 0x90, 0xBD, 0x2F, 0x14, 0xD3, 0x71, 0x72, 0x96, 0xA8,
        0x8A, 0x7D, 0x84, 0x56, 0x71, 0x8D, 0x6A, 0x22, 0x98, 0xAB, 0x9E, 0x3D, 0x90, 0x80, 0x2D, 0xC7,
        0x5E, 0x0C, 0x12, 0x52, 0xD3, 0x3F, 0x07, 0x08, 0x7B, 0x1C, 0xA4, 0x77, 0xF3, 0x13, 0xB8, 0x17,
        0xC0, 0xEE, 0x91, 0x81, 0x39, 0xB3, 0x87, 0xF0, 0xFF, 0x00, 0xB3, 0x6A, 0x52, 0x41, 0xED, 0x2E,
        0xB0, 0xF2, 0x64, 0x97, 0xA4, 0x9A, 0x9E, 0x63, 0xA1, 0xAE, 0x19, 0x74, 0x0D, 0xA9, 0xD5, 0x5B,
        0x6C, 0xEE, 0xB1, 0xE0, 0x2C, 0xDC, 0x61, 0xDC, 0xCB, 0x9D, 0x86, 0xCF, 0xE1, 0xDC, 0x0A, 0x7A,
        0x81, 0x14, 0x5F, 0xD0, 0x40, 0xC8, 0x7E, 0x0D, 0x97, 0x44, 0xCE, 0xB5, 0xC2, 0xFC, 0x2C, 0x59,
        0x08, 0xBF, 0x03, 0x80, 0xDC, 0xD7, 0x44, 0x8E, 0xB3, 0xD4, 0x2D, 0xDE, 0xE5, 0x16, 0x21, 0x6E,
        0x47, 0x82, 0xAC, 0x08, 0x59, 0xD8, 0xE4, 0x66, 0x29, 0x61, 0xD5, 0xD1, 0xFA, 0x49, 0x63, 0x90,
        0x11, 0x3E, 0x20, 0xD0, 0xA9, 0xE2, 0xD5, 0x14, 0x81, 0xD9, 0x23, 0xD0, 0x8F, 0x43, 0xAE, 0x45,
        0x55, 0x36, 0x69, 0xAA, 0x00, 0xE0, 0x00, 0xE5, 0x00, 0xAD, 0x0B, 0x00, 0x8C, 0xF1, 0x9D, 0x40,
        0x2B, 0xD0, 0x7D, 0x1D, 0x99, 0xEE, 0xE4, 0xDC, 0x63, 0x74, 0x64, 0x46, 0xA4, 0xA0, 0x4A, 0x64,
        0x65, 0xB2, 0xF6, 0x4E, 0xC1, 0xC8, 0x68, 0x9F, 0x27, 0x54, 0xAD, 0xBB, 0xA6, 0x34, 0x3C, 0x77,
        0xEC, 0x0F, 0x2E, 0x1B, 0x8E, 0x42, 0x27, 0xE5, 0x68, 0xBF, 0x60, 0xF4, 0x0B, 0x3A, 0xF0, 0x9B,
        0x31, 0xEB, 0xDF, 0x3F, 0xD8, 0xAF, 0xA5, 0x55, 0x92, 0x46, 0x05, 0x58, 0x22, 0x09, 0x8F, 0xA8,
        0x60, 0x08, 0x0B, 0xA3, 0xE9, 0x3E, 0xBC, 0xB4, 0x16, 0xDB, 0xC7, 0xA3, 0xA2, 0xC0, 0x16, 0xD5,
        0x14, 0xA7, 0x22, 0xE8, 0x2F, 0xE8, 0xB4, 0xD0, 0x77, 0x17, 0xC5, 0x8B, 0xE4, 0xF2, 0xBB, 0x6B,
        0xD6, 0xEF, 0x9A, 0x81, 0x34, 0x4E, 0x1D, 0xDC, 0xEC, 0x36, 0xE6, 0x44, 0x72, 0xBF, 0x29, 0xB5,
        0x3C, 0x05, 0x31, 0x60, 0x66, 0xBA, 0x2C, 0x03, 0x0F, 0xD6, 0x47, 0xC6, 0x7D, 0x85, 0xD4, 0xC5,
        0x5E, 0x4E, 0x57, 0x73, 0xC3, 0x41, 0x69, 0xBE, 0x0D, 0x8C, 0x9C, 0xB5, 0x15, 0xA9, 0xE7, 0xD2,
        0x78, 0x51, 0x4B, 0xD5, 0x29, 0xD0, 0xF9, 0x35, 0x1A, 0xC5, 0x5D, 0xF4, 0x8C, 0x7A, 0x70, 0xD5,
        0x5E, 0xA8, 0x31, 0x57, 0x80, 0xC8, 0xA5, 0xD8, 0xE0, 0x00, 0x00, 0x00, 0xFB, 0x47, 0x48, 0xDB,
        0x00, 0x01, 0x82, 0x03, 0xC9, 0x03, 0x00, 0x00, 0x0B, 0x04, 0x8E, 0xDE, 0x3E, 0x30, 0x0D, 0x8B,
        0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_lzma2_3)
{
    // "bad-1-lzma2-3.xz sets new invalid properties (lc=8, lp=0, pb=0) in
    //  the middle of Block."
    Array<u8, 424> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0xE0, 0x00, 0xE2, 0x00, 0xB6, 0x5D, 0x00, 0x26,
        0x1B, 0xCA, 0x46, 0x67, 0x5A, 0xF2, 0x77, 0xB8, 0x7D, 0x86, 0xD8, 0x41, 0xDB, 0x05, 0x35, 0xCD,
        0x83, 0xA5, 0x7C, 0x12, 0xA5, 0x05, 0xDB, 0x90, 0xBD, 0x2F, 0x14, 0xD3, 0x71, 0x72, 0x96, 0xA8,
        0x8A, 0x7D, 0x84, 0x56, 0x71, 0x8D, 0x6A, 0x22, 0x98, 0xAB, 0x9E, 0x3D, 0x90, 0x80, 0x2D, 0xC7,
        0x5E, 0x0C, 0x12, 0x52, 0xD3, 0x3F, 0x07, 0x08, 0x7B, 0x1C, 0xA4, 0x77, 0xF3, 0x13, 0xB8, 0x17,
        0xC0, 0xEE, 0x91, 0x81, 0x39, 0xB3, 0x87, 0xF0, 0xFF, 0x00, 0xB3, 0x6A, 0x52, 0x41, 0xED, 0x2E,
        0xB0, 0xF2, 0x64, 0x97, 0xA4, 0x9A, 0x9E, 0x63, 0xA1, 0xAE, 0x19, 0x74, 0x0D, 0xA9, 0xD5, 0x5B,
        0x6C, 0xEE, 0xB1, 0xE0, 0x2C, 0xDC, 0x61, 0xDC, 0xCB, 0x9D, 0x86, 0xCF, 0xE1, 0xDC, 0x0A, 0x7A,
        0x81, 0x14, 0x5F, 0xD0, 0x40, 0xC8, 0x7E, 0x0D, 0x97, 0x44, 0xCE, 0xB5, 0xC2, 0xFC, 0x2C, 0x59,
        0x08, 0xBF, 0x03, 0x80, 0xDC, 0xD7, 0x44, 0x8E, 0xB3, 0xD4, 0x2D, 0xDE, 0xE5, 0x16, 0x21, 0x6E,
        0x47, 0x82, 0xAC, 0x08, 0x59, 0xD8, 0xE4, 0x66, 0x29, 0x61, 0xD5, 0xD1, 0xFA, 0x49, 0x63, 0x90,
        0x11, 0x3E, 0x20, 0xD0, 0xA9, 0xE2, 0xD5, 0x14, 0x81, 0xD9, 0x23, 0xD0, 0x8F, 0x43, 0xAE, 0x45,
        0x55, 0x36, 0x69, 0xAA, 0x00, 0xC0, 0x00, 0xE5, 0x00, 0xAD, 0x08, 0x00, 0x8C, 0xF1, 0x9D, 0x40,
        0x2B, 0xD0, 0x7D, 0x1D, 0x99, 0xEE, 0xE4, 0xDC, 0x63, 0x74, 0x64, 0x46, 0xA4, 0xA0, 0x4A, 0x64,
        0x65, 0xB2, 0xF6, 0x4E, 0xC1, 0xC8, 0x68, 0x9F, 0x27, 0x54, 0xAD, 0xBB, 0xA6, 0x34, 0x3C, 0x77,
        0xEC, 0x0F, 0x2E, 0x1B, 0x8E, 0x42, 0x27, 0xE5, 0x68, 0xBF, 0x60, 0xF4, 0x0B, 0x3A, 0xF0, 0x9B,
        0x31, 0xEB, 0xDF, 0x3F, 0xD8, 0xAF, 0xA5, 0x55, 0x92, 0x46, 0x05, 0x58, 0x22, 0x09, 0x8F, 0xA8,
        0x60, 0x08, 0x0B, 0xA3, 0xE9, 0x3E, 0xBC, 0xB4, 0x16, 0xDB, 0xC7, 0xA3, 0xA2, 0xC0, 0x16, 0xD5,
        0x14, 0xA7, 0x22, 0xE8, 0x2F, 0xE8, 0xB4, 0xD0, 0x77, 0x17, 0xC5, 0x8B, 0xE4, 0xF2, 0xBB, 0x6B,
        0xD6, 0xEF, 0x9A, 0x81, 0x34, 0x4E, 0x1D, 0xDC, 0xEC, 0x36, 0xE6, 0x44, 0x72, 0xBF, 0x29, 0xB5,
        0x3C, 0x05, 0x31, 0x60, 0x66, 0xBA, 0x2C, 0x03, 0x0F, 0xD6, 0x47, 0xC6, 0x7D, 0x85, 0xD4, 0xC5,
        0x5E, 0x4E, 0x57, 0x73, 0xC3, 0x41, 0x69, 0xBE, 0x0D, 0x8C, 0x9C, 0xB5, 0x15, 0xA9, 0xE7, 0xD2,
        0x78, 0x51, 0x4B, 0xD5, 0x29, 0xD0, 0xF9, 0x35, 0x1A, 0xC5, 0x5D, 0xF4, 0x8C, 0x7A, 0x70, 0xD5,
        0x5E, 0xA8, 0x31, 0x57, 0x80, 0xC8, 0xA5, 0xD8, 0xE0, 0x00, 0x00, 0x00, 0xFB, 0x47, 0x48, 0xDB,
        0x00, 0x01, 0x82, 0x03, 0xC9, 0x03, 0x00, 0x00, 0x0B, 0x04, 0x8E, 0xDE, 0x3E, 0x30, 0x0D, 0x8B,
        0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_lzma2_4)
{
    // "bad-1-lzma2-4.xz has two LZMA2 chunks, of which the first is
    //  uncompressed and the second is LZMA. The first chunk resets dictionary
    //  as it should, but the second chunk tries to reset state without
    //  specifying properties for LZMA."
    Array<u8, 408> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x34, 0x4C, 0x6F, 0x72, 0x65, 0x6D,
        0x20, 0x69, 0x70, 0x73, 0x75, 0x6D, 0x20, 0x64, 0x6F, 0x6C, 0x6F, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6D, 0x65, 0x74, 0x2C, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x63, 0x74, 0x65, 0x74,
        0x75, 0x72, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x69, 0x63, 0x69, 0x6E, 0x67, 0x20, 0x0A,
        0xA0, 0x01, 0x93, 0x01, 0x24, 0x00, 0x32, 0x9B, 0x09, 0x6C, 0x54, 0xD7, 0x2E, 0x95, 0x6C, 0xF9,
        0xF7, 0x37, 0xD5, 0x1C, 0xE2, 0x46, 0x02, 0x82, 0x75, 0xFB, 0x49, 0x76, 0x8D, 0x73, 0x53, 0xB6,
        0xFD, 0x6D, 0xDB, 0xCA, 0xDB, 0xD9, 0x44, 0x0B, 0xB1, 0x2E, 0xBE, 0x13, 0xB6, 0xBA, 0xA8, 0xE2,
        0xF3, 0xED, 0x75, 0x54, 0xDC, 0x41, 0x20, 0xCC, 0xBF, 0x36, 0x5B, 0x20, 0x99, 0x5D, 0x0F, 0x21,
        0xA1, 0x06, 0xA3, 0x96, 0x2D, 0xB7, 0x97, 0x9C, 0xF0, 0x7B, 0xFE, 0xE2, 0x12, 0x8C, 0x2D, 0x51,
        0xF0, 0xDB, 0x76, 0x77, 0x7D, 0xA4, 0x7B, 0xD3, 0x95, 0xE9, 0xFB, 0x05, 0xE6, 0xF5, 0x97, 0x8F,
        0x62, 0xE9, 0xDB, 0x30, 0xBB, 0xB4, 0x70, 0x3D, 0x16, 0x78, 0x03, 0x77, 0x3A, 0x8B, 0x7A, 0xD5,
        0xB8, 0xF8, 0x4A, 0x27, 0x25, 0xF5, 0x8E, 0xAA, 0x24, 0x14, 0xA6, 0x29, 0x28, 0x6B, 0x2F, 0x73,
        0xE0, 0xA1, 0x71, 0xB4, 0x7B, 0xA4, 0x80, 0x50, 0x40, 0xCA, 0xEF, 0xDB, 0xB4, 0x95, 0xFD, 0xBB,
        0xC1, 0x8C, 0x8E, 0x60, 0x97, 0xDB, 0xCB, 0x7F, 0x21, 0xED, 0xC0, 0x10, 0x71, 0x1A, 0x7D, 0xCB,
        0xCD, 0x09, 0xD0, 0xD9, 0xFF, 0x6D, 0x80, 0xC0, 0x67, 0x7D, 0x3F, 0xC6, 0x94, 0xCF, 0x5B, 0xDD,
        0x51, 0x11, 0xD1, 0xCB, 0xD4, 0x20, 0xD7, 0x2B, 0x84, 0x4E, 0xA8, 0x45, 0xBB, 0x42, 0x78, 0x1A,
        0x68, 0x40, 0x5F, 0x24, 0x5E, 0x89, 0x3A, 0x36, 0x7D, 0xDB, 0x98, 0x28, 0xCC, 0xF9, 0x83, 0xEC,
        0x32, 0x06, 0x31, 0x47, 0x47, 0x3B, 0x6C, 0x1C, 0xF4, 0x62, 0x34, 0x40, 0xB3, 0x28, 0xBB, 0x54,
        0x36, 0xDD, 0x7A, 0x0E, 0x1C, 0x36, 0x25, 0x38, 0x58, 0x06, 0xF8, 0x15, 0xA3, 0xCE, 0x18, 0xC8,
        0xFD, 0x96, 0x1E, 0x69, 0x29, 0x03, 0xC3, 0xBD, 0x27, 0xF3, 0xE7, 0x8F, 0xDB, 0x73, 0xB4, 0x2B,
        0x4F, 0x38, 0x58, 0x24, 0xBF, 0x83, 0x14, 0x39, 0x7E, 0x73, 0xEE, 0xFE, 0xCF, 0xCA, 0xBD, 0xF3,
        0x21, 0x6A, 0x28, 0x80, 0xC8, 0x8E, 0x5D, 0x81, 0xC7, 0xBC, 0x17, 0xD0, 0x2C, 0x93, 0xB5, 0x08,
        0x95, 0xBA, 0x0E, 0x92, 0x82, 0x66, 0xAE, 0xFF, 0xB8, 0x03, 0x00, 0x00, 0xFB, 0x47, 0x48, 0xDB,
        0x00, 0x01, 0xF3, 0x02, 0xC9, 0x03, 0x00, 0x00, 0xDF, 0xF3, 0x90, 0x23, 0x3E, 0x30, 0x0D, 0x8B,
        0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_lzma2_5)
{
    // "bad-1-lzma2-5.xz is like bad-1-lzma2-4.xz but doesn't try to reset
    //  anything in the header of the second chunk."
    Array<u8, 408> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x34, 0x4C, 0x6F, 0x72, 0x65, 0x6D,
        0x20, 0x69, 0x70, 0x73, 0x75, 0x6D, 0x20, 0x64, 0x6F, 0x6C, 0x6F, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6D, 0x65, 0x74, 0x2C, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x63, 0x74, 0x65, 0x74,
        0x75, 0x72, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x69, 0x63, 0x69, 0x6E, 0x67, 0x20, 0x0A,
        0x80, 0x01, 0x93, 0x01, 0x24, 0x00, 0x32, 0x9B, 0x09, 0x6C, 0x54, 0xD7, 0x2E, 0x95, 0x6C, 0xF9,
        0xF7, 0x37, 0xD5, 0x1C, 0xE2, 0x46, 0x02, 0x82, 0x75, 0xFB, 0x49, 0x76, 0x8D, 0x73, 0x53, 0xB6,
        0xFD, 0x6D, 0xDB, 0xCA, 0xDB, 0xD9, 0x44, 0x0B, 0xB1, 0x2E, 0xBE, 0x13, 0xB6, 0xBA, 0xA8, 0xE2,
        0xF3, 0xED, 0x75, 0x54, 0xDC, 0x41, 0x20, 0xCC, 0xBF, 0x36, 0x5B, 0x20, 0x99, 0x5D, 0x0F, 0x21,
        0xA1, 0x06, 0xA3, 0x96, 0x2D, 0xB7, 0x97, 0x9C, 0xF0, 0x7B, 0xFE, 0xE2, 0x12, 0x8C, 0x2D, 0x51,
        0xF0, 0xDB, 0x76, 0x77, 0x7D, 0xA4, 0x7B, 0xD3, 0x95, 0xE9, 0xFB, 0x05, 0xE6, 0xF5, 0x97, 0x8F,
        0x62, 0xE9, 0xDB, 0x30, 0xBB, 0xB4, 0x70, 0x3D, 0x16, 0x78, 0x03, 0x77, 0x3A, 0x8B, 0x7A, 0xD5,
        0xB8, 0xF8, 0x4A, 0x27, 0x25, 0xF5, 0x8E, 0xAA, 0x24, 0x14, 0xA6, 0x29, 0x28, 0x6B, 0x2F, 0x73,
        0xE0, 0xA1, 0x71, 0xB4, 0x7B, 0xA4, 0x80, 0x50, 0x40, 0xCA, 0xEF, 0xDB, 0xB4, 0x95, 0xFD, 0xBB,
        0xC1, 0x8C, 0x8E, 0x60, 0x97, 0xDB, 0xCB, 0x7F, 0x21, 0xED, 0xC0, 0x10, 0x71, 0x1A, 0x7D, 0xCB,
        0xCD, 0x09, 0xD0, 0xD9, 0xFF, 0x6D, 0x80, 0xC0, 0x67, 0x7D, 0x3F, 0xC6, 0x94, 0xCF, 0x5B, 0xDD,
        0x51, 0x11, 0xD1, 0xCB, 0xD4, 0x20, 0xD7, 0x2B, 0x84, 0x4E, 0xA8, 0x45, 0xBB, 0x42, 0x78, 0x1A,
        0x68, 0x40, 0x5F, 0x24, 0x5E, 0x89, 0x3A, 0x36, 0x7D, 0xDB, 0x98, 0x28, 0xCC, 0xF9, 0x83, 0xEC,
        0x32, 0x06, 0x31, 0x47, 0x47, 0x3B, 0x6C, 0x1C, 0xF4, 0x62, 0x34, 0x40, 0xB3, 0x28, 0xBB, 0x54,
        0x36, 0xDD, 0x7A, 0x0E, 0x1C, 0x36, 0x25, 0x38, 0x58, 0x06, 0xF8, 0x15, 0xA3, 0xCE, 0x18, 0xC8,
        0xFD, 0x96, 0x1E, 0x69, 0x29, 0x03, 0xC3, 0xBD, 0x27, 0xF3, 0xE7, 0x8F, 0xDB, 0x73, 0xB4, 0x2B,
        0x4F, 0x38, 0x58, 0x24, 0xBF, 0x83, 0x14, 0x39, 0x7E, 0x73, 0xEE, 0xFE, 0xCF, 0xCA, 0xBD, 0xF3,
        0x21, 0x6A, 0x28, 0x80, 0xC8, 0x8E, 0x5D, 0x81, 0xC7, 0xBC, 0x17, 0xD0, 0x2C, 0x93, 0xB5, 0x08,
        0x95, 0xBA, 0x0E, 0x92, 0x82, 0x66, 0xAE, 0xFF, 0xB8, 0x03, 0x00, 0x00, 0xFB, 0x47, 0x48, 0xDB,
        0x00, 0x01, 0xF3, 0x02, 0xC9, 0x03, 0x00, 0x00, 0xDF, 0xF3, 0x90, 0x23, 0x3E, 0x30, 0x0D, 0x8B,
        0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_lzma2_6)
{
    // "bad-1-lzma2-6.xz has reserved LZMA2 control byte value (0x03)."
    Array<u8, 68> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x03, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x43, 0xA3, 0xA2, 0x15,
        0x00, 0x01, 0x24, 0x0D, 0x30, 0x28, 0xDF, 0xAF, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_lzma2_7)
{
    // "bad-1-lzma2-7.xz has EOPM at LZMA level."
    Array<u8, 408> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x04, 0xE6, 0xD6, 0xB4, 0x46, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0xE0, 0x01, 0xC8, 0x01, 0x57, 0x5D, 0x00, 0x26,
        0x1B, 0xCA, 0x46, 0x67, 0x5A, 0xF2, 0x77, 0xB8, 0x7D, 0x86, 0xD8, 0x41, 0xDB, 0x05, 0x35, 0xCD,
        0x83, 0xA5, 0x7C, 0x12, 0xA5, 0x05, 0xDB, 0x90, 0xBD, 0x2F, 0x14, 0xD3, 0x71, 0x12, 0x7C, 0x4D,
        0xCD, 0x11, 0xA9, 0xE3, 0x65, 0x01, 0x2E, 0x86, 0x49, 0x86, 0x92, 0x42, 0x32, 0x52, 0x94, 0x2E,
        0x10, 0x5F, 0xB7, 0x8E, 0x8F, 0xFD, 0xF5, 0x1B, 0xC6, 0x26, 0x01, 0xF0, 0xB3, 0xBB, 0xBB, 0x6E,
        0xC5, 0x7A, 0x96, 0xE1, 0xDF, 0xC8, 0x34, 0xC3, 0xF5, 0x4F, 0x83, 0x06, 0x28, 0x51, 0x81, 0x64,
        0xF9, 0x80, 0x6A, 0x71, 0x47, 0xD0, 0xE2, 0xA6, 0xD6, 0x0D, 0x64, 0x31, 0xCF, 0x8A, 0x30, 0x62,
        0xFB, 0x73, 0x35, 0x4A, 0x10, 0x05, 0xC4, 0xCE, 0xEF, 0xB4, 0xFE, 0xD3, 0x85, 0x36, 0xE0, 0xE9,
        0x67, 0xC0, 0xF0, 0xB5, 0xA1, 0x1E, 0x52, 0x58, 0x54, 0xDD, 0x40, 0x56, 0xF8, 0x9B, 0xF3, 0x59,
        0xF1, 0xD6, 0xE0, 0x7A, 0x06, 0x56, 0x3C, 0x3D, 0xBD, 0x15, 0x81, 0xBB, 0x3A, 0xEB, 0x85, 0x0E,
        0x12, 0xAA, 0xB1, 0x60, 0x59, 0x6C, 0xBE, 0x40, 0x8E, 0x8D, 0xAE, 0x01, 0x96, 0x28, 0x7A, 0x13,
        0x71, 0x3C, 0x53, 0x87, 0x35, 0x93, 0xBA, 0xE2, 0x25, 0xEA, 0xB5, 0x35, 0xAE, 0x50, 0x4E, 0xBE,
        0xE0, 0xDD, 0x0C, 0xBA, 0x8A, 0xC3, 0xF0, 0x24, 0x17, 0xF6, 0xF0, 0xE4, 0xCC, 0xDB, 0xBD, 0x27,
        0x2B, 0xB7, 0xAB, 0xC1, 0x95, 0x62, 0xB0, 0xBF, 0x80, 0x95, 0xA8, 0x08, 0x02, 0x7F, 0xD1, 0xD6,
        0x2B, 0x77, 0x8D, 0x1C, 0x6E, 0xCE, 0xA5, 0xD9, 0xDA, 0x5D, 0xD3, 0xE6, 0x8B, 0xB5, 0xE7, 0x79,
        0x41, 0xA6, 0xD3, 0x9E, 0x7D, 0x27, 0xBC, 0x49, 0x99, 0x85, 0x0B, 0xF1, 0x0E, 0x45, 0x1E, 0xFB,
        0x2A, 0xF7, 0xD7, 0x0E, 0x7C, 0xCF, 0xF0, 0xF4, 0x52, 0x48, 0x18, 0x7B, 0x11, 0x4B, 0xF1, 0xB9,
        0xA9, 0x81, 0xE9, 0x27, 0x0A, 0x37, 0xC3, 0x55, 0xBD, 0xB4, 0x55, 0xDB, 0xAD, 0xB7, 0xDF, 0x79,
        0x9F, 0x46, 0xB5, 0x95, 0x4B, 0x79, 0x7B, 0x11, 0xD9, 0x2D, 0x13, 0xE3, 0x08, 0xD5, 0xA1, 0x84,
        0xA0, 0x41, 0x3B, 0x6E, 0x11, 0xD3, 0x36, 0xF9, 0x7A, 0x55, 0x54, 0x10, 0xDF, 0x06, 0xE1, 0x4C,
        0xD7, 0x57, 0x49, 0xBD, 0x66, 0x69, 0x7D, 0x1B, 0xA0, 0xE1, 0x83, 0x68, 0x08, 0x1D, 0xA0, 0xFD,
        0x34, 0x86, 0x9E, 0x0D, 0xC1, 0x20, 0x1B, 0x65, 0x75, 0xDD, 0x3B, 0x5F, 0x73, 0xCA, 0xC2, 0x83,
        0xFF, 0xFF, 0xE8, 0x6A, 0x51, 0xD8, 0x00, 0x00, 0xB2, 0x07, 0x44, 0xE9, 0x17, 0x33, 0x4B, 0x84,
        0x00, 0x01, 0xF3, 0x02, 0xC9, 0x03, 0x00, 0x00, 0xDF, 0xF3, 0x90, 0x23, 0xB1, 0xC4, 0x67, 0xFB,
        0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_lzma2_8)
{
    // "bad-1-lzma2-8.xz is like good-1-lzma2-4.xz but doesn't set new
    //  properties in the third LZMA2 chunk."
    Array<u8, 464> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x04, 0xE6, 0xD6, 0xB4, 0x46, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0xE0, 0x00, 0xBB, 0x00, 0xA1, 0x5D, 0x00, 0x26,
        0x1B, 0xCA, 0x46, 0x67, 0x5A, 0xF2, 0x77, 0xB8, 0x7D, 0x86, 0xD8, 0x41, 0xDB, 0x05, 0x35, 0xCD,
        0x83, 0xA5, 0x7C, 0x12, 0xA5, 0x05, 0xDB, 0x90, 0xBD, 0x2F, 0x14, 0xD3, 0x71, 0x72, 0x96, 0xA8,
        0x8A, 0x7D, 0x84, 0x56, 0x71, 0x8D, 0x6A, 0x22, 0x98, 0xAB, 0x9E, 0x3D, 0x90, 0x80, 0x2D, 0xC7,
        0x5E, 0x0C, 0x12, 0x52, 0xD3, 0x3F, 0x07, 0x08, 0x7B, 0x1C, 0xA4, 0x77, 0xF3, 0x13, 0xB8, 0x17,
        0xC0, 0xEE, 0x91, 0x73, 0xCA, 0xBC, 0xCF, 0xEB, 0x34, 0x66, 0xAC, 0x48, 0x9B, 0x69, 0xD9, 0x93,
        0x07, 0xAE, 0xCE, 0x50, 0xAF, 0x68, 0x09, 0x2F, 0x5B, 0x88, 0x1F, 0xC2, 0x08, 0xA2, 0x2C, 0x58,
        0x45, 0xB0, 0xFF, 0x62, 0x09, 0xEB, 0xEE, 0xDB, 0x63, 0x4F, 0x6F, 0xE0, 0xF3, 0x1F, 0xCF, 0x12,
        0x37, 0x98, 0x96, 0x4E, 0xF6, 0xF2, 0xB2, 0xFB, 0x6E, 0xAF, 0x44, 0x02, 0xE2, 0x22, 0xDE, 0xD5,
        0xE6, 0x34, 0x97, 0x39, 0xA3, 0x45, 0x2F, 0xAE, 0x99, 0x2F, 0x79, 0x69, 0x8F, 0xE9, 0x37, 0x89,
        0x48, 0xFE, 0xCC, 0x7E, 0xEA, 0xA9, 0x28, 0xAD, 0xC3, 0xE6, 0xDC, 0xB9, 0xDA, 0xAA, 0x16, 0x7E,
        0x01, 0x00, 0x26, 0x6C, 0x61, 0x62, 0x6F, 0x72, 0x69, 0x73, 0x20, 0x6E, 0x69, 0x73, 0x69, 0x20,
        0x75, 0x74, 0x20, 0x61, 0x6C, 0x69, 0x71, 0x75, 0x69, 0x70, 0x20, 0x65, 0x78, 0x20, 0x65, 0x61,
        0x20, 0x63, 0x6F, 0x6D, 0x6D, 0x6F, 0x64, 0x6F, 0x20, 0x0A, 0xA0, 0x00, 0xE5, 0x00, 0xBD, 0x00,
        0x31, 0x9B, 0xCA, 0x19, 0xC5, 0x54, 0xEC, 0xB6, 0x54, 0xE7, 0xB1, 0x7D, 0xC4, 0x57, 0x9E, 0x6C,
        0x89, 0xAD, 0x4A, 0x6D, 0x16, 0xD8, 0x3C, 0x05, 0x94, 0x10, 0x16, 0x99, 0x38, 0x21, 0xA3, 0xB9,
        0xC5, 0x80, 0xFF, 0xFC, 0xEE, 0xD4, 0xD5, 0x3F, 0xDD, 0x8C, 0xD7, 0x3D, 0x8F, 0x76, 0xEC, 0x88,
        0xAA, 0x32, 0xAB, 0x65, 0xD4, 0x38, 0xEF, 0xF7, 0xF9, 0x8A, 0xBF, 0xF7, 0xF8, 0xA5, 0x56, 0xD7,
        0x6D, 0xD7, 0x3F, 0x85, 0x0B, 0x9E, 0x3F, 0xE2, 0x47, 0x68, 0x22, 0x08, 0x05, 0x35, 0xB8, 0x41,
        0x72, 0xF9, 0xDB, 0xBE, 0xB7, 0x8E, 0x86, 0xBF, 0x43, 0x4B, 0x8E, 0x0D, 0x43, 0x2F, 0x41, 0x69,
        0xDF, 0x61, 0x0C, 0xC4, 0xE8, 0x37, 0x08, 0x4A, 0xDE, 0xC2, 0x76, 0x16, 0xB8, 0x48, 0x4E, 0x9E,
        0xB9, 0x53, 0x50, 0x1F, 0x33, 0x83, 0xE8, 0x29, 0xA0, 0x67, 0xC8, 0x66, 0x3A, 0x7F, 0x22, 0x12,
        0x62, 0xFB, 0x47, 0xE4, 0xBC, 0xF4, 0x51, 0x0F, 0x15, 0x88, 0x49, 0xD8, 0xCA, 0x0B, 0x25, 0x8B,
        0x5E, 0xE8, 0xDA, 0xFD, 0x38, 0xC0, 0xCE, 0x4C, 0x73, 0x1B, 0xFF, 0xD0, 0x9B, 0xE8, 0x4C, 0xB7,
        0x13, 0xF8, 0x37, 0x99, 0xE2, 0xDA, 0x9C, 0x2F, 0xB5, 0xEA, 0xB8, 0xA5, 0x8D, 0xEA, 0x57, 0x82,
        0x9B, 0x25, 0xCA, 0xFB, 0xF6, 0x88, 0x0A, 0x9B, 0xDF, 0x41, 0x03, 0x6E, 0x00, 0x00, 0x00, 0x00,
        0xB2, 0x07, 0x44, 0xE9, 0x17, 0x33, 0x4B, 0x84, 0x00, 0x01, 0xAA, 0x03, 0xC9, 0x03, 0x00, 0x00,
        0x50, 0x83, 0x71, 0x35, 0xB1, 0xC4, 0x67, 0xFB, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_lzma2_9)
{
    // "bad-1-lzma2-9.xz has LZMA2 stream that is truncated at the end of
    //  a LZMA2 chunk (no end marker). The uncompressed size of the partial
    //  LZMA2 stream exceeds the value stored in the Block Header."
    Array<u8, 72> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x03, 0xC0, 0x14, 0x0D,
        0x21, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x15, 0x10, 0x0D, 0x01, 0x00, 0x0C, 0x48,
        0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x02, 0xFF, 0xFF, 0x78,
        0x43, 0xA3, 0xA2, 0x15, 0x00, 0x01, 0x28, 0x0D, 0x3C, 0x67, 0x6A, 0x03, 0x90, 0x42, 0x99, 0x0D,
        0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_lzma2_10)
{
    // "bad-1-lzma2-10.xz has LZMA2 stream that, from point of view of a
    //  LZMA2 decoder, extends past the end of Block (and even the end of
    //  the file). Uncompressed Size in Block Header is bigger than the
    //  invalid LZMA2 stream may produce (even if a decoder reads until
    //  the end of the file). The Check type is None to nullify certain
    //  simple size-based sanity checks in a Block decoder."
    Array<u8, 60> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x00, 0xFF, 0x12, 0xD9, 0x41, 0x02, 0xC0, 0x10, 0x30,
        0x21, 0x01, 0x08, 0x00, 0xE6, 0xD5, 0x78, 0x98, 0x01, 0xFF, 0xFF, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x01, 0x1C, 0x30, 0xDA, 0xD8, 0x28, 0xE0,
        0x06, 0x72, 0x9E, 0x7A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_lzma2_11)
{
    // "bad-1-lzma2-11.xz has LZMA2 stream that lacks the end of
    //  payload marker. When Compressed Size bytes have been decoded,
    //  Uncompressed Size bytes of output will have been produced but
    //  the LZMA2 decoder doesn't indicate end of stream."
    Array<u8, 64> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x00, 0xFF, 0x12, 0xD9, 0x41, 0x03, 0xC0, 0x10, 0x0D,
        0x21, 0x01, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0xF7, 0x6A, 0x9F, 0x01, 0x00, 0x0C, 0x48,
        0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x01, 0x20, 0x0D,
        0x34, 0xED, 0xB3, 0xCB, 0x06, 0x72, 0x9E, 0x7A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_stream_flags_1)
{
    // "bad-1-stream_flags-1.xz has different Stream Flags in Stream Header
    //  and Stream Footer."
    Array<u8, 68> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x43, 0xA3, 0xA2, 0x15,
        0x00, 0x01, 0x24, 0x0D, 0x30, 0x28, 0xDF, 0xAF, 0x2A, 0x13, 0x90, 0x94, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x02, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_stream_flags_2)
{
    // "bad-1-stream_flags-2.xz has wrong CRC32 in Stream Header."
    Array<u8, 68> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x76, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x43, 0xA3, 0xA2, 0x15,
        0x00, 0x01, 0x24, 0x0D, 0x30, 0x28, 0xDF, 0xAF, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_stream_flags_3)
{
    // "bad-1-stream_flags-3.xz has wrong CRC32 in Stream Footer."
    Array<u8, 68> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x43, 0xA3, 0xA2, 0x15,
        0x00, 0x01, 0x24, 0x0D, 0x30, 0x28, 0xDF, 0xAF, 0x90, 0x42, 0x98, 0x0D, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_vli_1)
{
    // "bad-1-vli-1.xz has two-byte variable-length integer in the
    //  Uncompressed Size field in Block Header while one-byte would be enough
    //  for that value. It's important that the file gets rejected due to too
    //  big integer encoding instead of due to Uncompressed Size not matching
    //  the value stored in the Block Header. That is, the decoder must not
    //  try to decode the Compressed Data field."
    Array<u8, 72> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x03, 0x80, 0x8D, 0x00,
        0x21, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x48, 0xA9, 0x17, 0x01, 0x00, 0x0C, 0x48,
        0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x00, 0x00, 0x00,
        0x43, 0xA3, 0xA2, 0x15, 0x00, 0x01, 0x25, 0x0D, 0x71, 0x19, 0xC4, 0xB6, 0x90, 0x42, 0x99, 0x0D,
        0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_1_vli_2)
{
    // "bad-1-vli-2.xz has ten-byte variable-length integer as Uncompressed
    //  Size in Block Header. It's important that the file gets rejected due
    //  to too big integer encoding instead of due to Uncompressed Size not
    //  matching the value stored in the Block Header. That is, the decoder
    //  must not try to decode the Compressed Data field."
    Array<u8, 76> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x04, 0x80, 0x8D, 0x80,
        0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01, 0x21, 0x01, 0x08, 0x00, 0xD2, 0x64, 0xF0, 0x5C,
        0x01, 0x00, 0x0C, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A,
        0x00, 0x00, 0x00, 0x00, 0x43, 0xA3, 0xA2, 0x15, 0x00, 0x01, 0x29, 0x0D, 0x7D, 0x56, 0x71, 0x1A,
        0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_2_compressed_data_padding)
{
    // "bad-2-compressed_data_padding.xz has non-null byte in the padding of
    //  the Compressed Data field of the first Block."
    Array<u8, 92> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x00, 0x00, 0x01, 0x16, 0x35, 0x96, 0x31, 0x02, 0x00, 0x21, 0x01, 0x08, 0x00, 0x00, 0x00,
        0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x00,
        0xDD, 0xD1, 0xCA, 0x53, 0x00, 0x02, 0x1A, 0x06, 0x1B, 0x07, 0x00, 0x00, 0x06, 0xDC, 0xE7, 0x5D,
        0x3E, 0x30, 0x0D, 0x8B, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_2_index_1)
{
    // "bad-2-index-1.xz has wrong Unpadded Sizes in Index."
    Array<u8, 92> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x00, 0x00, 0x00, 0x16, 0x35, 0x96, 0x31, 0x02, 0x00, 0x21, 0x01, 0x08, 0x00, 0x00, 0x00,
        0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x00,
        0xDD, 0xD1, 0xCA, 0x53, 0x00, 0x02, 0x1B, 0x06, 0x1A, 0x07, 0x00, 0x00, 0xC6, 0x68, 0x07, 0x2E,
        0x3E, 0x30, 0x0D, 0x8B, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_2_index_2)
{
    // "bad-2-index-2.xz has wrong Uncompressed Sizes in Index."
    Array<u8, 92> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x00, 0x00, 0x00, 0x16, 0x35, 0x96, 0x31, 0x02, 0x00, 0x21, 0x01, 0x08, 0x00, 0x00, 0x00,
        0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x00,
        0xDD, 0xD1, 0xCA, 0x53, 0x00, 0x02, 0x1A, 0x0D, 0x1B, 0x00, 0x00, 0x00, 0x92, 0xFB, 0x78, 0x2F,
        0x3E, 0x30, 0x0D, 0x8B, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_2_index_3)
{
    // "bad-2-index-3.xz has non-null byte in Index Padding."
    Array<u8, 92> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x00, 0x00, 0x00, 0x16, 0x35, 0x96, 0x31, 0x02, 0x00, 0x21, 0x01, 0x08, 0x00, 0x00, 0x00,
        0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x00,
        0xDD, 0xD1, 0xCA, 0x53, 0x00, 0x02, 0x1A, 0x06, 0x1B, 0x07, 0x00, 0x01, 0x90, 0xEC, 0xE0, 0x2A,
        0x3E, 0x30, 0x0D, 0x8B, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_2_index_4)
{
    // "bad-2-index-4.xz wrong CRC32 in Index."
    Array<u8, 92> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x00, 0x00, 0x00, 0x16, 0x35, 0x96, 0x31, 0x02, 0x00, 0x21, 0x01, 0x08, 0x00, 0x00, 0x00,
        0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x00,
        0xDD, 0xD1, 0xCA, 0x53, 0x00, 0x02, 0x1A, 0x06, 0x1B, 0x07, 0x00, 0x00, 0x06, 0xDC, 0xE7, 0x5C,
        0x3E, 0x30, 0x0D, 0x8B, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    // TODO: The index is currently not checked against the stored CRC32.
    (void)decompressor->read_until_eof(PAGE_SIZE);
}

TEST_CASE(xz_utils_bad_2_index_5)
{
    // "bad-2-index-5.xz has zero as Unpadded Size. It is important that the
    //  file gets rejected specifically due to Unpadded Size having an invalid
    //  value."
    Array<u8, 92> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x00, 0x00, 0x00, 0x16, 0x35, 0x96, 0x31, 0x02, 0x00, 0x21, 0x01, 0x08, 0x00, 0x00, 0x00,
        0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x00,
        0xDD, 0xD1, 0xCA, 0x53, 0x00, 0x02, 0x35, 0x06, 0x00, 0x07, 0x00, 0x00, 0x7B, 0xBB, 0x05, 0x2C,
        0x3E, 0x30, 0x0D, 0x8B, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_bad_3_index_uncomp_overflow)
{
    // "bad-3-index-uncomp-overflow.xz has Index whose Uncompressed Size
    //  fields have huge values whose sum exceeds the maximum allowed size
    //  of 2^63 - 1 bytes. In this file the sum is exactly 2^64."
    Array<u8, 132> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x0C, 0x00, 0x00, 0x00, 0x8F, 0x98, 0x41, 0x9C, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x00, 0x00, 0x00, 0x16, 0x35, 0x96, 0x31, 0x02, 0x00, 0x21, 0x01, 0x0C, 0x00, 0x00, 0x00,
        0x8F, 0x98, 0x41, 0x9C, 0x01, 0x00, 0x04, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x00, 0x00, 0x00, 0x00,
        0x47, 0x3E, 0xB6, 0xFB, 0x02, 0x00, 0x21, 0x01, 0x0C, 0x00, 0x00, 0x00, 0x8F, 0x98, 0x41, 0x9C,
        0x01, 0x00, 0x01, 0x21, 0x0A, 0x00, 0x00, 0x00, 0x02, 0xEE, 0x93, 0x2D, 0x00, 0x03, 0x1A, 0xFF,
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
        0xFF, 0x7F, 0x16, 0x02, 0x32, 0x89, 0xCE, 0x34, 0x28, 0x72, 0x9C, 0x10, 0x06, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

auto const xz_utils_hello_world = "Hello\nWorld!\n"sv;
auto const xz_utils_lorem_ipsum = R"(Lorem ipsum dolor sit amet, consectetur adipisicing 
elit, sed do eiusmod tempor incididunt ut 
labore et dolore magna aliqua. Ut enim 
ad minim veniam, quis nostrud exercitation ullamco 
laboris nisi ut aliquip ex ea commodo 
consequat. Duis aute irure dolor in reprehenderit 
in voluptate velit esse cillum dolore eu 
fugiat nulla pariatur. Excepteur sint occaecat cupidatat 
non proident, sunt in culpa qui officia 
deserunt mollit anim id est laborum. 
)"sv;

// The reference data is split into parts, since the binary contains a lot of filler data.
Array<u8, 112> const xz_utils_arm64_binary_part1 {
    0x00, 0x00, 0x00, 0x94, // bl #0x0
    0xFF, 0xFF, 0xFF, 0x97, // bl #0x0
    0xFE, 0xFF, 0xFF, 0x97, // bl #0x0
    0xFD, 0xFF, 0xFF, 0x97, // bl #0x0
    0x03, 0x00, 0x00, 0x94, // bl #0x1c
    0x02, 0x00, 0x00, 0x94, // bl #0x1c
    0x01, 0x00, 0x00, 0x94, // bl #0x1c
    0x00, 0x00, 0x00, 0x94, // bl #0x1c
    0x01, 0x00, 0x00, 0x96, // bl #0xfffffffff8000024
    0x00, 0x00, 0x00, 0x96, // bl #0xfffffffff8000024
    0xFF, 0xFF, 0xFF, 0x95, // bl #0x8000024
    0xFE, 0xFF, 0xFF, 0x95, // bl #0x8000024
    0x17, 0x11, 0x11, 0x95, // bl #0x444448c
    0x16, 0x11, 0x11, 0x95, // bl #0x444448c
    0x15, 0x11, 0x11, 0x95, // bl #0x444448c
    0x14, 0x11, 0x11, 0x95, // bl #0x444448c
    0x27, 0x22, 0x22, 0x96, // bl #0xfffffffff88888dc
    0x26, 0x22, 0x22, 0x96, // bl #0xfffffffff88888dc
    0x25, 0x22, 0x22, 0x96, // bl #0xfffffffff88888dc
    0x24, 0x22, 0x22, 0x96, // bl #0xfffffffff88888dc
    0xEC, 0xFF, 0xFF, 0x97, // bl #0x0
    0xEB, 0xFF, 0xFF, 0x97, // bl #0x0
    0xEA, 0xFF, 0xFF, 0x97, // bl #0x0
    0xE9, 0xFF, 0xFF, 0x97, // bl #0x0
    0x03, 0x00, 0x00, 0x90, // adrp x3, #0x0
    0x28, 0x00, 0x00, 0xB0, // adrp x8, #0x5000
    0xAD, 0x00, 0x00, 0xB0, // adrp x13, #0x15000
    0x32, 0x01, 0x00, 0xB0  // adrp x18, #0x25000
};
Array<u8, 3984> const xz_utils_arm64_binary_part2 = Array<u8, 3984>::from_repeated_value(0x55);
Array<u8, 384> const xz_utils_arm64_binary_part3 {
    0x0B, 0x10, 0x00, 0x90, // adrp x11, #0x200000
    0x30, 0x10, 0x00, 0xB0, // adrp x16, #0x205000
    0xF5, 0x17, 0x00, 0xD0, // adrp x21, #0x2fe000
    0xFA, 0x17, 0x00, 0xF0, // adrp x26, #0x2ff000
    0x1F, 0x18, 0x00, 0x90, // adrp xzr, #0x300000
    0x24, 0x18, 0x00, 0xB0, // adrp x4, #0x305000
    0xE9, 0x1F, 0x00, 0xD0, // adrp x9, #0x3fe000
    0xEE, 0x1F, 0x00, 0xF0, // adrp x14, #0x3ff000
    0x13, 0x20, 0x00, 0x90, // adrp x19, #0x400000
    0x38, 0x20, 0x00, 0xB0, // adrp x24, #0x405000
    0xFD, 0x27, 0x00, 0xD0, // adrp x29, #0x4fe000
    0xE2, 0x27, 0x00, 0xF0, // adrp x2, #0x4ff000
    0x07, 0x38, 0x00, 0x90, // adrp x7, #0x700000
    0x2C, 0x38, 0x00, 0xB0, // adrp x12, #0x705000
    0xF1, 0x3F, 0x00, 0xD0, // adrp x17, #0x7fe000
    0xF6, 0x3F, 0x00, 0xF0, // adrp x22, #0x7ff000
    0x1B, 0x40, 0x00, 0x90, // adrp x27, #0x800000
    0x20, 0x40, 0x00, 0xB0, // adrp x0, #0x805000
    0xE5, 0x47, 0x00, 0xD0, // adrp x5, #0x8fe000
    0xEA, 0x47, 0x00, 0xF0, // adrp x10, #0x8ff000
    0x0F, 0x78, 0x00, 0x90, // adrp x15, #0xf00000
    0x34, 0x78, 0x00, 0xB0, // adrp x20, #0xf05000
    0xF9, 0x7F, 0x00, 0xD0, // adrp x25, #0xffe000
    0xFE, 0x7F, 0x00, 0xF0, // adrp x30, #0xfff000
    0x03, 0x80, 0x00, 0x90, // adrp x3, #0x1000000
    0x28, 0x80, 0x00, 0xB0, // adrp x8, #0x1005000
    0xED, 0x87, 0x00, 0xD0, // adrp x13, #0x10fe000
    0xF2, 0x87, 0x00, 0xF0, // adrp x18, #0x10ff000
    0x17, 0xF8, 0x00, 0x90, // adrp x23, #0x1f00000
    0x3C, 0xF8, 0x00, 0xB0, // adrp x28, #0x1f05000
    0xE1, 0xFF, 0x00, 0xD0, // adrp x1, #0x1ffe000
    0xE6, 0xFF, 0x00, 0xF0, // adrp x6, #0x1fff000
    0x0B, 0x00, 0x01, 0x90, // adrp x11, #0x2000000
    0x30, 0x00, 0x01, 0xB0, // adrp x16, #0x2005000
    0xF5, 0x07, 0x01, 0xD0, // adrp x21, #0x20fe000
    0xFA, 0x07, 0x01, 0xF0, // adrp x26, #0x20ff000
    0x1F, 0xF8, 0x01, 0x90, // adrp xzr, #0x3f00000
    0x24, 0xF8, 0x01, 0xB0, // adrp x4, #0x3f05000
    0xE9, 0xFF, 0x01, 0xD0, // adrp x9, #0x3ffe000
    0xEE, 0xFF, 0x01, 0xF0, // adrp x14, #0x3fff000
    0x13, 0x00, 0x02, 0x90, // adrp x19, #0x4000000
    0x38, 0x00, 0x02, 0xB0, // adrp x24, #0x4005000
    0xFD, 0x07, 0x02, 0xD0, // adrp x29, #0x40fe000
    0xE2, 0x07, 0x02, 0xF0, // adrp x2, #0x40ff000
    0x07, 0xF8, 0x03, 0x90, // adrp x7, #0x7f00000
    0x2C, 0xF8, 0x03, 0xB0, // adrp x12, #0x7f05000
    0xF1, 0xFF, 0x03, 0xD0, // adrp x17, #0x7ffe000
    0xF6, 0xFF, 0x03, 0xF0, // adrp x22, #0x7fff000
    0x1B, 0x00, 0x04, 0x90, // adrp x27, #0x8000000
    0x20, 0x00, 0x04, 0xB0, // adrp x0, #0x8005000
    0xE5, 0x07, 0x04, 0xD0, // adrp x5, #0x80fe000
    0xEA, 0x07, 0x04, 0xF0, // adrp x10, #0x80ff000
    0x0F, 0xF8, 0x07, 0x90, // adrp x15, #0xff00000
    0x34, 0xF8, 0x07, 0xB0, // adrp x20, #0xff05000
    0xF9, 0xFF, 0x07, 0xD0, // adrp x25, #0xfffe000
    0xFE, 0xFF, 0x07, 0xF0, // adrp x30, #0xffff000
    0x03, 0x00, 0x08, 0x90, // adrp x3, #0x10000000
    0x28, 0x00, 0x08, 0xB0, // adrp x8, #0x10005000
    0xED, 0x07, 0x08, 0xD0, // adrp x13, #0x100fe000
    0xF2, 0x07, 0x08, 0xF0, // adrp x18, #0x100ff000
    0x17, 0xF8, 0x0F, 0x90, // adrp x23, #0x1ff00000
    0x3C, 0xF8, 0x0F, 0xB0, // adrp x28, #0x1ff05000
    0xE1, 0xFF, 0x0F, 0xD0, // adrp x1, #0x1fffe000
    0xE6, 0xFF, 0x0F, 0xF0, // adrp x6, #0x1ffff000
    0x0B, 0x00, 0x10, 0x90, // adrp x11, #0x20000000
    0x30, 0x00, 0x10, 0xB0, // adrp x16, #0x20005000
    0xF5, 0x07, 0x10, 0xD0, // adrp x21, #0x200fe000
    0xFA, 0x07, 0x10, 0xF0, // adrp x26, #0x200ff000
    0x1F, 0xF8, 0x1F, 0x90, // adrp xzr, #0x3ff00000
    0x24, 0xF8, 0x1F, 0xB0, // adrp x4, #0x3ff05000
    0xE9, 0xFF, 0x1F, 0xD0, // adrp x9, #0x3fffe000
    0xEE, 0xFF, 0x1F, 0xF0, // adrp x14, #0x3ffff000
    0x13, 0x00, 0x20, 0x90, // adrp x19, #0x40000000
    0x38, 0x00, 0x20, 0xB0, // adrp x24, #0x40005000
    0xFD, 0x07, 0x20, 0xD0, // adrp x29, #0x400fe000
    0xE2, 0x07, 0x20, 0xF0, // adrp x2, #0x400ff000
    0x07, 0xF8, 0x3F, 0x90, // adrp x7, #0x7ff00000
    0x2C, 0xF8, 0x3F, 0xB0, // adrp x12, #0x7ff05000
    0xF1, 0xFF, 0x3F, 0xD0, // adrp x17, #0x7fffe000
    0xF6, 0xFF, 0x3F, 0xF0, // adrp x22, #0x7ffff000
    0x1B, 0x00, 0x40, 0x90, // adrp x27, #0x80000000
    0x20, 0x00, 0x40, 0xB0, // adrp x0, #0x80005000
    0xE5, 0x07, 0x40, 0xD0, // adrp x5, #0x800fe000
    0xEA, 0x07, 0x40, 0xF0, // adrp x10, #0x800ff000
    0x0F, 0xF8, 0x7F, 0x90, // adrp x15, #0xfff00000
    0x34, 0xF8, 0x7F, 0xB0, // adrp x20, #0xfff05000
    0xF9, 0xFF, 0x7F, 0xD0, // adrp x25, #0xffffe000
    0xFE, 0xFF, 0x7F, 0xF0, // adrp x30, #0xfffff000
    0x03, 0x00, 0x80, 0x90, // adrp x3, #0xffffffff00000000
    0x28, 0x00, 0x80, 0xB0, // adrp x8, #0xffffffff00005000
    0xED, 0x07, 0x80, 0xD0, // adrp x13, #0xffffffff000fe000
    0xF2, 0x07, 0x80, 0xF0, // adrp x18, #0xffffffff000ff000
    0x17, 0xF8, 0xFF, 0x90, // adrp x23, #0xfffffffffff00000
    0x3C, 0xF8, 0xFF, 0xB0, // adrp x28, #0xfffffffffff05000
    0xE1, 0xFF, 0xFF, 0xD0, // adrp x1, #0xffffffffffffe000
    0xE6, 0xFF, 0xFF, 0xF0  // adrp x6, #0xfffffffffffff000
};
Array<u8, 3712> const xz_utils_arm64_binary_part4 = Array<u8, 3712>::from_repeated_value(0x55);
Array<u8, 384> const xz_utils_arm64_binary_part5 = xz_utils_arm64_binary_part3;

TEST_CASE(xz_utils_good_0cat_empty)
{
    // "good-0cat-empty.xz has two zero-Block Streams concatenated without
    //  Stream Padding."
    Array<u8, 64> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x00, 0x00, 0x00, 0x00,
        0x1C, 0xDF, 0x44, 0x21, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A,
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x00, 0x00, 0x00, 0x00,
        0x1C, 0xDF, 0x44, 0x21, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.size(), 0ul);
}

TEST_CASE(xz_utils_good_0catpad_empty)
{
    // "good-0catpad-empty.xz has two zero-Block Streams concatenated with
    //  four-byte Stream Padding between the Streams."
    Array<u8, 68> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x00, 0x00, 0x00, 0x00,
        0x1C, 0xDF, 0x44, 0x21, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A,
        0x00, 0x00, 0x00, 0x00, 0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36,
        0x00, 0x00, 0x00, 0x00, 0x1C, 0xDF, 0x44, 0x21, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.size(), 0ul);
}

TEST_CASE(xz_utils_good_0_empty)
{
    // "good-0-empty.xz has one Stream with no Blocks."
    Array<u8, 32> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x00, 0x00, 0x00, 0x00,
        0x1C, 0xDF, 0x44, 0x21, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.size(), 0ul);
}

TEST_CASE(xz_utils_good_0pad_empty)
{
    // "good-0pad-empty.xz has one Stream with no Blocks followed by
    //  four-byte Stream Padding."
    Array<u8, 36> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x00, 0x00, 0x00, 0x00,
        0x1C, 0xDF, 0x44, 0x21, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A,
        0x00, 0x00, 0x00, 0x00
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.size(), 0ul);
}

TEST_CASE(xz_utils_good_1_3delta_lzma2)
{
    // "good-1-3delta-lzma2.xz has three Delta filters and LZMA2."
    Array<u8, 528> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x04, 0xE6, 0xD6, 0xB4, 0x46, 0x04, 0x03, 0x03, 0x01,
        0x00, 0x03, 0x01, 0x01, 0x03, 0x01, 0x02, 0x21, 0x01, 0x08, 0x00, 0x00, 0xBC, 0x15, 0x65, 0xC6,
        0x01, 0x01, 0xC8, 0x4C, 0x23, 0xB7, 0x84, 0xE2, 0x09, 0x71, 0x4F, 0xFA, 0xBA, 0xA1, 0xF7, 0x51,
        0x63, 0x08, 0xAC, 0xAE, 0xF2, 0x58, 0x42, 0x0D, 0x66, 0xEE, 0xA8, 0x01, 0xCD, 0x60, 0x2E, 0x88,
        0x58, 0xD7, 0x6E, 0xDB, 0x3D, 0x26, 0x00, 0x05, 0xF1, 0xFB, 0xAF, 0x34, 0x67, 0x17, 0xC0, 0x9F,
        0x3F, 0xF9, 0xFC, 0x0D, 0x0E, 0x03, 0xA4, 0xE6, 0xAF, 0x69, 0xB1, 0x62, 0x9E, 0x47, 0x97, 0x43,
        0xC3, 0x2F, 0x47, 0xA3, 0xA3, 0xF5, 0x04, 0x5A, 0xC0, 0x9B, 0x3D, 0x01, 0xCC, 0x5B, 0x3A, 0xFA,
        0xB3, 0xC2, 0x4C, 0x9D, 0x4F, 0x57, 0xFD, 0xBB, 0xAF, 0x53, 0xFF, 0x06, 0xFF, 0xF5, 0xA7, 0x51,
        0x5E, 0xA4, 0x9C, 0x63, 0xB4, 0xB4, 0x62, 0xF7, 0x47, 0xA0, 0x50, 0x6E, 0xAF, 0xE3, 0x0B, 0x52,
        0xC3, 0xA7, 0x37, 0xC0, 0x54, 0x49, 0x01, 0xB9, 0xB4, 0xFF, 0x3B, 0x5F, 0x04, 0xAF, 0xBB, 0x28,
        0xCC, 0xFF, 0x84, 0x64, 0x71, 0xBE, 0x30, 0x3F, 0xD5, 0x5B, 0x30, 0xA9, 0x61, 0x7F, 0xA6, 0x27,
        0x53, 0xB5, 0xBF, 0x00, 0x53, 0x3D, 0xFB, 0xBA, 0xB3, 0x5E, 0xBB, 0xF9, 0x81, 0x49, 0xBB, 0x74,
        0xA9, 0xA1, 0x4E, 0xFD, 0xBC, 0xA6, 0x4C, 0xF1, 0xBF, 0x54, 0x66, 0xEF, 0xA4, 0xAD, 0x51, 0x20,
        0xE3, 0x0F, 0xEE, 0x0C, 0x02, 0xA4, 0x63, 0x3B, 0xFF, 0xA8, 0xC7, 0x56, 0x02, 0xAF, 0xDD, 0xB1,
        0x50, 0xC1, 0x67, 0xF7, 0x4B, 0xEF, 0xB4, 0x5A, 0x47, 0x06, 0xB7, 0x5F, 0xA3, 0x4D, 0xAA, 0xE3,
        0x17, 0x65, 0xBB, 0xA8, 0x30, 0x06, 0xB5, 0x52, 0x60, 0xA7, 0xF4, 0xF1, 0x17, 0x15, 0xF9, 0x41,
        0xAD, 0xB7, 0x3A, 0x15, 0xB8, 0xEA, 0x9F, 0x66, 0xC7, 0x51, 0xD1, 0x61, 0x19, 0xED, 0x08, 0xBC,
        0xFF, 0x5B, 0x71, 0xF1, 0x6F, 0x7A, 0x67, 0x8E, 0x05, 0xA6, 0x55, 0x9A, 0x71, 0xFE, 0x9C, 0xA2,
        0x04, 0x5D, 0x60, 0xFB, 0xA7, 0xB6, 0xF2, 0x4E, 0x51, 0xBE, 0x07, 0xEA, 0x50, 0xC2, 0xA7, 0x48,
        0xFB, 0x1E, 0xF8, 0xEE, 0x11, 0xFD, 0x06, 0x9E, 0xE9, 0xB5, 0x66, 0x74, 0x9E, 0x2C, 0x54, 0xBF,
        0xB7, 0x54, 0xE2, 0x11, 0x09, 0xB6, 0x56, 0x30, 0x09, 0xA9, 0xD0, 0xFE, 0x2C, 0x5E, 0x0C, 0xAA,
        0x59, 0x96, 0x67, 0x05, 0xA9, 0xBB, 0x38, 0xB0, 0x46, 0x60, 0x0F, 0xAC, 0xAE, 0x37, 0xC0, 0x4C,
        0x65, 0xAE, 0x88, 0x5C, 0xBF, 0xBC, 0x42, 0xE1, 0x7B, 0xC1, 0x35, 0x4A, 0xF5, 0xBE, 0xA3, 0x16,
        0x62, 0x34, 0x02, 0xAB, 0xB5, 0x5B, 0x03, 0x03, 0x9F, 0xEC, 0x7F, 0x86, 0xD1, 0x66, 0xDF, 0x3C,
        0x17, 0xEC, 0x0A, 0xB8, 0x4A, 0x3C, 0x14, 0xBA, 0x5F, 0x97, 0x38, 0x0A, 0xC1, 0xBC, 0x4F, 0xF0,
        0x11, 0xAE, 0x36, 0x51, 0x0A, 0xB7, 0x9A, 0x4C, 0x31, 0xF0, 0xFC, 0xA7, 0xE7, 0xB8, 0x58, 0xC4,
        0xF9, 0x3A, 0xB5, 0xFC, 0xA7, 0xAE, 0x5A, 0x16, 0x07, 0xA8, 0xE0, 0x96, 0x5F, 0xB8, 0x69, 0xA5,
        0x9D, 0x55, 0xB6, 0xFB, 0x07, 0x4B, 0xB4, 0x9A, 0x07, 0x6E, 0x4B, 0xE8, 0x53, 0x16, 0x9D, 0xFE,
        0xB1, 0xBA, 0x52, 0xF2, 0xBF, 0xEF, 0x9D, 0x5E, 0xC2, 0x56, 0xE8, 0x5D, 0xFB, 0x04, 0xA2, 0x5B,
        0x53, 0xFD, 0xB7, 0xAA, 0x5B, 0xB1, 0x36, 0x56, 0x0B, 0xC1, 0x57, 0x8B, 0x51, 0xBB, 0x05, 0x0A,
        0x49, 0x54, 0xF9, 0x8D, 0x17, 0xCD, 0xB9, 0x41, 0xDD, 0xBC, 0x04, 0x34, 0x00, 0x00, 0x00, 0x00,
        0xB2, 0x07, 0x44, 0xE9, 0x17, 0x33, 0x4B, 0x84, 0x00, 0x01, 0xE9, 0x03, 0xC9, 0x03, 0x00, 0x00,
        0x92, 0xFB, 0xBD, 0xBC, 0xB1, 0xC4, 0x67, 0xFB, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.span(), xz_utils_lorem_ipsum.bytes());
}

TEST_CASE(xz_utils_good_1_arm64_lzma2_1)
{
    // "good-1-arm64-lzma2-1.xz uses the ARM64 filter and LZMA2. The
    //  uncompressed data is constructed so that it tests integer
    //  wrap around and sign extension."
    Array<u8, 512> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x01, 0x0A, 0x00,
        0x21, 0x01, 0x08, 0x00, 0xA2, 0xD8, 0x7E, 0xF1, 0xE0, 0x21, 0x7F, 0x01, 0xC3, 0x6E, 0x00, 0x00,
        0x68, 0x23, 0x88, 0x71, 0x63, 0xC2, 0x8F, 0x53, 0x0A, 0xE6, 0xB1, 0xDF, 0xD0, 0x8A, 0xAE, 0x1B,
        0xA1, 0xB0, 0x78, 0xAB, 0x28, 0x43, 0x13, 0x5E, 0x7F, 0xE4, 0x97, 0xC5, 0x69, 0xCF, 0xC1, 0x0A,
        0xCD, 0xDA, 0x89, 0x2E, 0x3A, 0x9E, 0xF2, 0xAC, 0x4F, 0x83, 0xDC, 0x79, 0xB5, 0x0B, 0xC3, 0xFB,
        0xF1, 0xF8, 0x14, 0x14, 0xBA, 0xA1, 0xF6, 0xC3, 0x11, 0x97, 0x9E, 0x53, 0x71, 0x7A, 0x6B, 0x4D,
        0xDE, 0x7F, 0xAB, 0xB5, 0x81, 0x19, 0xD2, 0x87, 0xB3, 0x8E, 0x59, 0xCC, 0xAD, 0x32, 0xF5, 0x73,
        0x9A, 0x90, 0x0D, 0x99, 0x7D, 0x46, 0x55, 0x52, 0xA0, 0x15, 0x03, 0xE7, 0x1C, 0xF0, 0x97, 0x4F,
        0xAF, 0xC1, 0x8B, 0xCA, 0x2B, 0x76, 0x63, 0xC6, 0xD3, 0xDC, 0x68, 0xD9, 0xBF, 0x04, 0x20, 0x1A,
        0x1D, 0x80, 0x25, 0x28, 0x83, 0x30, 0x32, 0xA3, 0x64, 0xE4, 0x26, 0xDD, 0xC0, 0x16, 0xD6, 0x8B,
        0xB0, 0x11, 0x37, 0x88, 0xBD, 0xE2, 0xD9, 0xBC, 0x2D, 0xB7, 0x45, 0x3C, 0xCA, 0x5A, 0x0F, 0xAA,
        0x26, 0x98, 0x9D, 0xB9, 0xF8, 0x18, 0xA3, 0x55, 0xCD, 0xAE, 0x02, 0x30, 0x27, 0xF2, 0x62, 0xA8,
        0x0D, 0x0D, 0x20, 0x4D, 0xB1, 0x80, 0xAA, 0x48, 0x92, 0x7C, 0x98, 0x99, 0x5A, 0x8E, 0x0F, 0x5F,
        0xF8, 0x58, 0x7E, 0x5F, 0x79, 0x36, 0xF3, 0xD8, 0x3C, 0xEF, 0x03, 0xD4, 0x50, 0x2A, 0xB7, 0xC9,
        0x3A, 0x3C, 0xA6, 0xEB, 0x33, 0x8A, 0xD7, 0xFB, 0x8C, 0xBE, 0x31, 0xD3, 0x76, 0x72, 0x2E, 0x6B,
        0x89, 0x1F, 0x27, 0x74, 0xE1, 0x02, 0xF7, 0x5D, 0x1E, 0x59, 0xE0, 0x6F, 0xE1, 0xDD, 0xCC, 0xF9,
        0x90, 0xCB, 0x27, 0x59, 0xA0, 0xA3, 0x6F, 0x96, 0x73, 0x82, 0xCF, 0x4D, 0x71, 0x21, 0x1E, 0x4E,
        0xBF, 0xCF, 0xD0, 0x29, 0xB2, 0xCF, 0x56, 0x6E, 0x21, 0x8F, 0xC8, 0x77, 0x95, 0xEB, 0x6A, 0xEF,
        0x3C, 0xDC, 0x00, 0x76, 0xB0, 0x94, 0x63, 0x70, 0x8C, 0x94, 0x5F, 0x7F, 0x1F, 0x83, 0xF9, 0x1F,
        0xCE, 0x64, 0x4F, 0x45, 0xBD, 0xF8, 0x13, 0x5A, 0x78, 0x0C, 0x1A, 0xDF, 0xE4, 0x0B, 0xDC, 0xBA,
        0x07, 0x33, 0xEC, 0x53, 0xA9, 0xFB, 0x31, 0xE5, 0xCC, 0xC3, 0x87, 0x95, 0x90, 0xF5, 0x93, 0x8E,
        0x02, 0xEE, 0xE3, 0x56, 0xA6, 0xF9, 0xD3, 0xA3, 0x78, 0xA5, 0x08, 0x24, 0xBC, 0x1E, 0x2A, 0xA9,
        0x99, 0x78, 0x4B, 0xE8, 0xBB, 0x73, 0x47, 0xCE, 0x08, 0x0C, 0x5A, 0x01, 0xCE, 0xE1, 0xC5, 0x9D,
        0x85, 0xDC, 0xD4, 0x19, 0x59, 0xB5, 0x3D, 0xAF, 0xF5, 0xA4, 0xCF, 0x66, 0x12, 0xFD, 0x5B, 0xFE,
        0x0A, 0x7A, 0xEE, 0xF7, 0x61, 0x81, 0x0A, 0x06, 0x09, 0x5D, 0xCB, 0x10, 0xC5, 0x6F, 0x68, 0x4F,
        0xED, 0xED, 0x97, 0xC7, 0x37, 0x1F, 0xDE, 0x6D, 0x2D, 0xC2, 0x26, 0xA0, 0xE6, 0x94, 0x18, 0x06,
        0xC3, 0xA8, 0xC0, 0x0F, 0x4C, 0xE3, 0x1C, 0x0A, 0x9B, 0x03, 0xF7, 0x10, 0xB6, 0x81, 0xAB, 0x8A,
        0x5D, 0xAE, 0x0C, 0xAA, 0xA8, 0xAB, 0xB1, 0x65, 0x55, 0x7F, 0x33, 0x52, 0xF6, 0x23, 0x0F, 0xAC,
        0x21, 0xA4, 0xC5, 0xF1, 0x44, 0x9D, 0xE0, 0xB7, 0x39, 0x6D, 0x2D, 0x48, 0x20, 0x8C, 0x81, 0x51,
        0x50, 0x60, 0xEF, 0xA1, 0x00, 0x71, 0xD9, 0xE3, 0xB5, 0x4F, 0xFD, 0x57, 0xB6, 0x0E, 0xFC, 0x40,
        0x48, 0xD3, 0x00, 0x00, 0xA0, 0x7C, 0xE1, 0xD4, 0x00, 0x01, 0xDB, 0x03, 0x80, 0x43, 0x00, 0x00,
        0x43, 0xC7, 0x89, 0x63, 0x3E, 0x30, 0x0D, 0x8B, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    auto span = buffer.span();

    EXPECT_EQ(span.trim(xz_utils_arm64_binary_part1.size()), xz_utils_arm64_binary_part1.span());
    span = span.slice(xz_utils_arm64_binary_part1.size());

    EXPECT_EQ(span.trim(xz_utils_arm64_binary_part2.size()), xz_utils_arm64_binary_part2.span());
    span = span.slice(xz_utils_arm64_binary_part2.size());

    EXPECT_EQ(span.trim(xz_utils_arm64_binary_part3.size()), xz_utils_arm64_binary_part3.span());
    span = span.slice(xz_utils_arm64_binary_part3.size());

    EXPECT_EQ(span.trim(xz_utils_arm64_binary_part4.size()), xz_utils_arm64_binary_part4.span());
    span = span.slice(xz_utils_arm64_binary_part4.size());

    EXPECT_EQ(span.trim(xz_utils_arm64_binary_part5.size()), xz_utils_arm64_binary_part5.span());
    span = span.slice(xz_utils_arm64_binary_part5.size());

    EXPECT_EQ(span.size(), 0ul);
}

TEST_CASE(xz_utils_good_1_arm64_lzma2_2)
{
    // "good-1-arm64-lzma2-2.xz is like good-1-arm64-lzma2-1.xz but with
    //  non-zero start offset."
    Array<u8, 512> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x03, 0x01, 0x0A, 0x04,
        0x00, 0xF0, 0xFF, 0xFF, 0x21, 0x01, 0x08, 0x00, 0x67, 0x74, 0x40, 0x1C, 0xE0, 0x21, 0x7F, 0x01,
        0xA6, 0x6E, 0x00, 0x00, 0x3F, 0x1E, 0xEC, 0xFA, 0xC9, 0x8B, 0xE0, 0xE3, 0xD4, 0xE5, 0xEC, 0x75,
        0x8B, 0x62, 0x01, 0xD1, 0xB9, 0xAE, 0x17, 0xB3, 0xE1, 0x01, 0x82, 0xB1, 0x88, 0x36, 0x96, 0x7C,
        0xD3, 0x5E, 0x60, 0x14, 0x52, 0xE3, 0xD7, 0x99, 0x0D, 0x4E, 0x26, 0x37, 0x2E, 0xAA, 0xF2, 0xAE,
        0x49, 0x93, 0xF8, 0xCF, 0x48, 0x00, 0xAF, 0x88, 0xFE, 0x05, 0x57, 0xE7, 0x5C, 0xB8, 0x85, 0xAA,
        0x38, 0x18, 0x49, 0x6D, 0x35, 0xC7, 0x64, 0xC5, 0xD5, 0x19, 0xAB, 0x99, 0x05, 0x8F, 0x64, 0x29,
        0x5B, 0x39, 0xE3, 0x0A, 0xC0, 0x1C, 0xE6, 0x69, 0xF4, 0x7A, 0xCC, 0x0A, 0x06, 0xDD, 0xE5, 0x26,
        0x53, 0xC9, 0xA9, 0xAF, 0x2F, 0x44, 0x22, 0x3D, 0xE5, 0x96, 0x3B, 0x40, 0x50, 0xE5, 0x00, 0xE1,
        0xF3, 0x8E, 0x02, 0x10, 0xA7, 0xA7, 0x3F, 0x43, 0x22, 0x2D, 0xC1, 0xAA, 0x2F, 0x3A, 0xDA, 0xE7,
        0xBD, 0x72, 0xD4, 0x86, 0xD6, 0x16, 0x22, 0x35, 0xE3, 0x2D, 0x4F, 0x05, 0xF3, 0xE6, 0x36, 0x16,
        0xB5, 0x98, 0x6D, 0x56, 0x65, 0x47, 0x66, 0x0F, 0x35, 0x93, 0xA2, 0xFE, 0xE0, 0x2F, 0x34, 0xAD,
        0xE9, 0x34, 0x05, 0x79, 0x4D, 0x8A, 0x10, 0xF1, 0xDA, 0xF3, 0xA7, 0xC8, 0xD7, 0x24, 0xEC, 0x29,
        0xD7, 0x7B, 0xDC, 0x39, 0xE5, 0xAC, 0x30, 0xE7, 0x3D, 0x8F, 0xC2, 0x33, 0x6A, 0x63, 0x53, 0x0A,
        0xD6, 0xF0, 0x45, 0xBA, 0x92, 0xFF, 0x31, 0xCC, 0x3F, 0x55, 0x6F, 0xE8, 0xC7, 0xF0, 0xFC, 0x9C,
        0xA2, 0xEF, 0x4B, 0x6C, 0xCF, 0x67, 0xD9, 0xAF, 0x7C, 0x1D, 0xB8, 0x39, 0xFB, 0x48, 0xC6, 0x0D,
        0x7D, 0x97, 0x73, 0xB9, 0x58, 0x18, 0x20, 0x51, 0x86, 0xF1, 0x70, 0xD6, 0x7E, 0x3B, 0xAA, 0xFB,
        0x2B, 0x0E, 0x9A, 0x99, 0x26, 0x58, 0x71, 0x8A, 0xE6, 0x69, 0xF3, 0x79, 0xDE, 0xDE, 0x74, 0xED,
        0x86, 0x4D, 0xA1, 0xFE, 0xDF, 0x89, 0x48, 0x98, 0xDF, 0xF9, 0x5D, 0x4B, 0x07, 0x1B, 0x23, 0x20,
        0x51, 0xC1, 0x79, 0xC2, 0x89, 0x70, 0x9D, 0xA6, 0x59, 0x32, 0xF4, 0xA6, 0xB4, 0x61, 0xBB, 0xB4,
        0x9E, 0xA4, 0xD7, 0x6B, 0x84, 0x73, 0x72, 0x03, 0x3F, 0x87, 0xE3, 0x17, 0x67, 0xC3, 0xF9, 0x9B,
        0xDA, 0x4C, 0xCB, 0x6A, 0x1C, 0xAC, 0x85, 0xF4, 0x93, 0xBE, 0x6A, 0x76, 0x6C, 0xB1, 0x0E, 0xDA,
        0x3C, 0x75, 0x71, 0x97, 0xE8, 0x22, 0x2B, 0xB0, 0x1F, 0x32, 0x89, 0x10, 0x19, 0x58, 0xF8, 0xF8,
        0xC2, 0x6D, 0x9B, 0x74, 0x07, 0xE5, 0x4F, 0x5F, 0x0C, 0xF0, 0x06, 0x48, 0x77, 0x58, 0xD5, 0x3E,
        0xD4, 0xD1, 0x58, 0xBD, 0x18, 0xE6, 0xCF, 0x22, 0xD7, 0x94, 0xA9, 0xD2, 0x20, 0xD5, 0x06, 0xE2,
        0x1B, 0x57, 0xF9, 0x0D, 0xA5, 0x02, 0x5C, 0x41, 0x8E, 0x0C, 0xBF, 0x1D, 0x78, 0xE3, 0x68, 0xA1,
        0x86, 0x36, 0xCE, 0x0E, 0xCB, 0x26, 0xBD, 0x48, 0x73, 0x2D, 0xA8, 0x9D, 0x2A, 0xA7, 0x40, 0x29,
        0xCA, 0xE7, 0xC7, 0xC4, 0x57, 0x8B, 0xAA, 0xE3, 0x8F, 0xC6, 0x54, 0x81, 0xB4, 0x1A, 0x04, 0x4F,
        0x6E, 0x22, 0x77, 0x9C, 0x5A, 0xDF, 0x13, 0xD0, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x7C, 0xE1, 0xD4,
        0x00, 0x01, 0xC2, 0x03, 0x80, 0x43, 0x00, 0x00, 0x10, 0x94, 0x50, 0x47, 0x3E, 0x30, 0x0D, 0x8B,
        0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    auto span = buffer.span();

    EXPECT_EQ(span.trim(xz_utils_arm64_binary_part1.size()), xz_utils_arm64_binary_part1.span());
    span = span.slice(xz_utils_arm64_binary_part1.size());

    EXPECT_EQ(span.trim(xz_utils_arm64_binary_part2.size()), xz_utils_arm64_binary_part2.span());
    span = span.slice(xz_utils_arm64_binary_part2.size());

    EXPECT_EQ(span.trim(xz_utils_arm64_binary_part3.size()), xz_utils_arm64_binary_part3.span());
    span = span.slice(xz_utils_arm64_binary_part3.size());

    EXPECT_EQ(span.trim(xz_utils_arm64_binary_part4.size()), xz_utils_arm64_binary_part4.span());
    span = span.slice(xz_utils_arm64_binary_part4.size());

    EXPECT_EQ(span.trim(xz_utils_arm64_binary_part5.size()), xz_utils_arm64_binary_part5.span());
    span = span.slice(xz_utils_arm64_binary_part5.size());

    EXPECT_EQ(span.size(), 0ul);
}

TEST_CASE(xz_utils_good_1_block_header_1)
{
    // "good-1-block_header-1.xz has both Compressed Size and Uncompressed
    //  Size in the Block Header. This has also four extra bytes of Header
    //  Padding."
    Array<u8, 72> const compressed {
        // Stream Header
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, // Magic
        0x00, 0x01,                         // Stream Flags
        0x69, 0x22, 0xDE, 0x36,             // CRC32

        // Block Header
        0x03, // Block Header Size
        0xC0, // Block Flags (one filter, compressed size and uncompressed size present)
        0x11, // Compressed Size
        0x0D, // Uncompressed Size
        // Filter 0 Flags
        0x21,                         // Filter ID
        0x01,                         // Size of Properties
        0x08,                         // Filter Properties
        0x00, 0x00, 0x00, 0x00, 0x00, // Header Padding
        0x7F, 0xDE, 0x39, 0xEB,       // CRC32

        // Compressed Data (LZMA2)
        //   Uncompressed chunk with dictionary reset
        0x01,       // Control Byte
        0x00, 0x0C, // 16-bit data size minus one (big-endian)
        0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x0A, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A,
        //   End of LZMA2 stream
        0x00,

        // Block Padding
        0x00, 0x00, 0x00,

        // Uncompressed Data Check (CRC32)
        0x43, 0xA3, 0xA2, 0x15,

        // Index
        0x00, // Index Indicator
        0x01, // Number of Records (multibyte integer)
        //   Record 0
        0x25, // Unpadded Size (multibyte integer)
        0x0D, // Uncompressed Size (multibyte integer)
        //   CRC32
        0x71, 0x19, 0xC4, 0xB6,

        // Stream Footer
        0x90, 0x42, 0x99, 0x0D, // CRC32
        0x01, 0x00, 0x00, 0x00, // Backward Size
        0x00, 0x01,             // Stream Flags
        0x59, 0x5A,             // Footer Magic Bytes
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.span(), xz_utils_hello_world.bytes());
}

TEST_CASE(xz_utils_good_1_block_header_2)
{
    // "good-1-block_header-2.xz has known Compressed Size."
    Array<u8, 68> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x40, 0x11, 0x21,
        0x01, 0x08, 0x00, 0x00, 0x3A, 0x4C, 0x88, 0xE1, 0x01, 0x00, 0x0C, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x43, 0xA3, 0xA2, 0x15,
        0x00, 0x01, 0x21, 0x0D, 0x75, 0xDC, 0xA8, 0xD2, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.span(), xz_utils_hello_world.bytes());
}

TEST_CASE(xz_utils_good_1_block_header_3)
{
    // "good-1-block_header-3.xz has known Uncompressed Size."
    Array<u8, 68> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x80, 0x0D, 0x21,
        0x01, 0x08, 0x00, 0x00, 0x51, 0x11, 0x81, 0x59, 0x01, 0x00, 0x0C, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x43, 0xA3, 0xA2, 0x15,
        0x00, 0x01, 0x21, 0x0D, 0x75, 0xDC, 0xA8, 0xD2, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.span(), xz_utils_hello_world.bytes());
}

TEST_CASE(xz_utils_good_1_check_crc32)
{
    // "good-1-check-crc32.xz has one Stream with one Block with two
    //  uncompressed LZMA2 chunks and CRC32 check."
    Array<u8, 68> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x43, 0xA3, 0xA2, 0x15,
        0x00, 0x01, 0x24, 0x0D, 0x30, 0x28, 0xDF, 0xAF, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.span(), xz_utils_hello_world.bytes());
}

TEST_CASE(xz_utils_good_1_check_crc64)
{
    // "good-1-check-crc64.xz is like good-1-check-crc32.xz but with CRC64."
    Array<u8, 72> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x04, 0xE6, 0xD6, 0xB4, 0x46, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0xEF, 0x2E, 0x88, 0x11,
        0x9D, 0x3F, 0x96, 0xCA, 0x00, 0x01, 0x28, 0x0D, 0x3C, 0x67, 0x6A, 0x03, 0x1F, 0xB6, 0xF3, 0x7D,
        0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.span(), xz_utils_hello_world.bytes());
}

TEST_CASE(xz_utils_good_1_check_none)
{
    // "good-1-check-none.xz has one Stream with one Block with two
    //  uncompressed LZMA2 chunks and no integrity check."
    Array<u8, 64> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x00, 0xFF, 0x12, 0xD9, 0x41, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x00, 0x01, 0x20, 0x0D,
        0x34, 0xED, 0xB3, 0xCB, 0x06, 0x72, 0x9E, 0x7A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.span(), xz_utils_hello_world.bytes());
}

TEST_CASE(xz_utils_good_1_check_sha256)
{
    // "good-1-check-sha256.xz is like good-1-check-crc32.xz but with
    //  SHA256."
    Array<u8, 96> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x0A, 0xE1, 0xFB, 0x0C, 0xA1, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x8E, 0x59, 0x35, 0xE7,
        0xE1, 0x33, 0x68, 0xCD, 0x96, 0x88, 0xFE, 0x8F, 0x48, 0xA0, 0x95, 0x52, 0x93, 0x67, 0x6A, 0x02,
        0x15, 0x62, 0x58, 0x2C, 0x7E, 0x84, 0x8D, 0xAF, 0xE1, 0x3F, 0xB0, 0x46, 0x00, 0x01, 0x40, 0x0D,
        0x93, 0x86, 0x4E, 0xAE, 0x18, 0x9B, 0x4B, 0x9A, 0x01, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.span(), xz_utils_hello_world.bytes());
}

// "good-1-delta-lzma2.tiff.xz is an image file that compresses
//  better with Delta+LZMA2 than with plain LZMA2."
// This test has not been added due to it having a filesize of 50.1 KiB.

TEST_CASE(xz_utils_good_1_empty_bcj_lzma2)
{
    // "good-1-empty-bcj-lzma2.xz has an empty Block that uses PowerPC BCJ
    //  and LZMA2."
    Array<u8, 52> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x01, 0x05, 0x00,
        0x21, 0x01, 0x00, 0x00, 0x7F, 0xE0, 0xF1, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x11, 0x00, 0x3B, 0x96, 0x5F, 0x73, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    // TODO: This uses the currently unimplemented PowerPC branch/call/jump filter.
    (void)decompressor->read_until_eof(PAGE_SIZE);
}

TEST_CASE(xz_utils_good_1_lzma2_1)
{
    // "good-1-lzma2-1.xz has two LZMA2 chunks, of which the second sets
    //  new properties."
    Array<u8, 424> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0xE0, 0x00, 0xE2, 0x00, 0xB6, 0x5D, 0x00, 0x26,
        0x1B, 0xCA, 0x46, 0x67, 0x5A, 0xF2, 0x77, 0xB8, 0x7D, 0x86, 0xD8, 0x41, 0xDB, 0x05, 0x35, 0xCD,
        0x83, 0xA5, 0x7C, 0x12, 0xA5, 0x05, 0xDB, 0x90, 0xBD, 0x2F, 0x14, 0xD3, 0x71, 0x72, 0x96, 0xA8,
        0x8A, 0x7D, 0x84, 0x56, 0x71, 0x8D, 0x6A, 0x22, 0x98, 0xAB, 0x9E, 0x3D, 0x90, 0x80, 0x2D, 0xC7,
        0x5E, 0x0C, 0x12, 0x52, 0xD3, 0x3F, 0x07, 0x08, 0x7B, 0x1C, 0xA4, 0x77, 0xF3, 0x13, 0xB8, 0x17,
        0xC0, 0xEE, 0x91, 0x81, 0x39, 0xB3, 0x87, 0xF0, 0xFF, 0x00, 0xB3, 0x6A, 0x52, 0x41, 0xED, 0x2E,
        0xB0, 0xF2, 0x64, 0x97, 0xA4, 0x9A, 0x9E, 0x63, 0xA1, 0xAE, 0x19, 0x74, 0x0D, 0xA9, 0xD5, 0x5B,
        0x6C, 0xEE, 0xB1, 0xE0, 0x2C, 0xDC, 0x61, 0xDC, 0xCB, 0x9D, 0x86, 0xCF, 0xE1, 0xDC, 0x0A, 0x7A,
        0x81, 0x14, 0x5F, 0xD0, 0x40, 0xC8, 0x7E, 0x0D, 0x97, 0x44, 0xCE, 0xB5, 0xC2, 0xFC, 0x2C, 0x59,
        0x08, 0xBF, 0x03, 0x80, 0xDC, 0xD7, 0x44, 0x8E, 0xB3, 0xD4, 0x2D, 0xDE, 0xE5, 0x16, 0x21, 0x6E,
        0x47, 0x82, 0xAC, 0x08, 0x59, 0xD8, 0xE4, 0x66, 0x29, 0x61, 0xD5, 0xD1, 0xFA, 0x49, 0x63, 0x90,
        0x11, 0x3E, 0x20, 0xD0, 0xA9, 0xE2, 0xD5, 0x14, 0x81, 0xD9, 0x23, 0xD0, 0x8F, 0x43, 0xAE, 0x45,
        0x55, 0x36, 0x69, 0xAA, 0x00, 0xC0, 0x00, 0xE5, 0x00, 0xAD, 0x0B, 0x00, 0x8C, 0xF1, 0x9D, 0x40,
        0x2B, 0xD0, 0x7D, 0x1D, 0x99, 0xEE, 0xE4, 0xDC, 0x63, 0x74, 0x64, 0x46, 0xA4, 0xA0, 0x4A, 0x64,
        0x65, 0xB2, 0xF6, 0x4E, 0xC1, 0xC8, 0x68, 0x9F, 0x27, 0x54, 0xAD, 0xBB, 0xA6, 0x34, 0x3C, 0x77,
        0xEC, 0x0F, 0x2E, 0x1B, 0x8E, 0x42, 0x27, 0xE5, 0x68, 0xBF, 0x60, 0xF4, 0x0B, 0x3A, 0xF0, 0x9B,
        0x31, 0xEB, 0xDF, 0x3F, 0xD8, 0xAF, 0xA5, 0x55, 0x92, 0x46, 0x05, 0x58, 0x22, 0x09, 0x8F, 0xA8,
        0x60, 0x08, 0x0B, 0xA3, 0xE9, 0x3E, 0xBC, 0xB4, 0x16, 0xDB, 0xC7, 0xA3, 0xA2, 0xC0, 0x16, 0xD5,
        0x14, 0xA7, 0x22, 0xE8, 0x2F, 0xE8, 0xB4, 0xD0, 0x77, 0x17, 0xC5, 0x8B, 0xE4, 0xF2, 0xBB, 0x6B,
        0xD6, 0xEF, 0x9A, 0x81, 0x34, 0x4E, 0x1D, 0xDC, 0xEC, 0x36, 0xE6, 0x44, 0x72, 0xBF, 0x29, 0xB5,
        0x3C, 0x05, 0x31, 0x60, 0x66, 0xBA, 0x2C, 0x03, 0x0F, 0xD6, 0x47, 0xC6, 0x7D, 0x85, 0xD4, 0xC5,
        0x5E, 0x4E, 0x57, 0x73, 0xC3, 0x41, 0x69, 0xBE, 0x0D, 0x8C, 0x9C, 0xB5, 0x15, 0xA9, 0xE7, 0xD2,
        0x78, 0x51, 0x4B, 0xD5, 0x29, 0xD0, 0xF9, 0x35, 0x1A, 0xC5, 0x5D, 0xF4, 0x8C, 0x7A, 0x70, 0xD5,
        0x5E, 0xA8, 0x31, 0x57, 0x80, 0xC8, 0xA5, 0xD8, 0xE0, 0x00, 0x00, 0x00, 0xFB, 0x47, 0x48, 0xDB,
        0x00, 0x01, 0x82, 0x03, 0xC9, 0x03, 0x00, 0x00, 0x0B, 0x04, 0x8E, 0xDE, 0x3E, 0x30, 0x0D, 0x8B,
        0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.span(), xz_utils_lorem_ipsum.bytes());
}

TEST_CASE(xz_utils_good_1_lzma2_2)
{
    // "good-1-lzma2-2.xz has two LZMA2 chunks, of which the second resets
    //  the state without specifying new properties."
    Array<u8, 424> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0xE0, 0x00, 0xE2, 0x00, 0xB6, 0x5D, 0x00, 0x26,
        0x1B, 0xCA, 0x46, 0x67, 0x5A, 0xF2, 0x77, 0xB8, 0x7D, 0x86, 0xD8, 0x41, 0xDB, 0x05, 0x35, 0xCD,
        0x83, 0xA5, 0x7C, 0x12, 0xA5, 0x05, 0xDB, 0x90, 0xBD, 0x2F, 0x14, 0xD3, 0x71, 0x72, 0x96, 0xA8,
        0x8A, 0x7D, 0x84, 0x56, 0x71, 0x8D, 0x6A, 0x22, 0x98, 0xAB, 0x9E, 0x3D, 0x90, 0x80, 0x2D, 0xC7,
        0x5E, 0x0C, 0x12, 0x52, 0xD3, 0x3F, 0x07, 0x08, 0x7B, 0x1C, 0xA4, 0x77, 0xF3, 0x13, 0xB8, 0x17,
        0xC0, 0xEE, 0x91, 0x81, 0x39, 0xB3, 0x87, 0xF0, 0xFF, 0x00, 0xB3, 0x6A, 0x52, 0x41, 0xED, 0x2E,
        0xB0, 0xF2, 0x64, 0x97, 0xA4, 0x9A, 0x9E, 0x63, 0xA1, 0xAE, 0x19, 0x74, 0x0D, 0xA9, 0xD5, 0x5B,
        0x6C, 0xEE, 0xB1, 0xE0, 0x2C, 0xDC, 0x61, 0xDC, 0xCB, 0x9D, 0x86, 0xCF, 0xE1, 0xDC, 0x0A, 0x7A,
        0x81, 0x14, 0x5F, 0xD0, 0x40, 0xC8, 0x7E, 0x0D, 0x97, 0x44, 0xCE, 0xB5, 0xC2, 0xFC, 0x2C, 0x59,
        0x08, 0xBF, 0x03, 0x80, 0xDC, 0xD7, 0x44, 0x8E, 0xB3, 0xD4, 0x2D, 0xDE, 0xE5, 0x16, 0x21, 0x6E,
        0x47, 0x82, 0xAC, 0x08, 0x59, 0xD8, 0xE4, 0x66, 0x29, 0x61, 0xD5, 0xD1, 0xFA, 0x49, 0x63, 0x90,
        0x11, 0x3E, 0x20, 0xD0, 0xA9, 0xE2, 0xD5, 0x14, 0x81, 0xD9, 0x23, 0xD0, 0x8F, 0x43, 0xAE, 0x45,
        0x55, 0x36, 0x69, 0xAA, 0x00, 0xA0, 0x00, 0xE5, 0x00, 0xAF, 0x00, 0x8C, 0xF1, 0x9D, 0x40, 0x7D,
        0x82, 0x4F, 0x24, 0x72, 0x14, 0xF1, 0x9D, 0x84, 0xCB, 0x5A, 0x32, 0x6C, 0x97, 0x6A, 0x40, 0x83,
        0x8B, 0xF0, 0xAF, 0x31, 0xC2, 0xB4, 0x65, 0x6F, 0x89, 0xFD, 0xFB, 0xD8, 0x8B, 0x54, 0x41, 0x82,
        0x16, 0x54, 0x12, 0xD1, 0x4D, 0xD5, 0x86, 0xC5, 0xC0, 0x5A, 0xFA, 0x49, 0x63, 0x91, 0x11, 0xFE,
        0xFF, 0xF5, 0x8F, 0x14, 0x02, 0x85, 0x61, 0x79, 0x38, 0x4A, 0x4B, 0x4F, 0x41, 0x63, 0xF8, 0x87,
        0x2F, 0x2C, 0xE6, 0xE2, 0xE9, 0x31, 0x8F, 0x8B, 0x14, 0xD3, 0xA1, 0x7E, 0x81, 0xE8, 0x55, 0x02,
        0xEF, 0x21, 0x31, 0xA2, 0x7B, 0x05, 0xCC, 0x1F, 0xA4, 0x60, 0xE7, 0x81, 0xAA, 0xA7, 0xD9, 0x78,
        0x82, 0xE6, 0x18, 0xB2, 0xAB, 0x1C, 0xAA, 0x19, 0x2F, 0xC2, 0x87, 0x14, 0xC5, 0xD9, 0xCB, 0x3F,
        0xD0, 0x18, 0xA6, 0xCD, 0x2A, 0x4B, 0x5D, 0xA8, 0xC7, 0x5F, 0x01, 0x67, 0x28, 0x4C, 0x2C, 0xE4,
        0xCC, 0xD5, 0x52, 0x9E, 0x93, 0x02, 0x7E, 0x10, 0x5D, 0xF5, 0x03, 0xB1, 0x98, 0x2F, 0x26, 0xED,
        0x86, 0x7B, 0x56, 0x7F, 0x13, 0x79, 0x58, 0x8F, 0x44, 0x10, 0xD9, 0xD9, 0x0F, 0x96, 0xE9, 0x3B,
        0xBF, 0xB5, 0xB8, 0xDA, 0x2B, 0xE1, 0xD6, 0x81, 0xF1, 0xC9, 0x00, 0x00, 0xFB, 0x47, 0x48, 0xDB,
        0x00, 0x01, 0x83, 0x03, 0xC9, 0x03, 0x00, 0x00, 0xAE, 0xD7, 0xD2, 0x15, 0x3E, 0x30, 0x0D, 0x8B,
        0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.span(), xz_utils_lorem_ipsum.bytes());
}

TEST_CASE(xz_utils_good_1_lzma2_3)
{
    // "good-1-lzma2-3.xz has two LZMA2 chunks, of which the first is
    //  uncompressed and the second is LZMA. The first chunk resets dictionary
    //  and the second sets new properties."
    Array<u8, 408> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x34, 0x4C, 0x6F, 0x72, 0x65, 0x6D,
        0x20, 0x69, 0x70, 0x73, 0x75, 0x6D, 0x20, 0x64, 0x6F, 0x6C, 0x6F, 0x72, 0x20, 0x73, 0x69, 0x74,
        0x20, 0x61, 0x6D, 0x65, 0x74, 0x2C, 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x65, 0x63, 0x74, 0x65, 0x74,
        0x75, 0x72, 0x20, 0x61, 0x64, 0x69, 0x70, 0x69, 0x73, 0x69, 0x63, 0x69, 0x6E, 0x67, 0x20, 0x0A,
        0xC0, 0x01, 0x93, 0x01, 0x24, 0x5D, 0x00, 0x32, 0x9B, 0x09, 0x6C, 0x54, 0xD7, 0x2E, 0x95, 0x6C,
        0xF9, 0xF7, 0x37, 0xD5, 0x1C, 0xE2, 0x46, 0x02, 0x82, 0x75, 0xFB, 0x49, 0x76, 0x8D, 0x73, 0x53,
        0xB6, 0xFD, 0x6D, 0xDB, 0xCA, 0xDB, 0xD9, 0x44, 0x0B, 0xB1, 0x2E, 0xBE, 0x13, 0xB6, 0xBA, 0xA8,
        0xE2, 0xF3, 0xED, 0x75, 0x54, 0xDC, 0x41, 0x20, 0xCC, 0xBF, 0x36, 0x5B, 0x20, 0x99, 0x5D, 0x0F,
        0x21, 0xA1, 0x06, 0xA3, 0x96, 0x2D, 0xB7, 0x97, 0x9C, 0xF0, 0x7B, 0xFE, 0xE2, 0x12, 0x8C, 0x2D,
        0x51, 0xF0, 0xDB, 0x76, 0x77, 0x7D, 0xA4, 0x7B, 0xD3, 0x95, 0xE9, 0xFB, 0x05, 0xE6, 0xF5, 0x97,
        0x8F, 0x62, 0xE9, 0xDB, 0x30, 0xBB, 0xB4, 0x70, 0x3D, 0x16, 0x78, 0x03, 0x77, 0x3A, 0x8B, 0x7A,
        0xD5, 0xB8, 0xF8, 0x4A, 0x27, 0x25, 0xF5, 0x8E, 0xAA, 0x24, 0x14, 0xA6, 0x29, 0x28, 0x6B, 0x2F,
        0x73, 0xE0, 0xA1, 0x71, 0xB4, 0x7B, 0xA4, 0x80, 0x50, 0x40, 0xCA, 0xEF, 0xDB, 0xB4, 0x95, 0xFD,
        0xBB, 0xC1, 0x8C, 0x8E, 0x60, 0x97, 0xDB, 0xCB, 0x7F, 0x21, 0xED, 0xC0, 0x10, 0x71, 0x1A, 0x7D,
        0xCB, 0xCD, 0x09, 0xD0, 0xD9, 0xFF, 0x6D, 0x80, 0xC0, 0x67, 0x7D, 0x3F, 0xC6, 0x94, 0xCF, 0x5B,
        0xDD, 0x51, 0x11, 0xD1, 0xCB, 0xD4, 0x20, 0xD7, 0x2B, 0x84, 0x4E, 0xA8, 0x45, 0xBB, 0x42, 0x78,
        0x1A, 0x68, 0x40, 0x5F, 0x24, 0x5E, 0x89, 0x3A, 0x36, 0x7D, 0xDB, 0x98, 0x28, 0xCC, 0xF9, 0x83,
        0xEC, 0x32, 0x06, 0x31, 0x47, 0x47, 0x3B, 0x6C, 0x1C, 0xF4, 0x62, 0x34, 0x40, 0xB3, 0x28, 0xBB,
        0x54, 0x36, 0xDD, 0x7A, 0x0E, 0x1C, 0x36, 0x25, 0x38, 0x58, 0x06, 0xF8, 0x15, 0xA3, 0xCE, 0x18,
        0xC8, 0xFD, 0x96, 0x1E, 0x69, 0x29, 0x03, 0xC3, 0xBD, 0x27, 0xF3, 0xE7, 0x8F, 0xDB, 0x73, 0xB4,
        0x2B, 0x4F, 0x38, 0x58, 0x24, 0xBF, 0x83, 0x14, 0x39, 0x7E, 0x73, 0xEE, 0xFE, 0xCF, 0xCA, 0xBD,
        0xF3, 0x21, 0x6A, 0x28, 0x80, 0xC8, 0x8E, 0x5D, 0x81, 0xC7, 0xBC, 0x17, 0xD0, 0x2C, 0x93, 0xB5,
        0x08, 0x95, 0xBA, 0x0E, 0x92, 0x82, 0x66, 0xAE, 0xFF, 0xB8, 0x03, 0x00, 0xFB, 0x47, 0x48, 0xDB,
        0x00, 0x01, 0xF4, 0x02, 0xC9, 0x03, 0x00, 0x00, 0x67, 0xC3, 0x95, 0x3E, 0x3E, 0x30, 0x0D, 0x8B,
        0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.span(), xz_utils_lorem_ipsum.bytes());
}

TEST_CASE(xz_utils_good_1_lzma2_4)
{
    // "good-1-lzma2-4.xz has three LZMA2 chunks: First is LZMA, second is
    //  uncompressed with dictionary reset, and third is LZMA with new
    //  properties but without dictionary reset."
    Array<u8, 464> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x04, 0xE6, 0xD6, 0xB4, 0x46, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0xE0, 0x00, 0xBB, 0x00, 0xA1, 0x5D, 0x00, 0x26,
        0x1B, 0xCA, 0x46, 0x67, 0x5A, 0xF2, 0x77, 0xB8, 0x7D, 0x86, 0xD8, 0x41, 0xDB, 0x05, 0x35, 0xCD,
        0x83, 0xA5, 0x7C, 0x12, 0xA5, 0x05, 0xDB, 0x90, 0xBD, 0x2F, 0x14, 0xD3, 0x71, 0x72, 0x96, 0xA8,
        0x8A, 0x7D, 0x84, 0x56, 0x71, 0x8D, 0x6A, 0x22, 0x98, 0xAB, 0x9E, 0x3D, 0x90, 0x80, 0x2D, 0xC7,
        0x5E, 0x0C, 0x12, 0x52, 0xD3, 0x3F, 0x07, 0x08, 0x7B, 0x1C, 0xA4, 0x77, 0xF3, 0x13, 0xB8, 0x17,
        0xC0, 0xEE, 0x91, 0x73, 0xCA, 0xBC, 0xCF, 0xEB, 0x34, 0x66, 0xAC, 0x48, 0x9B, 0x69, 0xD9, 0x93,
        0x07, 0xAE, 0xCE, 0x50, 0xAF, 0x68, 0x09, 0x2F, 0x5B, 0x88, 0x1F, 0xC2, 0x08, 0xA2, 0x2C, 0x58,
        0x45, 0xB0, 0xFF, 0x62, 0x09, 0xEB, 0xEE, 0xDB, 0x63, 0x4F, 0x6F, 0xE0, 0xF3, 0x1F, 0xCF, 0x12,
        0x37, 0x98, 0x96, 0x4E, 0xF6, 0xF2, 0xB2, 0xFB, 0x6E, 0xAF, 0x44, 0x02, 0xE2, 0x22, 0xDE, 0xD5,
        0xE6, 0x34, 0x97, 0x39, 0xA3, 0x45, 0x2F, 0xAE, 0x99, 0x2F, 0x79, 0x69, 0x8F, 0xE9, 0x37, 0x89,
        0x48, 0xFE, 0xCC, 0x7E, 0xEA, 0xA9, 0x28, 0xAD, 0xC3, 0xE6, 0xDC, 0xB9, 0xDA, 0xAA, 0x16, 0x7E,
        0x01, 0x00, 0x26, 0x6C, 0x61, 0x62, 0x6F, 0x72, 0x69, 0x73, 0x20, 0x6E, 0x69, 0x73, 0x69, 0x20,
        0x75, 0x74, 0x20, 0x61, 0x6C, 0x69, 0x71, 0x75, 0x69, 0x70, 0x20, 0x65, 0x78, 0x20, 0x65, 0x61,
        0x20, 0x63, 0x6F, 0x6D, 0x6D, 0x6F, 0x64, 0x6F, 0x20, 0x0A, 0xC0, 0x00, 0xE5, 0x00, 0xBD, 0x5D,
        0x00, 0x31, 0x9B, 0xCA, 0x19, 0xC5, 0x54, 0xEC, 0xB6, 0x54, 0xE7, 0xB1, 0x7D, 0xC4, 0x57, 0x9E,
        0x6C, 0x89, 0xAD, 0x4A, 0x6D, 0x16, 0xD8, 0x3C, 0x05, 0x94, 0x10, 0x16, 0x99, 0x38, 0x21, 0xA3,
        0xB9, 0xC5, 0x80, 0xFF, 0xFC, 0xEE, 0xD4, 0xD5, 0x3F, 0xDD, 0x8C, 0xD7, 0x3D, 0x8F, 0x76, 0xEC,
        0x88, 0xAA, 0x32, 0xAB, 0x65, 0xD4, 0x38, 0xEF, 0xF7, 0xF9, 0x8A, 0xBF, 0xF7, 0xF8, 0xA5, 0x56,
        0xD7, 0x6D, 0xD7, 0x3F, 0x85, 0x0B, 0x9E, 0x3F, 0xE2, 0x47, 0x68, 0x22, 0x08, 0x05, 0x35, 0xB8,
        0x41, 0x72, 0xF9, 0xDB, 0xBE, 0xB7, 0x8E, 0x86, 0xBF, 0x43, 0x4B, 0x8E, 0x0D, 0x43, 0x2F, 0x41,
        0x69, 0xDF, 0x61, 0x0C, 0xC4, 0xE8, 0x37, 0x08, 0x4A, 0xDE, 0xC2, 0x76, 0x16, 0xB8, 0x48, 0x4E,
        0x9E, 0xB9, 0x53, 0x50, 0x1F, 0x33, 0x83, 0xE8, 0x29, 0xA0, 0x67, 0xC8, 0x66, 0x3A, 0x7F, 0x22,
        0x12, 0x62, 0xFB, 0x47, 0xE4, 0xBC, 0xF4, 0x51, 0x0F, 0x15, 0x88, 0x49, 0xD8, 0xCA, 0x0B, 0x25,
        0x8B, 0x5E, 0xE8, 0xDA, 0xFD, 0x38, 0xC0, 0xCE, 0x4C, 0x73, 0x1B, 0xFF, 0xD0, 0x9B, 0xE8, 0x4C,
        0xB7, 0x13, 0xF8, 0x37, 0x99, 0xE2, 0xDA, 0x9C, 0x2F, 0xB5, 0xEA, 0xB8, 0xA5, 0x8D, 0xEA, 0x57,
        0x82, 0x9B, 0x25, 0xCA, 0xFB, 0xF6, 0x88, 0x0A, 0x9B, 0xDF, 0x41, 0x03, 0x6E, 0x00, 0x00, 0x00,
        0xB2, 0x07, 0x44, 0xE9, 0x17, 0x33, 0x4B, 0x84, 0x00, 0x01, 0xAB, 0x03, 0xC9, 0x03, 0x00, 0x00,
        0xF5, 0x50, 0x2D, 0xFE, 0xB1, 0xC4, 0x67, 0xFB, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.span(), xz_utils_lorem_ipsum.bytes());
}

TEST_CASE(xz_utils_good_1_lzma2_5)
{
    // "good-1-lzma2-4.xz has three LZMA2 chunks: First is LZMA, second is
    //  uncompressed with dictionary reset, and third is LZMA with new
    //  properties but without dictionary reset."
    Array<u8, 52> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x10, 0x00, 0x00, 0x00, 0xA8, 0x70, 0x8E, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x11, 0x00, 0x3B, 0x96, 0x5F, 0x73, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.size(), 0ul);
}

TEST_CASE(xz_utils_good_1_sparc_lzma2)
{
    // "good-1-sparc-lzma2.xz uses the SPARC filter and LZMA2. The
    //  uncompressed file is compress_prepared_bcj_sparc found from the tests
    //  directory."
    Array<u8, 612> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x04, 0xE6, 0xD6, 0xB4, 0x46, 0x02, 0x01, 0x09, 0x00,
        0x21, 0x01, 0x08, 0x00, 0x0C, 0xAA, 0xEA, 0x77, 0xE0, 0x04, 0xD7, 0x02, 0x22, 0x5D, 0x00, 0x3F,
        0x91, 0x45, 0x84, 0x68, 0x34, 0x8A, 0x09, 0x0A, 0x41, 0x50, 0x57, 0x98, 0xF3, 0xBD, 0x43, 0xCD,
        0x26, 0xE9, 0xC6, 0xC9, 0xED, 0x84, 0x68, 0x5E, 0xA7, 0xDD, 0xE8, 0xA0, 0xA8, 0x77, 0x31, 0xD2,
        0xA0, 0x05, 0xC6, 0x90, 0x2C, 0x60, 0xDB, 0x04, 0x0C, 0x2E, 0xCC, 0xED, 0x09, 0x92, 0xC5, 0x8B,
        0xA2, 0x23, 0x64, 0x7D, 0x17, 0xF8, 0xE1, 0xC7, 0x24, 0x0B, 0xC2, 0x2A, 0xDB, 0x03, 0x4F, 0x3C,
        0x4E, 0xBC, 0x89, 0x17, 0xD7, 0xAF, 0x79, 0x88, 0x85, 0x36, 0x8C, 0x6E, 0xD5, 0x3C, 0x34, 0x6A,
        0x29, 0xA0, 0x45, 0x27, 0x85, 0x43, 0x52, 0xAF, 0x51, 0x9E, 0x4B, 0x5E, 0x9E, 0x34, 0xC1, 0xFF,
        0x8E, 0xC1, 0xBD, 0xE1, 0x0C, 0xD6, 0x21, 0x50, 0x5E, 0x14, 0x3B, 0x29, 0x54, 0x65, 0x28, 0x90,
        0x72, 0x4E, 0x2D, 0x65, 0x51, 0x35, 0x90, 0x25, 0x76, 0xB7, 0x61, 0x8A, 0x9F, 0xF0, 0x14, 0x75,
        0x39, 0xAA, 0xAE, 0x75, 0x17, 0xAB, 0x29, 0xDB, 0x36, 0xF6, 0xAE, 0xC6, 0x02, 0x3A, 0x3A, 0x93,
        0x05, 0x6C, 0x85, 0xA3, 0x8E, 0x55, 0xF0, 0x06, 0xC3, 0x37, 0x36, 0x90, 0xBB, 0x9B, 0x9C, 0x31,
        0x01, 0x6B, 0xDC, 0x9E, 0xFA, 0x6F, 0x2E, 0xF8, 0xA1, 0xC4, 0xCA, 0x6E, 0x27, 0x7C, 0x74, 0x1F,
        0x28, 0xE8, 0x7A, 0x76, 0x3F, 0xC3, 0x92, 0x24, 0x21, 0x8E, 0xD3, 0x0B, 0xC2, 0x13, 0xF5, 0x12,
        0xCE, 0x3B, 0x1A, 0x19, 0x57, 0x95, 0xFA, 0x9D, 0x3F, 0xDE, 0x16, 0xD2, 0x78, 0x10, 0x01, 0x1A,
        0x42, 0x11, 0xD9, 0x7B, 0xC0, 0x8E, 0x2C, 0x78, 0x9F, 0xCB, 0x43, 0xAF, 0xEE, 0x56, 0xA3, 0xAE,
        0x03, 0x70, 0xB7, 0x13, 0xB3, 0xE5, 0x31, 0xDB, 0x63, 0xDA, 0x65, 0xFA, 0x1F, 0xB6, 0x74, 0xE1,
        0xF7, 0xC4, 0x93, 0xA5, 0x03, 0xB7, 0xFC, 0x93, 0x31, 0x39, 0xA1, 0xFB, 0x82, 0xED, 0x6F, 0xC0,
        0xC2, 0xDA, 0xDF, 0x5D, 0x45, 0x54, 0x00, 0x5F, 0x4E, 0x35, 0xB0, 0xDE, 0xEE, 0x47, 0x37, 0x0A,
        0x66, 0x1C, 0x3C, 0x69, 0xEF, 0xD1, 0x7D, 0x39, 0x75, 0x45, 0xC4, 0x49, 0x5A, 0x86, 0xA2, 0x7E,
        0x45, 0xB9, 0x8E, 0x39, 0x1D, 0x47, 0xA0, 0x5B, 0x3A, 0xD8, 0x24, 0x97, 0xE8, 0x17, 0x80, 0x81,
        0xCD, 0xE6, 0xC8, 0x42, 0x47, 0x65, 0x50, 0x33, 0xE4, 0x6B, 0x99, 0xA7, 0xA4, 0x33, 0x0D, 0xC3,
        0x0E, 0x8E, 0x18, 0xEE, 0x06, 0x85, 0xD1, 0xD3, 0xCF, 0x6E, 0xCB, 0x8F, 0x67, 0x07, 0x84, 0x08,
        0xF3, 0xBB, 0xA1, 0x48, 0xDE, 0x81, 0x79, 0xBA, 0xFA, 0x1B, 0x36, 0x3E, 0xFA, 0x7E, 0x53, 0xB7,
        0xDD, 0x9C, 0xF0, 0xB6, 0x57, 0x93, 0x8E, 0x31, 0xAF, 0x52, 0xEC, 0xD6, 0x1F, 0x42, 0xC6, 0x77,
        0x5C, 0x23, 0x8A, 0x2C, 0xAF, 0xDF, 0x18, 0x9A, 0xAB, 0x63, 0x9E, 0x30, 0x32, 0xF1, 0xD1, 0x22,
        0x7F, 0xAE, 0xF1, 0x5A, 0xCD, 0xEC, 0x15, 0x55, 0x1D, 0x31, 0xB1, 0x7A, 0x59, 0x72, 0xF8, 0x38,
        0x9E, 0xE2, 0x50, 0x24, 0x2E, 0x98, 0x83, 0x67, 0x9C, 0xF0, 0xB6, 0x5F, 0x1B, 0x4F, 0x04, 0xA8,
        0x83, 0xF6, 0x87, 0x64, 0x5B, 0x2E, 0xB7, 0xC5, 0x16, 0x66, 0xDF, 0xA1, 0xE5, 0xD0, 0x89, 0x53,
        0xEA, 0x46, 0x2C, 0xB8, 0x2A, 0xBE, 0x71, 0x16, 0x93, 0x41, 0x20, 0x68, 0x68, 0x0A, 0x61, 0x39,
        0x4A, 0xD4, 0xB7, 0x28, 0x37, 0x06, 0x7D, 0x18, 0x83, 0x30, 0x7E, 0xD7, 0x6C, 0x1E, 0xA6, 0xD5,
        0xE5, 0x40, 0xC0, 0x96, 0xAC, 0x8A, 0xCB, 0x6E, 0xCD, 0x63, 0x76, 0xDC, 0xCC, 0x94, 0x25, 0x80,
        0x34, 0xC2, 0xDB, 0x5E, 0x78, 0x76, 0x6F, 0x10, 0xEE, 0x66, 0x5D, 0x85, 0x4F, 0x1E, 0x83, 0x62,
        0x70, 0x72, 0x6F, 0x88, 0x9B, 0xF7, 0xF3, 0x60, 0xE0, 0xA0, 0xD3, 0xF4, 0x22, 0xE9, 0xEF, 0xD1,
        0x22, 0xA8, 0x83, 0x09, 0x9B, 0x13, 0x53, 0xAC, 0x12, 0xEA, 0x63, 0xCE, 0xC8, 0xA8, 0x3A, 0x4F,
        0xF1, 0xC9, 0x58, 0xDA, 0x69, 0x02, 0xAF, 0x65, 0x7C, 0x57, 0xF2, 0x62, 0xEE, 0x7F, 0x71, 0x56,
        0x00, 0x00, 0x00, 0x00, 0xF7, 0xBD, 0x07, 0x0A, 0x2D, 0x3A, 0x72, 0xFA, 0x00, 0x01, 0xBE, 0x04,
        0xD8, 0x09, 0x00, 0x00, 0xE1, 0xAA, 0x24, 0xFA, 0xB1, 0xC4, 0x67, 0xFB, 0x02, 0x00, 0x00, 0x00,
        0x00, 0x04, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    // TODO: This uses the currently unimplemented SPARC branch/call/jump filter.
    (void)decompressor->read_until_eof(PAGE_SIZE);
}

TEST_CASE(xz_utils_good_1_x86_lzma2)
{
    // "good-1-x86-lzma2.xz uses the x86 filter (BCJ) and LZMA2. The
    //  uncompressed file is compress_prepared_bcj_x86 found from the tests
    //  directory."
    Array<u8, 716> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x04, 0xE6, 0xD6, 0xB4, 0x46, 0x02, 0x01, 0x04, 0x00,
        0x21, 0x01, 0x08, 0x00, 0xD2, 0xB9, 0x74, 0xCB, 0xE0, 0x05, 0x6B, 0x02, 0x8A, 0x5D, 0x00, 0x3F,
        0x91, 0x45, 0x84, 0x68, 0x3B, 0xDE, 0xDE, 0xA8, 0x4B, 0x03, 0xD8, 0x35, 0x53, 0xA4, 0x91, 0x73,
        0xA3, 0xE5, 0x1B, 0x1E, 0x5B, 0x1D, 0x4A, 0xF1, 0x06, 0xC1, 0xAE, 0x79, 0xEA, 0x45, 0x62, 0x76,
        0x0C, 0x29, 0xCD, 0x4B, 0x9F, 0x6E, 0xCD, 0x71, 0xB9, 0x15, 0xF0, 0x80, 0x58, 0xDE, 0x71, 0xF6,
        0x38, 0x55, 0x95, 0xD1, 0xFB, 0x03, 0xF0, 0xA9, 0x04, 0x71, 0x86, 0xC5, 0xD6, 0x4B, 0xB7, 0x0F,
        0xCE, 0x3C, 0x29, 0xA7, 0x05, 0x65, 0x35, 0xCF, 0x9D, 0xFF, 0x7A, 0x18, 0xCD, 0x09, 0x8B, 0xDD,
        0xAA, 0x4E, 0xEB, 0xE8, 0x21, 0xF4, 0x3D, 0xDF, 0x57, 0x4F, 0xF6, 0x62, 0x96, 0x34, 0x36, 0x9C,
        0xCB, 0x20, 0x48, 0x9F, 0x20, 0xEC, 0x87, 0xEE, 0x19, 0x4E, 0xCB, 0x01, 0x82, 0x21, 0x08, 0x75,
        0xBB, 0x09, 0x4D, 0x83, 0xCB, 0xC4, 0x10, 0xC1, 0xDF, 0x6F, 0xE6, 0x6E, 0x29, 0x9A, 0x51, 0x84,
        0x0B, 0x67, 0x34, 0x54, 0x4C, 0x0B, 0xDD, 0x5F, 0xBA, 0xE8, 0xBB, 0x23, 0x9E, 0x3E, 0x50, 0x3B,
        0x34, 0x82, 0x66, 0x06, 0xDB, 0x21, 0x6A, 0x62, 0x5B, 0x5F, 0x10, 0xB6, 0x7A, 0x70, 0x85, 0xB4,
        0x3E, 0x7E, 0x6D, 0x25, 0x7B, 0x7D, 0x48, 0x59, 0xCA, 0x94, 0xE9, 0xDB, 0xB6, 0x60, 0xE5, 0x89,
        0x24, 0xBE, 0xC6, 0x32, 0xC5, 0x18, 0xF1, 0x56, 0x2F, 0x1F, 0x24, 0x30, 0xB7, 0x62, 0x0C, 0x4B,
        0x98, 0xF5, 0x5A, 0xE7, 0xF8, 0x7A, 0x1E, 0x4A, 0x44, 0xC6, 0x14, 0x6E, 0x87, 0xD8, 0xCE, 0xE5,
        0x0E, 0x33, 0x8B, 0x14, 0x6D, 0xD2, 0xD0, 0xF6, 0xD6, 0xAB, 0x68, 0x4B, 0xC8, 0x75, 0xE4, 0x95,
        0xE7, 0x03, 0x69, 0x89, 0x3F, 0xB0, 0x07, 0xC0, 0x59, 0x4F, 0xEA, 0x26, 0x85, 0x36, 0x7A, 0x87,
        0xC3, 0x87, 0x74, 0x0A, 0xB1, 0x77, 0xE5, 0x3F, 0xAD, 0xB1, 0xFF, 0x3B, 0xAC, 0xA4, 0x3D, 0x7C,
        0xAC, 0xF7, 0xA6, 0xC5, 0xBC, 0xFE, 0x33, 0xF4, 0xB0, 0x26, 0xAF, 0xF1, 0x00, 0x57, 0xC8, 0x5F,
        0x5A, 0xF5, 0xD6, 0xA7, 0x59, 0x4F, 0xA6, 0x5A, 0x3D, 0x69, 0xB1, 0xC1, 0x80, 0x39, 0x1B, 0x67,
        0x86, 0x5E, 0xED, 0x78, 0x37, 0x06, 0x45, 0x0E, 0x85, 0xF3, 0x11, 0xC2, 0x71, 0x00, 0x92, 0xA4,
        0x66, 0x1B, 0x1C, 0xDC, 0x6F, 0xC5, 0x58, 0xA7, 0xED, 0x8C, 0x6F, 0xCD, 0x4D, 0x97, 0xAE, 0xE6,
        0xBE, 0x52, 0x5E, 0x9C, 0x5F, 0x1A, 0xDE, 0x06, 0x23, 0xDA, 0x1E, 0x06, 0x8D, 0x76, 0x6B, 0x33,
        0x06, 0x6B, 0xEC, 0xA4, 0x34, 0xFD, 0xD0, 0xF6, 0x72, 0xCC, 0x05, 0x09, 0xDB, 0xD1, 0xDE, 0x06,
        0xA4, 0xE4, 0x18, 0x34, 0xF3, 0x51, 0x2F, 0x5C, 0x98, 0x55, 0xAB, 0xCD, 0x08, 0x7B, 0x2F, 0x80,
        0x9E, 0x8D, 0x49, 0xD9, 0xB7, 0xB8, 0x35, 0x94, 0xB5, 0xEC, 0x16, 0xAD, 0x3B, 0x1B, 0x7E, 0x9A,
        0x2D, 0xA5, 0x84, 0x8C, 0xFC, 0xB3, 0x4D, 0x3F, 0x06, 0x53, 0x90, 0x7D, 0x53, 0x3E, 0x18, 0xD1,
        0x65, 0xB0, 0x91, 0x93, 0x97, 0x57, 0x7C, 0x9E, 0xD3, 0xAE, 0xA9, 0x6D, 0x52, 0xD8, 0xCF, 0xE8,
        0x7C, 0xF2, 0xC5, 0xB3, 0x9C, 0xF7, 0xFF, 0x55, 0xEF, 0x1B, 0x90, 0x5A, 0xE1, 0x03, 0xC2, 0x20,
        0x87, 0x8C, 0x8E, 0xF1, 0x00, 0x7A, 0x0A, 0x46, 0xE2, 0x72, 0xA5, 0x27, 0xC0, 0x6F, 0x87, 0xCE,
        0x37, 0xBB, 0x3A, 0x5D, 0xD3, 0x9C, 0x4F, 0x71, 0x7C, 0xD3, 0xCE, 0xB1, 0xE3, 0xD3, 0x6E, 0x23,
        0x67, 0x8D, 0xDB, 0xF6, 0x04, 0x66, 0xAA, 0x70, 0x5D, 0x73, 0xD0, 0x91, 0x22, 0x5A, 0xF9, 0xB4,
        0x86, 0x2A, 0xA1, 0x1C, 0x04, 0xAE, 0xC5, 0xE5, 0x14, 0x05, 0x11, 0xF3, 0xCD, 0xBC, 0xFF, 0x4E,
        0x15, 0x9F, 0x82, 0x51, 0x61, 0x1C, 0x6B, 0xBC, 0xAE, 0x79, 0x16, 0x38, 0x88, 0x2C, 0x96, 0x86,
        0x98, 0x1D, 0xE4, 0x5B, 0x11, 0x3A, 0x31, 0x57, 0x1C, 0xE6, 0x96, 0xE8, 0xBB, 0xA1, 0x0A, 0xA3,
        0xA4, 0xA9, 0xA0, 0x98, 0x33, 0x8C, 0xBD, 0x22, 0x38, 0x4D, 0x82, 0xA7, 0xBD, 0x81, 0x10, 0x75,
        0x48, 0xF8, 0x85, 0x8A, 0xA7, 0xA0, 0x48, 0xF5, 0xA6, 0x0A, 0xF3, 0xB0, 0x5F, 0xEF, 0x51, 0x95,
        0x68, 0x06, 0xEC, 0x08, 0x1A, 0xF6, 0xAB, 0xA5, 0x60, 0xC1, 0x25, 0x96, 0xD8, 0xD0, 0x39, 0x62,
        0x08, 0xD8, 0xAD, 0x6E, 0x35, 0xD7, 0xC3, 0x34, 0x30, 0x6F, 0x54, 0x47, 0x8E, 0x9C, 0xE8, 0xF8,
        0xEE, 0x3E, 0x1F, 0xF2, 0x04, 0xEB, 0xA3, 0xD8, 0x58, 0x85, 0xE2, 0x75, 0x88, 0x0E, 0x14, 0xDA,
        0x9F, 0x66, 0x60, 0x7C, 0x9A, 0xF3, 0x70, 0x27, 0xA2, 0xAC, 0xC6, 0x9C, 0x0A, 0xE1, 0xAF, 0x9B,
        0xB2, 0x70, 0x9E, 0x6D, 0x27, 0x17, 0x3C, 0x59, 0x96, 0x20, 0x4E, 0xBC, 0x02, 0xDF, 0x7B, 0x31,
        0xD1, 0x0F, 0x96, 0x8E, 0x5A, 0xF9, 0xE5, 0x84, 0xA7, 0x00, 0x00, 0x00, 0xCC, 0xFE, 0xAF, 0xFF,
        0x32, 0x1D, 0x43, 0xB0, 0x00, 0x01, 0xA6, 0x05, 0xEC, 0x0A, 0x00, 0x00, 0x08, 0xD2, 0xCE, 0x55,
        0xB1, 0xC4, 0x67, 0xFB, 0x02, 0x00, 0x00, 0x00, 0x00, 0x04, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    // TODO: This uses the currently unimplemented x86 branch/call/jump filter.
    (void)decompressor->read_until_eof(PAGE_SIZE);
}

TEST_CASE(xz_utils_good_2_lzma2)
{
    // "good-2-lzma2.xz has one Stream with two Blocks with one uncompressed
    //  LZMA2 chunk in each Block."
    Array<u8, 92> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x00, 0x00, 0x00, 0x16, 0x35, 0x96, 0x31, 0x02, 0x00, 0x21, 0x01, 0x08, 0x00, 0x00, 0x00,
        0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x00,
        0xDD, 0xD1, 0xCA, 0x53, 0x00, 0x02, 0x1A, 0x06, 0x1B, 0x07, 0x00, 0x00, 0x06, 0xDC, 0xE7, 0x5D,
        0x3E, 0x30, 0x0D, 0x8B, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));
    auto buffer = TRY_OR_FAIL(decompressor->read_until_eof(PAGE_SIZE));
    EXPECT_EQ(buffer.span(), xz_utils_hello_world.bytes());
}

// The following test files are designated as "unsupported", which usually means that they test indicators
// for not-yet-specified features or where they test files that are not explicitly wrong but that would fail
// in the reference implementation due to self-imposed limits (i.e. filter ordering restrictions).

TEST_CASE(xz_utils_unsupported_block_header)
{
    // "unsupported-block_header.xz has a non-null byte in Header Padding,
    //  which may indicate presence of a new unsupported field."
    Array<u8, 68> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x01, 0x4E, 0x3F, 0x24, 0x64, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x43, 0xA3, 0xA2, 0x15,
        0x00, 0x01, 0x24, 0x0D, 0x30, 0x28, 0xDF, 0xAF, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));

    // 3.1.6. Header Padding:
    // "If any of the bytes are not null bytes, the decoder MUST
    //  indicate an error. It is possible that there is a new field
    //  present which the decoder is not aware of, and can thus parse
    //  the Block Header incorrectly."
    // We test for failure in accordance with the specification.
    // In our in-tree setup of tests and implementation, changing this down the line is trivial.
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_unsupported_check)
{
    // "unsupported-check.xz uses Check ID 0x02 which isn't supported by
    //  the current version of the file format."
    Array<u8, 68> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x02, 0xD3, 0x73, 0xD7, 0xAF, 0x02, 0x00, 0x21, 0x01,
        0x08, 0x00, 0x00, 0x00, 0xD8, 0x0F, 0x23, 0x13, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x43, 0xA3, 0xA2, 0x15,
        0x00, 0x01, 0x24, 0x0D, 0x30, 0x28, 0xDF, 0xAF, 0x2A, 0x13, 0x90, 0x94, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x02, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));

    // 2.1.1.2. Stream Flags:
    // "If an unsupported Check is used, the decoder SHOULD
    //  indicate a warning or error."
    // We are throwing errors for unknown check IDs, so let's check for that.
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_unsupported_filter_flags_1)
{
    // "unsupported-filter_flags-1.xz has unsupported Filter ID 0x7F."
    Array<u8, 68> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x7F, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x73, 0xDD, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x43, 0xA3, 0xA2, 0x15,
        0x00, 0x01, 0x24, 0x0D, 0x30, 0x28, 0xDF, 0xAF, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));

    // Behavior for unknown filter IDs is not specified at all, but we are throwing errors, so let's test for that.
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_unsupported_filter_flags_2)
{
    // "unsupported-filter_flags-2.xz specifies only Delta filter in the
    //  List of Filter Flags, but Delta isn't allowed as the last filter in
    //  the chain. It could be a little more correct to detect this file as
    //  corrupt instead of unsupported, but saying it is unsupported is
    //  simpler in case of liblzma."
    Array<u8, 68> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x00, 0x03, 0x01,
        0xFF, 0x00, 0x00, 0x00, 0xFB, 0x85, 0xF6, 0x42, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x43, 0xA3, 0xA2, 0x15,
        0x00, 0x01, 0x24, 0x0D, 0x30, 0x28, 0xDF, 0xAF, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));

    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}

TEST_CASE(xz_utils_unsupported_filter_flags_3)
{
    // "unsupported-filter_flags-3.xz specifies two LZMA2 filters in the
    //  List of Filter Flags. LZMA2 is allowed only as the last filter in the
    //  chain. It could be a little more correct to detect this file as
    //  corrupt instead of unsupported, but saying it is unsupported is
    //  simpler in case of liblzma."
    Array<u8, 68> const compressed {
        0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00, 0x01, 0x69, 0x22, 0xDE, 0x36, 0x02, 0x01, 0x21, 0x01,
        0x08, 0x21, 0x01, 0x08, 0xC8, 0x91, 0x1B, 0x9B, 0x01, 0x00, 0x05, 0x48, 0x65, 0x6C, 0x6C, 0x6F,
        0x0A, 0x02, 0x00, 0x06, 0x57, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0A, 0x00, 0x43, 0xA3, 0xA2, 0x15,
        0x00, 0x01, 0x24, 0x0D, 0x30, 0x28, 0xDF, 0xAF, 0x90, 0x42, 0x99, 0x0D, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x59, 0x5A
    };

    auto stream = MUST(try_make<FixedMemoryStream>(compressed));
    auto decompressor = MUST(Compress::XzDecompressor::create(move(stream)));

    // Similar to the recommended behavior of the specification, we reject LZMA2 filters if they aren't the last one.
    auto buffer_or_error = decompressor->read_until_eof(PAGE_SIZE);
    EXPECT(buffer_or_error.is_error());
}
