Reimplement decode_f4(). It uses RLE.

This commit is contained in:
lzwdgc 2018-01-28 03:28:43 +03:00
parent aad50f9160
commit 13be828ef6
4 changed files with 111 additions and 18 deletions

View file

@ -222,7 +222,7 @@ int decode_f3(char *input, int size, char *output)
v10 = v21; v10 = v21;
memset32(v16, v18, v15 >> 1); memset32(v16, v18, v15 >> 1);
v19 = (int)((char *)v16 + 4 * (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; *(_WORD *)v19 = v18;
v19 += 2; v19 += 2;
@ -231,7 +231,10 @@ int decode_f3(char *input, int size, char *output)
} }
goto LABEL_13; goto LABEL_13;
} }
*(_WORD *)v11 = *(_WORD *)&v4[2 * idx]; else
{
*(_WORD *)v11 = *(_WORD *)&v4[2 * idx];
}
} }
else else
{ {
@ -307,3 +310,69 @@ int decode_f4(char *input, int size, char *output, int segment_offset)
} }
return result; 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;
}
}

View file

@ -27,8 +27,6 @@
#define FREAD(var) fread(&var, 1, sizeof(var), f) #define FREAD(var) fread(&var, 1, sizeof(var), f)
const int header_size = 0xC;
void header::load(FILE *f) void header::load(FILE *f)
{ {
FREAD(unk1); FREAD(unk1);
@ -42,7 +40,9 @@ void header::load(FILE *f)
void record::load(FILE *f) void record::load(FILE *f)
{ {
FREAD(name); char n[0x50];
FREAD(n);
name = n;
FREAD(pos); FREAD(pos);
FREAD(len); FREAD(len);
} }
@ -96,7 +96,7 @@ int record::read(pak *pak, void *output, int size)
void segment::load_header(FILE *f) void segment::load_header(FILE *f)
{ {
FREAD(unk1); FREAD(unk1);
FREAD(flags); FREAD(algorithm);
FREAD(offset); FREAD(offset);
} }
@ -105,7 +105,7 @@ void segment::load_segment()
auto f = file; auto f = file;
fseek(f, offset, SEEK_SET); 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 << "Something is wrong. Maybe you trying to open aim2 files?\n";
std::cerr << "They can be opened with SDK extractor.\n"; std::cerr << "They can be opened with SDK extractor.\n";
@ -114,7 +114,7 @@ void segment::load_segment()
FREAD(size1); FREAD(size1);
size2 = size1; size2 = size1;
if ((flags & 0x3) && (flags & 0xC)) if ((algorithm & 0x3) && (algorithm & 0xC))
{ {
FREAD(size2); FREAD(size2);
fread(&decoded[0], 1, size2, f); fread(&decoded[0], 1, size2, f);
@ -129,19 +129,30 @@ void segment::decompress(int segment_id)
{ {
load_segment(); 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); decode_f1((char*)decoded, size2, (char*)encoded);
else else
decode_f2((char*)decoded, size2, (char*)encoded); decode_f2((char*)decoded, size2, (char*)encoded);
} }
if (flags & 0x3) if ((algorithm & RLE_1_byte) || (algorithm & RLE_2_bytes))
{ {
if (flags & 0x1) if (algorithm & RLE_2_bytes)
decode_f3((char*)encoded, size1, (char*)decoded); {
//static std::vector<uint8_t> 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 else
decode_f4((char*)encoded, size1, (char*)decoded, segment_id * header_size); {
//static std::vector<uint8_t> 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);
}
} }
} }

View file

@ -40,7 +40,7 @@ struct header
struct record struct record
{ {
char name[0x50]; std::string name;
uint32_t pos; uint32_t pos;
uint32_t len; uint32_t len;
@ -55,8 +55,16 @@ struct record
struct segment struct segment
{ {
enum decode_algorithm
{
RLE_2_bytes = 0x1,
RLE_1_byte = 0x2,
DA_1 = 0x4,
DA_2 = 0x8,
};
uint32_t unk1; uint32_t unk1;
uint32_t flags; decode_algorithm algorithm;
uint32_t offset; uint32_t offset;
uint32_t size1; uint32_t size1;

View file

@ -27,14 +27,19 @@ void unpak(string fn)
return; return;
pak p; pak p;
p.load(f); p.load(f);
for (auto &f : p.files)
auto unpack = [&](auto &file)
{ {
record &file = f.second;
cout << "Unpacking " << file.name << "\n"; cout << "Unpacking " << file.name << "\n";
vector<char> buf(file.len); vector<char> buf(file.len);
file.read(&p, &buf[0], file.len); file.read(&p, &buf[0], file.len);
file.write(fn + ".dir", buf); file.write(fn + ".dir", buf);
}; };
unpack(p.files["arena.mmp"]);
//for (auto &[n,f] : p.files)
//unpack(f);
fclose(f); fclose(f);
} }