Skip to content

feat: config values like the binarizer, +=, enums, int64, text output - #51

Merged
TheWillard merged 8 commits into
mainfrom
feat/cfg-parser-gaps
Nov 11, 2026
Merged

TheWillard merged 8 commits into
mainfrom
feat/cfg-parser-gaps

Conversation

@TheWillard

@TheWillard TheWillard commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Text configs failed on much of what the game loads: += arrays, unquoted values (true, $STR_x, 0.2*4/3), numbers with leading zeros or in hex, class names starting with a digit, enum blocks. The parser is now hand-written instead of chumsky (raw value text isn't recoverable from the token stream) and stores values the way the game's binarizer does. Checked against the base game's config.bin files:

  • Integers are Long (Int64 when larger), hex included. Numbers with a fraction or exponent are Float, also 1.0: the base game has 7,636 whole-number floats.
  • Everything else unquoted is a String with the text as written: config.bin stores columns = "6 - 1", idc = "125+1", default = "true". Behavior change: true/false were Long(1)/Long(0).
  • name[] += {...} sets the new CfgProperty::append, also for binary entry type 5 (flags 1, found in ACE).
  • enum { A, B = 5, C }; goes to the new Cfg::enums, also read from the table at enum_offset of binary configs. Best-effort there: its count can be larger than the values stored (24 for 15 in 3den's config.bin), and damaged files point past the end.
  • A missing ; at line ends and after classes, ; instead of , in arrays, empty values (texture = ;), a stray } at the end and a quoted string followed by more text ('Indep' >> "IND_C_F", RHS Warlords) are accepted: BI's own and published mod files have them.
  • __EXEC(...) is skipped, __EVAL(...) is a string.
  • CfgValue::Int64 for binary value type 6 (2 base game configs panicked on it).

Binary configs:

  • read_compressed_int computed (b - 1) * 0x80 in u8: counts of 384 and more could read wrong. data_f\loadorder\config.bin failed, a Posadkovo rvmat read 132 of its 388 entries. It also printed every second byte (dbg!).
  • Unknown entry and value types are a new RapError instead of panics, class nesting is limited to 256 and counts aren't allocated up front: damaged files and decoys of obfuscated PBOs fail instead of aborting or overflowing the stack.

Writing configs:

  • Cfg, CfgEntry, CfgClass, CfgProperty and CfgValue implement Display, writing text that parses back to the same config (quotes doubled, line breaks as \n, floats always with a . or exponent, +=, enums). Every binarized config of the base game (19,025) reads back the same from its text. PrettyPrint and to_strr use it: they didn't escape quotes and wrote 1.0 as 1.

Breaking: new fields CfgProperty::append, Cfg::enums, new variant CfgValue::Int64, true/false are strings.

Checked every config in every PBO (config.bin, .cpp, .rvmat, .bisurf, .sqm, .ext, .bikb, .fsm, .cfg), text through the preprocessor of #50 with includes resolved across all PBOs, before and after:

  • Base game (196 PBOs): 1,370 of 1,773 text configs and 3 of 19,025 binary ones failed. Now all read, except 18 whose include files aren't shipped.
  • Mods (2,152 PBOs, ~250,000 configs): nothing that read before fails, with the same entry counts except the Posadkovo rvmat above. 535 more text and 168 more binary configs read, 7,147 panics and 11 stack overflows (whole PBOs lost) are errors now. Everything still failing is a decoy of an obfuscated mod, except two Stargate rvmats with damaged binary headers and a VT5 model.cfg with unbalanced braces.
  • CBA_A3 and ACE3 sources (220 config.cpp, game includes from ui_f.pbo): all parse, was 121.

Based on #50.

Text configs ignored every line starting with #, so macros were left
unexpanded and #include was dropped.

- rap::Preprocessor: #define (arguments, variadic __VA_* macros, # and
  ##, multi-line), #undef, #if/#ifdef/#ifndef/#else/#endif, #include,
  __has_include and the __XXX__ built-ins.
- Follows the game where it differs from C: arguments are expanded
  before # and ##, arguments are not trimmed, ## keeps the whitespace
  around it, single-quoted strings are expanded, double-quoted not.
- Includes go through IncludeResolver: FsIncludeResolver for files on
  disk, or any closure, with join_include_path for virtual paths.
- Cfg::parse_config and Cfg::read preprocess first, #include without a
  resolver is an error. Cfg::parse_config_with and Cfg::parse_path take
  a preprocessor.
Text configs failed on much of what the game loads: += arrays, unquoted
values (true, $STR_x, 0.2*4/3), numbers with leading zeros or in hex,
class names starting with a digit, enum blocks. The parser is now
hand-written instead of chumsky and stores values the way the game's
binarizer does:

- Integers are Long (Int64 when larger), hex included. Numbers with a
  fraction or exponent are Float, also 1.0. Everything else unquoted is
  a String with the text as written, true and false included (they were
  Long 1 and 0).
- name[] += {...} sets CfgProperty::append, in binary configs too
  (entry type 5).
- enum blocks go to Cfg::enums, also read from binary configs.
- A missing ; at line ends and after classes, ; in arrays, empty values
  and a stray } at the end are accepted, the game loads them.
