aboutsummaryrefslogtreecommitdiff
path: root/src/server/shared/DataStores
diff options
context:
space:
mode:
authorXTZGZoReX <none@none>2010-06-06 23:18:57 +0200
committerXTZGZoReX <none@none>2010-06-06 23:18:57 +0200
commit57f64f1f5a8eccff388211e0d08bf9d630d48ada (patch)
treed2136a7d198b667d9cbda7c845da112c4aa577db /src/server/shared/DataStores
parent51121d0769619b1690fb140079244c121a39afc8 (diff)
* Restructuring shared.
--HG-- branch : trunk
Diffstat (limited to 'src/server/shared/DataStores')
-rw-r--r--src/server/shared/DataStores/DBCFileLoader.cpp270
-rw-r--r--src/server/shared/DataStores/DBCFileLoader.h110
-rw-r--r--src/server/shared/DataStores/DBCStore.h265
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