data.cc

Go to the documentation of this file.
00001 ///
00002 /// \file       data.cc
00003 ///             Classes to help manage pre-determined data files.
00004 ///
00005 
00006 /*
00007     Copyright (C) 2005-2009, 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 "data.h"
00023 #include <fstream>
00024 #include <sstream>
00025 #include <iomanip>
00026 #include <string>
00027 #include <stdexcept>
00028 #include <string.h>
00029 #include <stdlib.h>
00030 
00031 //#define __DEBUG_MODE__
00032 #include "debug.h"
00033 
00034 
00035 using namespace std;
00036 
00037 
00038 namespace Barry {
00039 
00040 inline bool IsHexData(const std::string &s)
00041 {
00042         const char *str = s.c_str();
00043         for( int i = 0; i < 4 && *str; str++, i++ )
00044                 if( *str != ' ' )
00045                         return false;
00046 
00047         for( int i = 0; i < 8 && *str; str++, i++ ) {
00048                 const char *hexchars = "0123456789abcdef";
00049                 if( strchr(hexchars, *str) == NULL )
00050                         return false;
00051         }
00052 
00053         if( *str != ':' )
00054                 return false;
00055 
00056         return true;
00057 }
00058 
00059 
00060 
00061 ///////////////////////////////////////////////////////////////////////////////
00062 // Data class
00063 
00064 bool Data::bPrintAscii = true;
00065 
00066 Data::Data()
00067         : m_data(new unsigned char[0x4000]),
00068         m_bufsize(0x4000),
00069         m_datasize(0),
00070         m_endpoint(-1),
00071         m_externalData(0),
00072         m_external(false)
00073 {
00074         memset(m_data, 0, m_bufsize);
00075 }
00076 
00077 Data::Data(int endpoint, size_t startsize)
00078         : m_data(new unsigned char[startsize]),
00079         m_bufsize(startsize),
00080         m_datasize(0),
00081         m_endpoint(endpoint),
00082         m_externalData(0),
00083         m_external(false)
00084 {
00085         memset(m_data, 0, m_bufsize);
00086 }
00087 
00088 Data::Data(const void *ValidData, size_t size)
00089         : m_data(0),
00090         m_bufsize(0),
00091         m_datasize(size),
00092         m_endpoint(-1),
00093         m_externalData((const unsigned char*)ValidData),
00094         m_external(true)
00095 {
00096 }
00097 
00098 Data::Data(const Data &other)
00099         : m_data(other.m_bufsize ? new unsigned char[other.m_bufsize] : 0),
00100         m_bufsize(other.m_bufsize),
00101         m_datasize(other.m_datasize),
00102         m_endpoint(other.m_endpoint),
00103         m_externalData(other.m_externalData),
00104         m_external(other.m_external)
00105 {
00106         // copy over the raw data
00107         if( !m_external )
00108                 memcpy(m_data, other.m_data, other.m_bufsize);
00109 }
00110 
00111 Data::~Data()
00112 {
00113         delete [] m_data;
00114 }
00115 
00116 void Data::MakeSpace(size_t desiredsize)
00117 {
00118         if( m_bufsize < desiredsize ) {
00119                 desiredsize += 1024;    // get a proper chunk
00120                 unsigned char *newbuf = new unsigned char[desiredsize];
00121                 memcpy(newbuf, m_data, m_bufsize);
00122                 memset(newbuf + m_bufsize, 0, desiredsize - m_bufsize);
00123                 delete [] m_data;
00124                 m_data = newbuf;
00125                 m_bufsize = desiredsize;
00126         }
00127 }
00128 
00129 // perform the copy on write operation if needed
00130 void Data::CopyOnWrite(size_t desiredsize)
00131 {
00132         if( m_external ) {
00133                 // make room
00134                 MakeSpace(std::max(desiredsize, m_datasize));
00135 
00136                 // copy it over
00137                 memcpy(m_data, m_externalData, m_datasize);
00138 
00139                 // not external anymore
00140                 m_external = false;
00141         }
00142 }
00143 
00144 void Data::InputHexLine(istream &is)
00145 {
00146         unsigned int values[16];
00147         size_t index = 0;
00148 
00149         size_t address;
00150         is >> setbase(16) >> address;
00151         if( !is )
00152                 return;         // nothing to do
00153 
00154         is.ignore();            // eat the ':'
00155 
00156         while( is && index < 16 ) {
00157                 is >> setbase(16) >> values[index];
00158                 if( is )
00159                         index++;
00160         }
00161 
00162         dout("InputHexLine: read " << index << " bytes");
00163 
00164         CopyOnWrite(address + index);
00165         MakeSpace(address + index);     // make space for the new
00166         m_datasize = std::max(address + index, m_datasize);
00167         while( index-- )
00168                 m_data[address + index] = (unsigned char) values[index];
00169         return;
00170 }
00171 
00172 void Data::DumpHexLine(ostream &os, size_t index, size_t size) const
00173 {
00174         ios::fmtflags oldflags = os.setf(ios::right);
00175 
00176         // index
00177         os << "    ";
00178         os << setbase(16) << setfill('0') << setw(8)
00179            << index << ": ";
00180 
00181         // hex byte data
00182         for( size_t i = 0; i < size; i++ ) {
00183                 if( (index+i) < GetSize() ) {
00184                         os << setbase(16) << setfill('0')
00185                            << setw(2) << setprecision(2)
00186                            << (unsigned int) GetData()[index + i] << ' ';
00187                 }
00188                 else {
00189                         os << "   ";
00190                 }
00191         }
00192 
00193         // printable data
00194         if( bPrintAscii ) {
00195                 locale loc = os.getloc();
00196                 os << ' ';
00197                 for( size_t i = 0; i < size && (index+i) < GetSize(); i++ ) {
00198                         ostream::traits_type::char_type c = GetData()[index + i];
00199                         os << setbase(10) << (char) (isprint(c, loc) ? c : '.');
00200                 }
00201         }
00202 
00203         os << "\n";
00204         os.flags(oldflags);
00205 }
00206 
00207 void Data::DumpHex(ostream &os) const
00208 {
00209         for( size_t address = 0; address < GetSize(); address += 16 ) {
00210                 DumpHexLine(os, address, 16);
00211         }
00212 }
00213 
00214 unsigned char * Data::GetBuffer(size_t requiredsize)
00215 {
00216         CopyOnWrite(requiredsize);
00217         if( requiredsize > 0 )
00218                 MakeSpace(requiredsize);
00219         return m_data;
00220 }
00221 
00222 void Data::ReleaseBuffer(int datasize)
00223 {
00224         assert( datasize >= 0 || datasize == -1 );
00225         assert( datasize == -1 || (unsigned int)datasize <= m_bufsize );
00226         assert( !m_external );
00227 
00228         if( m_external )
00229                 return;
00230         if( datasize >= 0 && (unsigned int)datasize > m_bufsize ) {
00231                 dout("ReleaseBuffer called with datasize("
00232                         << std::dec << datasize << ") > m_bufsize("
00233                         << m_bufsize << ")");
00234                 return;
00235         }
00236 
00237         if( datasize >= 0 ) {
00238                 m_datasize = datasize;
00239         }
00240         else {
00241                 // search for last non-zero value in buffer
00242                 m_datasize = m_bufsize - 1;
00243                 while( m_datasize && m_data[m_datasize] == 0 )
00244                         --m_datasize;
00245         }
00246 }
00247 
00248 /// Append bytes of data based on str
00249 void Data::AppendHexString(const char *str)
00250 {
00251         CopyOnWrite(m_datasize + 512);
00252 
00253         std::istringstream iss(str);
00254         unsigned int byte;
00255         while( iss >> hex >> byte ) {
00256                 MakeSpace(m_datasize + 1);
00257                 m_data[m_datasize] = (unsigned char) byte;
00258                 m_datasize++;
00259         }
00260 }
00261 
00262 /// set buffer to 0 and remove all data
00263 void Data::Zap()
00264 {
00265         if( !m_external )
00266                 memset(m_data, 0, m_bufsize);
00267         m_datasize = 0;
00268 }
00269 
00270 Data & Data::operator=(const Data &other)
00271 {
00272         if( this == &other )
00273                 return *this;
00274 
00275         // don't remove our current buffer, only grow it if needed
00276         MakeSpace(other.m_bufsize);
00277         memcpy(m_data, other.m_data, other.m_bufsize);
00278 
00279         // then copy over the data state
00280         m_datasize = other.m_datasize;
00281         m_endpoint = other.m_endpoint;
00282         m_externalData = other.m_externalData;
00283         m_external = other.m_external;
00284         return *this;
00285 }
00286 
00287 istream& operator>> (istream &is, Data &data)
00288 {
00289         data.InputHexLine(is);
00290         return is;
00291 }
00292 
00293 ostream& operator<< (ostream &os, const Data &data)
00294 {
00295         data.DumpHex(os);
00296         return os;
00297 }
00298 
00299 
00300 ///////////////////////////////////////////////////////////////////////////////
00301 // Diff class
00302 
00303 Diff::Diff(const Data &old, const Data &new_)
00304         : m_old(old), m_new(new_)
00305 {
00306 }
00307 
00308 void Diff::Compare(ostream &os, size_t index, size_t size) const
00309 {
00310         size_t min = std::min(m_old.GetSize(), m_new.GetSize());
00311 
00312         // index
00313         os << ">   ";
00314         os << setbase(16) << setfill('0') << setw(8)
00315            << index << ": ";
00316 
00317         // diff data
00318         for( size_t i = 0; i < size; i++ ) {
00319                 size_t address = index + i;
00320 
00321                 // if data is available, print the diff
00322                 if( address < min ) {
00323                         if( m_old.GetData()[address] != m_new.GetData()[address] ) {
00324                                 // differ, print hex
00325                                 os << setbase(16) << setfill('0')
00326                                    << setw(2) << setprecision(2)
00327                                    << (unsigned int) m_new.GetData()[address] << ' ';
00328                         }
00329                         else {
00330                                 // same, just print spaces
00331                                 os << "   ";
00332                         }
00333                 }
00334                 else {
00335                         // one of the buffers is shorter...
00336                         if( address < m_new.GetSize() ) {
00337                                 // new still has data, print it
00338                                 os << setbase(16) << setfill('0')
00339                                    << setw(2) << setprecision(2)
00340                                    << (unsigned int) m_new.GetData()[address]
00341                                    << ' ';
00342                         }
00343                         else if( address < m_old.GetSize() ) {
00344                                 // new is out of data and old still has some
00345                                 os << "XX ";
00346                         }
00347                         else {
00348                                 // no more data, just print spaces
00349                                 os << "   ";
00350                         }
00351                 }
00352         }
00353 
00354         // printable data, just dump new
00355         if( Data::PrintAscii() ) {
00356                 os << ' ';
00357                 for( size_t i = 0; i < size && (index+i) < m_new.GetSize(); i++ ) {
00358                         int c = m_new.GetData()[index + i];
00359                         os << setbase(10) << (char) (isprint(c) ? c : '.');
00360                 }
00361         }
00362 
00363         os << "\n";
00364 }
00365 
00366 void Diff::Dump(std::ostream &os) const
00367 {
00368         if( m_old.GetSize() != m_new.GetSize() )
00369                 os << "sizes differ: "
00370                    << m_old.GetSize() << " != " << m_new.GetSize() << endl;
00371 
00372         size_t max = std::max(m_old.GetSize(), m_new.GetSize());
00373         for( size_t i = 0; i < max; i += 16 ) {
00374                 m_old.DumpHexLine(os, i, 16);
00375                 Compare(os, i, 16);
00376         }
00377 }
00378 
00379 ostream& operator<< (ostream &os, const Diff &diff)
00380 {
00381         diff.Dump(os);
00382         return os;
00383 }
00384 
00385 
00386 ///////////////////////////////////////////////////////////////////////////////
00387 // Utility functions
00388 
00389 static bool IsEndpointStart(const std::string &line, int &endpoint)
00390 {
00391         if( strncmp(line.c_str(), "sep: ", 5) == 0 ||
00392             strncmp(line.c_str(), "rep: ", 5) == 0 )
00393         {
00394                 endpoint = atoi(line.c_str() + 5);
00395                 return true;
00396         }
00397         return false;
00398 }
00399 
00400 bool LoadDataArray(const string &filename, std::vector<Data> &array)
00401 {
00402         ifstream in(filename.c_str());
00403         return ReadDataArray(in, array);
00404 }
00405 
00406 bool ReadDataArray(std::istream &is, std::vector<Data> &array)
00407 {
00408         if( !is )
00409                 return false;
00410 
00411         bool bInEndpoint = false;
00412         unsigned int nCurrent = 0;
00413         size_t nLargestSize = 0x100;
00414         while( is ) {
00415                 string line;
00416                 getline(is, line);
00417                 int endpoint;
00418                 if( bInEndpoint ) {
00419                         if( IsHexData(line) ) {
00420                                 istringstream sline(line);
00421                                 sline >> array[nCurrent];
00422                                 continue;
00423                         }
00424                         else {
00425                                 nLargestSize = std::max(nLargestSize,
00426                                         array[nCurrent].GetBufSize());
00427                                 bInEndpoint = false;
00428                         }
00429                 }
00430 
00431                 // check if this line starts a new endpoint
00432                 if( IsEndpointStart(line, endpoint) ) {
00433                         bInEndpoint = true;
00434                         Data chunk(endpoint, nLargestSize);
00435                         array.push_back(chunk);
00436                         nCurrent = array.size() - 1;
00437                 }
00438         }
00439         return true;
00440 }
00441 
00442 } // namespace Barry
00443 
00444 
00445 #ifdef __TEST_MODE__
00446 
00447 #include <iostream>
00448 #include <iomanip>
00449 #include "data.h"
00450 
00451 using namespace std;
00452 
00453 int main()
00454 {
00455         typedef std::vector<Data> DataVec;
00456         DataVec array;
00457         if( !LoadDataArray("data/parsed.log", array) ) {
00458                 cout << "Can't load file" << endl;
00459                 return 1;
00460         }
00461 
00462         DataVec::iterator i = array.begin();
00463         Data::PrintAscii(false);
00464         for( ; i != array.end(); i++ ) {
00465                 cout << "Endpoint: " << i->GetEndpoint() << endl;
00466                 cout << *i;
00467                 cout << "\n\n";
00468         }
00469 
00470 
00471         Data one, two;
00472         one.GetBuffer()[0] = 0x01;
00473         one.ReleaseBuffer(1);
00474         two.GetBuffer()[0] = 0x02;
00475         two.ReleaseBuffer(2);
00476 
00477         cout << Diff(one, two) << endl;
00478         cout << Diff(two, one) << endl;
00479 
00480         two.GetBuffer();
00481         two.ReleaseBuffer(32);
00482         cout << Diff(one, two) << endl;
00483 }
00484 
00485 #endif
00486 

Generated on Mon Jan 12 10:51:12 2009 for Barry by  doxygen 1.5.7.1