Zlib decompression function copies instead of decompresses - c++

I'm trying to implement archive handling in my application, using zlib on Linux. The app is written in C++ with Qt5.
This is my example function:
int Foo::decompress(const QString &file)
{
char buffer[128];
int num_read=0;
gzFile fi = gzopen(file.toUtf8().constData(),"rb");
FILE *outfile = fopen("/Data/test.unz", "wb");
if (!fi || !outfile) return -1;
while ((num_read = gzread(fi, buffer, sizeof(buffer))) > 0) {
fwrite(buffer, 1, num_read, outfile);
}
gzclose(fi);
fclose(outfile);
}
This code causes to copy whatever file I feed it , instead of decompressing it. I've read a few other zlib decompression topics, but all they do is add to my confusion.
Any help?

Then the input is not a gzip file. gzread() serves as a drop-in replacement for fread(), so that when the input is not a gzip file, it works like fread() and reads the file with no translation.
Since your input is apparently not a gzip file, and since you say "archive handling", it sounds like you are confused about the file formats. If you are trying to read a .zip file, that is an entirely different thing from a gzip file.

Related

Reading a file and saving the same exact file c++

I am actually writing a c++ program that reads any kind of file and saves it as a bmp file, but first I need to read the file, and thats were the issue is
char fileName[] = "test.jpg";
FILE * inFileForGettingSize;//This is for getting the file size
fopen_s(&inFileForGettingSize, fileName, "r");
fseek(inFileForGettingSize, 0L, SEEK_END);
int fileSize = ftell(inFileForGettingSize);
fclose(inFileForGettingSize);
ifstream inFile;//This is for reading the file
inFile.open(fileName);
if (inFile.fail()) {
cerr << "Error Opening File" << endl;
}
char * data = new char[fileSize];
inFile.read(data, fileSize);
ofstream outFile;//Writing the file back again
outFile.open("out.jpg");
outFile.write(data, fileSize);
outFile.close();
cin.get();
But when I read the file, lets say its a plainttext file it allways outputs some wierd charactes at the end, for example:
assdassaasd
sdaasddsa
sdadsa
passes to:
assdassaasd
sdaasddsa
sdadsaÍÍÍ
So when I do this with a jpg, exe, etc. It corrupts it.
I am not trying to COPY a file, I know there are other ways for that, Im just trying to read a complete file byte per byte. Thanks.
EDIT:
I found out that those 'Í' are equal to the number of end lines the file has, but this doesn't help me much
This is caused by newline handling.
You open the files in text mode (because you use "r" instead of "rb" for fopen and because you don't pass ios::binary to your fstream open calls), and on Windows, text mode translates "\r\n" pairs to "\n" on reading and back to "\r\n" when writing. The result is that the in-memory size is going to be shorter than the on-disk size, so when you try to write using the on-disk size, you go past the end of your array and write whatever random stuff happens to reside in memory.
You need to open files in binary mode when working with binary data:
fopen_s(&inFileForGettingSize, fileName, "rb");
inFile.open(fileName, ios::binary);
outFile.open("out.jpg", ios::binary);
For future reference, your copy routine could be improved. Mixing FILE* I/O with iostream I/O feels awkward, and opening and closing the file twice is extra work, and (most importantly), if your routine is ever run on a large enough file, it will exhaust memory trying to load the entire file into RAM. Copying a block at a time would be better:
const int BUFFER_SIZE = 65536;
char buffer[BUFFER_SIZE];
while (source.good()) {
source.read(buffer, BUFFER_SIZE);
dest.write(buffer, source.gcount());
}
It's a binary file, so you need to read and write the file as binary; otherwise it's treated as text, and assumed to have newlines that need translation.
In your call to fopen(), you need add the "b" designator:
fopen_s(&inFileForGettingSize, fileName, "rb");
And in your fstream::open calls, you need to add std::fstream::binary:
inFile.open(fileName, std::fstream::binary);
// ...
outFile.open("out.jpg", std::fstream::binary);

mp3 file length isn't shown correct

I'm trying to convert a WAV file into MP3 file using LAME (win7,vs2010,c++).
I found this code:
convert wav to mp3 using lame
The convert works fine, but when i'm trying to open the file using windows media player the length of the file is wrong.
Is there any way to fix this using lame lib?(not with another program or another lib or command line,only with c++ code...)
EDITED: after some reading i did i tried to use the lame_get_lametag_frame function as sellibitze suggested.
here is my code:
#include <stdio.h>
#include <lame/lame.h>
int main(void)
{
int read, write;
FILE *pcm = fopen("in.pcm", "rb");
FILE *mp3 = fopen("out.mp3", "wb");
const int PCM_SIZE = 8192;
const int MP3_SIZE = 8192;
short int pcm_buffer[PCM_SIZE*2];
unsigned char mp3_buffer[MP3_SIZE];
lame_t lame = lame_init();
lame_set_in_samplerate(lame, 44100);
lame_set_VBR(lame, vbr_default);
lame_set_write_id3tag_automatic(lame, 0);
lame_init_params(lame);
char buffer[256];
int imp3=lame_get_id3v2_tag(gfp, buffer, sizeof(buffer));
fwrite(buffer, 1, imp3, outf);
long audio_pos=ftell(outf); // store beginning of audio data
do {
read = fread(pcm_buffer, 2*sizeof(short int), PCM_SIZE, pcm);
if (read == 0)
write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
else
write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
fwrite(mp3_buffer, write, 1, mp3);
} while (read != 0);
imp3=lame_get_id3v1_tag(gfp, buffer, sizeof(buffer));
fwrite(buffer, 1, imp3, outf);
imp3=lame_get_lametag_frame(gfp, buffer, sizeof(buffer));
fseek(outf,audio_pos,SEEK_SET); // remember beginning of audio data
fwrite(buffer, 1, imp3, outf);
lame_close(lame);
fclose(mp3);
fclose(pcm);
return 0;
}
FIXED:
I manged to fix the problem but i don't really understand how it fix it.
i change the name of the mp3 file from "out.mp3" to any other name and wmp show the right length. also i tried to change the name of files already created from out to something else and it worked. can anybody explain to me way it's happened? is the name out.mp3 saved?
The example code you liked to uses the VBR mode. Length information in that case is typically put into the first frame as metadata. This is known as Xing/VBR header. It also includes a low accuracy seek table. But this information is obviously only available after you passed all the audio data to LAME. I suggest you look for a function in the LAME API that is able to update the Xing/VBR header to reflect the correct length and seek table and call it before you close the file.
lame_encode_flush does not take your FILE* thingy so it cannot seek back to the beginning of the file and update the first mp3 frame with the Xing/VBR header.

Uncompressing files with Qt qUnCompress function

I read documentation and post about uncompressing ZIP files but I've additional questions.
I need to uncompress zip file in Qt. That is XML file compressed with gzip.
I know that qUnCompress can uncompressing zip files prepared with ZLIB and ZLIB has diffrent header than GZIP.
As i read in documentation:
Note: If you want to use this function to uncompress external data that was compressed using zlib, you first need to prepend a four byte header to the byte array containing the data. The header must contain the expected length (in bytes) of the uncompressed data, expressed as an unsigned, big-endian, 32-bit integer.
Is that means that I have to put at the beginning only length (bigendian) and than compressed data ?
I did it but I have an error from qUncompress function:
qUncompress: Z_DATA_ERROR: Input data is corrupted
You need to write you own gUncompress() function using either zlib, or some other library, that implements the DEFLATE algorithm. I personally prefer miniz:
http://code.google.com/p/miniz/
Here's some code for you:
#include <stdexcept>
#include <QtCore>
#ifndef TINFL_HEADER_FILE_ONLY
# define TINFL_HEADER_FILE_ONLY
#endif // TINFL_HEADER_FILE_ONLY
extern "C" {
# include "tinfl.h"
}
#include "guncompress.hpp"
static tinfl_decompressor inflator;
static QByteArray result(TINFL_LZ_DICT_SIZE, 0);
//////////////////////////////////////////////////////////////////////////////
QByteArray gUncompress(QByteArray const& data)
{
mz_uint8 const* inPtr(reinterpret_cast<mz_uint8 const*>(data.data()) + 10);
tinfl_init(&inflator);
size_t inAvail(data.size());
size_t outTotal(0);
tinfl_status ret;
do
{
size_t inSize(inAvail);
size_t outSize(result.size() - outTotal);
ret = tinfl_decompress(&inflator,
inPtr,
&inSize,
reinterpret_cast<mz_uint8*>(result.data()),
reinterpret_cast<mz_uint8*>(result.data()) + outTotal,
&outSize,
0
);
switch (ret)
{
case TINFL_STATUS_HAS_MORE_OUTPUT:
inAvail -= inSize;
inPtr += inSize;
result.resize(2 * result.size());
case TINFL_STATUS_DONE:
outTotal += outSize;
break;
default:
throw std::runtime_error("error decompressing gzipped content");
}
}
while (TINFL_STATUS_DONE != ret);
return QByteArray::fromRawData(result.data(), outTotal);
}
Also note that zip files and gzip files do not share the same format. Zip files need to be handled differently, as they contain a directory of files they contain.
Look for qzip.cpp, qzipreader_p.h, qzipwriter_p.h in the source for Qt. It can be used for reading and writing zip files.

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

read binary bytes from a jpg file

I need to read bytes from a jpg file in c++ so write this codes:
ifstream in("1.jpg"ios::binary);
while(!in.eof()){
char ch = in.get();
}
as you know a jpg file consist of 256 difference chars that we can save it's repeat in a a arr.but the problem is that this code that i wrote read chars in the form of unicode so it consist of 9256 difference char.how can i read from 1.jpg that it wasn't unicode?
The get function reads unformatted data from the file, it just casts the char it read as an int. Are you seeing data read from the file as different to the actual data in the file? If you are there could be a problem elsewhere in the code, and you should provide more.
Alternatively you could read chunks of unformatted data using read.
int main()
{
std::ifstream in("1.jpg", std::ios::binary);
char buffer[1024];
while (in)
{
in.read(buffer, sizeof(buffer));
if (in.gcount() > 0)
{
// read in.gcount() chars from the file
// process them here.
}
}
}