zlib数据格式及解压缩实现

0x01 zlib和其他压缩的魔术头


一般来说压缩文件都有个魔术头,用于区分不同的压缩文件对应不同的解压缩算法。


7z文件: 

00000000   37 7A BC AF 27 1C 00 03  CD F7 CC 2E 66 6A 33 00   7z集'   枉?fj3 


tar.xz文件

00000000   FD 37 7A 58 5A 00 00 04  E6 D6 B4 46 02 00 21 01   ?zXZ   嬷碏  ! 


zip和apk文件

00000000   50 4B 03 04 14 00 00 00  08 00 A7 AD CF 48 D5 52   PK        Л螲誖

rar文件
00000000   52 61 72 21 1A 07 00 CF  90 73 00 00 0D 00 00 00   Rar!   ?s      

zlib文件

00000000   78 01 ED 9D 0B 94 1C 57  79 E7 AB A6 9F 33 9A 99   x ? ?Wy绔3殭



0x02 zlib在JAVA和c++的不同解压方法


JAVA:

public static byte[] decompress(byte[] compress) throws Exception {  
        ByteArrayInputStream bais = new ByteArrayInputStream(compress);  
        InflaterInputStream iis = new InflaterInputStream(bais);  
  
        ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  
        int c = 0;  
        byte[] buf = new byte[BUFFER_SIZE];  
        while (true) {  
            c = iis.read(buf);  
  
            if (c == EOF)  
                break;  
  
            baos.write(buf, 0, c);  
        }  
  
        baos.flush();  
  
        return baos.toByteArray();  
    } 

C++

#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "zlib.h"

#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
#  include <fcntl.h>
#  include <io.h>
#  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
#else
#  define SET_BINARY_MODE(file)
#endif

#define CHUNK 16384

/* Compress from file source to file dest until EOF on source.
   def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
   allocated for processing, Z_STREAM_ERROR if an invalid compression
   level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
   version of the library linked do not match, or Z_ERRNO if there is
   an error reading or writing the files. */
int def(FILE *source, FILE *dest, int level)
{
    int ret, flush;
    unsigned have;
    z_stream strm;
    unsigned char in[CHUNK];
    unsigned char out[CHUNK];

    /* allocate deflate state */
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    ret = deflateInit(&strm, level);
    if (ret != Z_OK)
        return ret;

    /* compress until end of file */
    do {
        strm.avail_in = fread(in, 1, CHUNK, source);
        if (ferror(source)) {
            (void)deflateEnd(&strm);
            return Z_ERRNO;
        }
        flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
        strm.next_in = in;

        /* run deflate() on input until output buffer not full, finish
           compression if all of source has been read in */
        do {
            strm.avail_out = CHUNK;
            strm.next_out = out;
            ret = deflate(&strm, flush);    /* no bad return value */
            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
            have = CHUNK - strm.avail_out;
            if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
                (void)deflateEnd(&strm);
                return Z_ERRNO;
            }
        } while (strm.avail_out == 0);
        assert(strm.avail_in == 0);     /* all input will be used */

        /* done when last data in file processed */
    } while (flush != Z_FINISH);
    assert(ret == Z_STREAM_END);        /* stream will be complete */

    /* clean up and return */
    (void)deflateEnd(&strm);
    return Z_OK;
}

/* Decompress from file source to file dest until stream ends or EOF.
   inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
   allocated for processing, Z_DATA_ERROR if the deflate data is
   invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
   the version of the library linked do not match, or Z_ERRNO if there
   is an error reading or writing the files. */
int inf(FILE *source, FILE *dest)
{
    int ret;
    unsigned have;
    z_stream strm;
    unsigned char in[CHUNK];
    unsigned char out[CHUNK];

    /* allocate inflate state */
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    strm.avail_in = 0;
    strm.next_in = Z_NULL;
    ret = inflateInit(&strm);
    if (ret != Z_OK)
        return ret;

    /* decompress until deflate stream ends or end of file */
    do {
        strm.avail_in = fread(in, 1, CHUNK, source);
        if (ferror(source)) {
            (void)inflateEnd(&strm);
            return Z_ERRNO;
        }
        if (strm.avail_in == 0)
            break;
        strm.next_in = in;

        /* run inflate() on input until output buffer not full */
        do {
            strm.avail_out = CHUNK;
            strm.next_out = out;
            ret = inflate(&strm, Z_NO_FLUSH);
            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
            switch (ret) {
            case Z_NEED_DICT:
                ret = Z_DATA_ERROR;     /* and fall through */
            case Z_DATA_ERROR:
            case Z_MEM_ERROR:
                (void)inflateEnd(&strm);
                return ret;
            }
            have = CHUNK - strm.avail_out;
            if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
                (void)inflateEnd(&strm);
                return Z_ERRNO;
            }
        } while (strm.avail_out == 0);

        /* done when inflate() says it's done */
    } while (ret != Z_STREAM_END);

    /* clean up and return */
    (void)inflateEnd(&strm);
    return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}

