Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- template <typename Callback>
- void compressed_block_iterate(const uint8_t *source_data, uint64_t source_size, Callback callback)
- {
- uint64_t position = 0xc;
- while (position < source_size)
- {
- uint32_t compressed_size = *reinterpret_cast<const uint32_t*>(source_data + position);
- position += sizeof(uint32_t);
- uint32_t uncompressed_size = *reinterpret_cast<const uint32_t*> (source_data + position);
- position += sizeof(uint32_t);
- const uint8_t *block_data = source_data + position;
- position += compressed_size;
- if (position >= source_size)
- break;
- position = (position + 3) & ~3; //make alignment
- callback(block_data, compressed_size, uncompressed_size);
- }
- }
- uint64_t calculate_uncompressed_size(const uint8_t *source_data, uint64_t source_size)
- {
- uint64_t result = 0;
- compressed_block_iterate(source_data, source_size, [&](const uint8_t *block_data, uint64_t compressed_size, uint64_t uncompressed_size)
- {
- result += uncompressed_size;
- });
- return result;
- }
- void decompress_block(const uint8_t *source_data, uint64_t source_size,
- uint8_t *destination_data, uint64_t destination_size)
- {
- uint64_t source_position = 0;
- uint64_t destination_position = 0;
- while (source_position < source_size)
- {
- uint8_t comp_byte = source_data[source_position++];
- uint32_t data_length = (comp_byte >> 4) & 0xf;
- uint32_t repeat_count = (comp_byte & 0xf);
- if (data_length == 0x0f)
- {
- while (true)
- {
- uint8_t data_length_byte = source_data[source_position++];
- data_length += data_length_byte;
- if (data_length_byte != 0xff)
- break;
- }
- }
- while (data_length--)
- {
- destination_data[destination_position++] = source_data[source_position++];
- }
- if (source_position >= source_size)
- {
- break;
- }
- uint32_t repeat_offset = *reinterpret_cast<const uint16_t*>(source_data + source_position);
- source_position += sizeof(uint16_t);
- uint64_t global_repeat_offset = destination_position - repeat_offset;
- if (repeat_count == 0x0f)
- {
- while (true)
- {
- uint8_t repeat_count_byte = source_data[source_position++];
- repeat_count += repeat_count_byte;
- if (repeat_count_byte != 0xff)
- break;
- }
- }
- for (uint32_t i = 0; i < repeat_count + 4; i++)
- {
- destination_data[destination_position++] = destination_data[global_repeat_offset + i];
- }
- }
- }
- std::unique_ptr<uint8_t[]> decompress_data(const uint8_t *source_data,
- uint64_t source_size, uint64_t &result_size)
- {
- result_size = calculate_uncompressed_size(source_data, source_size);
- std::unique_ptr<uint8_t[]> result_data = std::make_unique<uint8_t[]>(result_size);
- uint64_t destination_position = 0;
- compressed_block_iterate(source_data, source_size, [&](const uint8_t *block_data, uint64_t compressed_size, uint64_t uncompressed_size)
- {
- decompress_block(block_data, compressed_size,
- result_data.get() + destination_position, uncompressed_size);
- destination_position += uncompressed_size;
- });
- return result_data;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement