Доброго времени суток, уважаемый читатель! Эта статья представляет собой небольшой технический тутор по программированию с использованием библиотеки libbzip2, на базе которой создана популярная утилита bzip2. Если ты
начинающий UNIX/Windows-программист на сях и/или хочешь расширить свой кругозор, овладев удобным и компактным API для сжатия данных, то эта статья будет тебе интересна.

НЕМНОГО О BZIP2

Я очень сомневаюсь, что в наши дни найдется хоть кто-нибудь, кто не был бы знаком с этим «архиватором». Я более чем уверен, что если тебе когда-либо приходилось скачивать новое ядро linux’а или патч к нему, ты непременно брал .tar.bz2 =) bzip2
— абсолютный лидер по степени lossless-сжатия данных среди всех известных мне GNU’шных средств. Безусловной прелестью bzip2 является наличие очень компактной и удобной thread-safe-библиотеки (библиотека не использует внешних областей памяти, стало быть, её можно безопасно использовать в многопоточных приложениях), предоставляющей пару десятков функция для сжатия блоков данных и для работы с файлами .bz2-формата. 

К объективным недостаткам можно отнести огромную ресурсоёмкость: работа механизмов libbzip2 изрядно медленнее zlib’ных (gzip). Поэтому, если ты планируешь обрабатывать большие объёмы данных и вопрос ресурсоёмкости для тебя критичен (например, если ты хочешь снизить избыточность обмена информацией по относительно скоростным магистралям), обрати своё внимание на
zlib, которая, кстати, имеет порты и интерфейсы практически подо все мыслимые современных платформы и средства разработки. Есть интерфейс даже для Delphi и Visual Basic! =) Если тебе требуется ещё бОльшая скорость (в ущерб, разумеется, эффективности сжатия), то изучи
LZO. Возможно, в некотором будущем я сделаю howto и к этим библиотекам тоже. Если тебе это интересно, сообщи мне об этом по email’у.

РЕКВИЗИТЫ LIBBZIP2

Официальная страница libbzip2 находится на http://sources.redhat.com/bzip2/, отсюда ты сможешь скачать последнюю версию этой библиотеки и документацию к ней. Я
рассматриваю версию 1.0.2, но всё из того что я расскажу верно также и для более ранних версий этой библиотеки. Здесь ты также найдешь список доступных портов этой библиотеки под различные платформы. Я изучал libbzip2 на платформах linux (p3/533) и cygwin под Windows2000 (p4/2200). libbzip2 и скрипты к ней (bzip2, bunzip2, bzcat, etc…) идут в стандартных дистрибутивах linux’а и cygwin’а, так что тебе её даже устанавливать не придётся =) Проверь, есть ли в твоей /usr/include файл bzlib.h и содержит ли твой /usr/lib экспортные и динамические библиотеки libbz2*.

USAGE

file.c:
#include <bzlib.h>
int main (int argc, char **argv, char **envp) {

return 0;
}

Makefile:
gcc file.c -lbz2 -o file.exe

Библиотека libbzip2 экспортирует четыре типа функций:

1) низкоуровневые (low-level interface), с помощью которых программист может предельно глубоко овладеть процессом сжатия/восстановления данных (следует оговориться: настолько предельно глубоко, насколько ему позволено =)));

2) высокоуровневые (high-level interface), предоставляющие возможность работать с файлами .bz2-формата;

3) две специальные очень простые функции (utility functions), одна из который сжимает, а другая — разжимает блок данных;

4) функции совместимости с zlib (zlib compatibility functons).

Обрати внимание: в libbzip2, все функции и видимые пользователем константы начинаются с префикса BZ2_.

UTILITY FUNCTIONS

Если ты не собираешься работать с файлами в .bz2-формате и добиваться глубокого контроля над процессами сжатия и восстановления инфы, то ты вполне сможешь обойтись двумя очень простыми функциями, BZ2_bzBuffToBuffCompress() и BZ2_bzBuffToBuffDecompress(). Рассмотрим каждую из них в отдельности:

int BZ2_bzBuffToBuffCompress( char *dest,
unsigned int *destLen,
char *source,
unsigned int sourceLen,
int blockSize100k,
int verbosity,
int workFactor );

Эта функция сжимает sourceLen байт из source в dest, размер выделенной памяти под который содержится в destLen. После возврата управления, функция изменяет destLen, помещая туда размер сжатых данных, поэтому destLen передаётся в функцию по указателю. blockSize100k может принимать значение от 1 до 9 и является косвенным указателем на возможный размер памяти, которую функция затребует от системы для проведения операции сжатия. 1 соответствует 1200k, а 9
— 7600k. verbosity может принимать значения от 0 до 4 и соответствует количеству отладочной информации, которая будет выводиться в stdout в процессе работы функции. Устанавливая эту переменную, ты сможешь изучать процесс работы libbzip2. workFactor
— это один из основных параметров работы механизма сжатия программы, который косвенно влияет на скорость работы функции (он не влияет на результат), дефолтное значение
— 30. Если ты хочешь глубже понять эти механизмы, поиграйся с workFactor’ом, установив verbosity в значение 4.

int BZ2_bzBuffToBuffDecompress( char *dest,
unsigned int *destLen,
char *source,
unsigned int sourceLen,
int small,
int verbosity );

Эта функция выполняет обратные первой функции действия. В ней отсутствуют параметры blockSize100k и workFactor (первый явно указан в дескрипторе сжатого куска, а второй необходим лишь при сжатии). Установив параметр small в единичное значение, ты снизишь количество памяти, необходимое для восстановления сжатого куска (примерно в полтора раза), но увеличишь необходимое для проведения этой операции время.

Вот пример использования двух этих функций:

