aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2016-08-05 20:49:01 +0200
committerShauren <shauren.trinity@gmail.com>2016-08-05 20:49:01 +0200
commitbb93816b5c7b9a1936fb50d654e49b3d47482f39 (patch)
treedf7a205d53efa253d85d322fec5ce65008d7a110
parent8950ec43eb185cbcdebddc2b2fafd79c7d641202 (diff)
Core/DataStores: Refactored DB2 loaders to no longer require sparse format to be specified at compile time
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.cpp6
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.h4
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp6
-rw-r--r--src/server/game/DataStores/DB2Stores.h5
-rw-r--r--src/server/shared/DataStores/DB2SparseStorageLoader.cpp709
-rw-r--r--src/server/shared/DataStores/DB2SparseStorageLoader.h123
-rw-r--r--src/server/shared/DataStores/DB2StorageLoader.cpp934
-rw-r--r--src/server/shared/DataStores/DB2StorageLoader.h177
-rw-r--r--src/server/shared/DataStores/DB2Store.h116
9 files changed, 748 insertions, 1332 deletions
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp
index beff06ff757..71a874d7198 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.cpp
+++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp
@@ -378,13 +378,13 @@ void HotfixDatabaseConnection::DoPrepareStatements()
PrepareStatement(HOTFIX_SEL_ITEM_BONUS_TREE_NODE, "SELECT ID, BonusTreeID, SubTreeID, BonusListID, BonusTreeModID FROM item_bonus_tree_node"
" ORDER BY ID DESC", CONNECTION_SYNCH);
+ // ItemChildEquipment.db2
+ PrepareStatement(HOTFIX_SEL_ITEM_CHILD_EQUIPMENT, "SELECT ID, ItemID, AltItemID, AltEquipmentSlot FROM item_child_equipment ORDER BY ID DESC", CONNECTION_SYNCH);
+
// ItemClass.db2
PrepareStatement(HOTFIX_SEL_ITEM_CLASS, "SELECT ID, PriceMod, Name, Flags FROM item_class ORDER BY ID DESC", CONNECTION_SYNCH);
PREPARE_LOCALE_STMT(HOTFIX_SEL_ITEM_CLASS, "SELECT ID, Name_lang FROM item_class_locale WHERE locale = ?", CONNECTION_SYNCH);
- // ItemChildEquipment.db2
- PrepareStatement(HOTFIX_SEL_ITEM_CHILD_EQUIPMENT, "SELECT ID, ItemID, AltItemID, AltEquipmentSlot FROM item_child_equipment ORDER BY ID DESC", CONNECTION_SYNCH);
-
// ItemCurrencyCost.db2
PrepareStatement(HOTFIX_SEL_ITEM_CURRENCY_COST, "SELECT ID, ItemId FROM item_currency_cost ORDER BY ID DESC", CONNECTION_SYNCH);
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.h b/src/server/database/Database/Implementation/HotfixDatabase.h
index 4fc4d796f58..66d9d65cb07 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.h
+++ b/src/server/database/Database/Implementation/HotfixDatabase.h
@@ -215,11 +215,11 @@ enum HotfixDatabaseStatements
HOTFIX_SEL_ITEM_BONUS_TREE_NODE,
+ HOTFIX_SEL_ITEM_CHILD_EQUIPMENT,
+
HOTFIX_SEL_ITEM_CLASS,
HOTFIX_SEL_ITEM_CLASS_LOCALE,
- HOTFIX_SEL_ITEM_CHILD_EQUIPMENT,
-
HOTFIX_SEL_ITEM_CURRENCY_COST,
HOTFIX_SEL_ITEM_DAMAGE_AMMO,
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index 050fda2fa25..f86cc7da260 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -100,8 +100,8 @@ DB2Storage<ItemArmorTotalEntry> sItemArmorTotalStore("ItemArmorT
DB2Storage<ItemBagFamilyEntry> sItemBagFamilyStore("ItemBagFamily.db2", ItemBagFamilyMeta::Instance(), HOTFIX_SEL_ITEM_BAG_FAMILY);
DB2Storage<ItemBonusEntry> sItemBonusStore("ItemBonus.db2", ItemBonusMeta::Instance(), HOTFIX_SEL_ITEM_BONUS);
DB2Storage<ItemBonusTreeNodeEntry> sItemBonusTreeNodeStore("ItemBonusTreeNode.db2", ItemBonusTreeNodeMeta::Instance(), HOTFIX_SEL_ITEM_BONUS_TREE_NODE);
-DB2Storage<ItemClassEntry> sItemClassStore("ItemClass.db2", ItemClassMeta::Instance(), HOTFIX_SEL_ITEM_CLASS);
DB2Storage<ItemChildEquipmentEntry> sItemChildEquipmentStore("ItemChildEquipment.db2", ItemChildEquipmentMeta::Instance(), HOTFIX_SEL_ITEM_CHILD_EQUIPMENT);
+DB2Storage<ItemClassEntry> sItemClassStore("ItemClass.db2", ItemClassMeta::Instance(), HOTFIX_SEL_ITEM_CLASS);
DB2Storage<ItemCurrencyCostEntry> sItemCurrencyCostStore("ItemCurrencyCost.db2", ItemCurrencyCostMeta::Instance(), HOTFIX_SEL_ITEM_CURRENCY_COST);
DB2Storage<ItemDamageAmmoEntry> sItemDamageAmmoStore("ItemDamageAmmo.db2", ItemDamageAmmoMeta::Instance(), HOTFIX_SEL_ITEM_DAMAGE_AMMO);
DB2Storage<ItemDamageOneHandEntry> sItemDamageOneHandStore("ItemDamageOneHand.db2", ItemDamageOneHandMeta::Instance(), HOTFIX_SEL_ITEM_DAMAGE_ONE_HAND);
@@ -120,7 +120,7 @@ DB2Storage<ItemRandomSuffixEntry> sItemRandomSuffixStore("ItemRand
DB2Storage<ItemSearchNameEntry> sItemSearchNameStore("ItemSearchName.db2", ItemSearchNameMeta::Instance(), HOTFIX_SEL_ITEM_SEARCH_NAME);
DB2Storage<ItemSetEntry> sItemSetStore("ItemSet.db2", ItemSetMeta::Instance(), HOTFIX_SEL_ITEM_SET);
DB2Storage<ItemSetSpellEntry> sItemSetSpellStore("ItemSetSpell.db2", ItemSetSpellMeta::Instance(), HOTFIX_SEL_ITEM_SET_SPELL);
-DB2SparseStorage<ItemSparseEntry> sItemSparseStore("Item-sparse.db2", ItemSparseMeta::Instance(), HOTFIX_SEL_ITEM_SPARSE);
+DB2Storage<ItemSparseEntry> sItemSparseStore("Item-sparse.db2", ItemSparseMeta::Instance(), HOTFIX_SEL_ITEM_SPARSE);
DB2Storage<ItemSpecEntry> sItemSpecStore("ItemSpec.db2", ItemSpecMeta::Instance(), HOTFIX_SEL_ITEM_SPEC);
DB2Storage<ItemSpecOverrideEntry> sItemSpecOverrideStore("ItemSpecOverride.db2", ItemSpecOverrideMeta::Instance(), HOTFIX_SEL_ITEM_SPEC_OVERRIDE);
DB2Storage<ItemUpgradeEntry> sItemUpgradeStore("ItemUpgrade.db2", ItemUpgradeMeta::Instance(), HOTFIX_SEL_ITEM_UPGRADE);
@@ -362,8 +362,8 @@ void DB2Manager::LoadStores(std::string const& dataPath, uint32 defaultLocale)
LOAD_DB2(sItemBagFamilyStore);
LOAD_DB2(sItemBonusStore);
LOAD_DB2(sItemBonusTreeNodeStore);
- LOAD_DB2(sItemClassStore);
LOAD_DB2(sItemChildEquipmentStore);
+ LOAD_DB2(sItemClassStore);
LOAD_DB2(sItemCurrencyCostStore);
LOAD_DB2(sItemDamageAmmoStore);
LOAD_DB2(sItemDamageOneHandStore);
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index efe9bef5754..35550f9ce0d 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -108,7 +108,7 @@ TC_GAME_API extern DB2Storage<ItemRandomSuffixEntry> sItemRandomS
TC_GAME_API extern DB2Storage<ItemSearchNameEntry> sItemSearchNameStore;
TC_GAME_API extern DB2Storage<ItemSetEntry> sItemSetStore;
TC_GAME_API extern DB2Storage<ItemSetSpellEntry> sItemSetSpellStore;
-TC_GAME_API extern DB2SparseStorage<ItemSparseEntry> sItemSparseStore;
+TC_GAME_API extern DB2Storage<ItemSparseEntry> sItemSparseStore;
TC_GAME_API extern DB2Storage<ItemSpecEntry> sItemSpecStore;
TC_GAME_API extern DB2Storage<ItemSpecOverrideEntry> sItemSpecOverrideStore;
TC_GAME_API extern DB2Storage<ItemUpgradeEntry> sItemUpgradeStore;
@@ -304,7 +304,8 @@ public:
std::vector<QuestPackageItemEntry const*> const* GetQuestPackageItems(uint32 questPackageID) const;
uint32 GetQuestUniqueBitFlag(uint32 questId);
uint32 GetRulesetItemUpgrade(uint32 itemId) const;
- SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_); std::vector<SpecializationSpellsEntry const*> const* GetSpecializationSpells(uint32 specId) const;
+ SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_);
+ std::vector<SpecializationSpellsEntry const*> const* GetSpecializationSpells(uint32 specId) const;
std::vector<SpellPowerEntry const*> GetSpellPowers(uint32 spellId, Difficulty difficulty = DIFFICULTY_NONE, bool* hasDifficultyPowers = nullptr) const;
std::vector<SpellProcsPerMinuteModEntry const*> GetSpellProcsPerMinuteMods(uint32 spellprocsPerMinuteId) const;
std::vector<TalentEntry const*> const& GetTalentsByPosition(uint32 class_, uint32 tier, uint32 column) const;
diff --git a/src/server/shared/DataStores/DB2SparseStorageLoader.cpp b/src/server/shared/DataStores/DB2SparseStorageLoader.cpp
deleted file mode 100644
index 5b93d588965..00000000000
--- a/src/server/shared/DataStores/DB2SparseStorageLoader.cpp
+++ /dev/null
@@ -1,709 +0,0 @@
-/*
- * 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 "Common.h"
-#include "DB2SparseStorageLoader.h"
-#include "DatabaseEnv.h"
-#include "Log.h"
-
-DB2SparseFileLoader::DB2SparseFileLoader()
-{
- fileName = nullptr;
- meta = nullptr;
-
- recordCount = 0;
- fieldCount = 0;
- recordSize = 0;
- offsetsPos = 0;
- tableHash = 0;
- layoutHash = 0;
- minIndex = 0;
- maxIndex = 0;
- localeMask = 0;
- copyIdSize = 0;
-
- dataStart = 0;
- data = nullptr;
- offsets = nullptr;
- fields = nullptr;
-}
-
-bool DB2SparseFileLoader::Load(const char *filename, DB2Meta const* meta)
-{
- if (data)
- {
- delete[] data;
- data = nullptr;
- }
-
- FILE* f = fopen(filename, "rb");
- if (!f)
- return false;
-
- fileName = filename;
- this->meta = meta;
- uint32 header;
- if (fread(&header, 4, 1, f) != 1) // Signature
- {
- fclose(f);
- return false;
- }
-
- EndianConvert(header);
-
- if (header != 0x35424457)
- {
- fclose(f);
- return false; //'WDB5'
- }
-
- if (fread(&recordCount, 4, 1, f) != 1) // Number of records
- {
- fclose(f);
- return false;
- }
-
- EndianConvert(recordCount);
-
- if (fread(&fieldCount, 4, 1, f) != 1) // Number of fields
- {
- fclose(f);
- return false;
- }
-
- EndianConvert(fieldCount);
-
- if (fread(&recordSize, 4, 1, f) != 1) // Size of a record
- {
- fclose(f);
- return false;
- }
-
- EndianConvert(recordSize);
-
- if (fread(&offsetsPos, 4, 1, f) != 1) // String size
- {
- fclose(f);
- return false;
- }
-
- EndianConvert(offsetsPos);
-
- if (fread(&tableHash, 4, 1, f) != 1) // Table hash
- {
- fclose(f);
- return false;
- }
-
- EndianConvert(tableHash);
-
- if (fread(&layoutHash, 4, 1, f) != 1) // Layout hash
- {
- fclose(f);
- return false;
- }
-
- EndianConvert(layoutHash);
-
- if (layoutHash != meta->LayoutHash)
- {
- fclose(f);
- return false;
- }
-
- if (fread(&minIndex, 4, 1, f) != 1) // MinIndex WDB2
- {
- fclose(f);
- return false;
- }
-
- EndianConvert(minIndex);
-
- if (fread(&maxIndex, 4, 1, f) != 1) // MaxIndex WDB2
- {
- fclose(f);
- return false;
- }
-
- EndianConvert(maxIndex);
-
- if (fread(&localeMask, 4, 1, f) != 1) // Locales
- {
- fclose(f);
- return false;
- }
-
- EndianConvert(localeMask);
-
- if (fread(&copyIdSize, 4, 1, f) != 1)
- {
- fclose(f);
- return false;
- }
-
- EndianConvert(copyIdSize);
-
- if (fread(&metaFlags, 4, 1, f) != 1)
- {
- fclose(f);
- return false;
- }
-
- EndianConvert(metaFlags);
-
- ASSERT((metaFlags & 0x1) != 0, "%s is not a sparse storage, use DB2Storage!", filename);
-
- 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];
-
- if (fread(data, offsetsPos - dataStart, 1, f) != 1)
- {
- fclose(f);
- return false;
- }
-
- offsets = new OffsetTableEntry[maxIndex - minIndex + 1];
- if (fread(offsets, (maxIndex - minIndex + 1) * 6, 1, f) != 1)
- {
- fclose(f);
- return false;
- }
-
- fclose(f);
- return true;
-}
-
-DB2SparseFileLoader::~DB2SparseFileLoader()
-{
- delete[] data;
- delete[] offsets;
- delete[] fields;
-}
-
-static char const* const nullStr = "";
-
-char* DB2SparseFileLoader::AutoProduceData(IndexTable const& indexTable, uint32 locale, std::vector<char*>& stringPool)
-{
- if (meta->FieldCount != fieldCount)
- return NULL;
-
- //get struct size and index pos
- uint32 recordsize = meta->GetRecordSize();
-
- uint32 offsetCount = maxIndex - minIndex + 1;
- uint32 records = 0;
- uint32 expandedDataSize = 0;
- for (uint32 i = 0; i < offsetCount; ++i)
- {
- if (offsets[i].FileOffset && offsets[i].RecordSize)
- {
- ++records;
- expandedDataSize += offsets[i].RecordSize;
- }
- }
-
- char* dataTable = new char[records * recordsize];
-
- // we store flat holders pool as single memory block
- 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 stringHoldersRecordPoolSize = localizedStringFields * sizeof(LocalizedString) + (stringFields - localizedStringFields) * sizeof(char*);
- std::size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * records;
-
- char* stringHoldersPool = new char[stringHoldersPoolSize];
- stringPool.push_back(stringHoldersPool);
-
- // DB2 strings expected to have at least empty string
- for (std::size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i)
- ((char const**)stringHoldersPool)[i] = nullStr;
-
- 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;
-
- uint32 offset = 0;
- uint32 recordNum = 0;
- for (uint32 y = 0; y < offsetCount; ++y)
- {
- if (!offsets[y].FileOffset || !offsets[y].RecordSize)
- continue;
-
- indexTable.Insert(y + minIndex, &dataTable[offset]);
- uint32 fieldOffset = 0;
- uint32 stringFieldOffset = 0;
-
- if (!meta->HasIndexFieldInData())
- {
- *((uint32*)(&dataTable[offset])) = y + minIndex;
- offset += 4;
- }
-
- for (uint32 x = 0; x < fieldCount; ++x)
- {
- uint16 fieldBytes = 4 - fields[x].UnusedBits / 8;
- for (uint32 z = 0; z < meta->ArraySizes[x]; ++z)
- {
- switch (meta->Types[x])
- {
- 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 = 0;
- 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;
- }
- }
- }
-
- ++recordNum;
- }
-
- return dataTable;
-}
-
-char* DB2SparseFileLoader::AutoProduceStrings(char* dataTable, uint32 locale)
-{
- if (meta->FieldCount != fieldCount)
- return nullptr;
-
- if (!(localeMask & (1 << locale)))
- {
- char const* sep = "";
- std::ostringstream str;
- for (uint32 i = 0; i < TOTAL_LOCALES; ++i)
- {
- if (localeMask & (1 << i))
- {
- str << sep << localeNames[i];
- sep = ", ";
- }
- }
-
- TC_LOG_ERROR("", "Attempted to load %s which has locales %s as %s. Check if you placed your localized db2 files in correct directory.", fileName, str.str().c_str(), localeNames[locale]);
- return nullptr;
- }
-
- uint32 offsetCount = maxIndex - minIndex + 1;
- uint32 records = 0;
- for (uint32 i = 0; i < offsetCount; ++i)
- if (offsets[i].FileOffset && offsets[i].RecordSize)
- ++records;
-
- 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;
-
- for (uint32 y = 0; y < offsetCount; y++)
- {
- 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 z = 0; z < meta->ArraySizes[x]; ++z)
- {
- switch (meta->Types[x])
- {
- 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;
- }
- }
- }
- }
-
- return stringTable;
-}
-
-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;
-
- if (_meta->GetDbFieldCount() != result->GetFieldCount())
- return nullptr;
-
- // get struct size and index pos
- uint32 indexField = _meta->GetDbIndexField();
- uint32 recordSize = _meta->GetRecordSize();
-
- // we store flat holders pool as single memory block
- 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 stringHoldersRecordPoolSize = localizedStringFields * sizeof(LocalizedString) + (stringFields - localizedStringFields) * sizeof(char*);
-
- char* stringHolders = nullptr;
- if (stringFields)
- {
- std::size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * result->GetRowCount();
- stringHolders = new char[stringHoldersPoolSize];
- stringPool.push_back(stringHolders);
-
- // DB2 strings expected to have at least empty string
- for (std::size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i)
- ((char const**)stringHolders)[i] = nullStr;
- }
-
- char* tempDataTable = new char[result->GetRowCount() * recordSize];
- uint32* newIndexes = new uint32[result->GetRowCount()];
- uint32 rec = 0;
- uint32 newRecords = 0;
-
- do
- {
- Field* fields = result->Fetch();
- uint32 offset = 0;
- uint32 stringFieldOffset = 0;
-
- uint32 indexValue = fields[indexField].GetUInt32();
-
- // Attempt to overwrite existing data
- char* dataValue = indexTable.Get(indexValue);
- if (!dataValue)
- {
- newIndexes[newRecords] = indexValue;
- dataValue = &tempDataTable[newRecords++ * recordSize];
- }
-
- uint32 f = 0;
- if (!_meta->HasIndexFieldInData())
- {
- *((uint32*)(&dataValue[offset])) = indexValue;
- offset += 4;
- ++f;
- }
-
- for (uint32 x = 0; x < _meta->FieldCount; ++x)
- {
- for (uint32 z = 0; z < _meta->ArraySizes[x]; ++z)
- {
- switch (_meta->Types[x])
- {
- 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);
-
- 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);
-
- 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;
- }
- }
-
- ASSERT(offset == recordSize);
- ++rec;
- } while (result->NextRow());
-
- if (!newRecords)
- {
- delete[] tempDataTable;
- delete[] newIndexes;
- return nullptr;
- }
-
- // Compact new data table to only contain new records not previously loaded from file
- char* dataTable = new char[newRecords * recordSize];
- memcpy(dataTable, tempDataTable, newRecords * recordSize);
-
- // insert new records to index table
- for (uint32 i = 0; i < newRecords; ++i)
- indexTable.Insert(newIndexes[i], &dataTable[i * recordSize]);
-
- delete[] tempDataTable;
- delete[] newIndexes;
-
- return dataTable;
-}
-
-void DB2SparseDatabaseLoader::LoadStrings(HotfixDatabaseStatements preparedStatement, uint32 locale, IndexTable const& indexTable, std::vector<char*>& stringPool)
-{
- PreparedStatement* stmt = HotfixDatabase.GetPreparedStatement(preparedStatement);
- stmt->setString(0, localeNames[locale]);
- PreparedQueryResult result = HotfixDatabase.Query(stmt);
- if (!result)
- return;
-
- size_t stringFields = _meta->GetStringFieldCount(true);
- if (result->GetFieldCount() != stringFields + 1 /*ID*/)
- return;
-
- uint32 fieldCount = _meta->FieldCount;
- uint32 recordSize = _meta->GetRecordSize();
-
- do
- {
- Field* fields = result->Fetch();
- uint32 offset = 0;
- uint32 stringFieldNumInRecord = 0;
- uint32 indexValue = fields[0].GetUInt32();
-
- // Attempt to overwrite existing data
- if (char* dataValue = indexTable.Get(indexValue))
- {
- if (!_meta->HasIndexFieldInData())
- offset += 4;
-
- for (uint32 x = 0; x < fieldCount; ++x)
- {
- for (uint32 z = 0; z < _meta->ArraySizes[x]; ++z)
- {
- switch (_meta->Types[x])
- {
- 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;
- }
- }
- }
-
- 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);
-
- } while (result->NextRow());
-
- return;
-}
-
-char* DB2SparseDatabaseLoader::AddString(char const** holder, std::string const& value)
-{
- if (!value.empty())
- {
- std::size_t existingLength = strlen(*holder);
- if (existingLength >= value.length())
- {
- // Reuse existing storage if there is enough space
- char* str = const_cast<char*>(*holder);
- memcpy(str, value.c_str(), value.length());
- str[value.length()] = '\0';
- return nullptr;
- }
-
- char* str = new char[value.length() + 1];
- memcpy(str, value.c_str(), value.length());
- str[value.length()] = '\0';
- *holder = str;
- return str;
- }
-
- return nullptr;
-}
diff --git a/src/server/shared/DataStores/DB2SparseStorageLoader.h b/src/server/shared/DataStores/DB2SparseStorageLoader.h
deleted file mode 100644
index 0936947ea6a..00000000000
--- a/src/server/shared/DataStores/DB2SparseStorageLoader.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * 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 DB2_SPARSE_FILE_LOADER_H
-#define DB2_SPARSE_FILE_LOADER_H
-
-#include "DB2Meta.h"
-#include "Utilities/ByteConverter.h"
-#include "Implementation/HotfixDatabase.h"
-#include <unordered_map>
-#include <vector>
-
-class TC_SHARED_API IndexTable
-{
-public:
- virtual void Insert(uint32 index, char* data) const = 0;
- virtual char* Get(uint32 index) const = 0;
-};
-
-template<typename T>
-class IndexTableAdapter : public IndexTable
-{
-public:
- IndexTableAdapter(std::unordered_map<uint32, T const*>& indexTable) : _indexTable(indexTable) { }
-
- void Insert(uint32 index, char* data) const override
- {
- _indexTable[index] = (T const*)data;
- }
-
- char* Get(uint32 index) const override
- {
- auto itr = _indexTable.find(index);
- if (itr != _indexTable.end())
- return (char*)itr->second;
- return nullptr;
- }
-
-private:
- std::unordered_map<uint32, T const*>& _indexTable;
-};
-
-class TC_SHARED_API DB2SparseFileLoader
-{
- public:
- DB2SparseFileLoader();
- ~DB2SparseFileLoader();
-
- bool Load(char const* filename, DB2Meta const* meta);
-
- uint32 GetNumRows() const { return recordCount; }
- uint32 GetCols() const { return fieldCount; }
- uint32 GetTableHash() const { return tableHash; }
- uint32 GetLayoutHash() const { return layoutHash; }
- bool IsLoaded() const { return (data != NULL); }
- char* AutoProduceData(IndexTable const& indexTable, uint32 locale, std::vector<char*>& stringPool);
- char* AutoProduceStrings(char* dataTable, uint32 locale);
-
-private:
-#pragma pack(push, 1)
- struct OffsetTableEntry
- {
- uint32 FileOffset;
- uint16 RecordSize;
- };
- struct FieldEntry
- {
- uint16 UnusedBits;
- uint16 Offset;
- };
-#pragma pack(pop)
-
- char const* fileName;
- DB2Meta const* meta;
-
- // WDB2 / WCH2 fields
- uint32 recordSize;
- uint32 recordCount;
- uint32 fieldCount;
- uint32 offsetsPos;
- uint32 tableHash;
- uint32 layoutHash;
- uint32 minIndex;
- uint32 maxIndex;
- uint32 localeMask;
- uint32 copyIdSize;
- uint32 metaFlags;
- FieldEntry* fields;
-
- uint32 dataStart;
- unsigned char* data;
- OffsetTableEntry* offsets;
-};
-
-class TC_SHARED_API DB2SparseDatabaseLoader
-{
-public:
- DB2SparseDatabaseLoader(std::string const& storageName, DB2Meta const* meta) : _storageName(storageName), _meta(meta) { }
-
- 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 e1f02a350af..d63217e5e1c 100644
--- a/src/server/shared/DataStores/DB2StorageLoader.cpp
+++ b/src/server/shared/DataStores/DB2StorageLoader.cpp
@@ -15,205 +15,257 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "Common.h"
#include "DB2StorageLoader.h"
#include "Database/DatabaseEnv.h"
-#include "Log.h"
+#include "DB2Meta.h"
+#include "Utilities/ByteConverter.h"
-DB2FileLoader::DB2FileLoader()
+class DB2FileLoaderImpl
{
- fileName = nullptr;
- meta = nullptr;
-
- recordSize = 0;
- recordCount = 0;
- fieldCount = 0;
- stringSize = 0;
- tableHash = 0;
- layoutHash = 0;
- minIndex = 0;
- maxIndex = 0;
- localeMask = 0;
- copyIdSize = 0;
-
- data = nullptr;
- stringTable = nullptr;
- idTable = nullptr;
- idTableSize = 0;
- copyTable = nullptr;
- fields = nullptr;
-}
-
-bool DB2FileLoader::Load(char const* filename, DB2Meta const* meta)
+public:
+ virtual ~DB2FileLoaderImpl() { }
+ virtual bool Load(char const* filename, FILE* file, DB2Meta const* meta, DB2Header const* header) = 0;
+ virtual char* AutoProduceData(uint32& count, char**& indexTable, std::vector<char*>& stringPool) = 0;
+ virtual char* AutoProduceStrings(char* dataTable, uint32 locale) = 0;
+ virtual void AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable) = 0;
+};
+
+class DB2FileLoaderRegularImpl : public DB2FileLoaderImpl
{
- if (data)
- {
- delete[] data;
- data = nullptr;
- }
-
- FILE* f = fopen(filename, "rb");
- if (!f)
- return false;
-
- fileName = filename;
- this->meta = meta;
- uint32 header;
- if (fread(&header, 4, 1, f) != 1) // Signature
- {
- fclose(f);
- return false;
- }
-
- EndianConvert(header);
-
- if (header != 0x35424457)
- {
- fclose(f);
- return false; //'WDB5'
- }
-
- if (fread(&recordCount, 4, 1, f) != 1) // Number of records
- {
- fclose(f);
- return false;
- }
+public:
+ DB2FileLoaderRegularImpl();
+ ~DB2FileLoaderRegularImpl();
- EndianConvert(recordCount);
+ bool Load(char const* filename, FILE* file, DB2Meta const* meta, DB2Header const* header) override;
+ char* AutoProduceData(uint32& count, char**& indexTable, std::vector<char*>& stringPool) override;
+ char* AutoProduceStrings(char* dataTable, uint32 locale) override;
+ void AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable) override;
- if (fread(&fieldCount, 4, 1, f) != 1) // Number of fields
+private:
+ class Record
{
- fclose(f);
- return false;
- }
-
- EndianConvert(fieldCount);
-
- if (fread(&recordSize, 4, 1, f) != 1) // Size of a record
- {
- fclose(f);
- return false;
- }
-
- EndianConvert(recordSize);
-
- if (fread(&stringSize, 4, 1, f) != 1) // String size
+ public:
+ float getFloat(uint32 field, uint32 arrayIndex) const;
+ uint32 getUInt(uint32 field, uint32 arrayIndex) const;
+ uint8 getUInt8(uint32 field, uint32 arrayIndex) const;
+ uint16 getUInt16(uint32 field, uint32 arrayIndex) const;
+ char const* getString(uint32 field, uint32 arrayIndex) const;
+
+ private:
+ uint16 GetOffset(uint32 field) const;
+ uint16 GetByteSize(uint32 field) const;
+ uint32 GetVarInt(uint32 field, uint16 size, uint32 arrayIndex) const;
+
+ Record(DB2FileLoaderRegularImpl &file_, unsigned char *offset_);
+ unsigned char *offset;
+ DB2FileLoaderRegularImpl &file;
+
+ friend class DB2FileLoaderRegularImpl;
+ };
+
+ // Get record by id
+ Record getRecord(size_t id);
+
+#pragma pack(push, 1)
+ struct FieldEntry
{
- fclose(f);
- return false;
- }
-
- EndianConvert(stringSize);
-
- if (fread(&tableHash, 4, 1, f) != 1) // Table hash
+ uint16 UnusedBits;
+ uint16 Offset;
+ };
+#pragma pack(pop)
+
+ char const* fileName;
+ DB2Meta const* meta;
+ DB2Header const* header;
+
+ unsigned char* data;
+ unsigned char* stringTable;
+ unsigned char* idTable;
+ uint32 idTableSize;
+ unsigned char* copyTable;
+ FieldEntry* fields;
+};
+
+class DB2FileLoaderSparseImpl : public DB2FileLoaderImpl
+{
+public:
+ DB2FileLoaderSparseImpl();
+ ~DB2FileLoaderSparseImpl();
+
+ bool Load(char const* filename, FILE* file, DB2Meta const* meta, DB2Header const* header) override;
+ char* AutoProduceData(uint32& records, char**& indexTable, std::vector<char*>& stringPool);
+ char* AutoProduceStrings(char* dataTable, uint32 locale) override;
+ void AutoProduceRecordCopies(uint32 /*records*/, char** /*indexTable*/, char* /*dataTable*/) override { }
+
+private:
+#pragma pack(push, 1)
+ struct OffsetTableEntry
{
- fclose(f);
- return false;
- }
-
- EndianConvert(tableHash);
-
- if (fread(&layoutHash, 4, 1, f) != 1) // Build
+ uint32 FileOffset;
+ uint16 RecordSize;
+ };
+ struct FieldEntry
{
- fclose(f);
- return false;
- }
+ uint16 UnusedBits;
+ uint16 Offset;
+ };
+#pragma pack(pop)
+
+ char const* fileName;
+ DB2Meta const* meta;
+ DB2Header const* header;
+ FieldEntry* fields;
+
+ uint32 dataStart;
+ unsigned char* data;
+ OffsetTableEntry* offsets;
+};
+
+float DB2FileLoaderRegularImpl::Record::getFloat(uint32 field, uint32 arrayIndex) const
+{
+ ASSERT(field < file.header->FieldCount);
+ float val = *reinterpret_cast<float*>(offset + GetOffset(field) + arrayIndex * sizeof(float));
+ EndianConvert(val);
+ return val;
+}
- if (layoutHash != meta->LayoutHash)
- {
- fclose(f);
- return false;
- }
+uint32 DB2FileLoaderRegularImpl::Record::getUInt(uint32 field, uint32 arrayIndex) const
+{
+ ASSERT(field < file.header->FieldCount);
+ return GetVarInt(field, GetByteSize(field), arrayIndex);
+}
- EndianConvert(layoutHash);
+uint8 DB2FileLoaderRegularImpl::Record::getUInt8(uint32 field, uint32 arrayIndex) const
+{
+ ASSERT(field < file.header->FieldCount);
+ ASSERT(GetByteSize(field) == 1);
+ return *reinterpret_cast<uint8*>(offset + GetOffset(field) + arrayIndex * sizeof(uint8));
+}
- if (fread(&minIndex, 4, 1, f) != 1) // MinIndex WDB2
- {
- fclose(f);
- return false;
- }
+uint16 DB2FileLoaderRegularImpl::Record::getUInt16(uint32 field, uint32 arrayIndex) const
+{
+ ASSERT(field < file.header->FieldCount);
+ ASSERT(GetByteSize(field) == 2);
+ uint16 val = *reinterpret_cast<uint16*>(offset + GetOffset(field) + arrayIndex * sizeof(uint16));
+ EndianConvert(val);
+ return val;
+}
- EndianConvert(minIndex);
+char const* DB2FileLoaderRegularImpl::Record::getString(uint32 field, uint32 arrayIndex) const
+{
+ ASSERT(field < file.header->FieldCount);
+ uint32 stringOffset = *reinterpret_cast<uint32*>(offset + GetOffset(field) + arrayIndex * sizeof(uint32));
+ EndianConvert(stringOffset);
+ ASSERT(stringOffset < file.header->StringTableSize);
+ return reinterpret_cast<char*>(file.stringTable + stringOffset);
+}
- if (fread(&maxIndex, 4, 1, f) != 1) // MaxIndex WDB2
- {
- fclose(f);
- return false;
- }
+uint16 DB2FileLoaderRegularImpl::Record::GetOffset(uint32 field) const
+{
+ ASSERT(field < file.header->FieldCount);
+ return file.fields[field].Offset;
+}
- EndianConvert(maxIndex);
+uint16 DB2FileLoaderRegularImpl::Record::GetByteSize(uint32 field) const
+{
+ ASSERT(field < file.header->FieldCount);
+ return 4 - file.fields[field].UnusedBits / 8;
+}
- if (fread(&localeMask, 4, 1, f) != 1) // Locales
+uint32 DB2FileLoaderRegularImpl::Record::GetVarInt(uint32 field, uint16 size, uint32 arrayIndex) const
+{
+ ASSERT(field < file.header->FieldCount);
+ switch (size)
{
- fclose(f);
- return false;
+ 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;
}
- EndianConvert(localeMask);
-
- if (fread(&copyIdSize, 4, 1, f) != 1)
- {
- fclose(f);
- return false;
- }
+ ASSERT(false, "GetByteSize(field) < 4");
+ return 0;
+}
- EndianConvert(copyIdSize);
+DB2FileLoaderRegularImpl::Record::Record(DB2FileLoaderRegularImpl &file_, unsigned char *offset_) : offset(offset_), file(file_)
+{
- if (fread(&metaFlags, 4, 1, f) != 1)
- {
- fclose(f);
- return false;
- }
+}
- EndianConvert(metaFlags);
+DB2FileLoaderRegularImpl::DB2FileLoaderRegularImpl()
+{
+ fileName = nullptr;
+ meta = nullptr;
+ header = nullptr;
+ data = nullptr;
+ stringTable = nullptr;
+ idTable = nullptr;
+ idTableSize = 0;
+ copyTable = nullptr;
+ fields = nullptr;
+}
- ASSERT((metaFlags & 0x1) == 0, "%s is a sparse storage, use DB2SparseStorage!", filename);
- ASSERT((meta->IndexField == -1) || (meta->IndexField == int32(metaFlags >> 16)));
+bool DB2FileLoaderRegularImpl::Load(char const* filename, FILE* file, DB2Meta const* meta_, DB2Header const* header_)
+{
+ meta = meta_;
+ header = header_;
+ ASSERT(meta->IndexField == -1 || meta->IndexField == int32(header->IndexField));
- fields = new FieldEntry[fieldCount];
- if (fread(fields, fieldCount * sizeof(FieldEntry), 1, f) != 1)
- {
- fclose(f);
+ fileName = filename;
+ fields = new FieldEntry[header->FieldCount];
+ if (fread(fields, header->FieldCount * sizeof(FieldEntry), 1, file) != 1)
return false;
- }
if (!meta->HasIndexFieldInData())
- idTableSize = recordCount * sizeof(uint32);
+ idTableSize = header->RecordCount * sizeof(uint32);
- data = new unsigned char[recordSize * recordCount + stringSize];
- stringTable = data + recordSize * recordCount;
+ data = new unsigned char[header->RecordSize * header->RecordCount + header->StringTableSize];
+ stringTable = data + header->RecordSize * header->RecordCount;
- if (fread(data, recordSize * recordCount + stringSize, 1, f) != 1)
- {
- fclose(f);
+ if (fread(data, header->RecordSize * header->RecordCount + header->StringTableSize, 1, file) != 1)
return false;
- }
if (idTableSize)
{
idTable = new unsigned char[idTableSize];
- if (fread(idTable, idTableSize, 1, f) != 1)
- {
- fclose(f);
+ if (fread(idTable, idTableSize, 1, file) != 1)
return false;
- }
}
- if (copyIdSize)
+ if (header->CopyTableSize)
{
- copyTable = new unsigned char[copyIdSize];
- if (fread(copyTable, copyIdSize, 1, f) != 1)
- {
- fclose(f);
+ copyTable = new unsigned char[header->CopyTableSize];
+ if (fread(copyTable, header->CopyTableSize, 1, file) != 1)
return false;
- }
}
- fclose(f);
return true;
}
-DB2FileLoader::~DB2FileLoader()
+DB2FileLoaderRegularImpl::~DB2FileLoaderRegularImpl()
{
delete[] data;
delete[] idTable;
@@ -221,16 +273,17 @@ DB2FileLoader::~DB2FileLoader()
delete[] fields;
}
-DB2FileLoader::Record DB2FileLoader::getRecord(size_t id)
+DB2FileLoaderRegularImpl::Record DB2FileLoaderRegularImpl::getRecord(size_t id)
{
assert(data);
- return Record(*this, data + id * recordSize);
+ return Record(*this, data + id * header->RecordSize);
}
-char* DB2FileLoader::AutoProduceData(uint32& records, char**& indexTable)
+static char const* const nullStr = "";
+
+char* DB2FileLoaderRegularImpl::AutoProduceData(uint32& records, char**& indexTable, std::vector<char*>& stringPool)
{
- typedef char* ptr;
- if (meta->FieldCount != fieldCount)
+ if (meta->FieldCount != header->FieldCount)
return NULL;
//get struct size and index pos
@@ -241,7 +294,7 @@ char* DB2FileLoader::AutoProduceData(uint32& records, char**& indexTable)
//find max index
if (!idTableSize)
{
- for (uint32 y = 0; y < recordCount; ++y)
+ for (uint32 y = 0; y < header->RecordCount; ++y)
{
uint32 ind = getRecord(y).getUInt(indexField, 0);
if (ind > maxi)
@@ -250,7 +303,7 @@ char* DB2FileLoader::AutoProduceData(uint32& records, char**& indexTable)
}
else
{
- for (uint32 y = 0; y < recordCount; ++y)
+ for (uint32 y = 0; y < header->RecordCount; ++y)
{
uint32 ind = ((uint32*)idTable)[y];
if (ind > maxi)
@@ -258,23 +311,44 @@ char* DB2FileLoader::AutoProduceData(uint32& records, char**& indexTable)
}
}
- for (uint32 y = 0; y < copyIdSize; y += 8)
+ for (uint32 y = 0; y < header->CopyTableSize; y += 8)
{
uint32 ind = *((uint32*)(copyTable + y));
if (ind > maxi)
maxi = ind;
}
+ using index_entry_t = char*;
+
++maxi;
records = maxi;
- indexTable = new ptr[maxi];
- memset(indexTable, 0, maxi * sizeof(ptr));
+ indexTable = new index_entry_t[maxi];
+ memset(indexTable, 0, maxi * sizeof(index_entry_t));
+
+ char* dataTable = new char[(header->RecordCount + (header->CopyTableSize / 8)) * recordsize];
+
+ // we store flat holders pool as single memory block
+ std::size_t stringFields = meta->GetStringFieldCount(false);
+ std::size_t localizedStringFields = meta->GetStringFieldCount(true);
- char* dataTable = new char[(recordCount + (copyIdSize / 8)) * recordsize];
+ // each string field at load have array of string for each locale
+ std::size_t stringHoldersRecordPoolSize = localizedStringFields * sizeof(LocalizedString) + (stringFields - localizedStringFields) * sizeof(char*);
+ char* stringHoldersPool = nullptr;
+ if (stringFields)
+ {
+ std::size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * header->RecordCount;
+
+ stringHoldersPool = new char[stringHoldersPoolSize];
+ stringPool.push_back(stringHoldersPool);
+
+ // DB2 strings expected to have at least empty string
+ for (std::size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i)
+ ((char const**)stringHoldersPool)[i] = nullStr;
+ }
uint32 offset = 0;
- for (uint32 y = 0; y < recordCount; y++)
+ for (uint32 y = 0; y < header->RecordCount; y++)
{
Record rec = getRecord(y);
uint32 indexVal = meta->HasIndexFieldInData() ? rec.getUInt(indexField, 0) : ((uint32*)idTable)[y];
@@ -287,7 +361,9 @@ char* DB2FileLoader::AutoProduceData(uint32& records, char**& indexTable)
offset += 4;
}
- for (uint32 x = 0; x < fieldCount; ++x)
+ uint32 stringFieldOffset = 0;
+
+ for (uint32 x = 0; x < header->FieldCount; ++x)
{
for (uint32 z = 0; z < meta->ArraySizes[x]; ++z)
{
@@ -311,9 +387,18 @@ char* DB2FileLoader::AutoProduceData(uint32& records, char**& indexTable)
break;
case FT_STRING:
case FT_STRING_NOT_LOCALIZED:
- *((char**)(&dataTable[offset])) = nullptr; // will be replaced by non-empty or "" strings in AutoProduceStrings
+ {
+ // 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;
@@ -325,67 +410,314 @@ char* DB2FileLoader::AutoProduceData(uint32& records, char**& indexTable)
return dataTable;
}
-static char const* const nullStr = "";
-
-char* DB2FileLoader::AutoProduceStringsArrayHolders(char* dataTable)
+char* DB2FileLoaderRegularImpl::AutoProduceStrings(char* dataTable, uint32 locale)
{
- if (meta->FieldCount != fieldCount)
+ if (meta->FieldCount != header->FieldCount)
return nullptr;
- // we store flat holders pool as single memory block
- std::size_t stringFields = meta->GetStringFieldCount(false);
- if (!stringFields)
+ if (!(header->Locale & (1 << locale)))
+ {
+ char const* sep = "";
+ std::ostringstream str;
+ for (uint32 i = 0; i < TOTAL_LOCALES; ++i)
+ {
+ if (header->Locale & (1 << i))
+ {
+ str << sep << localeNames[i];
+ sep = ", ";
+ }
+ }
+
+ TC_LOG_ERROR("", "Attempted to load %s which has locales %s as %s. Check if you placed your localized db2 files in correct directory.", fileName, str.str().c_str(), localeNames[locale]);
return nullptr;
+ }
+
+ char* stringPool = new char[header->StringTableSize];
+ memcpy(stringPool, stringTable, header->StringTableSize);
+
+ uint32 offset = 0;
+
+ for (uint32 y = 0; y < header->RecordCount; y++)
+ {
+ if (!meta->HasIndexFieldInData())
+ offset += 4;
+
+ for (uint32 x = 0; x < header->FieldCount; ++x)
+ {
+ for (uint32 z = 0; z < meta->ArraySizes[x]; ++z)
+ {
+ switch (meta->Types[x])
+ {
+ 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**)(&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, 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;
+ }
+ }
+ }
+ }
+
+ return stringPool;
+}
+
+void DB2FileLoaderRegularImpl::AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable)
+{
+ uint32 recordsize = meta->GetRecordSize();
+ uint32 offset = header->RecordCount * recordsize;
+ uint32* copyIds = (uint32*)copyTable;
+ for (uint32 c = 0; c < header->CopyTableSize / 4; c += 2)
+ {
+ uint32 to = copyIds[c];
+ uint32 from = copyIds[c + 1];
+
+ if (from && from < records && to < 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;
+ }
+ }
+}
+
+DB2FileLoaderSparseImpl::DB2FileLoaderSparseImpl()
+{
+ fileName = nullptr;
+ meta = nullptr;
+ header = nullptr;
+ fields = nullptr;
+ dataStart = 0;
+ data = nullptr;
+ offsets = nullptr;
+}
+
+bool DB2FileLoaderSparseImpl::Load(char const* filename, FILE* file, DB2Meta const* meta_, DB2Header const* header_)
+{
+ meta = meta_;
+ header = header_;
+ fileName = filename;
+
+ fields = new FieldEntry[header->FieldCount];
+ if (fread(fields, header->FieldCount * sizeof(FieldEntry), 1, file) != 1)
+ return false;
+
+ dataStart = ftell(file);
+
+ data = new unsigned char[header->StringTableSize - dataStart];
+
+ if (fread(data, header->StringTableSize - dataStart, 1, file) != 1)
+ return false;
+
+ offsets = new OffsetTableEntry[header->MaxId - header->MinId + 1];
+ if (fread(offsets, (header->MaxId - header->MinId + 1) * 6, 1, file) != 1)
+ return false;
+
+ return true;
+}
+
+DB2FileLoaderSparseImpl::~DB2FileLoaderSparseImpl()
+{
+ delete[] data;
+ delete[] offsets;
+ delete[] fields;
+}
+
+char* DB2FileLoaderSparseImpl::AutoProduceData(uint32& maxId, char**& indexTable, std::vector<char*>& stringPool)
+{
+ if (meta->FieldCount != header->FieldCount)
+ return NULL;
+
+ //get struct size and index pos
+ uint32 recordsize = meta->GetRecordSize();
+
+ uint32 offsetCount = header->MaxId - header->MinId + 1;
+ uint32 records = 0;
+ uint32 expandedDataSize = 0;
+ for (uint32 i = 0; i < offsetCount; ++i)
+ {
+ if (offsets[i].FileOffset && offsets[i].RecordSize)
+ {
+ ++records;
+ expandedDataSize += offsets[i].RecordSize;
+ }
+ }
+
+ using index_entry_t = char*;
+ maxId = header->MaxId + 1;
+ indexTable = new index_entry_t[maxId];
+ memset(indexTable, 0, maxId * sizeof(index_entry_t));
+
+ char* dataTable = new char[records * recordsize];
+
+ // we store flat holders pool as single memory block
+ 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 stringHoldersRecordPoolSize = localizedStringFields * sizeof(LocalizedString) + (stringFields - localizedStringFields) * sizeof(char*);
- std::size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * recordCount;
+ std::size_t stringHoldersPoolSize = stringHoldersRecordPoolSize * records;
char* stringHoldersPool = new char[stringHoldersPoolSize];
+ stringPool.push_back(stringHoldersPool);
// DB2 strings expected to have at least empty string
for (std::size_t i = 0; i < stringHoldersPoolSize / sizeof(char*); ++i)
((char const**)stringHoldersPool)[i] = nullStr;
- uint32 offset = 0;
+ 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;
- // assign string holders to string field slots
- for (uint32 y = 0; y < recordCount; y++)
+ uint32 offset = 0;
+ uint32 recordNum = 0;
+ for (uint32 y = 0; y < offsetCount; ++y)
{
+ if (!offsets[y].FileOffset || !offsets[y].RecordSize)
+ continue;
+
+ indexTable[y + header->MinId] = &dataTable[offset];
+ ASSERT(indexTable[y + header->MinId]);
+ std::size_t fieldOffset = 0;
uint32 stringFieldOffset = 0;
if (!meta->HasIndexFieldInData())
+ {
+ *((uint32*)(&dataTable[offset])) = y + header->MinId;
offset += 4;
+ }
- for (uint32 x = 0; x < fieldCount; ++x)
+ for (uint32 x = 0; x < header->FieldCount; ++x)
{
+ uint16 fieldBytes = 4 - fields[x].UnusedBits / 8;
for (uint32 z = 0; z < meta->ArraySizes[x]; ++z)
{
switch (meta->Types[x])
{
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 = 0;
+ 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]);
+ for (uint32 locale = 0; locale < TOTAL_LOCALES; ++locale)
+ if (header->Locale & (1 << locale))
+ (*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:
{
- // 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*);
-
+ *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;
}
@@ -395,24 +727,25 @@ char* DB2FileLoader::AutoProduceStringsArrayHolders(char* dataTable)
}
}
}
+
+ ++recordNum;
}
- //send as char* for store in char* pool list for free at unload
- return stringHoldersPool;
+ return dataTable;
}
-char* DB2FileLoader::AutoProduceStrings(char* dataTable, uint32 locale)
+char* DB2FileLoaderSparseImpl::AutoProduceStrings(char* dataTable, uint32 locale)
{
- if (meta->FieldCount != fieldCount)
+ if (meta->FieldCount != header->FieldCount)
return nullptr;
- if (!(localeMask & (1 << locale)))
+ if (!(header->Locale & (1 << locale)))
{
char const* sep = "";
std::ostringstream str;
for (uint32 i = 0; i < TOTAL_LOCALES; ++i)
{
- if (localeMask & (1 << i))
+ if (header->Locale & (1 << i))
{
str << sep << localeNames[i];
sep = ", ";
@@ -423,50 +756,64 @@ char* DB2FileLoader::AutoProduceStrings(char* dataTable, uint32 locale)
return nullptr;
}
- char* stringPool = new char[stringSize];
- memcpy(stringPool, stringTable, stringSize);
+ uint32 offsetCount = header->MaxId - header->MinId + 1;
+ uint32 records = 0;
+ for (uint32 i = 0; i < offsetCount; ++i)
+ if (offsets[i].FileOffset && offsets[i].RecordSize)
+ ++records;
+
+ uint32 recordsize = meta->GetRecordSize();
+ std::size_t stringFields = meta->GetStringFieldCount(true);
+ char* stringTable = new char[header->StringTableSize - dataStart - records * ((recordsize - (!meta->HasIndexFieldInData() ? 4 : 0)) - stringFields * sizeof(char*))];
+ memset(stringTable, 0, header->StringTableSize - dataStart - records * ((recordsize - (!meta->HasIndexFieldInData() ? 4 : 0)) - stringFields * sizeof(char*)));
+ char* stringPtr = stringTable;
uint32 offset = 0;
- for (uint32 y = 0; y < recordCount; y++)
+ for (uint32 y = 0; y < offsetCount; y++)
{
+ if (!offsets[y].FileOffset || !offsets[y].RecordSize)
+ continue;
+
if (!meta->HasIndexFieldInData())
offset += 4;
- for (uint32 x = 0; x < fieldCount; ++x)
+ std::size_t fieldOffset = 0;
+ for (uint32 x = 0; x < header->FieldCount; ++x)
{
for (uint32 z = 0; z < meta->ArraySizes[x]; ++z)
{
switch (meta->Types[x])
{
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:
{
- // 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);
- }
-
+ 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:
{
- char** db2str = (char**)(&dataTable[offset]);
- char const* st = getRecord(y).getString(x, z);
- *db2str = stringPool + (st - (char const*)stringTable);
+ fieldOffset += strlen((char*)&data[offsets[y].FileOffset - dataStart + fieldOffset]) + 1;
offset += sizeof(char*);
break;
}
@@ -478,32 +825,7 @@ char* DB2FileLoader::AutoProduceStrings(char* dataTable, uint32 locale)
}
}
- return 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;
- }
- }
+ return stringTable;
}
char* DB2DatabaseLoader::Load(HotfixDatabaseStatements preparedStatement, uint32& records, char**& indexTable, char*& stringHolders, std::vector<char*>& stringPool)
@@ -770,3 +1092,151 @@ char* DB2DatabaseLoader::AddString(char const** holder, std::string const& value
return nullptr;
}
+
+DB2FileLoader::DB2FileLoader() : _impl(nullptr)
+{
+}
+
+DB2FileLoader::~DB2FileLoader()
+{
+ delete _impl;
+}
+
+bool DB2FileLoader::Load(char const* filename, DB2Meta const* meta)
+{
+ FILE* f = fopen(filename, "rb");
+ if (!f)
+ return false;
+
+ if (fread(&_header.Signature, 4, 1, f) != 1) // Signature
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(_header.Signature);
+
+ if (_header.Signature != 0x35424457)
+ {
+ fclose(f);
+ return false; //'WDB5'
+ }
+
+ if (fread(&_header.RecordCount, 4, 1, f) != 1) // Number of records
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(_header.RecordCount);
+
+ if (fread(&_header.FieldCount, 4, 1, f) != 1) // Number of fields
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(_header.FieldCount);
+
+ if (fread(&_header.RecordSize, 4, 1, f) != 1) // Size of a record
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(_header.RecordSize);
+
+ if (fread(&_header.StringTableSize, 4, 1, f) != 1) // String size
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(_header.StringTableSize);
+
+ if (fread(&_header.TableHash, 4, 1, f) != 1) // Table hash
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(_header.TableHash);
+
+ if (fread(&_header.LayoutHash, 4, 1, f) != 1) // Layout hash
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(_header.LayoutHash);
+
+ if (_header.LayoutHash != meta->LayoutHash)
+ {
+ fclose(f);
+ return false;
+ }
+
+ if (fread(&_header.MinId, 4, 1, f) != 1) // MinIndex WDB2
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(_header.MinId);
+
+ if (fread(&_header.MaxId, 4, 1, f) != 1) // MaxIndex WDB2
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(_header.MaxId);
+
+ if (fread(&_header.Locale, 4, 1, f) != 1) // Locales
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(_header.Locale);
+
+ if (fread(&_header.CopyTableSize, 4, 1, f) != 1)
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(_header.CopyTableSize);
+
+ if (fread(&_header.Flags, 4, 1, f) != 1)
+ {
+ fclose(f);
+ return false;
+ }
+
+ EndianConvert(_header.Flags);
+
+ if (!(_header.Flags & 0x1))
+ _impl = new DB2FileLoaderRegularImpl();
+ else
+ _impl = new DB2FileLoaderSparseImpl();
+
+ bool result = _impl->Load(filename, f, meta, &_header);
+ fclose(f);
+ return result;
+}
+
+char* DB2FileLoader::AutoProduceData(uint32& count, char**& indexTable, std::vector<char*>& stringPool)
+{
+ return _impl->AutoProduceData(count, indexTable, stringPool);
+}
+
+char* DB2FileLoader::AutoProduceStrings(char* dataTable, uint32 locale)
+{
+ return _impl->AutoProduceStrings(dataTable, locale);
+}
+
+void DB2FileLoader::AutoProduceRecordCopies(uint32 records, char** indexTable, char* dataTable)
+{
+ _impl->AutoProduceRecordCopies(records, indexTable, dataTable);
+}
diff --git a/src/server/shared/DataStores/DB2StorageLoader.h b/src/server/shared/DataStores/DB2StorageLoader.h
index b302a1afe7d..4cf55becc8d 100644
--- a/src/server/shared/DataStores/DB2StorageLoader.h
+++ b/src/server/shared/DataStores/DB2StorageLoader.h
@@ -18,164 +18,49 @@
#ifndef DB2_FILE_LOADER_H
#define DB2_FILE_LOADER_H
-#include "DB2Meta.h"
-#include "Utilities/ByteConverter.h"
+#include "Define.h"
#include "Implementation/HotfixDatabase.h"
-#include "Errors.h"
-#include <vector>
+
+class DB2FileLoaderImpl;
+struct DB2Meta;
+
+#pragma pack(push, 1)
+struct DB2Header
+{
+ uint32 Signature;
+ uint32 RecordCount;
+ uint32 FieldCount;
+ uint32 RecordSize;
+ uint32 StringTableSize;
+ uint32 TableHash;
+ uint32 LayoutHash;
+ uint32 MinId;
+ uint32 MaxId;
+ uint32 Locale;
+ uint32 CopyTableSize;
+ uint16 Flags;
+ int16 IndexField;
+};
+#pragma pack(pop)
class TC_SHARED_API DB2FileLoader
{
- public:
+public:
DB2FileLoader();
~DB2FileLoader();
bool Load(char const* filename, DB2Meta const* meta);
-
- class Record
- {
- public:
- float getFloat(uint32 field, uint32 arrayIndex) const
- {
- ASSERT(field < file.fieldCount);
- float val = *reinterpret_cast<float*>(offset + GetOffset(field) + arrayIndex * sizeof(float));
- EndianConvert(val);
- return val;
- }
-
- uint32 getUInt(uint32 field, uint32 arrayIndex) const
- {
- ASSERT(field < file.fieldCount);
- return GetVarInt(field, GetByteSize(field), arrayIndex);
- }
-
- uint8 getUInt8(uint32 field, uint32 arrayIndex) const
- {
- ASSERT(field < file.fieldCount);
- ASSERT(GetByteSize(field) == 1);
- return *reinterpret_cast<uint8*>(offset + GetOffset(field) + arrayIndex * sizeof(uint8));
- }
-
- uint16 getUInt16(uint32 field, uint32 arrayIndex) const
- {
- ASSERT(field < file.fieldCount);
- ASSERT(GetByteSize(field) == 2);
- uint16 val = *reinterpret_cast<uint16*>(offset + GetOffset(field) + arrayIndex * sizeof(uint16));
- EndianConvert(val);
- return val;
- }
-
- char const* getString(uint32 field, uint32 arrayIndex) const
- {
- 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;
-
- friend class DB2FileLoader;
- };
-
- // Get record by id
- Record getRecord(size_t id);
-
- uint32 GetNumRows() const { return recordCount;}
- uint32 GetCols() const { return fieldCount; }
- uint32 GetTableHash() const { return tableHash; }
- uint32 GetLayoutHash() const { return layoutHash; }
- bool IsLoaded() const { return (data != NULL); }
- char* AutoProduceData(uint32& count, char**& indexTable);
- char* AutoProduceStringsArrayHolders(char* dataTable);
+ char* AutoProduceData(uint32& count, char**& indexTable, std::vector<char*>& stringPool);
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)
+ uint32 GetCols() const { return _header.FieldCount; }
+ uint32 GetTableHash() const { return _header.TableHash; }
+ uint32 GetLayoutHash() const { return _header.LayoutHash; }
- char const* fileName;
- DB2Meta const* meta;
-
- // WDB2 / WCH2 fields
- uint32 recordSize;
- uint32 recordCount;
- uint32 fieldCount;
- uint32 stringSize;
- uint32 tableHash;
- uint32 layoutHash;
- uint32 minIndex;
- uint32 maxIndex;
- uint32 localeMask;
- uint32 copyIdSize;
- uint32 metaFlags;
-
- unsigned char* data;
- unsigned char* stringTable;
- unsigned char* idTable;
- uint32 idTableSize;
- unsigned char* copyTable;
- FieldEntry* fields;
+private:
+ DB2FileLoaderImpl* _impl;
+ DB2Header _header;
};
class TC_SHARED_API DB2DatabaseLoader
diff --git a/src/server/shared/DataStores/DB2Store.h b/src/server/shared/DataStores/DB2Store.h
index bf10d78f37b..0c63feba93c 100644
--- a/src/server/shared/DataStores/DB2Store.h
+++ b/src/server/shared/DataStores/DB2Store.h
@@ -19,8 +19,8 @@
#define DB2STORE_H
#include "Common.h"
+#include "DB2Meta.h"
#include "DB2StorageLoader.h"
-#include "DB2SparseStorageLoader.h"
#include "DBStorageIterator.h"
#include "ByteBuffer.h"
@@ -163,17 +163,12 @@ public:
_layoutHash = db2.GetLayoutHash();
// load raw non-string data
- _dataTable = db2.AutoProduceData(_indexTableSize, _indexTable.AsChar);
+ _dataTable = db2.AutoProduceData(_indexTableSize, _indexTable.AsChar, _stringPool);
- // create string holders for loaded string fields
- if (char* stringHolders = db2.AutoProduceStringsArrayHolders(_dataTable))
- {
- _stringPool.push_back(stringHolders);
-
- // load strings from db2 data
+ // load strings from db2 data
+ if (!_stringPool.empty())
if (char* stringBlock = db2.AutoProduceStrings(_dataTable, locale))
_stringPool.push_back(stringBlock);
- }
db2.AutoProduceRecordCopies(_indexTableSize, _indexTable.AsChar, _dataTable);
@@ -227,107 +222,4 @@ private:
uint32 _indexTableSize;
};
-template<class T>
-class DB2SparseStorage : public DB2StorageBase
-{
- static_assert(std::is_pod<T>::value, "T in DB2SparseStorage must be POD-type.");
-
-public:
- typedef struct iterator_wrapper : public std::unordered_map<uint32, T const*>::const_iterator
- {
- typedef typename std::unordered_map<uint32, T const*>::const_iterator Base;
-
- iterator_wrapper() = default;
- iterator_wrapper(iterator_wrapper const& right) = default;
- iterator_wrapper(Base const& baseItr) : Base(baseItr) { }
-
- T const* operator->() const { return Base::operator->()->second; }
- T const* operator*() const { return Base::operator*().second; }
- } iterator;
-
- DB2SparseStorage(char const* fileName, DB2Meta const* meta, HotfixDatabaseStatements preparedStmtIndex)
- : DB2StorageBase(fileName, meta, preparedStmtIndex)
- {
- }
-
- ~DB2SparseStorage()
- {
- }
-
- bool HasRecord(uint32 id) const override { return _indexTable.count(id) > 0; }
- void WriteRecord(uint32 id, uint32 locale, ByteBuffer& buffer) const override
- {
- WriteRecordData(reinterpret_cast<char const*>(AssertEntry(id)), locale, buffer);
- }
-
- void EraseRecord(uint32 id) override { _indexTable.erase(id); }
-
- T const* LookupEntry(uint32 id) const
- {
- auto itr = _indexTable.find(id);
- if (itr != _indexTable.end())
- return itr->second;
- return nullptr;
- }
-
- T const* AssertEntry(uint32 id) const { return ASSERT_NOTNULL(LookupEntry(id)); }
-
- uint32 GetNumRows() const { return _indexTable.size(); }
-
- bool Load(std::string const& path, uint32 locale) override
- {
- DB2SparseFileLoader db2;
- // Check if load was successful, only then continue
- if (!db2.Load((path + _fileName).c_str(), _meta))
- return false;
-
- _fieldCount = db2.GetCols();
- _tableHash = db2.GetTableHash();
- _layoutHash = db2.GetLayoutHash();
-
- // load raw non-string data
- _dataTable = db2.AutoProduceData(IndexTableAdapter<T>(_indexTable), locale, _stringPool);
-
- // error in db2 file at loading if NULL
- return !_indexTable.empty();
- }
-
- bool LoadStringsFrom(std::string const& path, uint32 locale) override
- {
- // DB2 must be already loaded using Load
- if (_indexTable.empty())
- return false;
-
- DB2SparseFileLoader db2;
- // Check if load was successful, only then continue
- if (!db2.Load((path + _fileName).c_str(), _meta))
- return false;
-
- // load strings from another locale db2 data
- if (_meta->GetStringFieldCount(true))
- if (char* stringBlock = db2.AutoProduceStrings(_dataTable, locale))
- _stringPool.push_back(stringBlock);
- return true;
- }
-
- void LoadFromDB() override
- {
- _dataTableEx = DB2SparseDatabaseLoader(_fileName, _meta).Load(_hotfixStatement, IndexTableAdapter<T>(_indexTable), _stringPool);
- }
-
- void LoadStringsFromDB(uint32 locale) override
- {
- if (!_meta->GetStringFieldCount(true))
- return;
-
- DB2SparseDatabaseLoader(_fileName, _meta).LoadStrings(HotfixDatabaseStatements(_hotfixStatement + 1), locale, IndexTableAdapter<T>(_indexTable), _stringPool);
- }
-
- iterator begin() const { return iterator(_indexTable.begin()); }
- iterator end() const { return iterator(_indexTable.end()); }
-
-private:
- std::unordered_map<uint32, T const*> _indexTable;
-};
-
#endif