aboutsummaryrefslogtreecommitdiff
path: root/src/server/shared
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2016-05-27 23:13:47 +0200
committerShauren <shauren.trinity@gmail.com>2016-05-27 23:14:36 +0200
commitb82332487afd7233850e7eed996615b3fdd7248c (patch)
tree4f440c5643049ff69c2544560fd750629c7a5552 /src/server/shared
parent31009887e35cf8db6e94bf5b6870b62538364bc4 (diff)
Core/DataStores: Updated db2 to 7.0.3.21737
Diffstat (limited to 'src/server/shared')
-rw-r--r--src/server/shared/DataStores/DB2Meta.cpp101
-rw-r--r--src/server/shared/DataStores/DB2Meta.h46
-rw-r--r--src/server/shared/DataStores/DB2SparseStorageLoader.cpp529
-rw-r--r--src/server/shared/DataStores/DB2SparseStorageLoader.h39
-rw-r--r--src/server/shared/DataStores/DB2StorageLoader.cpp658
-rw-r--r--src/server/shared/DataStores/DB2StorageLoader.h142
-rw-r--r--src/server/shared/DataStores/DB2Store.h150
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()); }