Extracting bytes from byte stream - c++

I receive a binary file via POST in a C++ CGI script and I'm using the Cgicc library to get its contents like so:
std::ofstream myfile;
myfile.open ("file.out", std::ios::in | std::ios::binary);
try
{
cgicc::Cgicc cgi;
cgicc::const_file_iterator file = cgi.getFile("bitmap");
if(file != cgi.getFiles().end())
{
file->writeToStream(myfile);
}
}
catch(std::exception &exception)
{
std::cout << exception.what();
}
The result is a binary file containing the bytes.
Now, because each byte should represent one pixel of an 8 bit bitmap file, I want to construct the entire bitmap file. In order to achieve this, I think I can use the easyBMP library, but since I need to create the image pixel by pixel, I need to somehow iterate over the received bytes. Does anyone know how this can be achieved? Can I get an iterator somehow to an std::ostream / std::ostrstream / std::ostringstream?
std::ostringstream stream;
file->writeToStream(stream);
//foreach byte in stream do { ... }

If you use std::ostringstream you can get std::string from it, using std::ostringstream::str function http://cplusplus.com/reference/iostream/ostringstream/str/ . Also, you can open your file and read it...

Related

Reads data correctly but writes incorrectly

I am trying to read specific binary data (2 Bytes) of a file and this mission works well, the problem when rewriting that (2 Bytes) again in the same place. Unfortunately, it changes the entire file data to zeros.
Look at the following two screenshots:
Data before writing:
Data after writing:
The code:
bool myClass::countChanger() {
std::ifstream sggFileObj_r(this->sggFilePath, std::ios::binary);
if (!sggFileObj_r.is_open()) {
std::cerr << strerror(errno) << std::endl;
return false;
}
// Buffer variable
unsigned short count;
// Move the file pointer to offset 4
sggFileObj_r.seekg(4);
// Reading data
sggFileObj_r.read((char*)&count, sizeof(unsigned short));
sggFileObj_r.close();
//// ---------------------- ////
std::ofstream sggFileObj_w(this->sggFilePath, std::ios::binary | std::ios::app);
// Increase the buffer variable by one
count += 1;
// Move the file pointer again to offset 4
sggFileObj_w.seekp(4);
// Rewriting data again to the file after modification
sggFileObj_w.write((char*)&count, sizeof(unsigned short));
sggFileObj_w.close();
return true;
}
Why did that happen and how to resolve?
UPDATE:
I have appended std::ios::app to file mode, and zeros problem solved but the specific data that I want to update is not updated.
Using
std::ofstream sggFileObj_w(this->sggFilePath, std::ios::binary)
will wipe out the data in the file since that is what ofstream does by default. You can use
std::ofstream sggFileObj_w(this->sggFilePath, std::ios::binary | std::ios::app);
to stop the data from being overridden but the issue with this is that file stream starts at the end of the file and pretends like the rest of the file doesn't exist, so you can seek back to the beggining and overwrite its contents.
What you can do instead is use a fstream like
std::fstream sggFileObj_w(this->sggFilePath, std::ios::binary | std::ios::out | std::ios::in);
To open the file in binary mode from the beginning without losing any contents. Then you can seek to where you want to write into the file.

Binary open and copy image file c++

