I have a program that reads the hex of a file, modifies it, and stores the modified hex in a std::string.
For example, how would I write this to a file
std::string wut="b6306edf953a6ac8d17d70bda3e93f2a3816eac333d1ac78";
and get its value
.0n..:j..}p...?*8...3..x
in the outputted file?
I'd prefer not to use sprintf, but I guess if it's necessary, I'll do what I must.
If I understand your question correctly you want the text converted to it's numeric equivalent and then written to file. Given the hint you provided in your question it looks like this should be done byte by byte. Below is one way to achieve this. Note the need to convert each byte from a string to an integer value.
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <ios>
std::string wut = "b6306edf953a6ac8d17d70bda3e93f2a3816eac333d1ac78";
int main()
{
std::ofstream datafile("c:\\temp\\temp1.dat", std::ios_base::binary | std::ios_base::out);
char buf[3];
buf[2] = 0;
std::stringstream input(wut);
input.flags(std::ios_base::hex);
while (input)
{
input >> buf[0] >> buf[1];
long val = strtol(buf, nullptr, 16);
datafile << static_cast<unsigned char>(val & 0xff);
}
}
The answer of #Peter R will lead to an output which is not 100% equal, due to the stringstream interpreting more than one '0's in a row in an unintended way.
Example: If we want to write the hex value "00000000", the stringstream would output " 000000".
The solution below works in every case, no matter how many zeros are contained in the hex string:
// Input
std::string hex = "180f00005e2c3415"; // (or longer)
std::basic_string<uint8_t> bytes;
// Iterate over every pair of hex values in the input string (e.g. "18", "0f", ...)
for (size_t i = 0; i < hex.length(); i += 2)
{
uint16_t byte;
// Get current pair and store in nextbyte
std::string nextbyte = hex.substr(i, 2);
// Put the pair into an istringstream and stream it through std::hex for
// conversion into an integer value.
// This will calculate the byte value of your string-represented hex value.
std::istringstream(nextbyte) >> std::hex >> byte;
// As the stream above does not work with uint8 directly,
// we have to cast it now.
// As every pair can have a maximum value of "ff",
// which is "11111111" (8 bits), we will not lose any information during this cast.
// This line adds the current byte value to our final byte "array".
bytes.push_back(static_cast<uint8_t>(byte));
}
// we are now generating a string obj from our bytes-"array"
// this string object contains the non-human-readable binary byte values
// therefore, simply reading it would yield a String like ".0n..:j..}p...?*8...3..x"
// however, this is very useful to output it directly into a binary file like shown below
std::string result(begin(bytes), end(bytes));
Then you can simply write this string to a file like this:
std::ofstream output_file("filename", std::ios::binary | std::ios::out);
if (output_file.is_open())
{
output_file << result;
output_file.close();
}
else
{
std::cout << "Error could not create file." << std::endl;
}
Related
I never thought I would have to turn to SO to solve this.
Alright so for more insight I am making my own encryption program.
I'm not trying to make it good or anything it's just a personal project.
What this program is doing is that it's flipping certain bits in every single byte of the character making it unreadable.
However every time I run the program and decrypt I get weird characters on the output. These characters seem to match the amount of lines as following:
^^ text that I want to encrypt
^^ after encrypting. (a lot of the text got cut off)
^^ after decrypting. there's 10 null character corresponding to the amount of newlines. there also seems to be another weird '�' character. Where are these bytes coming from??
I've tried a lot of stuff. Here is my code if anyone needs it (it's compiled with default flags):
#include <iostream>
#include <fstream>
#include <cstring>
#include <string>
#define ENCRYPTFILE "Encrypted.oskar"
typedef unsigned char BYTE;
char saltFunc(BYTE salt, char chr) {
for(int i = 0; i < 8; i++) {
if((salt >> i) & 1U) {
chr ^= 1UL << i;
}
}
return chr;
}
int main () {
std::ofstream encryptFile(ENCRYPTFILE, std::ifstream::in);
std::ifstream inputFile(ENCRYPTFILE, std::ifstream::in);
unsigned int length;
unsigned int lineLength;
BYTE salt = 0b00000001;
std::string line;
std::cin.unsetf(std::ios::dec);
std::cin.unsetf(std::ios::hex);
std::cin.unsetf(std::ios::oct);
//std::cout << "input salt in hex with a prefix 0x so for example. 0xA2" << std::endl;
//std::cin >> std::hex >> salt;
inputFile.seekg(0, inputFile.end);
length = inputFile.tellg();
inputFile.seekg(0, inputFile.beg);
std::cout << lineLength << std::endl;
char* fileBuffer = new char[length];
char* encryptFileBuffer = new char[length];
memset(fileBuffer, 0, length);
memset(encryptFileBuffer, 0, length);
while (inputFile.good()) { // just get file length in bytes.
static int i = 0;
fileBuffer[i] = inputFile.get();
i++;
}
while (std::getline(inputFile, line))
++lineLength;
inputFile.clear();
encryptFile.clear();
std::cout << "file size: " << length << std::endl;
for(int i = 0; i < length; i++) {
encryptFileBuffer[i] = saltFunc(salt, fileBuffer[i]);
encryptFile << encryptFileBuffer[i];
}
inputFile.close();
encryptFile.close();
delete[] encryptFileBuffer;
delete[] fileBuffer;
return 0;
}
The problem is that you are measuring the length of the file in bytes, which, for text files, is not the same as the length in characters. But you are then reading it as characters, so you end up reading too many characters and then writing extra garbage after then end in the output file.
Since you are getting one extra character per line, it is likely you are running on Windows, where line ending characters are two bytes in the file. That's where the extra incorrect length you are seeing is coming from.
For encryption/decryption what you probably want to do is read and write the file in binary mode, so you are reading and writing bytes not characters. You do this by adding std::ios::binary into the flags when opening the file(s):
std::ofstream encryptFile(ENCRYPTFILE, std::ifstream::in | std::ios::binary);
std::ifstream inputFile(ENCRYPTFILE, std::ifstream::in | std::ios::binary);
So I am currently able to read some hex values from a csv file using ifstream. I am able to read the values and assign them to a string variable. But I want to convert them to uint8_t values. So essentially I want something like this uint8_t A = 0x41;
I have tried atoi , stoi , and strtol but i don't seem to get any valid output.(I might be using them wrong)
int read_csv(){
using namespace std;
ifstream fin;
fin.open("simpletrajhex.txt");
while (fin.good ()){
char[] line;
getline (fin, line, ',');
uint8_t hex1 = (uint8_t)stoi(line,NULL,16);
cout << line << " " << hex1 << endl;
}
return 1;
}
When I read my csv file i get something similar
0xFF
0x5F
0x02
0x00
0xFF
But these are strings and I need each value to be converted to uint8_t
and when I try convert nothing shows up.
You have a number of problems with your code, but two primary problems related to your conversion to uint8_t. A general problem with attempting to read a .csv file with getline (fin, line, ','); is you have no way of tracking the number of values present in each line. Reading with the ',' delimiter will cause getline to skip the line-ending and simple read the next value until EOF is encountered. Better to read an entire line into line with getline (fin, line); and then create a stringstream from line allowing you to read the value in the line until the end of the stringstream is reached (limiting the value conversions to those within each line).
The primary obstacle to storing the values as uint8_t is your failure the validate the the result of the stoi conversion is within the range of uint8_t before making the assignment. Further, since uint8_t is an unsigned value, use of stoul is more appropriate. While the C-style cast to (uint8_t) is valid, it is better to use a static_cast<uint8_t>(...) (though both provide the same result). Finally, your attempt to output << hex1 ... will always fail as the << operator expects an int (or unsigned) value.
Putting all of those pieces together, you can rework your read_csv() to take the name of the file to open as a parameter rather than hardcoding the filename in the function (don't do that) and do something like:
int read_csv (const string& name)
{
string line;
ifstream fin (name);
while (getline (fin, line)) { /* read entire line into line */
stringstream ss (line); /* create stringstream from line */
string field; /* string to hold each field */
cout << "line: " << line << '\n';
while (getline (ss, field, ',')) { /* read each hex value from line */
uint64_t tmp = stoul (field, 0, 0); /* convert to uint64_t */
if (tmp <= UINT8_MAX) { /* validate in range of uint8_t */
uint8_t hex1 = static_cast<uint8_t>(tmp); /* store uint8_t */
/* output with cast to unsigned for << */
cout << " " << field << " -> " <<
static_cast<uint32_t>(hex1) << '\n';
}
}
}
return 1;
}
note: rather than casing within cout you can also precede hex1 with a numeric + to force the promotion, e.g.
cout << " " << field << " -> " << +hex1 << '\n';
also note: that using 0 for the base in stoul, the numeric base is auto-detected: if the prefix is 0, the base is octal, if the prefix is 0x or 0X, the base is hexadecimal, otherwise the base is decimal.
A short example making use of the function could be:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstdint>
using namespace std;
int read_csv (const string& name)
{
string line;
ifstream fin (name);
while (getline (fin, line)) { /* read entire line into line */
stringstream ss (line); /* create stringstream from line */
string field; /* string to hold each field */
cout << "line: " << line << '\n';
while (getline (ss, field, ',')) { /* read each hex value from line */
uint64_t tmp = stoul (field, 0, 0); /* convert to uint64_t */
if (tmp <= UINT8_MAX) { /* validate in range of uint8_t */
uint8_t hex1 = static_cast<uint8_t>(tmp); /* store uint8_t */
/* output with cast to unsigned for << */
cout << " " << field << " -> " <<
static_cast<uint32_t>(hex1) << '\n';
}
}
}
return 1;
}
int main (int argc, char **argv) {
if (argc < 2) {
cerr << "error: insufficient input\n" <<
"usage: " << argv[0] << " <file>\n";
return 1;
}
read_csv (argv[1]);
}
(note: using namespace std; is generally encouraged, so while it can ease typing for short example programs, you will generally want to avoid including the entire std namespace in each source file (and especially avoid including it in header files))
Example Input File
$ cat dat/hexcsv.csv
0xff,0x5f
0x02,0x00
0xff,0xaa
Example Use/Output
Each of the numeric values are store in the uint8_t variable hex1 before being output in decimal.
$ ./bin/read_csv_uint8 dat/hexcsv.csv
line: 0xff,0x5f
0xff -> 255
0x5f -> 95
line: 0x02,0x00
0x02 -> 2
0x00 -> 0
line: 0xff,0xaa
0xff -> 255
0xaa -> 170
You cannot store hex value as it is in an uint8_t variable, so uint8_t A = 0x41 is not possible. Instead, you will have to get a decimal equivalent of the hex number into uint8_t.
Try using std::stoul
Get the decimal equivalent of hex and get the hex back from the decimal when you need it.
I am having a string which contains the hex value:
string str = "e101";
I need to write this in a file as 2 bytes. While I am trying to write a file, it will write like the following 4 bytes value:
65 31 30 31
I am using the following operation for file write:
myfile.open ("file.cf3",std::ios::binary);
myfile << str << "\n";
myfile.close();
but I want to write it as a 2 bytes value.
For example, if i g How to write it as 2 bytes to a file?
std::string wut="b6306edf953a6ac8d17d70bda3e93f2a3816eac333d1ac78";
i want the output like
.0n..:j..}p...?*8...3..x
I think your question is ambiguous ...
Keep in mind that, from your string, every two char you have 1 byte (not two).
So you want to write two numbers (meaning in ascii) representing the hex value of the string...
If this is the right interpretation, you need to split the string in pairs of chars and then convert each one to the equivalent integer.
Here is my code ...
It writes out to stdout, but you can modify it easily in order to write to file instead to the screen.
#include <iostream>
#include <stdio.h>
#include <string>
#include <cstring>
#include <stdlib.h>
using namespace std;
int main () {
string str = "e101";
string two_char;
unsigned char byte;
for (int i=0 ; i<str.size(); i+=2) {
two_char = str.substr(i,2);
byte = strtol(two_char.c_str(),0,16);
cout << two_char << " " << (int)byte <<"\n";
}
}
Here is an example for a solution.
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::ofstream file("file.txt", std::ios::binary);
if(!file.is_open()) {
return -1;
}
std::string str("e101");
for (std::size_t i = 0; i < str.length() - 1; ++++i) {
file << static_cast<char>(str[i] * 16 + str[i + 1]);
}
file.close();
}
You can simply iterate over your string and take two characters as one byte. You multiply the first character with 16 and add the second character.
In answer to your original question about writing 2-bytes out in binary to a file in C++, you have a basic 2-step process. (1) convert your string representation of the number to a numeric value using stoi with base 16. This provides a numeric values you can store in an unsigned short. (2) write that value out to your file with f.write, not frwite where f is your open stream reference.
If you want to format the output in hex for cout, then you must set the flags for cout to output numeric values in hex-format (though not directly part of your question, it ties in the stream I/O formatting if desired.)
So essentially you have your string and convert it to a number, e.g.
std::string str = "e101";
unsigned short u = stoi(str, 0, 16);
Now u holds a numeric value converted from the text in str using base-16 that you can simply write to your file as a 2-byte value, e.g.
std::string filename = "out.bin"; /* output filename */
...
std::ofstream f (filename, f.trunc | f.binary); /* open out in binary */
if (!f.write(reinterpret_cast<char*>(&u), sizeof u)) { /* write 2 bytes */
std::cerr << "error: write of short to file failed.\n";
return 1;
}
Putting it altogether, you could do something short that outputs the hex value being written with cout as well as writing it to the file "out.bin", e.g.
#include <fstream>
#include <iostream>
#include <iomanip>
#include <string>
int main (void) {
std::string filename = "out.bin"; /* output filename */
std::string str = "e101";
unsigned short u = stoi(str, 0, 16);
/* output converted value to terminal in hex */
std::cout.setf(std::ios::hex, std::ios::basefield); /* set hex output */
std::cout << "writing value to file: " << u << '\n'; /* for cout */
/* output converted value to file */
std::ofstream f (filename, f.trunc | f.binary); /* open out in binary */
if (!f.write(reinterpret_cast<char*>(&u), sizeof u)) { /* write 2 bytes */
std::cerr << "error: write of short to file failed.\n";
return 1;
}
}
Example Use/Output
$ ./bin/stoi_short
writing value to file: e101
Resulting Output File
Confirm by dumping the contents of the file with a hexdump program, e.g.
$ hexdump out.bin
0000000 e101
0000002
Look things over and let me know if you have further questions.
I'm trying to create a compression program but I need to know the basics of how to open a file in binary and print out its contents.
In a text file, called "Tester.txt", I have this:
MJ
In a .cpp file, I have this:
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main
{
fstream istr;
istr.open("Tester.txt", ios::binary);
}
From my understanding in the cplusplus reference, this uses a stream object to open the file specified in binary?
But I'm stuck on how exactly I can "print" out the first byte of the file, i.e. the letter M in binary?
I know that M (capital letter) in binary is 01001101.
So how do I do a cout of M in binary?
Thanks
You have a confusion between numbers and representations of numbers, probably created by the fact that the word "binary" can sometimes be used to describe both. When you open a file in "binary mode", that means you see the raw values of the bytes in the file. This has nothing to do with "binary" in the sense of representing numbers in base two.
Say a file has "x" followed by a newline and a return. In "binary mode", you will see that as three byte-size values, one containing the ASCII code for "x", one containing the ASCII code for newline, and one containing the ASCII code for return. These are values that you read from the file. You can represent them in binary, but you can also represent them in decimal or hex, you still have read the exact same values from the file.
Reading a file in "binary" determines the values you read, not how you represent them. Two cars are the same two cars whether you represent the value two as "2" (decimal), "10" (binary), or "two" (English).
Binary input/output on streams is done using their member functions read() and write().
Like this:
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main
{
fstream istr;
istr.open("Tester.txt", ios::binary);
if (istr) {
// Read one byte
char byte;
if (!istr.read(&byte, 1)) {
// Error when reading
}
// Alternative way to read one byte (thanks to DyP)
byte = istr.get();
// Another alternative:
if (!istr.get(byte)) {
// Error when reading.
}
// Read a block of bytes:
char buffer[1024];
if (!istr.read(buffer, 1024)) {
// Read error, or EOF reached before 1024 bytes were read.
}
}
}
Here is a quick program which uses the C++ Standard Library to do all the heavy lifting.
#include <iostream>
#include <iterator>
#include <bitset>
#include <algorithm>
int main() {
std::istreambuf_iterator< char > in( std::cin ), in_end;
std::ostream_iterator< std::bitset< 8 > > out( std::cout, " " );
std::copy( in, in_end, out );
std::cout << '\n';
}
See it run. I used std::cin for demonstration, but you should open a file with std::ios::binary and pass that instead.
Since each variable is only used once, this could all be done on one line. Even if you open the file instead of using std::cin.
EDIT:
std::copy is a function encapsulating the loop for ( ; in != in_end; ++ in ) * out ++ = * in;.
The type std::istreambuf_iterator either takes an istream constructor argument and provides an iterator in suitable for such a loop, or takes no constructor argument and provides an iterator in_end such that in == in_end if in.eof() == true. The iterator gets unformatted bytes (type char) from the stream.
The type std::ostream_iterator< std::bitset< 8 > > provides an iterator out so * out ++ = x converts x to std::bitset< 8 > and prints the result. In this case x is a byte and bitset provides a constructor for such a byte value, and overloads operator<< to print a binary representation of 1's and 0's.
To output a value in binary you need to do it manually as the standard library does not support that output format.
int mask = 0x80;
while(mask)
{
std::cout << (byteValue & mask ? '1' : '0');
mask >>= 1;
}
std::cout << std::endl;
This will scan from the top bit to the low bit and print out a value representing each one.
try this:
#include <fstream>
#include <iostream>
#include <string>
#include <bitset>
#include <iomanip>
int main()
{
// Set up your objects.
char c;
std::fstream istr("Tester.txt", ios::binary);
unsigned long loc = 0;
// Read the file one character at a time.
// Remembering not to skip white space in this situation.
for(;istr >> std::noskipws >> c;++loc)
{
// When printing compensate for non printable characters.
// If the character is outside the ASCII range then print it as an integer.
std::stringstream charStr;
if ((c < 32) || (c > 126))
{
charStr << "Char: " << c;
}
else
{
charStr << "Non Printable: " << static_cast<int>(c);
}
// Print the value and location in a nicely formatted way.
std::cout << std::setw(16) << location
<< " : "
<< std::bitset<8>(c).to_string() // Prints the character as an 8 bit binary value.
<< " : "
<< charStr.str()
<< "\n";
}
}
But there are standard tools that do this already:
Look at od
I have a txt file which contains integers in hexadecimal form in each line like:
232B2344
A2BC34893
DEF9433
.....
I would like an elegant way of reading this .txt file in C++ and store them in arrays so that I can make computations on them. Also given the hex 232B2344 say I would like to be in position to say the value of each byte entry
First include a header
#include "sstream"
Then get the hexadecimal value in a simple char[] array string using file handling.
char str[100];
Declare an Unsigned int variable...
unsigned int value;
Then declare a "std::stringstream" variable. e.g.
std::stringstream ss;
ss<<std::hex<<str;
ss>>value;
Now the "value" contains the hexadecimal value in file in form of integer.
As far as you describe, each number in the file is a 4 bytes unsigned integer (that fit in 32 bits). Here you have a c++ version for parsing the file and getting the numbers array:
std::vector<std::string> fromFileToArray( const std::string & fileName )
{
std::string line;
std::vector<uint32_t> numbers;
std::stringstream ss;
uint32_t tmp;
std::ifstream numbersFile( fileName.c_str() );
while( numbersFile.good() )
{
getline( numbersFile, line );
ss << std::hex << line;
ss >> tmp;
numbers.push_back( tmp );
}
}
How about this (though it is written with C function, one could help me port this to use C++ functions):
const char hexstring[] = "deadbeef10203040b00b1e50", *pos = hexstring;
unsigned char val[12];
size_t count = 0;
/* WARNING: no sanitization or error-checking whatsoever - MAGIC. DO NOT TOUCH. */
for(count = 0; count < sizeof(val)/sizeof(val[0]); count++) {
sscanf(pos, "%2hhx", &val[count]);
pos += 2 * sizeof(char);
}
/* Does it work? */
printf("0x");
for(count = 0; count < sizeof(val)/sizeof(val[0]); count++)
printf("%02x", val[count]);
printf("\n");
In case of an odd number of hex digits in the string, you have to make sure you prefix it with a starting 0. For example, the string "f00f5" will be evaluated as {0xf0, 0x0f, 0x05} erroneously by the above example, instead of the proper {0x0f, 0x00, 0xf5}.
To read value in hex format - use std::hex from <iomanip>. Like in this very short example:
#include <iostream>
#include <iomanip>
int main() {
int value;
std::cin >> std::hex >> value;
std::cout << value;
}
Just read as many times as your array has elements.