diff options
| author | Shauren <shauren.trinity@gmail.com> | 2016-05-27 23:13:47 +0200 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2016-05-27 23:14:36 +0200 |
| commit | b82332487afd7233850e7eed996615b3fdd7248c (patch) | |
| tree | 4f440c5643049ff69c2544560fd750629c7a5552 /src/server/shared | |
| parent | 31009887e35cf8db6e94bf5b6870b62538364bc4 (diff) | |
Core/DataStores: Updated db2 to 7.0.3.21737
Diffstat (limited to 'src/server/shared')
| -rw-r--r-- | src/server/shared/DataStores/DB2Meta.cpp | 101 | ||||
| -rw-r--r-- | src/server/shared/DataStores/DB2Meta.h | 46 | ||||
| -rw-r--r-- | src/server/shared/DataStores/DB2SparseStorageLoader.cpp | 529 | ||||
| -rw-r--r-- | src/server/shared/DataStores/DB2SparseStorageLoader.h | 39 | ||||
| -rw-r--r-- | src/server/shared/DataStores/DB2StorageLoader.cpp | 658 | ||||
| -rw-r--r-- | src/server/shared/DataStores/DB2StorageLoader.h | 142 | ||||
| -rw-r--r-- | src/server/shared/DataStores/DB2Store.h | 150 |
7 files changed, 912 insertions, 753 deletions
diff --git a/src/server/shared/DataStores/DB2Meta.cpp b/src/server/shared/DataStores/DB2Meta.cpp new file mode 100644 index 00000000000..66c18961551 --- /dev/null +++ b/src/server/shared/DataStores/DB2Meta.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "DB2Meta.h" + +DB2Meta::DB2Meta(int32 indexField, uint32 fieldCount, char const* types, uint8 const* arraySizes) + : IndexField(indexField), FieldCount(fieldCount), Types(types), ArraySizes(arraySizes) +{ +} + +bool DB2Meta::HasIndexFieldInData() const +{ + return IndexField != -1; +} + +uint32 DB2Meta::GetIndexField() const +{ + return IndexField == -1 ? 0 : uint32(IndexField); +} + +uint32 DB2Meta::GetRecordSize() const +{ + uint32 size = 0; + for (uint32 i = 0; i < FieldCount; ++i) + { + for (uint8 j = 0; j < ArraySizes[i]; ++j) + { + switch (Types[i]) + { + case FT_BYTE: + size += 1; + break; + case FT_SHORT: + size += 2; + break; + case FT_FLOAT: + case FT_INT: + size += 4; + break; + case FT_STRING: + case FT_STRING_NOT_LOCALIZED: + size += sizeof(char*); + break; + } + } + } + + if (!HasIndexFieldInData()) + size += 4; + + return size; +} + +uint32 DB2Meta::GetDbIndexField() const +{ + if (IndexField == -1) + return 0; + + uint32 index = 0; + for (uint32 i = 0; i < FieldCount && i < uint32(IndexField); ++i) + index += ArraySizes[i]; + + return index; +} + +uint32 DB2Meta::GetDbFieldCount() const +{ + uint32 fields = 0; + for (uint32 i = 0; i < FieldCount; ++i) + fields += ArraySizes[i]; + + if (!HasIndexFieldInData()) + ++fields; + + return fields; +} + +uint32 DB2Meta::GetStringFieldCount(bool localizedOnly) const +{ + uint32 stringFields = 0; + for (uint32 i = 0; i < FieldCount; ++i) + if (Types[i] == FT_STRING || (Types[i] == FT_STRING_NOT_LOCALIZED && !localizedOnly)) + for (uint8 j = 0; j < ArraySizes[i]; ++j) + ++stringFields; + + return stringFields; +} diff --git a/src/server/shared/DataStores/DB2Meta.h b/src/server/shared/DataStores/DB2Meta.h new file mode 100644 index 00000000000..adfdfea37fb --- /dev/null +++ b/src/server/shared/DataStores/DB2Meta.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef DB2Meta_h__ +#define DB2Meta_h__ + +#include "Define.h" + +struct DB2Meta +{ + DB2Meta(int32 indexField, uint32 fieldCount, char const* types, uint8 const* arraySizes); + + bool HasIndexFieldInData() const; + + // Returns field index for data loaded in our structures (ID field is appended in the front if not present in db2 file data section) + uint32 GetIndexField() const; + + // Returns size of final loaded structure + uint32 GetRecordSize() const; + + uint32 GetDbIndexField() const; + uint32 GetDbFieldCount() const; + + uint32 GetStringFieldCount(bool localizedOnly) const; + + int32 IndexField; + uint32 FieldCount; + char const* Types; + uint8 const* ArraySizes; +}; + +#endif // DB2Meta_h__ diff --git a/src/server/shared/DataStores/DB2SparseStorageLoader.cpp b/src/server/shared/DataStores/DB2SparseStorageLoader.cpp index 2d5c11b9d5d..721ce6d8813 100644 --- a/src/server/shared/DataStores/DB2SparseStorageLoader.cpp +++ b/src/server/shared/DataStores/DB2SparseStorageLoader.cpp @@ -23,14 +23,14 @@ DB2SparseFileLoader::DB2SparseFileLoader() { fileName = nullptr; + meta = nullptr; recordCount = 0; fieldCount = 0; recordSize = 0; offsetsPos = 0; tableHash = 0; - build = 0; - unk1 = 0; + layoutHash = 0; minIndex = 0; maxIndex = 0; localeMask = 0; @@ -39,9 +39,10 @@ DB2SparseFileLoader::DB2SparseFileLoader() dataStart = 0; data = nullptr; offsets = nullptr; + fields = nullptr; } -bool DB2SparseFileLoader::Load(const char *filename) +bool DB2SparseFileLoader::Load(const char *filename, DB2Meta const* meta) { if (data) { @@ -54,6 +55,7 @@ bool DB2SparseFileLoader::Load(const char *filename) return false; fileName = filename; + this->meta = meta; uint32 header; if (fread(&header, 4, 1, f) != 1) // Signature { @@ -63,10 +65,10 @@ bool DB2SparseFileLoader::Load(const char *filename) EndianConvert(header); - if (header != 0x34424457) + if (header != 0x35424457) { fclose(f); - return false; //'WDB4' + return false; //'WDB5' } if (fread(&recordCount, 4, 1, f) != 1) // Number of records @@ -109,21 +111,13 @@ bool DB2SparseFileLoader::Load(const char *filename) EndianConvert(tableHash); - if (fread(&build, 4, 1, f) != 1) // Build + if (fread(&layoutHash, 4, 1, f) != 1) // Layout hash { fclose(f); return false; } - EndianConvert(build); - - if (fread(&unk1, 4, 1, f) != 1) // Unknown WDB2 - { - fclose(f); - return false; - } - - EndianConvert(unk1); + EndianConvert(layoutHash); if (fread(&minIndex, 4, 1, f) != 1) // MinIndex WDB2 { @@ -165,6 +159,13 @@ bool DB2SparseFileLoader::Load(const char *filename) EndianConvert(metaFlags); + fields = new FieldEntry[fieldCount]; + if (fread(fields, fieldCount * sizeof(FieldEntry), 1, f) != 1) + { + fclose(f); + return false; + } + dataStart = ftell(f); data = new unsigned char[offsetsPos - dataStart]; @@ -190,69 +191,19 @@ DB2SparseFileLoader::~DB2SparseFileLoader() { delete[] data; delete[] offsets; -} - -uint32 DB2SparseFileLoader::GetFormatRecordSize(const char * format) -{ - uint32 recordsize = 0; - for (uint32 x = 0; format[x]; ++x) - { - switch (format[x]) - { - case FT_FLOAT: - case FT_INT: - case FT_SORT: - recordsize += 4; - break; - case FT_STRING: - case FT_STRING_NOT_LOCALIZED: - recordsize += sizeof(char*); - break; - case FT_BYTE: - recordsize += 1; - break; - case FT_LONG: - recordsize += 8; - break; - case FT_SHORT: - recordsize += 2; - break; - } - } - - return recordsize; -} - -uint32 DB2SparseFileLoader::GetFormatStringFieldCount(const char* format) -{ - uint32 stringfields = 0; - for (uint32 x = 0; format[x]; ++x) - if (format[x] == FT_STRING || format[x] == FT_STRING_NOT_LOCALIZED) - ++stringfields; - - return stringfields; -} - -uint32 DB2SparseFileLoader::GetFormatLocalizedStringFieldCount(char const* format) -{ - uint32 stringfields = 0; - for (uint32 x = 0; format[x]; ++x) - if (format[x] == FT_STRING) - ++stringfields; - - return stringfields; + delete[] fields; } static char const* const nullStr = ""; -char* DB2SparseFileLoader::AutoProduceData(const char* format, IndexTable const& indexTable, uint32 locale, std::vector<char*>& stringPool) +char* DB2SparseFileLoader::AutoProduceData(IndexTable const& indexTable, uint32 locale, std::vector<char*>& stringPool) { typedef char* ptr; - if (strlen(format) != fieldCount + (format[0] == FT_SORT ? 1 : 0)) + if (meta->FieldCount != fieldCount) return NULL; //get struct size and index pos - uint32 recordsize = GetFormatRecordSize(format); + uint32 recordsize = meta->GetRecordSize(); uint32 offsetCount = maxIndex - minIndex + 1; uint32 records = 0; @@ -269,12 +220,11 @@ char* DB2SparseFileLoader::AutoProduceData(const char* format, IndexTable const& char* dataTable = new char[records * recordsize]; // we store flat holders pool as single memory block - std::size_t stringFields = GetFormatStringFieldCount(format); - std::size_t localizedStringFields = GetFormatLocalizedStringFieldCount(format); + std::size_t stringFields = meta->GetStringFieldCount(false); + std::size_t localizedStringFields = meta->GetStringFieldCount(true); // each string field at load have array of string for each locale - std::size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES; - std::size_t stringHoldersRecordPoolSize = localizedStringFields * stringHolderSize + (stringFields - localizedStringFields) * sizeof(char*); + std::size_t stringHoldersRecordPoolSize = localizedStringFields * sizeof(LocalizedString) + (stringFields - localizedStringFields) * sizeof(char*); std::size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * records; char* stringHoldersPool = new char[stringHoldersPoolSize]; @@ -284,8 +234,8 @@ char* DB2SparseFileLoader::AutoProduceData(const char* format, IndexTable const& for (std::size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i) ((char const**)stringHoldersPool)[i] = nullStr; - char* stringTable = new char[expandedDataSize - records * ((recordsize - (format[0] == FT_SORT ? 4 : 0)) - stringFields * sizeof(char*))]; - memset(stringTable, 0, expandedDataSize - records * ((recordsize - (format[0] == FT_SORT ? 4 : 0)) - stringFields * sizeof(char*))); + char* stringTable = new char[expandedDataSize - records * ((recordsize - (!meta->HasIndexFieldInData() ? 4 : 0)) - stringFields * sizeof(char*))]; + memset(stringTable, 0, expandedDataSize - records * ((recordsize - (!meta->HasIndexFieldInData() ? 4 : 0)) - stringFields * sizeof(char*))); stringPool.push_back(stringTable); char* stringPtr = stringTable; @@ -299,64 +249,113 @@ char* DB2SparseFileLoader::AutoProduceData(const char* format, IndexTable const& indexTable.Insert(y + minIndex, &dataTable[offset]); uint32 fieldOffset = 0; uint32 stringFieldOffset = 0; - for (uint32 x = 0; x < (fieldCount + (format[0] == FT_SORT ? 1 : 0)); x++) + + if (!meta->HasIndexFieldInData()) + { + *((uint32*)(&dataTable[offset])) = y + minIndex; + offset += 4; + } + + for (uint32 x = 0; x < fieldCount; ++x) { - switch (format[x]) + uint16 fieldBytes = 4 - fields[x].UnusedBits / 8; + for (uint32 z = 0; z < meta->ArraySizes[x]; ++z) { - case FT_FLOAT: - *((float*)(&dataTable[offset])) = *reinterpret_cast<float*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]); - offset += 4; - fieldOffset += 4; - break; - case FT_IND: - case FT_INT: - *((uint32*)(&dataTable[offset])) = *reinterpret_cast<uint32*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]); - offset += 4; - fieldOffset += 4; - break; - case FT_BYTE: - *((uint8*)(&dataTable[offset])) = *reinterpret_cast<uint8*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]); - offset += 1; - fieldOffset += 1; - break; - case FT_LONG: - *((uint64*)(&dataTable[offset])) = *reinterpret_cast<uint64*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]); - offset += 8; - fieldOffset += 8; - break; - case FT_SHORT: - *((uint16*)(&dataTable[offset])) = *reinterpret_cast<uint16*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]); - offset += 2; - fieldOffset += 2; - break; - case FT_STRING: - { - LocalizedString** slot = (LocalizedString**)(&dataTable[offset]); - *slot = (LocalizedString*)(&stringHoldersPool[stringHoldersRecordPoolSize * recordNum + stringFieldOffset]); - (*slot)->Str[locale] = stringPtr; - strcpy(stringPtr, (char*)&data[offsets[y].FileOffset - dataStart + fieldOffset]); - fieldOffset += strlen(stringPtr) + 1; - stringPtr += strlen(stringPtr) + 1; - stringFieldOffset += stringHolderSize; - offset += sizeof(LocalizedString*); - break; - } - case FT_STRING_NOT_LOCALIZED: + switch (meta->Types[x]) { - char const*** slot = (char const***)(&dataTable[offset]); - *slot = (char const**)(&stringHoldersPool[stringHoldersRecordPoolSize * recordNum + stringFieldOffset]); - **slot = stringPtr; - strcpy(stringPtr, (char*)&data[offsets[y].FileOffset - dataStart + fieldOffset]); - fieldOffset += strlen(stringPtr) + 1; - stringPtr += strlen(stringPtr) + 1; - ++stringFieldOffset; - offset += sizeof(char*); - break; + case FT_FLOAT: + { + float val = *reinterpret_cast<float*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]); + EndianConvert(val); + *((float*)(&dataTable[offset])) = val; + offset += 4; + fieldOffset += 4; + break; + } + case FT_INT: + { + ASSERT(fieldBytes && fieldBytes <= 4); + uint32 val; + switch (fieldBytes) + { + case 1: + val = *reinterpret_cast<uint8*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]); + break; + case 2: + { + uint16 val16 = *reinterpret_cast<uint16*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]); + EndianConvert(val16); + val = val16; + break; + } + case 3: + { +#pragma pack(push, 1) + struct dbcint24 { uint8 v[3]; }; +#pragma pack(pop) + dbcint24 i24v = *reinterpret_cast<dbcint24*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]); + EndianConvert(i24v); + val = uint32(i24v.v[0]) | (uint32(i24v.v[1]) << 8) | (uint32(i24v.v[2]) << 16); + break; + } + case 4: + val = *reinterpret_cast<uint32*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]); + EndianConvert(val); + break; + default: + break; + } + *((uint32*)(&dataTable[offset])) = val; + offset += 4; + fieldOffset += fieldBytes; + break; + } + case FT_BYTE: + { + ASSERT(fieldBytes == 1); + *((uint8*)(&dataTable[offset])) = *reinterpret_cast<uint8*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]); + offset += 1; + fieldOffset += 1; + break; + } + case FT_SHORT: + { + ASSERT(fieldBytes == 2); + uint16 val = *reinterpret_cast<uint16*>(&data[offsets[y].FileOffset - dataStart + fieldOffset]); + EndianConvert(val); + *((uint16*)(&dataTable[offset])) = val; + offset += 2; + fieldOffset += 2; + break; + } + case FT_STRING: + { + LocalizedString** slot = (LocalizedString**)(&dataTable[offset]); + *slot = (LocalizedString*)(&stringHoldersPool[stringHoldersRecordPoolSize * recordNum + stringFieldOffset]); + (*slot)->Str[locale] = stringPtr; + strcpy(stringPtr, (char*)&data[offsets[y].FileOffset - dataStart + fieldOffset]); + fieldOffset += strlen(stringPtr) + 1; + stringPtr += strlen(stringPtr) + 1; + stringFieldOffset += sizeof(LocalizedString); + offset += sizeof(LocalizedString*); + break; + } + case FT_STRING_NOT_LOCALIZED: + { + char const*** slot = (char const***)(&dataTable[offset]); + *slot = (char const**)(&stringHoldersPool[stringHoldersRecordPoolSize * recordNum + stringFieldOffset]); + **slot = stringPtr; + strcpy(stringPtr, (char*)&data[offsets[y].FileOffset - dataStart + fieldOffset]); + fieldOffset += strlen(stringPtr) + 1; + stringPtr += strlen(stringPtr) + 1; + stringFieldOffset += sizeof(char*); + offset += sizeof(char*); + break; + } + default: + ASSERT(false, "Unknown format character '%c' found in %s meta", meta->Types[x], fileName); + break; } - case FT_SORT: - *((uint32*)(&dataTable[offset])) = y + minIndex; - offset += 4; - break; } } @@ -366,9 +365,9 @@ char* DB2SparseFileLoader::AutoProduceData(const char* format, IndexTable const& return dataTable; } -char* DB2SparseFileLoader::AutoProduceStrings(const char* format, char* dataTable, uint32 locale) +char* DB2SparseFileLoader::AutoProduceStrings(char* dataTable, uint32 locale) { - if (strlen(format) != fieldCount + (format[0] == FT_SORT ? 1 : 0)) + if (meta->FieldCount != fieldCount) return nullptr; if (!(localeMask & (1 << locale))) @@ -394,10 +393,10 @@ char* DB2SparseFileLoader::AutoProduceStrings(const char* format, char* dataTabl if (offsets[i].FileOffset && offsets[i].RecordSize) ++records; - uint32 recordsize = GetFormatRecordSize(format); - std::size_t stringFields = GetFormatLocalizedStringFieldCount(format); - char* stringTable = new char[offsetsPos - dataStart - records * (recordsize - stringFields * sizeof(char*))]; - memset(stringTable, 0, offsetsPos - dataStart - records * (recordsize - stringFields * sizeof(char*))); + uint32 recordsize = meta->GetRecordSize(); + std::size_t stringFields = meta->GetStringFieldCount(true); + char* stringTable = new char[offsetsPos - dataStart - records * ((recordsize - (!meta->HasIndexFieldInData() ? 4 : 0)) - stringFields * sizeof(char*))]; + memset(stringTable, 0, offsetsPos - dataStart - records * ((recordsize - (!meta->HasIndexFieldInData() ? 4 : 0)) - stringFields * sizeof(char*))); char* stringPtr = stringTable; uint32 offset = 0; @@ -407,44 +406,51 @@ char* DB2SparseFileLoader::AutoProduceStrings(const char* format, char* dataTabl if (!offsets[y].FileOffset || !offsets[y].RecordSize) continue; + if (!meta->HasIndexFieldInData()) + offset += 4; + uint32 fieldOffset = 0; - for (uint32 x = 0; x < fieldCount; x++) + for (uint32 x = 0; x < fieldCount; ++x) { - switch (format[x]) + for (uint32 z = 0; z < meta->ArraySizes[x]; ++z) { - case FT_FLOAT: - case FT_IND: - case FT_INT: - offset += 4; - fieldOffset += 4; - break; - case FT_BYTE: - offset += 1; - fieldOffset += 1; - break; - case FT_LONG: - offset += 8; - fieldOffset += 8; - break; - case FT_SHORT: - offset += 2; - fieldOffset += 2; - break; - case FT_STRING: - { - LocalizedString* db2str = *(LocalizedString**)(&dataTable[offset]); - db2str->Str[locale] = stringPtr; - strcpy(stringPtr, (char*)&data[offsets[y].FileOffset - dataStart + fieldOffset]); - fieldOffset += strlen(stringPtr) + 1; - stringPtr += strlen(stringPtr) + 1; - offset += sizeof(char*); - break; - } - case FT_STRING_NOT_LOCALIZED: + switch (meta->Types[x]) { - fieldOffset += strlen((char*)&data[offsets[y].FileOffset - dataStart + fieldOffset]) + 1; - offset += sizeof(char*); - break; + case FT_FLOAT: + offset += 4; + fieldOffset += 4; + break; + case FT_INT: + offset += 4; + fieldOffset += 4 - fields[x].UnusedBits / 8; + break; + case FT_BYTE: + offset += 1; + fieldOffset += 1; + break; + case FT_SHORT: + offset += 2; + fieldOffset += 2; + break; + case FT_STRING: + { + LocalizedString* db2str = *(LocalizedString**)(&dataTable[offset]); + db2str->Str[locale] = stringPtr; + strcpy(stringPtr, (char*)&data[offsets[y].FileOffset - dataStart + fieldOffset]); + fieldOffset += strlen(stringPtr) + 1; + stringPtr += strlen(stringPtr) + 1; + offset += sizeof(char*); + break; + } + case FT_STRING_NOT_LOCALIZED: + { + fieldOffset += strlen((char*)&data[offsets[y].FileOffset - dataStart + fieldOffset]) + 1; + offset += sizeof(char*); + break; + } + default: + ASSERT(false, "Unknown format character '%c' found in %s meta", meta->Types[x], fileName); + break; } } } @@ -453,27 +459,26 @@ char* DB2SparseFileLoader::AutoProduceStrings(const char* format, char* dataTabl return stringTable; } -char* DB2SparseDatabaseLoader::Load(const char* format, HotfixDatabaseStatements preparedStatement, IndexTable const& indexTable, std::vector<char*>& stringPool) +char* DB2SparseDatabaseLoader::Load(HotfixDatabaseStatements preparedStatement, IndexTable const& indexTable, std::vector<char*>& stringPool) { // Even though this query is executed only once, prepared statement is used to send data from mysql server in binary format PreparedQueryResult result = HotfixDatabase.Query(HotfixDatabase.GetPreparedStatement(preparedStatement)); if (!result) return nullptr; - uint32 const fieldCount = strlen(format); - if (fieldCount != result->GetFieldCount()) + if (_meta->GetDbFieldCount() != result->GetFieldCount()) return nullptr; // get struct size and index pos - uint32 recordSize = DB2SparseFileLoader::GetFormatRecordSize(format); + uint32 indexField = _meta->GetDbIndexField(); + uint32 recordSize = _meta->GetRecordSize(); // we store flat holders pool as single memory block - std::size_t stringFields = DB2SparseFileLoader::GetFormatStringFieldCount(format); - std::size_t localizedStringFields = DB2SparseFileLoader::GetFormatLocalizedStringFieldCount(format); + std::size_t stringFields = _meta->GetStringFieldCount(false); + std::size_t localizedStringFields = _meta->GetStringFieldCount(true); // each string field at load have array of string for each locale - std::size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES; - std::size_t stringHoldersRecordPoolSize = localizedStringFields * stringHolderSize + (stringFields - localizedStringFields) * sizeof(char*); + std::size_t stringHoldersRecordPoolSize = localizedStringFields * sizeof(LocalizedString) + (stringFields - localizedStringFields) * sizeof(char*); char* stringHolders = nullptr; if (stringFields) @@ -498,7 +503,7 @@ char* DB2SparseDatabaseLoader::Load(const char* format, HotfixDatabaseStatements uint32 offset = 0; uint32 stringFieldOffset = 0; - uint32 indexValue = fields[0].GetUInt32(); + uint32 indexValue = fields[indexField].GetUInt32(); // Attempt to overwrite existing data char* dataValue = indexTable.Get(indexValue); @@ -508,60 +513,69 @@ char* DB2SparseDatabaseLoader::Load(const char* format, HotfixDatabaseStatements dataValue = &tempDataTable[newRecords++ * recordSize]; } - for (uint32 f = 0; f < fieldCount; f++) + uint32 f = 0; + if (!_meta->HasIndexFieldInData()) + { + *((uint32*)(&dataValue[offset])) = indexValue; + offset += 4; + ++f; + } + + for (uint32 x = 0; x < _meta->FieldCount; ++x) { - switch (format[f]) + for (uint32 z = 0; z < _meta->ArraySizes[x]; ++z) { - case FT_FLOAT: - *((float*)(&dataValue[offset])) = fields[f].GetFloat(); - offset += 4; - break; - case FT_IND: - case FT_INT: - case FT_SORT: - *((int32*)(&dataValue[offset])) = fields[f].GetInt32(); - offset += 4; - break; - case FT_BYTE: - *((int8*)(&dataValue[offset])) = fields[f].GetInt8(); - offset += 1; - break; - case FT_LONG: - *((int64*)(&dataValue[offset])) = fields[f].GetInt64(); - offset += 8; - break; - case FT_SHORT: - *((int16*)(&dataValue[offset])) = fields[f].GetInt16(); - offset += 2; - break; - case FT_STRING: + switch (_meta->Types[x]) { - LocalizedString** slot = (LocalizedString**)(&dataValue[offset]); - *slot = (LocalizedString*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringFieldOffset]); - ASSERT(*slot); + case FT_FLOAT: + *((float*)(&dataValue[offset])) = fields[f].GetFloat(); + offset += 4; + break; + case FT_INT: + *((int32*)(&dataValue[offset])) = fields[f].GetInt32(); + offset += 4; + break; + case FT_BYTE: + *((int8*)(&dataValue[offset])) = fields[f].GetInt8(); + offset += 1; + break; + case FT_SHORT: + *((int16*)(&dataValue[offset])) = fields[f].GetInt16(); + offset += 2; + break; + case FT_STRING: + { + LocalizedString** slot = (LocalizedString**)(&dataValue[offset]); + *slot = (LocalizedString*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringFieldOffset]); + ASSERT(*slot); - // Value in database in main table field must be for enUS locale - if (char* str = AddString(&(*slot)->Str[LOCALE_enUS], fields[f].GetString())) - stringPool.push_back(str); + // Value in database in main table field must be for enUS locale + if (char* str = AddString(&(*slot)->Str[LOCALE_enUS], fields[f].GetString())) + stringPool.push_back(str); - stringFieldOffset += stringHolderSize; - offset += sizeof(char*); - break; - } - case FT_STRING_NOT_LOCALIZED: - { - char const** slot = (char const**)(&dataValue[offset]); - *slot = (char*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringFieldOffset]); - ASSERT(*slot); + stringFieldOffset += sizeof(LocalizedString); + offset += sizeof(char*); + break; + } + case FT_STRING_NOT_LOCALIZED: + { + char const** slot = (char const**)(&dataValue[offset]); + *slot = (char*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringFieldOffset]); + ASSERT(*slot); - // Value in database in main table field must be for enUS locale - if (char* str = AddString(slot, fields[f].GetString())) - stringPool.push_back(str); + // Value in database in main table field must be for enUS locale + if (char* str = AddString(slot, fields[f].GetString())) + stringPool.push_back(str); - ++stringFieldOffset; - offset += sizeof(char*); - break; + stringFieldOffset += sizeof(char*); + offset += sizeof(char*); + break; + } + default: + ASSERT(false, "Unknown format character '%c' found in %s meta", _meta->Types[x], _storageName.c_str()); + break; } + ++f; } } @@ -590,7 +604,7 @@ char* DB2SparseDatabaseLoader::Load(const char* format, HotfixDatabaseStatements return dataTable; } -void DB2SparseDatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStatements preparedStatement, uint32 locale, IndexTable const& indexTable, std::vector<char*>& stringPool) +void DB2SparseDatabaseLoader::LoadStrings(HotfixDatabaseStatements preparedStatement, uint32 locale, IndexTable const& indexTable, std::vector<char*>& stringPool) { PreparedStatement* stmt = HotfixDatabase.GetPreparedStatement(preparedStatement); stmt->setString(0, localeNames[locale]); @@ -598,13 +612,12 @@ void DB2SparseDatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStat if (!result) return; - size_t stringFields = DB2SparseFileLoader::GetFormatLocalizedStringFieldCount(format); + size_t stringFields = _meta->GetStringFieldCount(true); if (result->GetFieldCount() != stringFields + 1 /*ID*/) return; - uint32 const fieldCount = strlen(format); - uint32 recordSize = DB2SparseFileLoader::GetFormatRecordSize(format); - ASSERT(0 >= 0, "DB2Storage must be indexed to load localized strings"); + uint32 fieldCount = _meta->FieldCount; + uint32 recordSize = _meta->GetRecordSize(); do { @@ -616,36 +629,40 @@ void DB2SparseDatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStat // Attempt to overwrite existing data if (char* dataValue = indexTable.Get(indexValue)) { - for (uint32 x = 0; x < fieldCount; x++) + if (!_meta->HasIndexFieldInData()) + offset += 4; + + for (uint32 x = 0; x < fieldCount; ++x) { - switch (format[x]) + for (uint32 z = 0; z < _meta->ArraySizes[x]; ++z) { - case FT_FLOAT: - case FT_IND: - case FT_INT: - case FT_SORT: - offset += 4; - break; - case FT_BYTE: - offset += 1; - break; - case FT_LONG: - offset += 8; - break; - case FT_SHORT: - offset += 2; - break; - case FT_STRING: + switch (_meta->Types[x]) { - // fill only not filled entries - LocalizedString* db2str = *(LocalizedString**)(&dataValue[offset]); - if (db2str->Str[locale] == nullStr) - if (char* str = AddString(&db2str->Str[locale], fields[1 + stringFieldNumInRecord].GetString())) - stringPool.push_back(str); - - ++stringFieldNumInRecord; - offset += sizeof(char*); - break; + case FT_FLOAT: + case FT_INT: + offset += 4; + break; + case FT_BYTE: + offset += 1; + break; + case FT_SHORT: + offset += 2; + break; + case FT_STRING: + { + // fill only not filled entries + LocalizedString* db2str = *(LocalizedString**)(&dataValue[offset]); + if (db2str->Str[locale] == nullStr) + if (char* str = AddString(&db2str->Str[locale], fields[1 + stringFieldNumInRecord].GetString())) + stringPool.push_back(str); + + ++stringFieldNumInRecord; + offset += sizeof(char*); + break; + } + default: + ASSERT(false, "Unknown format character '%c' found in %s meta", _meta->Types[x], _storageName.c_str()); + break; } } } diff --git a/src/server/shared/DataStores/DB2SparseStorageLoader.h b/src/server/shared/DataStores/DB2SparseStorageLoader.h index ac75e6b82d5..0936947ea6a 100644 --- a/src/server/shared/DataStores/DB2SparseStorageLoader.h +++ b/src/server/shared/DataStores/DB2SparseStorageLoader.h @@ -18,13 +18,13 @@ #ifndef DB2_SPARSE_FILE_LOADER_H #define DB2_SPARSE_FILE_LOADER_H -#include "Define.h" +#include "DB2Meta.h" #include "Utilities/ByteConverter.h" #include "Implementation/HotfixDatabase.h" #include <unordered_map> #include <vector> -class IndexTable +class TC_SHARED_API IndexTable { public: virtual void Insert(uint32 index, char* data) const = 0; @@ -54,24 +54,22 @@ private: std::unordered_map<uint32, T const*>& _indexTable; }; -class DB2SparseFileLoader +class TC_SHARED_API DB2SparseFileLoader { public: DB2SparseFileLoader(); ~DB2SparseFileLoader(); - bool Load(const char *filename); + bool Load(char const* filename, DB2Meta const* meta); uint32 GetNumRows() const { return recordCount; } uint32 GetCols() const { return fieldCount; } - uint32 GetHash() const { return tableHash; } - uint32 GetBuild() const { return build; } + uint32 GetTableHash() const { return tableHash; } + uint32 GetLayoutHash() const { return layoutHash; } bool IsLoaded() const { return (data != NULL); } - char* AutoProduceData(const char* fmt, IndexTable const& indexTable, uint32 locale, std::vector<char*>& stringPool); - char* AutoProduceStrings(const char* fmt, char* dataTable, uint32 locale); - static uint32 GetFormatRecordSize(const char * format); - static uint32 GetFormatStringFieldCount(const char * format); - static uint32 GetFormatLocalizedStringFieldCount(const char * format); + char* AutoProduceData(IndexTable const& indexTable, uint32 locale, std::vector<char*>& stringPool); + char* AutoProduceStrings(char* dataTable, uint32 locale); + private: #pragma pack(push, 1) struct OffsetTableEntry @@ -79,9 +77,15 @@ private: uint32 FileOffset; uint16 RecordSize; }; + struct FieldEntry + { + uint16 UnusedBits; + uint16 Offset; + }; #pragma pack(pop) char const* fileName; + DB2Meta const* meta; // WDB2 / WCH2 fields uint32 recordSize; @@ -89,30 +93,31 @@ private: uint32 fieldCount; uint32 offsetsPos; uint32 tableHash; - uint32 build; - uint32 unk1; + uint32 layoutHash; uint32 minIndex; uint32 maxIndex; uint32 localeMask; uint32 copyIdSize; uint32 metaFlags; + FieldEntry* fields; uint32 dataStart; unsigned char* data; OffsetTableEntry* offsets; }; -class DB2SparseDatabaseLoader +class TC_SHARED_API DB2SparseDatabaseLoader { public: - explicit DB2SparseDatabaseLoader(std::string const& storageName) : _storageName(storageName) { } + DB2SparseDatabaseLoader(std::string const& storageName, DB2Meta const* meta) : _storageName(storageName), _meta(meta) { } - char* Load(const char* format, HotfixDatabaseStatements preparedStatement, IndexTable const& indexTable, std::vector<char*>& stringPool); - void LoadStrings(const char* format, HotfixDatabaseStatements preparedStatement, uint32 locale, IndexTable const& indexTable, std::vector<char*>& stringPool); + char* Load(HotfixDatabaseStatements preparedStatement, IndexTable const& indexTable, std::vector<char*>& stringPool); + void LoadStrings(HotfixDatabaseStatements preparedStatement, uint32 locale, IndexTable const& indexTable, std::vector<char*>& stringPool); static char* AddString(char const** holder, std::string const& value); private: std::string _storageName; + DB2Meta const* _meta; }; #endif diff --git a/src/server/shared/DataStores/DB2StorageLoader.cpp b/src/server/shared/DataStores/DB2StorageLoader.cpp index 56a8dbbed65..0f45b75c8d6 100644 --- a/src/server/shared/DataStores/DB2StorageLoader.cpp +++ b/src/server/shared/DataStores/DB2StorageLoader.cpp @@ -23,28 +23,28 @@ DB2FileLoader::DB2FileLoader() { fileName = nullptr; + meta = nullptr; recordSize = 0; recordCount = 0; fieldCount = 0; stringSize = 0; tableHash = 0; - build = 0; - unk1 = 0; + layoutHash = 0; minIndex = 0; maxIndex = 0; localeMask = 0; copyIdSize = 0; - fieldsOffset = nullptr; data = nullptr; stringTable = nullptr; idTable = nullptr; idTableSize = 0; copyTable = nullptr; + fields = nullptr; } -bool DB2FileLoader::Load(const char *filename, const char *fmt) +bool DB2FileLoader::Load(char const* filename, DB2Meta const* meta) { if (data) { @@ -57,6 +57,7 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt) return false; fileName = filename; + this->meta = meta; uint32 header; if (fread(&header, 4, 1, f) != 1) // Signature { @@ -66,10 +67,10 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt) EndianConvert(header); - if (header != 0x34424457) + if (header != 0x35424457) { fclose(f); - return false; //'WDB4' + return false; //'WDB5' } if (fread(&recordCount, 4, 1, f) != 1) // Number of records @@ -112,21 +113,13 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt) EndianConvert(tableHash); - if (fread(&build, 4, 1, f) != 1) // Build + if (fread(&layoutHash, 4, 1, f) != 1) // Build { fclose(f); return false; } - EndianConvert(build); - - if (fread(&unk1, 4, 1, f) != 1) // Unknown WDB2 - { - fclose(f); - return false; - } - - EndianConvert(unk1); + EndianConvert(layoutHash); if (fread(&minIndex, 4, 1, f) != 1) // MinIndex WDB2 { @@ -168,26 +161,17 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt) EndianConvert(metaFlags); - if (fmt[0] == FT_SORT) + ASSERT((meta->IndexField == -1) || (meta->IndexField == (metaFlags >> 16))); + + fields = new FieldEntry[fieldCount]; + if (fread(fields, fieldCount * sizeof(FieldEntry), 1, f) != 1) { - idTableSize = recordCount * sizeof(uint32); - ++fmt; + fclose(f); + return false; } - fieldsOffset = new uint32[fieldCount]; - fieldsOffset[0] = 0; - for (uint32 i = 1; i < fieldCount; i++) - { - fieldsOffset[i] = fieldsOffset[i - 1]; - if (fmt[i - 1] == FT_BYTE) // byte fields - fieldsOffset[i] += 1; - else if (fmt[i - 1] == FT_LONG) - fieldsOffset[i] += 8; - else if (fmt[i - 1] == FT_SHORT) - fieldsOffset[i] += 2; - else // 4 byte fields (int32/float/strings) - fieldsOffset[i] += 4; - } + if (!meta->HasIndexFieldInData()) + idTableSize = recordCount * sizeof(uint32); data = new unsigned char[recordSize * recordCount + stringSize]; stringTable = data + recordSize * recordCount; @@ -227,7 +211,7 @@ DB2FileLoader::~DB2FileLoader() delete[] data; delete[] idTable; delete[] copyTable; - delete[] fieldsOffset; + delete[] fields; } DB2FileLoader::Record DB2FileLoader::getRecord(size_t id) @@ -236,181 +220,98 @@ DB2FileLoader::Record DB2FileLoader::getRecord(size_t id) return Record(*this, data + id * recordSize); } -uint32 DB2FileLoader::GetFormatRecordSize(const char * format, int32* index_pos) -{ - uint32 recordsize = 0; - int32 i = -1; - for (uint32 x = 0; format[x]; ++x) - { - switch (format[x]) - { - case FT_FLOAT: - case FT_INT: - recordsize += 4; - break; - case FT_STRING: - case FT_STRING_NOT_LOCALIZED: - recordsize += sizeof(char*); - break; - case FT_SORT: - case FT_IND: - i = x; - recordsize += 4; - break; - case FT_BYTE: - recordsize += 1; - break; - case FT_LONG: - recordsize += 8; - break; - case FT_SHORT: - recordsize += 2; - break; - } - } - - if (index_pos) - *index_pos = i; - - return recordsize; -} - -uint32 DB2FileLoader::GetFormatStringFieldCount(const char* format) -{ - uint32 stringfields = 0; - for (uint32 x = 0; format[x]; ++x) - if (format[x] == FT_STRING || format[x] == FT_STRING_NOT_LOCALIZED) - ++stringfields; - - return stringfields; -} - -uint32 DB2FileLoader::GetFormatLocalizedStringFieldCount(char const* format) -{ - uint32 stringfields = 0; - for (uint32 x = 0; format[x]; ++x) - if (format[x] == FT_STRING) - ++stringfields; - - return stringfields; -} - -char* DB2FileLoader::AutoProduceData(const char* format, uint32& records, char**& indexTable) +char* DB2FileLoader::AutoProduceData(uint32& records, char**& indexTable) { typedef char* ptr; - if (strlen(format) != fieldCount + (format[0] == FT_SORT ? 1 : 0)) + if (meta->FieldCount != fieldCount) return NULL; //get struct size and index pos - int32 indexField; - uint32 recordsize = GetFormatRecordSize(format, &indexField); + uint32 indexField = meta->GetIndexField(); + uint32 recordsize = meta->GetRecordSize(); - if (indexField >= 0) + uint32 maxi = 0; + //find max index + if (!idTableSize) { - uint32 maxi = 0; - //find max index - if (!idTableSize) - { - for (uint32 y = 0; y < recordCount; ++y) - { - uint32 ind = getRecord(y).getUInt(indexField); - if (ind > maxi) - maxi = ind; - } - } - else + for (uint32 y = 0; y < recordCount; ++y) { - for (uint32 y = 0; y < recordCount; ++y) - { - uint32 ind = ((uint32*)idTable)[y]; - if (ind > maxi) - maxi = ind; - } + uint32 ind = getRecord(y).getUInt(indexField, 0); + if (ind > maxi) + maxi = ind; } - for (uint32 y = 0; y < copyIdSize; y += 8) + } + else + { + for (uint32 y = 0; y < recordCount; ++y) { - uint32 ind = *((uint32*)(copyTable + y)); + uint32 ind = ((uint32*)idTable)[y]; if (ind > maxi) maxi = ind; } - - ++maxi; - records = maxi; - indexTable = new ptr[maxi]; - memset(indexTable, 0, maxi * sizeof(ptr)); } - else + + for (uint32 y = 0; y < copyIdSize; y += 8) { - ASSERT(!copyIdSize, "Storage %s uses id copy table - must be indexed!", fileName); - records = recordCount; - indexTable = new ptr[recordCount]; + uint32 ind = *((uint32*)(copyTable + y)); + if (ind > maxi) + maxi = ind; } + ++maxi; + records = maxi; + indexTable = new ptr[maxi]; + memset(indexTable, 0, maxi * sizeof(ptr)); + char* dataTable = new char[(recordCount + (copyIdSize / 8)) * recordsize]; uint32 offset = 0; for (uint32 y = 0; y < recordCount; y++) { - uint32 indexVal; - if (indexField >= 0) - indexVal = !idTableSize ? getRecord(y).getUInt(indexField) : ((uint32*)idTable)[y]; - else - indexVal = y; + uint32 indexVal = meta->HasIndexFieldInData() ? getRecord(y).getUInt(indexField, 0) : ((uint32*)idTable)[y]; indexTable[indexVal] = &dataTable[offset]; - uint32 x = 0; - for (char const* fmt = format; *fmt != '\0'; ++fmt) + if (!meta->HasIndexFieldInData()) { - switch (*fmt) - { - case FT_FLOAT: - *((float*)(&dataTable[offset])) = getRecord(y).getFloat(x++); - offset += 4; - break; - case FT_IND: - case FT_INT: - *((uint32*)(&dataTable[offset])) = getRecord(y).getUInt(x++); - offset += 4; - break; - case FT_BYTE: - *((uint8*)(&dataTable[offset])) = getRecord(y).getUInt8(x++); - offset += 1; - break; - case FT_LONG: - *((uint64*)(&dataTable[offset])) = getRecord(y).getUInt64(x++); - offset += 8; - break; - case FT_SHORT: - *((uint16*)(&dataTable[offset])) = getRecord(y).getUInt16(x++); - offset += 2; - break; - case FT_STRING: - case FT_STRING_NOT_LOCALIZED: - *((char**)(&dataTable[offset])) = nullptr; // will be replaces non-empty or "" strings in AutoProduceStrings - offset += sizeof(char*); - ++x; - break; - case FT_SORT: - *((uint32*)(&dataTable[offset])) = indexVal; - offset += 4; - break; - } + *((uint32*)(&dataTable[offset])) = indexVal; + offset += 4; } - } - uint32* copyIds = (uint32*)copyTable; - for (uint32 c = 0; c < copyIdSize / 4; c += 2) - { - uint32 to = copyIds[c]; - uint32 from = copyIds[c + 1]; - - if (from && from < records && indexTable[from]) + Record rec = getRecord(y); + for (uint32 x = 0; x < fieldCount; ++x) { - indexTable[to] = &dataTable[offset]; - memcpy(indexTable[to], indexTable[from], recordsize); - offset += recordsize; + for (uint32 z = 0; z < meta->ArraySizes[x]; ++z) + { + switch (meta->Types[x]) + { + case FT_FLOAT: + *((float*)(&dataTable[offset])) = rec.getFloat(x, z); + offset += 4; + break; + case FT_INT: + *((uint32*)(&dataTable[offset])) = rec.getUInt(x, z); + offset += 4; + break; + case FT_BYTE: + *((uint8*)(&dataTable[offset])) = rec.getUInt8(x, z); + offset += 1; + break; + case FT_SHORT: + *((uint16*)(&dataTable[offset])) = rec.getUInt16(x, z); + offset += 2; + break; + case FT_STRING: + case FT_STRING_NOT_LOCALIZED: + *((char**)(&dataTable[offset])) = nullptr; // will be replaced by non-empty or "" strings in AutoProduceStrings + offset += sizeof(char*); + break; + default: + ASSERT(false, "Unknown format character '%c' found in %s meta", meta->Types[x], fileName); + break; + } + } } } @@ -419,21 +320,20 @@ char* DB2FileLoader::AutoProduceData(const char* format, uint32& records, char** static char const* const nullStr = ""; -char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* dataTable) +char* DB2FileLoader::AutoProduceStringsArrayHolders(char* dataTable) { - if (strlen(format) != fieldCount + (format[0] == FT_SORT ? 1 : 0)) + if (meta->FieldCount != fieldCount) return nullptr; // we store flat holders pool as single memory block - std::size_t stringFields = GetFormatStringFieldCount(format); + std::size_t stringFields = meta->GetStringFieldCount(false); if (!stringFields) return nullptr; - std::size_t localizedStringFields = GetFormatLocalizedStringFieldCount(format); + std::size_t localizedStringFields = meta->GetStringFieldCount(true); // each string field at load have array of string for each locale - std::size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES; - std::size_t stringHoldersRecordPoolSize = localizedStringFields * stringHolderSize + (stringFields - localizedStringFields) * sizeof(char*); + std::size_t stringHoldersRecordPoolSize = localizedStringFields * sizeof(LocalizedString) + (stringFields - localizedStringFields) * sizeof(char*); std::size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * recordCount; char* stringHoldersPool = new char[stringHoldersPoolSize]; @@ -449,41 +349,43 @@ char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* da { uint32 stringFieldOffset = 0; - for (char const* fmt = format; *fmt != '\0'; ++fmt) + if (!meta->HasIndexFieldInData()) + offset += 4; + + for (uint32 x = 0; x < fieldCount; ++x) { - switch (*fmt) + for (uint32 z = 0; z < meta->ArraySizes[x]; ++z) { - case FT_FLOAT: - case FT_IND: - case FT_INT: - case FT_SORT: - offset += 4; - break; - case FT_BYTE: - offset += 1; - break; - case FT_LONG: - offset += 8; - break; - case FT_SHORT: - offset += 2; - break; - case FT_STRING: - case FT_STRING_NOT_LOCALIZED: + switch (meta->Types[x]) { - // init db2 string field slots by pointers to string holders - char const*** slot = (char const***)(&dataTable[offset]); - *slot = (char const**)(&stringHoldersPool[stringHoldersRecordPoolSize * y + stringFieldOffset]); - if (*fmt == FT_STRING) - stringFieldOffset += stringHolderSize; - else - ++stringFieldOffset; - - offset += sizeof(char*); - break; + case FT_FLOAT: + case FT_INT: + offset += 4; + break; + case FT_BYTE: + offset += 1; + break; + case FT_SHORT: + offset += 2; + break; + case FT_STRING: + case FT_STRING_NOT_LOCALIZED: + { + // init db2 string field slots by pointers to string holders + char const*** slot = (char const***)(&dataTable[offset]); + *slot = (char const**)(&stringHoldersPool[stringHoldersRecordPoolSize * y + stringFieldOffset]); + if (meta->Types[x] == FT_STRING) + stringFieldOffset += sizeof(LocalizedString); + else + stringFieldOffset += sizeof(char*); + + offset += sizeof(char*); + break; + } + default: + ASSERT(false, "Unknown format character '%c' found in %s meta", meta->Types[x], fileName); + break; } - default: - ASSERT(false, "unknown format character %c", *fmt); } } } @@ -492,9 +394,9 @@ char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* da return stringHoldersPool; } -char* DB2FileLoader::AutoProduceStrings(const char* format, char* dataTable, uint32 locale) +char* DB2FileLoader::AutoProduceStrings(char* dataTable, uint32 locale) { - if (strlen(format) != fieldCount + (format[0] == FT_SORT ? 1 : 0)) + if (meta->FieldCount != fieldCount) return nullptr; if (!(localeMask & (1 << locale))) @@ -521,86 +423,110 @@ char* DB2FileLoader::AutoProduceStrings(const char* format, char* dataTable, uin for (uint32 y = 0; y < recordCount; y++) { - uint32 x = 0; - for (char const* fmt = format; *fmt != '\0'; ++fmt) + if (!meta->HasIndexFieldInData()) + offset += 4; + + for (uint32 x = 0; x < fieldCount; ++x) { - switch (*fmt) + for (uint32 z = 0; z < meta->ArraySizes[x]; ++z) { - case FT_FLOAT: - case FT_IND: - case FT_INT: - case FT_SORT: - offset += 4; - break; - case FT_BYTE: - offset += 1; - break; - case FT_LONG: - offset += 8; - break; - case FT_SHORT: - offset += 2; - break; - case FT_STRING: + switch (meta->Types[x]) { - // fill only not filled entries - LocalizedString* db2str = *(LocalizedString**)(&dataTable[offset]); - if (db2str->Str[locale] == nullStr) + case FT_FLOAT: + case FT_INT: + offset += 4; + break; + case FT_BYTE: + offset += 1; + break; + case FT_SHORT: + offset += 2; + break; + case FT_STRING: { - char const* st = getRecord(y).getString(x); - db2str->Str[locale] = stringPool + (st - (char const*)stringTable); - } + // fill only not filled entries + LocalizedString* db2str = *(LocalizedString**)(&dataTable[offset]); + if (db2str->Str[locale] == nullStr) + { + char const* st = getRecord(y).getString(x, z); + db2str->Str[locale] = stringPool + (st - (char const*)stringTable); + } - offset += sizeof(char*); - break; - } - case FT_STRING_NOT_LOCALIZED: - { - char** db2str = (char**)(&dataTable[offset]); - char const* st = getRecord(y).getString(x); - *db2str = stringPool + (st - (char const*)stringTable); - offset += sizeof(char*); - break; + offset += sizeof(char*); + break; + } + case FT_STRING_NOT_LOCALIZED: + { + char** db2str = (char**)(&dataTable[offset]); + char const* st = getRecord(y).getString(x, z); + *db2str = stringPool + (st - (char const*)stringTable); + offset += sizeof(char*); + break; + } + default: + ASSERT(false, "Unknown format character '%c' found in %s meta", meta->Types[x], fileName); + break; } } - - if (*fmt != FT_SORT) - ++x; } } return stringPool; } -char* DB2DatabaseLoader::Load(const char* format, HotfixDatabaseStatements preparedStatement, uint32& records, char**& indexTable, char*& stringHolders, std::vector<char*>& stringPool) +void DB2FileLoader::AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable) +{ + uint32 recordsize = meta->GetRecordSize(); + uint32 offset = recordCount * recordsize; + uint32* copyIds = (uint32*)copyTable; + for (uint32 c = 0; c < copyIdSize / 4; c += 2) + { + uint32 to = copyIds[c]; + uint32 from = copyIds[c + 1]; + + if (from && from < records && indexTable[from]) + { + indexTable[to] = &dataTable[offset]; + memcpy(indexTable[to], indexTable[from], recordsize); + + if (meta->HasIndexFieldInData()) + *((uint32*)(&dataTable[offset + fields[meta->GetIndexField()].Offset])) = to; + else + *((uint32*)(&dataTable[offset])) = to; + + offset += recordsize; + } + } +} + +char* DB2DatabaseLoader::Load(HotfixDatabaseStatements preparedStatement, uint32& records, char**& indexTable, char*& stringHolders, std::vector<char*>& stringPool) { // Even though this query is executed only once, prepared statement is used to send data from mysql server in binary format PreparedQueryResult result = HotfixDatabase.Query(HotfixDatabase.GetPreparedStatement(preparedStatement)); if (!result) return nullptr; - uint32 const fieldCount = strlen(format); - if (fieldCount != result->GetFieldCount()) + if (_meta->GetDbFieldCount() != result->GetFieldCount()) return nullptr; // get struct size and index pos - int32 indexField; - uint32 recordSize = DB2FileLoader::GetFormatRecordSize(format, &indexField); + uint32 indexField = _meta->GetDbIndexField(); + uint32 recordSize = _meta->GetRecordSize(); // we store flat holders pool as single memory block - size_t stringFields = DB2FileLoader::GetFormatStringFieldCount(format); + std::size_t stringFields = _meta->GetStringFieldCount(false); + std::size_t localizedStringFields = _meta->GetStringFieldCount(true); // each string field at load have array of string for each locale - size_t stringHolderSize = sizeof(char*) * TOTAL_LOCALES; - size_t stringHoldersRecordPoolSize = stringFields * stringHolderSize; + std::size_t stringHoldersRecordPoolSize = localizedStringFields * sizeof(LocalizedString) + (stringFields - localizedStringFields) * sizeof(char*); if (stringFields) { - size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * result->GetRowCount(); + std::size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * result->GetRowCount(); stringHolders = new char[stringHoldersPoolSize]; // DB2 strings expected to have at least empty string - for (size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i) + for (std::size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i) ((char const**)stringHolders)[i] = nullStr; } else @@ -608,15 +534,9 @@ char* DB2DatabaseLoader::Load(const char* format, HotfixDatabaseStatements prepa // Resize index table // database query *MUST* contain ORDER BY `index_field` DESC clause - uint32 indexTableSize; - if (indexField >= 0) - { - indexTableSize = (*result)[indexField].GetUInt32() + 1; - if (indexTableSize < records) - indexTableSize = records; - } - else - indexTableSize = records + result->GetRowCount(); + uint32 indexTableSize = (*result)[indexField].GetUInt32() + 1; + if (indexTableSize < records) + indexTableSize = records; if (indexTableSize > records) { @@ -636,13 +556,9 @@ char* DB2DatabaseLoader::Load(const char* format, HotfixDatabaseStatements prepa { Field* fields = result->Fetch(); uint32 offset = 0; - uint32 stringFieldNumInRecord = 0; + uint32 stringFieldOffset = 0; - uint32 indexValue; - if (indexField >= 0) - indexValue = fields[indexField].GetUInt32(); - else - indexValue = records + rec; + uint32 indexValue = fields[indexField].GetUInt32(); // Attempt to overwrite existing data char* dataValue = indexTable[indexValue]; @@ -652,63 +568,69 @@ char* DB2DatabaseLoader::Load(const char* format, HotfixDatabaseStatements prepa dataValue = &tempDataTable[newRecords++ * recordSize]; } - for (uint32 f = 0; f < fieldCount; f++) + uint32 f = 0; + if (!_meta->HasIndexFieldInData()) + { + *((uint32*)(&dataValue[offset])) = indexValue; + offset += 4; + ++f; + } + + for (uint32 x = 0; x < _meta->FieldCount; ++x) { - switch (format[f]) + for (uint32 z = 0; z < _meta->ArraySizes[x]; ++z) { - case FT_FLOAT: - *((float*)(&dataValue[offset])) = fields[f].GetFloat(); - offset += 4; - break; - case FT_IND: - case FT_INT: - *((int32*)(&dataValue[offset])) = fields[f].GetInt32(); - offset += 4; - break; - case FT_BYTE: - *((int8*)(&dataValue[offset])) = fields[f].GetInt8(); - offset += 1; - break; - case FT_LONG: - *((int64*)(&dataValue[offset])) = fields[f].GetInt64(); - offset += 8; - break; - case FT_SHORT: - *((int16*)(&dataValue[offset])) = fields[f].GetInt16(); - offset += 2; - break; - case FT_STRING: + switch (_meta->Types[x]) { - LocalizedString** slot = (LocalizedString**)(&dataValue[offset]); - *slot = (LocalizedString*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringHolderSize * stringFieldNumInRecord]); - ASSERT(*slot); + case FT_FLOAT: + *((float*)(&dataValue[offset])) = fields[f].GetFloat(); + offset += 4; + break; + case FT_INT: + *((int32*)(&dataValue[offset])) = fields[f].GetInt32(); + offset += 4; + break; + case FT_BYTE: + *((int8*)(&dataValue[offset])) = fields[f].GetInt8(); + offset += 1; + break; + case FT_SHORT: + *((int16*)(&dataValue[offset])) = fields[f].GetInt16(); + offset += 2; + break; + case FT_STRING: + { + LocalizedString** slot = (LocalizedString**)(&dataValue[offset]); + *slot = (LocalizedString*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringFieldOffset]); + ASSERT(*slot); - // Value in database in main table field must be for enUS locale - if (char* str = AddString(&(*slot)->Str[LOCALE_enUS], fields[f].GetString())) - stringPool.push_back(str); + // Value in database in main table field must be for enUS locale + if (char* str = AddString(&(*slot)->Str[LOCALE_enUS], fields[f].GetString())) + stringPool.push_back(str); - ++stringFieldNumInRecord; - offset += sizeof(char*); - break; - } - case FT_STRING_NOT_LOCALIZED: - { - char const** slot = (char const**)(&dataValue[offset]); - *slot = (char*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringHolderSize * stringFieldNumInRecord]); - ASSERT(*slot); + stringFieldOffset += sizeof(LocalizedString); + offset += sizeof(char*); + break; + } + case FT_STRING_NOT_LOCALIZED: + { + char const** slot = (char const**)(&dataValue[offset]); + *slot = (char*)(&stringHolders[stringHoldersRecordPoolSize * rec + stringFieldOffset]); + ASSERT(*slot); - // Value in database in main table field must be for enUS locale - if (char* str = AddString(slot, fields[f].GetString())) - stringPool.push_back(str); + // Value in database in main table field must be for enUS locale + if (char* str = AddString(slot, fields[f].GetString())) + stringPool.push_back(str); - ++stringFieldNumInRecord; - offset += sizeof(char*); - break; + stringFieldOffset += sizeof(char*); + offset += sizeof(char*); + break; + } + default: + ASSERT(false, "Unknown format character '%c' found in %s meta", _meta->Types[x], _storageName.c_str()); + break; } - case FT_SORT: - *((int32*)(&dataValue[offset])) = indexValue; - offset += 4; - break; + ++f; } } @@ -739,7 +661,7 @@ char* DB2DatabaseLoader::Load(const char* format, HotfixDatabaseStatements prepa return dataTable; } -void DB2DatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStatements preparedStatement, uint32 locale, char**& indexTable, std::vector<char*>& stringPool) +void DB2DatabaseLoader::LoadStrings(HotfixDatabaseStatements preparedStatement, uint32 locale, uint32 records, char** indexTable, std::vector<char*>& stringPool) { PreparedStatement* stmt = HotfixDatabase.GetPreparedStatement(preparedStatement); stmt->setString(0, localeNames[locale]); @@ -747,14 +669,12 @@ void DB2DatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStatements if (!result) return; - size_t stringFields = DB2FileLoader::GetFormatLocalizedStringFieldCount(format); + std::size_t stringFields = _meta->GetStringFieldCount(true); if (result->GetFieldCount() != stringFields + 1 /*ID*/) return; - uint32 const fieldCount = strlen(format); - int32 indexField; - uint32 recordSize = DB2FileLoader::GetFormatRecordSize(format, &indexField); - ASSERT(indexField >= 0, "DB2Storage must be indexed to load localized strings"); + uint32 fieldCount = _meta->FieldCount; + uint32 recordSize = _meta->GetRecordSize(); do { @@ -763,39 +683,49 @@ void DB2DatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStatements uint32 stringFieldNumInRecord = 0; uint32 indexValue = fields[0].GetUInt32(); + if (indexValue >= records) + continue; + // Attempt to overwrite existing data if (char* dataValue = indexTable[indexValue]) { - for (uint32 x = 0; x < fieldCount; x++) + if (!_meta->HasIndexFieldInData()) + offset += 4; + + for (uint32 x = 0; x < fieldCount; ++x) { - switch (format[x]) + for (uint32 z = 0; z < _meta->ArraySizes[x]; ++z) { - case FT_FLOAT: - case FT_IND: - case FT_INT: - case FT_SORT: - offset += 4; - break; - case FT_BYTE: - offset += 1; - break; - case FT_LONG: - offset += 8; - break; - case FT_SHORT: - offset += 2; - break; - case FT_STRING: + switch (_meta->Types[x]) { - // fill only not filled entries - LocalizedString* db2str = *(LocalizedString**)(&dataValue[offset]); - if (db2str->Str[locale] == nullStr) - if (char* str = AddString(&db2str->Str[locale], fields[1 + stringFieldNumInRecord].GetString())) - stringPool.push_back(str); - - ++stringFieldNumInRecord; - offset += sizeof(char*); - break; + case FT_FLOAT: + case FT_INT: + offset += 4; + break; + case FT_BYTE: + offset += 1; + break; + case FT_SHORT: + offset += 2; + break; + case FT_STRING: + { + // fill only not filled entries + LocalizedString* db2str = *(LocalizedString**)(&dataValue[offset]); + if (db2str->Str[locale] == nullStr) + if (char* str = AddString(&db2str->Str[locale], fields[1 + stringFieldNumInRecord].GetString())) + stringPool.push_back(str); + + ++stringFieldNumInRecord; + offset += sizeof(LocalizedString*); + break; + } + case FT_STRING_NOT_LOCALIZED: + offset += sizeof(char*); + break; + default: + ASSERT(false, "Unknown format character '%c' found in %s meta", _meta->Types[x], _storageName.c_str()); + break; } } } @@ -803,7 +733,7 @@ void DB2DatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStatements ASSERT(offset == recordSize); } else - TC_LOG_ERROR("sql.sql", "Hotfix locale table for storage %s references row that does not exist %u!", _storageName.c_str(), indexValue); + TC_LOG_ERROR("sql.sql", "Hotfix locale table for storage %s references row that does not exist %u locale %s!", _storageName.c_str(), indexValue, localeNames[locale]); } while (result->NextRow()); diff --git a/src/server/shared/DataStores/DB2StorageLoader.h b/src/server/shared/DataStores/DB2StorageLoader.h index c84f38b74b9..b302a1afe7d 100644 --- a/src/server/shared/DataStores/DB2StorageLoader.h +++ b/src/server/shared/DataStores/DB2StorageLoader.h @@ -18,10 +18,10 @@ #ifndef DB2_FILE_LOADER_H #define DB2_FILE_LOADER_H -#include "Define.h" +#include "DB2Meta.h" #include "Utilities/ByteConverter.h" #include "Implementation/HotfixDatabase.h" -#include <cassert> +#include "Errors.h" #include <vector> class TC_SHARED_API DB2FileLoader @@ -30,53 +30,101 @@ class TC_SHARED_API DB2FileLoader DB2FileLoader(); ~DB2FileLoader(); - bool Load(const char *filename, const char *fmt); + bool Load(char const* filename, DB2Meta const* meta); class Record { public: - float getFloat(size_t field) const + float getFloat(uint32 field, uint32 arrayIndex) const { - assert(field < file.fieldCount); - float val = *reinterpret_cast<float*>(offset + file.GetOffset(field)); + ASSERT(field < file.fieldCount); + float val = *reinterpret_cast<float*>(offset + GetOffset(field) + arrayIndex * sizeof(float)); EndianConvert(val); return val; } - uint32 getUInt(size_t field) const - { - assert(field < file.fieldCount); - uint32 val = *reinterpret_cast<uint32*>(offset + file.GetOffset(field)); - EndianConvert(val); - return val; - } - uint8 getUInt8(size_t field) const + + uint32 getUInt(uint32 field, uint32 arrayIndex) const { - assert(field < file.fieldCount); - return *reinterpret_cast<uint8*>(offset + file.GetOffset(field)); + ASSERT(field < file.fieldCount); + return GetVarInt(field, GetByteSize(field), arrayIndex); } - uint64 getUInt64(size_t field) const + + uint8 getUInt8(uint32 field, uint32 arrayIndex) const { - assert(field < file.fieldCount); - uint64 val = *reinterpret_cast<uint64*>(offset + file.GetOffset(field)); - EndianConvert(val); - return val; + ASSERT(field < file.fieldCount); + ASSERT(GetByteSize(field) == 1); + return *reinterpret_cast<uint8*>(offset + GetOffset(field) + arrayIndex * sizeof(uint8)); } - uint16 getUInt16(size_t field) const + + uint16 getUInt16(uint32 field, uint32 arrayIndex) const { - assert(field < file.fieldCount); - uint16 val = *reinterpret_cast<uint16*>(offset + file.GetOffset(field)); + ASSERT(field < file.fieldCount); + ASSERT(GetByteSize(field) == 2); + uint16 val = *reinterpret_cast<uint16*>(offset + GetOffset(field) + arrayIndex * sizeof(uint16)); EndianConvert(val); return val; } - const char *getString(size_t field) const + + char const* getString(uint32 field, uint32 arrayIndex) const { - assert(field < file.fieldCount); - size_t stringOffset = getUInt(field); - assert(stringOffset < file.stringSize); + ASSERT(field < file.fieldCount); + uint32 stringOffset = *reinterpret_cast<uint32*>(offset + GetOffset(field) + arrayIndex * sizeof(uint32)); + EndianConvert(stringOffset); + ASSERT(stringOffset < file.stringSize); return reinterpret_cast<char*>(file.stringTable + stringOffset); } private: + uint16 GetOffset(uint32 field) const + { + ASSERT(field < file.fieldCount); + return file.fields[field].Offset; + } + + uint16 GetByteSize(uint32 field) const + { + ASSERT(field < file.fieldCount); + return 4 - file.fields[field].UnusedBits / 8; + } + + uint32 GetVarInt(uint32 field, uint16 size, uint32 arrayIndex) const + { + ASSERT(field < file.fieldCount); + switch (size) + { + case 1: + { + return *reinterpret_cast<uint8*>(offset + GetOffset(field) + arrayIndex * sizeof(uint8)); + } + case 2: + { + uint16 val = *reinterpret_cast<uint16*>(offset + GetOffset(field) + arrayIndex * sizeof(uint16)); + EndianConvert(val); + return val; + } + case 3: + { +#pragma pack(push, 1) + struct dbcint24 { uint8 v[3]; }; +#pragma pack(pop) + dbcint24 val = *reinterpret_cast<dbcint24*>(offset + GetOffset(field) + arrayIndex * sizeof(dbcint24)); + EndianConvert(val); + return uint32(val.v[0]) | (uint32(val.v[1]) << 8) | (uint32(val.v[2]) << 16); + } + case 4: + { + uint32 val = *reinterpret_cast<uint32*>(offset + GetOffset(field) + arrayIndex * sizeof(uint32)); + EndianConvert(val); + return val; + } + default: + break; + } + + ASSERT(false, "GetByteSize(field) < 4"); + return 0; + } + Record(DB2FileLoader &file_, unsigned char *offset_): offset(offset_), file(file_) {} unsigned char *offset; DB2FileLoader &file; @@ -86,22 +134,28 @@ class TC_SHARED_API DB2FileLoader // Get record by id Record getRecord(size_t id); - /// Get begin iterator over records uint32 GetNumRows() const { return recordCount;} uint32 GetCols() const { return fieldCount; } - uint32 GetOffset(size_t id) const { return (fieldsOffset != NULL && id < fieldCount) ? fieldsOffset[id] : 0; } - uint32 GetHash() const { return tableHash; } - uint32 GetBuild() const { return build; } + uint32 GetTableHash() const { return tableHash; } + uint32 GetLayoutHash() const { return layoutHash; } bool IsLoaded() const { return (data != NULL); } - char* AutoProduceData(const char* fmt, uint32& count, char**& indexTable); - char* AutoProduceStringsArrayHolders(const char* fmt, char* dataTable); - char* AutoProduceStrings(const char* fmt, char* dataTable, uint32 locale); - static uint32 GetFormatRecordSize(const char * format, int32 * index_pos = NULL); - static uint32 GetFormatStringFieldCount(const char * format); - static uint32 GetFormatLocalizedStringFieldCount(const char * format); + char* AutoProduceData(uint32& count, char**& indexTable); + char* AutoProduceStringsArrayHolders(char* dataTable); + char* AutoProduceStrings(char* dataTable, uint32 locale); + void AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable); + private: +#pragma pack(push, 1) + struct FieldEntry + { + uint16 UnusedBits; + uint16 Offset; + }; +#pragma pack(pop) + char const* fileName; + DB2Meta const* meta; // WDB2 / WCH2 fields uint32 recordSize; @@ -109,33 +163,33 @@ private: uint32 fieldCount; uint32 stringSize; uint32 tableHash; - uint32 build; - uint32 unk1; + uint32 layoutHash; uint32 minIndex; uint32 maxIndex; uint32 localeMask; uint32 copyIdSize; uint32 metaFlags; - uint32 *fieldsOffset; unsigned char* data; unsigned char* stringTable; unsigned char* idTable; uint32 idTableSize; unsigned char* copyTable; + FieldEntry* fields; }; class TC_SHARED_API DB2DatabaseLoader { public: - explicit DB2DatabaseLoader(std::string const& storageName) : _storageName(storageName) { } + DB2DatabaseLoader(std::string const& storageName, DB2Meta const* meta) : _storageName(storageName), _meta(meta) { } - char* Load(const char* format, HotfixDatabaseStatements preparedStatement, uint32& records, char**& indexTable, char*& stringHolders, std::vector<char*>& stringPool); - void LoadStrings(const char* format, HotfixDatabaseStatements preparedStatement, uint32 locale, char**& indexTable, std::vector<char*>& stringPool); + char* Load(HotfixDatabaseStatements preparedStatement, uint32& records, char**& indexTable, char*& stringHolders, std::vector<char*>& stringPool); + void LoadStrings(HotfixDatabaseStatements preparedStatement, uint32 locale, uint32 records, char** indexTable, std::vector<char*>& stringPool); static char* AddString(char const** holder, std::string const& value); private: std::string _storageName; + DB2Meta const* _meta; }; #endif diff --git a/src/server/shared/DataStores/DB2Store.h b/src/server/shared/DataStores/DB2Store.h index e1c05cfbbe7..e673b8a6a97 100644 --- a/src/server/shared/DataStores/DB2Store.h +++ b/src/server/shared/DataStores/DB2Store.h @@ -28,8 +28,8 @@ class DB2StorageBase { public: - DB2StorageBase(char const* fileName, char const* format, HotfixDatabaseStatements preparedStmtIndex) - : _tableHash(0), _build(0), _fileName(fileName), _fieldCount(0), _format(format), _dataTable(nullptr), _dataTableEx(nullptr), _hotfixStatement(preparedStmtIndex) { } + DB2StorageBase(char const* fileName, DB2Meta const* meta, HotfixDatabaseStatements preparedStmtIndex) + : _tableHash(0), _layoutHash(0), _fileName(fileName), _fieldCount(0), _meta(meta), _dataTable(nullptr), _dataTableEx(nullptr), _hotfixStatement(preparedStmtIndex) { } virtual ~DB2StorageBase() { @@ -39,9 +39,9 @@ public: delete[] strings; } - uint32 GetHash() const { return _tableHash; } + uint32 GetTableHash() const { return _tableHash; } - uint32 GetBuild() const { return _build; } + uint32 GetLayoutHash() const { return _layoutHash; } virtual bool HasRecord(uint32 id) const = 0; @@ -53,7 +53,7 @@ public: uint32 GetFieldCount() const { return _fieldCount; } - char const* GetFormat() const { return _format; } + DB2Meta const* GetMeta() const { return _meta; } virtual bool Load(std::string const& path, uint32 locale) = 0; virtual bool LoadStringsFrom(std::string const& path, uint32 locale) = 0; @@ -63,63 +63,67 @@ public: protected: void WriteRecordData(char const* entry, uint32 locale, ByteBuffer& buffer) const { - std::size_t fields = strlen(_format); - for (uint32 i = 0; i < fields; ++i) + if (!_meta->HasIndexFieldInData()) + entry += 4; + + for (uint32 i = 0; i < _meta->FieldCount; ++i) { - switch (_format[i]) + for (uint32 a = 0; a < _meta->ArraySizes[i]; ++a) { - case FT_IND: - case FT_INT: - buffer << *(uint32*)entry; - entry += 4; - break; - case FT_FLOAT: - buffer << *(float*)entry; - entry += 4; - break; - case FT_BYTE: - buffer << *(uint8*)entry; - entry += 1; - break; - case FT_STRING: + switch (_meta->Types[i]) { - LocalizedString* locStr = *(LocalizedString**)entry; - if (locStr->Str[locale][0] == '\0') - locale = 0; - - char const* str = locStr->Str[locale]; - std::size_t len = strlen(str); - buffer << uint16(len ? len + 1 : 0); - if (len) + case FT_INT: + buffer << *(uint32*)entry; + entry += 4; + break; + case FT_FLOAT: + buffer << *(float*)entry; + entry += 4; + break; + case FT_BYTE: + buffer << *(uint8*)entry; + entry += 1; + break; + case FT_STRING: { - buffer.append(str, len); - buffer << uint8(0); + LocalizedString* locStr = *(LocalizedString**)entry; + if (locStr->Str[locale][0] == '\0') + locale = 0; + + char const* str = locStr->Str[locale]; + std::size_t len = strlen(str); + buffer << uint16(len ? len + 1 : 0); + if (len) + { + buffer.append(str, len); + buffer << uint8(0); + } + entry += sizeof(LocalizedString*); + break; } - entry += sizeof(LocalizedString*); - break; - } - case FT_STRING_NOT_LOCALIZED: - { - char const* str = *(char const**)entry; - std::size_t len = strlen(str); - buffer << uint16(len ? len + 1 : 0); - if (len) + case FT_STRING_NOT_LOCALIZED: { - buffer.append(str, len); - buffer << uint8(0); + char const* str = *(char const**)entry; + std::size_t len = strlen(str); + buffer << uint16(len ? len + 1 : 0); + if (len) + { + buffer.append(str, len); + buffer << uint8(0); + } + entry += sizeof(char const*); + break; } - entry += sizeof(char const*); - break; } } } } uint32 _tableHash; - uint32 _build; + uint32 _layoutHash; std::string _fileName; uint32 _fieldCount; - char const* _format; + DB2Meta const* _meta; char* _dataTable; char* _dataTableEx; std::vector<char*> _stringPool; @@ -134,7 +138,7 @@ class DB2Storage : public DB2StorageBase public: typedef DBStorageIterator<T> iterator; - DB2Storage(char const* fileName, char const* format, HotfixDatabaseStatements preparedStmtIndex) : DB2StorageBase(fileName, format, preparedStmtIndex), + DB2Storage(char const* fileName, DB2Meta const* meta, HotfixDatabaseStatements preparedStmtIndex) : DB2StorageBase(fileName, meta, preparedStmtIndex), _indexTableSize(0) { _indexTable.AsT = NULL; @@ -161,26 +165,28 @@ public: { DB2FileLoader db2; // Check if load was successful, only then continue - if (!db2.Load((path + _fileName).c_str(), _format)) + if (!db2.Load((path + _fileName).c_str(), _meta)) return false; _fieldCount = db2.GetCols(); - _tableHash = db2.GetHash(); - _build = db2.GetBuild(); + _tableHash = db2.GetTableHash(); + _layoutHash = db2.GetLayoutHash(); // load raw non-string data - _dataTable = db2.AutoProduceData(_format, _indexTableSize, _indexTable.AsChar); + _dataTable = db2.AutoProduceData(_indexTableSize, _indexTable.AsChar); // create string holders for loaded string fields - if (char* stringHolders = db2.AutoProduceStringsArrayHolders(_format, _dataTable)) + if (char* stringHolders = db2.AutoProduceStringsArrayHolders(_dataTable)) { _stringPool.push_back(stringHolders); // load strings from db2 data - if (char* stringBlock = db2.AutoProduceStrings(_format, _dataTable, locale)) + if (char* stringBlock = db2.AutoProduceStrings(_dataTable, locale)) _stringPool.push_back(stringBlock); } + db2.AutoProduceRecordCopies(_indexTableSize, _indexTable.AsChar, _dataTable); + // error in db2 file at loading if NULL return _indexTable.AsT != NULL; } @@ -193,12 +199,12 @@ public: DB2FileLoader db2; // Check if load was successful, only then continue - if (!db2.Load((path + _fileName).c_str(), _format)) + if (!db2.Load((path + _fileName).c_str(), _meta)) return false; // load strings from another locale db2 data - if (DB2FileLoader::GetFormatLocalizedStringFieldCount(_format)) - if (char* stringBlock = db2.AutoProduceStrings(_format, _dataTable, locale)) + if (_meta->GetStringFieldCount(true)) + if (char* stringBlock = db2.AutoProduceStrings(_dataTable, locale)) _stringPool.push_back(stringBlock); return true; } @@ -206,17 +212,17 @@ public: void LoadFromDB() override { char* extraStringHolders = nullptr; - _dataTableEx = DB2DatabaseLoader(_fileName).Load(_format, _hotfixStatement, _indexTableSize, _indexTable.AsChar, extraStringHolders, _stringPool); + _dataTableEx = DB2DatabaseLoader(_fileName, _meta).Load(_hotfixStatement, _indexTableSize, _indexTable.AsChar, extraStringHolders, _stringPool); if (extraStringHolders) _stringPool.push_back(extraStringHolders); } void LoadStringsFromDB(uint32 locale) override { - if (!DB2FileLoader::GetFormatLocalizedStringFieldCount(_format)) + if (!_meta->GetStringFieldCount(true)) return; - DB2DatabaseLoader(_fileName).LoadStrings(_format, HotfixDatabaseStatements(_hotfixStatement + 1), locale, _indexTable.AsChar, _stringPool); + DB2DatabaseLoader(_fileName, _meta).LoadStrings(HotfixDatabaseStatements(_hotfixStatement + 1), locale, _indexTableSize, _indexTable.AsChar, _stringPool); } iterator begin() { return iterator(_indexTable.AsT, _indexTableSize); } @@ -249,8 +255,8 @@ public: T const* operator*() const { return Base::operator*().second; } } iterator; - DB2SparseStorage(char const* fileName, char const* format, HotfixDatabaseStatements preparedStmtIndex) - : DB2StorageBase(fileName, format, preparedStmtIndex) + DB2SparseStorage(char const* fileName, DB2Meta const* meta, HotfixDatabaseStatements preparedStmtIndex) + : DB2StorageBase(fileName, meta, preparedStmtIndex) { } @@ -282,15 +288,15 @@ public: { DB2SparseFileLoader db2; // Check if load was successful, only then continue - if (!db2.Load((path + _fileName).c_str())) + if (!db2.Load((path + _fileName).c_str(), _meta)) return false; _fieldCount = db2.GetCols(); - _tableHash = db2.GetHash(); - _build = db2.GetBuild(); + _tableHash = db2.GetTableHash(); + _layoutHash = db2.GetLayoutHash(); // load raw non-string data - _dataTable = db2.AutoProduceData(_format, IndexTableAdapter<T>(_indexTable), locale, _stringPool); + _dataTable = db2.AutoProduceData(IndexTableAdapter<T>(_indexTable), locale, _stringPool); // error in db2 file at loading if NULL return !_indexTable.empty(); @@ -304,27 +310,27 @@ public: DB2SparseFileLoader db2; // Check if load was successful, only then continue - if (!db2.Load((path + _fileName).c_str())) + if (!db2.Load((path + _fileName).c_str(), _meta)) return false; // load strings from another locale db2 data - if (DB2SparseFileLoader::GetFormatLocalizedStringFieldCount(_format)) - if (char* stringBlock = db2.AutoProduceStrings(_format, _dataTable, locale)) + if (_meta->GetStringFieldCount(true)) + if (char* stringBlock = db2.AutoProduceStrings(_dataTable, locale)) _stringPool.push_back(stringBlock); return true; } void LoadFromDB() override { - _dataTableEx = DB2SparseDatabaseLoader(_fileName).Load(_format, _hotfixStatement, IndexTableAdapter<T>(_indexTable), _stringPool); + _dataTableEx = DB2SparseDatabaseLoader(_fileName, _meta).Load(_hotfixStatement, IndexTableAdapter<T>(_indexTable), _stringPool); } void LoadStringsFromDB(uint32 locale) override { - if (!DB2SparseFileLoader::GetFormatLocalizedStringFieldCount(_format)) + if (!_meta->GetStringFieldCount(true)) return; - DB2SparseDatabaseLoader(_fileName).LoadStrings(_format, HotfixDatabaseStatements(_hotfixStatement + 1), locale, IndexTableAdapter<T>(_indexTable), _stringPool); + DB2SparseDatabaseLoader(_fileName, _meta).LoadStrings(HotfixDatabaseStatements(_hotfixStatement + 1), locale, IndexTableAdapter<T>(_indexTable), _stringPool); } iterator begin() const { return iterator(_indexTable.begin()); } |