#include <stdio.h>
#include <bzlib.h>
int main (int argc, char **argv, char **envp) {
char *dst;
unsigned int destLen;
char *src;
unsigned int srcLen;
int bsize = 9;
int verbosity = 4;
int factor = 30;
int i;
int rc;

src = (char *)malloc(256*1024);
dst = (char *)malloc(64*1024);
destLen = 65536;

for(i=0;i<256*1024;i++) src[i] = rand();

rc = BZ2_bzBuffToBuffCompress(dst,&destLen,src,256*1024*10,bsize,verbosity,factor);

printf(«Return code: %u\n»,rc);
printf(«Compressed length: %u\n», destLen);

rc = BZ2_bzBuffToBuffDecompress(src,&srcLen,dst,destLen,0,verbosity);

printf(«\nReturn code:%u\n»,rc);
printf(«Uncompressed length: %u\n», srcLen);

return 0;
}

ZLIB COMPATIBILITY FUNCTIONS

Функции совместимости с zlib (BZ2_bzopen, BZ2_bzread, BZ2_bzwrite, BZ2_bzflush, BZ2_bzclose, BZ2_bzerror, BZ2_bzlibVersion) официально не являются частью libbzip2, но они включены в библиотеку и, я думаю, они будут очень многим полезны и интересны. Эти функции работают с .bz2-файлами. Обрати внимание, эти функции работают со специальным типом typedef void BZFILE.

const char *BZ2_bzlibVersion(void) возвращает строку с версией библиотеки.

BZFILE * BZ2_bzopen (const char *path, const char *mode);
BZFILE * BZ2_bzdopen (int fd, const char *mode);

открывают файл (вторая — файловый дескриптор) в указанном в *mode режиме, аналогично fopen и fdopen из stdio.

int BZ2_bzread (BZFILE *b, void *buf, int len);
int BZ2_bzwrite (BZFILE *b, void *buf, int len);

читают и записывают в файл *b len байт из *buf, аналогично fread и fwrite из stdio.

int BZ2_bzflush (BZFILE *b);
void BZ2_bzclose (BZFILE *b);

работают аналогично fflush и fclose из stdio.

const char * BZ2_bzerror (BZFILE *b, int *errnum);

возвращает состояние .bz2-файла *b и кладёт в errnum код ошибки последней проведённой операции.

Учти, что операции записи и сброса буферов в .bz2-файлы не обязательно будут выполнены физически сразу же после их вызова. Логику работы этих операций ты сможешь прочувствовать на этом примере использования zlib compatible functions:

#include <stdio.h>
#include <bzlib.h>

#define DDD «this is a string to put!\n»

int main (int argc, char **argv, char **envp) {

BZFILE *file;
int i;

printf(«%s\n»,BZ2_bzlibVersion());
printf(«Creating bzip2 file…»);

file = BZ2_bzopen(«./bzfile.bz2″,»w»);
if(!file) {
printf(«failed!\n»);
return 1;
}
printf(«done!\n»);

printf(«bzwriting…»);
fflush(stdout);
for(i=0;i<256*16;i++) {
BZ2_bzwrite(file,DDD,strlen(DDD));
}
printf(«done!\n»);

printf(«bzclosing…»);
fflush(stdout);
BZ2_bzclose(file);
printf(«done!\n»);

return 0;
}

HIGH LEVEL INTERFACE

Функции BZ2_bzReadOpen, BZ2_bzRead, BZ2_bzReadGetUnused, BZ2_bzReadClose, BZ2_bzWriteOpen, BZ2_bzWrite и BZ2_bzWriteClose составляют высокоуровневый интерфейс libbzip2, и, как и zlib compatible functions, позволяют манипулировать .bz2-файлами. Собственно говоря, zlib compatible functions
— это надстройка над верхнеуровневым интерфейсом libbzip2.

Все функции принимают в качестве первого параметра аргумент int *bzerror. После возврата управления каждой функции необходимо прежде всего проверять значение этого аргумента, и лишь затем следует проверять код возврата самой функции.

Если bzerror содержит код ошибки (что угодно, кроме BZ_OK или BZ_STREAM_END), следует немедленно вызвать BZ2_bzReadClose (или BZ2_bzWriteClose, в зависимости от того, чем занимается твоя программа) и освободить все связанные с обрабатываемыми данными ресурсы, так как поведение других функций после возврата ошибки не определено. bzerror должен проверяться после каждого вызова функций high level interface.

Файлы типа FILE *, идущие параметром к функциям BZ2_bzReadOpen и BZ2_bzWriteOpen, должны быть установлены в двоичный формат. (По дефолту это уже так и в linux, и в cygwin).

Высокоуровневые функции не предоставляют возможности использования альтернативных функций выделения и освобождения динамической памяти (такая возможность присутствует в низкоуровневых API), libbzip2 использует стандартные
malloc/free.

BZFILE *BZ2_bzReadOpen( int *bzerror,
FILE *f,
int small,
int verbosity,
void *unused,
int nUnused);

Эта функция совершает подготовку к чтению сжатых данных из файла FILE *f. FILE *f должен ссылаться на уже открытый для чтения файл. Если параметр small установлен в единицу, функция попытается использовать меньшее количество памяти (в ущерб скорости). Значение параметра verbosity мы уже рассматривали. Прежде чем читать данные из файла FILE *f, функция будет читать nUnused байт из void *unused. nUnused не должен превышать BZ_MAX_UNUSED. Если эта фича не требуется, оба последних параметра должны быть установлены в ноль.

Оставить мнение

Check Also

Скрытая сила пробела. Эксплуатируем критическую уязвимость в Apache Tomcat

В этой статье мы поговорим о баге в Apache Tomcat, популярнейшем веб-сервере для сайтов на…