I want to copy one image file to another new file. This is my method to do this:
std::ofstream myOutpue;
std::ifstream mySource;
//int i = 0;
mySource.open(ofn.lpstrFile, std::ios::binary);
myOutpue.open("im4.jpg", std::ios::binary);
char buffer;
char bufferToSave[100];
if (mySource.is_open())
{
//client->sendFilePacket(FileStates::START_SAVE, buffer, false,i);
i++;
while (!mySource.eof())
{
mySource >> std::noskipws >> buffer;
myOutpue << buffer;
//client->sendFilePacket(FileStates::CONTINUE_SAVE, buffer, false,i);
i++;
}
}
i++;
//client->sendFilePacket(FileStates::END_SAVE, buffer, true,i);
mySource.close();
//myOutpue.close();
This method work correctly, but my problem is that i want to copy char/bit's and send it to another client. When i doing this by each char , that not work correctly so i want to make a bigger buffor(for example char t[512]) or something like that and copy them to new file.
I try to doing this like that:
std::ofstream myOutpue;
std::ifstream mySource;
mySource.open(ofn.lpstrFile, std::ios::binary);
myOutpue.open("im4.jpg", std::ios::binary);
char buffer;
char bufferToSave[100];
if (mySource.is_open())
{
//client->sendFilePacket(FileStates::START_SAVE, buffer, false,i);
i++;
while (!mySource.eof())
{
if (i == 100)
{
for (int i = 0; i < 100; i++)myOutpue << bufferToSave[i];
i = 0;
}
mySource >> std::noskipws >> buffer;
bufferToSave[i] = buffer;
//myOutpue << buffer;
//client->sendFilePacket(FileStates::CONTINUE_SAVE, buffer, false,i);
i++;
}
}
i++;
//client->sendFilePacket(FileStates::END_SAVE, buffer, true,i);
mySource.close();
myOutpue.close();
But i get image that i can't open.
So my question is how to read file to get more bits from it and that create me the same image as original.
You have an error in your original file copy algorithm in that you should never loop using eof() as the end flag.
See: Why is iostream::eof inside a loop condition considered wrong?
Copying files can be a simple as this:
std::ofstream("output.jpg", std::ios::binary) << std::ifstream("input.jpg", std::ios::binary).rdbuf();
It uses a special overload of the output operator when passing an std::istream buffer (using rdbuf()). It copies the whole stream.
When reading a whole buffer you should use std::istream::read:
std::ifstream ifs("input.jpg", std::ios::binary)
char buffer[1025]; // create a buffer
// keep going as long as the reading succeeds
while(ifs.read(buffer, sizeof(buffer)))
{
// ifs.gcount() is the number of chars read successfully
client->sendFilePacket(buffer, ifs.gcount()); // send all bytes
}
I know it's been a long time, but reading these topic I found the solution:
std::ifstream ifs(ofn.lpstrFile, std::ios::binary);
std::ofstream myOutpue;
char buffer[1024]; // create a buffer
myOutpue.open("output.jpg", std::ios::binary);
//client->sendFilePacket(FileStates::START_SAVE, buffer, false, i);
while (ifs.read(buffer, sizeof(buffer)))
{
myOutpue.write(buffer, ifs.gcount());
}
//
myOutpue.write(buffer, ifs.gcount());
myOutpue.close();
Note: My answer is similar to #dawcza94, but to avoid black screen, after the loop you have to save the rest of the reading, because in the loop you save only what fits in the buffer, and the rest you ignore. Sometimes it happens that the rest can be a few characters long, and it looks like the images are the same size, but they aren't.
Note2: I posted here to help those who are still in trouble as I was!!
C++ FAQ:
You probably want to use iostream’s read() and write() methods instead of its >> and << operators. read() and write() are better for binary mode; >> and << are better for text mode.
You can specify how much you want to read. With gcount you can ask, how much characters are read successfully. Same goes for write.
I try with this code:
std::ifstream ifs(ofn.lpstrFile, std::ios::binary);
std::ofstream myOutpue;
char buffer[1024]; // create a buffer
myOutpue.open("output.jpg", std::ios::binary);
//client->sendFilePacket(FileStates::START_SAVE, buffer, false, i);
while (ifs.read(buffer, sizeof(buffer)))
{
//client->sendFilePacket(FileStates::CONTINUE_SAVE, buffer, false, ifs.gcount());
myOutpue.write(buffer, ifs.gcount());
}
//client->sendFilePacket(FileStates::END_SAVE, buffer, true, i);
myOutpue.close();
But when i doing this like that, in my copy of image i got only half of original image and half of black screen( number of kb is the same like in original file), so i don't know what's a problem with that ?
Instead of using "manual" copy, try using ifstream::read method

saving file with ofstream

I'm new to C++, I have an image named "test.jpg", i convert it to base64 and decode it again like this:
std::ifstream inputFile;
inputFile.open("test.jpg",std::ios::binary);
std::filebuf* pbuf = inputFile.rdbuf();
inputFile.seekg (0, ios::end);
int length = inputFile.tellg();
// allocate memory to contain file data
char* buffer=new char[length];
// get file data
pbuf->sgetn (buffer,length);
inputFile.close();
CBase64 base64;
string encodedData = base64.base64_encode((unsigned char*)buffer,length);
delete[] buffer;
string decodedData = base64.base64_decode(encodedData);
ofstream outPutFile;
outPutFile.open("test2.jpg",ios::binary | ios::out);
outPutFile.write(decodedData.c_str(), decodedData.length());
outPutFile.close();
the "test2.jpg" has exact same size as "test.jpg"(the original file) but, i can't open it.
i couldn't find what is the problem.
i got it working. i just replaced:
outPutFile.open("test2.jpg",ios::binary | ios::out);
with
outPutFile.open("test2.jpg", ios_base::out | ios_base::binary);
std::string path = "file.txt";
std::string cfgString = "data";
std::ofstream output(path.c_str(), ios_base::out | std::ios::binary);
if (output.is_open()) {
output.write(cfgString.data(), cfgString.length());
}
output.close();
Apparently, there is no superficial problem with your file writing logic even though there are some irregularities. The biggest problem is in your main logic.
The program seems to be simple program of copying a file. What you are doing is reading a file, converting its data to base64 string and then again decoding the data to std::string. Now one small problem. Conversion of base64 string cannot be successfully done into a null terminated ANSI string for obvious reasons that any 0 in decoded binary data will terminate the string prematurely. Secondly you are opening a file in binary mode to write but trying to write std::string in the file. But that doesn't matter as you data has already been corrupted in your previous operation.
To solve this, you can simply use file copying example as this or make sure you write only binary data with care to your output file which means read in binary from input file and write to output file the same buffer. No base64 encoding decoding is required.
it looks like you forgot to write
inputFile.seekg (0, ios::beg);
after getting file length. it means you try to read from the end of the file instead of its beginning.

How to dump (write) IStream's content into file (Image)

