Why is the file I'm writng to printing gibberish? - c++

I'm not sure what's happening, but I'm using an ofstream object to write to a file in binary mode.
I am writing a byte to a file, but the file is printing gibberish. It's printing this type of gibberish: ôß
I have a class called ByteOutput with a function called inByte defined as so:
void inByte(int byte)
{
ostreamObj.write(&buffer, byte & 255);
}
&buffer is a reference to a bit buffer I am using to store a byte of data
In my main, I defined an ofstream obj and opened a file in binary using:
obj.open("tester", std::ios::binary);
I write a byte of data to the file using a ByteOutput object using:
writeObj.inByte(1001011);
However, when I check the file, it is all hieroglyphics. It does not show the letter K, which has the binary presentation 1001011.
What am I doing wrong?

this
writeObj.inByte(1001011);
calls the function with an integer = 1,001,001 decimal, not binary.

If you want to use binary, consider hex or std::bitset
#include <bitset>
#include <iostream>
using namespace std;
int main()
{
int a = 0x4B; // 01001011
bitset<8> bs(a);
cout << hex << a << endl;
cout << bs << endl;
}
if you output std::bitset to a file, every bit will be represented as a char, i.e., you will see 01001011 in you file.

Related

Need to write string to a file in hex format in c++

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.

Writing hex to a file

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;
}

Calculating the info-hash of a torrent file

I'm using C++ to parse the info hash of a torrent file, and I am having trouble getting a "correct" hash value in comparison to this site:
http://i-tools.org/torrent
I have constructed a very simple toy example just to make sure I have the basics right.
I opened a .torrent file in sublime and stripped off everything except for the info dictionary, so I have a file that looks like this:
d6:lengthi729067520e4:name31:ubuntu-12.04.1-desktop-i386.iso12:piece lengthi524288e6:pieces27820:¡´E¶ˆØËš3í ..............(more unreadable stuff.....)..........
I read this file in and parse it with this code:
#include <string>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <iostream>
#include <openssl/sha.h>
void printHexRep(const unsigned char * test_sha) {
std::cout << "CALLED HEX REP...PREPPING TO PRINT!\n";
std::ostringstream os;
os.fill('0');
os << std::hex;
for (const unsigned char * ptr = test_sha; ptr < test_sha + 20; ptr++) {
os << std::setw(2) << (unsigned int) *ptr;
}
std::cout << os.str() << std::endl << std::endl;
}
int main() {
using namespace std;
ifstream myFile ("INFO_HASH__ubuntu-12.04.1-desktop-i386.torrent", ifstream::binary);
//Get file length
myFile.seekg(0, myFile.end);
int fileLength = myFile.tellg();
myFile.seekg(0, myFile.beg);
char buffer[fileLength];
myFile.read(buffer, fileLength);
cout << "File length == " << fileLength << endl;
cout << buffer << endl << endl;
unsigned char datSha[20];
SHA1((unsigned char *) buffer, fileLength, datSha);
printHexRep(datSha);
myFile.close();
return 0;
}
Compile it like so:
g++ -o hashes info_hasher.cpp -lssl -lcrypto
And I am met with this output:
4d0ca7e1599fbb658d886bddf3436e6543f58a8b
When I am expecting this output:
14FFE5DD23188FD5CB53A1D47F1289DB70ABF31E
Does anybody know what I might be doing wrong here? Could the problem lie with the un-readability of the end of the file? Do I need to parse this as hex first or something?
Make sure you don't have a newline at the end of the file, you may also want to make sure it ends with an 'e'.
The info-hash of a torrent file is the SHA-1 hash of the info-section (in bencoded form) from the .torrent file. Essentially you need to decode the file (it's bencoded) and remember the byte offsets where the content of the value associated with the "info" key begins and end. That's the range of bytes you need to hash.
For example, if this is the torrent file:
d4:infod6:pieces20:....................4:name4:test12:piece lengthi1024ee8:announce27:http://tracker.com/announcee
You wan to just hash this section:
d6:pieces20:....................4:name4:test12:piece lengthi1024ee
For more information on bencoding, see BEP3.
SHA1 calculation is just as simple as what you've written, more or less. The error is probably in the data you're feeding it, if you get the wrong answer from the library function.
I can't speak to the torrent file prep work you've done, but I do see a few problems. If you'll revisit the SHA1 docs, notice the SHA1 function never requires its own digest length as a parameter. Next, you'll want to be quite certain the technique you're using to read the file's contents is faithfully sucking up the exact bytes, no translation.
A less critical style suggestion: make use of the third parameter to SHA1. General rule, static storage in the library is best avoided. Always prefer to supply your own buffer. Also, where you have a hard-coded 20 in your print function, that's a marvelous place for that digest length constant you've been flirting with.

How do you print out the binary representation of a file?

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

Automatically extend file size when seeking / writing to a location on a read/write fstream

I'm working on some legacy code that uses win32 WriteFile() to write to a random location in a binary file. The offset of the write can be past the end of the file in which case WriteFile() seems to automatically extend the file size to the offset and then write the data to the file.
I'd like to use std::fstream to do the same, but when I try to seekp() to the appropriate location, past the end of the file, the seekp() fails and the subsequent write() fails as well.
So it seems to me that I have to 'manually' fill in the space between the current EOF and the location I want to write to.
The code looks like this:
void Save(size_t offset, const Element& element)
{
m_File.seekp(offset, std::ios_base::beg);
m_File.write(reinterpret_cast<const char*>(&element), sizeof(Element));
if (m_File.fail()) {
// ... error handling
}
}
So is my only option to 'manually' write 0s from the current EOF up to offset?
Here is an example I picked up verbatim from MSDN:
// basic_ostream_seekp.cpp
// compile with: /EHsc
#include <fstream>
#include <iostream>
int main()
{
using namespace std;
ofstream x("basic_ostream_seekp.txt");
streamoff i = x.tellp();
cout << i << endl;
x << "testing";
i = x.tellp();
cout << i << endl;
x.seekp(2); // Put char in third char position in file
x << " ";
x.seekp(2, ios::end); // Put char two after end of file
x << "z";
}
The file "basic_ostream_seekp.txt" has te ting\0\0z at the end of the program, i.e., you are allowed to seek past the end of the file.
In any case, if write does fail for you, you could check and see if seekp does too. If it does, you can detect the failure earlier.