How to read hex values into integer with fstream (C++) - c++

I am trying to read a little-endian hex string from a binary file, and put that value into an integer to work with it. When I try to read, instead of getting a number I get ascii symbols. I've tried casts and atoi and nothing seems to work. What is the best way to use fstream to read a hex string into an integer from a file?
This is essentially my program:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(int argc, char* argv[]) {
fstream input;
fstream output;
char cbuffer[4];
char revbuffer[8];
input.open(argv[1], fstream::binary | fstream::in);
output.open("output.txt", ios::out | ios::app);
input.seekg(16, input.beg);
input.read(cbuffer, 4);
cout << sizeof(revbuffer) << endl;
cout << cbuffer[0] << cbuffer[1] << cbuffer[2] << cbuffer[3] << endl;
}

If it's an integer value stored in binary format, I guess it's either a int32_t or a uint32_t. Since you mention that the value is stored in little-endian byte order, I guess you want to make sure that the host running your program converts it (if it needs to). C++20 has std::endian. If that's not available to you, there are usually macros for detecting endianness at compiletime that you can use instead of the std::endian tests I've used. I've assumed that the value is a uint32_t below.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <type_traits> // std::endian
// little endian unsigned 32 bit integer to host byte order
inline uint32_t Le32toh(uint32_t le) {
#if __cplusplus <= 201703L
// run-time check
static constexpr uint16_t endian = 1;
if(*reinterpret_cast<const uint8_t*>(&endian)==1) return le;
#else
// compile-time check
static_assert(std::endian::native == std::endian::little || std::endian::native == std::endian::big);
if constexpr (std::endian::native == std::endian::little) return le;
#endif
const uint8_t* c=reinterpret_cast<const uint8_t*>(&le);
return // little-to-big endian conversion
(static_cast<uint32_t>(c[0])<<24) |
(static_cast<uint32_t>(c[1])<<16) |
(static_cast<uint32_t>(c[2])<<8) |
(static_cast<uint32_t>(c[3]));
return le;
}
int main(int argc, char* argv[]) {
std::vector<std::string> args(argv+1, argv+argc);
std::fstream output("output.txt", std::ios::out | std::ios::app);
uint32_t cbuffer;
for(const auto& file : args) {
std::fstream input(file, std::fstream::binary | std::fstream::in);
input.seekg(16, input.beg);
// read directly into the varibles memory
input.read(reinterpret_cast<char*>(&cbuffer), 4);
// output the value unconverted
std::cout << std::hex << cbuffer << "\n";
// convert if needed
cbuffer = Le32toh(cbuffer);
// output the value converted
std::cout << std::hex << cbuffer << "\n";
}
}

Related

Reading binary data into std::string c++

I am trying to read data from binary file to an std::string.Here is what I have tried at first.
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main(int argc, char const *argv[])
{
fstream file("output.bin" , ios::out | ios::binary | ios::in);
string my_str(5, '\0');
file.read(my_str.c_str(), 5);
cout << "String = " << my_str<< endl ;
}
And the compiler gave the error :
error: invalid conversion from ‘const char*’ to ‘std::basic_istream<char>::char_type* {aka char*}’ [-fpermissive]
file.read(my_str.c_str(), 5);
As far as I understand, c_str() returns a const pointer which cannot be used in read method, so I changed my approach a little bit(which you can see below). Is there a better way to do this ?
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
int main(int argc, char const *argv[])
{
fstream file("output.bin" , ios::out | ios::binary | ios::in);
string my_str(5, '\0');
char buffer[6];
file.read(buffer, 5);
buffer[5] = '\0';
my_str = string(buffer);
cout << "String = " << my_str<< endl ;
}
ps : forgive me if I could not make myself clear, this is my first time here :)
In C++11, the way to get a non-const pointer to the string's data is:
file.read(&my_str[0], 5);
C++17 will introduce non-const data() for this as well:
file.read(my_str.data(), 5);
another way, using standard algorithms:
#include <iostream>
#include <string>
#include <fstream>
#include <algorithm>
#include <iterator>
using namespace std;
int main(int argc, char const *argv[])
{
fstream file("output.bin" , ios::out | ios::binary | ios::in);
auto my_str = string();
copy_n(istream_iterator<char>(file),
5,
std::back_inserter(my_str));
cout << "String = " << my_str<< endl ;
}
std::string is specially designed to work with strings and with c-style strings as well, so this fact will work against you in this situation. For example your code:
char buffer[6];
file.read(buffer, 5);
buffer[5] = '\0';
my_str = string(buffer);
what is wrong with it? You are reading binary data and who guarantees that there won't be '\0' byte there? You can fix it by:
my_str = string(buffer,5);
but this shows the point - std::string as a buffer is not a good choice. So you better use std::vector<char> or even better std::vector<uint8_t> which has method data() but will not implicitly convert from c-string, output to std::ostream etc.

