Inlined Data::QuickZap()
[barry.git] / src / data.cc
blob2a51e28934359bcfcdec2f9cba6dca1af134235d
1 ///
2 /// \file data.cc
3 /// Classes to help manage pre-determined data files.
4 ///
6 /*
7 Copyright (C) 2005-2009, 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>
28 #include <string.h>
29 #include <stdlib.h>
31 //#define __DEBUG_MODE__
32 #include "debug.h"
35 using namespace std;
38 namespace Barry {
40 inline bool IsHexData(const std::string &s)
42 const char *str = s.c_str();
43 for( int i = 0; i < 4 && *str; str++, i++ )
44 if( *str != ' ' )
45 return false;
47 for( int i = 0; i < 8 && *str; str++, i++ ) {
48 const char *hexchars = "0123456789abcdef";
49 if( strchr(hexchars, *str) == NULL )
50 return false;
53 if( *str != ':' )
54 return false;
56 return true;
61 ///////////////////////////////////////////////////////////////////////////////
62 // Data class
64 bool Data::bPrintAscii = true;
66 Data::Data()
67 : m_data(new unsigned char[0x4000]),
68 m_bufsize(0x4000),
69 m_datasize(0),
70 m_endpoint(-1),
71 m_externalData(0),
72 m_external(false)
74 memset(m_data, 0, m_bufsize);
77 Data::Data(int endpoint, size_t startsize)
78 : m_data(new unsigned char[startsize]),
79 m_bufsize(startsize),
80 m_datasize(0),
81 m_endpoint(endpoint),
82 m_externalData(0),
83 m_external(false)
85 memset(m_data, 0, m_bufsize);
88 Data::Data(const void *ValidData, size_t size)
89 : m_data(0),
90 m_bufsize(0),
91 m_datasize(size),
92 m_endpoint(-1),
93 m_externalData((const unsigned char*)ValidData),
94 m_external(true)
98 Data::Data(const Data &other)
99 : m_data(other.m_bufsize ? new unsigned char[other.m_bufsize] : 0),
100 m_bufsize(other.m_bufsize),
101 m_datasize(other.m_datasize),
102 m_endpoint(other.m_endpoint),
103 m_externalData(other.m_externalData),
104 m_external(other.m_external)
106 // copy over the raw data
107 if( !m_external )
108 memcpy(m_data, other.m_data, other.m_bufsize);
111 Data::~Data()
113 delete [] m_data;
116 void Data::MakeSpace(size_t desiredsize)
118 if( m_bufsize < desiredsize ) {
119 desiredsize += 1024; // get a proper chunk
120 unsigned char *newbuf = new unsigned char[desiredsize];
121 memcpy(newbuf, m_data, m_bufsize);
122 memset(newbuf + m_bufsize, 0, desiredsize - m_bufsize);
123 delete [] m_data;
124 m_data = newbuf;
125 m_bufsize = desiredsize;
129 // perform the copy on write operation if needed
130 void Data::CopyOnWrite(size_t desiredsize)
132 if( m_external ) {
133 // make room
134 MakeSpace(std::max(desiredsize, m_datasize));
136 // copy it over
137 memcpy(m_data, m_externalData, m_datasize);
139 // not external anymore
140 m_external = false;
144 void Data::InputHexLine(istream &is)
146 unsigned int values[16];
147 size_t index = 0;
149 size_t address;
150 is >> setbase(16) >> address;
151 if( !is )
152 return; // nothing to do
154 is.ignore(); // eat the ':'
156 while( is && index < 16 ) {
157 is >> setbase(16) >> values[index];
158 if( is )
159 index++;
162 dout("InputHexLine: read " << index << " bytes");
164 CopyOnWrite(address + index);
165 MakeSpace(address + index); // make space for the new
166 m_datasize = std::max(address + index, m_datasize);
167 while( index-- )
168 m_data[address + index] = (unsigned char) values[index];
169 return;
172 void Data::DumpHexLine(ostream &os, size_t index, size_t size) const
174 ios::fmtflags oldflags = os.setf(ios::right);
176 // index
177 os << " ";
178 os << setbase(16) << setfill('0') << setw(8)
179 << index << ": ";
181 // hex byte data
182 for( size_t i = 0; i < size; i++ ) {
183 if( (index+i) < GetSize() ) {
184 os << setbase(16) << setfill('0')
185 << setw(2) << setprecision(2)
186 << (unsigned int) GetData()[index + i] << ' ';
188 else {
189 os << " ";
193 // printable data
194 if( bPrintAscii ) {
195 locale loc = os.getloc();
196 os << ' ';
197 for( size_t i = 0; i < size && (index+i) < GetSize(); i++ ) {
198 ostream::traits_type::char_type c = GetData()[index + i];
199 os << setbase(10) << (char) (isprint(c, loc) ? c : '.');
203 os << "\n";
204 os.flags(oldflags);
207 void Data::DumpHex(ostream &os) const
209 for( size_t address = 0; address < GetSize(); address += 16 ) {
210 DumpHexLine(os, address, 16);
214 unsigned char * Data::GetBuffer(size_t requiredsize)
216 CopyOnWrite(requiredsize);
217 if( requiredsize > 0 )
218 MakeSpace(requiredsize);
219 return m_data;
222 void Data::ReleaseBuffer(int datasize)
224 assert( datasize >= 0 || datasize == -1 );
225 assert( datasize == -1 || (unsigned int)datasize <= m_bufsize );
226 assert( !m_external );
228 if( m_external )
229 return;
230 if( datasize >= 0 && (unsigned int)datasize > m_bufsize ) {
231 dout("ReleaseBuffer called with datasize("
232 << std::dec << datasize << ") > m_bufsize("
233 << m_bufsize << ")");
234 return;
237 if( datasize >= 0 ) {
238 m_datasize = datasize;
240 else {
241 // search for last non-zero value in buffer
242 m_datasize = m_bufsize - 1;
243 while( m_datasize && m_data[m_datasize] == 0 )
244 --m_datasize;
248 /// Append bytes of data based on str
249 void Data::AppendHexString(const char *str)
251 CopyOnWrite(m_datasize + 512);
253 std::istringstream iss(str);
254 unsigned int byte;
255 while( iss >> hex >> byte ) {
256 MakeSpace(m_datasize + 1);
257 m_data[m_datasize] = (unsigned char) byte;
258 m_datasize++;
262 /// set buffer to 0 and remove all data
263 void Data::Zap()
265 if( !m_external )
266 memset(m_data, 0, m_bufsize);
267 m_datasize = 0;
270 Data & Data::operator=(const Data &other)
272 if( this == &other )
273 return *this;
275 // don't remove our current buffer, only grow it if needed
276 MakeSpace(other.m_bufsize);
277 memcpy(m_data, other.m_data, other.m_bufsize);
279 // then copy over the data state
280 m_datasize = other.m_datasize;
281 m_endpoint = other.m_endpoint;
282 m_externalData = other.m_externalData;
283 m_external = other.m_external;
284 return *this;
287 istream& operator>> (istream &is, Data &data)
289 data.InputHexLine(is);
290 return is;
293 ostream& operator<< (ostream &os, const Data &data)
295 data.DumpHex(os);
296 return os;
300 ///////////////////////////////////////////////////////////////////////////////
301 // Diff class
303 Diff::Diff(const Data &old, const Data &new_)
304 : m_old(old), m_new(new_)
308 void Diff::Compare(ostream &os, size_t index, size_t size) const
310 size_t min = std::min(m_old.GetSize(), m_new.GetSize());
312 // index
313 os << "> ";
314 os << setbase(16) << setfill('0') << setw(8)
315 << index << ": ";
317 // diff data
318 for( size_t i = 0; i < size; i++ ) {
319 size_t address = index + i;
321 // if data is available, print the diff
322 if( address < min ) {
323 if( m_old.GetData()[address] != m_new.GetData()[address] ) {
324 // differ, print hex
325 os << setbase(16) << setfill('0')
326 << setw(2) << setprecision(2)
327 << (unsigned int) m_new.GetData()[address] << ' ';
329 else {
330 // same, just print spaces
331 os << " ";
334 else {
335 // one of the buffers is shorter...
336 if( address < m_new.GetSize() ) {
337 // new still has data, print it
338 os << setbase(16) << setfill('0')
339 << setw(2) << setprecision(2)
340 << (unsigned int) m_new.GetData()[address]
341 << ' ';
343 else if( address < m_old.GetSize() ) {
344 // new is out of data and old still has some
345 os << "XX ";
347 else {
348 // no more data, just print spaces
349 os << " ";
354 // printable data, just dump new
355 if( Data::PrintAscii() ) {
356 os << ' ';
357 for( size_t i = 0; i < size && (index+i) < m_new.GetSize(); i++ ) {
358 int c = m_new.GetData()[index + i];
359 os << setbase(10) << (char) (isprint(c) ? c : '.');
363 os << "\n";
366 void Diff::Dump(std::ostream &os) const
368 if( m_old.GetSize() != m_new.GetSize() )
369 os << "sizes differ: "
370 << m_old.GetSize() << " != " << m_new.GetSize() << endl;
372 size_t max = std::max(m_old.GetSize(), m_new.GetSize());
373 for( size_t i = 0; i < max; i += 16 ) {
374 m_old.DumpHexLine(os, i, 16);
375 Compare(os, i, 16);
379 ostream& operator<< (ostream &os, const Diff &diff)
381 diff.Dump(os);
382 return os;
386 ///////////////////////////////////////////////////////////////////////////////
387 // Utility functions
389 static bool IsEndpointStart(const std::string &line, int &endpoint)
391 if( strncmp(line.c_str(), "sep: ", 5) == 0 ||
392 strncmp(line.c_str(), "rep: ", 5) == 0 )
394 endpoint = atoi(line.c_str() + 5);
395 return true;
397 return false;
400 bool LoadDataArray(const string &filename, std::vector<Data> &array)
402 ifstream in(filename.c_str());
403 return ReadDataArray(in, array);
406 bool ReadDataArray(std::istream &is, std::vector<Data> &array)
408 if( !is )
409 return false;
411 bool bInEndpoint = false;
412 unsigned int nCurrent = 0;
413 size_t nLargestSize = 0x100;
414 while( is ) {
415 string line;
416 getline(is, line);
417 int endpoint;
418 if( bInEndpoint ) {
419 if( IsHexData(line) ) {
420 istringstream sline(line);
421 sline >> array[nCurrent];
422 continue;
424 else {
425 nLargestSize = std::max(nLargestSize,
426 array[nCurrent].GetBufSize());
427 bInEndpoint = false;
431 // check if this line starts a new endpoint
432 if( IsEndpointStart(line, endpoint) ) {
433 bInEndpoint = true;
434 Data chunk(endpoint, nLargestSize);
435 array.push_back(chunk);
436 nCurrent = array.size() - 1;
439 return true;
442 } // namespace Barry
445 #ifdef __TEST_MODE__
447 #include <iostream>
448 #include <iomanip>
449 #include "data.h"
451 using namespace std;
453 int main()
455 typedef std::vector<Data> DataVec;
456 DataVec array;
457 if( !LoadDataArray("data/parsed.log", array) ) {
458 cout << "Can't load file" << endl;
459 return 1;
462 DataVec::iterator i = array.begin();
463 Data::PrintAscii(false);
464 for( ; i != array.end(); i++ ) {
465 cout << "Endpoint: " << i->GetEndpoint() << endl;
466 cout << *i;
467 cout << "\n\n";
471 Data one, two;
472 one.GetBuffer()[0] = 0x01;
473 one.ReleaseBuffer(1);
474 two.GetBuffer()[0] = 0x02;
475 two.ReleaseBuffer(2);
477 cout << Diff(one, two) << endl;
478 cout << Diff(two, one) << endl;
480 two.GetBuffer();
481 two.ReleaseBuffer(32);
482 cout << Diff(one, two) << endl;
485 #endif