zlib

zlib

zlib是提供數據壓縮用的函式庫,由Jean-loup Gailly與Mark Adler所開發,初版0.9版在1995年5月1日發表。zlib使用DEFLATE算法,最初是為libpng函式庫所寫的,後來普遍為許多軟體所使用。此函式庫為自由軟體,使用zlib授權。截至2007年3月,zlib是包含在Coverity的美國國土安全部贊助者選擇繼續審查的開源項目。

特性

數據頭(header)

zlib能使用一個gzip數據頭,zlib數據頭或者不使用數據頭壓縮數據。

通常情況下,數據壓縮使用zlib數據頭,因為這提供錯誤數據檢測。當數據不使用數據頭寫入時,結果是沒有任何錯誤檢測的原始DEFLATE數據,那么解壓縮軟體的調用者不知道壓縮數據在什麼地方結束。

gzip數據頭比zlib數據頭要大,因為它保存了檔案名稱和其他檔案系統信息,事實上這是廣泛使用的gzip檔案的數據頭格式。注意zlib函式庫本身不能創建一個gzip檔案,但是它相當輕鬆的通過把壓縮數據寫入到一個有gzip檔案頭的檔案中。

算法

目前zlib僅支持一個LZ77的變種算法,DEFLATE的算法。

這個算法使用很少的系統資源,對各種數據提供很好的壓縮效果。這也是在ZIP檔案中無一例外的使用這個算法。(儘管zip檔案格式也支持幾種其他的算法)。

看起來zlib格式將不會被擴展使用任何其他算法,儘管數據頭可以有這種可能性。

使用資源

函式館提供了對處理器和記憶體使用控制的能力

不同的壓縮級別數值可以指示不同的壓縮執行速度。

還有記憶體控制管理的功能。這在一些諸如嵌入式系統這樣記憶體有限制的環境中是有用的。

策略

壓縮可以針對特定類型的數據進行最佳化

如果你總是使用zlib庫壓縮壓縮特定類型的數據,那么可以使用有針對性的策略可以提高壓縮效率和性能。例如,如果你的數據包含很長的重複數據,那么可以用RLE(運行長度編碼)策略,可能會有更好的結果。

對於一般的數據,默認的策略是首選。

錯誤處理

錯誤可以被發現和跳過

數據混亂可以被檢測(只要數據和zlib或者gzip數據頭一起被寫入-參見上面)

此外,如果全刷新點(full-flush points)被寫入到壓縮後的數據流中,那么錯誤數據是可以被跳過的,並且解壓縮將重新同步到下個全刷新點。(錯誤數據的無錯恢復被提供)。全刷新點技術對於在不可靠的通道上的大數據流是很有用的,一些過去的數據丟失是不重要的(例如多媒體數據),但是建立太多的全刷新點會極大的影響速度和壓縮。

數據長度

對於壓縮和解壓縮,沒有數據長度的限制

重複調用庫函式允許處理無限的數據塊。一些輔助代碼(計數變數)可能會溢出,但是不影響實際的壓縮和解壓縮。

當壓縮一個長(無限)數據流時,最好寫入全刷新點。

業界套用

今天,zlib是一種事實上的業界標準,以至於在標準文檔中,zlib和DEFLATE常常互換使用。數以千計的應用程式直接或間接依靠zlib壓縮函式庫,包括:

* Linux核心:使用zlib以實作網路協定的壓縮、檔案系統的壓縮以及開機時解壓縮自身的核心。

* libpng,用於PNG圖形格式的一個實現,對bitmap數據規定了DEFLATE作為流壓縮方法。

* Apache:使用zlib實作http 1.1。

* OpenSSH、OpenSSL:以zlib達到最佳化加密網路傳輸。

* FFmpeg:以zlib讀寫Matroska等以DEFLATE算法壓縮的多媒體串流格式。

* rsync:以zlib最佳化遠端同步時的傳輸。

