- fixed locale issues in src/data.cc
[barry.git] / src / data.cc
blob4fe2bc122766cccd577c9538f52ee2c1ed9a6230
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 const char *hexchars = "0123456789abcdef";
47 if( strchr(hexchars, *str) == NULL )
48 return false;
51 if( *str != ':' )
52 return false;
54 return true;
59 ///////////////////////////////////////////////////////////////////////////////
60 // Data class
62 bool Data::bPrintAscii = true;
64 Data::Data()
65 : m_data(new unsigned char[0x4000]),
66 m_bufsize(0x4000),
67 m_datasize(0),
68 m_endpoint(-1),
69 m_externalData(0),
70 m_external(false)
72 memset(m_data, 0, m_bufsize);
75 Data::Data(int endpoint, size_t startsize)
76 : m_data(new unsigned char[startsize]),
77 m_bufsize(startsize),
78 m_datasize(0),
79 m_endpoint(endpoint),
80 m_externalData(0),
81 m_external(false)
83 memset(m_data, 0, m_bufsize);
86 Data::Data(const void *ValidData, size_t size)
87 : m_data(0),
88 m_bufsize(0),
89 m_datasize(size),
90 m_endpoint(-1),
91 m_externalData((const unsigned char*)ValidData),
92 m_external(true)
96 Data::Data(const Data &other)
97 : m_data(other.m_bufsize ? new unsigned char[other.m_bufsize] : 0),
98 m_bufsize(other.m_bufsize),
99 m_datasize(other.m_datasize),
100 m_endpoint(other.m_endpoint),
101 m_externalData(other.m_externalData),
102 m_external(other.m_external)
104 // copy over the raw data
105 if( !m_external )
106 memcpy(m_data, other.m_data, other.m_bufsize);
109 Data::~Data()
111 delete [] m_data;
114 void Data::MakeSpace(size_t desiredsize)
116 if( m_bufsize < desiredsize ) {
117 desiredsize += 1024; // get a proper chunk
118 unsigned char *newbuf = new unsigned char[desiredsize];
119 memcpy(newbuf, m_data, m_bufsize);
120 memset(newbuf + m_bufsize, 0, desiredsize - m_bufsize);
121 delete [] m_data;
122 m_data = newbuf;
123 m_bufsize = desiredsize;
127 // perform the copy on write operation if needed
128 void Data::CopyOnWrite(size_t desiredsize)
130 if( m_external ) {
131 // make room
132 MakeSpace(std::max(desiredsize, m_datasize));
134 // copy it over
135 memcpy(m_data, m_externalData, m_datasize);
137 // not external anymore
138 m_external = false;
142 void Data::InputHexLine(istream &is)
144 unsigned int values[16];
145 size_t index = 0;
147 size_t address;
148 is >> setbase(16) >> address;
149 if( !is )
150 return; // nothing to do
152 is.ignore(); // eat the ':'
154 while( is && index < 16 ) {
155 is >> setbase(16) >> values[index];
156 if( is )
157 index++;
160 dout("InputHexLine: read " << index << " bytes");
162 CopyOnWrite(address + index);
163 MakeSpace(address + index); // make space for the new
164 m_datasize = std::max(address + index, m_datasize);
165 while( index-- )
166 m_data[address + index] = (unsigned char) values[index];
167 return;
170 void Data::DumpHexLine(ostream &os, size_t index, size_t size) const
172 ios::fmtflags oldflags = os.setf(ios::right);
174 // index
175 os << " ";
176 os << setbase(16) << setfill('0') << setw(8)
177 << index << ": ";
179 // hex byte data
180 for( size_t i = 0; i < size; i++ ) {
181 if( (index+i) < GetSize() ) {
182 os << setbase(16) << setfill('0')
183 << setw(2) << setprecision(2)
184 << (unsigned int) GetData()[index + i] << ' ';
186 else {
187 os << " ";
191 // printable data
192 if( bPrintAscii ) {
193 locale loc = os.getloc();
194 os << ' ';
195 for( size_t i = 0; i < size && (index+i) < GetSize(); i++ ) {
196 ostream::traits_type::char_type c = GetData()[index + i];
197 os << setbase(10) << (char) (isprint(c, loc) ? c : '.');
201 os << "\n";
202 os.flags(oldflags);
205 void Data::DumpHex(ostream &os) const
207 for( size_t address = 0; address < GetSize(); address += 16 ) {
208 DumpHexLine(os, address, 16);
212 unsigned char * Data::GetBuffer(size_t requiredsize)
214 CopyOnWrite(requiredsize);
215 if( requiredsize > 0 )
216 MakeSpace(requiredsize);
217 return m_data;
220 void Data::ReleaseBuffer(int datasize)
222 assert( datasize >= 0 || datasize == -1 );
223 assert( datasize == -1 || (unsigned int)datasize <= m_bufsize );
224 assert( !m_external );
226 if( m_external )
227 return;
228 if( datasize >= 0 && (unsigned int)datasize > m_bufsize ) {
229 dout("ReleaseBuffer called with datasize("
230 << std::dec << datasize << ") > m_bufsize("
231 << m_bufsize << ")");
232 return;
235 if( datasize >= 0 ) {
236 m_datasize = datasize;
238 else {
239 // search for last non-zero value in buffer
240 m_datasize = m_bufsize - 1;
241 while( m_datasize && m_data[m_datasize] == 0 )
242 --m_datasize;
246 /// Append bytes of data based on str
247 void Data::AppendHexString(const char *str)
249 CopyOnWrite(m_datasize + 512);
251 std::istringstream iss(str);
252 unsigned int byte;
253 while( iss >> hex >> byte ) {
254 MakeSpace(m_datasize + 1);
255 m_data[m_datasize] = (unsigned char) byte;
256 m_datasize++;
260 /// set buffer to 0 and remove all data
261 void Data::Zap()
263 if( !m_external )
264 memset(m_data, 0, m_bufsize);
265 m_datasize = 0;
268 Data & Data::operator=(const Data &other)
270 if( this == &other )
271 return *this;
273 // don't remove our current buffer, only grow it if needed
274 MakeSpace(other.m_bufsize);
275 memcpy(m_data, other.m_data, other.m_bufsize);
277 // then copy over the data state
278 m_datasize = other.m_datasize;
279 m_endpoint = other.m_endpoint;
280 m_externalData = other.m_externalData;
281 m_external = other.m_external;
282 return *this;
285 istream& operator>> (istream &is, Data &data)
287 data.InputHexLine(is);
288 return is;
291 ostream& operator<< (ostream &os, const Data &data)
293 data.DumpHex(os);
294 return os;
298 ///////////////////////////////////////////////////////////////////////////////
299 // Diff class
301 Diff::Diff(const Data &old, const Data &new_)
302 : m_old(old), m_new(new_)
306 void Diff::Compare(ostream &os, size_t index, size_t size) const
308 size_t min = std::min(m_old.GetSize(), m_new.GetSize());
310 // index
311 os << "> ";
312 os << setbase(16) << setfill('0') << setw(8)
313 << index << ": ";
315 // diff data
316 for( size_t i = 0; i < size; i++ ) {
317 size_t address = index + i;
319 // if data is available, print the diff
320 if( address < min ) {
321 if( m_old.GetData()[address] != m_new.GetData()[address] ) {
322 // differ, print hex
323 os << setbase(16) << setfill('0')
324 << setw(2) << setprecision(2)
325 << (unsigned int) m_new.GetData()[address] << ' ';
327 else {
328 // same, just print spaces
329 os << " ";
332 else {
333 // one of the buffers is shorter...
334 if( address < m_new.GetSize() ) {
335 // new still has data, print it
336 os << setbase(16) << setfill('0')
337 << setw(2) << setprecision(2)
338 << (unsigned int) m_new.GetData()[address]
339 << ' ';
341 else if( address < m_old.GetSize() ) {
342 // new is out of data and old still has some
343 os << "XX ";
345 else {
346 // no more data, just print spaces
347 os << " ";
352 // printable data, just dump new
353 if( Data::PrintAscii() ) {
354 os << ' ';
355 for( size_t i = 0; i < size && (index+i) < m_new.GetSize(); i++ ) {
356 int c = m_new.GetData()[index + i];
357 os << setbase(10) << (char) (isprint(c) ? c : '.');
361 os << "\n";
364 void Diff::Dump(std::ostream &os) const
366 if( m_old.GetSize() != m_new.GetSize() )
367 os << "sizes differ: "
368 << m_old.GetSize() << " != " << m_new.GetSize() << endl;
370 size_t max = std::max(m_old.GetSize(), m_new.GetSize());
371 for( size_t i = 0; i < max; i += 16 ) {
372 m_old.DumpHexLine(os, i, 16);
373 Compare(os, i, 16);
377 ostream& operator<< (ostream &os, const Diff &diff)
379 diff.Dump(os);
380 return os;
384 ///////////////////////////////////////////////////////////////////////////////
385 // Utility functions
387 static bool IsEndpointStart(const std::string &line, int &endpoint)
389 if( strncmp(line.c_str(), "sep: ", 5) == 0 ||
390 strncmp(line.c_str(), "rep: ", 5) == 0 )
392 endpoint = atoi(line.c_str() + 5);
393 return true;
395 return false;
398 bool LoadDataArray(const string &filename, std::vector<Data> &array)
400 ifstream in(filename.c_str());
401 return ReadDataArray(in, array);
404 bool ReadDataArray(std::istream &is, std::vector<Data> &array)
406 if( !is )
407 return false;
409 bool bInEndpoint = false;
410 unsigned int nCurrent = 0;
411 size_t nLargestSize = 0x100;
412 while( is ) {
413 string line;
414 getline(is, line);
415 int endpoint;
416 if( bInEndpoint ) {
417 if( IsHexData(line) ) {
418 istringstream sline(line);
419 sline >> array[nCurrent];
420 continue;
422 else {
423 nLargestSize = std::max(nLargestSize,
424 array[nCurrent].GetBufSize());
425 bInEndpoint = false;
429 // check if this line starts a new endpoint
430 if( IsEndpointStart(line, endpoint) ) {
431 bInEndpoint = true;
432 Data chunk(endpoint, nLargestSize);
433 array.push_back(chunk);
434 nCurrent = array.size() - 1;
437 return true;
440 } // namespace Barry
443 #ifdef __TEST_MODE__
445 #include <iostream>
446 #include <iomanip>
447 #include "data.h"
449 using namespace std;
451 int main()
453 typedef std::vector<Data> DataVec;
454 DataVec array;
455 if( !LoadDataArray("data/parsed.log", array) ) {
456 cout << "Can't load file" << endl;
457 return 1;
460 DataVec::iterator i = array.begin();
461 Data::PrintAscii(false);
462 for( ; i != array.end(); i++ ) {
463 cout << "Endpoint: " << i->GetEndpoint() << endl;
464 cout << *i;
465 cout << "\n\n";
469 Data one, two;
470 one.GetBuffer()[0] = 0x01;
471 one.ReleaseBuffer(1);
472 two.GetBuffer()[0] = 0x02;
473 two.ReleaseBuffer(2);
475 cout << Diff(one, two) << endl;
476 cout << Diff(two, one) << endl;
478 two.GetBuffer();
479 two.ReleaseBuffer(32);
480 cout << Diff(one, two) << endl;
483 #endif