r_dbdb.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       r_dbdb.cc
00003 ///             DatabaseDatabase record parser class
00004 ///
00005 
00006 /*
00007     Copyright (C) 2005-2012, Net Direct Inc. (http://www.netdirect.ca/)
00008 
00009     This program is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     This program is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018     See the GNU General Public License in the COPYING file at the
00019     root directory of this project for more details.
00020 */
00021 
00022 #include "record.h"
00023 #include "record-internal.h"
00024 #include "data.h"
00025 #include "protocol.h"
00026 #include "debug.h"
00027 #include <algorithm>
00028 
00029 using namespace std;
00030 using namespace Barry::Protocol;
00031 
00032 namespace Barry {
00033 
00034 ///////////////////////////////////////////////////////////////////////////////
00035 // DatabaseDatabase class
00036 
00037 DatabaseDatabase::DatabaseDatabase()
00038 {
00039 }
00040 
00041 DatabaseDatabase::~DatabaseDatabase()
00042 {
00043 }
00044 
00045 template <class RecordType, class FieldType>
00046 void DatabaseDatabase::ParseRec(const RecordType &rec, const unsigned char *end)
00047 {
00048 }
00049 
00050 template <class FieldType>
00051 const unsigned char* DatabaseDatabase::ParseField(const unsigned char *begin,
00052                                                   const unsigned char *end)
00053 {
00054         // check if there is enough data for a header
00055         const unsigned char *headend = begin + sizeof(FieldType);
00056         if( headend > end )
00057                 return headend;
00058 
00059         // get our header
00060         const FieldType *field = (const FieldType *) begin;
00061 
00062         // advance and check size
00063         begin += sizeof(FieldType) - sizeof(field->name) + ConvertHtoB(field->nameSize);
00064         if( begin > end )               // if begin==end, we are ok
00065                 return begin;
00066 
00067         if( !ConvertHtoB(field->nameSize) ) // if field has no size, something's up
00068                 return begin;
00069 
00070         Database db;
00071         db.Number = ConvertHtoB(field->dbNumber);
00072         db.RecordCount = ConvertHtoB(field->dbRecordCount);
00073         db.Name.assign((const char *)field->name, ConvertHtoB(field->nameSize) - 1);
00074         Databases.push_back(db);
00075         return begin;
00076 }
00077 
00078 void DatabaseDatabase::Parse(const Data &data)
00079 {
00080         // check size to make sure we have up to the DBAccess operation byte
00081         if( data.GetSize() < (SB_PACKET_DBACCESS_HEADER_SIZE + 1) )
00082                 return;
00083 
00084         MAKE_PACKET(pack, data);
00085         const unsigned char *begin = 0;
00086         const unsigned char *end = data.GetData() + data.GetSize();
00087 
00088         switch( pack->u.db.u.response.operation )
00089         {
00090         case SB_DBOP_GET_DBDB:
00091                 // using the new protocol
00092                 if( data.GetSize() > SB_PACKET_DBDB_HEADER_SIZE ) {
00093                         begin = (const unsigned char *)
00094                                 &pack->u.db.u.response.u.dbdb.field[0];
00095 
00096                         // this while check is ok, since ParseField checks
00097                         // for header size
00098                         while( begin < end )
00099                                 begin = ParseField<DBDBField>(begin, end);
00100                 }
00101                 else
00102                         dout("DatabaseDatabase: not enough data for parsing");
00103                 break;
00104 
00105         case SB_DBOP_OLD_GET_DBDB:
00106                 // using the old protocol
00107                 if( data.GetSize() > SB_PACKET_OLD_DBDB_HEADER_SIZE ) {
00108                         begin = (const unsigned char *)
00109                                 &pack->u.db.u.response.u.old_dbdb.field[0];
00110 
00111                         // this while check is ok, since ParseField checks
00112                         // for header size
00113                         while( begin < end )
00114                                 begin = ParseField<OldDBDBField>(begin, end);
00115                 }
00116                 else
00117                         dout("DatabaseDatabase: not enough data for parsing");
00118                 break;
00119 
00120         default:
00121                 // unknown protocol
00122                 dout("Unknown protocol");
00123                 break;
00124         }
00125 
00126 
00127 }
00128 
00129 void DatabaseDatabase::Clear()
00130 {
00131         Databases.clear();
00132 }
00133 
00134 namespace {
00135         bool NameSort(const DatabaseDatabase::Database &one,
00136                 const DatabaseDatabase::Database &two)
00137         {
00138                 return one.Name < two.Name;
00139         }
00140 
00141         bool CountSort(const DatabaseDatabase::Database &one,
00142                 const DatabaseDatabase::Database &two)
00143         {
00144                 return one.RecordCount < two.RecordCount;
00145         }
00146 }
00147 
00148 void DatabaseDatabase::SortByName()
00149 {
00150         std::sort(Databases.begin(), Databases.end(), NameSort);
00151 }
00152 
00153 void DatabaseDatabase::SortByRecordCount()
00154 {
00155         std::sort(Databases.begin(), Databases.end(), CountSort);
00156 }
00157 
00158 unsigned int DatabaseDatabase::GetTotalRecordCount() const
00159 {
00160         unsigned int sum = 0;
00161 
00162         DatabaseArrayType::const_iterator b = Databases.begin();
00163         for( ; b != Databases.end(); ++b ) {
00164                 sum += b->RecordCount;
00165         }
00166         return sum;
00167 }
00168 
00169 bool DatabaseDatabase::GetDBNumber(const std::string &name,
00170                                    unsigned int &number) const
00171 {
00172         DatabaseArrayType::const_iterator b = Databases.begin();
00173         for( ; b != Databases.end(); ++b )
00174                 if( b->Name == name ) {
00175                         number = b->Number;
00176                         return true;
00177                 }
00178         return false;
00179 }
00180 
00181 bool DatabaseDatabase::GetDBName(unsigned int number,
00182                                  std::string &name) const
00183 {
00184         DatabaseArrayType::const_iterator b = Databases.begin();
00185         for( ; b != Databases.end(); ++b )
00186                 if( b->Number == number ) {
00187                         name = b->Name;
00188                         return true;
00189                 }
00190         return false;
00191 }
00192 
00193 void DatabaseDatabase::Dump(std::ostream &os) const
00194 {
00195         DatabaseArrayType::const_iterator b = Databases.begin();
00196         os << "Database database:\n";
00197         for( ; b != Databases.end(); b++ ) {
00198                 os << "    Database: 0x" << setbase(16) << b->Number
00199                    << " '" << b->Name << "' (records: "
00200                    << setbase(10) << b->RecordCount << ")\n";
00201         }
00202 }
00203 
00204 } // namespace Barry
00205