From 9c925923983c46cab0aaac1a4fe553a05fd04626 Mon Sep 17 00:00:00 2001 From: lzwdgc Date: Tue, 10 Jan 2023 17:31:26 +0300 Subject: [PATCH] [unpaker2] RLEW decompression. --- src/unpaker2/unpaker2.cpp | 89 ++++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 15 deletions(-) diff --git a/src/unpaker2/unpaker2.cpp b/src/unpaker2/unpaker2.cpp index 02c477e..3f96ddd 100644 --- a/src/unpaker2/unpaker2.cpp +++ b/src/unpaker2/unpaker2.cpp @@ -37,8 +37,6 @@ using namespace std; -constexpr auto supported_block_size = 32768; - #pragma pack(push, 1) struct pak { uint32_t magic; @@ -85,17 +83,46 @@ struct stream { } }; + +void decode_rle(const short *input, const int size, short *&output) { + if (size < 2) + return; + + // input ptr, also rle_indicator + const auto rle_indicator = input++; + while (1) { + auto c = *input++; + if ((c & 0xFF00) != (*rle_indicator << 8)) + *output++ = c; + else { + uint32_t count = (uint8_t)c; + if (count == (*rle_indicator << 8) + 255) + *output++ = c; // insert indicator byte itself + else { + count += 3; + for (int i = 0; i < count / 2; i++) { + *output++ = *input; + *output++ = *input; + } + for (int i = 0; i < ((count / 2) & 1); i++) { + *output++ = *input; + } + } + } + + if (input >= rle_indicator + size) + return; + } +} + void unpack_file(path fn) { primitives::templates2::mmap_file f{fn}; stream s{f}; pak p = s; - if (p.block_size != supported_block_size) { - throw std::runtime_error{"block size mismatch"}; - } auto descs = s.span(p.n_files); auto segments = s.span(p.n_blocks); std::vector bbb; - bbb.resize((segments.size() + 1) * supported_block_size); + bbb.resize((segments.size() + 1) * p.block_size * 4); auto pp = bbb.data(); for (auto &&seg : segments) { s.p = f.p + seg.offset; @@ -116,19 +143,51 @@ void unpack_file(path fn) { break; } case segment::decode_algorithm::rlew: { + /*short *pps = (short*)pp; + decode_rle((short*)s.p, len, pps); + pp = (uint8_t*)pps; + break;*/ auto base = s.p; uint16_t flag = s; - uint32_t outlen = 0; while (s.p < base + len) { - uint8_t w = s; - if (w == 0xfe && (*(uint8_t*)s.p) == flag) { - uint8_t w1 = s; - auto cntr = 0x20e; - uint8_t w2 = s; - while (cntr--) { + uint16_t w = s; + if ((w & 0xFF00) == (flag << 8)) { + uint16_t count = (uint8_t)w; + if (count == 0xff) { + uint16_t w2 = s; + *(decltype(w2) *)pp = w2; + pp += sizeof(w2); + continue; + } + if (count == (flag << 8) + 255) { + throw std::runtime_error{"untested branch"}; + *(decltype(w) *)pp = w; + pp += sizeof(w); + continue; + } + + + uint16_t w2 = s; + count += 3; + + while (count--) { *(decltype(w2)*)pp = w2; pp += sizeof(w2); } + + /* + * + for (int i = 0; i < count / 2; i++) { + *(decltype(w) *)pp = w2; + pp += sizeof(w2); + + *(decltype(w) *)pp = w2; + pp += sizeof(w2); + } + for (int i = 0; i < ((count / 2) & 1); i++) { + *(decltype(w) *)pp = w2; + pp += sizeof(w2); + }*/ } else { *(decltype(w)*)pp = w; pp += sizeof(w); @@ -143,9 +202,9 @@ void unpack_file(path fn) { strm.next_in = s.p; strm.avail_in = len; strm.next_out = pp; - strm.avail_out = 1'000'000; + strm.avail_out = p.block_size; - auto r = lzma_auto_decoder(&strm, 1'000'000'000, flags); + auto r = lzma_lzip_decoder(&strm, 10'000'000, flags); if (r != LZMA_OK) { throw std::runtime_error{"lzma error"}; }