3 /// Classes to help manage pre-determined data files.
7 Copyright (C) 2005-2008, 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__
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
++ )
45 for( int i
= 0; i
< 8 && *str
; str
++, i
++ ) {
46 const char *hexchars
= "0123456789abcdef";
47 if( strchr(hexchars
, *str
) == NULL
)
59 ///////////////////////////////////////////////////////////////////////////////
62 bool Data::bPrintAscii
= true;
65 : m_data(new unsigned char[0x4000]),
72 memset(m_data
, 0, m_bufsize
);
75 Data::Data(int endpoint
, size_t startsize
)
76 : m_data(new unsigned char[startsize
]),
83 memset(m_data
, 0, m_bufsize
);
86 Data::Data(const void *ValidData
, size_t size
)
91 m_externalData((const unsigned char*)ValidData
),
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
106 memcpy(m_data
, other
.m_data
, other
.m_bufsize
);
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
);
123 m_bufsize
= desiredsize
;
127 // perform the copy on write operation if needed
128 void Data::CopyOnWrite(size_t desiredsize
)
132 MakeSpace(std::max(desiredsize
, m_datasize
));
135 memcpy(m_data
, m_externalData
, m_datasize
);
137 // not external anymore
142 void Data::InputHexLine(istream
&is
)
144 unsigned int values
[16];
148 is
>> setbase(16) >> address
;
150 return; // nothing to do
152 is
.ignore(); // eat the ':'
154 while( is
&& index
< 16 ) {
155 is
>> setbase(16) >> values
[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
);
166 m_data
[address
+ index
] = (unsigned char) values
[index
];
170 void Data::DumpHexLine(ostream
&os
, size_t index
, size_t size
) const
172 ios::fmtflags oldflags
= os
.setf(ios::right
);
176 os
<< setbase(16) << setfill('0') << setw(8)
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
] << ' ';
193 locale loc
= os
.getloc();
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
: '.');
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
);
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
);
228 if( datasize
>= 0 && (unsigned int)datasize
> m_bufsize
) {
229 dout("ReleaseBuffer called with datasize("
230 << std::dec
<< datasize
<< ") > m_bufsize("
231 << m_bufsize
<< ")");
235 if( datasize
>= 0 ) {
236 m_datasize
= datasize
;
239 // search for last non-zero value in buffer
240 m_datasize
= m_bufsize
- 1;
241 while( m_datasize
&& m_data
[m_datasize
] == 0 )
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
);
253 while( iss
>> hex
>> byte
) {
254 MakeSpace(m_datasize
+ 1);
255 m_data
[m_datasize
] = (unsigned char) byte
;
260 /// set buffer to 0 and remove all data
264 memset(m_data
, 0, m_bufsize
);
268 Data
& Data::operator=(const Data
&other
)
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
;
285 istream
& operator>> (istream
&is
, Data
&data
)
287 data
.InputHexLine(is
);
291 ostream
& operator<< (ostream
&os
, const Data
&data
)
298 ///////////////////////////////////////////////////////////////////////////////
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());
312 os
<< setbase(16) << setfill('0') << setw(8)
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
] ) {
323 os
<< setbase(16) << setfill('0')
324 << setw(2) << setprecision(2)
325 << (unsigned int) m_new
.GetData()[address
] << ' ';
328 // same, just print spaces
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
]
341 else if( address
< m_old
.GetSize() ) {
342 // new is out of data and old still has some
346 // no more data, just print spaces
352 // printable data, just dump new
353 if( Data::PrintAscii() ) {
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
: '.');
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);
377 ostream
& operator<< (ostream
&os
, const Diff
&diff
)
384 ///////////////////////////////////////////////////////////////////////////////
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);
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
)
409 bool bInEndpoint
= false;
410 unsigned int nCurrent
= 0;
411 size_t nLargestSize
= 0x100;
417 if( IsHexData(line
) ) {
418 istringstream
sline(line
);
419 sline
>> array
[nCurrent
];
423 nLargestSize
= std::max(nLargestSize
,
424 array
[nCurrent
].GetBufSize());
429 // check if this line starts a new endpoint
430 if( IsEndpointStart(line
, endpoint
) ) {
432 Data
chunk(endpoint
, nLargestSize
);
433 array
.push_back(chunk
);
434 nCurrent
= array
.size() - 1;
453 typedef std::vector
<Data
> DataVec
;
455 if( !LoadDataArray("data/parsed.log", array
) ) {
456 cout
<< "Can't load file" << endl
;
460 DataVec::iterator i
= array
.begin();
461 Data::PrintAscii(false);
462 for( ; i
!= array
.end(); i
++ ) {
463 cout
<< "Endpoint: " << i
->GetEndpoint() << endl
;
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
;
479 two
.ReleaseBuffer(32);
480 cout
<< Diff(one
, two
) << endl
;