String16 Type Support (lestring16 / bestring16)#
lestring16 and bestring16 are magic(5) type keywords for reading UCS-2 16-bit encoded strings from binary files. They are the primary way magic rules match Windows-style wide-character strings (e.g., NTLDR, PE resource strings, registry data).
AST Representation#
Both keywords map to the TypeKind::String16 variant in src/parser/ast.rs:
String16 {
endian: Endianness,
}
lestring16 produces Endianness::Little; bestring16 produces Endianness::Big. There is no bare string16 keyword — magic(5) only defines the explicitly-endian forms .
Parser Support#
Keyword recognition is in parse_type_keyword in src/parser/types.rs. lestring16 and bestring16 are listed before string in the alt() combinator so the longer keyword wins .
Keyword-to-kind mapping is handled by string16_family, which is called from type_keyword_to_kind. Unlike regex and search, the String16 variant is fully constructed from the keyword alone — no suffix parsing is needed.
Evaluator Support#
Reading#
The evaluator dispatches TypeKind::String16 { endian } to read_string16 in src/evaluator/types/string.rs .
read_string16 behavior:
- Reads 2-byte code units starting at
offset, interpreting them with the givenEndianness - Stops at a U+0000 terminator (
0x00 0x00), buffer end, or afterSTRING16_MAX_UNITS(8192) code units - Surrogate-pair code units (U+D800–U+DFFF) are replaced with U+FFFD — UCS-2 does not resolve surrogates
- A trailing odd byte (buffer length not even) is silently ignored
- Returns
TypeReadError::BufferOverrunwhenoffset >= buffer.len() - Returns
Ok(Value::String(decoded))on success, with non-ASCII BMP characters preserved
Anchor Advancement#
For relative-offset child rules (&N), the evaluator calls string16_bytes_consumed . This mirrors read_string16's walk and returns the byte count consumed, including the 2-byte NUL terminator when one is found . The count is always a multiple of 2.
Serialization#
Code generation for built-in rules handles TypeKind::String16 in src/parser/codegen.rs , emitting the endian field via serialize_endianness.
Key Constraints#
| Property | Value |
|---|---|
| Encoding | UCS-2 (BMP only; no surrogate pairs) |
| Unit size | 2 bytes |
| Terminator | 0x00 0x00 (2 bytes) |
| Max units | 8192 (STRING16_MAX_UNITS) |
| Invalid code units | Replaced with U+FFFD |
| Keywords | lestring16, bestring16 (no bare string16) |
| Endianness | Explicit only (le / be); Native is valid at the Rust level but not produced by the parser |
Related Source Files#
| File | Role |
|---|---|
src/parser/ast.rs | TypeKind::String16 variant definition |
src/parser/types.rs | Keyword parsing and kind mapping |
src/evaluator/types/string.rs | read_string16 and string16_bytes_consumed |
src/evaluator/types/mod.rs | Evaluator dispatch |
src/parser/codegen.rs | Build-time serialization |