In the Groove PCK
The rhythm dancing game In the Groove internally uses several PCK archive files to store game data. The format is not publicly documented, but has been reverse-engineered.
Contents |
Format details
A PCK archive consists overall of three segments: a short fixed header, a table listing file locations and details, and file data (which may be compressed).
Within the file, all strings are ASCII (the behavior of high-bit strings is unknown, as it is not used), all numbers are stored as little-endian 32-bit integers, and all sizes are in bytes.
Header
A PCK archive always begins with a 132-byte header:
Offset | Contents | Details |
---|---|---|
0 + 4 | Magic identifier | Must contain the string "PCKF". Files lacking this identifier will be rejected by ITG. |
4 + 128 | Archive name | Contains a null-terminated string describing the archive's contents. This data is never displayed to the user; it is only shown in a few debug messages. |
132 + 4 | File count | Number of files in the archive. |
File table
Immediately following the header is a list of the files contained in the archive. The order can be arbitrary. Each file is described with the following variable-length structure:
Offset | Contents | Details |
---|---|---|
0 + 4 | Data size | Size of the file being described. |
4 + 4 | Compressed size | Size of the file within the archive. Equal to the data size if the file is not compressed. |
8 + 4 | Data offset | Byte offset within the archive where the data for this file begins. |
12 + 4 | Name length | Length of the filename |
16 + 4 | Compress flag | 1 if the file is compressed, 0 if not. |
20 + n | File name | Name of the file. Unterminated -- next file table entry immediately follows the last byte. |
File data
While the data for files can technically be arranged however desired, in practice each file is stored in the same order given in the file table, at offsets specified in that table.
If the compress flag is set for a file, the data for that file is deflated using zlib. The following Python code can be used to implement compression and decompression:
compressed_data = zlib.compress(data, 9)[2:] decompressed_data = zlib.uncompress(data, -15)