The tools behind this site’s map database, now released for the community. Everything is plain Python 3.8+ with zero third-party dependencies — copy the script, run it. Windows, Linux and macOS all work.
Downloads
| Tool | Size | What it does |
|---|---|---|
| hpi.py | ~7 KB | Full HPI/UFO/CCX parser: list + extract any archive |
| feature_scan.py | ~5 KB | Walk a folder of map zips, dump every map’s feature table |
| gaf.py | ~2 KB | List the entries (frames, names) inside a GAF |
Save the file, then:
python hpi.py some_map.ufo outdir # extract everything
python hpi.py some_mod.ccx outdir --list # just list contents
python feature_scan.py /path/to/maps results.json
python gaf.py features.gaf # list feature animations
What they can read
- HPI / UFO / CCX archives — including the key-encrypted ones the classic HPIView chokes on (the XOR directory transform below).
- SQSH chunks — stored, TA-LZ77 (the 4096-byte window scheme) and zlib.
- GAF animations — entry names and frame counts.
- TNT feature tables — every map’s feature names, the data behind our feature coverage list.
Why these exist
The HPI format is documented in fragments across 25-year-old forum posts, and two details are almost always wrong in the copies that circulate:
- Directory encryption is XOR, not subtraction.
dec[i] = ((absolute_file_offset + i) & 0xFF) ^ key ^ raw[i]— decrypt the whole directory blob once, then all offsets inside are file-absolute. - The file entry triple is (DataOffset, FileSize, Compression) — offset first, size second. Several popular docs swap them, which is why some community parsers “work” on key-0 archives and explode on encrypted ones.
We verified both against every file of a 25 MB CCX (591/591 extracted) plus key-encrypted UFOs from the wild. If your parser fails on archives with a non-zero header key, this is why.
Licence & source
MIT licence — use it in your own tools, credit appreciated but not required. The scripts are the same ones that power the feature inventory behind our map pages. Bug reports and pull requests welcome via the contact page.