Resources are indexed by a multiple level binary-sorted tree structure. The general design can incorporate 2**31 levels. By convention, however, Windows NT uses three levels:
A series of Resource Directory Tables relate all the levels in the following way: each directory table is followed by a series of directory entries, which give the name or ID for that level (Type, Name, or Language level) and an address of either a data description or another directory table. If a data description is pointed to, then the data is a leaf in the tree. If another directory table is pointed to, then that table lists directory entries at the next level down.
A leaf’s Type, Name, and Language IDs are determined by the path taken, through directory tables, to reach the leaf. The first table determines Type ID, the second table (pointed to by the directory entry in the first table) determines Name ID, and the third table determines Language ID.
The general structure of the .rsrc section is:
Data | Description |
Resource Directory Tables (and Resource Directory Entries) | A series of tables, one for each group of nodes in the tree. All top-level (Type) nodes are listed in the first table. Entries in this table point to second-level tables. Each second-level tree has the same Type identifier but different Name identifiers. Third-level trees have the same Type and Name identifiers but different Language identifiers.
Each individual table is immediately followed by directory entries, in which each entry has: 1) a name or numeric identifier, and 2) a pointer to a data description or a table at the next lower level. |
Resource Directory Strings | Two-byte-aligned Unicode™ strings, which serve as string data pointed to by directory entries. |
Resource Data Description | An array of records, pointed to by tables, which describe the actual size and location of the resource data. These records are the leaves in the resource-description tree. |
Resource Data | Raw data of the resource section. The size and location information in the Resource Data Descriptions delimit the individual regions of resource data. |
Each Resource Directory Table has the following format. This data structure should be considered the heading of a table, because the table actually consists of directory entries (see next section) as well as this structure:
Offset | Size | Field | Description |
0 | 4 | Characteristics | Resource flags, reserved for future use; currently set to zero. |
4 | 4 | Time/Date Stamp | Time the resource data was created by the resource compiler. |
8 | 2 | Major Version | Major version number, set by the user. |
10 | 2 | Minor Version | Minor version number. |
12 | 2 | Number of Name Entries | Number of directory entries, immediately following the table, that use strings to identify Type, Name, or Language (depending on the level of the table). |
14 | 2 | Number of ID Entries | Number of directory entries, immediately following the Name entries, that use numeric identifiers for Type, Name, or Language. |
The directory entries make up the rows of a table. Each Resource Directory Entry has the following format. Note that whether the entry is a Name or ID entry is indicated by the Resource Directory Table, which indicates how many Name and ID entries follow it (remember that all the Name entries precede all the ID entries for the table). All entries for the table are sorted in ascending order: the Name entries by case-insensitive string, and the ID entries by numeric value.
Offset | Size | Field | Description |
0 | 4 | Name RVA | Address of string that gives the Type, Name, or Language identifier, depending on level of table. |
0 | 4 | Integer ID | 32-bit integer that identifies Type, Name, or Language. |
4 | 4 | Data Entry RVA | High bit 0. Address of a Resource Data Entry (a leaf). |
4 | 4 | Subdirectory RVA | High bit 1. Lower 31 bits are the address of another Resource Directory Table (the next level down). |
The Resource Directory String area consists of Unicode strings, which are word aligned. These strings are stored together after the last Resource Directory Entry and before the first Resource Data Entry. This minimizes the impact of these variable length strings on the alignment of the fixed-size directory entries. Each Resource Directory String has the following format:
Offset | Size | Field | Description |
0 | 2 | Length | Size of string, not including length field itself. |
2 | Variable | Unicode String | Variable-length Unicode string data, word aligned. |
Each Resource Data Entry describes an actual unit of raw data in the Resource Data area, and has the following format:
Offset | Size | Field | Description |
0 | 4 | Data RVA | Address of a unit of resource data in the Resource Data area. |
4 | 4 | Size | Size, in bytes, of the resource data pointed to by the Data RVA field. |
8 | 4 | Codepage | Code page used to decode code point values within the resource data. Typically, the code page would be the Unicode code page. |
12 | 4 | Reserved (must be set to 0) |
The resource example shows the PE/COFF representation of the following resource data:
TypeId# NameId# Language ID Resource Data
1 1 0 00010001
1 1 1 10010001
1 2 0 00010002
1 3 0 00010003
2 1 0 00020001
2 2 0 00020002
2 3 0 00020003
2 4 0 00020004
9 1 0 00090001
9 9 0 00090009
9 9 1 10090009
9 9 2 20090009
When this data is encoded, a dump of the PE/COFF Resource Directory results in the following output:
Offset Data
0000: 00000000 00000000 00000000 00030000 (3 entries in this directory)
0010: 00000001 80000028 (TypeId #1, Subdirectory at offset 0x28)
0018: 00000002 80000050 (TypeId #2, Subdirectory at offset 0x50)
0020: 00000009 80000080 (TypeId #9, Subdirectory at offset 0x80)
0028: 00000000 00000000 00000000 00030000 (3 entries in this directory)
0038: 00000001 800000A0 (NameId #1, Subdirectory at offset 0xA0)
0040: 00000002 00000108 (NameId #2, data desc at offset 0x108)
0048: 00000003 00000118 (NameId #3, data desc at offset 0x118)
0050: 00000000 00000000 00000000 00040000 (4 entries in this directory)
0060: 00000001 00000128 (NameId #1, data desc at offset 0x128)
0068: 00000002 00000138 (NameId #2, data desc at offset 0x138)
0070: 00000003 00000148 (NameId #3, data desc at offset 0x148)
0078: 00000004 00000158 (NameId #4, data desc at offset 0x158)
0080: 00000000 00000000 00000000 00020000 (2 entries in this directory)
0090: 00000001 00000168 (NameId #1, data desc at offset 0x168)
0098: 00000009 800000C0 (NameId #9, Subdirectory at offset 0xC0)
00A0: 00000000 00000000 00000000 00020000 (2 entries in this directory)
00B0: 00000000 000000E8 (Language ID 0, data desc at offset 0xE8
00B8: 00000001 000000F8 (Language ID 1, data desc at offset 0xF8
00C0: 00000000 00000000 00000000 00030000 (3 entries in this directory)
00D0: 00000001 00000178 (Language ID 0, data desc at offset 0x178
00D8: 00000001 00000188 (Language ID 1, data desc at offset 0x188
00E0: 00000001 00000198 (Language ID 2, data desc at offset 0x198
00E8: 000001A8 (At offset 0x1A8, for TypeId #1, NameId #1,
Language id #0
00000004 (4 bytes of data)
00000000 (codepage)
00000000 (reserved)
00F8: 000001AC (At offset 0x1AC, for TypeId #1, NameId #1,
Language id #1
00000004 (4 bytes of data)
00000000 (codepage)
00000000 (reserved)
0108: 000001B0 (At offset 0x1B0, for TypeId #1, NameId #2,
00000004 (4 bytes of data)
00000000 (codepage)
00000000 (reserved)
0118: 000001B4 (At offset 0x1B4, for TypeId #1, NameId #3,
00000004 (4 bytes of data)
00000000 (codepage)
00000000 (reserved)
0128: 000001B8 (At offset 0x1B8, for TypeId #2, NameId #1,
00000004 (4 bytes of data)
00000000 (codepage)
00000000 (reserved)
0138: 000001BC (At offset 0x1BC, for TypeId #2, NameId #2,
00000004 (4 bytes of data)
00000000 (codepage)
00000000 (reserved)
0148: 000001C0 (At offset 0x1C0, for TypeId #2, NameId #3,
00000004 (4 bytes of data)
00000000 (codepage)
00000000 (reserved)
0158: 000001C4 (At offset 0x1C4, for TypeId #2, NameId #4,
00000004 (4 bytes of data)
00000000 (codepage)
00000000 (reserved)
0168: 000001C8 (At offset 0x1C8, for TypeId #9, NameId #1,
00000004 (4 bytes of data)
00000000 (codepage)
00000000 (reserved)
0178: 000001CC (At offset 0x1CC, for TypeId #9, NameId #9,
Language id #0
00000004 (4 bytes of data)
00000000 (codepage)
00000000 (reserved)
0188: 000001D0 (At offset 0x1D0, for TypeId #9, NameId #9,
Language id #1
00000004 (4 bytes of data)
00000000 (codepage)
00000000 (reserved)
0198: 000001D4 (At offset 0x1D4, for TypeId #9, NameId #9,
Language id #2
00000004 (4 bytes of data)
00000000 (codepage)
00000000 (reserved)
The raw data for the resources follows:
01A8: 00010001
01AC: 10010001
01B0: 00010002
01B4: 00010003
01B8: 00020001
01BC: 00020002
01C0: 00020003
01C4: 00020004
01C8: 00090001
01CC: 00090009
01D0: 10090009
01D4: 20090009