I have an IStream which I know it contains a PNG file, but I can't write its content into a file like normal I/O stream, I don't know if I am doing something wrong or I should do a different thing for writing IStream into file.
IStream *imageStream;
std::wstring imageName;
packager.ReadPackage(imageStream, &imageName);
std::ofstream test("mypic.png");
test<< imageStream;
Based on the IStream reference you gave here is some untested code that should do roughly what you want:
void output_image(IStream* imageStream, const std::string& file_name)
{
std::ofstream ofs(file_name, std::ios::binary); // binary mode!!
char buffer[1024]; // temporary transfer buffer
ULONG pcbRead; // number of bytes actually read
// keep going as long as read was successful and we have data to write
while(imageStream->Read(buffer, sizeof(buffer), &pcbRead) == S_OK && pcbRead > 0)
{
ofs.write(buffer, pcbRead);
}
ofs.close();
}

Read/write operation works neither good nor bad

I am programming a face detection algorithm. In my code I'm parsing an XML file (in a recursion way, very inefficient takes my about 4 minutes to parse the whole XML file). I'd like to save the XML content using Iosteam binary to a file. I'm using a struct in C++ in order to use the raw data.
My goal is to parse the XML only if the raw data file is not exist.
The method work like this:
If the raw data file is not exist, parse the XML file and save the data to a file.
If the raw data file exist, read the raw data from the file
My problem is: whenever I open the raw data file and read from it. I get to read only small amount of byte from the file, I don't know how much, but in a certain point I receive only 0x00 data on my buffer.
My guess: I believe this has to do with the OS buffer, Which has a certain amount of buffer for read and write operations. I might be wrong about this. Though I'm not sure which one from the operations doesn't work well, it's either the write or read.
I was thinking to write / read the raw data char by char or line by line. In the other hand the file doesn't contain a text, which means that I can't read line by line or char by char.
The raw data size is
size_t datasize = DataSize(); == 196876 (Byte)
Which is retrieve in this function
/* Get the upper bound for predefined cascade size */
size_t CCacadeInterpreter::DataSize()
{
// this is an upper boundary for the whole hidden cascade size
size_t datasize = sizeof(HaarClassifierCascade) * TOTAL_CASCADE+
sizeof(HaarStageClassifier)*TOTAL_STAGES +
sizeof(HaarClassifier) * TOTAL_CLASSIFIERS +
sizeof(void*)*(TOTAL_CASCADE+TOTAL_STAGES+TOTAL_CLASSIFIERS);
return datasize;
}
The method work like this
BYTE * CCacadeInterpreter::Interpreter()
{
printf("|Phase - Load cascade from memory | CCacadeInterpreter::Interpreter | \n");
size_t datasize = DataSize();
// Create a memory structure
nextFreeSpace = pStartMemoryLocation = new BYTE [datasize];
memset(nextFreeSpace,0x00,datasize);
// Try to open a predefined cascade file on the current folder (instead of parsing the file again)
fstream stream;
stream.open(cascadeSavePath); // ...try existing file
if (stream.is_open())
{
stream.seekg(0,ios::beg);
stream.read((char*)pStartMemoryLocation , datasize); // **ream from file**
stream.close();
printf("|Load cascade from saved memory location | CCacadeInterpreter::Interpreter | \n");
printf("Completed\n\n");
stream.close();
return pStartMemoryLocation;
}
// Open the cascade file and parse the cascade xml file
std::fstream cascadeFile;
cascadeFile.open(cascadeDestanationPath, std::fstream::in); // open the file with read only attributes
if (!cascadeFile.is_open())
{
printf("Error: couldn't open cascade XML file\n");
delete pStartMemoryLocation;
return NULL;
}
// Read the file XML file , line by line
string buffer, str;
getline(cascadeFile,str);
while(cascadeFile)
{
buffer+=str;
getline(cascadeFile,str);
}
cascadeFile.close();
split(buffer, '<',m_tokens);
// Parsing begins
pHaarClassifierCascade = (HaarClassifierCascade*)nextFreeSpace;
nextFreeSpace += sizeof(HaarClassifierCascade);
pHaarClassifierCascade->count=0;
pHaarClassifierCascade->orig_window_size_height=20;
pHaarClassifierCascade->orig_window_size_width=20;
m_deptInTree=0;
m_numOfStage = 0;
m_numOfTotalClassifiers=0;
while (m_tokens.size())
{
Parsing();
}
// Save the current cascade into a file
SaveBlockToMemory(pStartMemoryLocation,datasize);
printf("\nCompleted\n\n");
return pStartMemoryLocation;
}
bool CCacadeInterpreter::SaveBlockToMemory(BYTE * pStartMemoryLocation,size_t dataSize)
{
fstream stream;
if (stream.is_open() )
stream.close();
stream.open(cascadeSavePath); // ...try existing file
if (!stream.is_open()) // ...else, create new file...
stream.open(cascadeSavePath, ios_base::in | ios_base::out | ios_base::trunc);
stream.seekg(0,ios::beg);
stream.write((char*)pStartMemoryLocation,dataSize);
stream.close();
return true;
}
Try using the Boost IOstreams library.
It has an easy to use wrrapers for file handling