使用 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 数据。