Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
DBCFileLoader.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9
10#include "DBCFileLoader.h"
11#include "Errors.h"
12
14
15bool DBCFileLoader::Load(const char* filename, const char* fmt)
16{
17 uint32 header;
18 if (data)
19 {
20 delete[] data;
21 data = NULL;
22 }
23
24 FILE* f = fopen(filename, "rb");
25 if (!f)
26 return false;
27
28 if (fread(&header, 4, 1, f) != 1) // Number of records
29 {
30 fclose(f);
31 return false;
32 }
33
34
35 EndianConvert(header);
36
37 if (header != 0x43424457) //'WDBC'
38 {
39 fclose(f);
40 return false;
41 }
42
43 if (fread(&recordCount, 4, 1, f) != 1) // Number of records
44 {
45 fclose(f);
46 return false;
47 }
48
50
51 if (fread(&fieldCount, 4, 1, f) != 1) // Number of fields
52 {
53 fclose(f);
54 return false;
55 }
56
58
59 if (fread(&recordSize, 4, 1, f) != 1) // Size of a record
60 {
61 fclose(f);
62 return false;
63 }
64
66
67 if (fread(&stringSize, 4, 1, f) != 1) // String size
68 {
69 fclose(f);
70 return false;
71 }
72
74
76 fieldsOffset[0] = 0;
77 for (uint32 i = 1; i < fieldCount; ++i)
78 {
79 fieldsOffset[i] = fieldsOffset[i - 1];
80 if (fmt[i - 1] == 'b' || fmt[i - 1] == 'X') // byte fields
81 fieldsOffset[i] += sizeof(uint8);
82 else // 4 byte fields (int32/float/strings)
83 fieldsOffset[i] += sizeof(uint32);
84 }
85
86 data = new unsigned char[recordSize * recordCount + stringSize];
88
89 if (fread(data, recordSize * recordCount + stringSize, 1, f) != 1)
90 {
91 fclose(f);
92 return false;
93 }
94
95 fclose(f);
96
97 return true;
98}
99
101{
102 if (data)
103 delete[] data;
104
105 if (fieldsOffset)
106 delete[] fieldsOffset;
107}
108
110{
111 assert(data);
112 return Record(*this, data + id * recordSize);
113}
114
115uint32 DBCFileLoader::GetFormatRecordSize(std::string format, int32* index_pos)
116{
117 uint32 recordsize = 0;
118 int32 i = -1;
119 for (uint32 x = 0; format[x]; ++x)
120 {
121 switch (format[x])
122 {
123 case FT_FLOAT:
124 recordsize += sizeof(float);
125 break;
126 case FT_INT:
127 recordsize += sizeof(uint32);
128 break;
129 case FT_STRING:
130 recordsize += sizeof(char*);
131 break;
132 case FT_SORT:
133 i = x;
134 break;
135 case FT_IND:
136 i = x;
137 recordsize += sizeof(uint32);
138 break;
139 case FT_BYTE:
140 recordsize += sizeof(uint8);
141 break;
142 case FT_NA:
143 case FT_NA_BYTE:
144 break;
145 default:
146 ASSERT(false && "Unknown field format character in DBCfmt.h");
147 break;
148 }
149 }
150
151 if (index_pos)
152 *index_pos = i;
153
154 return recordsize;
155}
156
157char* DBCFileLoader::AutoProduceData(std::string format, uint32& records, char**& indexTable, uint32 sqlRecordCount, uint32 sqlHighestIndex, char*& sqlDataTable)
158{
159 /*
160 format STRING, NA, FLOAT, NA, INT <=>
161 struct{
162 char* field0,
163 float field1,
164 int field2
165 }entry;
166
167 this func will generate entry[rows] data;
168 */
169
170 typedef char* ptr;
171 if (format.length() != fieldCount)
172 return NULL;
173
174 //get struct size and index pos
175 int32 i;
176 uint32 recordsize = GetFormatRecordSize(format, &i);
177
178 if (i >= 0)
179 {
180 uint32 maxi = 0;
181 //find max index
182 for (uint32 y = 0; y < recordCount; ++y)
183 {
184 uint32 ind = getRecord(y).getUInt(i);
185 if (ind > maxi)
186 maxi = ind;
187 }
188
189 // If higher index avalible from sql - use it instead of dbcs
190 if (sqlHighestIndex > maxi)
191 maxi = sqlHighestIndex;
192
193 ++maxi;
194 records = maxi;
195 indexTable = new ptr[maxi];
196 memset(indexTable, 0, maxi * sizeof(ptr));
197 }
198 else
199 {
200 records = recordCount + sqlRecordCount;
201 indexTable = new ptr[recordCount + sqlRecordCount];
202 }
203
204 char* dataTable = new char[(recordCount + sqlRecordCount) * recordsize];
205
206 uint32 offset = 0;
207
208 for (uint32 y = 0; y < recordCount; ++y)
209 {
210 if (i >= 0)
211 indexTable[getRecord(y).getUInt(i)] = &dataTable[offset];
212 else
213 indexTable[y] = &dataTable[offset];
214
215 for (uint32 x = 0; x < fieldCount; ++x)
216 {
217 switch (format[x])
218 {
219 case FT_FLOAT:
220 *((float*)(&dataTable[offset])) = getRecord(y).getFloat(x);
221 offset += sizeof(float);
222 break;
223 case FT_IND:
224 case FT_INT:
225 *((uint32*)(&dataTable[offset])) = getRecord(y).getUInt(x);
226 offset += sizeof(uint32);
227 break;
228 case FT_BYTE:
229 *((uint8*)(&dataTable[offset])) = getRecord(y).getUInt8(x);
230 offset += sizeof(uint8);
231 break;
232 case FT_STRING:
233 *((char**)(&dataTable[offset])) = NULL; // will replace non-empty or "" strings in AutoProduceStrings
234 offset += sizeof(char*);
235 break;
236 case FT_NA:
237 case FT_NA_BYTE:
238 case FT_SORT:
239 break;
240 default:
241 ASSERT(false && "Unknown field format character in DBCfmt.h");
242 break;
243 }
244 }
245 }
246
247 sqlDataTable = dataTable + offset;
248
249 return dataTable;
250}
251
252char* DBCFileLoader::AutoProduceStrings(std::string format, char* dataTable)
253{
254 if (format.length() != fieldCount)
255 return NULL;
256
257 char* stringPool = new char[stringSize];
258 memcpy(stringPool, stringTable, stringSize);
259
260 uint32 offset = 0;
261
262 for (uint32 y = 0; y < recordCount; ++y)
263 {
264 for (uint32 x = 0; x < fieldCount; ++x)
265 {
266 switch (format[x])
267 {
268 case FT_FLOAT:
269 offset += sizeof(float);
270 break;
271 case FT_IND:
272 case FT_INT:
273 offset += sizeof(uint32);
274 break;
275 case FT_BYTE:
276 offset += sizeof(uint8);
277 break;
278 case FT_STRING:
279 {
280 // fill only not filled entries
281 char** slot = (char**)(&dataTable[offset]);
282 if (!*slot || !**slot)
283 {
284 const char* st = getRecord(y).getString(x);
285 *slot = stringPool + (st - (const char*)stringTable);
286 }
287 offset += sizeof(char*);
288 break;
289 }
290 case FT_NA:
291 case FT_NA_BYTE:
292 case FT_SORT:
293 break;
294 default:
295 ASSERT(false && "Unknown field format character in DBCfmt.h");
296 break;
297 }
298 }
299 }
300
301 return stringPool;
302}
void EndianConvert(T &)
std::int32_t int32
Definition Define.h:73
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
@ FT_IND
Definition Define.h:90
@ FT_NA
Definition Define.h:83
@ FT_FLOAT
Definition Define.h:86
@ FT_STRING
Definition Define.h:85
@ FT_SORT
Definition Define.h:89
@ FT_NA_BYTE
Definition Define.h:84
@ FT_INT
Definition Define.h:87
@ FT_BYTE
Definition Define.h:88
#define ASSERT
Definition Errors.h:29
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
unsigned char * data
Record getRecord(size_t id)
bool Load(const char *filename, const char *fmt)
unsigned char * stringTable
uint32 * fieldsOffset
char * AutoProduceData(std::string fmt, uint32 &count, char **&indexTable, uint32 sqlRecordCount, uint32 sqlHighestIndex, char *&sqlDataTable)
static uint32 GetFormatRecordSize(std::string format, int32 *index_pos=NULL)
char * AutoProduceStrings(std::string fmt, char *dataTable)