cacadump
A terminal hex editor with binary templates.
- gtcaca — a libcaca-based TUI toolkit — draws the interface.
- libpcapng / pycapng and its POSA decoder language provide the parsing engine.
Binary structure is described declaratively in .posa files (not code); the
POSA engine parses a buffer into a field tree, and that same tree drives both the
coloured hex grid and the template pane.
cacadump photo.png 69 bytes fmt:PNG F1 Help
00000000 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 |.PNG........IHDR| │ Inspector @ 0x10
00000010 00 00 00 04 00 00 00 04 08 06 00 00 00 A9 F1 9E |................| │ uint32 4
00000020 7E 00 00 00 0C 49 44 41 54 78 9C 63 60 20 0D 00 |~....IDATx.c` ..| │ …
│ Template: PNG
│ PNG
│ Signature: 8 bytes
│ Chunks
│ IHDR (13 bytes)
│ Width: 4
│ Color type: Truecolor+Alpha (6)
0x10 (16) HEX OVR PNG
Features
- Hex + ASCII panes with a movable caret, insert/overwrite editing, undo/redo.
- Binary templates via POSA: autodetects the format from the buffer's magic, dissects it, colours each byte by the field it belongs to, and shows the parsed structure in a live tree that follows the cursor.
- Data inspector: the bytes at the cursor decoded as int8…int64 / uint / float32 / float64 (both byte orders), char and binary — all at once.
- Goto offset, find (text or
0x..hex) with find-next, selection anchor, bookmarks. - Foldable template tree: navigate the parsed structure, fold and unfold nodes, and the element you land on highlights exactly its bytes in the grid.
- Ships decoders for PNG, GIF, BMP, GZIP, WAV and — because POSA is libpcapng's own decoder language — every network protocol libpcapng/carcal ships (DNS, HTTP, TLS, DHCP, SMB, …), usable on any selected buffer.
Install
pip install cacadump # pulls in gtcaca and pycapng wheels
cacadump path/to/file
The .posa decoders live in the fileformat.posa
submodule, so clone with --recurse-submodules (or run git submodule update --init in an existing checkout).
For local development against checkouts of gtcaca and libpcapng:
git clone --recurse-submodules https://github.com/stricaud/cacadump
python -m venv .venv
PKG_CONFIG_PATH=$(brew --prefix libcaca)/lib/pkgconfig \
.venv/bin/pip install scikit-build-core pybind11 setuptools-scm
PKG_CONFIG_PATH=$(brew --prefix libcaca)/lib/pkgconfig \
.venv/bin/pip install --no-build-isolation -e ../gtcaca -e ../libpcapng
.venv/bin/pip install -e .
Keys
| arrows / PgUp / PgDn / Home / End | move the cursor |
0-9 a-f (hex pane) / any char (ASCII pane) |
overwrite the byte under the cursor |
| INSERT | toggle insert / overwrite |
| DELETE / BACKSPACE | delete byte / delete left |
| Ctrl-A | set / clear the selection anchor |
| Ctrl-B | toggle a bookmark |
| F2 | run the template (POSA autodetect) |
| F3 | goto offset (0x.., or +N from cursor) |
| F4 / F5 | find (text or 0x.. hex) / find next |
| F6 / F7 | undo / redo |
| F8 | toggle the sidebar |
| F9 / F10 | open the menu bar (ESC leaves it) |
| Ctrl-S | save (Ctrl-W also works, for terminals that swallow Ctrl-S as XOFF) |
| Ctrl-D / Ctrl-U | decode the payload of a wrapped file / back out to the file bytes |
| TAB / Ctrl-X o | cycle the hex, inspector and template panes |
| F11 | switch between the hex and ASCII panes |
| mouse wheel | scroll the focused pane (3 rows a notch) |
+ / - / Enter / Space / Left / Right (template pane) |
fold / unfold a tree node |
| Ctrl-X c / Ctrl-Q | quit (always confirms through a modal dialog) |
| F1 | help |
Ctrl-X is an emacs-style prefix, so it no longer quits on its own: C-x o
cycles panes, C-x c (or C-x C-c) quits, C-x C-s saves, C-x k backs out
of a decoded layer. Ctrl-Q quits directly — though some terminals swallow it
as XON, in which case use C-x c.
Everything on the menu bar is also a key, and vice versa — File, Edit, View, Template and Help route to the same commands. F10 is gtcaca's own menu binding; F9 is wired to the same thing because F10 is intercepted by some terminals.
Wrapped files
Some formats are a header around a compressed stream. A NoteWorthy score is six
bytes then zlib, and NWC1_SCORE only matches what comes out of it — so
cacadump opens such a file at its payload and the template just works. The title
bar shows the layer stack ([1/1 file > NWC (zlib)]); Ctrl-U drops back to the
bytes on disk, Ctrl-D goes in again, and --raw skips decoding entirely.
Decoding is automatic only when the outer bytes have no decoder of their own. A
.gz keeps its gzip.posa view — inflating it silently would hide the very
structure that decoder exists to show — so you descend into it with Ctrl-D.
Each layer is a separate buffer with its own offsets, cursor and undo history, and offsets are never mapped across layers: DEFLATE has no byte-to-byte correspondence between input and output, so "the compressed bytes behind this field" would be a fiction. Saving re-encodes edited payloads back through their containers; a layer you did not edit is written back exactly as it was read, so opening and saving a file you didn't change never rewrites it.
Writing a template
Templates are .posa files (see the src/cacadump/protos/ submodule and
libpcapng's doc/posa.md). A decoder is declarative — types, enums, repeat, when/else,
scope, bits, and a label/info line:
Object<main> PNG
abbrev "png"
col "PNG"
required bytes<8> signature "Signature"
repeat until end as chunk "Chunks"
label "%s (%u bytes)" ctype, length
required uint32 length "Length"
required str<4> ctype "Type"
when ctype == 0x49484452: # "IHDR"
required uint32 width "Width"
required uint32 height "Height"
required uint8 bit_depth "Bit depth"
required uint8 color_type "Color type"
Truecolor+Alpha = 6
else:
required bytes[length] data "Data"
required uint32 crc hex "CRC"
Point CACADUMP_PROTOS_DIR at a directory of your own (or several, separated by
:) and the format is understood on the next open — no code change. Decoders meant for everyone belong
upstream in fileformat.posa
rather than dropped into the submodule checkout, where they would be lost on the
next git submodule update.
Notes / limitations
- POSA is byte-order-per-type, so formats that switch endianness or word size on a runtime field (ELF/PE/Mach-O 32-vs-64) are only partially expressible today.
- Editing operates on an in-memory buffer; very large files load fully into memory.
License
MIT.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cacadump-0.0.3.tar.gz.
File metadata
- Download URL: cacadump-0.0.3.tar.gz
- Upload date:
- Size: 36.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8aacc42fae624d9aea583f8b6f9fc58e30e4002d4df90fd6197a6aa47d0f7139
|
|
| MD5 |
a6502343d928d48d1fdc56dbc5ecc0f6
|
|
| BLAKE2b-256 |
7823ae23158d56d6472f5b2df3a0841b74111a768883f17c6415c86ac2d26cec
|
Provenance
The following attestation bundles were made for cacadump-0.0.3.tar.gz:
Publisher:
release.yml on stricaud/cacadump
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cacadump-0.0.3.tar.gz -
Subject digest:
8aacc42fae624d9aea583f8b6f9fc58e30e4002d4df90fd6197a6aa47d0f7139 - Sigstore transparency entry: 2341300990
- Sigstore integration time:
-
Permalink:
stricaud/cacadump@d44a4992a0dac28c42b26a727c3443c1ef95bbbf -
Branch / Tag:
refs/tags/v0.0.3 - Owner: https://github.com/stricaud
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d44a4992a0dac28c42b26a727c3443c1ef95bbbf -
Trigger Event:
push
-
Statement type:
File details
Details for the file cacadump-0.0.3-py3-none-any.whl.
File metadata
- Download URL: cacadump-0.0.3-py3-none-any.whl
- Upload date:
- Size: 35.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d986ab6b6d6da482e32f688f531e6d89bcf1249fd524bda0cf9c292ae2c2cd8e
|
|
| MD5 |
daeb769d4f5ca957fe3f1f39967d638d
|
|
| BLAKE2b-256 |
87ea6ece00ec659112323348500b446c7be3e57c042b33f537f2119c90e07c04
|
Provenance
The following attestation bundles were made for cacadump-0.0.3-py3-none-any.whl:
Publisher:
release.yml on stricaud/cacadump
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cacadump-0.0.3-py3-none-any.whl -
Subject digest:
d986ab6b6d6da482e32f688f531e6d89bcf1249fd524bda0cf9c292ae2c2cd8e - Sigstore transparency entry: 2341301002
- Sigstore integration time:
-
Permalink:
stricaud/cacadump@d44a4992a0dac28c42b26a727c3443c1ef95bbbf -
Branch / Tag:
refs/tags/v0.0.3 - Owner: https://github.com/stricaud
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d44a4992a0dac28c42b26a727c3443c1ef95bbbf -
Trigger Event:
push
-
Statement type: