#ifndef DB_WOW_CLIENT_DB_HPP #define DB_WOW_CLIENT_DB_HPP #include "db/IDatabase.hpp" #include "db/WowClientDB_Common.hpp" #include #include #include template class WowClientDB : public WowClientDB_Common, IDatabase { public: // Virtual member functions virtual void Load(const char* filename, int32_t linenumber); virtual void LoadRecords(SFile* f, const char* filename, int32_t linenumber); virtual int32_t GetRecordByIndex(int32_t index, void* ptr) const; virtual T* GetRecord(int32_t id); // Member functions T* GetRecordByIndex(int32_t index) const; }; template T* WowClientDB::GetRecordByIndex(int32_t index) const { STORM_ASSERT(this->m_numRecords >= 0); if (index < 0 || index >= this->m_numRecords) { return nullptr; } return &this->m_records[index]; } template int32_t WowClientDB::GetRecordByIndex(int32_t index, void* ptr) const { STORM_ASSERT(this->m_numRecords >= 0); if (index < 0 || index >= this->m_numRecords) { return 0; } memcpy(ptr, &this->m_records[index], sizeof(T)); return 1; } template T* WowClientDB::GetRecord(int32_t id) { STORM_ASSERT(this->m_numRecords >= 0); if (id < this->m_minID || id > this->m_maxID) { return nullptr; } return this->m_recordsById[id - this->m_minID]; } template void WowClientDB::Load(const char* filename, int32_t linenumber) { if (this->m_loaded) { // TODO // SErrDisplayAppFatalCustom(0x85100079, "%s already loaded! Aborting to prevent memory leak!", T::GetFilename()); return; } SFile* f; if (!SFile::OpenEx(nullptr, T::GetFilename(), 0x20000, &f)) { // TODO // SErrDisplayAppFatalCustom(0x85100079, "Unable to open %s", T::GetFilename()); return; } uint32_t signature; if (!SFile::Read(f, &signature, sizeof(signature), nullptr, nullptr, nullptr)) { // TODO // SErrDisplayAppFatalCustom(0x85100079, "Unable to read signature from %s", T::GetFilename()); return; } if (signature != 'CBDW') { // TODO // SErrDisplayAppFatalCustom(0x85100079, "Invalid signature 0x%x from %s", signature, T::GetFilename()); return; } if (!SFile::Read(f, &this->m_numRecords, sizeof(this->m_numRecords), nullptr, nullptr, nullptr)) { // TODO // SErrDisplayAppFatalCustom(0x85100079, "Unable to read record count from %s", T::GetFilename()); return; } if (!this->m_numRecords) { SFile::Close(f); return; } uint32_t columnCount; if (!SFile::Read(f, &columnCount, sizeof(columnCount), nullptr, nullptr, nullptr)) { // TODO // SErrDisplayAppFatalCustom(0x85100079, "Unable to read column count from %s", T::GetFilename()); return; } if (columnCount != T::columnCount) { // TODO // SErrDisplayAppFatalCustom(0x85100079, "%s has wrong number of columns (found %i, expected %i)", T::GetFilename(), columnCount, T::columnCount); return; } uint32_t rowSize; if (!SFile::Read(f, &rowSize, sizeof(rowSize), nullptr, nullptr, nullptr)) { // TODO // SErrDisplayAppFatalCustom(0x85100079, "Unable to read row size from %s", T::GetFilename()); return; } if (rowSize != T::rowSize) { // TODO // SErrDisplayAppFatalCustom(0x85100079, "%s has wrong row size (found %i, expected %i)", T::GetFilename(), rowSize, T::rowSize); return; } uint32_t stringSize; if (!SFile::Read(f, &stringSize, sizeof(stringSize), nullptr, nullptr, nullptr)) { // TODO // SErrDisplayAppFatalCustom(0x85100079, "Unable to read string size from %s", T::GetFilename()); return; } auto stringBuffer = SMemAlloc(stringSize, filename, linenumber, 0x0); this->m_strings = static_cast(stringBuffer); this->m_maxID = 0; this->m_minID = 0xFFFFFFF; this->LoadRecords(f, filename, linenumber); if (!SFile::Read(f, const_cast(this->m_strings), stringSize, nullptr, nullptr, nullptr)) { SErrDisplayAppFatal("%s: Cannot read string table", T::GetFilename()); } SFile::Close(f); this->m_loaded = 1; } template void WowClientDB::LoadRecords(SFile* f, const char* filename, int32_t linenumber) { auto records = SMemAlloc(sizeof(T) * this->m_numRecords, filename, linenumber, 0x0); this->m_records = static_cast(records); for (uint32_t i = 0; i < this->m_numRecords; i++) { auto record = &this->m_records[i]; record->Read(f, this->m_strings); this->m_maxID = record->m_ID > this->m_maxID ? record->m_ID : this->m_maxID; this->m_minID = record->m_ID < this->m_minID ? record->m_ID : this->m_minID; } auto recordsById = SMemAlloc(sizeof(void*) * (this->m_maxID - this->m_minID + 1), __FILE__, __LINE__, 0x0); memset(recordsById, 0, sizeof(void*) * (this->m_maxID - this->m_minID + 1)); this->m_recordsById = static_cast(recordsById); for (uint32_t i = 0; i < this->m_numRecords; i++) { auto record = &this->m_records[i]; auto id = record->m_ID - this->m_minID; this->m_recordsById[id] = record; } } #endif