Integer to char* and char* to Integer conversion

I'm using the Crypto++ library, and I created this simple class:
class EncoderRSA
{
public:
EncoderRSA();
void keyGeneration();
void substitutePublicKey(Integer e, Integer n);
Integer encode(std::string plainText);
std::string decode(Integer cypher);
private:
AutoSeededRandomPool prng; // Pseudo Random Number Generator
RSA::PublicKey publicKey; // For encrypt plain text
RSA::PrivateKey privateKey; // For decrypt plain text
};
But I have some problem: when I encoded my message using EncoderRSA::encode(message), I want to convert it from Integer to char* (for send by sockets) and from char* to Integer (after receive on the other side). How can I do it?
Integer to char* and char* to Integer conversion
I'm going to answer the question in the title, and side step the body's question because that appear to encrypt, and not encode.
Integer to char*
Its easy to get a char* because the Integer class (header, implementation) overloads operator<<.
So, you would do something like:
#include <iostream>
#include <sstream>
#include <string>
#include "integer.h"
...
using std::cout;
using std::endl;
using std::string;
using CryptoPP::Integer;
// Perhaps this is received from the EncoderRSA::encode() function
Integer n = ...;
ostringstream oss;
oss << n;
// Create this temporary; otherwise, you might get yourself into trouble
string str(oss.str());
cout << "string: " << str << endl;
cout << "char*: " << str.c_str() << endl;
char* to Integer
This is just as easy because the Integer class has a constructor for it. From integer.h:
// convert from string (requires NULL terminator)
Integer (const char *str)
Here's the program:
#include <string>
#include "integer.h"
...
using std::cout;
using std::endl;
using std::string;
using CryptoPP::Integer;
// Read from the wire
const char data[] = "12345678901234567890123456789012345678901234567890123456789012345678901234567890.";
// Perhaps this is passed to the EncoderRSA::decode() function
Integer n(data, strlen(data));
If you want the byte array version, then...
Integer to byte*
#include <vector>
#include "integer.h"
...
using std::vector;
using CryptoPP::Integer;
// Perhaps this is received from the EncoderRSA::encode() function
Integer n = ...;
size_t sz = n.MinEncodedSize();
vector v;
v.resize(sz);
n.Encode(&v[0], v.size());
byte* to Integer
This is just as easy because the Integer class has a constructor for it. From integer.h:
// convert from string (does NOT require NULL terminator)
Decode (const byte *input, size_t inputLen, Signedness=UNSIGNED)
Here's the program:
#include "integer.h"
...
using CryptoPP::Integer;
// Read from the wire; pretend they are binary
const char byte[] = "12345678901234567890123456789012345678901234567890123456789012345678901234567890";
// Perhaps this is passed to the EncoderRSA::decode() function
Integer n;
n.decode(data, sizeof(data));
You can get even fancier with the encoding and decoding. For example, here's a program that HexEncodes encodes them:
#include <iostream>
#include <string>
#include "integer.h"
...
using std::cout;
using std::endl;
using std::string;
using CryptoPP::Integer;
// Perhaps this is received from the EncoderRSA::encode() function
Integer n("0xfedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321");
string encoded;
size_t req = n.MinEncodedSize();
encoded.reserve(req);
HexEncoder encoder(new StringSink(encoded));
n.Encode(encoder, req);
cout << encoded << endl;
It produces:
$ ./cryptopp-test.exe
FEDCBA0987654321FEDCBA0987654321FEDCBA0987654321FEDCBA0987654321
And you can switch to a Base64 encoder with:
Base64Encoder encoder(new StringSink(encoded));
n.Encode(encoder, req);
cout << encoded << endl;
It produces:
$ ./cryptopp-test.exe
/ty6CYdlQyH+3LoJh2VDIf7cugmHZUMh/ty6CYdl
Resolve of this problem are next two methods:
Integer EncryptorRSA::stringToInteger(std::string str) {
Integer integer(str.c_str());
return integer;
}
std::string EncryptorRSA::integerToString(Integer integer) {
std::stringstream stream;
stream << std::hex << integer;
return stream.str();
}

