Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

DBDatabase.cpp

Go to the documentation of this file.
00001 /*
00002  * DBDatabase.cpp
00003  *
00004  * Part of Fly! Legacy project
00005  *
00006  * Copyright 2003 Chris Wallace
00007  *
00008  * Fly! Legacy is free software; you can redistribute it and/or modify
00009  *   it under the terms of the GNU General Public License as published by
00010  *   the Free Software Foundation; either version 2 of the License, or
00011  *   (at your option) any later version.
00012  *
00013  * Fly! Legacy is distributed in the hope that it will be useful,
00014  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  *   GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  *   along with Fly! Legacy; if not, write to the Free Software
00020  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00039 #include "../Include/Globals.h"
00040 #include "../Include/Database.h"
00041 #include "../Include/Pod.h"
00042 
00043 using namespace std;
00044 
00045 
00046 CDatabaseRecord::CDatabaseRecord (void)
00047 {
00048   sequence = 0;
00049 }
00050 
00051 void CDatabaseRecord::SetSequence (unsigned long sequence)
00052 {
00053   this->sequence = sequence;
00054 }
00055 
00056 void CDatabaseRecord::AddField (CDatabaseField f)
00057 {
00058   field.push_back (f);
00059 }
00060 
00061 int CDatabaseRecord::GetNumFields (void)
00062 {
00063   return field.size();
00064 }
00065 
00066 CDatabaseField *CDatabaseRecord::GetField (unsigned int i)
00067 {
00068   CDatabaseField *rc = NULL;
00069 
00070   if (i < field.size()) {
00071     rc = &(field[i]);
00072   }
00073 
00074   return rc;
00075 }
00076 
00077 
00078 CDatabase::CDatabase (const char* dbtFilename)
00079 {
00080   // Load the database template
00081   LoadTemplate (dbtFilename);
00082 
00083   // Allocate a data record used to cache the last-read record
00084   cacheRecord = NULL;
00085 /*
00086   int nFields = dbt.GetNumItems ();
00087   cacheOffset = 0;
00088   cacheRecord = new CDatabaseRecord;
00089   // \todo Add fields to cache record
00090 */
00091 
00092   // Initialize state to UNMOUNTED until Mount() is called
00093   state = DB_UNMOUNTED;
00094   podfile = NULL;
00095   recordBuffer = NULL;
00096 }
00097 
00101 CDatabase::~CDatabase (void)
00102 {
00103   // Delete buffer for current record
00104   if (recordBuffer != NULL) delete[] recordBuffer;
00105 
00106   // Delete data record cache
00107   if (cacheRecord != NULL) {
00108     delete cacheRecord;
00109   }
00110 
00111   // Delete indices
00112   vector<CDatabaseIndex*>::iterator i;
00113   for (i=dbi.begin(); i!=dbi.end(); i++) delete *i;
00114 
00115   Unmount ();
00116 }
00117 
00118 //
00119 // Template related methods
00120 //
00121 
00122 void CDatabase::LoadTemplate (const char* dbtFilename)
00123 {
00124   dbt.Load (dbtFilename);
00125 }
00126 
00127 CDatabaseTemplate* CDatabase::GetTemplate (void)
00128 {
00129   return &dbt;
00130 }
00131 
00132 //
00133 // Index related methods
00134 //
00135 
00136 void CDatabase::AddIndex (const char *dbiFilename)
00137 {
00138   dbi.push_back (new CDatabaseIndex (dbiFilename));
00139 }
00140 
00141 unsigned int CDatabase::GetNumIndexes (void)
00142 {
00143   return dbi.size();
00144 }
00145 
00146 CDatabaseIndex* CDatabase::GetIndex (Tag tag)
00147 {
00148   CDatabaseIndex *rc = NULL;
00149 
00150   vector<CDatabaseIndex*>::iterator i;
00151   for (i=dbi.begin(); i!=dbi.end(); i++) {
00152     Tag iKey = (*i)->GetKeyId();
00153     if (iKey == tag) {
00154       rc = *i;
00155     }
00156   }
00157 
00158   return rc;
00159 }
00160 
00161 
00162 //
00163 // Data (DBD) related methods
00164 //
00165 
00166 typedef struct {
00167   unsigned long  signature;
00168   unsigned long  unknown0;
00169   unsigned long  unknown1;
00170   unsigned long  checksum;
00171   unsigned long  nRecords;
00172   unsigned long  recLength;
00173   unsigned long  dummy[8];
00174 } DBDHeader;
00175 
00176 
00177 //
00178 // Mount the database but do not load any of the records into memory
00179 //
00180 void CDatabase::Mount (PODFILE *f)
00181 {
00182   // Confirm that valid template exists
00183   int nFields = dbt.GetNumItems();
00184   if (nFields > 0) {
00185     // Read header
00186     DBDHeader h;
00187     ReadULong (f, &h.signature);
00188     ReadULong (f, &h.unknown0);
00189     ReadULong (f, &h.unknown1);
00190     ReadULong (f, &h.checksum);
00191     ReadULong (f, &h.nRecords);
00192     ReadULong (f, &h.recLength);
00193     for (unsigned int i=0; i<8; i++) ReadULong (f, &h.dummy[i]);
00194 
00195     nRecords = h.nRecords;
00196     recLength = h.recLength;
00197   }
00198 
00199   // Update database state
00200   state = DB_MOUNTED;
00201   podfile = f;
00202   recordBuffer = new char[recLength];
00203 }
00204 
00205 void CDatabase::Mount (const char* dbdFilename)
00206 {
00207   char fullFilename[64];
00208   strcpy (fullFilename, "Database\\");
00209   strcat (fullFilename, dbdFilename);
00210   PODFILE *p = popen (&globals->pfs, fullFilename);
00211   if (p) {
00212     // Mount the database, PODFILE must be left open
00213     Mount (p);
00214   }
00215 }
00216 
00217 void CDatabase::Unmount (void)
00218 {
00219   if (podfile != NULL) {
00220     pclose (podfile);
00221   }
00222 }
00223 /*
00224 void CDatabase::Load (PODFILE *f)
00225 {
00226   unsigned int i, j;
00227 
00228   // Confirm that valid template exists
00229   unsigned int nFields = dbt.GetNumItems();
00230   if (nFields > 0) {
00231     // Read header
00232     DBDHeader h;
00233     ReadULong (f, &h.signature);
00234     ReadULong (f, &h.unknown0);
00235     ReadULong (f, &h.unknown1);
00236     ReadULong (f, &h.checksum);
00237     ReadULong (f, &h.nRecords);
00238     ReadULong (f, &h.recLength);
00239     for (i=0; i<8; i++) ReadULong (f, &h.dummy[i]);
00240 
00241     // Allocate buffer for raw data record storage
00242     char *buffer = new char[h.recLength];
00243 
00244     // Allocate storage for data records
00245     nRecords = h.nRecords;
00246     recLength = h.recLength;
00247     record = new DataRecord[nRecords];
00248 
00249     // Read data records
00250     for (i=0; i<nRecords; i++) {
00251       // Read raw data record into buffer
00252       pread (buffer, h.recLength, 1, f);
00253 
00254       // Read record sequence number
00255       unsigned long tempLong;
00256       memcpy (&tempLong, buffer, sizeof(unsigned long));
00257       CorrectEndian (&tempLong, sizeof(unsigned long));
00258       record[i].sequence = tempLong;
00259 
00260       // Allocate storage within record for fields
00261       record[i].field = new DataItem[nFields];
00262 
00263       for (j=0; j<nFields; j++) {
00264 
00265         // Initialize locals from database template field
00266         unsigned long dataStart = dbt.item[j].start;
00267         unsigned char dataType = dbt.item[j].type;
00268         int dataLength = dbt.item[j].length;
00269 
00270         // Initialize pointer to field data in raw buffer
00271         char *p = buffer + dataStart;
00272 
00273         record[i].field[j].type = dataType;
00274         record[i].field[j].length = dataLength;
00275         switch (dataType) {
00276           case 'C':
00277             {
00278               // Char string data
00279               char *s = new char[dataLength+1];
00280               memcpy (s, p, dataLength);
00281               s[dataLength] = '\0';
00282               record[i].field[j].pData = s;
00283             }
00284             break;
00285 
00286           case 'D':
00287             // Double-precision float data
00288             record[i].field[j].pData = new double;
00289             memcpy (record[i].field[j].pData, p, dataLength);
00290             CorrectEndian (record[i].field[j].pData, dataLength);
00291             break;
00292 
00293           case 'I':
00294             // Integer (unsigned long) data
00295             record[i].field[j].pData = new unsigned long;
00296             memcpy (record[i].field[j].pData, p, dataLength);
00297             CorrectEndian (record[i].field[j].pData, dataLength);
00298             break;
00299         }
00300       }
00301     }
00302 
00303     delete[] buffer;
00304   }
00305 
00306   // Update database state
00307   state = DB_LOADED;
00308 }
00309 
00310 void CDatabase::Load (const char *dbdFilename)
00311 {
00312   char fullFilename[64];
00313   strcpy (fullFilename, "Database\\");
00314   strcat (fullFilename, dbdFilename);
00315   PODFILE *p = popen (&globals->pfs, fullFilename);
00316   if (p) {
00317     Load (p);
00318     pclose (p);
00319   }
00320 }
00321 
00322 void CDatabase::Save (FILE *f)
00323 {
00324   int i, j;
00325 
00326   // Confirm that valid template exists
00327   int nFields = dbt.GetNumItems();
00328   if (nFields > 0) {
00329     // Initialize header
00330     DBDHeader h;
00331     h.signature = signature;
00332     h.unknown0 = 0;
00333     h.unknown1 = 1;
00334     h.checksum = 0;
00335     h.nRecords = GetNumDataRecords();
00336 
00337     // Calculate raw record length
00338     int nFields = dbt.GetNumItems();
00339     int recLength = 4;
00340     for (i=0; i<nFields; i++) {
00341       TemplateItem ti = dbt.GetItem (i);
00342       recLength += ti.length;
00343     }
00344     h.recLength = recLength;
00345     for (i=0; i<8; i++) {
00346       h.dummy[i] = 0;
00347     }
00348 
00349     // Write header
00350     fwrite (&h, sizeof(DBDHeader), 1, f);
00351 
00352     // Write data records
00353     for (i=0; i<(int)nRecords; i++) {
00354       // Write record sequence number
00355       fwrite (&record[i].sequence, sizeof(unsigned long), 1, f);
00356 
00357       // Write field data
00358       for (j=0; j<nFields; j++) {
00359         DataItem &item = record[i].field[j];
00360         fwrite (item.pData, item.length, 1, f);
00361       }
00362     }
00363   }
00364 }
00365 
00366 void CDatabase::Save (const char *dataFilename)
00367 {
00368   FILE *f;
00369   f = fopen (dataFilename, "wb");
00370   if (f) {
00371     Save (f);
00372     fclose (f);
00373   }
00374 }
00375 */
00376 
00377 
00378 //
00379 // Data access methods
00380 //
00381 
00382 unsigned long CDatabase::GetRawRecordLength (void)
00383 {
00384   return recLength;
00385 }
00386 
00387 unsigned long CDatabase::GetNumRecords (void)
00388 {
00389   return nRecords;
00390 }
00391 
00392 unsigned long CDatabase::GetNumFields (void)
00393 {
00394   return dbt.GetNumItems();
00395 }
00396 
00397 
00398 //
00399 // Start a new search of the database.  The index and search key are saved 
00400 //   such that subsequent matching records can be retrieved using the SearchNext
00401 //   method
00402 //
00403 //  @param tag       Unique identifier of index to search on
00404 //  @param key       String value to search for
00405 //
00406 //  @return Pointer to first database record matching key, or NULL if none found
00407 //
00408 unsigned long CDatabase::Search (Tag tag, const char* key)
00409 {
00410   unsigned long rc = 0;
00411 
00412   // Verify that database is mounted
00413   if (state == DB_MOUNTED) {
00414     search_index = GetIndex (tag);
00415     if (search_index != NULL) {
00416       rc = search_index->Search (key);
00417     }
00418   }
00419 
00420   return rc;
00421 }
00422 
00423 unsigned long CDatabase::Search (Tag tag, double key)
00424 {
00425   unsigned long rc = 0;
00426 
00427   // Verify that database is mounted
00428   if (state == DB_MOUNTED) {
00429     search_index = GetIndex (tag);
00430     if (search_index != NULL) {
00431       rc = search_index->Search (key);
00432     }
00433   }
00434 
00435   return rc;
00436 }
00437 
00438 unsigned long CDatabase::Search (Tag tag, long key)
00439 {
00440   unsigned long rc = 0;
00441 
00442   // Verify that database is mounted
00443   if (state == DB_MOUNTED) {
00444     search_index = GetIndex (tag);
00445     if (search_index != NULL) {
00446       rc = search_index->Search (key);
00447     }
00448   }
00449 
00450   return rc;
00451 }
00452 
00453 //
00454 // Continue searching using the same key values from the last call to Search()
00455 //
00456 // Return code:
00457 //  unsigned long Record pointer of next match
00458 //
00459 unsigned long CDatabase::SearchNext (void)
00460 {
00461   unsigned long rc = 0;
00462 
00463   // Verify that database is mounted or loaded
00464   if ((state == DB_MOUNTED) && (search_index != NULL)) {
00465     rc = search_index->SearchNext ();
00466   }
00467 
00468   return rc;
00469 }
00470 
00471 /*
00472 CDatabaseRecord* CDatabase::Search (Tag tag, const char* key)
00473 {
00474   CDatabaseRecord *rc = NULL;
00475 
00476   // Verify that database is mounted
00477   if (state == DB_MOUNTED) {
00478     search_index = GetIndex (tag);
00479     if (search_index != NULL) {
00480       unsigned long offset = search_index->Search (key);
00481       if (offset != 0) {
00482         rc = GetRecordByOffset (offset);
00483       }
00484     }
00485   }
00486 
00487   return rc;
00488 }
00489 
00490 CDatabaseRecord* CDatabase::Search (Tag tag, double key)
00491 {
00492   CDatabaseRecord *rc = NULL;
00493 
00494   // Verify that database is mounted
00495   if (state == DB_MOUNTED) {
00496     search_index = GetIndex (tag);
00497     if (search_index != NULL) {
00498       unsigned long offset = search_index->Search (key);
00499       if (offset != 0) {
00500         rc = GetRecordByOffset (offset);
00501       }
00502     }
00503   }
00504 
00505   return rc;
00506 }
00507 
00508 CDatabaseRecord* CDatabase::Search (Tag tag, long key)
00509 {
00510   CDatabaseRecord *rc = NULL;
00511 
00512   // Verify that database is mounted
00513   if (state == DB_MOUNTED) {
00514     search_index = GetIndex (tag);
00515     if (search_index != NULL) {
00516       unsigned long offset = search_index->Search (key);
00517       if (offset != 0) {
00518         rc = GetRecordByOffset (offset);
00519       }
00520     }
00521   }
00522 
00523   return rc;
00524 }
00525 
00526 //
00527 // Continue searching using the same key values from the last call to Search()
00528 //
00529 // Return code:
00530 //  unsigned long Record pointer of next match
00531 //
00532 CDatabaseRecord* CDatabase::SearchNext (void)
00533 {
00534   CDatabaseRecord *rc = NULL;
00535 
00536   // Verify that database is mounted or loaded
00537   if ((state == DB_MOUNTED) && (search_index != NULL)) {
00538       unsigned long offset = search_index->SearchNext ();
00539       if (offset != 0) {
00540         rc = GetRecordByOffset (offset);
00541       }
00542   }
00543 
00544   return rc;
00545 }
00546 */
00547 
00548 //
00549 // Retrieve a raw data record from the database.  The application is responsible
00550 //   for decoding and formatting the fields
00551 //
00552 void CDatabase::GetRawRecord (unsigned long offset, char* buffer)
00553 {
00554   // Verify that database is mounted
00555   if (state == DB_MOUNTED) {
00556     pseek (podfile, offset, SEEK_SET);
00557     pread (buffer, recLength, 1, podfile);
00558   }
00559 }
00560 
00561 CDatabaseRecord* CDatabase::GetRecordByOffset (unsigned long offset)
00562 {
00563   CDatabaseRecord* rc = new CDatabaseRecord;
00564 
00565   GetRawRecord (offset, recordBuffer);
00566   for (unsigned long i=0; i<GetNumFields(); i++) {
00567     CDatabaseField f;
00568     CDatabaseTemplateItem *t = dbt.GetItem (i);
00569     f.type = t->type;
00570     f.length = t->length;
00571     void *pData = recordBuffer + t->start;
00572     switch (t->type) {
00573     case 'C':
00574       if (t->length < 256) {
00575         strncpy (f.data.charData, (char*)pData, t->length);
00576       } else {
00577         gtfo ("CDatabase::GetRecord : Char field length > 255 chars");
00578       }
00579       break;
00580 
00581     case 'D':
00582       f.data.doubleData = *((double*)pData);
00583       break;
00584 
00585     case 'I':
00586       f.data.intData = *((long*)pData);
00587       break;
00588     }
00589     rc->AddField (f);
00590   }
00591 
00592   return rc;
00593 }
00594 
00595 unsigned long CDatabase::RecordOffset (unsigned long index)
00596 {
00597   return sizeof(DBDHeader) + (index * recLength);
00598 }
00599 
00600 CDatabaseRecord* CDatabase::GetRecordByIndex (unsigned long index)
00601 {
00602   return GetRecordByOffset (RecordOffset (index));
00603 }
00604 
00605 
00606 //
00607 // Dump the database contents to a file for debugging
00608 //
00609 void CDatabase::Dump (FILE *f)
00610 {
00611   // Dump template
00612   dbt.Dump (f);
00613   fprintf (f, "\n");
00614 
00615   // Dump indices
00616   vector<CDatabaseIndex*>::iterator i;
00617   for (i=dbi.begin(); i!=dbi.end(); i++) {
00618     (*i)->Dump (f);
00619   }
00620   fprintf (f, "\n");
00621 
00622   // Dump database state
00623   fprintf (f, "State : ");
00624   switch (state) {
00625   case DB_UNMOUNTED:
00626     fprintf (f, "UNMOUNTED\n");
00627     break;
00628 
00629   case DB_MOUNTED:
00630     fprintf (f, "MOUNTED\n");
00631     break;
00632   }
00633 
00634   // Dump all data records
00635   if (state == DB_MOUNTED) {
00636     int nRecords = GetNumRecords ();
00637     fprintf (f, "  nRecords = %d\n", nRecords);
00638     int nFields = GetNumFields ();
00639     fprintf (f, "  nFields  = %d\n", nFields);
00640 
00641     int i, j;
00642     for (i=0; i < nRecords; i++) {
00643       CDatabaseRecord *record = GetRecordByIndex (i);
00644 
00645       for (j=0; j < nFields; j++) {
00646         CDatabaseField *field =  record->GetField (j);
00647         char s[256];
00648         field->Format (s);
00649         if (j != 0) fprintf (f, ", ");
00650         fprintf (f, "%s", s);
00651       }
00652       fprintf (f, "\n");
00653     }
00654   }
00655 }
00656 
00657 
SourceForge.net Logo Documentation generated by doxygen