Categories: C/C++

zlib/

Продолжая серию постов о полезных библиотеках в мире C/C++, стоило бы упомянуть хотя бы одну библиотеку для сжатия данных. Библиотек таких великое множество. Среди них, пожалуй, наиболее распространенной, своего рода стандартом де-факто, является zlib. Поэтому о ней далее речь и пойдет.

Пользуясь случаем, напомню, что в предыдущих сериях вы видели:

Теперь вернемся к zlib. Допустим, вам нужно сжать сравнительно небольшой кусок данных, целиком помещающийся в память. Делается это элементарно:

uLongf compress_buff_size = compressBound ( file_size ) ;
void * compress_buff = malloc ( compress_buff_size ) ;
if ( compress_buff == NULL )
{
fprintf ( stderr ,
«malloc(compress_buff_size) failed, »
«compress_buff_size = %lu n » ,
compress_buff_size ) ;
exit ( 1 ) ;
}

uLongf compressed_size = compress_buff_size ;
res = compress ( compress_buff, & compressed_size, file_buff, file_size ) ;
if ( res ! = Z_OK )
{
fprintf ( stderr , «compress(…) failed, res = %d n » , res ) ;
exit ( 1 ) ;
}

Процедура compressBound возвращает максимальный размер, какого могут оказаться данные в сжатом виде, а compress непосредственно производит сжатие. В результате в compress_buff будут записаны данные в сжатом виде, а в compressed_size — их размер.

Разжатие производится по аналогии:

uLongf decompressed_size = ( uLongf ) file_size ;
res = uncompress ( file_buff, & decompressed_size,
compress_buff, compressed_size ) ;
if ( res ! = Z_OK )
{
fprintf ( stderr , «uncompress(…) failed, res = %d n » , res ) ;
exit ( 1 ) ;
}

Компрессия и декомпрессия больших объемов данных производится чуть сложнее, но ненамного:

/* Компрессия */
bool compress_file ( FILE * src, FILE * dst )
{
uint8_t inbuff [ CHUNK_SIZE ] ;
uint8_t outbuff [ CHUNK_SIZE ] ;
z_stream stream = { 0 } ;

if ( deflateInit ( & stream, COMPRESSION_LEVEL ) ! = Z_OK )
{
fprintf ( stderr , «deflateInit(…) failed! n » ) ;
return false ;
}

int flush ;
do {
stream. avail_in = fread ( inbuff, 1 , CHUNK_SIZE, src ) ;
if ( ferror ( src ) )
{
fprintf ( stderr , «fread(…) failed! n » ) ;
deflateEnd ( & stream ) ;
return false ;
}

flush = feof ( src ) ? Z_FINISH : Z_NO_FLUSH ;
stream. next_in = inbuff ;

do {
stream. avail_out = CHUNK_SIZE ;
stream. next_out = outbuff ;
deflate ( & stream, flush ) ;
uint32_t nbytes = CHUNK_SIZE stream. avail_out ;

if ( fwrite ( outbuff, 1 , nbytes, dst ) ! = nbytes ||
ferror ( dst ) )
{
fprintf ( stderr , «fwrite(…) failed! n » ) ;
deflateEnd ( & stream ) ;
return false ;
}
} while ( stream. avail_out == 0 ) ;
} while ( flush ! = Z_FINISH ) ;

deflateEnd ( & stream ) ;
return true ;
}

/* Декомпрессия */
bool decompress_file ( FILE * src, FILE * dst )
{
uint8_t inbuff [ CHUNK_SIZE ] ;
uint8_t outbuff [ CHUNK_SIZE ] ;
z_stream stream = { 0 } ;

int result = inflateInit ( & stream ) ;
if ( result ! = Z_OK )
{
fprintf ( stderr , «inflateInit(…) failed! n » ) ;
return false ;
}

do {
stream. avail_in = fread ( inbuff, 1 , CHUNK_SIZE, src ) ;
if ( ferror ( src ) )
{
fprintf ( stderr , «fread(…) failed! n » ) ;
inflateEnd ( & stream ) ;
return false ;
}

if ( stream. avail_in == 0 )
break ;

stream. next_in = inbuff ;

do {
stream. avail_out = CHUNK_SIZE ;
stream. next_out = outbuff ;
result = inflate ( & stream, Z_NO_FLUSH ) ;
if ( result == Z_NEED_DICT || result == Z_DATA_ERROR ||
result == Z_MEM_ERROR )
{
fprintf ( stderr , «inflate(…) failed: %d n » , result ) ;
inflateEnd ( & stream ) ;
return false ;
}

uint32_t nbytes = CHUNK_SIZE stream. avail_out ;

if ( fwrite ( outbuff, 1 , nbytes, dst ) ! = nbytes ||
ferror ( dst ) )
{
fprintf ( stderr , «fwrite(…) failed! n » ) ;
inflateEnd ( & stream ) ;
return false ;
}
} while ( stream. avail_out == 0 ) ;
} while ( result ! = Z_STREAM_END ) ;

inflateEnd ( & stream ) ;
return result == Z_STREAM_END ;
}

Долго и нудно разжевывать этот код мне что-то лень. Думаю, вы в состоянии самостоятельно в нем разобраться. В крайнем случае всегда можно почитать /usr/include/zlib.h — в нем есть подробные комментарии ко всем процедурам.

Полная версия исходников к этому посту лежит на GitHub . Для сборки проекта я использовал Autotools. Не помню, зачем мне нужен был именно Autotools, так как код писался давно. В README.md есть инструкция по сборке, плюс обратите внимание на пост Основы сборки проектов при помощи Autotools .

Как обычно, буду рад вашим вопросам и дополнениям.

admin

Share
Published by
admin
Tags: C/C++

Recent Posts

vim-commands/

Самое главное — побороть боязнь белого листа. Я всегда говорю это себе, когда нужно начать…

1 месяц ago

firefox-thunderbird-en-ru-dict/

По не вполне ясным причинам, Firefox умеет проверять орфографию либо только в русских, либо только…

1 месяц ago

perl-hacks/

Около месяца собирал разные «хаки» на языке программирования Perl. Эта подборка наглядно демонстрирует, как в…

1 месяц ago

perl-cy-check/

C недавних пор я стал увлекаться SEO. Порой передо мной встает задача быстро проверить индекс…

1 месяц ago

which-cms-perl/

Недавно написал несколько скриптов, позволяющих автоматически определять, какая CMS (Content Management System, система управления контентом)…

1 месяц ago

smtp-descr/

Я так подозреваю, что среди вас найдется те, кто скажет, что этот пост боян и…

1 месяц ago