How to convert binary files context into int/long value in C++

I am storing a value in a binary file with fstream. The value is unsigned short type.
unsigned shord value=1750; //2 byte variable
file.write((char*)&value,sizeof(value));
My problem is that I want to read this binary file in another function, but it gives me some weird symbols (Obviously because it is binary).
Is there any way to get those two bytes and convert them to my old value (1750) ?
Here's what I have tried:
cout <<(unsigned short)(unsigned char)(s2[8]);//s2 variable where the whole body is stored
cout <<(unsigned short)(char*)(s2[8]);
I have tried other things, too, but they were just chickenscratch and aren't worth including here.
Here's how you might do it (note uses C++11 features):
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
void write_shorts(string filename, vector<unsigned short> shorts)
{
ofstream f;
f.open(filename, ofstream::trunc|ofstream::binary);
for(auto s: shorts)
f.write(reinterpret_cast<char*>(&s), sizeof(s));
}
auto read_shorts(string filename)
{
ifstream f(filename);
vector<unsigned short> res;
short x;
while(f.read(reinterpret_cast<char*>(&x), sizeof(x)))
res.push_back(x);
return res;
}
int main()
{
// Write 3 shorts to a file
write_shorts("myshorts", {4711, 1, 0xffff});
// Read them back into a vector
auto v = read_shorts("myshorts");
cout << "Read " << v.size() << "shorts: " << endl;
for(auto x: v)
cout << x << endl;
}

Reading binary data into struct with ifstream

I'm trying to read binary data from a file using ifstream.
Specifically, I'm trying to populate this "Header" struct with data read from a file:
struct Header {
char id[16];
int length;
int count;
};
Now, if I read the file in this way, the result is exactly what I want:
input.read((char*)&hdr, sizeof(hdr));
But if I instead read each variable of the struct manually, the results are gibberish:
input.read((char*)&hdr.id, sizeof(hdr.id));
input.read((char*)&hdr.length, sizeof(hdr.length));
input.read((char*)&hdr.count, sizeof(hdr.count));
My question is, what is happening here that makes these two methods return different results?
It is also possible to read the struct in one step.
i.e. fh.read((char*)&h, sizeof(Header));
As the comment above states, you are probably missing hdr.length and hdr.count.
I tried it with gcc 4.8 and clang 3.5 and it works correctly.
#include <iostream>
#include <fstream>
#pragma pack(push, r1, 1)
struct Header {
char id[15];
int length;
int count;
};
#pragma pack(pop, r1)
int main() {
Header h = {"alalalala", 5, 10};
std::fstream fh;
fh.open("test.txt", std::fstream::out | std::fstream::binary);
fh.write((char*)&h, sizeof(Header));
fh.close();
fh.open("test.txt", std::fstream::in | std::fstream::binary);
fh.read((char*)&h.id, sizeof(h.id));
fh.read((char*)&h.length, sizeof(h.length));
fh.read((char*)&h.count, sizeof(h.count));
fh.close();
std::cout << h.id << " " << h.length << " " << h.count << std::endl;
}

Converting char to int c++

I'm loosing my mind at the moment and below is what I'm trying to do.
char* buffer;
sprintf(buffer, "0x%08x", 5);
*(int *)(0x834AF2AC + 0x1a) = ?buffer?;
Buffer = 0x05000000
I need to set that in memory, if I just set 05 it will set 0x00000005
Question asked better.
How can I convert an INT into a format of "0x%08x"
So 5 becomes 0x05000000
ANSWERD:
The correct answer is *(int *)(0x834AF2AC + 0x1a) = 5<<24;
Something like this:
#include <iostream> // for std::cout, std::endl
#include <string> // for std::string, std::stoi
int main()
{
std::string s{"0x05"};
int i = std::stoi(s, nullptr, 16); // convert base 16 number in s to int
std::cout << i << std::endl;
}
Two result from google which points to stackoverflow (result 1 and 2).
Convert char to int in C and C++
C char* to int conversion
I'm not sure if I understand correctly but if you want to convert an entire string to int, then I would suggest stringstream.
http://www.cplusplus.com/reference/sstream/stringstream/stringstream/
For hexadecimal string:
#include <string> // std::string
#include <iostream> // std::cout
#include <sstream> // std::stringstream
int main () {
std::stringstream ss;
ss << std::hex << 0x05;
int foo;
ss >> foo;
std::cout << "foo: " << foo << '\n';
return 0;
}