确定C中Z-lib的压缩/未压缩缓冲区大小

时间:2018-11-09 16:39:54

标签: c zlib

我正在使用Zlib v1.2.7读取文本文件,然后将其压缩并将其写入输出文件。我的问题是在以下示例中,如何根据输入大小确定输出缓冲区的大小? (在示例gz_length中) 我正在将该库用于STM32设备。我添加了unzip方法,但对于未压缩的数据长度也有这个问题。

#include "zlib.h"

int unzip(unsigned char *dst, unsigned long *dst_length, unsigned char *src, unsigned long src_length)
{
    z_stream stream;
    memset(&stream, 0, sizeof(stream));

    stream.next_in = src;
    stream.avail_in = src_length;

    stream.next_out = dst;
    stream.avail_out = *dst_length;

    int rv = inflateInit2(&stream, 15 + 16);
    if (Z_OK == rv) {
        rv = inflate(&stream, Z_NO_FLUSH);
        if (Z_STREAM_END == rv) {
            inflateEnd(&stream);
            rv = Z_OK;
        }
    }

    if (Z_OK == rv) {
        *dst_length = stream.total_out;
    } else {
        *dst_length = 0;
    }

    return rv;
}


int zip(unsigned char *dst, unsigned long *dst_length, unsigned char *src, unsigned long src_length)
{
    z_stream        stream;
    memset(&stream, 0, sizeof(stream));

    stream.next_in = src;
    stream.avail_in = src_length;

    stream.next_out = Z_NULL;
    stream.avail_out = 0;

    /* add 16 to MAX_WBITS to specify gzip format - it gets taken off again in defaultInit2 */
    int rv = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 16 + MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
    if (Z_OK == rv) {
        unsigned long dst_bound = deflateBound(&stream, stream.avail_in) + 12; /* 12 bytes for the gzip header */
        if (dst_bound > *dst_length) {
            rv = Z_MEM_ERROR;
        } else {
            stream.next_out   = dst;
            stream.avail_out = dst_bound;
        }
    }

    if (Z_OK == rv) {
        gz_header        header;
        memset(&header, 0, sizeof(header));
        rv = deflateSetHeader(&stream, &header);
    }

    if (Z_OK == rv) {
        rv = deflate(&stream, Z_FINISH);
        if (Z_STREAM_END == rv) {
            rv = deflateEnd(&stream);
        }
    }

    if (Z_OK == rv) {
        *dst_length = stream.total_out;
    } else {
        *dst_length = 0;
    }

    return rv;
}

int main()
{
    unsigned long read_size;
    unsigned char *buffer = NULL;
    unsigned char *gz_buffer = NULL;
    unsigned long input_size = 0;

    /* Open your_file in read-only mode */
    FILE *fp = fopen("/local/new.txt", "r");
    fseek(fp, 0, SEEK_END); /* Go to end of file */
    input_size = ftell(fp); /* How many bytes did we pass ? */
    printf("Filesize: %ld\n", input_size);
    /* Set position of stream to the beginning */
    rewind(fp);
    /* Allocate the buffer (no need to initialize it with calloc) */
    buffer = (unsigned char*) malloc((input_size + 1) * sizeof(*buffer)); /* input_size + 1 byte for the \0 */
    /* Read the file into the buffer */
    fread(buffer, input_size, 1, fp); /* Read 1 chunk of input_size bytes from fp into buffer */
    /* NULL-terminate the buffer */
    buffer[input_size] = '\0';
    /* Print it ! */
    printf("FileData: %s\n", buffer);
    fclose(fp);
    //PROBLEM HERE how to determine valid gz_length for output based on input_size
    unsigned long gz_length = input_size + 50;
    gz_buffer = (unsigned char*) malloc((gz_length) * sizeof(*gz_buffer));

    if (input_size > 0)
    {
        int rv = zip(gz_buffer, &gz_length, buffer, input_size);
        if (Z_OK == rv)
        {
            FILE *ofp = fopen("/local/out.gz", "w");
            if (ofp)
            {
                int bw = fwrite(gz_buffer, 1, gz_length, ofp);
                fclose(ofp);
            }
        }
        else
        {
            printf("%s:%d: %d%s", __FILE__, __LINE__, rv, newline);
        }
    }
    free(buffer);
    free(gz_buffer);
    return 0;
}

1 个答案:

答案 0 :(得分:1)

如果您想在单个deflate()调用中进行压缩(这并不是必须的),则zlib为此目的提供了功能deflateBound()

在另一个方向上没有有用的界限。所谓无用的意思是说,解压缩输出的大小的界限是压缩输入的大小的一千倍以上。