Mercurial > touhou
view doc/PBG3 @ 792:11bc22bad1bf default tip
python: Replace the image crate with png
We weren’t using any of its features anyway, so the png crate is exactly what
we need, without the many heavy dependencies of image.
https://github.com/image-rs/image-png/pull/670 will eventually make it even
faster to build.
| author | Link Mauve <linkmauve@linkmauve.fr> |
|---|---|
| date | Sat, 17 Jan 2026 22:22:25 +0100 |
| parents | 6b2c7af2384c |
| children |
line wrap: on
line source
The PBG3 format is an archive format used by Touhou 6 (The Embodiment of Scarlet Devil). It is a bitstream composed of a header, a file table, and LZSS-compressed files. Reading integers ---------------- Integers in PBG3 files are never signed, they are not byte-aligned, and have a variable size. Their size is given by two bits: 00 means the number is stored in one byte, 10 means it is stored in three bytes. Ex: 0x0012 is stored as: 0000010010 0x0112 is stored as: 010000000100010010 Reading strings --------------- Strings are stored as standard NULL-terminated sequences of bytes. The only catch is they are not byte-aligned. Header ------ The header is composed of three fields: * magic (string): "PBG3" * number of entries (integer) * offset of the file table (integer) The size of the header is thus comprised between 52 bits and 100 bits. File table ---------- The file table starts at a byte boundary, but as the rest of the file, isn't byte-aligned. It consists of a sequence of entries. Each entry is composed of five fields: * unknown1 (int) #TODO * unknown2 (int) #TODO * checksum (int): simple checksum of compressed data * size (int): size of uncompressed data * name (string): name of the file The checksum is a mere sum of the compressed data. Files are compressed using the LZSS algorithm, with a dictionary size of 8192 bytes and a minimum matching length of 4 bytes. The size of the offset component of (offset, length) tuples is 13 bits, whereas the size of the length component is 4 bits. A file ends with a (0, 0) tuple, that is, 18 zero bits. Uncompressing a LZSS-compressed file is quite easy, see lzss.py.
