How to read/write continuous hex dump using STL

C

capnwhit

Hello all,

The program below has a bug... The program is supposed to convert a
string to a continuous hex dump and back to a string. The output
should be as follows:

abcd
61626364
abcd

But the output I see is as follows:

abcd
61626364
dddd

Can someone please show me what I'm doing wrong and what is the proper
way of reading a continuous hex dump using the STL?

// BEGIN SAMPLE PROGRAM
#include <iostream> // For std::cout
#include <string> // For std::string
#include <sstream> // For std::eek:stringstream
#include <iomanip> // For std::setfill

int
main()
{
// Set "input"
//
std::string input = "abcd";
std::cout << input << std::endl;

// Set "hexDump"
//
std::eek:stringstream oss;
oss << std::hex << std::setfill('0');
for(int i = 0; i < input.length(); i++)
{
int temp = input;
oss << std::setw(2) << temp;
}
std::string hexDump = oss.str();
assert(hexDump.length() == 2 * input.length());
std::cout << hexDump << std::endl;

// Set "output"
//
std::string output;
int numChars = hexDump.length() / 2;
output.resize(numChars);
std::istringstream iss(hexDump);
iss >> std::hex;
for(int i = 0; i < numChars; i++)
{
int temp;
iss >> std::setw(2) >> temp; // BUG: Using setw DOES NOT WORK!!!
output = temp;
}
std::cout << output << std::endl;
}
// END SAMPLE PROGRAM
 
M

Mike Wahler

Hello all,

The program below has a bug... The program is supposed to convert a
string to a continuous hex dump and back to a string. The output
should be as follows:

abcd
61626364
abcd

But the output I see is as follows:

abcd
61626364
dddd

Can someone please show me what I'm doing wrong and what is the proper
way of reading a continuous hex dump using the STL?

// BEGIN SAMPLE PROGRAM
#include <iostream> // For std::cout
#include <string> // For std::string
#include <sstream> // For std::eek:stringstream
#include <iomanip> // For std::setfill

