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-2010, 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 void Data::MemCpy(size_t &offset, const void *src, size_t size)
00288 {
00289         unsigned char *pd = GetBuffer(offset + size) + offset;
00290         memcpy(pd, src, size);
00291         offset += size;
00292 }
00293 
00294 istream& operator>> (istream &is, Data &data)
00295 {
00296         data.InputHexLine(is);
00297         return is;
00298 }
00299 
00300 ostream& operator<< (ostream &os, const Data &data)
00301 {
00302         data.DumpHex(os);
00303         return os;
00304 }
00305 
00306 
00307 ///////////////////////////////////////////////////////////////////////////////
00308 // Diff class
00309 
00310 Diff::Diff(const Data &old, const Data &new_)
00311         : m_old(old), m_new(new_)
00312 {
00313 }
00314 
00315 void Diff::Compare(ostream &os, size_t index, size_t size) const
00316 {
00317         size_t min = std::min(m_old.GetSize(), m_new.GetSize());
00318 
00319         // index
00320         os << ">   ";
00321         os << setbase(16) << setfill('0') << setw(8)
00322            << index << ": ";
00323 
00324         // diff data
00325         for( size_t i = 0; i < size; i++ ) {
00326                 size_t address = index + i;
00327 
00328                 // if data is available, print the diff
00329                 if( address < min ) {
00330                         if( m_old.GetData()[address] != m_new.GetData()[address] ) {
00331                                 // differ, print hex
00332                                 os << setbase(16) << setfill('0')
00333                                    << setw(2) << setprecision(2)
00334                                    << (unsigned int) m_new.GetData()[address] << ' ';
00335                         }
00336                         else {
00337                                 // same, just print spaces
00338                                 os << "   ";
00339                         }
00340                 }
00341                 else {
00342                         // one of the buffers is shorter...
00343                         if( address < m_new.GetSize() ) {
00344                                 // new still has data, print it
00345                                 os << setbase(16) << setfill('0')
00346                                    << setw(2) << setprecision(2)
00347                                    << (unsigned int) m_new.GetData()[address]
00348                                    << ' ';
00349                         }
00350                         else if( address < m_old.GetSize() ) {
00351                                 // new is out of data and old still has some
00352                                 os << "XX ";
00353                         }
00354                         else {
00355                                 // no more data, just print spaces
00356                                 os << "   ";
00357                         }
00358                 }
00359         }
00360 
00361         // printable data, just dump new
00362         if( Data::PrintAscii() ) {
00363                 os << ' ';
00364                 for( size_t i = 0; i < size && (index+i) < m_new.GetSize(); i++ ) {
00365                         int c = m_new.GetData()[index + i];
00366                         os << setbase(10) << (char) (isprint(c) ? c : '.');
00367                 }
00368         }
00369 
00370         os << "\n";
00371 }
00372 
00373 void Diff::Dump(std::ostream &os) const
00374 {
00375         if( m_old.GetSize() != m_new.GetSize() )
00376                 os << "sizes differ: "
00377                    << m_old.GetSize() << " != " << m_new.GetSize() << endl;
00378 
00379         size_t max = std::max(m_old.GetSize(), m_new.GetSize());
00380         for( size_t i = 0; i < max; i += 16 ) {
00381                 m_old.DumpHexLine(os, i, 16);
00382                 Compare(os, i, 16);
00383         }
00384 }
00385 
00386 ostream& operator<< (ostream &os, const Diff &diff)
00387 {
00388         diff.Dump(os);
00389         return os;
00390 }
00391 
00392 
00393 ///////////////////////////////////////////////////////////////////////////////
00394 // Utility functions
00395 
00396 static bool IsEndpointStart(const std::string &line, int &endpoint)
00397 {
00398         if( strncmp(line.c_str(), "sep: ", 5) == 0 ||
00399             strncmp(line.c_str(), "rep: ", 5) == 0 )
00400         {
00401                 endpoint = atoi(line.c_str() + 5);
00402                 return true;
00403         }
00404         return false;
00405 }
00406 
00407 bool LoadDataArray(const string &filename, std::vector<Data> &array)
00408 {
00409         ifstream in(filename.c_str());
00410         return ReadDataArray(in, array);
00411 }
00412 
00413 bool ReadDataArray(std::istream &is, std::vector<Data> &array)
00414 {
00415         if( !is )
00416                 return false;
00417 
00418         bool bInEndpoint = false;
00419         unsigned int nCurrent = 0;
00420         size_t nLargestSize = 0x100;
00421         while( is ) {
00422                 string line;
00423                 getline(is, line);
00424                 int endpoint;
00425                 if( bInEndpoint ) {
00426                         if( IsHexData(line) ) {
00427                                 istringstream sline(line);
00428                                 sline >> array[nCurrent];
00429                                 continue;
00430                         }
00431                         else {
00432                                 nLargestSize = std::max(nLargestSize,
00433                                         array[nCurrent].GetBufSize());
00434                                 bInEndpoint = false;
00435                         }
00436                 }
00437 
00438                 // check if this line starts a new endpoint
00439                 if( IsEndpointStart(line, endpoint) ) {
00440                         bInEndpoint = true;
00441                         Data chunk(endpoint, nLargestSize);
00442                         array.push_back(chunk);
00443                         nCurrent = array.size() - 1;
00444                 }
00445         }
00446         return true;
00447 }
00448 
00449 } // namespace Barry
00450 
00451 
00452 #ifdef __TEST_MODE__
00453 
00454 #include <iostream>
00455 #include <iomanip>
00456 #include "data.h"
00457 
00458 using namespace std;
00459 
00460 int main()
00461 {
00462         typedef std::vector<Data> DataVec;
00463         DataVec array;
00464         if( !LoadDataArray("data/parsed.log", array) ) {
00465                 cout << "Can't load file" << endl;
00466                 return 1;
00467         }
00468 
00469         DataVec::iterator i = array.begin();
00470         Data::PrintAscii(false);
00471         for( ; i != array.end(); i++ ) {
00472                 cout << "Endpoint: " << i->GetEndpoint() << endl;
00473                 cout << *i;
00474                 cout << "\n\n";
00475         }
00476 
00477 
00478         Data one, two;
00479         one.GetBuffer()[0] = 0x01;
00480         one.ReleaseBuffer(1);
00481         two.GetBuffer()[0] = 0x02;
00482         two.ReleaseBuffer(2);
00483 
00484         cout << Diff(one, two) << endl;
00485         cout << Diff(two, one) << endl;
00486 
00487         two.GetBuffer();
00488         two.ReleaseBuffer(32);
00489         cout << Diff(one, two) << endl;
00490 }
00491 
00492 #endif
00493 

Generated on 29 Mar 2010 for Barry by  doxygen 1.6.1