r_recordstate.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       r_recordstate.cc
00003 ///             RecordStateTable database 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 <sstream>
00026 #include <iomanip>
00027 
00028 using namespace std;
00029 using namespace Barry::Protocol;
00030 
00031 namespace Barry {
00032 
00033 ///////////////////////////////////////////////////////////////////////////////
00034 // RecordStateTable class
00035 
00036 RecordStateTable::RecordStateTable()
00037         : m_LastNewRecordId(1)
00038 {
00039 }
00040 
00041 RecordStateTable::~RecordStateTable()
00042 {
00043 }
00044 
00045 const unsigned char* RecordStateTable::ParseField(const unsigned char *begin,
00046                                                   const unsigned char *end)
00047 {
00048         const RecordStateTableField *field = (const RecordStateTableField *) begin;
00049 
00050         // advance and check size
00051         begin += sizeof(RecordStateTableField);
00052         if( begin > end )               // if begin==end, we are ok
00053                 return begin;
00054 
00055         State state;
00056         state.Index = btohs(field->index);
00057         state.RecordId = btohl(field->uniqueId);
00058         state.Dirty = (field->flags & BARRY_RSTF_DIRTY) != 0;
00059         state.RecType = field->rectype;
00060         state.Unknown2.assign((const char*)field->unknown2, sizeof(field->unknown2));
00061         StateMap[state.Index] = state;
00062 
00063         return begin;
00064 }
00065 
00066 void RecordStateTable::Parse(const Data &data)
00067 {
00068         size_t offset = 12;     // skipping the unknown 2 bytes at start
00069 
00070         if( offset >= data.GetSize() )
00071                 return;
00072 
00073         const unsigned char *begin = data.GetData() + offset;
00074         const unsigned char *end = data.GetData() + data.GetSize();
00075 
00076         while( begin < end )
00077                 begin = ParseField(begin, end);
00078 }
00079 
00080 void RecordStateTable::Clear()
00081 {
00082         StateMap.clear();
00083         m_LastNewRecordId = 1;
00084 }
00085 
00086 // Searches the StateMap table for RecordId, and returns the "index"
00087 // in the map if found.  Returns true if found, false if not.
00088 // pFoundIndex can be null if only the existence of the index is desired
00089 bool RecordStateTable::GetIndex(uint32_t RecordId, IndexType *pFoundIndex) const
00090 {
00091         StateMapType::const_iterator i = StateMap.begin();
00092         for( ; i != StateMap.end(); ++i ) {
00093                 if( i->second.RecordId == RecordId ) {
00094                         if( pFoundIndex )
00095                                 *pFoundIndex = i->first;
00096                         return true;
00097                 }
00098         }
00099         return false;
00100 }
00101 
00102 // Generate a new RecordId that is not in the state table.
00103 // Starts at 1 and keeps incrementing until a free one is found.
00104 uint32_t RecordStateTable::MakeNewRecordId() const
00105 {
00106         // start with next Id
00107         m_LastNewRecordId++;
00108 
00109         // make sure it doesn't already exist
00110         StateMapType::const_iterator i = StateMap.begin();
00111         while( i != StateMap.end() ) {
00112                 if( m_LastNewRecordId == i->second.RecordId ) {
00113                         m_LastNewRecordId++;            // try again
00114                         i = StateMap.begin();           // start over
00115                 }
00116                 else {
00117                         ++i;                            // next State
00118                 }
00119         }
00120         return m_LastNewRecordId;
00121 }
00122 
00123 void RecordStateTable::Dump(std::ostream &os) const
00124 {
00125         ios::fmtflags oldflags = os.setf(ios::right);
00126         char fill = os.fill(' ');
00127         bool bPrintAscii = Data::PrintAscii();
00128         Data::PrintAscii(false);
00129 
00130         os << "  Index  RecordId    Dirty  RecType" << endl;
00131         os << "-------  ----------  -----  -------" << endl;
00132 
00133         StateMapType::const_iterator b, e = StateMap.end();
00134         for( b = StateMap.begin(); b != e ; ++b ) {
00135                 const State &state = b->second;
00136 
00137                 os.fill(' ');
00138                 os << setbase(10) << setw(7) << state.Index;
00139                 os << "  0x" << setbase(16) << setfill('0') << setw(8) << state.RecordId;
00140                 os << "  " << setfill(' ') << setw(5) << (state.Dirty ? "yes" : "no");
00141                 os << "     0x" << setbase(16) << setfill('0') << setw(2) << state.RecType;
00142                 os << "   " << Data(state.Unknown2.data(), state.Unknown2.size());
00143         }
00144 
00145         // cleanup the stream
00146         os.flags(oldflags);
00147         os.fill(fill);
00148         Data::PrintAscii(bPrintAscii);
00149 }
00150 
00151 
00152 } // namespace Barry
00153