* The dpkg and RPM package managers, which use zlib to unpack files from compressed software packages.

* Subversion 、Git和 CVS 版本控制 系統,使用zlib來壓縮和遠端倉庫的通訊流量。

* dpkg和RPM等包管理軟體:以zlib解壓縮RPM或者其他封包。

因為其代碼的可移植性,寬鬆的許可以及較小的記憶體占用,zlib在許多嵌入式設備中也有套用。

使用範例

以下代碼可直接用於解壓HTTP gzip

#include <stdlib.h>

#include <string.h>

#include <errno.h>

#include <zlib.h>

/* Compress data */

int zcompress(Bytef *data, uLong ndata,

Bytef *zdata, uLong *nzdata)

{

z_stream c_stream;

int err = 0;

if(data && ndata > 0)

{

c_stream.zalloc = (alloc_func)0;

c_stream.zfree = (free_func)0;

c_stream.opaque = (voidpf)0;

if(deflateInit(&c_stream, Z_DEFAULT_COMPRESSION) != Z_OK) return -1;

c_stream.next_in = data;

c_stream.avail_in = ndata;

c_stream.next_out = zdata;

c_stream.avail_out = *nzdata;

while (c_stream.avail_in != 0 && c_stream.total_out < *nzdata)

{

if(deflate(&c_stream, Z_NO_FLUSH) != Z_OK) return -1;

}

if(c_stream.avail_in != 0) return c_stream.avail_in;

for (;;) {

if((err = deflate(&c_stream, Z_FINISH)) == Z_STREAM_END) break;

if(err != Z_OK) return -1;

}

if(deflateEnd(&c_stream) != Z_OK) return -1;

*nzdata = c_stream.total_out;

return 0;

}

return -1;

}

/* Compress gzip data */

int gzcompress(Bytef *data, uLong ndata,

Bytef *zdata, uLong *nzdata)

{

z_stream c_stream;

int err = 0;

if(data && ndata > 0)

{

c_stream.zalloc = (alloc_func)0;

c_stream.zfree = (free_func)0;

c_stream.opaque = (voidpf)0;

if(deflateInit2(&c_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,

-MAX_WBITS, 8, Z_DEFAULT_STRATEGY) != Z_OK) return -1;

c_stream.next_in = data;

c_stream.avail_in = ndata;

c_stream.next_out = zdata;

c_stream.avail_out = *nzdata;

while (c_stream.avail_in != 0 && c_stream.total_out < *nzdata)

{

if(deflate(&c_stream, Z_NO_FLUSH) != Z_OK) return -1;

}

if(c_stream.avail_in != 0) return c_stream.avail_in;

for (;;) {

if((err = deflate(&c_stream, Z_FINISH)) == Z_STREAM_END) break;

if(err != Z_OK) return -1;

}

if(deflateEnd(&c_stream) != Z_OK) return -1;

*nzdata = c_stream.total_out;

return 0;

}

return -1;

}

/* Uncompress data */

int zdecompress(Byte *zdata, uLong nzdata,

Byte *data, uLong *ndata)

{

int err = 0;

z_stream d_stream; /* decompression stream */

d_stream.zalloc = (alloc_func)0;

d_stream.zfree = (free_func)0;

d_stream.opaque = (voidpf)0;

d_stream.next_in = zdata;

d_stream.avail_in = 0;

d_stream.next_out = data;

if(inflateInit(&d_stream) != Z_OK) return -1;

while (d_stream.total_out < *ndata && d_stream.total_in < nzdata) {

d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */

if((err = inflate(&d_stream, Z_NO_FLUSH)) == Z_STREAM_END) break;

if(err != Z_OK) return -1;

}

if(inflateEnd(&d_stream) != Z_OK) return -1;

*ndata = d_stream.total_out;

return 0;

}

/* HTTP gzip decompress */

int httpgzdecompress(Byte *zdata, uLong nzdata,

Byte *data, uLong *ndata)

