/src/server/shared/DataStores/DB2FileLoader.cpp

https://gitlab.com/tkrokli/TrinityCore_434 · C++ · 408 lines · 319 code · 63 blank · 26 comment · 69 complexity · 5e2451d28351ef56898b652658555c3a MD5 · raw file

  1. /*
  2. * Copyright (C) 2011 TrintiyCore <http://www.trinitycore.org/>
  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. #include "Common.h"
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include "DB2FileLoader.h"
  22. DB2FileLoader::DB2FileLoader()
  23. {
  24. data = NULL;
  25. fieldsOffset = NULL;
  26. }
  27. bool DB2FileLoader::Load(const char *filename, const char *fmt)
  28. {
  29. if (data)
  30. {
  31. delete [] data;
  32. data = NULL;
  33. }
  34. FILE* f = fopen(filename, "rb");
  35. if (!f)
  36. return false;
  37. uint32 header;
  38. if (fread(&header, 4, 1, f) != 1) // Signature
  39. {
  40. fclose(f);
  41. return false;
  42. }
  43. EndianConvert(header);
  44. if (header != 0x32424457)
  45. {
  46. fclose(f);
  47. return false; //'WDB2'
  48. }
  49. if (fread(&recordCount, 4, 1, f) != 1) // Number of records
  50. {
  51. fclose(f);
  52. return false;
  53. }
  54. EndianConvert(recordCount);
  55. if (fread(&fieldCount, 4, 1, f) != 1) // Number of fields
  56. {
  57. fclose(f);
  58. return false;
  59. }
  60. EndianConvert(fieldCount);
  61. if (fread(&recordSize, 4, 1, f) != 1) // Size of a record
  62. {
  63. fclose(f);
  64. return false;
  65. }
  66. EndianConvert(recordSize);
  67. if (fread(&stringSize, 4, 1, f) != 1) // String size
  68. {
  69. fclose(f);
  70. return false;
  71. }
  72. EndianConvert(stringSize);
  73. /* NEW WDB2 FIELDS*/
  74. if (fread(&tableHash, 4, 1, f) != 1) // Table hash
  75. {
  76. fclose(f);
  77. return false;
  78. }
  79. EndianConvert(tableHash);
  80. if (fread(&build, 4, 1, f) != 1) // Build
  81. {
  82. fclose(f);
  83. return false;
  84. }
  85. EndianConvert(build);
  86. if (fread(&unk1, 4, 1, f) != 1) // Unknown WDB2
  87. {
  88. fclose(f);
  89. return false;
  90. }
  91. EndianConvert(unk1);
  92. if (build > 12880)
  93. {
  94. if (fread(&minIndex, 4, 1, f) != 1) // MinIndex WDB2
  95. {
  96. fclose(f);
  97. return false;
  98. }
  99. EndianConvert(minIndex);
  100. if (fread(&maxIndex, 4, 1, f) != 1) // MaxIndex WDB2
  101. {
  102. fclose(f);
  103. return false;
  104. }
  105. EndianConvert(maxIndex);
  106. if (fread(&locale, 4, 1, f) != 1) // Locales
  107. {
  108. fclose(f);
  109. return false;
  110. }
  111. EndianConvert(locale);
  112. if (fread(&unk5, 4, 1, f) != 1) // Unknown WDB2
  113. {
  114. fclose(f);
  115. return false;
  116. }
  117. EndianConvert(unk5);
  118. }
  119. if (maxIndex != 0)
  120. {
  121. int32 diff = maxIndex - minIndex + 1;
  122. fseek(f, diff * 4 + diff * 2, SEEK_CUR); // diff * 4: an index for rows, diff * 2: a memory allocation bank
  123. }
  124. fieldsOffset = new uint32[fieldCount];
  125. fieldsOffset[0] = 0;
  126. for (uint32 i = 1; i < fieldCount; i++)
  127. {
  128. fieldsOffset[i] = fieldsOffset[i - 1];
  129. if (fmt[i - 1] == 'b' || fmt[i - 1] == 'X')
  130. fieldsOffset[i] += 1;
  131. else
  132. fieldsOffset[i] += 4;
  133. }
  134. data = new unsigned char[recordSize*recordCount+stringSize];
  135. stringTable = data + recordSize*recordCount;
  136. if (fread(data, recordSize * recordCount + stringSize, 1, f) != 1)
  137. {
  138. fclose(f);
  139. return false;
  140. }
  141. fclose(f);
  142. return true;
  143. }
  144. DB2FileLoader::~DB2FileLoader()
  145. {
  146. if (data)
  147. delete [] data;
  148. if (fieldsOffset)
  149. delete [] fieldsOffset;
  150. }
  151. DB2FileLoader::Record DB2FileLoader::getRecord(size_t id)
  152. {
  153. assert(data);
  154. return Record(*this, data + id*recordSize);
  155. }
  156. uint32 DB2FileLoader::GetFormatRecordSize(const char * format, int32* index_pos)
  157. {
  158. uint32 recordsize = 0;
  159. int32 i = -1;
  160. for (uint32 x=0; format[x]; ++x)
  161. {
  162. switch (format[x])
  163. {
  164. case FT_FLOAT:
  165. case FT_INT:
  166. recordsize += 4;
  167. break;
  168. case FT_STRING:
  169. recordsize += sizeof(char*);
  170. break;
  171. case FT_SORT:
  172. i = x;
  173. break;
  174. case FT_IND:
  175. i = x;
  176. recordsize += 4;
  177. break;
  178. case FT_BYTE:
  179. recordsize += 1;
  180. break;
  181. }
  182. }
  183. if (index_pos)
  184. *index_pos = i;
  185. return recordsize;
  186. }
  187. uint32 DB2FileLoader::GetFormatStringsFields(const char * format)
  188. {
  189. uint32 stringfields = 0;
  190. for (uint32 x=0; format[x]; ++x)
  191. if (format[x] == FT_STRING)
  192. ++stringfields;
  193. return stringfields;
  194. }
  195. char* DB2FileLoader::AutoProduceData(const char* format, uint32& records, char**& indexTable)
  196. {
  197. typedef char * ptr;
  198. if (strlen(format) != fieldCount)
  199. return NULL;
  200. //get struct size and index pos
  201. int32 i;
  202. uint32 recordsize=GetFormatRecordSize(format, &i);
  203. if (i >= 0)
  204. {
  205. uint32 maxi = 0;
  206. //find max index
  207. for (uint32 y = 0; y < recordCount; y++)
  208. {
  209. uint32 ind=getRecord(y).getUInt(i);
  210. if (ind>maxi)
  211. maxi = ind;
  212. }
  213. ++maxi;
  214. records = maxi;
  215. indexTable = new ptr[maxi];
  216. memset(indexTable, 0, maxi * sizeof(ptr));
  217. }
  218. else
  219. {
  220. records = recordCount;
  221. indexTable = new ptr[recordCount];
  222. }
  223. char* dataTable = new char[recordCount * recordsize];
  224. uint32 offset=0;
  225. for (uint32 y =0; y < recordCount; y++)
  226. {
  227. if (i>=0)
  228. {
  229. indexTable[getRecord(y).getUInt(i)] = &dataTable[offset];
  230. }
  231. else
  232. indexTable[y] = &dataTable[offset];
  233. for (uint32 x = 0; x < fieldCount; x++)
  234. {
  235. switch (format[x])
  236. {
  237. case FT_FLOAT:
  238. *((float*)(&dataTable[offset])) = getRecord(y).getFloat(x);
  239. offset += 4;
  240. break;
  241. case FT_IND:
  242. case FT_INT:
  243. *((uint32*)(&dataTable[offset])) = getRecord(y).getUInt(x);
  244. offset += 4;
  245. break;
  246. case FT_BYTE:
  247. *((uint8*)(&dataTable[offset])) = getRecord(y).getUInt8(x);
  248. offset += 1;
  249. break;
  250. case FT_STRING:
  251. *((char**)(&dataTable[offset])) = NULL; // will be replaces non-empty or "" strings in AutoProduceStrings
  252. offset += sizeof(char*);
  253. break;
  254. }
  255. }
  256. }
  257. return dataTable;
  258. }
  259. static char const* const nullStr = "";
  260. char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* dataTable)
  261. {
  262. if (strlen(format) != fieldCount)
  263. return NULL;
  264. // we store flat holders pool as single memory block
  265. size_t stringFields = GetFormatStringsFields(format);
  266. // each string field at load have array of string for each locale
  267. size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES;
  268. size_t stringHoldersRecordPoolSize = stringFields * stringHolderSize;
  269. size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * recordCount;
  270. char* stringHoldersPool = new char[stringHoldersPoolSize];
  271. // DB2 strings expected to have at least empty string
  272. for (size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i)
  273. ((char const**)stringHoldersPool)[i] = nullStr;
  274. uint32 offset=0;
  275. // assign string holders to string field slots
  276. for (uint32 y = 0; y < recordCount; y++)
  277. {
  278. uint32 stringFieldNum = 0;
  279. for (uint32 x = 0; x < fieldCount; x++)
  280. switch (format[x])
  281. {
  282. case FT_FLOAT:
  283. case FT_IND:
  284. case FT_INT:
  285. offset += 4;
  286. break;
  287. case FT_BYTE:
  288. offset += 1;
  289. break;
  290. case FT_STRING:
  291. {
  292. // init db2 string field slots by pointers to string holders
  293. char const*** slot = (char const***)(&dataTable[offset]);
  294. *slot = (char const**)(&stringHoldersPool[stringHoldersRecordPoolSize * y + stringHolderSize*stringFieldNum]);
  295. ++stringFieldNum;
  296. offset += sizeof(char*);
  297. break;
  298. }
  299. case FT_NA:
  300. case FT_NA_BYTE:
  301. case FT_SORT:
  302. break;
  303. default:
  304. assert(false && "unknown format character");
  305. }
  306. }
  307. //send as char* for store in char* pool list for free at unload
  308. return stringHoldersPool;
  309. }
  310. char* DB2FileLoader::AutoProduceStrings(const char* format, char* dataTable, uint32 locale)
  311. {
  312. if (strlen(format) != fieldCount)
  313. return NULL;
  314. char* stringPool= new char[stringSize];
  315. memcpy(stringPool, stringTable, stringSize);
  316. uint32 offset = 0;
  317. for (uint32 y =0; y < recordCount; y++)
  318. {
  319. for (uint32 x = 0; x < fieldCount; x++)
  320. switch (format[x])
  321. {
  322. case FT_FLOAT:
  323. case FT_IND:
  324. case FT_INT:
  325. offset += 4;
  326. break;
  327. case FT_BYTE:
  328. offset += 1;
  329. break;
  330. case FT_STRING:
  331. {
  332. // fill only not filled entries
  333. LocalizedString* db2str = *(LocalizedString**)(&dataTable[offset]);
  334. if (db2str->Str[locale] == nullStr)
  335. {
  336. const char * st = getRecord(y).getString(x);
  337. db2str->Str[locale] = stringPool + (st - (const char*)stringTable);
  338. }
  339. offset += sizeof(char*);
  340. break;
  341. }
  342. }
  343. }
  344. return stringPool;
  345. }