1#ifndef RPNX_COMPRESSION_IMPLEMENTATION_XZ_HPP
2#define RPNX_COMPRESSION_IMPLEMENTATION_XZ_HPP
33 inline constexpr std::uint32_t
range_top = 1U << 24U;
60 std::array< std::uint16_t, 256U >
high{};
72 std::array< std::uint16_t, state_count >
is_rep{};
73 std::array< std::uint16_t, state_count >
is_rep0{};
74 std::array< std::uint16_t, state_count >
is_rep1{};
75 std::array< std::uint16_t, state_count >
is_rep2{};
102 if (properties > 224U)
106 position_bits =
static_cast< std::uint8_t
>(properties / 45U);
107 std::uint8_t
const remainder =
static_cast< std::uint8_t
>(properties % 45U);
119 void fill_probabilities()
122 for (std::array< std::uint16_t, position_state_count >& probabilities :
is_match)
124 probabilities.fill(initial);
130 for (std::array< std::uint16_t, position_state_count >& probabilities :
is_rep0_long)
132 probabilities.fill(initial);
134 for (std::array< std::uint16_t, 64U >& probabilities :
distance_slot)
136 probabilities.fill(initial);
142 for (std::array< std::uint16_t, literal_coder_size >& probabilities :
literal)
144 probabilities.fill(initial);
152 model.choice = initial;
153 model.choice2 = initial;
154 for (std::array< std::uint16_t, 8U >& probabilities : model.low)
156 probabilities.fill(initial);
158 for (std::array< std::uint16_t, 8U >& probabilities : model.mid)
160 probabilities.fill(initial);
162 model.high.fill(initial);
176 if (input.size() < 5U)
178 throw compression_error(error_code::invalid_data, format::xz,
"truncated LZMA range-coded chunk");
180 for (std::size_t index = 0U; index < 5U; ++index)
182 m_code = (m_code << 8U) | read_byte();
191 [[nodiscard]] std::uint8_t
decode_bit(std::uint16_t& probability)
194 std::uint32_t
const bound = (m_range >> 11U) * probability;
213 [[nodiscard]] std::uint32_t
decode_tree(std::span< std::uint16_t > probabilities, std::uint32_t leaf_base)
215 std::uint32_t symbol = 1U;
216 while (symbol < leaf_base)
218 if (symbol >= probabilities.size())
222 symbol = (symbol << 1U) |
decode_bit(probabilities[symbol]);
234 [[nodiscard]] std::uint32_t
decode_reverse_tree(std::span< std::uint16_t > probabilities, std::ptrdiff_t base, std::uint8_t bit_count)
236 std::uint32_t symbol = 1U;
237 std::uint32_t value = 0U;
238 for (std::uint8_t bit_index = 0U; bit_index < bit_count; ++bit_index)
240 std::ptrdiff_t
const probability_index = base +
static_cast< std::ptrdiff_t
>(symbol);
241 if (probability_index < 0 ||
static_cast< std::size_t
>(probability_index) >= probabilities.size())
245 std::uint8_t
const bit =
decode_bit(probabilities[
static_cast< std::size_t
>(probability_index)]);
246 symbol = (symbol << 1U) | bit;
247 value |=
static_cast< std::uint32_t
>(bit) << bit_index;
259 std::uint32_t value = 0U;
260 for (std::uint8_t bit_index = 0U; bit_index < bit_count; ++bit_index)
264 std::uint8_t bit = 0U;
265 if (m_code >= m_range)
270 value = (value << 1U) | bit;
279 if (m_position != m_input.size() || m_code != 0U)
286 [[nodiscard]] std::uint8_t read_byte()
288 if (m_position >= m_input.size())
292 return std::to_integer< std::uint8_t >(m_input[m_position++]);
300 m_code = (m_code << 8U) | read_byte();
304 std::span< std::byte const > m_input;
305 std::size_t m_position = 0U;
306 std::uint32_t m_range = std::numeric_limits< std::uint32_t >::max();
307 std::uint32_t m_code = 0U;
319 void encode_bit(std::uint16_t& probability, std::uint8_t bit)
321 std::uint32_t
const bound = (m_range >> 11U) * probability;
344 [[nodiscard]] std::vector< std::byte >
finish()
346 for (std::size_t index = 0U; index < 5U; ++index)
350 return std::move(m_output);
356 std::uint32_t
const low =
static_cast< std::uint32_t
>(m_low);
357 std::uint32_t
const high =
static_cast< std::uint32_t
>(m_low >> 32U);
358 if (low < 0xff000000U || high != 0U)
360 std::uint8_t cached = m_cache;
363 m_output.push_back(
static_cast< std::byte
>(cached + high));
365 }
while (--m_cache_size != 0U);
366 m_cache =
static_cast< std::uint8_t
>(low >> 24U);
369 m_low =
static_cast< std::uint64_t
>(low & 0x00ffffffU) << 8U;
372 std::vector< std::byte > m_output;
373 std::uint64_t m_low = 0U;
374 std::uint32_t m_range = std::numeric_limits< std::uint32_t >::max();
375 std::uint8_t m_cache = 0U;
376 std::size_t m_cache_size = 1U;
384 [[nodiscard]]
inline std::uint32_t
crc32(std::span< std::byte const > input)
noexcept
386 std::uint32_t crc = 0xffffffffU;
387 for (std::byte value : input)
389 crc ^= std::to_integer< std::uint8_t >(value);
390 for (std::uint8_t bit = 0U; bit < 8U; ++bit)
392 crc = (crc & 1U) != 0U ? (crc >> 1U) ^ 0xedb88320U : crc >> 1U;
408 m_crc ^= std::to_integer< std::uint8_t >(
value);
409 for (std::uint8_t bit = 0U; bit < 8U; ++bit)
411 m_crc = (m_crc & 1U) != 0U ? (m_crc >> 1U) ^ 0xc96c5795d7870f42ULL : m_crc >> 1U;
419 [[nodiscard]] std::uint64_t
value() const noexcept
425 std::uint64_t m_crc = std::numeric_limits< std::uint64_t >::max();
435 [[nodiscard]]
inline std::uint64_t
read_little_endian(std::span< std::byte const > input, std::size_t& position, std::uint8_t byte_count)
437 if (position > input.size() || byte_count > input.size() - position)
441 std::uint64_t value = 0U;
442 for (std::uint8_t byte_index = 0U; byte_index < byte_count; ++byte_index)
444 value |=
static_cast< std::uint64_t
>(std::to_integer< std::uint8_t >(input[position++])) << (byte_index * 8U);
458 std::uint64_t value = 0U;
459 for (std::uint8_t byte_index = 0U; byte_index < 9U; ++byte_index)
461 if (position >= input.size())
465 std::uint8_t
const byte = std::to_integer< std::uint8_t >(input[position++]);
466 if (byte_index != 0U &&
byte == 0U)
470 value |=
static_cast< std::uint64_t
>(
byte & 0x7fU) << (byte_index * 7U);
471 if ((
byte & 0x80U) == 0U)
484 [[nodiscard]]
inline std::size_t
check_size(std::uint8_t check_identifier)
486 constexpr std::array< std::size_t, 16U > sizes{0U, 4U, 4U, 4U, 8U, 8U, 8U, 16U, 16U, 16U, 32U, 32U, 32U, 64U, 64U, 64U};
487 return sizes[check_identifier];
500 else if (state <= 9U)
502 state =
static_cast< std::uint8_t
>(state - 3U);
506 state =
static_cast< std::uint8_t
>(state - 6U);
521 return 2U + decoder.
decode_tree(model.
low[position_state], 8U) - 8U;
525 return 10U + decoder.
decode_tree(model.
mid[position_state], 8U) - 8U;
539 inline void copy_match(std::vector< std::byte >& output, std::size_t history_begin, std::uint32_t dictionary_size, std::uint32_t distance, std::uint32_t length, std::size_t output_limit)
541 std::size_t
const history_size = output.size() - history_begin;
542 if (distance >= history_size || distance >= dictionary_size)
546 if (output.size() > output_limit || length > output_limit - output.size())
550 for (std::uint32_t index = 0U; index < length; ++index)
552 output.push_back(output[output.size() - distance - 1U]);
567 inline void decode_lzma_chunk(std::span< std::byte const > encoded, std::size_t uncompressed_size,
lzma_model& model, std::vector< std::byte >& output, std::size_t history_begin, std::uint32_t dictionary_size, std::size_t output_limit, std::size_t dictionary_position_offset = 0U)
569 if (output.size() > output_limit || uncompressed_size > output_limit - output.size())
573 std::size_t
const target_size = output.size() + uncompressed_size;
575 while (output.size() < target_size)
577 std::size_t
const dictionary_position = dictionary_position_offset + output.size() - history_begin;
578 std::size_t
const position_state = dictionary_position & ((std::size_t{1U} << model.
position_bits) - 1U);
581 std::uint8_t
const previous = dictionary_position == 0U ? 0U : std::to_integer< std::uint8_t >(output.back());
583 std::array< std::uint16_t, literal_coder_size >& probabilities = model.
literal[literal_context];
584 std::uint32_t symbol = 1U;
585 if (model.
state < 7U)
587 symbol = decoder.
decode_tree(probabilities, 0x100U);
591 if (model.
rep0 >= dictionary_position || model.
rep0 >= dictionary_size)
595 std::uint32_t match_byte =
static_cast< std::uint32_t
>(std::to_integer< std::uint8_t >(output[output.size() - model.
rep0 - 1U])) << 1U;
596 std::uint32_t offset = 0x100U;
597 while (symbol < 0x100U)
599 std::uint32_t
const match_bit = match_byte & offset;
601 std::size_t
const probability_index = offset + match_bit + symbol;
602 std::uint8_t
const bit = decoder.
decode_bit(probabilities[probability_index]);
603 symbol = (symbol << 1U) | bit;
604 offset &= bit != 0U ? match_bit : ~match_bit;
607 output.push_back(
static_cast< std::byte
>(symbol));
612 std::uint32_t length = 0U;
620 std::size_t
const distance_state = std::min< std::size_t >(length - 2U, 3U);
628 std::uint8_t
const additional_bits =
static_cast< std::uint8_t
>((slot >> 1U) - 1U);
629 model.
rep0 = 2U + (slot & 1U);
632 model.
rep0 <<= additional_bits;
633 std::ptrdiff_t
const base =
static_cast< std::ptrdiff_t
>(model.
rep0) -
static_cast< std::ptrdiff_t
>(slot) - 1;
638 std::uint8_t
const direct_bits =
static_cast< std::uint8_t
>(additional_bits - 4U);
657 std::uint32_t distance = 0U;
660 distance = model.
rep1;
666 distance = model.
rep2;
670 distance = model.
rep3;
676 model.
rep0 = distance;
684 if (length > target_size - output.size())
688 copy_match(output, history_begin, dictionary_size, model.
rep0, length, output_limit);
701 [[nodiscard]]
inline std::vector< std::byte >
compress_lzma_literals(std::span< std::byte const > input,
lzma_model& model, std::size_t dictionary_position, std::uint8_t previous_byte)
704 for (std::byte value : input)
706 std::size_t
const position_state = dictionary_position & ((std::size_t{1U} << model.
position_bits) - 1U);
709 std::array< std::uint16_t, literal_coder_size >& probabilities = model.
literal[literal_context];
710 std::uint32_t symbol = 1U;
711 std::uint8_t
const byte = std::to_integer< std::uint8_t >(value);
712 for (std::uint8_t bit_index = 0U; bit_index < 8U; ++bit_index)
714 std::uint8_t
const bit =
static_cast< std::uint8_t
>((
byte >> (7U - bit_index)) & 1U);
715 encoder.
encode_bit(probabilities[symbol], bit);
716 symbol = (symbol << 1U) | bit;
719 previous_byte = byte;
720 ++dictionary_position;
732 if (properties > 40U)
736 if (properties == 40U)
738 return std::numeric_limits< std::uint32_t >::max();
740 std::uint32_t size = 2U | (properties & 1U);
741 size <<= static_cast< std::uint8_t >(properties / 2U + 11U);
756 template < std::input_iterator input_iterator, std::sentinel_for< input_iterator > sentinel,
typename output_iterator >
759 std::int32_t
const level = options.
level.value_or(6);
760 if (level < 0 || level > 9)
764 auto write_bytes = [&](std::span< std::byte const > bytes)
766 for (std::byte value : bytes)
771 auto write_little_endian = [&](std::uint64_t value, std::uint8_t count)
773 for (std::uint8_t index = 0U; index < count; ++index)
779 constexpr std::array< std::byte, 6U > magic{std::byte{0xfd}, std::byte{
'7'}, std::byte{
'z'}, std::byte{
'X'}, std::byte{
'Z'}, std::byte{0}};
781 constexpr std::array< std::byte, 2U > stream_flags{std::byte{0}, std::byte{4}};
782 write_bytes(stream_flags);
783 write_little_endian(
crc32(stream_flags), 4U);
785 std::array< std::byte, 12U > header{std::byte{2}, std::byte{0}, std::byte{0x21}, std::byte{1}, std::byte{22}, std::byte{0}, std::byte{0}, std::byte{0}};
786 std::uint32_t
const header_crc =
crc32(std::span< std::byte const >(header).first(8U));
787 for (std::uint8_t index = 0U; index < 4U; ++index)
789 header[8U + index] =
static_cast< std::byte
>(header_crc >> (index * 8U));
795 bool dictionary_reset_needed =
true;
796 bool properties_needed =
true;
797 std::size_t dictionary_position = 0U;
798 std::uint8_t previous_byte = 0U;
799 std::uint64_t uncompressed_size = 0U;
800 std::uint64_t compressed_size = 0U;
802 std::vector< std::byte > chunk;
803 chunk.reserve(60000U);
804 while (first != last)
807 while (first != last && chunk.size() < 60000U)
811 chunk.push_back(value);
816 if (properties_needed)
820 std::vector< std::byte > compressed;
825 std::size_t
const compressed_header_size = properties_needed ? 6U : 5U;
826 bool const use_compressed = level != 0 && compressed.size() <= 65536U && compressed.size() + compressed_header_size < chunk.size() + 3U;
829 std::uint8_t control = dictionary_reset_needed ? 0xe0U : properties_needed ? 0xc0U : 0x80U;
830 control |=
static_cast< std::uint8_t
>((chunk.size() - 1U) >> 16U);
836 compressed_size += 5U;
837 if (properties_needed)
842 write_bytes(compressed);
843 compressed_size += compressed.size();
844 model = std::move(candidate_model);
845 dictionary_reset_needed =
false;
846 properties_needed =
false;
854 compressed_size += chunk.size() + 3U;
855 if (dictionary_reset_needed)
857 dictionary_reset_needed =
false;
858 properties_needed =
true;
859 dictionary_position = 0U;
862 dictionary_position += chunk.size();
863 previous_byte = std::to_integer< std::uint8_t >(chunk.back());
867 for (std::size_t padding =
static_cast< std::size_t
>((4U - compressed_size % 4U) % 4U); padding > 0U; --padding)
871 write_little_endian(block_crc.
value(), 8U);
873 std::uint64_t
const unpadded_size = header.size() + compressed_size + 8U;
875 std::size_t index_size = 0U;
876 auto write_index_byte = [&](std::byte value)
882 auto write_index_integer = [&](std::uint64_t value)
886 std::uint8_t
byte =
static_cast< std::uint8_t
>(value & 0x7fU);
892 write_index_byte(
static_cast< std::byte
>(
byte));
893 }
while (value != 0U);
895 write_index_byte(std::byte{0});
896 write_index_integer(1U);
897 write_index_integer(unpadded_size);
898 write_index_integer(uncompressed_size);
899 while (index_size % 4U != 0U)
901 write_index_byte(std::byte{0});
903 write_little_endian(index_crc.
value(), 4U);
905 std::array< std::byte, 6U > footer{
static_cast< std::byte
>((index_size + 4U) / 4U - 1U),
static_cast< std::byte
>(((index_size + 4U) / 4U - 1U) >> 8U),
static_cast< std::byte
>(((index_size + 4U) / 4U - 1U) >> 16U),
static_cast< std::byte
>(((index_size + 4U) / 4U - 1U) >> 24U), std::byte{0}, std::byte{4}};
906 write_little_endian(
crc32(footer), 4U);
924 template < std::input_iterator input_iterator, std::sentinel_for< input_iterator > sentinel,
typename output_iterator >
928 auto read_byte = [&]() -> std::byte
931 if (!source.
read(value))
937 auto read_little_endian_source = [&](std::uint8_t count) -> std::uint64_t
939 std::uint64_t value = 0U;
940 for (std::uint8_t index = 0U; index < count; ++index)
942 value |=
static_cast< std::uint64_t
>(std::to_integer< std::uint8_t >(read_byte())) << (index * 8U);
946 std::size_t total_output = 0U;
947 bool decoded_stream =
false;
954 constexpr std::array< std::byte, 6U > magic{std::byte{0xfd}, std::byte{
'7'}, std::byte{
'z'}, std::byte{
'X'}, std::byte{
'Z'}, std::byte{0}};
955 for (std::byte expected : magic)
957 if (read_byte() != expected)
962 std::array< std::byte, 2U >
const stream_flags{read_byte(), read_byte()};
963 if (stream_flags[0U] != std::byte{0} || (std::to_integer< std::uint8_t >(stream_flags[1U]) & 0xf0U) != 0U)
967 if (read_little_endian_source(4U) !=
crc32(stream_flags))
971 std::uint8_t
const check_identifier = std::to_integer< std::uint8_t >(stream_flags[1U]);
972 if (check_identifier != 0U && check_identifier != 1U && check_identifier != 4U)
977 std::vector< block_record > records;
980 std::uint8_t
const encoded_header_size = std::to_integer< std::uint8_t >(read_byte());
981 if (encoded_header_size == 0U)
985 std::size_t
const header_size = (
static_cast< std::size_t
>(encoded_header_size) + 1U) * 4U;
986 if (header_size < 8U)
990 std::vector< std::byte > header;
991 header.reserve(header_size);
992 header.push_back(
static_cast< std::byte
>(encoded_header_size));
993 for (std::size_t index = 1U; index < header_size; ++index)
995 header.push_back(read_byte());
997 std::size_t header_crc_position = header_size - 4U;
998 if (
read_little_endian(header, header_crc_position, 4U) !=
crc32(std::span< std::byte const >(header).first(header_size - 4U)))
1002 std::size_t header_position = 1U;
1003 std::uint8_t
const block_flags = std::to_integer< std::uint8_t >(header[header_position++]);
1004 if ((block_flags & 0x3cU) != 0U)
1008 std::size_t
const filter_count = (block_flags & 0x03U) + 1U;
1009 std::optional< std::uint64_t > declared_compressed_size;
1010 std::optional< std::uint64_t > declared_uncompressed_size;
1011 std::span< std::byte const >
const header_fields = std::span< std::byte const >(header).first(header_size - 4U);
1012 if ((block_flags & 0x40U) != 0U)
1016 if ((block_flags & 0x80U) != 0U)
1024 std::uint32_t
const dictionary_size =
decode_dictionary_size(std::to_integer< std::uint8_t >(header[header_position++]));
1025 while (header_position < header_size - 4U)
1027 if (header[header_position++] != std::byte{0})
1033 std::vector< std::byte > history;
1035 bool need_dictionary_reset =
true;
1036 bool need_properties =
true;
1037 std::size_t dictionary_position = 0U;
1038 std::uint64_t compressed_size = 0U;
1039 std::uint64_t block_output_size = 0U;
1042 auto emit = [&](std::byte value)
1048 block_crc32.
update(value);
1049 block_crc64.
update(value);
1052 ++block_output_size;
1057 std::uint8_t
const control = std::to_integer< std::uint8_t >(read_byte());
1063 if (control >= 0xe0U || control == 0x01U)
1066 dictionary_position = 0U;
1067 need_dictionary_reset =
false;
1068 need_properties =
true;
1070 else if (need_dictionary_reset)
1074 if (control < 0x80U)
1076 if (control > 0x02U)
1080 std::size_t
const chunk_size = (
static_cast< std::size_t
>(std::to_integer< std::uint8_t >(read_byte())) << 8U) | std::to_integer< std::uint8_t >(read_byte());
1081 compressed_size += 2U;
1082 for (std::size_t index = 0U; index <= chunk_size; ++index)
1084 std::byte
const value = read_byte();
1086 history.push_back(value);
1089 dictionary_position += chunk_size + 1U;
1090 if (history.size() > dictionary_size)
1092 history.erase(history.begin(), history.begin() +
static_cast< std::ptrdiff_t
>(history.size() - dictionary_size));
1097 std::size_t
const uncompressed_size = (
static_cast< std::size_t
>(control & 0x1fU) << 16U) | (
static_cast< std::size_t
>(std::to_integer< std::uint8_t >(read_byte())) << 8U) | std::to_integer< std::uint8_t >(read_byte());
1098 std::size_t
const compressed_chunk_size = (
static_cast< std::size_t
>(std::to_integer< std::uint8_t >(read_byte())) << 8U) | std::to_integer< std::uint8_t >(read_byte());
1099 compressed_size += 4U;
1100 if (control >= 0xc0U)
1102 model.
set_properties(std::to_integer< std::uint8_t >(read_byte()));
1104 need_properties =
false;
1106 else if (need_properties)
1110 else if (control >= 0xa0U)
1114 std::vector< std::byte > encoded;
1115 encoded.reserve(compressed_chunk_size + 1U);
1116 for (std::size_t index = 0U; index <= compressed_chunk_size; ++index)
1118 encoded.push_back(read_byte());
1120 compressed_size += compressed_chunk_size + 1U;
1121 std::vector< std::byte > working = std::move(history);
1122 std::size_t
const history_size = working.size();
1123 decode_lzma_chunk(encoded, uncompressed_size + 1U, model, working, 0U, dictionary_size, history_size + uncompressed_size + 1U, dictionary_position - history_size);
1124 for (std::size_t index = history_size; index < working.size(); ++index)
1126 emit(working[index]);
1128 dictionary_position += uncompressed_size + 1U;
1129 std::size_t
const retained = std::min< std::size_t >(working.size(), dictionary_size);
1130 history.assign(working.end() -
static_cast< std::ptrdiff_t
>(retained), working.end());
1132 if (declared_compressed_size.has_value() && *declared_compressed_size != compressed_size)
1136 if (declared_uncompressed_size.has_value() && *declared_uncompressed_size != block_output_size)
1140 for (std::size_t padding =
static_cast< std::size_t
>((4U - compressed_size % 4U) % 4U); padding > 0U; --padding)
1142 if (read_byte() != std::byte{0})
1147 if (check_identifier == 1U && read_little_endian_source(4U) != block_crc32.
value())
1151 if (check_identifier == 4U && read_little_endian_source(8U) != block_crc64.
value())
1155 records.push_back(
block_record{header_size + compressed_size +
check_size(check_identifier), block_output_size});
1159 index_crc.
update(std::byte{0});
1160 std::size_t index_size = 1U;
1161 auto read_index_byte = [&]() -> std::byte
1163 std::byte
const value = read_byte();
1168 auto read_index_integer = [&]() -> std::uint64_t
1170 std::uint64_t value = 0U;
1171 for (std::uint8_t byte_index = 0U; byte_index < 9U; ++byte_index)
1173 std::uint8_t
const byte = std::to_integer< std::uint8_t >(read_index_byte());
1174 if (byte_index != 0U &&
byte == 0U)
1178 value |=
static_cast< std::uint64_t
>(
byte & 0x7fU) << (byte_index * 7U);
1179 if ((
byte & 0x80U) == 0U)
1186 if (read_index_integer() != records.size())
1192 if (read_index_integer() != record.unpadded_size || read_index_integer() != record.uncompressed_size)
1197 while (index_size % 4U != 0U)
1199 if (read_index_byte() != std::byte{0})
1204 if (read_little_endian_source(4U) != index_crc.
value())
1209 std::array< std::byte, 12U > footer{};
1210 for (std::byte& value : footer)
1212 value = read_byte();
1214 std::size_t footer_position = 0U;
1215 std::uint32_t
const expected_footer_crc =
static_cast< std::uint32_t
>(
read_little_endian(footer, footer_position, 4U));
1216 if (
crc32(std::span< std::byte const >(footer).subspan(4U, 6U)) != expected_footer_crc)
1220 std::uint64_t
const backward_size = (
read_little_endian(footer, footer_position, 4U) + 1U) * 4U;
1221 if (backward_size != index_size || footer[8U] != stream_flags[0U] || footer[9U] != stream_flags[1U] || footer[10U] != std::byte{
'Y'} || footer[11U] != std::byte{
'Z'})
1225 decoded_stream =
true;
1226 std::size_t padding_size = 0U;
1228 while (source.
peek(next) && next == std::byte{0})
1230 static_cast< void >(read_byte());
1233 if (padding_size % 4U != 0U)
1237 }
while (!source.
empty());
Exception raised for malformed streams, invalid options, and codec failures.
Single-pass byte reader over an input iterator and sentinel.
bool peek(std::byte &value)
Inspects the next byte without consuming it.
bool empty() const
Tests whether no unread byte remains.
bool read(std::byte &value)
Reads one byte.
Incremental reflected IEEE CRC-32 accumulator.
std::uint32_t value() const noexcept
Returns the checksum for all bytes supplied so far.
void update(std::byte value) noexcept
Includes one byte in the checksum.
Incremental CRC-64/XZ accumulator for streamed block data.
std::uint64_t value() const noexcept
Returns the checksum for all supplied bytes.
void update(std::byte value) noexcept
Includes one byte in the checksum.
One-shot LZMA range decoder.
void finish()
Validate exact consumption and the LZMA terminal range state.
range_decoder(std::span< std::byte const > input)
Initializes a decoder from one complete LZMA chunk.
std::uint32_t decode_direct(std::uint8_t bit_count)
Decodes equiprobable direct bits.
std::uint8_t decode_bit(std::uint16_t &probability)
Decodes one adaptive binary symbol.
std::uint32_t decode_tree(std::span< std::uint16_t > probabilities, std::uint32_t leaf_base)
Decodes a most-significant-bit-first probability tree.
std::uint32_t decode_reverse_tree(std::span< std::uint16_t > probabilities, std::ptrdiff_t base, std::uint8_t bit_count)
Decodes a least-significant-bit-first probability tree.
One-shot LZMA range encoder used by the deterministic literal encoder.
void encode_bit(std::uint16_t &probability, std::uint8_t bit)
Encodes one adaptive binary symbol.
std::vector< std::byte > finish()
Finishes the range stream.
Shared iterator, byte-conversion, and checksum primitives.
void write_byte(output_iterator &output, std::byte value)
Writes one byte through an output iterator and advances it.
constexpr std::byte to_byte(value_type value) noexcept
Converts one supported iterator value to std::byte.
Internal implementation of xz and its LZMA2 payload format.
constexpr std::size_t state_count
Number of LZMA state-machine states.
void decode_lzma_chunk(std::span< std::byte const > encoded, std::size_t uncompressed_size, lzma_model &model, std::vector< std::byte > &output, std::size_t history_begin, std::uint32_t dictionary_size, std::size_t output_limit, std::size_t dictionary_position_offset=0U)
Decodes one LZMA range-coded chunk into an LZMA2 dictionary.
constexpr std::uint32_t probability_total
LZMA probability-model total.
constexpr std::size_t position_state_count
Maximum number of position states.
constexpr std::size_t literal_coder_count
Number of literal contexts retained by the supported properties.
std::uint32_t decode_length(range_decoder &decoder, lzma_model::length_model &model, std::size_t position_state)
Decodes one LZMA match length.
std::size_t check_size(std::uint8_t check_identifier)
Returns the number of bytes in an xz integrity check.
std::uint32_t crc32(std::span< std::byte const > input) noexcept
Computes the reflected CRC-32 used by xz metadata and checks.
constexpr std::size_t literal_coder_size
Probability count in one LZMA literal coder.
constexpr std::uint32_t probability_move_bits
Adaptation shift applied after every probability decision.
output_iterator decompress(input_iterator first, sentinel last, output_iterator output, decompression_options const &options)
Decompresses one or more xz streams containing LZMA2.
std::uint64_t read_variable_integer(std::span< std::byte const > input, std::size_t &position)
Decodes one minimal xz variable-length integer.
std::uint32_t decode_dictionary_size(std::uint8_t properties)
Decodes the one-byte LZMA2 dictionary-size property.
void copy_match(std::vector< std::byte > &output, std::size_t history_begin, std::uint32_t dictionary_size, std::uint32_t distance, std::uint32_t length, std::size_t output_limit)
Copies one validated LZMA match into the output dictionary.
void update_literal_state(std::uint8_t &state) noexcept
Updates an LZMA state after decoding a literal.
output_iterator compress(input_iterator first, sentinel last, output_iterator output, compression_options const &options)
Compresses an iterator range as an xz stream containing LZMA2.
std::vector< std::byte > compress_lzma_literals(std::span< std::byte const > input, lzma_model &model, std::size_t dictionary_position, std::uint8_t previous_byte)
Encodes a literal-only LZMA range-coded chunk.
std::uint64_t read_little_endian(std::span< std::byte const > input, std::size_t &position, std::uint8_t byte_count)
Reads a fixed-width little-endian integer.
constexpr std::uint32_t range_top
Range threshold below which the arithmetic coder normalizes.
@ xz
xz container containing LZMA2 data.
@ trailing_data
Bytes remain after the permitted stream members.
@ output_limit_exceeded
Decoding would exceed a configured resource limit.
@ invalid_option
An option or format value is outside its accepted range.
@ unsupported_feature
Valid input requires a format feature not implemented by the library.
@ invalid_data
The input does not conform to the selected format.
Options shared by compression operations.
std::optional< std::int32_t > level
Optional format-specific compression level.
Resource and stream-validation policy for decompression operations.
std::size_t maximum_output_size
Maximum total number of bytes the operation may emit.
bool allow_concatenated_streams
Whether to decode adjacent members for formats that define concatenation.
Size metadata collected while decoding one xz block.
std::uint64_t uncompressed_size
Number of bytes produced by the block.
std::uint64_t unpadded_size
Header, payload, and check size before four-byte padding.
Probability tables for the three LZMA match-length ranges.
std::array< std::array< std::uint16_t, 8U >, position_state_count > mid
Middle-range trees by position state.
std::uint16_t choice2
Selects the middle or high range.
std::array< std::uint16_t, 256U > high
High-range probability tree.
std::uint16_t choice
Selects the low range.
std::array< std::array< std::uint16_t, 8U >, position_state_count > low
Low-range trees by position state.
Adaptive probability tables and state used by LZMA.
std::array< std::uint16_t, state_count > is_rep0
Most-recent-distance probabilities.
std::uint32_t rep2
Third most recent repeated distance minus one.
std::uint8_t state
Current LZMA literal/match state.
std::uint8_t position_bits
Number of low position bits selecting a position state.
length_model match_length
Length model for new matches.
std::array< std::uint16_t, 114U > distance_special
Probability trees for middle distance bits.
std::uint32_t rep0
Most recent repeated match distance minus one.
length_model repeated_length
Length model for repeated matches.
void set_properties(std::uint8_t properties)
Configures lc, lp, and pb from one LZMA properties byte.
std::array< std::array< std::uint16_t, position_state_count >, state_count > is_rep0_long
Short repeated-match probabilities.
std::uint32_t rep1
Second most recent repeated distance minus one.
std::uint8_t literal_position_bits
Number of low position bits in a literal context.
std::array< std::array< std::uint16_t, position_state_count >, state_count > is_match
Literal-versus-match probabilities.
std::array< std::array< std::uint16_t, literal_coder_size >, literal_coder_count > literal
Literal probability trees by context.
std::array< std::uint16_t, 16U > distance_align
Reversed tree for low aligned distance bits.
std::array< std::uint16_t, state_count > is_rep1
Second-distance probabilities.
std::array< std::array< std::uint16_t, 64U >, 4U > distance_slot
Distance-slot trees by match-length state.
std::array< std::uint16_t, state_count > is_rep
New-versus-repeated match probabilities.
std::uint8_t literal_context_bits
Number of high previous-byte bits in a literal context.
std::array< std::uint16_t, state_count > is_rep2
Third-versus-fourth distance probabilities.
std::uint32_t rep3
Fourth most recent repeated distance minus one.
void reset()
Reset the probability model and recent-match state.