CSF File Format
CSF files hold stringtables for RA2/YR (also for Generals/ZH and probably others).
For more information about what a CSF file is, go to the CSF page.
On this page you will find a guide to how the format is built up.
The Header
The header of a CSF file is 0x18 bytes long.
It is built up like this:
Offset | Type | Description |
---|---|---|
0x0 | char[4] |
" FSC" |
0x4 | DWORD |
CSF Version |
0x8 | DWORD |
NumLabels |
0xC | DWORD |
NumExtraValues |
0x10 | DWORD |
(nothing) |
0x14 | DWORD |
Language |
Language
The language DWORD can have the following values (others will be recognized as "Unknown"):
0 = US (English)* 1 = UK (English) 2 = German* 3 = French* 4 = Spanish 5 = Italian 6 = Japanese 7 = Jabberwockie 8 = Korean* 9 = Chinese* >9 = Unknown
* RA2/YR has been released in this language.
Labels
After the header, the label data follows.
A label can be considered an entry in the stringtable (e.g. "GUI:OK" is a label).
Each label can have a name (e.g. "NAME:MTNK"), a value (e.g. "Grizzly Tank") and an extra value (no example in the original ra2.csf/ra2md.csf).
While the name and the extra value are ASCII strings, the value is a Unicode string (in order to support Korean, Chinese, etc).
Now let's come to how the data is stored in the CSF file:
Label header
The label data begins with a label header, which is built up like this:
Offset | Type | Description |
---|---|---|
0x0 | char[4] |
" LBL" |
0x4 | DWORD |
Unknown |
0x8 | DWORD |
LabelNameLength |
0xC | char[LabelNameLength] |
LabelName |
The first label in ra2md.csf can be found at 0x18.
Note: Spaces, tabs and line breaks will be formatted out of the label's name, therefore they cannot be used.
Values
Directly after the label header, the value data follows.
This is how it is built up:
Offset | Type | Description |
---|---|---|
0x0 | char[4] |
" RTS or "WRTS" |
0x4 | DWORD |
ValueLength |
0x8 | byte[ValueLength*2] |
Value |
0x8+ValueLength*2 | DWORD |
ExtraValueLength |
0x8+ValueLength*2+0x4 | char[ExtraValueLength] |
ExtraValue |
Decoding the value
To decode the value to a Unicode string, not every byte of the value data (or substract it from 0xFF).
An example in C/C++:
int ValueDataLength=ValueLength<<1 for(register int i=0;i<ValueDataLen;i++) { ValueData[i]=~ValueData[i] }