aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmake/macros/ConfigureBoost.cmake2
-rw-r--r--sql/updates/hotfixes/2015_08_30_00_hotfixes.sql37
-rw-r--r--src/common/Define.h1
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.cpp9
-rw-r--r--src/server/database/Database/Implementation/HotfixDatabase.h6
-rw-r--r--src/server/game/DataStores/DB2Stores.cpp41
-rw-r--r--src/server/game/DataStores/DB2Stores.h4
-rw-r--r--src/server/game/DataStores/DB2Structure.h20
-rw-r--r--src/server/game/DataStores/DB2fmt.h3
-rw-r--r--src/server/game/Entities/Player/Player.cpp2
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp4
-rw-r--r--src/server/game/Globals/ObjectMgr.h2
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp8
-rw-r--r--src/server/game/Tools/PlayerDump.cpp2
-rw-r--r--src/server/scripts/Commands/cs_character.cpp4
-rw-r--r--src/server/shared/DataStores/DB2StorageLoader.cpp94
-rw-r--r--src/server/shared/DataStores/DB2StorageLoader.h6
-rw-r--r--src/server/shared/DataStores/DB2Store.h17
18 files changed, 226 insertions, 36 deletions
diff --git a/cmake/macros/ConfigureBoost.cmake b/cmake/macros/ConfigureBoost.cmake
index 98caa5eb227..022d84246ef 100644
--- a/cmake/macros/ConfigureBoost.cmake
+++ b/cmake/macros/ConfigureBoost.cmake
@@ -29,7 +29,7 @@ if(WIN32)
add_definitions(-D_WIN32_WINNT=${ver})
endif()
-find_package(Boost 1.49 REQUIRED system filesystem thread program_options iostreams)
+find_package(Boost 1.49 REQUIRED system filesystem thread program_options iostreams regex)
add_definitions(-DBOOST_DATE_TIME_NO_LIB)
add_definitions(-DBOOST_REGEX_NO_LIB)
add_definitions(-DBOOST_CHRONO_NO_LIB)
diff --git a/sql/updates/hotfixes/2015_08_30_00_hotfixes.sql b/sql/updates/hotfixes/2015_08_30_00_hotfixes.sql
new file mode 100644
index 00000000000..820b5a52308
--- /dev/null
+++ b/sql/updates/hotfixes/2015_08_30_00_hotfixes.sql
@@ -0,0 +1,37 @@
+--
+-- Table structure for table `names_profanity`
+--
+
+DROP TABLE IF EXISTS `names_profanity`;
+CREATE TABLE `names_profanity` (
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `Name` text,
+ `Language` int(10) NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `names_reserved`
+--
+
+DROP TABLE IF EXISTS `names_reserved`;
+CREATE TABLE `names_reserved` (
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `Name` text,
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+--
+-- Table structure for table `names_reserved_locale`
+--
+
+DROP TABLE IF EXISTS `names_reserved_locale`;
+CREATE TABLE `names_reserved_locale` (
+ `ID` int(10) unsigned NOT NULL DEFAULT '0',
+ `Name` text,
+ `LocaleMask` int(10) unsigned NOT NULL DEFAULT '0',
+ `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`ID`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
diff --git a/src/common/Define.h b/src/common/Define.h
index cf288c3053f..92962bfab79 100644
--- a/src/common/Define.h
+++ b/src/common/Define.h
@@ -111,6 +111,7 @@ enum DBCFormer
FT_NA = 'x', //not used or unknown, 4 byte size
FT_NA_BYTE = 'X', //not used or unknown, byte
FT_STRING = 's', //char*
+ FT_STRING_NOT_LOCALIZED = 'S', //char* but without locale in DB2
FT_FLOAT = 'f', //float
FT_INT = 'i', //uint32
FT_BYTE = 'b', //uint8
diff --git a/src/server/database/Database/Implementation/HotfixDatabase.cpp b/src/server/database/Database/Implementation/HotfixDatabase.cpp
index ff3f8e906c7..927e7f623d8 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.cpp
+++ b/src/server/database/Database/Implementation/HotfixDatabase.cpp
@@ -291,6 +291,15 @@ void HotfixDatabaseConnection::DoPrepareStatements()
PrepareStatement(HOTFIX_SEL_NAME_GEN, "SELECT ID, Name, Race, Sex FROM name_gen ORDER BY ID DESC", CONNECTION_SYNCH);
PREPARE_LOCALE_STMT(HOTFIX_SEL_NAME_GEN, "SELECT ID, Name_lang FROM name_gen_locale WHERE locale = ?", CONNECTION_SYNCH);
+ // NamesProfanity.db2
+ PrepareStatement(HOTFIX_SEL_NAMES_PROFANITY, "SELECT ID, Name, Language FROM names_profanity ORDER BY ID DESC", CONNECTION_SYNCH);
+
+ // NamesReserved.db2
+ PrepareStatement(HOTFIX_SEL_NAMES_RESERVED, "SELECT ID, Name FROM names_reserved ORDER BY ID DESC", CONNECTION_SYNCH);
+
+ // NamesReservedLocale.db2
+ PrepareStatement(HOTFIX_SEL_NAMES_RESERVED_LOCALE, "SELECT ID, Name, LocaleMask FROM names_reserved_locale ORDER BY ID DESC", CONNECTION_SYNCH);
+
// OverrideSpellData.db2
PrepareStatement(HOTFIX_SEL_OVERRIDE_SPELL_DATA, "SELECT ID, SpellID1, SpellID2, SpellID3, SpellID4, SpellID5, SpellID6, SpellID7, SpellID8, "
"SpellID9, SpellID10, Flags, PlayerActionbarFileDataID FROM override_spell_data 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 abc584a8b20..c181ef9e9e6 100644
--- a/src/server/database/Database/Implementation/HotfixDatabase.h
+++ b/src/server/database/Database/Implementation/HotfixDatabase.h
@@ -168,6 +168,12 @@ enum HotfixDatabaseStatements
HOTFIX_SEL_NAME_GEN,
HOTFIX_SEL_NAME_GEN_LOCALE,
+ HOTFIX_SEL_NAMES_PROFANITY,
+
+ HOTFIX_SEL_NAMES_RESERVED,
+
+ HOTFIX_SEL_NAMES_RESERVED_LOCALE,
+
HOTFIX_SEL_OVERRIDE_SPELL_DATA,
HOTFIX_SEL_PHASE_X_PHASE_GROUP,
diff --git a/src/server/game/DataStores/DB2Stores.cpp b/src/server/game/DataStores/DB2Stores.cpp
index 88ed3989efa..66321a1c6b1 100644
--- a/src/server/game/DataStores/DB2Stores.cpp
+++ b/src/server/game/DataStores/DB2Stores.cpp
@@ -82,6 +82,9 @@ DB2Storage<MountCapabilityEntry> sMountCapabilityStore("MountCapa
DB2Storage<MountEntry> sMountStore("Mount.db2", MountFormat, HOTFIX_SEL_MOUNT);
DB2Storage<MountTypeXCapabilityEntry> sMountTypeXCapabilityStore("MountTypeXCapability.db2", MountTypeXCapabilityFormat, HOTFIX_SEL_MOUNT_TYPE_X_CAPABILITY);
DB2Storage<NameGenEntry> sNameGenStore("NameGen.db2", NameGenFormat, HOTFIX_SEL_NAME_GEN);
+DB2Storage<NamesProfanityEntry> sNamesProfanityStore("NamesProfanity.db2", NamesProfanityFormat, HOTFIX_SEL_NAMES_PROFANITY);
+DB2Storage<NamesReservedEntry> sNamesReservedStore("NamesReserved.db2", NamesReservedFormat, HOTFIX_SEL_NAMES_RESERVED);
+DB2Storage<NamesReservedLocaleEntry> sNamesReservedLocaleStore("NamesReservedLocale.db2", NamesReservedLocaleFormat, HOTFIX_SEL_NAMES_RESERVED_LOCALE);
DB2Storage<OverrideSpellDataEntry> sOverrideSpellDataStore("OverrideSpellData.db2", OverrideSpellDataFormat, HOTFIX_SEL_OVERRIDE_SPELL_DATA);
DB2Storage<PhaseXPhaseGroupEntry> sPhaseXPhaseGroupStore("PhaseXPhaseGroup.db2", PhaseXPhaseGroupFormat, HOTFIX_SEL_PHASE_X_PHASE_GROUP);
DB2Storage<QuestMoneyRewardEntry> sQuestMoneyRewardStore("QuestMoneyReward.db2", QuestMoneyRewardFormat, HOTFIX_SEL_QUEST_MONEY_REWARD);
@@ -244,6 +247,9 @@ void DB2Manager::LoadStores(std::string const& dataPath)
LOAD_DB2(sMountStore);
LOAD_DB2(sMountTypeXCapabilityStore);
LOAD_DB2(sNameGenStore);
+ LOAD_DB2(sNamesProfanityStore);
+ LOAD_DB2(sNamesReservedStore);
+ LOAD_DB2(sNamesReservedLocaleStore);
LOAD_DB2(sOverrideSpellDataStore);
LOAD_DB2(sPhaseXPhaseGroupStore);
LOAD_DB2(sQuestMoneyRewardStore);
@@ -349,6 +355,27 @@ void DB2Manager::LoadStores(std::string const& dataPath)
for (NameGenEntry const* entry : sNameGenStore)
_nameGenData[entry->Race][entry->Sex].push_back(entry);
+ for (NamesProfanityEntry const* namesProfanity : sNamesProfanityStore)
+ {
+ ASSERT(namesProfanity->Language < TOTAL_LOCALES || namesProfanity->Language == -1);
+ if (namesProfanity->Language != -1)
+ _nameValidators[namesProfanity->Language].emplace_back(namesProfanity->Name, boost::regex::perl | boost::regex::icase | boost::regex::optimize);
+ else
+ for (uint32 i = 0; i < TOTAL_LOCALES; ++i)
+ _nameValidators[i].emplace_back(namesProfanity->Name, boost::regex::perl | boost::regex::icase | boost::regex::optimize);
+ }
+
+ for (NamesReservedEntry const* namesReserved : sNamesReservedStore)
+ _nameValidators[TOTAL_LOCALES].emplace_back(namesReserved->Name, boost::regex::perl | boost::regex::icase | boost::regex::optimize);
+
+ for (NamesReservedLocaleEntry const* namesReserved : sNamesReservedLocaleStore)
+ {
+ ASSERT(!(namesReserved->LocaleMask & ~((1 << TOTAL_LOCALES) - 1)));
+ for (uint32 i = 0; i < TOTAL_LOCALES; ++i)
+ if (namesReserved->LocaleMask & (1 << i))
+ _nameValidators[i].emplace_back(namesReserved->Name, boost::regex::perl | boost::regex::icase | boost::regex::optimize);
+ }
+
for (PhaseXPhaseGroupEntry const* group : sPhaseXPhaseGroupStore)
if (PhaseEntry const* phase = sPhaseStore.LookupEntry(group->PhaseID))
_phasesByGroup[group->PhaseGroupID].insert(phase->ID);
@@ -711,6 +738,20 @@ DB2Manager::MountTypeXCapabilitySet const* DB2Manager::GetMountCapabilities(uint
return nullptr;
}
+ResponseCodes DB2Manager::ValidateName(std::string const& name, LocaleConstant locale) const
+{
+ for (boost::regex const& regex : _nameValidators[locale])
+ if (boost::regex_search(name, regex))
+ return CHAR_NAME_PROFANE;
+
+ // regexes at TOTAL_LOCALES are loaded from NamesReserved which is not locale specific
+ for (boost::regex const& regex : _nameValidators[TOTAL_LOCALES])
+ if (boost::regex_search(name, regex))
+ return CHAR_NAME_RESERVED;
+
+ return CHAR_NAME_SUCCESS;
+}
+
std::vector<QuestPackageItemEntry const*> const* DB2Manager::GetQuestPackageItems(uint32 questPackageID) const
{
auto itr = _questPackages.find(questPackageID);
diff --git a/src/server/game/DataStores/DB2Stores.h b/src/server/game/DataStores/DB2Stores.h
index 98c36fe4b1d..6ccf3933984 100644
--- a/src/server/game/DataStores/DB2Stores.h
+++ b/src/server/game/DataStores/DB2Stores.h
@@ -21,6 +21,7 @@
#include "DB2Store.h"
#include "DB2Structure.h"
#include "SharedDefines.h"
+#include <boost/regex.hpp>
#include <array>
extern DB2Storage<AuctionHouseEntry> sAuctionHouseStore;
@@ -142,6 +143,7 @@ public:
typedef std::set<MountTypeXCapabilityEntry const*, MountTypeXCapabilityEntryComparator> MountTypeXCapabilitySet;
typedef std::unordered_map<uint32, MountTypeXCapabilitySet> MountCapabilitiesByTypeContainer;
typedef std::unordered_map<uint32, std::array<std::vector<NameGenEntry const*>, 2>> NameGenContainer;
+ typedef std::array<std::vector<boost::regex>, TOTAL_LOCALES + 1> NameValidationRegexContainer;
typedef std::unordered_map<uint32, std::set<uint32>> PhaseGroupContainer;
typedef std::unordered_map<uint32, std::vector<QuestPackageItemEntry const*>> QuestPackageItemContainer;
typedef std::unordered_map<uint32, std::vector<SpecializationSpellsEntry const*>> SpecializationSpellsContainer;
@@ -176,6 +178,7 @@ public:
MountEntry const* GetMount(uint32 spellId) const;
MountEntry const* GetMountById(uint32 id) const;
MountTypeXCapabilitySet const* GetMountCapabilities(uint32 mountType) const;
+ ResponseCodes ValidateName(std::string const& name, LocaleConstant locale) const;
std::vector<QuestPackageItemEntry const*> const* GetQuestPackageItems(uint32 questPackageID) const;
uint32 GetQuestUniqueBitFlag(uint32 questId);
std::set<uint32> GetPhasesForGroup(uint32 group) const;
@@ -200,6 +203,7 @@ private:
MountContainer _mountsBySpellId;
MountCapabilitiesByTypeContainer _mountCapabilitiesByType;
NameGenContainer _nameGenData;
+ NameValidationRegexContainer _nameValidators;
PhaseGroupContainer _phasesByGroup;
QuestPackageItemContainer _questPackages;
SpecializationSpellsContainer _specializationSpellsBySpec;
diff --git a/src/server/game/DataStores/DB2Structure.h b/src/server/game/DataStores/DB2Structure.h
index b8bb0f2a94d..b0b99b20959 100644
--- a/src/server/game/DataStores/DB2Structure.h
+++ b/src/server/game/DataStores/DB2Structure.h
@@ -727,6 +727,26 @@ struct NameGenEntry
uint32 Sex; // 3
};
+struct NamesProfanityEntry
+{
+ uint32 ID; // 0
+ char const* Name; // 1
+ int32 Language; // 2
+};
+
+struct NamesReservedEntry
+{
+ uint32 ID; // 0
+ char const* Name; // 1
+};
+
+struct NamesReservedLocaleEntry
+{
+ uint32 ID; // 0
+ char const* Name; // 1
+ uint32 LocaleMask; // 2
+};
+
#define MAX_OVERRIDE_SPELL 10
struct OverrideSpellDataEntry
diff --git a/src/server/game/DataStores/DB2fmt.h b/src/server/game/DataStores/DB2fmt.h
index a9da1ae646a..6088ff82ec0 100644
--- a/src/server/game/DataStores/DB2fmt.h
+++ b/src/server/game/DataStores/DB2fmt.h
@@ -76,6 +76,9 @@ char const MountCapabilityFormat[] = "niiiiiii";
char const MountFormat[] = "niiiisssii";
char const MountTypeXCapabilityFormat[] = "niii";
char const NameGenFormat[] = "nsii";
+char const NamesProfanityFormat[] = "nSi";
+char const NamesReservedFormat[] = "nS";
+char const NamesReservedLocaleFormat[] = "nSi";
char const OverrideSpellDataFormat[] = "niiiiiiiiiiii";
char const PhaseXPhaseGroupFormat[] = "nii";
char const QuestMoneyRewardFormat[] = "niiiiiiiiii";
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 5003cd52d74..9012be79547 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -16717,7 +16717,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder *holder)
m_name = fields[2].GetString();
// check name limitations
- if (ObjectMgr::CheckPlayerName(m_name) != CHAR_NAME_SUCCESS ||
+ if (ObjectMgr::CheckPlayerName(m_name, GetSession()->GetSessionDbcLocale()) != CHAR_NAME_SUCCESS ||
(!GetSession()->HasPermission(rbac::RBAC_PERM_SKIP_CHECK_CHARACTER_CREATION_RESERVEDNAME) &&
sObjectMgr->IsReservedName(m_name)))
{
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 459de1bdcd9..463158762c2 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -7509,7 +7509,7 @@ bool isValidString(const std::wstring& wstr, uint32 strictMask, bool numericOrSp
return false;
}
-ResponseCodes ObjectMgr::CheckPlayerName(const std::string& name, bool create)
+ResponseCodes ObjectMgr::CheckPlayerName(std::string const& name, LocaleConstant locale, bool create /*= false*/)
{
std::wstring wname;
if (!Utf8toWStr(name, wname))
@@ -7531,7 +7531,7 @@ ResponseCodes ObjectMgr::CheckPlayerName(const std::string& name, bool create)
if (wname[i] == wname[i-1] && wname[i] == wname[i-2])
return CHAR_NAME_THREE_CONSECUTIVE;
- return CHAR_NAME_SUCCESS;
+ return sDB2Manager.ValidateName(name, locale);
}
bool ObjectMgr::IsValidCharterName(const std::string& name)
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index 1ae3e113331..8e660e3f32c 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -1229,7 +1229,7 @@ class ObjectMgr
bool IsReservedName(std::string const& name) const;
// name with valid structure and symbols
- static ResponseCodes CheckPlayerName(std::string const& name, bool create = false);
+ static ResponseCodes CheckPlayerName(std::string const& name, LocaleConstant locale, bool create = false);
static PetNameInvalidReason CheckPetName(std::string const& name);
static bool IsValidCharterName(std::string const& name);
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 3dc6b72157a..dfbd48f0dec 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -458,7 +458,7 @@ void WorldSession::HandleCharCreateOpcode(WorldPackets::Character::CreateCharact
}
// check name limitations
- ResponseCodes res = ObjectMgr::CheckPlayerName(charCreate.CreateInfo->Name, true);
+ ResponseCodes res = ObjectMgr::CheckPlayerName(charCreate.CreateInfo->Name, GetSessionDbcLocale(), true);
if (res != CHAR_NAME_SUCCESS)
{
SendCharCreate(res);
@@ -1271,7 +1271,7 @@ void WorldSession::HandleCharRenameOpcode(WorldPackets::Character::CharacterRena
return;
}
- ResponseCodes res = ObjectMgr::CheckPlayerName(request.RenameInfo->NewName, true);
+ ResponseCodes res = ObjectMgr::CheckPlayerName(request.RenameInfo->NewName, GetSessionDbcLocale(), true);
if (res != CHAR_NAME_SUCCESS)
{
SendCharRename(res, request.RenameInfo.get());
@@ -1567,7 +1567,7 @@ void WorldSession::HandleCharCustomizeCallback(PreparedQueryResult result, World
return;
}
- ResponseCodes res = ObjectMgr::CheckPlayerName(customizeInfo->CharName, true);
+ ResponseCodes res = ObjectMgr::CheckPlayerName(customizeInfo->CharName, GetSessionDbcLocale(), true);
if (res != CHAR_NAME_SUCCESS)
{
SendCharCustomize(res, customizeInfo);
@@ -1811,7 +1811,7 @@ void WorldSession::HandleCharRaceOrFactionChangeCallback(PreparedQueryResult res
return;
}
- ResponseCodes res = ObjectMgr::CheckPlayerName(factionChangeInfo->Name, true);
+ ResponseCodes res = ObjectMgr::CheckPlayerName(factionChangeInfo->Name, GetSessionDbcLocale(), true);
if (res != CHAR_NAME_SUCCESS)
{
SendCharFactionChange(res, factionChangeInfo);
diff --git a/src/server/game/Tools/PlayerDump.cpp b/src/server/game/Tools/PlayerDump.cpp
index 71719c19b3a..900be2ba44a 100644
--- a/src/server/game/Tools/PlayerDump.cpp
+++ b/src/server/game/Tools/PlayerDump.cpp
@@ -435,7 +435,7 @@ DumpReturn PlayerDumpReader::LoadDump(std::string const& file, uint32 account, s
if (!normalizePlayerName(name))
name.clear();
- if (ObjectMgr::CheckPlayerName(name, true) == CHAR_NAME_SUCCESS)
+ if (ObjectMgr::CheckPlayerName(name, sWorld->GetDefaultDbcLocale(), true) == CHAR_NAME_SUCCESS)
{
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHECK_NAME);
stmt->setString(0, name);
diff --git a/src/server/scripts/Commands/cs_character.cpp b/src/server/scripts/Commands/cs_character.cpp
index 93a4a526786..ef39e2feb98 100644
--- a/src/server/scripts/Commands/cs_character.cpp
+++ b/src/server/scripts/Commands/cs_character.cpp
@@ -336,7 +336,7 @@ public:
return false;
}
- if (ObjectMgr::CheckPlayerName(newName, true) != CHAR_NAME_SUCCESS)
+ if (ObjectMgr::CheckPlayerName(newName, target ? target->GetSession()->GetSessionDbcLocale() : sWorld->GetDefaultDbcLocale(), true) != CHAR_NAME_SUCCESS)
{
handler->SendSysMessage(LANG_BAD_VALUE);
handler->SetSentErrorMessage(true);
@@ -896,7 +896,7 @@ public:
return false;
}
- if (ObjectMgr::CheckPlayerName(name, true) != CHAR_NAME_SUCCESS)
+ if (ObjectMgr::CheckPlayerName(name, sWorld->GetDefaultDbcLocale(), true) != CHAR_NAME_SUCCESS)
{
handler->PSendSysMessage(LANG_INVALID_CHARACTER_NAME);
handler->SetSentErrorMessage(true);
diff --git a/src/server/shared/DataStores/DB2StorageLoader.cpp b/src/server/shared/DataStores/DB2StorageLoader.cpp
index 763819695b7..a67d921ba90 100644
--- a/src/server/shared/DataStores/DB2StorageLoader.cpp
+++ b/src/server/shared/DataStores/DB2StorageLoader.cpp
@@ -22,13 +22,14 @@
DB2FileLoader::DB2FileLoader()
{
+ fileName = nullptr;
recordSize = 0;
recordCount = 0;
fieldCount = 0;
stringSize = 0;
- fieldsOffset = NULL;
- data = NULL;
- stringTable = NULL;
+ fieldsOffset = nullptr;
+ data = nullptr;
+ stringTable = nullptr;
tableHash = 0;
build = 0;
@@ -36,7 +37,7 @@ DB2FileLoader::DB2FileLoader()
unk1 = 0;
minIndex = 0;
maxIndex = 0;
- locale = 0;
+ localeMask = 0;
unk5 = 0;
}
@@ -44,14 +45,15 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
{
if (data)
{
- delete [] data;
- data = NULL;
+ delete[] data;
+ data = nullptr;
}
FILE* f = fopen(filename, "rb");
if (!f)
return false;
+ fileName = filename;
uint32 header;
if (fread(&header, 4, 1, f) != 1) // Signature
{
@@ -140,13 +142,13 @@ bool DB2FileLoader::Load(const char *filename, const char *fmt)
EndianConvert(maxIndex);
- if (fread(&locale, 4, 1, f) != 1) // Locales
+ if (fread(&localeMask, 4, 1, f) != 1) // Locales
{
fclose(f);
return false;
}
- EndianConvert(locale);
+ EndianConvert(localeMask);
if (fread(&unk5, 4, 1, f) != 1) // Unknown WDB2
{
@@ -213,6 +215,7 @@ uint32 DB2FileLoader::GetFormatRecordSize(const char * format, int32* index_pos)
recordsize += 4;
break;
case FT_STRING:
+ case FT_STRING_NOT_LOCALIZED:
recordsize += sizeof(char*);
break;
case FT_SORT:
@@ -234,7 +237,17 @@ uint32 DB2FileLoader::GetFormatRecordSize(const char * format, int32* index_pos)
return recordsize;
}
-uint32 DB2FileLoader::GetFormatStringFieldCount(char const* format)
+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)
@@ -305,7 +318,8 @@ char* DB2FileLoader::AutoProduceData(const char* format, uint32& records, char**
offset += 1;
break;
case FT_STRING:
- *((char**)(&dataTable[offset])) = NULL; // will be replaces non-empty or "" strings in AutoProduceStrings
+ case FT_STRING_NOT_LOCALIZED:
+ *((char**)(&dataTable[offset])) = nullptr; // will be replaces non-empty or "" strings in AutoProduceStrings
offset += sizeof(char*);
break;
}
@@ -358,6 +372,7 @@ char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* da
offset += 1;
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]);
@@ -379,7 +394,24 @@ char* DB2FileLoader::AutoProduceStringsArrayHolders(const char* format, char* da
char* DB2FileLoader::AutoProduceStrings(const char* format, char* dataTable, uint32 locale)
{
if (strlen(format) != fieldCount)
- return NULL;
+ 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;
+ }
char* stringPool = new char[stringSize];
memcpy(stringPool, stringTable, stringSize);
@@ -406,13 +438,21 @@ char* DB2FileLoader::AutoProduceStrings(const char* format, char* dataTable, uin
LocalizedString* db2str = *(LocalizedString**)(&dataTable[offset]);
if (db2str->Str[locale] == nullStr)
{
- const char * st = getRecord(y).getString(x);
- db2str->Str[locale] = stringPool + (st - (const char*)stringTable);
+ char const* st = getRecord(y).getString(x);
+ 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;
+ }
}
}
}
@@ -524,7 +564,21 @@ char* DB2DatabaseLoader::Load(const char* format, HotfixDatabaseStatements prepa
ASSERT(*slot);
// Value in database in main table field must be for enUS locale
- if (char* str = AddLocaleString(*slot, LOCALE_enUS, fields[f].GetString()))
+ if (char* str = AddString(&(*slot)->Str[LOCALE_enUS], fields[f].GetStringView()))
+ 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);
+
+ // Value in database in main table field must be for enUS locale
+ if (char* str = AddString(slot, fields[f].GetStringView()))
stringPool.push_back(str);
++stringFieldNumInRecord;
@@ -569,7 +623,7 @@ void DB2DatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStatements
if (!result)
return;
- size_t stringFields = DB2FileLoader::GetFormatStringFieldCount(format);
+ size_t stringFields = DB2FileLoader::GetFormatLocalizedStringFieldCount(format);
if (result->GetFieldCount() != stringFields + 1 /*ID*/)
return;
@@ -605,7 +659,7 @@ void DB2DatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStatements
// fill only not filled entries
LocalizedString* db2str = *(LocalizedString**)(&dataValue[offset]);
if (db2str->Str[locale] == nullStr)
- if (char* str = AddLocaleString(db2str, locale, fields[1 + stringFieldNumInRecord].GetString()))
+ if (char* str = AddString(&db2str->Str[locale], fields[1 + stringFieldNumInRecord].GetStringView()))
stringPool.push_back(str);
++stringFieldNumInRecord;
@@ -625,15 +679,15 @@ void DB2DatabaseLoader::LoadStrings(const char* format, HotfixDatabaseStatements
return;
}
-char* DB2DatabaseLoader::AddLocaleString(LocalizedString* holder, uint32 locale, std::string const& value)
+char* DB2DatabaseLoader::AddString(char const** holder, std::string const& value)
{
if (!value.empty())
{
- std::size_t existingLength = strlen(holder->Str[locale]);
+ std::size_t existingLength = strlen(*holder);
if (existingLength >= value.length())
{
// Reuse existing storage if there is enough space
- char* str = const_cast<char*>(holder->Str[locale]);
+ char* str = const_cast<char*>(*holder);
memcpy(str, value.c_str(), value.length());
str[value.length()] = '\0';
return nullptr;
@@ -642,7 +696,7 @@ char* DB2DatabaseLoader::AddLocaleString(LocalizedString* holder, uint32 locale,
char* str = new char[value.length() + 1];
memcpy(str, value.c_str(), value.length());
str[value.length()] = '\0';
- holder->Str[locale] = str;
+ *holder = str;
return str;
}
diff --git a/src/server/shared/DataStores/DB2StorageLoader.h b/src/server/shared/DataStores/DB2StorageLoader.h
index e209955025a..587174a804b 100644
--- a/src/server/shared/DataStores/DB2StorageLoader.h
+++ b/src/server/shared/DataStores/DB2StorageLoader.h
@@ -85,7 +85,9 @@ class DB2FileLoader
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);
private:
+ char const* fileName;
uint32 recordSize;
uint32 recordCount;
@@ -102,7 +104,7 @@ private:
int unk1; // WDB2 (Unix time in WCH2)
int minIndex; // WDB2
int maxIndex; // WDB2 (index table)
- int locale; // WDB2
+ int localeMask; // WDB2
int unk5; // WDB2
};
@@ -113,7 +115,7 @@ public:
char* Load(const char* format, HotfixDatabaseStatements preparedStatement, uint32& records, char**& indexTable, char*& stringHolders, std::list<char*>& stringPool);
void LoadStrings(const char* format, HotfixDatabaseStatements preparedStatement, uint32 locale, char**& indexTable, std::list<char*>& stringPool);
- static char* AddLocaleString(LocalizedString* holder, uint32 locale, std::string const& value);
+ static char* AddString(char const** holder, std::string const& value);
private:
std::string _storageName;
diff --git a/src/server/shared/DataStores/DB2Store.h b/src/server/shared/DataStores/DB2Store.h
index c27d32df136..5ae7be4d046 100644
--- a/src/server/shared/DataStores/DB2Store.h
+++ b/src/server/shared/DataStores/DB2Store.h
@@ -105,6 +105,19 @@ public:
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)
+ {
+ buffer.append(str, len);
+ buffer << uint8(0);
+ }
+ entry += sizeof(char const*);
+ break;
+ }
}
}
}
@@ -157,7 +170,7 @@ public:
return false;
// load strings from another locale db2 data
- if (DB2FileLoader::GetFormatStringFieldCount(_format))
+ if (DB2FileLoader::GetFormatLocalizedStringFieldCount(_format))
if (char* stringBlock = db2.AutoProduceStrings(_format, (char*)_dataTable, locale))
_stringPoolList.push_back(stringBlock);
return true;
@@ -175,7 +188,7 @@ public:
void LoadStringsFromDB(uint32 locale)
{
- if (!DB2FileLoader::GetFormatStringFieldCount(_format))
+ if (!DB2FileLoader::GetFormatLocalizedStringFieldCount(_format))
return;
DB2DatabaseLoader(_fileName).LoadStrings(_format, HotfixDatabaseStatements(_hotfixStatement + 1), locale, _indexTable.AsChar, _stringPoolList);