PageRenderTime 42ms CodeModel.GetById 15ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

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