Re: find a pattern in binary file
On Jun 21, 2:13 am, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
Ivan wrote:
On Jun 20, 1:11 pm, vizzz <andrea.visin...@gmail.com> wrote:
Hmmm... I had a look at this and ran accross a simple
problem. How do you read a binary file and just echo the
HEX for byte to the screen.
#include <iostream>
#include <ostream>
#include <fstream>
#include <iterator>
#include <iomanip>
#include <algorithm>
#include <cassert>
class print_hex {
std::ostream * ostr_ptr;
unsigned int line_length;
unsigned int index;
public:
print_hex ( std::ostream & str_ref, unsigned int length )
: ostr_ptr( &str_ref )
, line_length ( length )
, index ( 0 )
{}
void operator() ( unsigned char ch ) {
++index;
if ( index >= line_length ) {
(*ostr_ptr) << std::hex << std::setw(2) << std::setfill( '0' )
<< (unsigned int)(ch) << '\n';
index = 0;
} else {
(*ostr_ptr) << std::hex << std::setw(2) << std::setfill( '0' )
<< (unsigned int)(ch) << ' ';
Wouldn't it be preferable to set the formatting flags in the
constructor? I'd also provide an "indent" argument; if index
were 0, I'd output indent spaces, otherwise a single space---or
perhaps the best solution would be to provide a start of line
and a separator string to the constructor, then:
(*ostr_ptr)
<< (inLineCount == 0 ? startString : separString)
<< std::setw( 2 ) << (unsigned int)( ch ) ;
++ inLineCount ;
if ( inLineCount == lineLength ) {
(*ostr_ptr) << endString ;
inLineCount = 0 ;
}
(This supposes that hex and fill were set in the constructor.)
Given the copying that's going on, I'd also simulate move
semantics, so that the final destructor could do something like:
if ( inLineCount != 0 ) {
(*ostr_ptr) << endString ;
}
}
}
};
int main ( int argn, char ** args ) {
assert( argn == 2 );
std::ifstream in ( args[1] );
std::for_each( std::istreambuf_iterator< char >( in ),
std::istreambuf_iterator< char >(),
print_hex( std::cout, 25 ) );
Unless you're doing something relatively generic, with support
for different separators, etc., this really looks like a case of
for_each abuse.
std::cout << '\n';
Which results in one new line too many if the number of elements
just happened to be an exact multiple of the line length.
About the only real use for this sort of output I've found is
debugging or experimenting, but there, I use it often enough
that I've a generic Dump<T> class (and a generic function which
returns it, for automatic type deduction), so that I can write
things like:
std::cout << dump( someObject ) << std::endl ;
The code that ends up getting called in the << operator is:
IOSave saver( dest ) ;
dest.fill( '0' ) ;
dest.setf( std::ios::hex, std::ios::basefield ) ;
char const* baseStr = "" ;
if ( (dest.flags() & std::ios::showbase) != 0 ) {
baseStr = "0x" ;
dest.unsetf( std::ios::showbase ) ;
}
unsigned char const* const
end = myObj + sizeof( T ) ;
for ( unsigned char const* p = myObj ; p != end ; ++ p ) {
if ( p != myObj ) {
dest << ' ' ;
}
dest << baseStr << std::setw( 2 ) << (unsigned int)( *p ) ;
}
(Note that there's extra code there to support my personal
preference: a "0x" with a small x, even if std::ios::uppercase
is specified.)
}
The issue is the c++ read function doesn't return number of
bytes read... so on the last read into a buffer how do you
know how many characters to print?
Have a look at readsome().
Yes, have a look at it. Read it's specification very carefully.
Because if you do, you're realize that it is absolutely
worthless here.
The function he's looking for is istream::gcount(), which
returns the number of bytes read by the last unformatted read.
His basic loop would be:
while ( input.read( &buffer[ 0 ], buffer.size() ) ) {
process( buffer.begin(), buffer.end() ) ;
}
process( buffer.begin(), buffer.begin() + input.gcount() ) ;
(But IMHO, istream really isn't appropriate for binary; if I'm
really working with a binary file, I'll drop down to the system
API.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34