Khurram Shehzad
Khurram Shehzad

Reputation: 1

Reading from a file as a hexadecimal value

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

Answers (3)

user2249683
user2249683

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

Jerry Coffin
Jerry Coffin

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

Marian
Marian

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

Related Questions