-
Notifications
You must be signed in to change notification settings - Fork 28
/
wiki-wdc1.bt
161 lines (156 loc) · 6.7 KB
/
wiki-wdc1.bt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include "basics.h"
struct wdc1_db2_header
{
uint32_t magic; // 'WDC1'
uint32_t record_count;
uint32_t field_count;
uint32_t record_size;
uint32_t string_table_size;
uint32_t table_hash; // hash of the table name
uint32_t layout_hash; // this is a hash field that changes only when the structure of the data changes
uint32_t min_id;
uint32_t max_id;
uint32_t locale; // as seen in TextWowEnum
uint32_t copy_table_size;
uint16_t flags; // possible values are listed in Known Flag Meanings
uint16_t id_index; // this is the index of the field containing ID values; this is ignored if flags & 0x04 != 0
uint32_t total_field_count; // in WDC1 this value seems to always be the same as the 'field_count' value
uint32_t bitpacked_data_offset; // relative position in record where bitpacked data begins; not important for parsing the file
uint32_t lookup_column_count;
uint32_t offset_map_offset; // Offset to array of struct {uint32_t offset; uint16_t size;}[max_id - min_id + 1];
uint32_t id_list_size; // List of ids present in the DB file
uint32_t field_storage_info_size;
uint32_t common_data_size;
uint32_t pallet_data_size;
uint32_t relationship_data_size;
};
struct field_structure
{
uint16_t size;
uint16_t offset;
};
wdc1_db2_header header;
field_structure fields[header.total_field_count];
if ((header.flags & 1) == 0) {
// Normal records
struct record_data
{
char data[header.record_size];
};
record_data records[header.record_count];
char string_data[header.string_table_size];
} else {
// Offset map records -- these records have null-terminated strings inlined, and
// since they are variable-length, they are pointed to by an array of 6-byte
// offset+size pairs.
char variable_record_data[header.offset_map_offset - sizeof(wdc1_db2_header) - (sizeof(field_structure) * header.total_field_count)];
struct offset_map_entry
{
uint32_t offset;
uint16_t size;
};
offset_map_entry offset_map[header.max_id - header.min_id + 1];
}
enum field_compression
{
// None -- the field is a 8-, 16-, 32-, or 64-bit integer in the record data
field_compression_none,
// Bitpacked -- the field is a bitpacked integer in the record data. It
// is field_size_bits long and starts at field_offset_bits.
// A bitpacked value occupies
// (field_size_bits + (field_offset_bits & 7) + 7) / 8
// bytes starting at byte
// field_offset_bits / 8
// in the record data. These bytes should be read as a little-endian value,
// then the value is shifted to the right by (field_offset_bits & 7) and
// masked with ((1ull << field_size_bits) - 1).
field_compression_bitpacked,
// Common data -- the field is assumed to be a default value, and exceptions
// from that default value are stored in the corresponding section in
// common_data as pairs of { uint32_t record_id; uint32_t value; }.
field_compression_common_data,
// Bitpacked indexed -- the field has a bitpacked index in the record data.
// This index is used as an index into the corresponding section in
// pallet_data. The pallet_data section is an array of uint32_t, so the index
// should be multiplied by 4 to obtain a byte offset.
field_compression_bitpacked_indexed,
// Bitpacked indexed array -- the field has a bitpacked index in the record
// data. This index is used as an index into the corresponding section in
// pallet_data. The pallet_data section is an array of uint32_t[array_count],
//
field_compression_bitpacked_indexed_array,
};
typedef struct
{
uint16_t field_offset_bits;
uint16_t field_size_bits; // very important for reading bitpacked fields; size is the sum of all array pieces in bits - for example, uint32[3] will appear here as '96'
// additional_data_size is the size in bytes of the corresponding section in
// common_data or pallet_data. These sections are in the same order as the
// field_info, so to find the offset, add up the additional_data_size of any
// previous fields which are stored in the same block (common_data or
// pallet_data).
uint32_t additional_data_size;
field_compression storage_type;
switch (storage_type)
{
case field_compression_bitpacked:
uint32_t bitpacking_offset_bits; // not useful for most purposes; formula they use to calculate is bitpacking_offset_bits = field_offset_bits - (header.bitpacked_data_offset * 8)
uint32_t bitpacking_size_bits; // not useful for most purposes
uint32_t flags; // known values - 0x01: sign-extend (signed)
break;
case field_compression_common_data:
uint32_t default_value;
uint32_t unk_or_unused2;
uint32_t unk_or_unused3;
break;
case field_compression_bitpacked_indexed:
uint32_t bitpacking_offset_bits; // not useful for most purposes; formula they use to calculate is bitpacking_offset_bits = field_offset_bits - (header.bitpacked_data_offset * 8)
uint32_t bitpacking_size_bits; // not useful for most purposes
uint32_t unk_or_unused3;
break;
case field_compression_bitpacked_indexed_array:
uint32_t bitpacking_offset_bits; // not useful for most purposes; formula they use to calculate is bitpacking_offset_bits = field_offset_bits - (header.bitpacked_data_offset * 8)
uint32_t bitpacking_size_bits; // not useful for most purposes
uint32_t array_count;
break;
default:
uint32_t unk_or_unused1;
uint32_t unk_or_unused2;
uint32_t unk_or_unused3;
break;
}
} field_storage_info;
uint32_t id_list[header.id_list_size / 4];
if (header.copy_table_size > 0) {
struct copy_table_entry
{
uint32_t id_of_new_row;
uint32_t id_of_copied_row;
};
copy_table_entry copy_table[header.copy_table_size / sizeof(copy_table_entry)];
}
local uint32_t sizeof_field_storage_info = 2+2+4+4+4+4+4;
field_storage_info field_info[header.field_storage_info_size / sizeof_field_storage_info];
char pallet_data[header.pallet_data_size];
char common_data[header.common_data_size];
if (header.relationship_data_size > 0) {
// In some tables, this relationship mapping replaced columns that were used
// only as a lookup, such as the SpellID in SpellX* tables.
struct relationship_entry
{
// This is the id of the foreign key for the record, e.g. SpellID in
// SpellX* tables.
uint32_t foreign_id;
// This is the index of the record in record_data. Note that this is
// *not* the record's own ID.
uint32_t record_index;
};
struct relationship_mapping
{
uint32_t num_entries;
uint32_t min_id;
uint32_t max_id;
relationship_entry entries[num_entries];
};
relationship_mapping relationship_map;
}