Studying the zip file format and zlib, I wrote a simple program that displays the contents of a zip file named test.zip
and tries to use zlib
to unzip the test.txt
file in the archive:
#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include <zlib.h>
using namespace std;
#pragma pack(1)
struct LocalFileHeader {
uint32_t signature;
uint16_t version;
uint16_t bit_flag;
uint16_t compression;
uint16_t last_mod_time;
uint16_t last_mod_date;
uint32_t crc32;
uint32_t compressed_size;
uint32_t uncompressed_size;
uint16_t filename_length;
uint16_t extra_length;
};
int readfile(FILE* f)
{
LocalFileHeader lfh= {0};
while(true)
{
if(!fread(&lfh,sizeof(LocalFileHeader),1,f)) return 1;
if(lfh.signature!=0x04034b50) return 0;
string filename(lfh.filename_length,0);
if(!fread(filename.data(),1,lfh.filename_length,f)) return 1;
cout<<filename<<" "<<lfh.compression<<" "<<lfh.compressed_size
<<" "<<lfh.uncompressed_size<<endl;
if(lfh.extra_length>0) fseek(f,lfh.extra_length,SEEK_CUR);
if(filename=="test.txt"s)
{
cout<<endl<<"---------------test.txt------------------"<<endl;
vector<unsigned char> srcbuf(lfh.compressed_size,0);
vector<unsigned char> dstbuf(lfh.uncompressed_size+1,0);
unsigned long dstlen= lfh.uncompressed_size;
if(!fread(srcbuf.data(),1,lfh.compressed_size,f)) return 1;
int res= uncompress(dstbuf.data(),&dstlen,srcbuf.data(), lfh.compressed_size);
if(res !=Z_OK)
{
if(res==Z_DATA_ERROR) cout<<"Z_DATA_ERROR"<<endl;
if(res==Z_BUF_ERROR) cout<<"Z_BUF_ERROR"<<endl;
if(res==Z_MEM_ERROR) cout<<"Z_MEM_ERROR"<<endl;
return 1;
}
cout<<dstbuf.data();
cout<<endl<<"--------------------------------------"<<endl;
}
else if(fseek(f,lfh.compressed_size,SEEK_CUR)) return 1;
}
return 0;
}
int main()
{
FILE* f= fopen("test.zip","rb");
if(!f)
{
cout << "Error opening file" << endl;
return 1;
}
if(readfile(f)) cout<<"Bad file"<<endl;
fclose(f);
return 0;
}
My program successfully outputs the contents of a zip file, but when it tries to unpack test.txt
, I get Z_DATA_ERROR
in the uncompress
function. Obviously, I missed something, but I do not understand what exactly.
uncompress()
is expecting a zlib stream, but you are giving it the raw deflate data of a zip entry. You need to use zlib's inflateInit2()
, inflate()
, and inflateEnd()
functions to decompress raw deflate data.