2012-09-13 45 views
2

我有一个字符缓冲区,我想压缩到位。现在我已经设置好了,所以有两个缓冲区和zlib的deflate从输入缓冲区读取并写入输出缓冲区。然后我必须改变输入缓冲区指针指向输出缓冲区并释放旧的输入缓冲区。这似乎是不必要的分配量。由于zlib正在压缩,所以next_out指针应该总是落后于next_in指针。无论如何,我找不到足够的文件来验证这一点,并希望有人有这方面的经验。谢谢你的时间!是否有可能让zlib从相同的内存缓冲区中读取和写入?

回答

5

它可以做到,小心。下面的例程是这样做的。并非所有数据都是可压缩的,因此您必须处理输出数据与输入数据匹配的情况。它需要大量不可压缩的数据,但它可能会发生(请参阅代码中的注释),在这种情况下,您必须分配一个缓冲区来临时保留剩余的输入。

/* Compress buf[0..len-1] in place into buf[0..*max-1]. *max must be greater 
    than or equal to len. Return Z_OK on success, Z_BUF_ERROR if *max is not 
    enough output space, Z_MEM_ERROR if there is not enough memory, or 
    Z_STREAM_ERROR if *strm is corrupted (e.g. if it wasn't initialized or if it 
    was inadvertently written over). If Z_OK is returned, *max is set to the 
    actual size of the output. If Z_BUF_ERROR is returned, then *max is 
    unchanged and buf[] is filled with *max bytes of uncompressed data (which is 
    not all of it, but as much as would fit). 

    Incompressible data will require more output space than len, so max should 
    be sufficiently greater than len to handle that case in order to avoid a 
    Z_BUF_ERROR. To assure that there is enough output space, max should be 
    greater than or equal to the result of deflateBound(strm, len). 

    strm is a deflate stream structure that has already been successfully 
    initialized by deflateInit() or deflateInit2(). That structure can be 
    reused across multiple calls to deflate_inplace(). This avoids unnecessary 
    memory allocations and deallocations from the repeated use of deflateInit() 
    and deflateEnd(). */ 
int deflate_inplace(z_stream *strm, unsigned char *buf, unsigned len, 
        unsigned *max) 
{ 
    int ret;     /* return code from deflate functions */ 
    unsigned have;    /* number of bytes in temp[] */ 
    unsigned char *hold;  /* allocated buffer to hold input data */ 
    unsigned char temp[11];  /* must be large enough to hold zlib or gzip 
            header (if any) and one more byte -- 11 
            works for the worst case here, but if gzip 
            encoding is used and a deflateSetHeader() 
            call is inserted in this code after the 
            deflateReset(), then the 11 needs to be 
            increased to accomodate the resulting gzip 
            header size plus one */ 

    /* initialize deflate stream and point to the input data */ 
    ret = deflateReset(strm); 
    if (ret != Z_OK) 
     return ret; 
    strm->next_in = buf; 
    strm->avail_in = len; 

    /* kick start the process with a temporary output buffer -- this allows 
     deflate to consume a large chunk of input data in order to make room for 
     output data there */ 
    if (*max < len) 
     *max = len; 
    strm->next_out = temp; 
    strm->avail_out = sizeof(temp) > *max ? *max : sizeof(temp); 
    ret = deflate(strm, Z_FINISH); 
    if (ret == Z_STREAM_ERROR) 
     return ret; 

    /* if we can, copy the temporary output data to the consumed portion of the 
     input buffer, and then continue to write up to the start of the consumed 
     input for as long as possible */ 
    have = strm->next_out - temp; 
    if (have <= (strm->avail_in ? len - strm->avail_in : *max)) { 
     memcpy(buf, temp, have); 
     strm->next_out = buf + have; 
     have = 0; 
     while (ret == Z_OK) { 
      strm->avail_out = strm->avail_in ? strm->next_in - strm->next_out : 
               (buf + *max) - strm->next_out; 
      ret = deflate(strm, Z_FINISH); 
     } 
     if (ret != Z_BUF_ERROR || strm->avail_in == 0) { 
      *max = strm->next_out - buf; 
      return ret == Z_STREAM_END ? Z_OK : ret; 
     } 
    } 

    /* the output caught up with the input due to insufficiently compressible 
     data -- copy the remaining input data into an allocated buffer and 
     complete the compression from there to the now empty input buffer (this 
     will only occur for long incompressible streams, more than ~20 MB for 
     the default deflate memLevel of 8, or when *max is too small and less 
     than the length of the header plus one byte) */ 
    hold = strm->zalloc(strm->opaque, strm->avail_in, 1); 
    if (hold == Z_NULL) 
     return Z_MEM_ERROR; 
    memcpy(hold, strm->next_in, strm->avail_in); 
    strm->next_in = hold; 
    if (have) { 
     memcpy(buf, temp, have); 
     strm->next_out = buf + have; 
    } 
    strm->avail_out = (buf + *max) - strm->next_out; 
    ret = deflate(strm, Z_FINISH); 
    strm->zfree(strm->opaque, hold); 
    *max = strm->next_out - buf; 
    return ret == Z_OK ? Z_BUF_ERROR : (ret == Z_STREAM_END ? Z_OK : ret); 
} 
+0

太棒了!喜欢这个地方。而且我没有很长的不可压缩的流,所以更好!万分感谢! – Ben

相关问题