3 /// Classes to help manage pre-determined data files.
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.
29 //#define __DEBUG_MODE__
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
++ )
43 for( int i
= 0; i
< 8 && *str
; str
++, i
++ )
44 if( !isdigit(*str
) && !(*str
>= 'a' && *str
<= 'f') )
55 ///////////////////////////////////////////////////////////////////////////////
58 bool Data::bPrintAscii
= true;
61 : m_data(new unsigned char[0x4000]),
68 memset(m_data
, 0, m_bufsize
);
71 Data::Data(int endpoint
, size_t startsize
)
72 : m_data(new unsigned char[startsize
]),
79 memset(m_data
, 0, m_bufsize
);
82 Data::Data(const void *ValidData
, size_t size
)
87 m_externalData((const unsigned char*)ValidData
),
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
102 memcpy(m_data
, other
.m_data
, other
.m_bufsize
);
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
);
119 m_bufsize
= desiredsize
;
123 // perform the copy on write operation if needed
124 void Data::CopyOnWrite(size_t desiredsize
)
128 MakeSpace(std::max(desiredsize
, m_datasize
));
131 memcpy(m_data
, m_externalData
, m_datasize
);
133 // not external anymore
138 void Data::InputHexLine(istream
&is
)
140 unsigned int values
[16];
144 is
>> setbase(16) >> address
;
146 return; // nothing to do
148 is
.ignore(); // eat the ':'
150 while( is
&& index
< 16 ) {
151 is
>> setbase(16) >> values
[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
);
162 m_data
[address
+ index
] = (unsigned char) values
[index
];
166 void Data::DumpHexLine(ostream
&os
, size_t index
, size_t size
) const
168 ios::fmtflags oldflags
= os
.setf(ios::right
);
172 os
<< setbase(16) << setfill('0') << setw(8)
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
] << ' ';
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
: '.');
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
);
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
;
225 // search for last non-zero value in buffer
226 m_datasize
= m_bufsize
- 1;
227 while( m_datasize
&& m_data
[m_datasize
] == 0 )
232 /// set buffer to 0 and remove all data
236 memset(m_data
, 0, m_bufsize
);
240 Data
& Data::operator=(const Data
&other
)
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
;
257 istream
& operator>> (istream
&is
, Data
&data
)
259 data
.InputHexLine(is
);
263 ostream
& operator<< (ostream
&os
, const Data
&data
)
270 ///////////////////////////////////////////////////////////////////////////////
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());
284 os
<< setbase(16) << setfill('0') << setw(8)
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
] ) {
295 os
<< setbase(16) << setfill('0')
296 << setw(2) << setprecision(2)
297 << (unsigned int) m_new
.GetData()[address
] << ' ';
300 // same, just print spaces
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
]
313 else if( address
< m_old
.GetSize() ) {
314 // new is out of data and old still has some
318 // no more data, just print spaces
324 // printable data, just dump new
325 if( Data::PrintAscii() ) {
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
: '.');
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);
349 ostream
& operator<< (ostream
&os
, const Diff
&diff
)
356 ///////////////////////////////////////////////////////////////////////////////
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);
370 bool LoadDataArray(const string
&filename
, std::vector
<Data
> &array
)
372 ifstream
in(filename
.c_str());
376 bool bInEndpoint
= false;
377 unsigned int nCurrent
= 0;
378 size_t nLargestSize
= 0x100;
384 if( IsHexData(line
) ) {
385 istringstream
sline(line
);
386 sline
>> array
[nCurrent
];
390 nLargestSize
= std::max(nLargestSize
,
391 array
[nCurrent
].GetBufSize());
396 // check if this line starts a new endpoint
397 if( IsEndpointStart(line
, endpoint
) ) {
399 Data
chunk(endpoint
, nLargestSize
);
400 array
.push_back(chunk
);
401 nCurrent
= array
.size() - 1;
418 typedef std::vector
<Data
> DataVec
;
420 if( !LoadDataArray("data/parsed.log", array
) ) {
421 cout
<< "Can't load file" << endl
;
425 DataVec::iterator i
= array
.begin();
426 Data::PrintAscii(false);
427 for( ; i
!= array
.end(); i
++ ) {
428 cout
<< "Endpoint: " << i
->GetEndpoint() << endl
;
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
;
444 two
.ReleaseBuffer(32);
445 cout
<< Diff(one
, two
) << endl
;