https://github.com/ikskuh/livedecode
A super hacky tool to decode unknown binary formats
https://github.com/ikskuh/livedecode
Last synced: 3 months ago
JSON representation
A super hacky tool to decode unknown binary formats
- Host: GitHub
- URL: https://github.com/ikskuh/livedecode
- Owner: ikskuh
- License: mit
- Created: 2022-10-18T10:02:40.000Z (about 3 years ago)
- Default Branch: master
- Last Pushed: 2023-08-29T07:16:54.000Z (over 2 years ago)
- Last Synced: 2025-06-10T02:57:37.221Z (7 months ago)
- Language: Zig
- Size: 229 KB
- Stars: 29
- Watchers: 3
- Forks: 5
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
Awesome Lists containing this project
README
# livedecode
Decode binary data on the fly quicker.
## Usage
```sh-session
[user@host project]$ livedecode example/png.spec example/example.png
```
The tool is meant to be run live while typing on a spec, so one can do stuff like this:

Just run the program periodically in the background:
```sh-session
[user@host project]$ while true; do
clear
date
livedecode docs/wmb6.spec data/wmb/wmb6/block.wmb > /tmp/dump.txt
sleep 1
done
```
## Syntax
The format is a very crude line based syntax. Empty lines are ignored, everything past a `#` is a comment.
Lines are split into tokens separated by either space or tab characters.
The first token in a line determines the command or type of the line.
A line starting with `.` is a macro and is always executed. All other lines can be conditionally be executed.
If a line starts with a type, this type is decoded. If a name is given after the type, a variable is created with that name.
In a lot of places where not a name is expected, either immediate numbers can be written as decimal, hexadecimal (`0x1A`) or a variable reference can be used (`*variable`).
The parser can also accept tuple types, which are started by `(` and terminated by `)`. Tuples are inhomogenous arrays that are passed as a single argument. They are used for grouping arguments together.
Lines can be continued with a `\`, so the following code is considered a single line by the parser:
```
lut *key \
(key value) \
(key value) \
(key value) \
(key value) \
(key value)
```
## Commands, Macros and Variables
### Commands
#### `print …`
prints all arguments. if an argument is a semicolon, no space is printed after the argument. If a semicolon is last, no line feed is printed.
#### `def `
creates a variable called with the value . Useful for constants or aliases
#### `seek …`
sums up all offsets and moves the read cursor to the absolute position
#### `move …`
sums up all offsets and moves the read cursor relatively. Accepts negative numbers
#### `tell`
prints the file cursor
#### `tell
#### `dump `
dumps bytes
appends everything past the ! to the last created program
#### `call …`
invokes a program named . all arguments past that are passed as variables arg[0] to arg[n]
#### `array `
Creates an array of items called . In , the first occurance of `?` will be replaced with the array index. determines the type of the array items.
#### `array `
Creates an array of items called where is a sized type (str, blob, ...). In , the first occurance of `?` will be replaced with the array index. determines the type of the array items.
#### `select …`
Builds a variable name from and all provided s. For each key, the next `?` in the is replaced with the value of .
After all `?` are resolved, a global lookup is performed and the variable with the computed name is then copied into .
#### `endian le`
changes integer endianess to little endian
#### `endian little`
changes integer endianess to little endian
#### `endian be`
changes integer endianess to big endian
#### `endian big`
changes integer endianess to big endian
#### `bitread`
switches to bit-reading mode
#### `byteread`
switches out of bit-reading mode, discarding any unread bits in the current byte
#### `bitmap `
consumes a bitmap of size \* and rgb565, rgb888, bgr888, rgbx8888 or rgba8888
#### `bitmap
#### `lut ( ) …`
Will perform a lookup on value . If matches , the following is printed. Any number of pairs can be passed.
#### `divs
#### `diskdump bytes and writes them into a file called . Useful to extract portions of a file.
#### `findpattern …`
All arguments together form a pattern. This pattern is then searched in the file from the cursor position on and each occurrence is printed with offset.
Pattern components can either be a `*` for any kind of byte, or a list of `|`-separated integers that list the possibilities for this option.
To make this more clear, let's consider this example:
We're searching for a list of u32 that can only consist of the integer values 1, 2 or 3, but there's a unknown length marker at the start that is a 16 bit value less than 256:
```rb
# Search for at least 3 items:
# len item 0 item 1 item 2
findpattern * 0 1|2|3 0 0 0 1|2|3 0 0 0 1|2|3 0 0 0
```
### Macros
```rb
.if # the code following this will be executed if is not 0
.if # the code following this will be executed if is equals to
.else # swaps the current execution condition
.endif # ends a if block
.loop # Repeats the following code for times.
.loop # Repeats the following code for times. Writes the current index into .
.endloop # Terminates the current loop
.pgm # creates a new program called
.endpgm # ends the current program
```
### Types
```rb
u8 # 8 bit unsigned integer
u16 # 16 bit unsigned integer
u32 # 32 bit unsigned integer
u64 # 64 bit unsigned integer
i8 # 8 bit signed integer, two's complement
i16 # 16 bit signed integer, two's complement
i32 # 32 bit signed integer, two's complement
i64 # 64 bit signed integer, two's complement
f32 # 32 bit floating point
f64 # 64 bit floating point
str # ascii string of bytes, displayed as string+escapes
blob # binary blob of bytes, displayed as array
bitblob # binary blob of bits, displayed as array of bits (only valid in bit-reading mode)
bits # an unsigned integer of bits up to 64 (only valid in bit-reading mode)
```
### Predefined variables
```sh
str > file.path # The full path of the current file
str > file.name # The file name of the current file
u64 file.size # Size of the current file in bytes
```
## Example
```
endian le
u32 magic
u32 type
u32 offset
u32 length
print section 1
seek *offset
dump *length
.if *type 10
seek 0x200
str 10 description
.endif
```
A more complete example can be found [here](example/), which will decode a good amount of a PNG file.
## Building
1. Fetch the latest zig install (tested with `0.10.0-dev.4442+ce3ffa5e1`).
2. Invoke `zig build`.
3. Install `zig-out/bin/livedecode` into your system in a way you like it.