I made this because I needed a way to work with .cpk archives on platforms other than Windows, specifically Android (Termux + NDK) and Linux. Most existing tools are .NET-based and tied to Windows, so I wrote this from scratch in C11 with no external dependencies.
It handles reading, extracting, replacing, and rebuilding CRI Middleware CPK archives. The kind you find in a lot of Japanese games.
- list: show everything inside a CPK with file sizes and offsets
- extract: pull out all files, with proper naming even for ID-only (ITOC) archives
- replace: swap one file in-place without touching the rest of the archive
- build: reconstruct a CPK from a directory (TOC and ITOC modes)
- info: print archive layout: sections, offsets, encryption status
makepkg install clang make
makemake CC=gccmake CC=x86_64-w64-mingw32-gcc TARGET=cpktool.exeShows every file entry in the archive: numeric ID, file size on disk, extract size (after decompression), absolute offset inside the CPK, and the resolved path or ID-based name.
Options: --compact for just names, --sort-size to rank by size, --filter STR to narrow results.
Pulls all files out to a directory. For archives that have real filenames (TOC-based), the original directory structure is preserved. For ID-only archives (ITOC-based), I provide three naming modes so you can pick whatever is easiest to work with later:
--naming id->0042--naming prefix->ID0042(default)--naming dir->ID0042/0042
--no-decomp skips CRILAYLA decompression if you want the raw compressed blobs. --quiet suppresses the per-file output.
Swaps one file inside the archive in-place, then rewrites the header packets so sizes stay consistent. The entry name is matched against all three naming formats (ID0042, 0042, ID0042/0042) so whatever extract produced will work without modification.
The replacement file must be the same size or smaller than the original slot. If it's smaller, the leftover space is zero-padded. Pass --force to allow this explicitly.
Reconstructs a CPK from scratch from a directory. if every file parses as a numeric ID it uses ITOC, otherwise TOC. You can force a mode with --mode toc or --mode itoc.
For ITOC builds, files with size ≤ 65535 bytes go into the DataL sub-table (u16 fields) and larger files go into DataH (u32 fields), matching how the original format works. The two-pass layout ensures content offsets are accurate before anything is written.
Use --align to set the file slot boundary (default 2048) and --encrypt if the source archive had encrypted @UTF packets.
Prints the archive's top-level metadata: which sections are present and where they start, the content offset, total file count, and whether @UTF encryption is in use.
ITOC-based CPKs store files by numeric ID only — there are no filenames in the archive at all. I default to the prefix format (ID0042) because it makes entries unambiguous when passing them to replace or build, and it's less error-prone than bare numbers when you're working with a lot of files.
All three formats are accepted interchangeably by replace and build:
| Format | Example |
|---|---|
id |
0042 |
prefix (default) |
ID0042 |
dir |
ID0042/0042 |
I'm not going to pretend this is a complete reimplementation. What I know it handles:
- TOC, ITOC, ETOC section types (GTOC is parsed but skipped on build)
- CRILAYLA decompression on extract
- Encrypted and unencrypted @UTF packets (auto-detected on read, opt-in on build)
- ITOC DataL (u16 sizes) and DataH (u32 sizes) split
- CPK variants where the outer
sizefield is smaller than the actual content — the tool readstable_sizefrom inside the @UTF header itself and extends the buffer if needed
If you feel this tool is helpful, you can show your gratitude by giving this repository a star🥰