Xz.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /*
  2. * Copyright (c) 2023, Tim Schumacher <timschumi@gmx.de>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/CircularBuffer.h>
  8. #include <AK/ConstrainedStream.h>
  9. #include <AK/CountingStream.h>
  10. #include <AK/Endian.h>
  11. #include <AK/Error.h>
  12. #include <AK/MaybeOwned.h>
  13. #include <AK/NonnullOwnPtr.h>
  14. #include <AK/OwnPtr.h>
  15. #include <AK/Stream.h>
  16. #include <AK/Vector.h>
  17. namespace Compress {
  18. // This implementation is based on the "The .xz File Format" specification version 1.1.0:
  19. // https://tukaani.org/xz/xz-file-format-1.1.0.txt
  20. // 1.2. Multibyte Integers
  21. class [[gnu::packed]] XzMultibyteInteger {
  22. public:
  23. constexpr XzMultibyteInteger() = default;
  24. constexpr XzMultibyteInteger(u64 value)
  25. : m_value(value)
  26. {
  27. }
  28. constexpr operator u64() const { return m_value; }
  29. static ErrorOr<XzMultibyteInteger> read_from_stream(Stream& stream);
  30. private:
  31. u64 m_value { 0 };
  32. };
  33. // 2.1.1.2. Stream Flags
  34. enum XzStreamCheckType : u8 {
  35. None = 0x00,
  36. CRC32 = 0x01,
  37. CRC64 = 0x04,
  38. SHA256 = 0x0A,
  39. };
  40. // 2.1.1.2. Stream Flags
  41. struct [[gnu::packed]] XzStreamFlags {
  42. u8 reserved;
  43. XzStreamCheckType check_type : 4;
  44. u8 reserved_bits : 4;
  45. };
  46. static_assert(sizeof(XzStreamFlags) == 2);
  47. // 2.1.1. Stream Header
  48. struct [[gnu::packed]] XzStreamHeader {
  49. u8 magic[6];
  50. XzStreamFlags flags;
  51. LittleEndian<u32> flags_crc32;
  52. ErrorOr<void> validate() const;
  53. };
  54. static_assert(sizeof(XzStreamHeader) == 12);
  55. // 2.1.2. Stream Footer
  56. struct [[gnu::packed]] XzStreamFooter {
  57. LittleEndian<u32> size_and_flags_crc32;
  58. LittleEndian<u32> encoded_backward_size;
  59. XzStreamFlags flags;
  60. u8 magic[2];
  61. ErrorOr<void> validate() const;
  62. u32 backward_size() const;
  63. };
  64. static_assert(sizeof(XzStreamFooter) == 12);
  65. // 3.1.2. Block Flags
  66. struct [[gnu::packed]] XzBlockFlags {
  67. u8 encoded_number_of_filters : 2;
  68. u8 reserved : 4;
  69. bool compressed_size_present : 1;
  70. bool uncompressed_size_present : 1;
  71. size_t number_of_filters() const;
  72. };
  73. static_assert(sizeof(XzBlockFlags) == 1);
  74. // 5.3.1. LZMA2
  75. struct [[gnu::packed]] XzFilterLzma2Properties {
  76. u8 encoded_dictionary_size : 6;
  77. u8 reserved : 2;
  78. ErrorOr<void> validate() const;
  79. u32 dictionary_size() const;
  80. };
  81. static_assert(sizeof(XzFilterLzma2Properties) == 1);
  82. // 5.3.2. Branch/Call/Jump Filters for Executables
  83. struct [[gnu::packed]] XzFilterBCJProperties {
  84. u32 start_offset;
  85. };
  86. static_assert(sizeof(XzFilterBCJProperties) == 4);
  87. class XzFilterBCJArm64 : public Stream {
  88. public:
  89. static ErrorOr<NonnullOwnPtr<XzFilterBCJArm64>> create(MaybeOwned<Stream>, u32 start_offset);
  90. virtual ErrorOr<Bytes> read_some(Bytes) override;
  91. virtual ErrorOr<size_t> write_some(ReadonlyBytes) override;
  92. virtual bool is_eof() const override;
  93. virtual bool is_open() const override;
  94. virtual void close() override;
  95. private:
  96. static constexpr size_t INSTRUCTION_ALIGNMENT = 4;
  97. static constexpr size_t INSTRUCTION_SIZE = 4;
  98. XzFilterBCJArm64(CountingStream, u32 start_offset, CircularBuffer input_buffer, CircularBuffer output_buffer);
  99. CountingStream m_stream;
  100. u32 m_start_offset;
  101. CircularBuffer m_input_buffer;
  102. CircularBuffer m_output_buffer;
  103. };
  104. // 5.3.3. Delta
  105. struct [[gnu::packed]] XzFilterDeltaProperties {
  106. u8 encoded_distance;
  107. u32 distance() const;
  108. };
  109. static_assert(sizeof(XzFilterDeltaProperties) == 1);
  110. class XzFilterDelta : public Stream {
  111. public:
  112. static ErrorOr<NonnullOwnPtr<XzFilterDelta>> create(MaybeOwned<Stream>, u32 distance);
  113. virtual ErrorOr<Bytes> read_some(Bytes) override;
  114. virtual ErrorOr<size_t> write_some(ReadonlyBytes) override;
  115. virtual bool is_eof() const override;
  116. virtual bool is_open() const override;
  117. virtual void close() override;
  118. private:
  119. XzFilterDelta(MaybeOwned<Stream>, CircularBuffer);
  120. MaybeOwned<Stream> m_stream;
  121. CircularBuffer m_buffer;
  122. };
  123. class XzDecompressor : public Stream {
  124. public:
  125. static ErrorOr<NonnullOwnPtr<XzDecompressor>> create(MaybeOwned<Stream>);
  126. virtual ErrorOr<Bytes> read_some(Bytes) override;
  127. virtual ErrorOr<size_t> write_some(ReadonlyBytes) override;
  128. virtual bool is_eof() const override;
  129. virtual bool is_open() const override;
  130. virtual void close() override;
  131. private:
  132. XzDecompressor(NonnullOwnPtr<CountingStream>);
  133. ErrorOr<bool> load_next_stream();
  134. ErrorOr<void> load_next_block(u8 encoded_block_header_size);
  135. ErrorOr<void> finish_current_block();
  136. ErrorOr<void> finish_current_stream();
  137. NonnullOwnPtr<CountingStream> m_stream;
  138. Optional<XzStreamFlags> m_stream_flags;
  139. bool m_found_first_stream_header { false };
  140. bool m_found_last_stream_footer { false };
  141. Optional<MaybeOwned<Stream>> m_current_block_stream {};
  142. Optional<u64> m_current_block_expected_uncompressed_size {};
  143. u64 m_current_block_uncompressed_size {};
  144. u64 m_current_block_start_offset {};
  145. struct BlockMetadata {
  146. u64 uncompressed_size {};
  147. u64 unpadded_size {};
  148. };
  149. Vector<BlockMetadata> m_processed_blocks;
  150. };
  151. }
  152. template<>
  153. struct AK::Traits<Compress::XzStreamHeader> : public AK::DefaultTraits<Compress::XzStreamHeader> {
  154. static constexpr bool is_trivially_serializable() { return true; }
  155. };
  156. template<>
  157. struct AK::Traits<Compress::XzStreamFooter> : public AK::DefaultTraits<Compress::XzStreamFooter> {
  158. static constexpr bool is_trivially_serializable() { return true; }
  159. };
  160. template<>
  161. struct AK::Traits<Compress::XzBlockFlags> : public AK::DefaultTraits<Compress::XzBlockFlags> {
  162. static constexpr bool is_trivially_serializable() { return true; }
  163. };