mirror of
https://github.com/aimrebirth/tools.git
synced 2026-04-14 17:33:25 +00:00
[unpaker2] RLEW decompression.
This commit is contained in:
parent
b3c0b0489e
commit
9c92592398
1 changed files with 74 additions and 15 deletions
|
|
@ -37,8 +37,6 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
constexpr auto supported_block_size = 32768;
|
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct pak {
|
struct pak {
|
||||||
uint32_t magic;
|
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) {
|
void unpack_file(path fn) {
|
||||||
primitives::templates2::mmap_file<uint8_t> f{fn};
|
primitives::templates2::mmap_file<uint8_t> f{fn};
|
||||||
stream s{f};
|
stream s{f};
|
||||||
pak p = s;
|
pak p = s;
|
||||||
if (p.block_size != supported_block_size) {
|
|
||||||
throw std::runtime_error{"block size mismatch"};
|
|
||||||
}
|
|
||||||
auto descs = s.span<file_description>(p.n_files);
|
auto descs = s.span<file_description>(p.n_files);
|
||||||
auto segments = s.span<segment>(p.n_blocks);
|
auto segments = s.span<segment>(p.n_blocks);
|
||||||
std::vector<uint8_t> bbb;
|
std::vector<uint8_t> bbb;
|
||||||
bbb.resize((segments.size() + 1) * supported_block_size);
|
bbb.resize((segments.size() + 1) * p.block_size * 4);
|
||||||
auto pp = bbb.data();
|
auto pp = bbb.data();
|
||||||
for (auto &&seg : segments) {
|
for (auto &&seg : segments) {
|
||||||
s.p = f.p + seg.offset;
|
s.p = f.p + seg.offset;
|
||||||
|
|
@ -116,19 +143,51 @@ void unpack_file(path fn) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case segment::decode_algorithm::rlew: {
|
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;
|
auto base = s.p;
|
||||||
uint16_t flag = s;
|
uint16_t flag = s;
|
||||||
uint32_t outlen = 0;
|
|
||||||
while (s.p < base + len) {
|
while (s.p < base + len) {
|
||||||
uint8_t w = s;
|
uint16_t w = s;
|
||||||
if (w == 0xfe && (*(uint8_t*)s.p) == flag) {
|
if ((w & 0xFF00) == (flag << 8)) {
|
||||||
uint8_t w1 = s;
|
uint16_t count = (uint8_t)w;
|
||||||
auto cntr = 0x20e;
|
if (count == 0xff) {
|
||||||
uint8_t w2 = s;
|
uint16_t w2 = s;
|
||||||
while (cntr--) {
|
*(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;
|
*(decltype(w2)*)pp = w2;
|
||||||
pp += sizeof(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 {
|
} else {
|
||||||
*(decltype(w)*)pp = w;
|
*(decltype(w)*)pp = w;
|
||||||
pp += sizeof(w);
|
pp += sizeof(w);
|
||||||
|
|
@ -143,9 +202,9 @@ void unpack_file(path fn) {
|
||||||
strm.next_in = s.p;
|
strm.next_in = s.p;
|
||||||
strm.avail_in = len;
|
strm.avail_in = len;
|
||||||
strm.next_out = pp;
|
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) {
|
if (r != LZMA_OK) {
|
||||||
throw std::runtime_error{"lzma error"};
|
throw std::runtime_error{"lzma error"};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue