diff --git a/ArcFormats/Gss/ArcARC.cs b/ArcFormats/Gss/ArcARC.cs index 4a6b5274..3ad88eb0 100644 --- a/ArcFormats/Gss/ArcARC.cs +++ b/ArcFormats/Gss/ArcARC.cs @@ -85,19 +85,51 @@ namespace GameRes.Formats.Gss using (var input = arc.File.CreateStream (entry.Offset+12, entry.Size-12)) { var data = new byte[unpacked_size]; + int len; switch ((char)pack_method) { - case 'D': UnpackD (input, data); break; - case 'R': UnpackR (input, data); break; - case 'H': UnpackH (input, data); break; - case 'W': UnpackW (input, data); break; - default: input.Read (data, 0, data.Length); break; + case 'D': len = UnpackD (input, data); break; + case 'R': len = UnpackR (input, data); break; + case 'H': len = UnpackH (input, data); break; + case 'W': len = UnpackW (input, data); break; + default: len = input.Read (data, 0, data.Length); break; } + len = Math.Min (len, data.Length); switch ((char)enc_method) { + case 'N': + break; 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': + 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': + 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; } return new BinMemoryStream (data, entry.Name); @@ -109,12 +141,75 @@ namespace GameRes.Formats.Gss 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; while (dst < output.Length) @@ -135,7 +230,7 @@ namespace GameRes.Formats.Gss } switch (ctl) { - case 0xF0: return; + case 0xF0: return 0; case 0x40: input.Read (output, dst, count); dst += count; @@ -174,14 +269,171 @@ namespace GameRes.Formats.Gss 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(); /* @@ -239,6 +491,7 @@ namespace GameRes.Formats.Gss v7 += v20 - shift; } } + return dst; */ } @@ -254,5 +507,40 @@ namespace GameRes.Formats.Gss 0x00, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x1F, 0x3F, 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 + }; } }