diff options
| author | XTZGZoReX <none@none> | 2010-06-06 23:18:57 +0200 |
|---|---|---|
| committer | XTZGZoReX <none@none> | 2010-06-06 23:18:57 +0200 |
| commit | 57f64f1f5a8eccff388211e0d08bf9d630d48ada (patch) | |
| tree | d2136a7d198b667d9cbda7c845da112c4aa577db /src/server/shared/DataStores | |
| parent | 51121d0769619b1690fb140079244c121a39afc8 (diff) | |
* Restructuring shared.
--HG--
branch : trunk
Diffstat (limited to 'src/server/shared/DataStores')
| -rw-r--r-- | src/server/shared/DataStores/DBCFileLoader.cpp | 270 | ||||
| -rw-r--r-- | src/server/shared/DataStores/DBCFileLoader.h | 110 | ||||
| -rw-r--r-- | src/server/shared/DataStores/DBCStore.h | 265 |
3 files changed, 645 insertions, 0 deletions
diff --git a/src/server/shared/DataStores/DBCFileLoader.cpp b/src/server/shared/DataStores/DBCFileLoader.cpp new file mode 100644 index 00000000000..bad87a36fce --- /dev/null +++ b/src/server/shared/DataStores/DBCFileLoader.cpp @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * Copyright (C) 2008-2010 Trinity <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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "DBCFileLoader.h" + +DBCFileLoader::DBCFileLoader() +{ + data = NULL; + fieldsOffset = NULL; +} + +bool DBCFileLoader::Load(const char *filename, const char *fmt) +{ + uint32 header; + if (data) + { + delete [] data; + data = NULL; + } + + FILE * f = fopen(filename,"rb"); + if (!f) + return false; + + if (fread(&header,4,1,f)!=1) // Number of records + return false; + + EndianConvert(header); + + if (header!=0x43424457) + return false; //'WDBC' + + if (fread(&recordCount,4,1,f)!=1) // Number of records + return false; + + EndianConvert(recordCount); + + if (fread(&fieldCount,4,1,f)!=1) // Number of fields + return false; + + EndianConvert(fieldCount); + + if (fread(&recordSize,4,1,f)!=1) // Size of a record + return false; + + EndianConvert(recordSize); + + if (fread(&stringSize,4,1,f)!=1) // String size + return false; + + EndianConvert(stringSize); + + fieldsOffset = new uint32[fieldCount]; + fieldsOffset[0] = 0; + for (uint32 i = 1; i < fieldCount; i++) + { + fieldsOffset[i] = fieldsOffset[i - 1]; + if (fmt[i - 1] == 'b' || fmt[i - 1] == 'X') // byte fields + fieldsOffset[i] += 1; + else // 4 byte fields (int32/float/strings) + fieldsOffset[i] += 4; + } + + data = new unsigned char[recordSize*recordCount+stringSize]; + stringTable = data + recordSize*recordCount; + + if (fread(data,recordSize*recordCount+stringSize,1,f)!=1) + return false; + + fclose(f); + + return true; +} + +DBCFileLoader::~DBCFileLoader() +{ + if (data) + delete [] data; + + if (fieldsOffset) + delete [] fieldsOffset; +} + +DBCFileLoader::Record DBCFileLoader::getRecord(size_t id) +{ + assert(data); + return Record(*this, data + id*recordSize); +} + +uint32 DBCFileLoader::GetFormatRecordSize(const char * format,int32* index_pos) +{ + uint32 recordsize = 0; + int32 i = -1; + for (uint32 x=0; format[x]; ++x) + { + switch(format[x]) + { + case FT_FLOAT: + case FT_INT: + recordsize+=4; + break; + case FT_STRING: + recordsize+=sizeof(char*); + break; + case FT_SORT: + i=x; + break; + case FT_IND: + i=x; + recordsize+=4; + break; + case FT_BYTE: + recordsize += 1; + break; + } + } + + if (index_pos) + *index_pos = i; + + return recordsize; +} + +char* DBCFileLoader::AutoProduceData(const char* format, uint32& records, char**& indexTable, uint32 sqlRecordCount, uint32 sqlHighestIndex, char *& sqlDataTable) +{ + /* + format STRING, NA, FLOAT,NA,INT <=> + struct{ + char* field0, + float field1, + int field2 + }entry; + + this func will generate entry[rows] data; + */ + + typedef char * ptr; + if (strlen(format)!=fieldCount) + return NULL; + + //get struct size and index pos + int32 i; + uint32 recordsize=GetFormatRecordSize(format,&i); + + if (i>=0) + { + uint32 maxi=0; + //find max index + for (uint32 y=0; y<recordCount; y++) + { + uint32 ind=getRecord(y).getUInt (i); + if(ind>maxi)maxi=ind; + } + + // If higher index avalible from sql - use it instead of dbcs + if (sqlHighestIndex > maxi) + maxi = sqlHighestIndex; + + ++maxi; + records=maxi; + indexTable=new ptr[maxi]; + memset(indexTable,0,maxi*sizeof(ptr)); + } + else + { + records = recordCount + sqlRecordCount; + indexTable = new ptr[recordCount+ sqlRecordCount]; + } + + char* dataTable= new char[(recordCount + sqlRecordCount)*recordsize]; + + uint32 offset=0; + + for (uint32 y =0; y<recordCount; ++y) + { + if(i>=0) + indexTable[getRecord(y).getUInt(i)]=&dataTable[offset]; + else + indexTable[y]=&dataTable[offset]; + + for (uint32 x=0; x<fieldCount; x++) + { + switch(format[x]) + { + case FT_FLOAT: + *((float*)(&dataTable[offset]))=getRecord(y).getFloat(x); + offset+=4; + break; + case FT_IND: + case FT_INT: + *((uint32*)(&dataTable[offset]))=getRecord(y).getUInt(x); + offset+=4; + break; + case FT_BYTE: + *((uint8*)(&dataTable[offset]))=getRecord(y).getUInt8(x); + offset+=1; + break; + case FT_STRING: + *((char**)(&dataTable[offset]))=NULL; // will be replaces non-empty or "" strings in AutoProduceStrings + offset+=sizeof(char*); + break; + } + } + } + + sqlDataTable = dataTable + offset; + + return dataTable; +} + +char* DBCFileLoader::AutoProduceStrings(const char* format, char* dataTable) +{ + if (strlen(format)!=fieldCount) + return NULL; + + char* stringPool= new char[stringSize]; + memcpy(stringPool,stringTable,stringSize); + + uint32 offset=0; + + for (uint32 y =0; y<recordCount; y++) + { + for (uint32 x=0; x<fieldCount; x++) + switch(format[x]) + { + case FT_FLOAT: + case FT_IND: + case FT_INT: + offset+=4; + break; + case FT_BYTE: + offset+=1; + break; + case FT_STRING: + // fill only not filled entries + char** slot = (char**)(&dataTable[offset]); + if(!*slot || !**slot) + { + const char * st = getRecord(y).getString(x); + *slot=stringPool+(st-(const char*)stringTable); + } + offset+=sizeof(char*); + break; + } + } + + return stringPool; +} + diff --git a/src/server/shared/DataStores/DBCFileLoader.h b/src/server/shared/DataStores/DBCFileLoader.h new file mode 100644 index 00000000000..a97ab4d60fa --- /dev/null +++ b/src/server/shared/DataStores/DBCFileLoader.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DBC_FILE_LOADER_H +#define DBC_FILE_LOADER_H +#include "Platform/Define.h" +#include "Utilities/ByteConverter.h" +#include <cassert> + +enum +{ + FT_NA='x', //not used or unknown, 4 byte size + FT_NA_BYTE='X', //not used or unknown, byte + FT_STRING='s', //char* + FT_FLOAT='f', //float + FT_INT='i', //uint32 + FT_BYTE='b', //uint8 + FT_SORT='d', //sorted by this field, field is not included + FT_IND='n', //the same,but parsed to data + FT_LOGIC='l', //Logical (boolean) + FT_SQL_PRESENT='p', //Used in sql format to mark column present in sql dbc + FT_SQL_ABSENT='a' //Used in sql format to mark column absent in sql dbc +}; + +class DBCFileLoader +{ + public: + DBCFileLoader(); + ~DBCFileLoader(); + + bool Load(const char *filename, const char *fmt); + + class Record + { + public: + float getFloat(size_t field) const + { + assert(field < file.fieldCount); + float val = *reinterpret_cast<float*>(offset+file.GetOffset(field)); + EndianConvert(val); + return val; + } + uint32 getUInt(size_t field) const + { + assert(field < file.fieldCount); + uint32 val = *reinterpret_cast<uint32*>(offset+file.GetOffset(field)); + EndianConvert(val); + return val; + } + uint8 getUInt8(size_t field) const + { + assert(field < file.fieldCount); + return *reinterpret_cast<uint8*>(offset+file.GetOffset(field)); + } + + const char *getString(size_t field) const + { + assert(field < file.fieldCount); + size_t stringOffset = getUInt(field); + assert(stringOffset < file.stringSize); + return reinterpret_cast<char*>(file.stringTable + stringOffset); + } + + private: + Record(DBCFileLoader &file_, unsigned char *offset_): offset(offset_), file(file_) {} + unsigned char *offset; + DBCFileLoader &file; + + friend class DBCFileLoader; + + }; + + // Get record by id + Record getRecord(size_t id); + /// Get begin iterator over records + + uint32 GetNumRows() const { return recordCount; } + uint32 GetRowSize() const { return recordSize; } + uint32 GetCols() const { return fieldCount; } + uint32 GetOffset(size_t id) const { return (fieldsOffset != NULL && id < fieldCount) ? fieldsOffset[id] : 0; } + bool IsLoaded() { return data != NULL; } + char* AutoProduceData(const char* fmt, uint32& count, char**& indexTable, uint32 sqlRecordCount, uint32 sqlHighestIndex, char *& sqlDataTable); + char* AutoProduceStrings(const char* fmt, char* dataTable); + static uint32 GetFormatRecordSize(const char * format, int32 * index_pos = NULL); + private: + + uint32 recordSize; + uint32 recordCount; + uint32 fieldCount; + uint32 stringSize; + uint32 *fieldsOffset; + unsigned char *data; + unsigned char *stringTable; +}; +#endif diff --git a/src/server/shared/DataStores/DBCStore.h b/src/server/shared/DataStores/DBCStore.h new file mode 100644 index 00000000000..61e2f7a6d06 --- /dev/null +++ b/src/server/shared/DataStores/DBCStore.h @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DBCSTORE_H +#define DBCSTORE_H + +#include "DBCFileLoader.h" +#include "Log.h" + +struct SqlDbc +{ + const std::string * formatString; + const std::string * indexName; + std::string sqlTableName; + int32 indexPos; + int32 sqlIndexPos; + SqlDbc(const std::string * _filename, const std::string * _format, const std::string * _idname, const char * fmt) + :formatString(_format),sqlIndexPos(0), indexName (_idname) + { + // Convert dbc file name to sql table name + sqlTableName = *_filename; + for (uint32 i = 0; i< sqlTableName.size(); ++i) + { + if (isalpha(sqlTableName[i])) + sqlTableName[i] = tolower(sqlTableName[i]); + else if (sqlTableName[i] == '.') + sqlTableName[i] = '_'; + } + + // Get sql index position + DBCFileLoader::GetFormatRecordSize(fmt, &indexPos); + if (indexPos>=0) + { + for (int32 x=0; x < formatString->size(); x++) + { + // Count only fields present in sql + if ((*formatString)[x] == FT_SQL_PRESENT) + { + if (x == indexPos) + break; + ++sqlIndexPos; + } + } + } + } +}; + +template<class T> +class DBCStorage +{ + typedef std::list<char*> StringPoolList; + public: + explicit DBCStorage(const char *f) : nCount(0), fieldCount(0), fmt(f), indexTable(NULL), m_dataTable(NULL) { } + ~DBCStorage() { Clear(); } + + T const* LookupEntry(uint32 id) const { return (id>=nCount)?NULL:indexTable[id]; } + uint32 GetNumRows() const { return nCount; } + char const* GetFormat() const { return fmt; } + uint32 GetFieldCount() const { return fieldCount; } + + bool Load(char const* fn, SqlDbc * sql) + { + DBCFileLoader dbc; + // Check if load was sucessful, only then continue + if (!dbc.Load(fn, fmt)) + return false; + + uint32 sqlRecordCount = 0; + uint32 sqlHighestIndex = 0; + Field *fields = NULL; + QueryResult_AutoPtr result = QueryResult_AutoPtr(NULL); + // Load data from sql + if (sql) + { + std::string query = "SELECT * FROM " + sql->sqlTableName; + if (sql->indexPos >= 0) + query +=" ORDER BY + " + *sql->indexName + " DESC"; + query += ";"; + + result = WorldDatabase.Query(query.c_str()); + if (result) + { + sqlRecordCount = result->GetRowCount(); + if (sql->indexPos >= 0) + { + fields = result->Fetch(); + sqlHighestIndex = fields[sql->sqlIndexPos].GetUInt32(); + } + // Check if sql index pos is valid + if (int32(result->GetFieldCount()-1) < sql->sqlIndexPos) + { + sLog.outError("Invalid index pos for dbc:'%s'", sql->sqlTableName.c_str()); + return false; + } + } + } + char * sqlDataTable; + fieldCount = dbc.GetCols(); + m_dataTable = (T*)dbc.AutoProduceData(fmt,nCount,(char**&)indexTable, sqlRecordCount, sqlHighestIndex, sqlDataTable); + + m_stringPoolList.push_back(dbc.AutoProduceStrings(fmt,(char*)m_dataTable)); + + // Insert sql data into arrays + if (result) + { + if (indexTable) + { + uint32 offset = 0; + uint32 rowIndex = dbc.GetNumRows(); + do + { + if (!fields) + fields = result->Fetch(); + + if(sql->indexPos >= 0) + { + uint32 id = fields[sql->sqlIndexPos].GetUInt32(); + if (indexTable[id]) + { + sLog.outError("Index %d already exists in dbc:'%s'", id, sql->sqlTableName.c_str()); + return false; + } + indexTable[id]=(T*)&sqlDataTable[offset]; + } + else + indexTable[rowIndex]=(T*)&sqlDataTable[offset]; + uint32 columnNumber = 0; + uint32 sqlColumnNumber = 0; + + for (; columnNumber < sql->formatString->size(); ++columnNumber) + { + if ((*sql->formatString)[columnNumber] == FT_SQL_ABSENT) + { + switch(fmt[columnNumber]) + { + case FT_FLOAT: + *((float*)(&sqlDataTable[offset]))= 0.0f; + offset+=4; + break; + case FT_IND: + case FT_INT: + *((uint32*)(&sqlDataTable[offset]))=uint32(0); + offset+=4; + break; + case FT_BYTE: + *((uint8*)(&sqlDataTable[offset]))=uint8(0); + offset+=1; + break; + case FT_STRING: + // Beginning of the pool - empty string + *((char**)(&sqlDataTable[offset]))=m_stringPoolList.back(); + offset+=sizeof(char*); + break; + } + } + else if ((*sql->formatString)[columnNumber] == FT_SQL_PRESENT) + { + bool validSqlColumn = true; + switch(fmt[columnNumber]) + { + case FT_FLOAT: + *((float*)(&sqlDataTable[offset]))=fields[sqlColumnNumber].GetFloat(); + offset+=4; + break; + case FT_IND: + case FT_INT: + *((uint32*)(&sqlDataTable[offset]))=fields[sqlColumnNumber].GetUInt32(); + offset+=4; + break; + case FT_BYTE: + *((uint8*)(&sqlDataTable[offset]))=fields[sqlColumnNumber].GetUInt8(); + offset+=1; + break; + case FT_STRING: + sLog.outError("Unsupported data type in table '%s' at char %d", sql->sqlTableName.c_str(), columnNumber); + return false; + case FT_SORT: + break; + default: + validSqlColumn = false; + } + if (validSqlColumn && (columnNumber != (sql->formatString->size()-1))) + sqlColumnNumber++; + } + else + { + sLog.outError("Incorrect sql format string '%s' at char %d", sql->sqlTableName.c_str(), columnNumber); + return false; + } + } + if (sqlColumnNumber != (result->GetFieldCount()-1)) + { + sLog.outError("SQL and DBC format strings are not matching for table: '%s'", sql->sqlTableName.c_str()); + return false; + } + + fields = NULL; + ++rowIndex; + }while (result->NextRow()); + } + } + + // error in dbc file at loading if NULL + return indexTable!=NULL; + } + + bool LoadStringsFrom(char const* fn) + { + // DBC must be already loaded using Load + if(!indexTable) + return false; + + DBCFileLoader dbc; + // Check if load was successful, only then continue + if(!dbc.Load(fn, fmt)) + return false; + + m_stringPoolList.push_back(dbc.AutoProduceStrings(fmt,(char*)m_dataTable)); + + return true; + } + + void Clear() + { + if (!indexTable) + return; + + delete[] ((char*)indexTable); + indexTable = NULL; + delete[] ((char*)m_dataTable); + m_dataTable = NULL; + + while(!m_stringPoolList.empty()) + { + delete[] m_stringPoolList.front(); + m_stringPoolList.pop_front(); + } + nCount = 0; + } + + private: + char const* fmt; + uint32 nCount; + uint32 fieldCount; + T** indexTable; + T* m_dataTable; + StringPoolList m_stringPoolList; +}; + +#endif |
