I want to read the single bytes of a midi file, and I wrote a simple program to try to do that:
ifstream file{"D:\Descargas\OutFile.midi" };
if (!file.is_open())
cout << "Not open" << endl; // It passes this test
char c;
for (unsigned i = 0; i < 100; ++i) {
file >> c;
cout << c << endl; // Output is -52, but it must output 4D which is 77 in decimal
}
but as I wrote, the output is not good and I don't know where I'm going wrong.
You need to configure the output to print in hexedecimal and to pad each number with 0 to a width of 2. Also you need to cast the character c to an int so it doesn't get output as a letter:
// configure output
cout << std::hex << std::setfill('0') << std::uppercase;
char c;
// read in the while block so you only use it if the read succeeds
while(file >> c)
{
// set the width and convert to an integer
cout << std::setw(2) << int(c) << endl;
}
It actually was that the \ character must be escaped.
Related
I'm trying to create a program that displays output of a bmp file in the form of hexadecimal. So far I get the output, but I need it to be organized a certain way.
The way it needs to be organized is with the address of the bmp file to be on the left column and then 16 bytes of data in hex across each row in the order they appear in the file. While leaving an extra space between every 8 bytes. So far, I got the hexadecimal to show up, I just need help with organizing it.
What I have:
What I'm trying to make it look like:
Here is my code:
#include <iostream> // cout
#include <fstream> // ifstream
#include <iomanip> // setfill, setw
#include <stdlib.h>
using namespace std; // Use this to avoid repeated "std::cout", etc.
int main(int argc, char *argv[]) // argv[1] is the first command-line argument
[enter image description here][1]{
// Open the provided file for reading of binary data
ifstream is("C:\\Users\\Test\\Documents\\SmallTest.bmp", ifstream::binary);
if (is) // if file was opened correctly . . .
{
is.seekg(0, is.end); // Move to the end of the file
int length = is.tellg(); // Find the current position, which is file length
is.seekg(0, is.beg); // Move to the beginning of the file
char * buffer = new char[length]; // Explicit allocation of memory.
cout << "Reading " << length << " characters... ";
is.read(buffer, length); // read data as a block or group (not individually)
if (is)
cout << "all characters read successfully.\n";
else
cout << "error: only " << is.gcount() << " could be read.\n";
is.close();
// Now buffer contains the entire file. The buffer can be printed as if it
// is a _string_, but by definition that kind of print will stop at the first
// occurrence of a zero character, which is the string-ending mark.
cout << "buffer is:\n" << buffer << "\n"; // Print buffer
for (int i = 0; i < 100; i++) // upper range limit is typically length
{
cout << setfill('0') << setw(4) << hex << i << " ";
cout << setfill('0') << setw(2) << hex << (0xff & (int)buffer[i]) << " ";
}
delete[] buffer; // Explicit freeing or de-allocation of memory.
}
else // There was some error opening file. Show message.
{
cout << "\n\n\tUnable to open file " << argv[1] << "\n";
}
return 0;
}
You could do it something like this:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <vector>
#include <cctype>
std::ostream& fullLine(std::ostream& out, const std::vector<uint8_t>& v, size_t offset)
{
//save stream state so we can restore it after all the hex/setw/setfill nonsense.
std::ios oldState(0);
oldState.copyfmt(out);
out << std::hex << std::setfill('0') << std::setw(8) << offset << " ";
for (size_t i = 0; i < 16; ++i)
{
if (i == 8) out << " ";
out << std::hex << std::setfill('0') << std::setw(2) << static_cast<uint32_t>(v[i + offset]) << " ";
}
out << " ";
//restore stream state to print normal text
out.copyfmt(oldState);
for (size_t i = 0; i < 16; ++i)
{
out << (std::isprint(v[i + offset]) ? static_cast<char>(v[i + offset]) : '.');
}
out << "\n";
return out;
}
int main()
{
std::vector<uint8_t> data;
std::ifstream f("test.txt", std::ios::binary);
if (f)
{
f.seekg(0, f.end);
data.resize(static_cast<size_t>(f.tellg()));
f.seekg(0, f.beg);
f.read((char*)data.data(), data.size());
const size_t numFullLines = data.size() / 16;
const size_t lastLineLength = data.size() % 16;
for (size_t i = 0; i < numFullLines; ++i)
{
if (!fullLine(std::cout, data, i * 16))
{
std::cerr << "Error during output!\n";
return -1;
}
}
}
return 0;
}
There's probably a fancy way to do it, but I usually go for brute force when I'm looking for particular output using iostreams.
How to handle the partial last line is up to you. :)
Use the % operator to break the line after every 16th count:
cout << hex;
for(int i = 0; i < 100; i++)
{
if(i && (i % 16) == 0)
cout << "\n";
cout << setfill('0') << setw(2) << (buffer[i] & 0xFF) << " ";
}
I need it to be organized a certain way.
In another answer, I submitted this form of dumpByteHex()... perhaps it can help you achieve what you want. (see also https://stackoverflow.com/a/46083427/2785528)
// C++ support function
std::string dumpByteHex (char* startAddr, // reinterpret_cast explicitly
size_t len, // allows to char* from T*
std::string label = "",
int indent = 0)
{
std::stringstream ss;
if(len == 0) {
std::cerr << "\n dumpByteHex() err: data length is 0? " << std::endl << std::dec;
assert(len != 0);
}
// Output description
ss << label << std::flush;
unsigned char* kar = reinterpret_cast<unsigned char*>(startAddr); // signed to unsigned
std::string echo; // holds input chars until eoln
size_t indx;
size_t wSpaceAdded = false;
for (indx = 0; indx < len; indx++)
{
if((indx % 16) == 0)
{
if(indx != 0) // echo is empty the first time through for loop
{
ss << " " << echo << std::endl;
echo.erase();
}
// fields are typically < 8 bytes, so skip when small
if(len > 7) {
if (indent) { ss << std::setw(indent) << " "; }
ss << std::setfill('0') << std::setw(4) << std::hex
<< indx << " " << std::flush;
} // normally show index
}
// hex code
ss << " " << std::setfill('0') << std::setw(2) << std::hex
<< static_cast<int>(kar[indx]) << std::flush;
if((indx % 16) == 7) { ss << " "; wSpaceAdded = true; } // white space for readability
// defer the echo-of-input, capture to echo
if (std::isprint(kar[indx])) { echo += kar[indx]; }
else { echo += '.'; }
}
// finish last line when < 17 characters
if (((indx % 16) != 0) && wSpaceAdded) { ss << " "; indx++; } // when white space added
while ((indx % 16) != 0) { ss << " "; indx++; } // finish line
// the last echo
ss << " " << echo << '\n';
return ss.str();
} // void dumpByteHex()
Output format:
0000 11 22 33 44 55 66 00 00 00 00 77 88 99 aa ."3DUf....w...
Everthing goes well until the f << "string" << temp_int << endl; statement
get different results with different openmodes, either doesn't write at all or writes the first two chars of "NumberSaves"
unsigned int temp_int = 0;
fstream f("resources/saveData/Player/savelog.txt");
if (!f)
{
cout << "error accessing savelist" << endl;
}
else
{
string skip;
std::stringstream iss;
string line;
readVarFromFile(f, iss, skip, line, { &temp_int }); //check how many saves currently
temp_int += 1; //increment number of saves by 1
f.seekp(ios_base::beg);
cout << "Write position: " << f.tellp() << endl; //check stream is at beginning
f << "<NumberSaves>" << temp_int << endl; //truncate <NumberSaves> 'x' with <NumberSaves> 'x + 1'
cout << "Write position: " << f.tellp() << endl; //position suggests the entire string has been written, only two characters have been
if (!f)
{
cout << "ERROR";
}
f.seekp(ios_base::end);
f << currentPlayer->getName(); //append players name to end of file
}
desired output is as follows
NumberSaves 2
player
anotherplayer
current output
Nu
player
Use seekp properly like this:
os.seekp(0, std::ios_base::end); // means bring me to 0 from the end of file.
look at the example code in
http://en.cppreference.com/w/cpp/io/basic_ostream/seekp
std::ios_base::end is a direction not an absolute position. It is just an enum value. The value is probably 2 and that is why it brings you to position 2 inside the file.
I have a c++ program which writes changing numbers to screen, something in the vein of the following snippet:
stringstream ss, ssd; ss << 0; int decs=0; ssd << decs;
cout << "Number ";
for(int i=1;i<=1000;i++) {
cout << ss.str() << " Decades: " << decs; cout.flush();
int l=ss.str().length()+12+ssd.str().length();
for(int j=0;j<l;j++) cout << "\b";
this_thread::sleep_for (chrono::milliseconds(100));
ss.str(""); ss << i;
if(i%10==0) {
decs++; ssd.str(""); ssd << decs;
}
}
This works fine, but sometimes (not always) I would like to send the output to a file instead of the terminal, using e.g. ./prog > out.txt. Here the backspace character \b doesn't delete character but outputs some symbol (googling tells me this is not surprising).
One option would be to e.g. only output the data at the end of the calculation when printing to a file. But this would entail different code for terminal/file, switching with an input parameter for example. Is there a way I can do this without having separate code for terminal/file output?
I am using cygwin on Windows 7.
Try to write whole string every time and to write just '\r' without '\n'
stringstream ss, ssd; ss << 0; int decs=0; ssd << decs;
for(int i=1;i<=1000;i++) {
cout << "Number " << ss.str() << " Decades: " << decs; cout.flush();
//int l=ss.str().length()+12+ssd.str().length();
//for(int j=0;j<l;j++) cout << "\b";
cout << '\r';
this_thread::sleep_for (chrono::milliseconds(100));
ss.str(""); ss << i;
if(i%10==0) {
decs++; ssd.str(""); ssd << decs;
}
}
In this case you'll have the full output in the file.
A possible workaround may be to use std::cerr for intermediate result (and so for '\b'),
and std::cout for final result.
I am writing a simple program to convert grayscale binary (P5) to grayscale ascii (P2) but am having trouble reading in the binary and converting it to int.
#include <iostream>
#include <fstream>
#include <sstream>
using namespace::std;
int usage(char* arg) {
// exit program
cout << arg << ": Error" << endl;
return -1;
}
int main(int argc, char* argv[]) {
int rows, cols, size, greylevels;
string filetype;
// open stream in binary mode
ifstream istr(argv[1], ios::in | ios::binary);
if(istr.fail()) return usage(argv[1]);
// parse header
istr >> filetype >> rows >> cols >> greylevels;
size = rows * cols;
// check data
cout << "filetype: " << filetype << endl;
cout << "rows: " << rows << endl;
cout << "cols: " << cols << endl;
cout << "greylevels: " << greylevels << endl;
cout << "size: " << size << endl;
// parse data values
int* data = new int[size];
int fail_tracker = 0; // find which pixel failing on
for(int* ptr = data; ptr < data+size; ptr++) {
char t_ch;
// read in binary char
istr.read(&t_ch, sizeof(char));
// convert to integer
int t_data = static_cast<int>(t_ch);
// check if legal pixel
if(t_data < 0 || t_data > greylevels) {
cout << "Failed on pixel: " << fail_tracker << endl;
cout << "Pixel value: " << t_data << endl;
return usage(argv[1]);
}
// if passes add value to data array
*ptr = t_data;
fail_tracker++;
}
// close the stream
istr.close();
// write a new P2 binary ascii image
ofstream ostr("greyscale_ascii_version.pgm");
// write header
ostr << "P2 " << rows << cols << greylevels << endl;
// write data
int line_ctr = 0;
for(int* ptr = data; ptr < data+size; ptr++) {
// print pixel value
ostr << *ptr << " ";
// endl every ~20 pixels for some readability
if(++line_ctr % 20 == 0) ostr << endl;
}
ostr.close();
// clean up
delete [] data;
return 0;
}
sample image - Pulled this from an old post. Removed the comment within the image file as I am not worried about this functionality now.
When compiled with g++ I get output:
$> ./a.out a.pgm
filetype: P5
rows: 1024
cols: 768
greylevels: 255
size: 786432
Failed on pixel: 1
Pixel value: -110
a.pgm: Error
The image is a little duck and there's no way the pixel value can be -110...where am I going wrong?
Thanks.
greylevels: 255
-110 is 146 as an unsigned char. It appears you are on a platform where char is a signed type, try using unsigned char.
If you cannot have negative values , use an unsigned int * instead of int* for your pixel pointers. This way you won't have values read as signed values
You need a correction in output:
ostr << "P2\n" << rows << " "<< cols << " "<< greylevels << endl;
I need to read 16 bits from the binary file as std::string or char *. For example, a binary file contains 89 ab cd ef, and I want to be able to extract them as std::strings or char *. I have tried the following code:
ifstream *p = new ifstream();
char *buffer;
p->seekg(address, ios::beg);
buffer = new char[16];
memset(buffer, 0, 16);
p->read(buffer, 16);
When I try to std::cout the buffer, nothing appeared. How can I read these characters in the binary file?
EDIT: I was looking for the buffer to be a int type such as "0x89abcdef". Is it possible to achieve?
Something like:
#include <string>
#include <iostream>
#include <fstream>
#include <iomanip>
int main()
{
if (ifstream input("filename"))
{
std::string s(2 /*bytes*/, '\0' /*initial content - irrelevant*/);
if (input.read(&s[0], 2 /*bytes*/))
std::cout << "SUCCESS: [0] " << std::hex << (int)s[0] << " [1] " << (int)s[1] << '\n';
else
std::cerr << "Couldn't read from file\n";
}
else
std::cerr << "Couldn't open file\n";
}
You can't read a binary stream as though it were text.
You can, of course, read as binary (by using "file.read()" and "file.write()" methods on your stream object). Just like what you're doing now :)
You can also convert binary to text: "convert to hex text string" and "uuencode base 64" are two common ways to do this.
You'll want to read the bytes as numbers (of type long long probably).
Then you can print those using formatting specifiers like this:
#include <iostream>
#include <iomanip>
int main()
{
using namespace std;
int x = 2;
int y = 255;
cout << showbase // show the 0x prefix
<< internal // fill between the prefix and the number
<< setfill('0'); // fill with 0s
cout << hex << setw(4) << x << dec << " = " << setw(3) << x << endl;
cout << hex << setw(4) << y << dec << " = " << setw(3) << y << endl;
return 0;
}