YPF: Difference between revisions
Jump to navigation
Jump to search
(8 intermediate revisions by the same user not shown) | |||
Line 25: | Line 25: | ||
| 4Bytes|| Unknown1 || | | 4Bytes|| Unknown1 || | ||
|- | |- | ||
| 1Bytes|| Filename Length || XOR 0xFF, then table lookup. | | 1Bytes|| Filename Length || XOR 0xFF, then table lookup (see below). | ||
|- | |- | ||
| ?Bytes|| Filename || XOR 0xFF then XOR 0x40 | | ?Bytes|| Filename || XOR 0xFF then XOR 0x40 | ||
Line 41: | Line 41: | ||
==Comments== | ==Comments== | ||
To decode the filenames, each byte in the filename is XOR by 0xFF and then 0x40. However, the filenames are not null terminated so 1 byte is stored before the filename that represents the the filename's length. This value is protected like the filename but is slightly different (as far as I can tell). XOR by 0xFF and then do a table lookup. | |||
The table is generated at runtime and swaps around a number of values. | |||
<syntaxhighlight lang="cpp"> | |||
char lookup(char incoming) | |||
{ | |||
switch (incoming) | |||
{ | |||
case 0x09: | |||
return 0x0B; | |||
case 0x0B: | |||
return 0x09; | |||
case 0x0C: | |||
return 0x10; | |||
case 0x0D: | |||
return 0x13; | |||
case 0x10: | |||
return 0x0C; | |||
case 0x11: | |||
return 0x19; | |||
case 0x13: | |||
return 0x0D; | |||
case 0x15: | |||
return 0x1B; | |||
case 0x19: | |||
return 0x11; | |||
case 0x1B: | |||
return 0x15; | |||
case 0x1C: | |||
return 0x1E; | |||
case 0x1E: | |||
return 0x1C; | |||
case 0x20: | |||
return 0x23; | |||
case 0x23: | |||
return 0x20; | |||
case 0x26: | |||
return 0x29; | |||
case 0x29: | |||
return 0x26; | |||
case 0x2C: | |||
return 0x2F; | |||
case 0x2E: | |||
return 0x32; | |||
case 0x2F: | |||
return 0x2C; | |||
case 0x32: | |||
return 0x2E; | |||
default: | |||
return incoming; | |||
} | |||
} | |||
</syntaxhighlight> | |||
ToDo: | |||
Figure out what the unknown values are for repacking function. |
Latest revision as of 07:08, 31 March 2015
Used in the following games:
- Eroge! ~Sex and Games Make Sexy Games~
Structure
Header | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Size | Content | Description | ||||||||||||
4Bytes | Magic/ID | "YPF/0" | ||||||||||||
4Bytes | Unknown1 | Static? | ||||||||||||
4Bytes | File Count | Number of Files in archive | ||||||||||||
4Bytes | Index Size | Size of Index | ||||||||||||
16Bytes | Padding | |||||||||||||
Index Entry | ||||||||||||||
Size | Content | Description | ||||||||||||
4Bytes | Unknown1 | |||||||||||||
1Bytes | Filename Length | XOR 0xFF, then table lookup (see below). | ||||||||||||
?Bytes | Filename | XOR 0xFF then XOR 0x40 | ||||||||||||
2Bytes | Unknown2 | Static? | ||||||||||||
4Bytes | FileSize1 | |||||||||||||
4Bytes | FileSize2 | Suggests compression is supported | ||||||||||||
4Bytes | File Offset | |||||||||||||
4Bytes | Unknown3 |
Comments
To decode the filenames, each byte in the filename is XOR by 0xFF and then 0x40. However, the filenames are not null terminated so 1 byte is stored before the filename that represents the the filename's length. This value is protected like the filename but is slightly different (as far as I can tell). XOR by 0xFF and then do a table lookup. The table is generated at runtime and swaps around a number of values.
char lookup(char incoming)
{
switch (incoming)
{
case 0x09:
return 0x0B;
case 0x0B:
return 0x09;
case 0x0C:
return 0x10;
case 0x0D:
return 0x13;
case 0x10:
return 0x0C;
case 0x11:
return 0x19;
case 0x13:
return 0x0D;
case 0x15:
return 0x1B;
case 0x19:
return 0x11;
case 0x1B:
return 0x15;
case 0x1C:
return 0x1E;
case 0x1E:
return 0x1C;
case 0x20:
return 0x23;
case 0x23:
return 0x20;
case 0x26:
return 0x29;
case 0x29:
return 0x26;
case 0x2C:
return 0x2F;
case 0x2E:
return 0x32;
case 0x2F:
return 0x2C;
case 0x32:
return 0x2E;
default:
return incoming;
}
}
ToDo: Figure out what the unknown values are for repacking function.