- fixed compile error on g++ 3.3 systems (missing stdint.h in probe.h)
[barry.git] / src / data.cc
blob67de7b7119d12df73b0990d3460db0cd1e915098
1 ///
2 /// \file data.cc
3 /// Classes to help manage pre-determined data files.
4 ///
6 /*
7 Copyright (C) 2005-2006, Net Direct Inc. (http://www.netdirect.ca/)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 See the GNU General Public License in the COPYING file at the
19 root directory of this project for more details.
22 #include "data.h"
23 #include <fstream>
24 #include <sstream>
25 #include <iomanip>
26 #include <string>
27 #include <stdexcept>
29 //#define __DEBUG_MODE__
30 #include "debug.h"
33 using namespace std;
36 inline bool IsHexData(const std::string &s)
38 const char *str = s.c_str();
39 for( int i = 0; i < 4 && *str; str++, i++ )
40 if( *str != ' ' )
41 return false;
43 for( int i = 0; i < 8 && *str; str++, i++ )
44 if( !isdigit(*str) && !(*str >= 'a' && *str <= 'f') )
45 return false;
47 if( *str != ':' )
48 return false;
50 return true;
55 ///////////////////////////////////////////////////////////////////////////////
56 // Data class
58 bool Data::bPrintAscii = true;
60 Data::Data()
61 : m_data(new unsigned char[0x4000]),
62 m_bufsize(0x4000),
63 m_datasize(0),
64 m_endpoint(-1),
65 m_externalData(0),
66 m_external(false)
68 memset(m_data, 0, m_bufsize);
71 Data::Data(int endpoint, size_t startsize)
72 : m_data(new unsigned char[startsize]),
73 m_bufsize(startsize),
74 m_datasize(0),
75 m_endpoint(endpoint),
76 m_externalData(0),
77 m_external(false)
79 memset(m_data, 0, m_bufsize);
82 Data::Data(const void *ValidData, size_t size)
83 : m_data(0),
84 m_bufsize(0),
85 m_datasize(size),
86 m_endpoint(-1),
87 m_externalData((const unsigned char*)ValidData),
88 m_external(true)
92 Data::Data(const Data &other)
93 : m_data(other.m_bufsize ? new unsigned char[other.m_bufsize] : 0),
94 m_bufsize(other.m_bufsize),
95 m_datasize(other.m_datasize),
96 m_endpoint(other.m_endpoint),
97 m_externalData(other.m_externalData),
98 m_external(other.m_external)
100 // copy over the raw data
101 if( !m_external )
102 memcpy(m_data, other.m_data, other.m_bufsize);
105 Data::~Data()
107 delete [] m_data;
110 void Data::MakeSpace(size_t desiredsize)
112 if( m_bufsize < desiredsize ) {
113 desiredsize += 1024; // get a proper chunk
114 unsigned char *newbuf = new unsigned char[desiredsize];
115 memcpy(newbuf, m_data, m_bufsize);
116 memset(newbuf + m_bufsize, 0, desiredsize - m_bufsize);
117 delete [] m_data;
118 m_data = newbuf;
119 m_bufsize = desiredsize;
123 // perform the copy on write operation if needed
124 void Data::CopyOnWrite(size_t desiredsize)
126 if( m_external ) {
127 // make room
128 MakeSpace(std::max(desiredsize, m_datasize));
130 // copy it over
131 memcpy(m_data, m_externalData, m_datasize);
133 // not external anymore
134 m_external = false;
138 void Data::InputHexLine(istream &is)
140 unsigned int values[16];
141 size_t index = 0;
143 size_t address;
144 is >> setbase(16) >> address;
145 if( !is )
146 return; // nothing to do
148 is.ignore(); // eat the ':'
150 while( is && index < 16 ) {
151 is >> setbase(16) >> values[index];
152 if( is )
153 index++;
156 dout("InputHexLine: read " << index << " bytes");
158 CopyOnWrite(address + index);
159 MakeSpace(address + index); // make space for the new
160 m_datasize = std::max(address + index, m_datasize);
161 while( index-- )
162 m_data[address + index] = (unsigned char) values[index];
163 return;
166 void Data::DumpHexLine(ostream &os, size_t index, size_t size) const
168 ios::fmtflags oldflags = os.setf(ios::right);
170 // index
171 os << " ";
172 os << setbase(16) << setfill('0') << setw(8)
173 << index << ": ";
175 // hex byte data
176 for( size_t i = 0; i < size; i++ ) {
177 if( (index+i) < GetSize() ) {
178 os << setbase(16) << setfill('0')
179 << setw(2) << setprecision(2)
180 << (unsigned int) GetData()[index + i] << ' ';
182 else {
183 os << " ";
187 // printable data
188 if( bPrintAscii ) {
189 os << ' ';
190 for( size_t i = 0; i < size && (index+i) < GetSize(); i++ ) {
191 int c = GetData()[index + i];
192 os << setbase(10) << (char) (isprint(c) ? c : '.');
196 os << "\n";
197 os.flags(oldflags);
200 void Data::DumpHex(ostream &os) const
202 for( size_t address = 0; address < GetSize(); address += 16 ) {
203 DumpHexLine(os, address, 16);
207 unsigned char * Data::GetBuffer(size_t requiredsize)
209 CopyOnWrite(requiredsize);
210 if( requiredsize > 0 )
211 MakeSpace(requiredsize);
212 return m_data;
215 void Data::ReleaseBuffer(int datasize)
217 assert( datasize <= m_bufsize );
218 assert( datasize >= 0 || datasize == -1 );
219 assert( !m_external );
221 if( datasize >= 0 ) {
222 m_datasize = datasize;
224 else {
225 // search for last non-zero value in buffer
226 m_datasize = m_bufsize - 1;
227 while( m_datasize && m_data[m_datasize] == 0 )
228 --m_datasize;
232 /// set buffer to 0 and remove all data
233 void Data::Zap()
235 if( !m_external )
236 memset(m_data, 0, m_bufsize);
237 m_datasize = 0;
240 Data & Data::operator=(const Data &other)
242 if( this == &other )
243 return *this;
245 // don't remove our current buffer, only grow it if needed
246 MakeSpace(other.m_bufsize);
247 memcpy(m_data, other.m_data, other.m_bufsize);
249 // then copy over the data state
250 m_datasize = other.m_datasize;
251 m_endpoint = other.m_endpoint;
252 m_externalData = other.m_externalData;
253 m_external = other.m_external;
254 return *this;
257 istream& operator>> (istream &is, Data &data)
259 data.InputHexLine(is);
260 return is;
263 ostream& operator<< (ostream &os, const Data &data)
265 data.DumpHex(os);
266 return os;
270 ///////////////////////////////////////////////////////////////////////////////
271 // Diff class
273 Diff::Diff(const Data &old, const Data &new_)
274 : m_old(old), m_new(new_)
278 void Diff::Compare(ostream &os, size_t index, size_t size) const
280 size_t min = std::min(m_old.GetSize(), m_new.GetSize());
282 // index
283 os << "> ";
284 os << setbase(16) << setfill('0') << setw(8)
285 << index << ": ";
287 // diff data
288 for( size_t i = 0; i < size; i++ ) {
289 size_t address = index + i;
291 // if data is available, print the diff
292 if( address < min ) {
293 if( m_old.GetData()[address] != m_new.GetData()[address] ) {
294 // differ, print hex
295 os << setbase(16) << setfill('0')
296 << setw(2) << setprecision(2)
297 << (unsigned int) m_new.GetData()[address] << ' ';
299 else {
300 // same, just print spaces
301 os << " ";
304 else {
305 // one of the buffers is shorter...
306 if( address < m_new.GetSize() ) {
307 // new still has data, print it
308 os << setbase(16) << setfill('0')
309 << setw(2) << setprecision(2)
310 << (unsigned int) m_new.GetData()[address]
311 << ' ';
313 else if( address < m_old.GetSize() ) {
314 // new is out of data and old still has some
315 os << "XX ";
317 else {
318 // no more data, just print spaces
319 os << " ";
324 // printable data, just dump new
325 if( Data::PrintAscii() ) {
326 os << ' ';
327 for( size_t i = 0; i < size && (index+i) < m_new.GetSize(); i++ ) {
328 int c = m_new.GetData()[index + i];
329 os << setbase(10) << (char) (isprint(c) ? c : '.');
333 os << "\n";
336 void Diff::Dump(std::ostream &os) const
338 if( m_old.GetSize() != m_new.GetSize() )
339 os << "sizes differ: "
340 << m_old.GetSize() << " != " << m_new.GetSize() << endl;
342 size_t max = std::max(m_old.GetSize(), m_new.GetSize());
343 for( size_t i = 0; i < max; i += 16 ) {
344 m_old.DumpHexLine(os, i, 16);
345 Compare(os, i, 16);
349 ostream& operator<< (ostream &os, const Diff &diff)
351 diff.Dump(os);
352 return os;
356 ///////////////////////////////////////////////////////////////////////////////
357 // Utility functions
359 static bool IsEndpointStart(const std::string &line, int &endpoint)
361 if( strncmp(line.c_str(), "sep: ", 5) == 0 ||
362 strncmp(line.c_str(), "rep: ", 5) == 0 )
364 endpoint = atoi(line.c_str() + 5);
365 return true;
367 return false;
370 bool LoadDataArray(const string &filename, std::vector<Data> &array)
372 ifstream in(filename.c_str());
373 if( !in )
374 return false;
376 bool bInEndpoint = false;
377 unsigned int nCurrent = 0;
378 size_t nLargestSize = 0x100;
379 while( in ) {
380 string line;
381 getline(in, line);
382 int endpoint;
383 if( bInEndpoint ) {
384 if( IsHexData(line) ) {
385 istringstream sline(line);
386 sline >> array[nCurrent];
387 continue;
389 else {
390 nLargestSize = std::max(nLargestSize,
391 array[nCurrent].GetBufSize());
392 bInEndpoint = false;
396 // check if this line starts a new endpoint
397 if( IsEndpointStart(line, endpoint) ) {
398 bInEndpoint = true;
399 Data chunk(endpoint, nLargestSize);
400 array.push_back(chunk);
401 nCurrent = array.size() - 1;
404 return true;
408 #ifdef __TEST_MODE__
410 #include <iostream>
411 #include <iomanip>
412 #include "data.h"
414 using namespace std;
416 int main()
418 typedef std::vector<Data> DataVec;
419 DataVec array;
420 if( !LoadDataArray("data/parsed.log", array) ) {
421 cout << "Can't load file" << endl;
422 return 1;
425 DataVec::iterator i = array.begin();
426 Data::PrintAscii(false);
427 for( ; i != array.end(); i++ ) {
428 cout << "Endpoint: " << i->GetEndpoint() << endl;
429 cout << *i;
430 cout << "\n\n";
434 Data one, two;
435 one.GetBuffer()[0] = 0x01;
436 one.ReleaseBuffer(1);
437 two.GetBuffer()[0] = 0x02;
438 two.ReleaseBuffer(2);
440 cout << Diff(one, two) << endl;
441 cout << Diff(two, one) << endl;
443 two.GetBuffer();
444 two.ReleaseBuffer(32);
445 cout << Diff(one, two) << endl;
448 #endif