{

int err = 0;

z_stream d_stream = {0}; /* decompression stream */

static char dummy_head[2] =

{

0x8 + 0x7 * 0x10,

(((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,

};

d_stream.zalloc = (alloc_func)0;

d_stream.zfree = (free_func)0;

d_stream.opaque = (voidpf)0;

d_stream.next_in = zdata;

d_stream.avail_in = 0;

d_stream.next_out = data;

if(inflateInit2(&d_stream, 47) != Z_OK) return -1;

while (d_stream.total_out < *ndata && d_stream.total_in < nzdata) {

d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */

if((err = inflate(&d_stream, Z_NO_FLUSH)) == Z_STREAM_END) break;

if(err != Z_OK )

{

if(err == Z_DATA_ERROR)

{

d_stream.next_in = (Bytef*) dummy_head;

d_stream.avail_in = sizeof(dummy_head);

if((err = inflate(&d_stream, Z_NO_FLUSH)) != Z_OK)

{

return -1;

}

}

else return -1;

}

}

if(inflateEnd(&d_stream) != Z_OK) return -1;

*ndata = d_stream.total_out;

return 0;

}

/* Uncompress gzip data */

int gzdecompress(Byte *zdata, uLong nzdata,

Byte *data, uLong *ndata)

{

int err = 0;

z_stream d_stream = {0}; /* decompression stream */

static char dummy_head[2] =

{

0x8 + 0x7 * 0x10,

(((0x8 + 0x7 * 0x10) * 0x100 + 30) / 31 * 31) & 0xFF,

};

d_stream.zalloc = (alloc_func)0;

d_stream.zfree = (free_func)0;

d_stream.opaque = (voidpf)0;

d_stream.next_in = zdata;

d_stream.avail_in = 0;

d_stream.next_out = data;

if(inflateInit2(&d_stream, -MAX_WBITS) != Z_OK) return -1;

//if(inflateInit2(&d_stream, 47) != Z_OK) return -1;

while (d_stream.total_out < *ndata && d_stream.total_in < nzdata) {

d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */

if((err = inflate(&d_stream, Z_NO_FLUSH)) == Z_STREAM_END) break;

if(err != Z_OK )

{

if(err == Z_DATA_ERROR)

{

d_stream.next_in = (Bytef*) dummy_head;

d_stream.avail_in = sizeof(dummy_head);

if((err = inflate(&d_stream, Z_NO_FLUSH)) != Z_OK)

{

return -1;

}

}

else return -1;

}

}

if(inflateEnd(&d_stream) != Z_OK) return -1;

*ndata = d_stream.total_out;

return 0;

}

#ifdef _DEBUG_ZSTREAM

#define BUF_SIZE 65535

int main()

{

char *data = "kjdalkfjdflkjdlkfjdklfjdlkfjlkdjflkdjflddajfkdjfkdfaskf;ldsfk;ldakf;ldskfl;dskf;ld";

uLong ndata = strlen(data);

Bytef zdata[BUF_SIZE];

uLong nzdata = BUF_SIZE;

Bytef odata[BUF_SIZE];

uLong nodata = BUF_SIZE;

memset(zdata, 0, BUF_SIZE);

//if(zcompress((Bytef *)data, ndata, zdata, &nzdata) == 0)

if(gzcompress((Bytef *)data, ndata, zdata, &nzdata) == 0)

{

fprintf(stdout, "nzdata:%d %s\n", nzdata, zdata);

memset(odata, 0, BUF_SIZE);

//if(zdecompress(zdata, ndata, odata, &nodata) == 0)

if(gzdecompress(zdata, ndata, odata, &nodata) == 0)

{

fprintf(stdout, "%d %s\n", nodata, odata);

}

}

}

#endif

zlib許可

zlib許可 是一個自由軟體授權協定,但並非copyleft。Box2D就使用了zlib許可。

相關詞條

相關搜尋

熱門詞條

聯絡我們