c++ read binary data contained in an string variable - c++

I have a function that uses zlib to unzip files from a zip file to memory, and then stores the resulting file content in a string object. The problem is that the string is now composed of the binary representation of the files, and I don't know how to read that string in blocks like with
ifstream::read():
file.read((char*)result, sizeof(int));
It's necessary that I read the data in block by block, but I haven't found any process to do that from a string variable.
This is the function that returns the file content as a string (I can change the function if there's a better approach):
string externalresourcemanager::getFileInsideZip(string zipFile, string fileInZip) {
int err = UNZ_OK; // error status
uInt size_buf = WRITEBUFFERSIZE; // byte size of buffer to store raw csv data
void* buf; // the buffer
string sout; // output strings
char filename_inzip[256]; // for unzGetCurrentFileInfo
unz_file_info file_info; // for unzGetCurrentFileInfo
unzFile uf = unzOpen(zipFile.c_str()); // open zipfile stream
if (uf==NULL) {
cerr << "Cannot open " << zipFile << endl;
return sout;
} // file is open
if ( unzLocateFile(uf,fileInZip.c_str(),1) ) { // try to locate file inside zip
// second argument of unzLocateFile: 1 = case sensitive, 0 = case-insensitive
cerr << "File " << fileInZip << " not found in " << zipFile << endl;
return sout;
} // file inside zip found
if (unzGetCurrentFileInfo(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0)) {
cerr << "Error " << err << " with zipfile " << zipFile << " in unzGetCurrentFileInfo." << endl;
return sout;
} // obtained the necessary details about file inside zip
buf = (void*)malloc(size_buf); // setup buffer
if (buf==NULL) {
cerr << "Error allocating memory for read buffer" << endl;
return sout;
} // buffer ready
err = unzOpenCurrentFilePassword(uf,NULL); // Open the file inside the zip (password = NULL)
if (err!=UNZ_OK) {
cerr << "Error " << err << " with zipfile " << zipFile << " in unzOpenCurrentFilePassword." << endl;
return sout;
} // file inside the zip is open
// Copy contents of the file inside the zip to the buffer
cout << "Extracting: " << filename_inzip << " from " << zipFile << endl;
do {
err = unzReadCurrentFile(uf,buf,size_buf);
if (err<0) {
cerr << "Error " << err << " with zipfile " << zipFile << " in unzReadCurrentFile" << endl;
sout = ""; // empty output string
break;
}
// copy the buffer to a string
if (err>0) for (int i = 0; i < (int) err; i++) sout.push_back( *(((char*)buf)+i) );
} while (err>0);
err = unzCloseCurrentFile (uf); // close the zipfile
if (err!=UNZ_OK) {
cerr << "Error " << err << " with zipfile " << zipFile << " in unzCloseCurrentFile" << endl;
sout = ""; // empty output string
}
free(buf); // free up buffer memory
return sout;
}
Thank you!
EDIT:
im trying your solution (john) but i get an empty result. Here is an example code to explain the problem:
int store = 1024;
string result = "";
ofstream file("test.txt", std::ios::binary);
//save a few data
file.write(reinterpret_cast<const char*>(&store), sizeof(int));
file.write(reinterpret_cast<const char*>(&store), sizeof(int));
file.close();
//remember that i receive the "string binary data" from the getFileInsideZip() function (here i simulating the problem and store the binary data in a string only for explanation purpose)
ifstream newFile("test.txt", std::ios::binary);
newFile.seekg(0, std::ios::end);
int length = newFile.tellg();
newFile.seekg(0, std::ios::beg);
char* begin = &*result.begin();
//here i have a binary file in a string variable
newFile.read(begin, length);
newFile.close();
cout << "result:" << result << "\n";
//now im trying to get the first int from this binary data
int stored = 0;
std::istringstream bin(result);
bin.read((char*)&stored, sizeof(int));
cout << "stored: " << stored << "\n";
//but the output is:
//result -> empty (initial value)
//stored: 0 -> (initial value)
any suggestion?

Related

fstream stops to read at substitute control character

I'm writing a simple encryption program in C++ to encrypt a text-based file.
It's using a simple XOR cipher algorithm, but this produces ASCII control characters in the output file. When I try to read from the newly encrypted file with std::ifstream, it stumbles upon character #26, it stops and becomes unable to read the rest of the file.
Example if I try to encrypt this text:
This is just a simple sample
text with two rows and one sentence.
It turns it to this
/[[[[[
[[[ [[[U
When I try to read that file in my program, it can't read past the character at position 15, so I get a half encrypted file.
How can I fix this?
Here's the code:
#include <iostream>
#include <Windows.h>
#include <string>
#include <fstream>
void Encrypt(char encryptionKey, std::string filename)
{
std::ifstream sourceFile(filename);
std::ofstream outputFile(filename.substr(0, filename.find_last_of("\\")) + "\\Encrypted" + filename.substr(filename.find_last_of("\\") + 1), std::ofstream::out | std::ofstream::trunc);
std::string sourceLine;
std::string outputLine;
long numLines = 0;
if (sourceFile.is_open())
{
std::cout << "Opening file: " + filename + " for encryption" << std::endl;
while (sourceFile.good()) // This iterates over the whole file, once for each line
{
sourceLine = ""; //Clearing the line for each new line
outputLine = ""; //Clearing the line for each new line
std::getline(sourceFile, sourceLine);
for (int i = 0; i < sourceLine.length(); i++) // Looping through all characters in each line
{
char focusByte = sourceLine[i] ^ encryptionKey;
std::cout << " focusByte: " << focusByte << std::endl;
outputLine.push_back(focusByte);
//std::cout << sourceLine << std::flush;
}
numLines++;
outputFile << outputLine << std::endl;
}
}
sourceFile.close();
outputFile.close();
}
void Decrypt(unsigned int encryptionKey, std::string filename)
{
std::ifstream sourceFile(filename);
std::ofstream outputFile(filename.substr(0, filename.find_last_of("\\")) + "\\Decrypted" + filename.substr(filename.find_last_of("\\") + 1), std::ofstream::out | std::ofstream::trunc);
std::string sourceLine;
std::string outputLine;
long numLines = 0;
if (sourceFile.is_open())
{
std::cout << "Opening file: " + filename + " for decryption" << std::endl;
while (sourceFile.good()) // This iterates over the whole file, once for each line
{
if (sourceFile.fail() == true)
std::cout << "eof" << std::endl;
sourceLine = ""; //Clearing the line for each new line
outputLine = ""; //Clearing the line for each new line
std::getline(sourceFile, sourceLine);
for (int i = 0; i < sourceLine.length(); i++) // Looping through all characters in each line
{
char focusByte = sourceLine[i] ^ encryptionKey;
std::cout << " focusByte: " << focusByte << std::endl;
outputLine.push_back(focusByte);
}
numLines++;
outputFile << outputLine << std::endl;
}
}
sourceFile.close();
outputFile.close();
}
int main(int argument_count,
char * argument_list[])
{
system("color a");
std::string filename;
if (argument_count < 2)
{
std::cout << "You didn't supply a filename" << std::endl;
}
else
{
filename = argument_list[1];
std::cout << "Target file: " << filename << std::endl;
std::cout << "Press e to encrypt the selected file, Press d to decrypt the file > " << std::flush;
char choice;
while (true)
{
std::cin >> choice;
if (choice == 'e')
{
Encrypt(123, filename);
break;
}
else if (choice == 'd')
{
Decrypt(123, filename);
break;
}
else
{
std::cout << "please choose option e or d for encryption respectivly decryption" << std::endl;
}
}
}
std::cout << "\nPaused, press Enter to continue > " << std::flush;
system("Pause");
return EXIT_SUCCESS;
}
In Decrypt(), after the first call to std::getline(), sourceFile.good() is false and sourceFile.fail() is true, which is why you stop reading subsequent lines from the encrypted file.
The reason is because the encrypted file has an encoded 0x1A byte in it, and depending on your platform and STL implementation, that character likely gets interpreted as an EOF condition, thus enabling the std::ifstream's eofbit state, terminating further reading.
In my compiler's STL implementation on Windows, when std::ifstream reads from a file, it ultimately calls a function named _Fgetc():
template<> inline bool _Fgetc(char& _Byte, _Filet *_File)
{ // get a char element from a C stream
int _Meta;
if ((_Meta = fgetc(_File)) == EOF) // <-- here
return (false);
else
{ // got one, convert to char
_Byte = (char)_Meta;
return (true);
}
}
When it tries to read an 0x1A character, fgetc() returns EOF, and when _Fgetc() returns false, std::getline() sets the eofbit on the std::ifstream and exits.
Check your compiler's STL for similar behavior.
This behavior is because you are opening the encrypted file in text mode. You need to open the encrypted file in binary mode instead:
std::ifstream sourceFile(..., std::ifstream::binary);
Also, you should enable binary mode on the encrypted file in Encrypt() as well:
std::ofstream outputFile(..., std::ofstream::binary | std::ofstream::trunc);
Try something more like this instead:
#include <Windows.h>
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
void Encrypt(char encryptionKey, const std::string &filename)
{
std::string::size_type pos = filename.find_last_of("\\");
std::string out_filename = filename.substr(0, pos+1) + "Encrypted" + filename.substr(pos + 1);
std::ifstream sourceFile(filename.c_str());
std::ofstream outputFile(out_filename.c_str(), std::ofstream::binary | std::ofstream::trunc);
if (sourceFile.is_open())
{
std::cout << "Opened file: " + filename + " for encryption" << std::endl;
std::string line;
long numLines = 0;
while (std::getline(sourceFile, line)) // This iterates over the whole file, once for each line
{
for (std::string::size_type i = 0; i < line.length(); ++i) // Looping through all characters in each line
{
char focusByte = line[i] ^ encryptionKey;
std::cout << " focusByte: " << focusByte << std::endl;
line[i] = focusByte;
//std::cout << line << std::flush;
}
outputFile << line << std::endl;
++numLines;
}
}
}
void Decrypt(char encryptionKey, const std::string &filename)
{
std::string::size_type pos = filename.find_last_of("\\");
std::string out_filename = filename.substr(0, pos+1) + "Decrypted" + filename.substr(pos + 1);
std::ifstream sourceFile(filename.c_str(), std::ifstream::binary);
std::ofstream outputFile(out_filename.c_str(), std::ofstream::trunc);
if (sourceFile.is_open())
{
std::cout << "Opened file: " + filename + " for decryption" << std::endl;
std::string line;
long numLines = 0;
while (std::getline(sourceFile, line)) // This iterates over the whole file, once for each line
{
for (std::string::size_type i = 0; i < line.length(); ++i) // Looping through all characters in each line
{
char focusByte = line[i] ^ encryptionKey;
std::cout << " focusByte: " << focusByte << std::endl;
line[i] = focusByte;
}
outputFile << line << std::endl;
++numLines;
}
std::cout << "eof" << std::endl;
}
}
int main(int argument_count, char* argument_list[])
{
std::system("color a");
std::string filename;
if (argument_count < 2)
{
std::cout << "Enter a file to process: " << std::flush;
std::getline(std::cin, filename);
}
else
{
filename = argument_list[1];
}
if (filename.empty())
{
std::cout << "You didn't supply a filename" << std::endl;
return EXIT_FAILURE;
}
std::cout << "Target file: " << filename << std::endl;
std::cout << "Press e to encrypt the file" << std::endl;
std::cout << "Press d to decrypt the file" << std::endl;
char choice;
while (true)
{
std::cout << "> " << std::flush;
std::cin >> choice;
if (choice == 'e')
{
Encrypt(123, filename);
break;
}
else if (choice == 'd')
{
Decrypt(123, filename);
break;
}
else
{
std::cout << "please choose option e or d for encryption or decryption, respectively" << std::endl;
}
}
std::cout << std::endl << "Paused, press Enter to continue" << std::flush;
std::system("pause");
return EXIT_SUCCESS;
}
That being said, keep in mind that when using XOR, some of the encrypted characters might end up being \r (0x0D) or \n (0x0A), which will interfere with std::getline() when decrypting the file later on, producing a decrypted output that does not match the original text input.
Since you should be treating the encrypted file as binary, you should not be reading/writing the file as text at all. Choose a different format for your encrypted output that does not rely on line-break semantics in text vs binary mode.
For example:
#include <Windows.h>
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
void Encrypt(char encryptionKey, const std::string &filename)
{
std::string::size_type pos = filename.find_last_of("\\");
std::string out_filename = filename.substr(0, pos+1) + "Encrypted" + filename.substr(pos + 1);
std::ifstream sourceFile(filename.c_str());
std::ofstream outputFile(out_filename.c_str(), std::ofstream::binary | std::ofstream::trunc);
if (sourceFile.is_open())
{
std::cout << "Opened file: " + filename + " for encryption" << std::endl;
std::string line;
std::string::size_type lineLen;
long numLines = 0;
while (std::getline(sourceFile, line)) // This iterates over the whole file, once for each line
{
lineLen = line.length();
for (std::string::size_type i = 0; i < lineLen; ++i) // Looping through all characters in each line
{
char focusByte = line[i] ^ encryptionKey;
std::cout << " focusByte: " << focusByte << std::endl;
line[i] = focusByte;
//std::cout << line << std::flush;
}
outputFile.write((char*)&lineLen, sizeof(lineLen));
outputFile.write(line.c_str(), lineLen);
++numLines;
}
}
}
void Decrypt(char encryptionKey, const std::string &filename)
{
std::string::size_type pos = filename.find_last_of("\\");
std::string out_filename = filename.substr(0, pos+1) + "Decrypted" + filename.substr(pos + 1);
std::ifstream sourceFile(filename.c_str(), std::ifstream::binary);
std::ofstream outputFile(out_filename.c_str(), std::ofstream::trunc);
if (sourceFile.is_open())
{
std::cout << "Opened file: " + filename + " for decryption" << std::endl;
std::string line;
std::string::size_type lineLen;
long numLines = 0;
while (sourceFile.read((char*)&lineLen, sizeof(lineLen))) // This iterates over the whole file, once for each line
{
line.resize(lineLen);
if (!sourceFile.read(&line[0], lineLen))
break;
for (std::string::size_type i = 0; i < lineLen; ++i) // Looping through all characters in each line
{
char focusByte = line[i] ^ encryptionKey;
std::cout << " focusByte: " << focusByte << std::endl;
line[i] = focusByte;
}
outputFile << line << std::endl;
++numLines;
}
std::cout << "eof" << std::endl;
}
}
int main(int argument_count, char* argument_list[])
{
std::system("color a");
std::string filename;
if (argument_count < 2)
{
std::cout << "Enter a file to process: " << std::flush;
std::getline(std::cin, filename);
}
else
{
filename = argument_list[1];
}
if (filename.empty())
{
std::cout << "You didn't supply a filename" << std::endl;
return EXIT_FAILURE;
}
std::cout << "Target file: " << filename << std::endl;
std::cout << "Press e to encrypt the file" << std::endl;
std::cout << "Press d to decrypt the file" << std::endl;
char choice;
while (true)
{
std::cout << "> " << std::flush;
std::cin >> choice;
if (choice == 'e')
{
Encrypt(123, filename);
break;
}
else if (choice == 'd')
{
Decrypt(123, filename);
break;
}
else
{
std::cout << "please choose option e or d for encryption or decryption, respectively" << std::endl;
}
}
std::cout << std::endl << "Paused, press Enter to continue" << std::flush;
std::system("pause");
return EXIT_SUCCESS;
}
ASCII value 26 is EOF on some operating systems.
You should probably treat your encrypted file as a byte stream rather than a text file for reading and writing. That means either using read() and write() functions of the IOStream or at the very least opening the files in binary mode.
If you're just enciphering your text instead of encrypting, maybe choose a different cipher (eg. ROT13) that is closed on the set of printable ASCII or UTF-8 characters.
I compiled your code in Linux (minus all the Windows stuff)...
I get this when encrypting your sentence with your code:
/[[[[[
[[[ [[[U
It also decrypts back to the original sentence. Without the goofy characters, it is the same as your output so your actual issue seems related to the encoding of the file and the program you are using to view the results. Stephan is correct in saying you should be reading/writing bytes instead of text. This can cause all sorts of issues with the characters you create. For example, line feeds and carriage returns since you are using getline().
Edit: Strange. After editing this answer, all the odd characters disappeared. Here is a screenshot:

Segfault after fread() call

I have the following code:
char*
Sender::PrepareData(char* filename, unsigned long long int bytesToTransfer)
{
FILE* dataFile = fopen(filename, "rb");
if (dataFile==NULL) {fputs ("File error",stderr); exit (1);}
cout << "File Open: " << filename << endl;
char* theData;
size_t bytesRead = fread(&theData, 1, bytesToTransfer, dataFile);
if (bytesRead != bytesToTransfer) {fputs ("Reading error",stderr); exit (3);}
cout << "Data Read -- Num Bytes: " << bytesRead << endl;
cout << "Data to Send: " << *theData << endl;
return theData;
}
When this method gets hit, my output is:
File Open: t.bin
Data Read -- Num Bytes: 10
Segmentation fault (core dumped)
My t.bin file contains the following:
This is a test.
98172398172837129837
alsjdf89u32ijofiou2
TEST TEST...
!!## TESTING TEST!! ###(DLKAJ)
When I run through gdb, the segfault output is:
File Open: t.bin Data Read -- Num Bytes: 10
Program received signal SIGSEGV, Segmentation fault. 0x00000000004015e2 in Sender::PrepareData (this=0x603010, filename=0x7fffffffe363 "t.bin", bytesToTransfer=10)
at sender.cpp:98 98 cout << "Data to Send: " << *theData << endl;
Can someone tell me what I'm doing wrong?
You need a buffer, theData is just a pointer.
Something like
char theData[1000];
size_t bytesRead = fread(theData, 1, bytesToTransfer, dataFile);
might work depending on the maximum value of bytesToTransfer
If you are sure you are reading a string you might also need to terminate theData before writing to cout,
theData[bytesRead] = '\0';
You'll need to allocate your buffer on the heap if you want to return it.
It'd be a lot easier to do something like
std::vector<char>
PrepareData(char* filename, unsigned long long int bytesToTransfer)
{
std::ifstream file(filename, file.binary);
if (!file) {
std::cerr << "File error";
exit(1);
}
std::cout << "File Open: " << filename << '\n';
std::vector<char> data(bytesToTransfer + 1);
file.read(data.data(), bytesToTransfer);
data.back() = '\0';
if (!file) {
std::cerr << "Reading error";
exit(3);
}
std::cout << "Data Read -- Num Bytes: " << bytesToTransfer << '\n';
std::cout << "Data to Send: " << data.data() << '\n';
return data;
}
Then again if all you are doing is reading chars from a file you should probably consider using strings.

fseek not reading all the data?

I am making a c++ installer and I have appended both the file to extract and an 8 byte filesize of the file to extract within the program, to the executable. My program exits on a file read error, whats going wrong? To note I don't have any knowledge about c file managing, apart from what I've learned today. I am writing the file test_before.tar.gz, which is 161 bytes, the executable is 12335 bytes long and the filesize file is 8 bytes long, containing 0000161. What's wrong? Ask for more info if needed.
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
int main(int argc, char* argv[])
{
cout << "Opening the executable as read-only!" << endl;
FILE *exeFile; // The executable file pointer
FILE *outFile; // The file to write pointer
// Check whether a file name was supplied
if(argc < 2)
{
cout << "Please enter the file to write!" << endl;
return 1;
}
// Open the executable as read-only
if((exeFile = fopen(argv[0], "rb")) == 0)
{
cout << "Error opening the executable!" << endl;
return 1;
}
cout << "Getting the executables size!" << endl;
// Get the files size
fseek(exeFile, 0, SEEK_END);
int size = ftell(exeFile);
cout << "Reading ofset!" << endl;
// Read the ofset bytes contained in the last 7-bytes
char filesize_char[9];
fseek(exeFile, -8, SEEK_END);
fgets(filesize_char, 9, exeFile);
// Convert
int filesize = atoi(filesize_char);
int ofset = (size - filesize) - 8;
cout << "The ofset size is " << ofset << " bytes!" << endl;
cout << "The file size is " << filesize << " bytes!" << endl;
cout << "Reading the file to extract!" << endl;
// Create the variable to contain the file and goto the ofset
char* contents = new char[filesize + 1];
fseek(exeFile, ofset, SEEK_SET);
// Read the file to extract
if(fread(contents, sizeof(char), filesize + 1, exeFile) != sizeof(contents))
{
// Error has occured
if(feof(exeFile)) {
cout << "Premature end of file!" << endl;
// Delete variables so they dont "leak"
fclose(exeFile);
delete[] contents;
return 1;
} else {
cout << "File read error!" << endl;
// Delete variables so they dont "leak"
fclose(exeFile);
delete[] contents;
return 1;
}
}
cout << "Writing the file to " << argv[1] << "!" << endl;
// Write the file to extract
if((outFile = fopen(argv[1], "wb")) == 0)
{
cout << "Error opening the file to write!" << endl;
// Delete variables so they dont "leak"
fclose(exeFile);
fclose(outFile);
delete[] contents;
return 1;
}
fwrite(contents, 1, sizeof(contents), outFile);
//delete variables
fclose(exeFile);
fclose(outFile);
delete[] contents;
return 0;
}
You don't need the while loop at all. After all, you already allocated the memory that would contain all your data. Move file pointer to the start of data fseek(exeFile, ofset, SEEK_SET), then use fread to read it as whole, and then use fwrite to write it into outFile.
You should open your exeFile and outFile with "rb" and "wb" flags otherwise your code would work reliably only with text data.

After dragging a file on exe, ifstream fails to open file

I have have the following problem:
When I drag and drop a file to my tool (exe) when ifstream fails to open the file.
If I give it manually though the console it works!
I don't get where the diffenence is, because I am cutting the path and passing just the filename.
Have a look at the code:
int main(int argc, char* argv[]) {
if (argc < 2) {
cout
<< "ERROR: Wrong amount of arguments! Give at least one argument ...\n"
<< endl;
cout << "\n" << "Programm finished...\n\n" << endl;
cin.ignore();
exit(1);
return 0;
}
vector<string> files;
for (int g = 1; g < argc; g++) {
string s = argv[g];
cout<<"parameter at: " << g << " = " << argv[g] << "\n" << endl;
string filename = "";
int pos = s.find_last_of("\\", s.size());
if (pos != -1) {
filename.append(s.substr(pos + 1));
// cout<<" cutted path: " << s.substr(0,s.size()-filename.size()) << endl;
// cout << "argv[1] " << argv[1] << endl;
cout << "\n filename: " << filename << "\t pos: " << pos << endl;
files.push_back(filename);
}
files.push_back(s);
}
for (unsigned int k = 0; k < files.size(); k++)
{
cout << "files.at( " << k << " ): " << files.at(k).c_str() << endl;
Converter a(files.at(k).c_str());
a.getCommandsFromCSV();
a.saveConvertedFile();
}
cout << "\n" << "Programm finished...\n\n" << endl;
cin.ignore();
return 0;
}
It fails already on the constructor:
Converter::Converter(const char* file) {
filename = file;
myfile.open(filename.c_str(), ios_base::in);
cout << (myfile ? "open successful on constructor " : "some error on constructor");
cin.ignore();
trace_raw = "";
}
You have any idea why?
UPDATE:
The file as parameter works now. The solution was to leave the full path.
Anyway I have the same error on a hard coded file. I thought it may be the same that's why I added .\ at the beginning of the file name... without success.
The code:
void GenericCommandConverter::getATCommandsFromCSV() {
cout << "\t| +++++++++++getATCommandsFromCSV() started+++++++++++++ |"
<< endl;
/*
* CSV file name is hardcoded
*/
string filename_csv = ".\\test.csv";
string commands = "";
int pos_start = 0;
int pos_end = 0; // "|"
int substrLength = 0;
int separator_count = 0;
char c;
vector<string> lines;
vector<string> commandList;
vector<vector<string> > linesSeparated;
ifstream csvFile;
csvFile.open(filename_csv.c_str(), ios_base::in);
cout << (myfile ? "open successful on getATCommandsFromCSV " : "some error on getATCommandsFromCSV ");
cin.ignore();
...
UPDATE2:
The solution was: on dropping a file to the exe, the "root" folder changes to the one where the dropped file comes from. Giving the hardcoded file the path from the *.exe solved it!
I am guessing your current directory is wrong. Don't cut the path off. Anyway you should do error checking / debugging to see why it couldn't open the file. Diligent debugging is essential for solving problems without having to make blind guesses.

Why does read of /proc/cpuinfo seem to not advance file position?

I have the following code which ends up forever reading '/proc/cpuinfo' as it keeps getting the same result every read. Why doesn't the file pointer get advanced and reach eof ever? Seems this special file has different semantics.
const int bufSize = 4096;
char buf[bufSize + 1];
const string cpuInfo = "/proc/cpuinfo";
int cpuFD = ::open(cpuInfo.c_str(), O_RDONLY);
if (cpuFD == -1) {
logOutputStream << "Failed attempt to open '" << cpuInfo << "': "
<< strerror(errno) << endl;
} else {
assert(bufSize <= SSIZE_MAX);
logOutputStream << "Contents of: '" << cpuInfo << "'.\n";
for (int nRead = ::read(cpuFD, buf, bufSize); nRead != 0;) {
if (nRead == -1) {
logOutputStream << "Failed attempt to read '" << cpuInfo << "': "
<< strerror(errno) << endl;
break;
} else {
buf[nRead] = '\0';
logOutputStream << buf;
}
}
if (::close(cpuFD) == -1) {
logOutputStream << "Failed attempt to close '" << cpuInfo << "': "
<< strerror(errno) << endl;
}
}
for (int nRead = ::read(cpuFD, buf, bufSize); nRead != 0;) {
is wrong. You're using read as an initializer, so read is only being called once, not once per loop. After that, you're just looping forever printing it out (because nothing is changing nRead).
What happens if you try dumping the content into an actual text file with something like
cat /proc/cpuinfo > cpuinfo.txt
and then reading that file ?