- CfgValue::Int64 for binary value type 6.

Binary configs:

- read_compressed_int computed in u8: counts of 384 and more could
  read wrong, a root of 388 entries read 132.
- Unknown entry and value types are RapError instead of panics, class
  nesting is limited and counts aren't allocated up front, so damaged
  files fail instead of aborting or overflowing the stack.
/tmp/x/config.cpp on Linux was taken for a path of the game (\a3\...)
and only looked up in the include directories.
@codecov

codecov Bot commented Nov 11, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.14815% with 13 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...rma-file-formats/src/real_virtuality/rap/parser.rs 98.70% 6 Missing ⚠️
arma-file-formats/src/real_virtuality/rap/class.rs 80.00% 2 Missing ⚠️
...rma-file-formats/src/real_virtuality/rap/writer.rs 98.60% 2 Missing ⚠️
...rma-file-formats/src/real_virtuality/rap/config.rs 96.29% 1 Missing ⚠️
...a-file-formats/src/real_virtuality/rap/property.rs 88.88% 1 Missing ⚠️
arma-file-formats/src/real_virtuality/rap/value.rs 91.66% 1 Missing ⚠️
Files with missing lines Coverage Δ
arma-file-formats/src/core/read.rs 100.00% <100.00%> (+25.60%) ⬆️
arma-file-formats/src/real_virtuality/rap/entry.rs 100.00% <100.00%> (+47.05%) ⬆️
arma-file-formats/src/real_virtuality/rap/mod.rs 100.00% <ø> (+40.00%) ⬆️
...rma-file-formats/src/real_virtuality/rap/config.rs 96.55% <96.29%> (+11.13%) ⬆️
...a-file-formats/src/real_virtuality/rap/property.rs 95.65% <88.88%> (+35.65%) ⬆️
arma-file-formats/src/real_virtuality/rap/value.rs 96.36% <91.66%> (+35.25%) ⬆️
arma-file-formats/src/real_virtuality/rap/class.rs 90.90% <80.00%> (+23.69%) ⬆️
...rma-file-formats/src/real_virtuality/rap/writer.rs 98.60% <98.60%> (ø)
...rma-file-formats/src/real_virtuality/rap/parser.rs 98.73% <98.70%> (+31.59%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Cfg, CfgEntry, CfgClass, CfgProperty and CfgValue implement Display,
writing text that parses back to the same config: quotes doubled, line
breaks as " \n ", floats with a dot. PrettyPrint and to_strr use it, they
didn't escape quotes and wrote 1.0 as 1. Every binarized config of the
base game (19,025) reads back the same from its text.

Tests for the entry accessors, class loops, binary configs without enums,
round trips of the test data. The rap tests that only printed errors now
fail on them. Removes unused read helpers and the parser's comment
handling, the preprocessor removes comments.
@TheWillard TheWillard changed the title feat: config values like the binarizer, +=, enums, int64 feat: config values like the binarizer, +=, enums, int64, text output Nov 11, 2026
@TheWillard
TheWillard merged commit f55c120 into main Nov 11, 2026
2 checks passed
@TheWillard
TheWillard deleted the feat/cfg-parser-gaps branch November 11, 2026 22:21
TheWillard added a commit that referenced this pull request Nov 11, 2026
check_for_magic_and_decompress_lzss, Pbo::verify and the signature hashes
printed their values to stderr. The one in read_compressed_int goes with
#51, which rewrites that function.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant