Language.dll¶
Classified VAs: 104 | Exhaustive index: Language.dll
Codepage-aware localizable string-table loader.
Role and boundary¶
Language.dll is a resource and localization module, not a call-level API. It
has no named exports beyond the DLL entry point. The game loads the module,
uses its module handle to reach the STRINGTABLE resources, and resolves string
ids through the module's codepage-aware lookup layer.
The DLL is built with a statically linked VC6 LIBCMT runtime and imports only KERNEL32. The language/codepage machinery is compiled into the module; it does not forward to the host CRT's locale layer. Roughly 95% of the code is runtime support, with the localization contract concentrated in the codepage, arena, string-table, and error-message paths.
Localization model¶
The localizable text lives in the module's .rsrc STRINGTABLE blocks. The
code around those resources provides:
- codepage resolution and conversion;
- lead-byte and character-class tables;
- case folding and case-insensitive comparison;
- a string-table arena for copied or converted strings;
- runtime error-message lookup and display;
- per-thread state and locks around the shared tables.
The lookup model is id-based. The module does not expose a public
GetString-style export; the caller uses the loaded module and the string id,
and the module's internal table/arena layer supplies the text. The exact
pointer lifetime is tied to the module's scratch/arena state, so callers must
not retain a returned pointer across unrelated lookups.
Codepage and case handling¶
The codepage layer resolves special values to the host codepages:
| Value | Meaning |
|---|---|
-2 |
GetOEMCP() |
-3 |
GetACP() |
-4 |
display codepage from the module's configuration |
FUN_1000248B builds the lead-byte table and initializes the codepage state.
FUN_10002638 resolves the special values, FUN_10002682 maps display
codepages (0x3A4 -> 0x411, 0x3A8 -> 0x804, 0x3B5 -> 0x412,
0x3B6 -> 0x404), and FUN_100026DE builds the case-fold table from
GetCPInfo and the character-type helpers.
The case/locale wrappers are the usual Win32 pair:
FUN_100041E8-LCMapStringW/LCMapStringA;FUN_10004437-GetStringTypeW/GetStringTypeA;FUN_100046C4- character-type lookup;FUN_100045F8/FUN_10004E55- single-character upper/lower mapping;FUN_10004589-toupper;FUN_10004B90/FUN_10004C60-stricmp/strnicmp.
These wrappers are the observable case-mapping contract. They use the same codepage state as the string-table layer, so changing the codepage changes both conversion and comparison behavior.
String arena¶
The string arena is a paged allocator, not the CRT heap:
FUN_10002F9Finitializes a 0x140-byte arena header;FUN_10002FE7scans the 0x14-byte entry array;FUN_10003012maintains the 0x204-byte bucket free-lists and the0x44/0xC4allocation bitmaps;FUN_1000333Ballocates a block;FUN_10003644grows an allocation;FUN_100036F5creates a new0x8000-byte page;FUN_100037F0creates a new 4 MBVirtualAllocarena;FUN_10003934/FUN_1000398Afree and trim;FUN_10003A4Cresolves an entry;FUN_10003AA3accrues accounting;FUN_10003AE8/FUN_10003CF0allocate blocks and runs.
The arena header is static at 0x10006340; entries are 0x14 bytes. The
allocator uses VirtualFree with 0x8000 pages and keeps the free-list
metadata in the same module data. It is protected by the module's lock family,
so lookups and insertions are safe across threads.
Runtime errors¶
The module carries a runtime error-message table at 0x10006060. Each entry is
eight bytes: a message id and a character pointer. FUN_10001D5E looks up an
id and either writes the message to stderr or builds a Runtime Error! message
box. FUN_10001D25 dispatches the load (0xFC) and finalize (0xFF) callbacks;
FUN_10003E14 is a lazy user32 MessageBox wrapper.
The module-name override is g_10009118; the replaceable callback is
g_1000911C. These are the points where a host can replace the default error
presentation without changing the message table.
Runtime and data layout¶
The module's .text is about 16 KB and contains roughly 100 functions. The
localization code is a small part of that; the rest is CRT startup, TLS, heap,
stdio, environment, command-line, exit, string, and SEH support.
Important data:
| Address | Contents |
|---|---|
0x10006340 |
arena header |
0x10008EE0 |
codepage lead-byte bitmap (0x41 dwords) |
0x10008EE1 |
codepage flags |
0x10008DE0 |
case-fold table |
0x100084E8 |
character-class table |
0x10006060 |
runtime error-message table |
0x10008DB0/0x10008DB4 |
arena state |
0x10008DCC/0x10008DC0-0x10008DC8 |
codepage state |
0x10008FE4/0x10008FE8 |
private heap state |
0x10008FEC |
heap-select value |
The .rdata block at 0x10005000 holds the import table, strings, and
constants; the .data blocks at 0x10006000, 0x10007000, and 0x10008000
hold the writable tables and arena metadata.
The TLS block is 0x74 bytes. It holds the per-thread data pointer at +0x50,
a flag at +0x14, and several owned pointers freed by the thread teardown
path. The module's locks are the CRT _lock/_unlock family, including the
nine small leave wrappers in the 0x10002055-0x100022E6 range.
Invariants and failure modes¶
- The module has no callable string API; callers must use the loaded module handle and the resource/string id.
- Codepage values
-2,-3, and-4are sentinels, not table indices. - The case-fold table and lead-byte table are built once per codepage; changing the codepage requires the reset/init path.
- Arena allocations are page/arena backed and freed through the arena, not
through
free. - Runtime error lookup is id-based; the table contains the module's known messages, and there is no general-purpose string API.
- The module is single-instance state: the arena, codepage tables, and error table are module globals, protected by locks rather than per-caller objects.
- The
.rsrcSTRINGTABLE blocks are the text source; the code does not embed the localized strings in.text.
Key entry points¶
| VA | Detail | What it does |
|---|---|---|
0x100010E9 |
crt | DLL entry dispatcher |
0x1000248B |
codepage | lead-byte table/state setup |
0x10002638 |
codepage | special-codepage resolver |
0x10002682 |
codepage | display-codepage map |
0x100026DE |
codepage | case-fold table builder |
0x10002863 |
codepage | one-time ACP initialization |
0x100041E8 |
codepage | LCMapString wrapper |
0x10004437 |
codepage | GetStringType wrapper |
0x100046C4 |
codepage | character-type lookup |
0x100045F8/0x10004E55 |
codepage | upper/lower mapping |
0x10004B90/0x10004C60 |
string | case-insensitive compare |
0x10002F9F |
arena | arena initialization |
0x1000333B |
arena | block allocation |
0x10003644 |
arena | grow allocation |
0x100036F5 |
arena | new page |
0x100037F0 |
arena | new 4 MB arena |
0x10003A4C |
arena | entry resolution |
0x10001D5E |
error | runtime message lookup/display |
0x10001D25 |
error | load/finalize callback dispatch |
0x10003E14 |
error | lazy MessageBox wrapper |
Details¶
| Detail | VAs | Responsibility |
|---|---|---|
| crt | 36 | Statically linked C runtime. |
| string | 20 | String table lookup/storage. |
| codepage | 17 | Codepage conversion. |
| arena | 13 | String arena. |
| locks | 10 | Lock helpers. |
| error | 4 | Error reporting. |
| data | 3 | Initialized data. |
| rdata | 1 | Read-only constants and vtables. |
Coverage¶
All 104 classified VAs are in the Language.dll index, which lists role, size, source, and evidence.