TrinityCore
Loading...
Searching...
No Matches
DBCFileLoader.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21
22#include "DBCFileLoader.h"
23#include "Errors.h"
24
25DBCFileLoader::DBCFileLoader() : recordSize(0), recordCount(0), fieldCount(0), stringSize(0), fieldsOffset(nullptr), data(nullptr), stringTable(nullptr) { }
26
27bool DBCFileLoader::Load(char const* filename, char const* fmt)
28{
29 uint32 header;
30 if (data)
31 {
32 delete [] data;
33 data = nullptr;
34 }
35
36 FILE* f = fopen(filename, "rb");
37 if (!f)
38 return false;
39
40 if (fread(&header, 4, 1, f) != 1) // Number of records
41 {
42 fclose(f);
43 return false;
44 }
45
46 EndianConvert(header);
47
48 if (header != 0x43424457) //'WDBC'
49 {
50 fclose(f);
51 return false;
52 }
53
54 if (fread(&recordCount, 4, 1, f) != 1) // Number of records
55 {
56 fclose(f);
57 return false;
58 }
59
61
62 if (fread(&fieldCount, 4, 1, f) != 1) // Number of fields
63 {
64 fclose(f);
65 return false;
66 }
67
69
70 if (fread(&recordSize, 4, 1, f) != 1) // Size of a record
71 {
72 fclose(f);
73 return false;
74 }
75
77
78 if (fread(&stringSize, 4, 1, f) != 1) // String size
79 {
80 fclose(f);
81 return false;
82 }
83
85
87 fieldsOffset[0] = 0;
88 for (uint32 i = 1; i < fieldCount; ++i)
89 {
90 fieldsOffset[i] = fieldsOffset[i - 1];
91 if (fmt[i - 1] == FT_BYTE || fmt[i - 1] == FT_NA_BYTE) // byte fields
92 fieldsOffset[i] += sizeof(uint8);
93 else // 4 byte fields (int32/float/strings)
94 fieldsOffset[i] += sizeof(uint32);
95 }
96
97 data = new unsigned char[recordSize * recordCount + stringSize];
99
100 if (fread(data, recordSize * recordCount + stringSize, 1, f) != 1)
101 {
102 fclose(f);
103 return false;
104 }
105
106 fclose(f);
107
108 return true;
109}
110
112{
113 delete[] data;
114
115 delete[] fieldsOffset;
116}
117
119{
120 ASSERT(data);
121 return Record(*this, data + id * recordSize);
122}
123
124uint32 DBCFileLoader::GetFormatRecordSize(char const* format, int32* index_pos)
125{
126 uint32 recordsize = 0;
127 int32 i = -1;
128 for (uint32 x = 0; format[x]; ++x)
129 {
130 switch (format[x])
131 {
132 case FT_FLOAT:
133 recordsize += sizeof(float);
134 break;
135 case FT_INT:
136 recordsize += sizeof(uint32);
137 break;
138 case FT_STRING:
139 recordsize += sizeof(char*);
140 break;
141 case FT_SORT:
142 i = x;
143 break;
144 case FT_IND:
145 i = x;
146 recordsize += sizeof(uint32);
147 break;
148 case FT_BYTE:
149 recordsize += sizeof(uint8);
150 break;
151 case FT_NA:
152 case FT_NA_BYTE:
153 break;
154 case FT_LOGIC:
155 ABORT_MSG("Attempted to load DBC files that do not have field types that match what is in the core. Check DBCfmt.h or your DBC files.");
156 break;
157 default:
158 ABORT_MSG("Unknown field format character in DBCfmt.h");
159 break;
160 }
161 }
162
163 if (index_pos)
164 *index_pos = i;
165
166 return recordsize;
167}
168
169char* DBCFileLoader::AutoProduceData(char const* format, uint32& records, char**& indexTable)
170{
171 /*
172 format STRING, NA, FLOAT, NA, INT <=>
173 struct{
174 char* field0,
175 float field1,
176 int field2
177 }entry;
178
179 this func will generate entry[rows] data;
180 */
181
182 typedef char* ptr;
183 if (strlen(format) != fieldCount)
184 return nullptr;
185
186 //get struct size and index pos
187 int32 i;
188 uint32 recordsize = GetFormatRecordSize(format, &i);
189
190 if (i >= 0)
191 {
192 uint32 maxi = 0;
193 //find max index
194 for (uint32 y = 0; y < recordCount; ++y)
195 {
196 uint32 ind = getRecord(y).getUInt(i);
197 if (ind > maxi)
198 maxi = ind;
199 }
200
201 ++maxi;
202 records = maxi;
203 indexTable = new ptr[maxi];
204 memset(indexTable, 0, maxi * sizeof(ptr));
205 }
206 else
207 {
208 records = recordCount;
209 indexTable = new ptr[recordCount];
210 }
211
212 char* dataTable = new char[recordCount * recordsize];
213
214 uint32 offset = 0;
215
216 for (uint32 y = 0; y < recordCount; ++y)
217 {
218 if (i >= 0)
219 indexTable[getRecord(y).getUInt(i)] = &dataTable[offset];
220 else
221 indexTable[y] = &dataTable[offset];
222
223 for (uint32 x=0; x < fieldCount; ++x)
224 {
225 switch (format[x])
226 {
227 case FT_FLOAT:
228 *((float*)(&dataTable[offset])) = getRecord(y).getFloat(x);
229 offset += sizeof(float);
230 break;
231 case FT_IND:
232 case FT_INT:
233 *((uint32*)(&dataTable[offset])) = getRecord(y).getUInt(x);
234 offset += sizeof(uint32);
235 break;
236 case FT_BYTE:
237 *((uint8*)(&dataTable[offset])) = getRecord(y).getUInt8(x);
238 offset += sizeof(uint8);
239 break;
240 case FT_STRING:
241 *((char**)(&dataTable[offset])) = nullptr; // will replace non-empty or "" strings in AutoProduceStrings
242 offset += sizeof(char*);
243 break;
244 case FT_LOGIC:
245 ABORT_MSG("Attempted to load DBC files that do not have field types that match what is in the core. Check DBCfmt.h or your DBC files.");
246 break;
247 case FT_NA:
248 case FT_NA_BYTE:
249 case FT_SORT:
250 break;
251 default:
252 ABORT_MSG("Unknown field format character in DBCfmt.h");
253 break;
254 }
255 }
256 }
257
258 return dataTable;
259}
260
261char* DBCFileLoader::AutoProduceStrings(char const* format, char* dataTable)
262{
263 if (strlen(format) != fieldCount)
264 return nullptr;
265
266 char* stringPool = new char[stringSize];
267 memcpy(stringPool, stringTable, stringSize);
268
269 uint32 offset = 0;
270
271 for (uint32 y = 0; y < recordCount; ++y)
272 {
273 for (uint32 x = 0; x < fieldCount; ++x)
274 {
275 switch (format[x])
276 {
277 case FT_FLOAT:
278 offset += sizeof(float);
279 break;
280 case FT_IND:
281 case FT_INT:
282 offset += sizeof(uint32);
283 break;
284 case FT_BYTE:
285 offset += sizeof(uint8);
286 break;
287 case FT_STRING:
288 {
289 // fill only not filled entries
290 char** slot = (char**)(&dataTable[offset]);
291 if (!*slot || !**slot)
292 {
293 const char * st = getRecord(y).getString(x);
294 *slot = stringPool + (st - (char const*)stringTable);
295 }
296 offset += sizeof(char*);
297 break;
298 }
299 case FT_LOGIC:
300 ABORT_MSG("Attempted to load DBC files that does not have field types that match what is in the core. Check DBCfmt.h or your DBC files.");
301 break;
302 case FT_NA:
303 case FT_NA_BYTE:
304 case FT_SORT:
305 break;
306 default:
307 ABORT_MSG("Unknown field format character in DBCfmt.h");
308 break;
309 }
310 }
311 }
312
313 return stringPool;
314}
void EndianConvert(T &val)
@ FT_IND
@ FT_NA
@ FT_FLOAT
@ FT_STRING
@ FT_SORT
@ FT_NA_BYTE
@ FT_INT
@ FT_LOGIC
@ FT_BYTE
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
uint32_t uint32
Definition Define.h:133
#define ABORT_MSG
Definition Errors.h:75
#define ASSERT
Definition Errors.h:68
const char * getString(size_t field) const
uint32 getUInt(size_t field) const
float getFloat(size_t field) const
uint8 getUInt8(size_t field) const
char * AutoProduceStrings(char const *fmt, char *dataTable)
unsigned char * data
Record getRecord(size_t id)
bool Load(const char *filename, const char *fmt)
unsigned char * stringTable
uint32 * fieldsOffset
static uint32 GetFormatRecordSize(const char *format, int32 *index_pos=nullptr)
char * AutoProduceData(char const *fmt, uint32 &count, char **&indexTable)