diff --git a/src/unpaker/decode.h b/src/unpaker/decode.h index 2127423..3a3aa19 100644 --- a/src/unpaker/decode.h +++ b/src/unpaker/decode.h @@ -222,7 +222,7 @@ int decode_f3(char *input, int size, char *output) v10 = v21; memset32(v16, v18, v15 >> 1); v19 = (int)((char *)v16 + 4 * (v15 >> 1)); - for (i = (v13 + 3) & 1; i; --i) + for (i = v15 & 1; i; --i) { *(_WORD *)v19 = v18; v19 += 2; @@ -231,7 +231,10 @@ int decode_f3(char *input, int size, char *output) } goto LABEL_13; } - *(_WORD *)v11 = *(_WORD *)&v4[2 * idx]; + else + { + *(_WORD *)v11 = *(_WORD *)&v4[2 * idx]; + } } else { @@ -307,3 +310,69 @@ int decode_f4(char *input, int size, char *output, int segment_offset) } return result; } + +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 decode_rle(const char *input, const int size, char *output) +{ + if (size < 2) + return; + + // input ptr, also rle_indicator + const auto rle_indicator = input++; + while (1) + { + auto c = *input++; + if (c != *rle_indicator) + *output++ = c; + else + { + uint32_t count = (uint8_t)*input++; + if (count == 255) + *output++ = *rle_indicator; // insert indicator byte itself + else + { + memset(output, *input++, count += 3); + output += count; + } + } + + if (input >= rle_indicator + size) + return; + } +} diff --git a/src/unpaker/pak.cpp b/src/unpaker/pak.cpp index 5e3c055..bb0db64 100644 --- a/src/unpaker/pak.cpp +++ b/src/unpaker/pak.cpp @@ -27,8 +27,6 @@ #define FREAD(var) fread(&var, 1, sizeof(var), f) -const int header_size = 0xC; - void header::load(FILE *f) { FREAD(unk1); @@ -42,7 +40,9 @@ void header::load(FILE *f) void record::load(FILE *f) { - FREAD(name); + char n[0x50]; + FREAD(n); + name = n; FREAD(pos); FREAD(len); } @@ -96,7 +96,7 @@ int record::read(pak *pak, void *output, int size) void segment::load_header(FILE *f) { FREAD(unk1); - FREAD(flags); + FREAD(algorithm); FREAD(offset); } @@ -105,7 +105,7 @@ void segment::load_segment() auto f = file; fseek(f, offset, SEEK_SET); - if (flags == 0) + if (algorithm == 0) { std::cerr << "Something is wrong. Maybe you trying to open aim2 files?\n"; std::cerr << "They can be opened with SDK extractor.\n"; @@ -114,7 +114,7 @@ void segment::load_segment() FREAD(size1); size2 = size1; - if ((flags & 0x3) && (flags & 0xC)) + if ((algorithm & 0x3) && (algorithm & 0xC)) { FREAD(size2); fread(&decoded[0], 1, size2, f); @@ -129,19 +129,30 @@ void segment::decompress(int segment_id) { load_segment(); - if (flags & 0xC) + if ((algorithm & DA_1) || (algorithm & DA_2)) { - if (flags & 0x4) + if (algorithm & DA_1) decode_f1((char*)decoded, size2, (char*)encoded); else decode_f2((char*)decoded, size2, (char*)encoded); } - if (flags & 0x3) + if ((algorithm & RLE_1_byte) || (algorithm & RLE_2_bytes)) { - if (flags & 0x1) - decode_f3((char*)encoded, size1, (char*)decoded); + if (algorithm & RLE_2_bytes) + { + //static std::vector buf(4194432); + decode_f3((char*)encoded, size1, (char*)decoded/*buf.data()*/); + //decode_rle((short*)encoded, size1, (short*)decoded); + //assert(memcmp(decoded, buf.data(), size1) == 0); + } else - decode_f4((char*)encoded, size1, (char*)decoded, segment_id * header_size); + { + //static std::vector buf(4194432); + //const int header_size = 0xC; + //decode_f4((char*)encoded, size1, (char*)buf.data(), segment_id * header_size); + decode_rle((char*)encoded, size1, (char*)decoded); + //assert(memcmp(decoded, buf.data(), size1) == 0); + } } } diff --git a/src/unpaker/pak.h b/src/unpaker/pak.h index c9dbfa1..a48f2d7 100644 --- a/src/unpaker/pak.h +++ b/src/unpaker/pak.h @@ -40,7 +40,7 @@ struct header struct record { - char name[0x50]; + std::string name; uint32_t pos; uint32_t len; @@ -55,8 +55,16 @@ struct record struct segment { + enum decode_algorithm + { + RLE_2_bytes = 0x1, + RLE_1_byte = 0x2, + DA_1 = 0x4, + DA_2 = 0x8, + }; + uint32_t unk1; - uint32_t flags; + decode_algorithm algorithm; uint32_t offset; uint32_t size1; diff --git a/src/unpaker/unpaker.cpp b/src/unpaker/unpaker.cpp index 6396142..d1f48fa 100644 --- a/src/unpaker/unpaker.cpp +++ b/src/unpaker/unpaker.cpp @@ -27,14 +27,19 @@ void unpak(string fn) return; pak p; p.load(f); - for (auto &f : p.files) + + auto unpack = [&](auto &file) { - record &file = f.second; cout << "Unpacking " << file.name << "\n"; vector buf(file.len); file.read(&p, &buf[0], file.len); file.write(fn + ".dir", buf); }; + + unpack(p.files["arena.mmp"]); + + //for (auto &[n,f] : p.files) + //unpack(f); fclose(f); }