Reputation: 1
I have a simple text file and i want to read it as hexadecimal. For example following text is in text file "315c4e", now these are actually three bytes, i want to save them in separate variables(or in an array, which ever is possible). For example, the first variable say uint8_t v1, should contain 31, in other words this variable should have 00110001 value(which is 31 in hex).
I am doing a cryptography assignment in my college and i had to read values from text files which contain hex-encoded cipher texts.
Upvotes: 0
Views: 3276
Reputation:
If you want to read tuples of 3 bytes (6 characters) separated by white spaces:
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <vector>
struct ToHex
{
typedef std::uint8_t byte;
typedef std::istream::traits_type traits;
byte& value;
ToHex(byte& value)
: value(value)
{}
void read(std::istream& stream) const {
byte b[2];
for(unsigned i = 0; i < 2; ++i) {
traits::char_type ch = stream.get();
if('0' <= ch && ch <= '9') b[i] = ch - '0';
else if('a' <= ch && ch <= 'f') b[i] = ch - 'a' + 10;
else if('A' <= ch && ch <= 'F') b[i] = ch - 'A' + 10;
else {
if(ch != traits::eof())
stream.putback(ch);
stream.setstate(std::ios_base::failbit);
}
}
value = b[0] * 16 + b[1]; // Rubbish if an extraction failed
}
};
inline ToHex to_hex(ToHex::byte& value) {
return ToHex(value);
}
inline std::istream& operator >> (std::istream& stream, const ToHex& value) {
value.read(stream);
return stream;
}
int main() {
std::istringstream input(""
"315c4e\n"
"010c0e\n"
"Failure");
ToHex::byte a[3];
input >> std::ws;
while(input && ! input.eof()) {
for(unsigned i = 0; i < 3; ++i) {
input >> to_hex(a[i]);
}
if(input) {
for(unsigned i = 0; i < 3; ++i)
std::cout << std::hex << std::setw(2) << std::setfill('0') << (unsigned)a[i];
std::cout << '\n';
input >> std::ws;
}
}
if(input.fail()) {
std::cerr << "Failure\n";
}
}
Upvotes: 0
Reputation: 490108
The normal setw
and setprecision
won't limit the amount of input read to two characters, so something like this:
infile >> std::setw(2) >> setprecision(2) >> std::hex >> ch;
...just won't work. That being the case, it's probably about as easy as anything to just read a 2-character string, and do the conversion yourself:
#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
#include <ctype.h>
unsigned char hstouc(std::string const &in) {
static const std::string v{ "0123456789ABCDEF" };
return v.find(toupper(in[0])) * 16 + v.find(toupper(in[1]));
}
int main() {
std::istringstream in{ "315c4e" };
std::vector<unsigned char> vals;
std::string temp;
while (in >> std::setw(2) >> temp)
vals.push_back(hstouc(temp));
for (unsigned v : vals)
std::cout << v << "\t";
}
If your input is machine generated, that will probably suffice. If it may have been edited by hand (or anything else that could produce incorrect input) you'll probably need/want to add some error checking to the conversion routine. Alternatively, you might want to use something like strtoul
, which already does such checking, then cast the result to unsigned char
.
Upvotes: 1
Reputation: 7472
This question gave me the idea to the following function and I can't resist to post it here. BTW, is there a standard function doing the same as this atob
?
int atob(unsigned char c) {
static char x[256];
int i;
if (x[0]==0) {
for(i=0;i<256;i++) x[i] = -1;
for(i=0;i<10;i++) x[i+'0'] = i;
for(i=0;i<6;i++) x[i+'a']= x[i+'A'] = i+10;
}
return(x[c]);
}
int main() {
FILE *ff;
int hex, c1, c2;
ff = fopen("test.txt", "r");
for(;;) {
c1 = fgetc(ff);
c2 = fgetc(ff);
if (c2 == EOF) break;
hex = atob(c1)*16 + atob(c2);
printf("0x%02x ", hex);
}
fclose(ff);
}
Upvotes: 0