feat: implement UnpackD, UnpackH and decryption for GSS

Untested yet.
This commit is contained in:
devseed
2026-02-05 02:52:51 +08:00
committed by scientificworld
parent af695a70b3
commit 75b2c78665

View File

@@ -85,19 +85,51 @@ namespace GameRes.Formats.Gss
using (var input = arc.File.CreateStream (entry.Offset+12, entry.Size-12)) using (var input = arc.File.CreateStream (entry.Offset+12, entry.Size-12))
{ {
var data = new byte[unpacked_size]; var data = new byte[unpacked_size];
int len;
switch ((char)pack_method) switch ((char)pack_method)
{ {
case 'D': UnpackD (input, data); break; case 'D': len = UnpackD (input, data); break;
case 'R': UnpackR (input, data); break; case 'R': len = UnpackR (input, data); break;
case 'H': UnpackH (input, data); break; case 'H': len = UnpackH (input, data); break;
case 'W': UnpackW (input, data); break; case 'W': len = UnpackW (input, data); break;
default: input.Read (data, 0, data.Length); break; default: len = input.Read (data, 0, data.Length); break;
} }
len = Math.Min (len, data.Length);
switch ((char)enc_method) switch ((char)enc_method)
{ {
case 'N':
break;
case 'B': case 'B':
for (int i = 0; i < len; i++)
{
var d = data[i];
var tmp = -d;
if (i != 0)
tmp = data[i - 1] - d;
data[i] = (byte)tmp;
}
break;
case 'W': case 'W':
for (int i = 0; i < len; i += 2)
{
var d = data[i] | (data[i + 1] << 8);
var tmp = -d;
if (i != 0)
tmp = (data[i - 2] | data[i - 1] << 8) - d;
data[i] = (byte)(tmp & 0xff);
data[i + 1] = (byte)(tmp >> 8);
}
break;
case 'S': case 'S':
for (int i = 0; i < len; i += 2)
{
var d = data[i + 1] | (data[i] << 8);
var tmp = -d;
if (i != 0)
tmp = (data[i - 1] | data[i - 2] << 8) - d;
data[i] = (byte)(tmp >> 8);
data[i + 1] = (byte)(tmp & 0xff);
}
break; break;
} }
return new BinMemoryStream (data, entry.Name); return new BinMemoryStream (data, entry.Name);
@@ -109,12 +141,75 @@ namespace GameRes.Formats.Gss
throw new NotImplementedException(); throw new NotImplementedException();
} }
void UnpackD (IBinaryStream input, byte[] output) int UnpackD (IBinaryStream input, byte[] output)
{ {
throw new NotImplementedException(); var buf_packed = input.ReadBytes ((int)input.Length);
int result = 0, i = 0, v8, v12;
int v3 = 0, qword_811C97A8 = 0;
var size1 = output.Length >> 1;
byte v6, v16;
if (size1 != 0)
{
int cur_output_addr = 0;
int cur_pos = 0;
do
{
v6 = (byte)(v3 & 0x1F);
int v7 = (int)((v3 >> 3) & 0xFFFFFFFC);
if ((int)(v3 & 0x1F) < 28)
{
v8 = BitConverter.ToInt32 (buf_packed, v7);
}
else
{
v8 = BitConverter.ToInt32 (buf_packed, v7 + 1);
v6 -= (byte)8;
}
var v23 = v8 >> v6;
qword_811C97A8 += 5;
byte v10 = (byte)(qword_811C97A8 & 0x1F);
int idx = v23 & 0xF;
int v11 = (int)(((qword_811C97A8) >> 3) & 0xFFFFFFFC);
if (v10 >= 24)
{
v12 = BitConverter.ToInt32 (buf_packed, v11 + 3);
v16 = (byte)(v10 - 24);
}
else if (v10 >= 16)
{
v12 = BitConverter.ToInt32 (buf_packed, v11 + 2);
v16 = (byte)(v10 - 16);
}
else
{
if (v10 < 8)
{
v12 = BitConverter.ToInt32 (buf_packed, v11);
}
else
{
v12 = BitConverter.ToInt32 (buf_packed, v11 + 1);
v10 -= 8;
}
v16 = v10;
}
var v19 = (dword_8107F750[idx] & (v12 >> v16)) + dword_8107F7A4[0x10 + idx];
if ((v23 & 0x10) != 0)
v19 = v19 & 0xffff0000 | (~v19 & 0xffff);
output[cur_output_addr++] = (byte)(v19); //word
output[cur_output_addr++] = (byte)(v19 >> 8);
qword_811C97A8 += (int)dword_8107F7A4[idx];
++i;
v3 = qword_811C97A8;
cur_pos += 2;
}
while (i != size1);
result = cur_pos + 2;
}
return result;
} }
void UnpackR (IBinaryStream input, byte[] output) int UnpackR (IBinaryStream input, byte[] output)
{ {
int dst = 0; int dst = 0;
while (dst < output.Length) while (dst < output.Length)
@@ -135,7 +230,7 @@ namespace GameRes.Formats.Gss
} }
switch (ctl) switch (ctl)
{ {
case 0xF0: return; case 0xF0: return 0;
case 0x40: case 0x40:
input.Read (output, dst, count); input.Read (output, dst, count);
dst += count; dst += count;
@@ -174,14 +269,171 @@ namespace GameRes.Formats.Gss
break; break;
} }
} }
return dst;
} }
void UnpackH (IBinaryStream input, byte[] output) int UnpackH (IBinaryStream input, byte[] output)
{ {
throw new NotImplementedException(); var buf_packed = input.ReadBytes ((int)input.Length);
var buf = new byte[0x10000];
const uint off2 = 0x2004;
const uint off3 = 0x2804;
const uint off4 = 0x3004; //0x811C9784
uint cur_addr = 2, pre_pos, next_pos = 2, cur_output_addr = 0;
byte outchar, i1 = 0, i2, v29, first_char = buf_packed[0];
int idx1 = 0, v28 = 0;
do
{
pre_pos = next_pos;
var cur_char1 = buf_packed[cur_addr];
var next_addr = cur_addr + 1;
next_pos++;
if (cur_char1 != 0)
{
byte l1 = buf_packed[cur_addr + 1];
byte h1 = buf_packed[cur_addr + 2];
uint t1 = (ushort)(l1 + (h1 << 8));
if (cur_char1 >= 8)
{
if (cur_char1 >= 0xD)
{
uint d;
if (cur_char1 < 0x10) // 2 byte
{
d = t1;
next_addr = cur_addr + 3;
next_pos = pre_pos + 3;
}
else // 3 byte
{
d = (uint)(t1 + (buf_packed[cur_addr + 3] << 16));
next_addr = cur_addr + 4;
next_pos = pre_pos + 4;
}
buf[off3 + 4 + 8 * i1] = cur_char1;
BitConverter.GetBytes ((uint)(d)).CopyTo (buf, off3 + 8 * i1);
buf[off3 + 5 + 8 * i1] = (byte)idx1;
i1++;
}
else // 2 byte
{
buf[2 * t1] = (byte)idx1;
buf[2 * t1 + 1] = cur_char1;
next_addr = cur_addr + 3;
next_pos = pre_pos + 3;
}
}
else // 1 byte
{
buf[2 * l1] = (byte)idx1;
buf[2 * l1 + 1] = cur_char1;
next_addr = cur_addr + 2;
next_pos = pre_pos + 2;
}
}
cur_addr = next_addr;
++idx1;
} while (idx1 != 0x100);
byte idx2 = 0;
byte v19 = 0xD;
do
{
i2 = 0;
buf[off4 + v19] = (byte)idx2;
if (i1 != 0)
{
int buf3_addr = 0x2804; //buf3_addr = (_BYTE *)&dword_811C8F84;
do
{
if (buf[buf3_addr + 4] == v19)
{
Array.Copy (buf, buf3_addr, buf, off2 + 8 * idx2, 4);
Array.Copy (buf, buf3_addr+4, buf, off2 + 4 + 8 * idx2, 4);
idx2++;
}
++i2;
buf3_addr += 8;
}
while (i2 != i1);
}
v19++;
} while (v19 != 0x18);
buf[0x301c] = (byte)idx2; //unk_811C979C = idx2;
Array.Clear (buf, 0x3028, 8);//qword_811C97A8 = 0i64;
int v23 = (int)output.Length, v33 = 0, size_done = 0;
while (true)
{
int v24 = (int)(next_pos + ((uint)(v33 & 0x1F) >> 3) + ((v33 >> 3) & 0xFFFFFFFC)); //this place, out of range
ulong v25 = BitConverter.ToUInt32 (buf_packed, v24);
byte cur_char2 = first_char;
uint a3 = (uint)((v33 & 0x1F) - (v33 & 0x18));
uint v27 = (uint)v25;
if (a3 > 63)
v27 = 0;
else if (a3 != 0)
v27 = (uint)(v25 >> (int)a3);
if (first_char != 0xD)
{
while (true)
{
v28 = (int)(v27 & dword_8107F828[2 * cur_char2]);
BitConverter.GetBytes ((int)(2 * v28 + 0x811C6780)).CopyTo (buf, off2 - 4); //must pay attention to the type convert and length
if (cur_char2 == buf[2 * v28 + 1])// buf1+1
break;
cur_char2++;
if (cur_char2 == 0xD)
goto LABEL_22;
}
outchar = buf[2 * v28];
goto LABEL_29;
}
LABEL_22:
if (cur_char2 == 0x18)
break;
LABEL_26_2:
while (true)
{
v29 = buf[off4 + cur_char2];
if (v29 != buf[off4 + 1 + cur_char2])
break;
if (++cur_char2 == 0x18)
{
return 0;
//outchar = buf[off2 + 5 + 8 * v29]; //this seems a hack...
//goto LABEL_29;
}
}
while (BitConverter.ToUInt32 (buf, (int)off2 + 8 * v29) !=
(v27 & dword_8107F828[2 * cur_char2]))
{
v29++;
if (v29 == buf[off4 + 1 + cur_char2 ])
{
if (++cur_char2 == 0x18)
{
return 0;
}
goto LABEL_26_2;
}
}
outchar = buf[off2 + 5 + 8 * v29];
LABEL_29:
output[cur_output_addr] = (byte)outchar;
BitConverter.GetBytes ((Int64)v33 + (ushort)cur_char2).CopyTo (buf, 0x3028);
v23 = size_done + 1;
++cur_output_addr;
v33 += cur_char2 ;
size_done = v23;
if (v23 >= output.Length)
return size_done;
}
return 0;
} }
void UnpackW (IBinaryStream input, byte[] output) int UnpackW (IBinaryStream input, byte[] output)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
/* /*
@@ -239,6 +491,7 @@ namespace GameRes.Formats.Gss
v7 += v20 - shift; v7 += v20 - shift;
} }
} }
return dst;
*/ */
} }
@@ -254,5 +507,40 @@ namespace GameRes.Formats.Gss
0x00, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x1F, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x1F, 0x3F,
0x7F, 0xFF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF 0x7F, 0xFF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF
}; };
static readonly uint[] dword_8107F828 = {
0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x07, 0x00,
0x0F, 0x00, 0x1F, 0x00, 0x3F, 0x00, 0x7F, 0x00,
0xFF, 0x00, 0x01FF, 0x00, 0x03FF, 0x00, 0x07FF, 0x00,
0x0FFF, 0x00, 0x1FFF, 0x00, 0x3FFF, 0x00, 0x7FFF, 0x00,
0xFFFF, 0x00, 0x01FFFF, 0x00, 0x03FFFF, 0x00, 0x07FFFF, 0x00,
0x0FFFFF, 0x00, 0x1FFFFF, 0x00, 0x3FFFFF, 0x00, 0x7FFFFF, 0x00,
0xFFFFFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0F,
0x1F, 0x3F, 0x7F, 0xFF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x01FFFF, 0x03FFFF, 0x0FFFFF, 0x00,
0x06050403, 0x0A090807, 0x0E0D0C0B, 0x00, 0x01, 0x02, 0x04, 0x08,
0x10, 0x20, 0x40, 0x80, 0x0100, 0x0200, 0x0400, 0x0800,
0x1000, 0x2000, 0x4000, 0x00, 0xFFFF0001, 0x00, 0x00, 0x01,
0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x01, 0x01
};
static readonly uint[] dword_8107F750 = {
0x00, 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F,
0x7F, 0xFF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF,
0x7FFF, 0xFFFF, 0x01FFFF, 0x03FFFF, 0x0FFFFF, 0x00, 0x00, 0x01
};
static readonly uint[] dword_8107F7A4 = {
0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40,
0x80, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000,
0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x07,
0x00, 0x0F, 0x00, 0x1F, 0x00, 0x3F, 0x00, 0x7F,
0x00, 0xFF, 0x00, 0x01FF, 0x00, 0x03FF, 0x00, 0x07FF,
0x00, 0x0FFF, 0x00, 0x1FFF, 0x00, 0x3FFF, 0x00, 0x7FFF,
0x00, 0xFFFF, 0x00, 0x01FFFF, 0x00, 0x03FFFF, 0x00, 0x07FFFF,
0x00, 0x0FFFFF, 0x00, 0x1FFFFF, 0x00, 0x3FFFFF, 0x00, 0x7FFFFF,
0x00, 0xFFFFFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
0x0F, 0x1F, 0x3F, 0x7F, 0xFF, 0x01FF, 0x03FF, 0x07FF,
0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x01FFFF, 0x03FFFF, 0x0FFFFF
};
} }
} }