3 /// Classes to help manage pre-determined data files.
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.
31 //#define __DEBUG_MODE__
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
++ )
47 for( int i
= 0; i
< 8 && *str
; str
++, i
++ ) {
48 const char *hexchars
= "0123456789abcdef";
49 if( strchr(hexchars
, *str
) == NULL
)
61 ///////////////////////////////////////////////////////////////////////////////
64 bool Data::bPrintAscii
= true;
67 : m_data(new unsigned char[0x4000]),
74 memset(m_data
, 0, m_bufsize
);
77 Data::Data(int endpoint
, size_t startsize
)
78 : m_data(new unsigned char[startsize
]),
85 memset(m_data
, 0, m_bufsize
);
88 Data::Data(const void *ValidData
, size_t size
)
93 m_externalData((const unsigned char*)ValidData
),
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
108 memcpy(m_data
, other
.m_data
, other
.m_bufsize
);
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
);
125 m_bufsize
= desiredsize
;
129 // perform the copy on write operation if needed
130 void Data::CopyOnWrite(size_t desiredsize
)
134 MakeSpace(std::max(desiredsize
, m_datasize
));
137 memcpy(m_data
, m_externalData
, m_datasize
);
139 // not external anymore
144 void Data::InputHexLine(istream
&is
)
146 unsigned int values
[16];
150 is
>> setbase(16) >> address
;
152 return; // nothing to do
154 is
.ignore(); // eat the ':'
156 while( is
&& index
< 16 ) {
157 is
>> setbase(16) >> values
[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
);
168 m_data
[address
+ index
] = (unsigned char) values
[index
];
172 void Data::DumpHexLine(ostream
&os
, size_t index
, size_t size
) const
174 ios::fmtflags oldflags
= os
.setf(ios::right
);
178 os
<< setbase(16) << setfill('0') << setw(8)
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
] << ' ';
195 locale loc
= os
.getloc();
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
: '.');
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
);
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
);
230 if( datasize
>= 0 && (unsigned int)datasize
> m_bufsize
) {
231 dout("ReleaseBuffer called with datasize("
232 << std::dec
<< datasize
<< ") > m_bufsize("
233 << m_bufsize
<< ")");
237 if( datasize
>= 0 ) {
238 m_datasize
= datasize
;
241 // search for last non-zero value in buffer
242 m_datasize
= m_bufsize
- 1;
243 while( m_datasize
&& m_data
[m_datasize
] == 0 )
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
);
255 while( iss
>> hex
>> byte
) {
256 MakeSpace(m_datasize
+ 1);
257 m_data
[m_datasize
] = (unsigned char) byte
;
262 /// set buffer to 0 and remove all data
266 memset(m_data
, 0, m_bufsize
);
270 Data
& Data::operator=(const Data
&other
)
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
;
287 istream
& operator>> (istream
&is
, Data
&data
)
289 data
.InputHexLine(is
);
293 ostream
& operator<< (ostream
&os
, const Data
&data
)
300 ///////////////////////////////////////////////////////////////////////////////
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());
314 os
<< setbase(16) << setfill('0') << setw(8)
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
] ) {
325 os
<< setbase(16) << setfill('0')
326 << setw(2) << setprecision(2)
327 << (unsigned int) m_new
.GetData()[address
] << ' ';
330 // same, just print spaces
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
]
343 else if( address
< m_old
.GetSize() ) {
344 // new is out of data and old still has some
348 // no more data, just print spaces
354 // printable data, just dump new
355 if( Data::PrintAscii() ) {
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
: '.');
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);
379 ostream
& operator<< (ostream
&os
, const Diff
&diff
)
386 ///////////////////////////////////////////////////////////////////////////////
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);
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
)
411 bool bInEndpoint
= false;
412 unsigned int nCurrent
= 0;
413 size_t nLargestSize
= 0x100;
419 if( IsHexData(line
) ) {
420 istringstream
sline(line
);
421 sline
>> array
[nCurrent
];
425 nLargestSize
= std::max(nLargestSize
,
426 array
[nCurrent
].GetBufSize());
431 // check if this line starts a new endpoint
432 if( IsEndpointStart(line
, endpoint
) ) {
434 Data
chunk(endpoint
, nLargestSize
);
435 array
.push_back(chunk
);
436 nCurrent
= array
.size() - 1;
455 typedef std::vector
<Data
> DataVec
;
457 if( !LoadDataArray("data/parsed.log", array
) ) {
458 cout
<< "Can't load file" << endl
;
462 DataVec::iterator i
= array
.begin();
463 Data::PrintAscii(false);
464 for( ; i
!= array
.end(); i
++ ) {
465 cout
<< "Endpoint: " << i
->GetEndpoint() << endl
;
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
;
481 two
.ReleaseBuffer(32);
482 cout
<< Diff(one
, two
) << endl
;