Release tarball for barry-0.9
[barry.git] / src / data.cc
blob29f319c58e8e4ba753be124d3f9cd4e8a7c4920a
1 ///
2 /// \file data.cc
3 /// Classes to help manage pre-determined data files.
4 ///
6 /*
7 Copyright (C) 2005-2007, 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 namespace Barry {
38 inline bool IsHexData(const std::string &s)
40 const char *str = s.c_str();
41 for( int i = 0; i < 4 && *str; str++, i++ )
42 if( *str != ' ' )
43 return false;
45 for( int i = 0; i < 8 && *str; str++, i++ )
46 if( !isdigit(*str) && !(*str >= 'a' && *str <= 'f') )
47 return false;
49 if( *str != ':' )
50 return false;
52 return true;
57 ///////////////////////////////////////////////////////////////////////////////
58 // Data class
60 bool Data::bPrintAscii = true;
62 Data::Data()
63 : m_data(new unsigned char[0x4000]),
64 m_bufsize(0x4000),
65 m_datasize(0),
66 m_endpoint(-1),
67 m_externalData(0),
68 m_external(false)
70 memset(m_data, 0, m_bufsize);
73 Data::Data(int endpoint, size_t startsize)
74 : m_data(new unsigned char[startsize]),
75 m_bufsize(startsize),
76 m_datasize(0),
77 m_endpoint(endpoint),
78 m_externalData(0),
79 m_external(false)
81 memset(m_data, 0, m_bufsize);
84 Data::Data(const void *ValidData, size_t size)
85 : m_data(0),
86 m_bufsize(0),
87 m_datasize(size),
88 m_endpoint(-1),
89 m_externalData((const unsigned char*)ValidData),
90 m_external(true)
94 Data::Data(const Data &other)
95 : m_data(other.m_bufsize ? new unsigned char[other.m_bufsize] : 0),
96 m_bufsize(other.m_bufsize),
97 m_datasize(other.m_datasize),
98 m_endpoint(other.m_endpoint),
99 m_externalData(other.m_externalData),
100 m_external(other.m_external)
102 // copy over the raw data
103 if( !m_external )
104 memcpy(m_data, other.m_data, other.m_bufsize);
107 Data::~Data()
109 delete [] m_data;
112 void Data::MakeSpace(size_t desiredsize)
114 if( m_bufsize < desiredsize ) {
115 desiredsize += 1024; // get a proper chunk
116 unsigned char *newbuf = new unsigned char[desiredsize];
117 memcpy(newbuf, m_data, m_bufsize);
118 memset(newbuf + m_bufsize, 0, desiredsize - m_bufsize);
119 delete [] m_data;
120 m_data = newbuf;
121 m_bufsize = desiredsize;
125 // perform the copy on write operation if needed
126 void Data::CopyOnWrite(size_t desiredsize)
128 if( m_external ) {
129 // make room
130 MakeSpace(std::max(desiredsize, m_datasize));
132 // copy it over
133 memcpy(m_data, m_externalData, m_datasize);
135 // not external anymore
136 m_external = false;
140 void Data::InputHexLine(istream &is)
142 unsigned int values[16];
143 size_t index = 0;
145 size_t address;
146 is >> setbase(16) >> address;
147 if( !is )
148 return; // nothing to do
150 is.ignore(); // eat the ':'
152 while( is && index < 16 ) {
153 is >> setbase(16) >> values[index];
154 if( is )
155 index++;
158 dout("InputHexLine: read " << index << " bytes");
160 CopyOnWrite(address + index);
161 MakeSpace(address + index); // make space for the new
162 m_datasize = std::max(address + index, m_datasize);
163 while( index-- )
164 m_data[address + index] = (unsigned char) values[index];
165 return;
168 void Data::DumpHexLine(ostream &os, size_t index, size_t size) const
170 ios::fmtflags oldflags = os.setf(ios::right);
172 // index
173 os << " ";
174 os << setbase(16) << setfill('0') << setw(8)
175 << index << ": ";
177 // hex byte data
178 for( size_t i = 0; i < size; i++ ) {
179 if( (index+i) < GetSize() ) {
180 os << setbase(16) << setfill('0')
181 << setw(2) << setprecision(2)
182 << (unsigned int) GetData()[index + i] << ' ';
184 else {
185 os << " ";
189 // printable data
190 if( bPrintAscii ) {
191 os << ' ';
192 for( size_t i = 0; i < size && (index+i) < GetSize(); i++ ) {
193 int c = GetData()[index + i];
194 os << setbase(10) << (char) (isprint(c) ? c : '.');
198 os << "\n";
199 os.flags(oldflags);
202 void Data::DumpHex(ostream &os) const
204 for( size_t address = 0; address < GetSize(); address += 16 ) {
205 DumpHexLine(os, address, 16);
209 unsigned char * Data::GetBuffer(size_t requiredsize)
211 CopyOnWrite(requiredsize);
212 if( requiredsize > 0 )
213 MakeSpace(requiredsize);
214 return m_data;
217 void Data::ReleaseBuffer(int datasize)
219 assert( datasize >= 0 || datasize == -1 );
220 assert( datasize == -1 || (unsigned int)datasize <= m_bufsize );
221 assert( !m_external );
223 if( m_external )
224 return;
225 if( datasize >= 0 && (unsigned int)datasize > m_bufsize ) {
226 dout("ReleaseBuffer called with datasize("
227 << std::dec << datasize << ") > m_bufsize("
228 << m_bufsize << ")");
229 return;
232 if( datasize >= 0 ) {
233 m_datasize = datasize;
235 else {
236 // search for last non-zero value in buffer
237 m_datasize = m_bufsize - 1;
238 while( m_datasize && m_data[m_datasize] == 0 )
239 --m_datasize;
243 /// Append bytes of data based on str
244 void Data::AppendHexString(const char *str)
246 CopyOnWrite(m_datasize + 512);
248 std::istringstream iss(str);
249 unsigned int byte;
250 while( iss >> hex >> byte ) {
251 MakeSpace(m_datasize + 1);
252 m_data[m_datasize] = (unsigned char) byte;
253 m_datasize++;
257 /// set buffer to 0 and remove all data
258 void Data::Zap()
260 if( !m_external )
261 memset(m_data, 0, m_bufsize);
262 m_datasize = 0;
265 Data & Data::operator=(const Data &other)
267 if( this == &other )
268 return *this;
270 // don't remove our current buffer, only grow it if needed
271 MakeSpace(other.m_bufsize);
272 memcpy(m_data, other.m_data, other.m_bufsize);
274 // then copy over the data state
275 m_datasize = other.m_datasize;
276 m_endpoint = other.m_endpoint;
277 m_externalData = other.m_externalData;
278 m_external = other.m_external;
279 return *this;
282 istream& operator>> (istream &is, Data &data)
284 data.InputHexLine(is);
285 return is;
288 ostream& operator<< (ostream &os, const Data &data)
290 data.DumpHex(os);
291 return os;
295 ///////////////////////////////////////////////////////////////////////////////
296 // Diff class
298 Diff::Diff(const Data &old, const Data &new_)
299 : m_old(old), m_new(new_)
303 void Diff::Compare(ostream &os, size_t index, size_t size) const
305 size_t min = std::min(m_old.GetSize(), m_new.GetSize());
307 // index
308 os << "> ";
309 os << setbase(16) << setfill('0') << setw(8)
310 << index << ": ";
312 // diff data
313 for( size_t i = 0; i < size; i++ ) {
314 size_t address = index + i;
316 // if data is available, print the diff
317 if( address < min ) {
318 if( m_old.GetData()[address] != m_new.GetData()[address] ) {
319 // differ, print hex
320 os << setbase(16) << setfill('0')
321 << setw(2) << setprecision(2)
322 << (unsigned int) m_new.GetData()[address] << ' ';
324 else {
325 // same, just print spaces
326 os << " ";
329 else {
330 // one of the buffers is shorter...
331 if( address < m_new.GetSize() ) {
332 // new still has data, print it
333 os << setbase(16) << setfill('0')
334 << setw(2) << setprecision(2)
335 << (unsigned int) m_new.GetData()[address]
336 << ' ';
338 else if( address < m_old.GetSize() ) {
339 // new is out of data and old still has some
340 os << "XX ";
342 else {
343 // no more data, just print spaces
344 os << " ";
349 // printable data, just dump new
350 if( Data::PrintAscii() ) {
351 os << ' ';
352 for( size_t i = 0; i < size && (index+i) < m_new.GetSize(); i++ ) {
353 int c = m_new.GetData()[index + i];
354 os << setbase(10) << (char) (isprint(c) ? c : '.');
358 os << "\n";
361 void Diff::Dump(std::ostream &os) const
363 if( m_old.GetSize() != m_new.GetSize() )
364 os << "sizes differ: "
365 << m_old.GetSize() << " != " << m_new.GetSize() << endl;
367 size_t max = std::max(m_old.GetSize(), m_new.GetSize());
368 for( size_t i = 0; i < max; i += 16 ) {
369 m_old.DumpHexLine(os, i, 16);
370 Compare(os, i, 16);
374 ostream& operator<< (ostream &os, const Diff &diff)
376 diff.Dump(os);
377 return os;
381 ///////////////////////////////////////////////////////////////////////////////
382 // Utility functions
384 static bool IsEndpointStart(const std::string &line, int &endpoint)
386 if( strncmp(line.c_str(), "sep: ", 5) == 0 ||
387 strncmp(line.c_str(), "rep: ", 5) == 0 )
389 endpoint = atoi(line.c_str() + 5);
390 return true;
392 return false;
395 bool LoadDataArray(const string &filename, std::vector<Data> &array)
397 ifstream in(filename.c_str());
398 return ReadDataArray(in, array);
401 bool ReadDataArray(std::istream &is, std::vector<Data> &array)
403 if( !is )
404 return false;
406 bool bInEndpoint = false;
407 unsigned int nCurrent = 0;
408 size_t nLargestSize = 0x100;
409 while( is ) {
410 string line;
411 getline(is, line);
412 int endpoint;
413 if( bInEndpoint ) {
414 if( IsHexData(line) ) {
415 istringstream sline(line);
416 sline >> array[nCurrent];
417 continue;
419 else {
420 nLargestSize = std::max(nLargestSize,
421 array[nCurrent].GetBufSize());
422 bInEndpoint = false;
426 // check if this line starts a new endpoint
427 if( IsEndpointStart(line, endpoint) ) {
428 bInEndpoint = true;
429 Data chunk(endpoint, nLargestSize);
430 array.push_back(chunk);
431 nCurrent = array.size() - 1;
434 return true;
437 } // namespace Barry
440 #ifdef __TEST_MODE__
442 #include <iostream>
443 #include <iomanip>
444 #include "data.h"
446 using namespace std;
448 int main()
450 typedef std::vector<Data> DataVec;
451 DataVec array;
452 if( !LoadDataArray("data/parsed.log", array) ) {
453 cout << "Can't load file" << endl;
454 return 1;
457 DataVec::iterator i = array.begin();
458 Data::PrintAscii(false);
459 for( ; i != array.end(); i++ ) {
460 cout << "Endpoint: " << i->GetEndpoint() << endl;
461 cout << *i;
462 cout << "\n\n";
466 Data one, two;
467 one.GetBuffer()[0] = 0x01;
468 one.ReleaseBuffer(1);
469 two.GetBuffer()[0] = 0x02;
470 two.ReleaseBuffer(2);
472 cout << Diff(one, two) << endl;
473 cout << Diff(two, one) << endl;
475 two.GetBuffer();
476 two.ReleaseBuffer(32);
477 cout << Diff(one, two) << endl;
480 #endif