REXPaint is an ASCII art tool used to design user interfaces and level prefabs, storing its data in a specific .xp file format. These files are gzipped binary structures that require a multi-step decoding process—inflating the compression and then parsing a little-endian sequence of integers and color bytes—to reconstruct the layered art.
The .xp File Structure
A REXPaint .xp file begins with a standard gzip header, identified by the magic number 1f8b. Once decompressed, the file follows a simple little-endian layout starting with a version number (typically -1) and a layer count. Each layer is defined by its own width and height, followed by a sequence of cells.

This table illustrates the specific byte layout and data types used in the .xp file format.
Each cell in the file occupies exactly 10 bytes, consisting of a 4-byte character index and two 3-byte RGB color values for the foreground and background. These cells are organized in column-major order, meaning the first column is written top-to-bottom before the second column begins.

This code snippet demonstrates the structural layout of the REXPaint file format.
Chart drawn by HN Digest from figures reported by tylerelton.com; values are shown as written in the source.
“Every value is little-endian, and the whole file is a handful of integers followed by a long run of cells.”
— Decoding REXPaint Files in Odin
Parsing Logic in Odin
To decode these files in the Odin programming language, the process first uses the `core:compress/gzip` package to inflate the file into a byte buffer. A custom `Reader` struct is then employed to maintain the current offset within the raw bytes, providing helper procedures to read `i32` and `u8` values while checking for buffer overflows.

This code shows the initial step of the decoding process using Odin's compression library.
The decoder maps the raw data into a nested hierarchy of structs: a `File` struct contains a slice of `Layer` structs, which in turn contain slices of `Cell` structs. This allows the program to represent the layered art as a structured, navigable object rather than a flat stream of bytes.
Memory Safety and Validation
The decoding process includes several safety checks to prevent memory exhaustion from corrupted or malicious files. Before allocating memory for a layer, the code calculates the expected size and compares it against the remaining bytes in the buffer. It also enforces a `MAX_CELLS_PER_LAYER` limit to ensure a single layer does not exceed a reasonable size.
Odin's `defer` mechanism is used to manage memory during the parsing of multiple layers. If a failure occurs while reading a specific layer, the `defer if` block ensures that any memory already allocated for that specific layer's cells is freed, preventing leaks while allowing the rest of the file to be processed or reported as an error.
Transparency and Rendering Trade-offs
The REXPaint format handles transparency through a specific color value: hot pink (255, 0, 255). The format specifies that any cell with this background color is treated as transparent. A specific rule applies to the base layer: if a transparent cell on a higher layer reveals a transparent cell on the lowest layer, the final result is rendered as black.
While the decoding logic successfully extracts these values, the specific implementation of the rendering engine's transparency blending is not detailed in the decoding process. The primary focus of the decoder is ensuring the integrity of the data extraction from the binary format into the Odin environment.