# Boxsim .bpj / .bch file format (reverse engineered) Boxsim (Visaton, Delphi, codec and container "MyIniFile" by UG 2004) stores projects (`.bpj`) and driver files (`.bch`) in a three-layer container. Reverse engineered 2026-09-28 from Boxsim 2.1 DE (`Boxsim.exe`, no prior public documentation existed). ## Container layout | Layer | Content | | ----- | ------- | | 1 | 8-byte plaintext magic `MyIni2CK` | | 2 | Everything after the magic is XOR-encrypted with a position-based PRNG keystream, seeds (123, 456), identical for every file | | 3 | The decrypted body is a custom LZ + canonical-Huffman stream ("A2F" codec, `CompressA2F`/`ExpandA2F` at VA `0xa1013c`/`0xa11880`) | | 4 | The decompressed payload is plain INI-style text: `key=value` lines, CRLF, `#Section` headers, German decimal commas, arrays as `;`-separated values | ## Layer 2: the Krypt PRNG Table-shuffled combination of three LCGs (found at VA `0xa12be4` init, `0xa12c9c` next byte). All arithmetic mod 2^32: ```text init(s1=123, s2=456): s3 = (s1 mod 0xFFFE) * (s2 mod 0x7F23) repeat 256 times: step(); table[i] = s1 + s2 step(): s1 = s1 * 0x10B95 + 1 s2 = s2 * 0x10BA9 + 1 (reset to 0 if >= 0xFFFFFFFF) s3 = s3 * 0x1155D + 1 next_byte(): step() idx = s3 and 0xFF out = table[idx]; table[idx] = s1 + s2 return out mod 256 ``` `plaintext[i] = filebyte[8+i] XOR next_byte()`. ## Layer 3: the A2F codec Sliding-window LZ (1 MB window, flush keeps the last 0x3FFF8 bytes) with a 356-symbol canonical Huffman alphabet: 0..255 literals, 0x100 end-of-stream, 0x101 rebuild code-length tables (adaptive), 0x102 special, rest match lengths/distances. Decoding uses a 65536-entry direct lookup table; initial state gives every symbol a 9-bit code. Not re-implemented: `bpj2ini.py` runs the original `ExpandA2F` machine code under Unicorn instead, which is exact by construction. ## Crossover encoding (`#Weiche` section) The crossover editor grid serializes as `_Part_*` keys. Only non-empty slots are written: | Key | Meaning | | --- | ------- | | `_Part_typ` | 0 empty, 1 wire, 2 resistor, 3 capacitor, 4 inductor, 5 driver, 6 amplifier input | | `_Part_value` | Component value in SI base units (Ohm, Farad, Henry) | | `_Part_Rvalue` | Series resistance of an inductor in Ohm | | `_Part_bem` | Part label, e.g. `MKT-A`, `SP 0,6mm`, `Keramik 10W` | | `_Part_chassisnr` | Driver index (0-based) for typ 5 | | `_Part_verpolt` | Polarity flag (-1 / 1) for typ 5 and 6 | | `_Part368..375_nod1/nod2` | Extra node-to-node connections | Other sections: `#General` (nAmps, nChassis), `#AktFilter` (active filters), `#Chassis` (TSP set plus measured frequency/impedance/phase arrays), `#Einbau` (enclosure: Typ 1 closed with `Vb` in m³, etc.), `#Schallwand` (baffle geometry in m), `#GemGeh` (shared enclosure). ## Tool ```bash .venv/bin/python bpj2ini.py [output.ini] ``` Needs `unicorn` and `pefile` (see `.venv/`) and `Boxsim.exe` (path via `BOXSIM_EXE` env, default: the bundled download under `boxsim_dl/`). Works for `.bpj` and `.bch` alike.