Tag Engine
The tag engine parses binary files according to a JSON schema and produces a list of named, colored regions called tags. Tags are displayed in the panel alongside the hex view, letting you navigate a file's structure at a high level instead of reading raw bytes.
How It Works
When you load a schema, the editor reads its tag definitions and templates, then walks through the file from the beginning, applying tags in order and resolving offsets, lengths, and conditions. The result is a list of tags, each with a start offset, end offset, and display value.
Evaluation runs top-to-bottom. Each tag normally begins right after the previous one ends (auto offset), but any tag can override its position with an explicit or computed start_offset.
Aliases
An alias is a named integer or string value saved during evaluation and available to subsequent tags in the same schema.
When a tag has an alias field, the engine reads its bytes as an unsigned integer (up to 8 bytes) and stores that value under the alias name. Later tags can reference the alias in length, start_offset, count, condition, and expression fields.
String types (string, stringz) also save their decoded text into a separate string alias table, which can be used in string comparisons inside condition.
{ "name": "Filename length", "alias": "fnLen", "length": 2, "type": "uint16_t" },
{ "name": "Filename", "length": "fnLen", "type": "string" }
Dynamic Lengths and Offsets
length and start_offset can be:
- A literal integer:
"length": 4 - An alias name:
"length": "fnLen" - An alias with an arithmetic modifier:
"length": "fnLen+4","start_offset": "base-2"
Supported operators: +, -, *, /.
The left side resolves to an alias value; the right side resolves to another alias or a literal number. Operations are applied in one step (there is no operator precedence — use this for simple adjustments only).
Conditions
A tag with a condition field is only evaluated when the condition is true. Skipped tags produce no output and do not advance the file cursor.
{ "name": "Extra field", "length": "xlen", "condition": "flags & 4" }
The condition syntax is alias operator value:
| Operator | Meaning |
|---|---|
== |
equal |
!= |
not equal |
> / < |
greater / less than |
>= / <= |
greater or equal / less or equal |
& |
bit is set |
!& |
bit is not set |
For string comparisons, wrap the value in single quotes:
{ "condition": "de_name != '.'" }
Definitions and Arrays
Definitions are reusable named groups of tags declared in the definitions section of the schema. They are not evaluated directly — they are referenced by array and ref tags.
An array tag expands a definition template a given number of times, each iteration starting where the previous one ended:
{
"name": "Local File Entries",
"type": "array",
"count": "totalEntries",
"template": "local_file"
}
count can be a literal integer or an alias. The array also accepts max_offset (expression) to stop iteration before reaching a byte boundary.
A ref tag expands a definition inline but does not advance the file cursor — the offset is restored to its value before the ref. Use this to overlay structure on bytes that belong to a previously parsed tag.
Eval Tags
An eval tag computes an arithmetic expression and stores the result in an alias. It reads no bytes and produces no visible output. This is useful for computing derived values that other tags need.
{ "type": "eval", "alias": "dataEnd", "value": "dataOffset+dataSize" }
Expressions support +, -, *, /, & applied left-to-right across aliases and literal numbers.
Lookup Tables
An array tag can build a lookup table from the aliases produced by each iteration:
{
"type": "array",
"count": "numSections",
"template": "section_header",
"lookup": { "name": "sections", "fields": ["sh_offset", "sh_size"] }
}
After the array runs, sections holds a list of records. Later tags can query it by index or by range:
- Index lookup:
sections[idx].sh_offset - Range lookup:
sections[value @ sh_offset : sh_size].someField— finds the record whose range[sh_offset, sh_offset + sh_size)containsvalue
Magic Values and Backward Search
A magic tag matches a known byte pattern. When "search": "backward" is set, the engine scans backward from the end of the file to find the pattern. This is used for ZIP's End of Central Directory record, which sits at a variable position near the end of the file.
{
"name": "End of Central Directory",
"type": "magic",
"value": "504b0506",
"search": "backward"
}
Python Scripts
A schema can delegate additional parsing to a Python script:
{ "script": "png_parser.py" }
The path is relative to the schema file's directory. The script runs after the schema's tags are evaluated: it can read the file and the schema's aliases and add its own tags through the hexedit module. See the Plugins API reference. See the Plugins API reference.
Byte Order
The schema-level default endianness is set at the top level:
{ "endian": "big" }
Individual tags can override it:
{ "endian": "little" }
When omitted, a tag inherits the schema default, which is little if not specified.