/* report a zlib or i/o error */
void zerr(int ret)
{
    fputs("zpipe: ", stderr);
    switch (ret) {
    case Z_ERRNO:
        if (ferror(stdin))
            fputs("error reading stdin\n", stderr);
        if (ferror(stdout))
            fputs("error writing stdout\n", stderr);
        break;
    case Z_STREAM_ERROR:
        fputs("invalid compression level\n", stderr);
        break;
    case Z_DATA_ERROR:
        fputs("invalid or incomplete deflate data\n", stderr);
        break;
    case Z_MEM_ERROR:
        fputs("out of memory\n", stderr);
        break;
    case Z_VERSION_ERROR:
        fputs("zlib version mismatch!\n", stderr);
    }
}

/* compress or decompress from stdin to stdout */
int main(int argc, char **argv)
{
    int ret;

    /* avoid end-of-line conversions */
    SET_BINARY_MODE(stdin);
    SET_BINARY_MODE(stdout);

    /* do compression if no arguments */
    if (argc == 1) {
        ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION);
        if (ret != Z_OK)
            zerr(ret);
        return ret;
    }

    /* do decompression if -d specified */
    else if (argc == 2 && strcmp(argv[1], "-d") == 0) {
        ret = inf(stdin, stdout);
        if (ret != Z_OK)
            zerr(ret);
        return ret;
    }

    /* otherwise, report usage */
    else {
        fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr);
        return 1;
    }
}




  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Qt中使用zlib库进行文件夹压缩和解压缩,可以按照以下步骤进行: 1. 首先,需要将zlib库添加到Qt项目中。可以将zlib源码下载到本地,然后在.pro文件中添加如下内容: ``` INCLUDEPATH += /path/to/zlib LIBS += -L/path/to/zlib -lz ``` 其中,/path/to/zlibzlib源码所在路径。 2. 接下来,需要编写压缩和解压缩函数。可以使用zlib库提供的函数gzopen、gzwrite、gzclose实现压缩,使用gzopen、gzread、gzclose实现解压缩。具体代码如下: ``` #include <zlib.h> #include <QDir> bool compressFolder(const QString &folderPath, const QString &outputFilePath) { gzFile outputFile = gzopen(outputFilePath.toUtf8().constData(), "wb"); if (!outputFile) { return false; } QDir folder(folderPath); QStringList files = folder.entryList(QDir::Files | QDir::NoDotAndDotDot); foreach (const QString &file, files) { QString filePath = folderPath + QDir::separator() + file; QFile inputFile(filePath); if (!inputFile.open(QIODevice::ReadOnly)) { gzclose(outputFile); return false; } while (!inputFile.atEnd()) { QByteArray buffer = inputFile.read(1024); int ret = gzwrite(outputFile, buffer.constData(), buffer.size()); if (ret == 0) { gzclose(outputFile); return false; } } inputFile.close(); } gzclose(outputFile); return true; } bool decompressFolder(const QString &inputFilePath, const QString &outputFolderPath) { gzFile inputFile = gzopen(inputFilePath.toUtf8().constData(), "rb"); if (!inputFile) { return false; } QDir outputFolder(outputFolderPath); if (!outputFolder.exists()) { outputFolder.mkpath("."); } char buffer[1024]; int ret; while ((ret = gzread(inputFile, buffer, sizeof(buffer))) > 0) { QString outputPath = outputFolderPath + QDir::separator() + "temp.dat"; QFile outputFile(outputPath); if (!outputFile.open(QIODevice::Append)) { gzclose(inputFile); return false; } outputFile.write(buffer, ret); outputFile.close(); } gzclose(inputFile); return true; } ``` 3. 最后,在需要压缩或解压缩文件夹的地方调用对应的函数即可。 ``` QString folderPath = "path/to/folder"; QString outputFilePath = "path/to/output/file.gz"; compressFolder(folderPath, outputFilePath); QString inputFilePath = "path/to/input/file.gz"; QString outputFolderPath = "path/to/output/folder"; decompressFolder(inputFilePath, outputFolderPath); ``` 注意,由于zlib库只能压缩单个文件,因此在压缩文件夹时需要逐一压缩文件。同样,在解压缩时也需要将读取到的数据写入临时文件中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值