使用 zlib 解压缩 zip 文件
Uncompressing a zip file using zlib
研究 zip 文件格式和 zlib,我写了一个简单的程序来显示名为 test.zip
的 zip 文件的内容,并尝试使用 zlib
解压缩 test.txt
文件在存档中:
#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;
}
我的程序成功输出了一个 zip 文件的内容,但是当它试图解压缩 test.txt
时,我在 uncompress
函数中得到 Z_DATA_ERROR
。显然,我错过了什么,但我不明白到底是什么。
uncompress()
需要一个 zlib 流,但您给它的是 zip 条目的原始压缩数据。您需要使用 zlib 的 inflateInit2()
、inflate()
和 inflateEnd()
函数来解压缩原始 deflate 数据。
研究 zip 文件格式和 zlib,我写了一个简单的程序来显示名为 test.zip
的 zip 文件的内容,并尝试使用 zlib
解压缩 test.txt
文件在存档中:
#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;
}
我的程序成功输出了一个 zip 文件的内容,但是当它试图解压缩 test.txt
时,我在 uncompress
函数中得到 Z_DATA_ERROR
。显然,我错过了什么,但我不明白到底是什么。
uncompress()
需要一个 zlib 流,但您给它的是 zip 条目的原始压缩数据。您需要使用 zlib 的 inflateInit2()
、inflate()
和 inflateEnd()
函数来解压缩原始 deflate 数据。