#include said:
int
main()
{
// Set "input"
//
std::string input = "abcd";
std::cout << input << std::endl;

// Set "hexDump"
//
std::eek:stringstream oss;
oss << std::hex << std::setfill('0');
for(int i = 0; i < input.length(); i++)
{
int temp = input;
oss << std::setw(2) << temp;
}
std::string hexDump = oss.str();
assert(hexDump.length() == 2 * input.length());
std::cout << hexDump << std::endl;

// Set "output"
//
std::string output;
int numChars = hexDump.length() / 2;
output.resize(numChars);
std::istringstream iss(hexDump);
iss >> std::hex;
for(int i = 0; i < numChars; i++)
{
int temp;
iss >> std::setw(2) >> temp; // BUG: Using setw DOES NOT WORK!!!


// Not true. 'setw' sets *output* width
*/

Had you checked the stream state of 'iss' (which should always be
done with any stream), you'd have seen the conversion failed.
The '>>' operator stops reading upon encountering whitespace.
So it tried to read hex value '6162636465', which is
418262508645 in decimal, most likely outside the guaranteed range
of type 'int' for your platform (32 bits?).

You'll need to either insert whitespace between your hex values,
or only read two characters at a time (you could use 'iss.get()'
or 'iss.read()'.
output = temp;
}
std::cout << output << std::endl;
}
// END SAMPLE PROGRAM
-Mike
 
C

capnwhit

Hello Mike,

Thanks for the quick reply!
You'll need to either insert whitespace between your hex values,
Yes, I have a version working which inserts whitespace, but I need
a continuous hex dump.
// Not true. 'setw' sets *output* width
Yes, apparently so... but my reference book on STL says it sets
the *input* width as well. I am using "The C++ Standard Library:
A Tutorial and Reference" by Nicolai M. Josuttis, August 2002,
and on page 619, Table 13.16 he says: "setw(val) Sets the field
width for input and output to val" Can people confirm whether this
is a typo on the Josuttis book? (I've noticed several others).

Thanks!
 
C

capnwhit

The '>>' operator stops reading upon encountering whitespace.
So it tried to read hex value '6162636465', which is
418262508645 in decimal, most likely outside the guaranteed range
of type 'int' for your platform (32 bits?).
This post is for the benefit of the archive and anybody who reads
this thread in the future. I believe Mike recompiled the program
and used "abcde" as input, instead of "abcd". That is the reason
why he says that the program tried to read hex value '6162636465'.
The original program tries to read hex value '61626364' which is
32 bits. Thanks for actually compiling the program Mike!
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

Hello Mike,

Thanks for the quick reply!

Yes, I have a version working which inserts whitespace, but I need
a continuous hex dump.

Yes, apparently so... but my reference book on STL says it sets
the *input* width as well. I am using "The C++ Standard Library:
A Tutorial and Reference" by Nicolai M. Josuttis, August 2002,
and on page 619, Table 13.16 he says: "setw(val) Sets the field
width for input and output to val" Can people confirm whether this
is a typo on the Josuttis book? (I've noticed several others).

setw() will call width() on the istream, and width() only controls the
width of output, the reason istream has it is because it's inherited
from ios_base.
 
B

BobR

Hello Mike,
Yes, I have a version working which inserts whitespace, but I need
a continuous hex dump.

Well, whitespace makes it easier. <G>
Just in case, this works with your original set-up:

{ // ....... your main, up to here.
// - Set "output" -
std::string output;
std::istringstream iss( hexDump ); // "61626364"
// std::istringstream Tiss( oss.str() ); // alt. way
// std::cout<< Tiss.str() <<std::endl; // out: 61626364

std::stringstream iss2;
for( std::string temp( 4, ' ' ); // or: 2
iss.read( &temp.at(0), 2 ); /*m t*/){
iss2.str( temp );
int tmp(0);
iss2 >> std::hex >> tmp; // if( not tmp ){ break;}
output += char( tmp & 0xFF ); // or: '& 0x7F'
} // for(iss.read)
std::cout << output << std::endl;
}
// out:abcd
This loop just reads two chars at a time, then (re-)converts them.
Hope it helps you in some way.

BTW, your original post == very good posting. Makes it easy to help you when
good information is provided, and code style is easy to read and complete.
You get an "atta boy(or girl)!".
 
M

Mike Wahler

This post is for the benefit of the archive and anybody who reads
this thread in the future. I believe Mike recompiled the program
and used "abcde" as input, instead of "abcd". That is the reason
why he says that the program tried to read hex value '6162636465'.

Actually, I compiled if almost it as you posted it, but with the addition
The original program tries to read hex value '61626364' which is
32 bits.

Actually, my error was that I simply typed the
(wrong) hex value into a calculator and converted to decimal.

I just now made a few more modifications to the code to 'watch' it and
realized:
The real reason for the fail state of 'iss' was that the entire
hex value (0x61626364) was read into 'temp' on the first loop
iteration, and all other reads cause an end of stream condition
(which also sets 'failbit'). That's why every character of the
string 'output' had this same value. (Casting this value to char
(Win XP, Pentium, gives character 'd').

Modified code: (my changes marked /* MKW */)

#include <iostream> // For std::cout
#include <string> // For std::string
#include <sstream> // For std::eek:stringstream
#include <iomanip> // For std::setfill
#include <cassert> /* MKW */
int
main()
{
// Set "input"
//
std::string input = "abcd";
std::cout << input << std::endl;

// Set "hexDump"
//
std::eek:stringstream oss;
oss << std::hex << std::setfill('0');
for(int i = 0; i < input.length(); i++)
{
int temp = input;
oss << std::setw(2) << temp;
}
std::string hexDump = oss.str();
assert(hexDump.length() == 2 * input.length());
std::cout << hexDump << std::endl;

// Set "output"
//
std::string output;
int numChars = hexDump.length() / 2;
output.resize(numChars);
std::istringstream iss(hexDump);
iss >> std::hex;
for(int i = 0; i < numChars; i++)
{
int temp;
iss >> std::setw(2) ;
if(!iss) /* MKW */
std::cerr << "iss error on setw\n"; /* MKW */
else /* MKW */
std::cerr << "OK on setw\n"; /* MKW */

iss >> temp; // BUG: Using setw DOES NOT WORK!!!
if(!iss) /* MKW */
std::cerr << "iss error on temp\n"; /* MKW */
else /* MKW */
{ /* MKW */
std::cerr << "OK on temp\n"; /* MKW */
std::cerr << " (temp == " << temp << ")\n"; /* MKW */
} /* MKW */
output = temp;
}
std::cout << output << std::endl;

std::cout << char(0x61626364) << '\n'; /* MKW */
}

Thanks for actually compiling the program Mike!

Output:

abcd
61626364
OK on setw
OK on temp
(temp == 1633837924)
OK on setw
iss error on temp
iss error on setw
iss error on temp
iss error on setw
iss error on temp
dddd
d


.... so in my haste, I did err in my analysis. The stream
state was indeed 'fail', but not for the reason I originally
stated.

My apologies for any confusion.

But I still stand by my advice to always check stream
state after all operations.

-Mike
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top