сдувать и надувать (zlib.h) в C

Я пытаюсь реализовать функции zlib.h deflate и inflate для сжатия и распаковки массива символов (а не файла).

Я хотел бы знать, правильный ли следующий синтаксис? Я что-то упустил или что-то неправильно определил?

char a[50] = "Hello World!";
char b[50];
char c[50];

// deflate
// zlib struct
z_stream defstream;
defstream.zalloc = Z_NULL;
defstream.zfree = Z_NULL;
defstream.opaque = Z_NULL;
defstream.avail_in = (uInt)sizeof(a); // size of input
defstream.next_in = (Bytef *)a; // input char array
defstream.avail_out = (uInt)sizeof(b); // size of output
defstream.next_out = (Bytef *)b; // output char array

deflateInit(&defstream, Z_DEFAULT_COMPRESSION);
deflate(&defstream, Z_FINISH);
deflateEnd(&defstream);

printf("Deflate:\n%lu\n%s\n", strlen(b), b);

// inflate
// zlib struct
z_stream infstream;
infstream.zalloc = Z_NULL;
infstream.zfree = Z_NULL;
infstream.opaque = Z_NULL;
infstream.avail_in = (uInt)sizeof(b); // size of input
infstream.next_in = (Bytef *)b; // input char array
infstream.avail_out = (uInt)sizeof(c); // size of output
infstream.next_out = (Bytef *)c; // output char array

inflateInit(&infstream);
inflate(&infstream, Z_NO_FLUSH);
inflateEnd(&infstream);

printf("Inflate:\n%lu\n%s\n", strlen(c), c);

person Jane Watson    schedule 24.09.2011    source источник
comment
Вы спрашиваете, потому что это не работает? Вы получаете какое-то сообщение об ошибке?   -  person larsks    schedule 24.09.2011
comment
@larsks Компилируется без предупреждений, но я хочу знать, имеют ли смысл выбранные мной функции и определения или мне следует использовать другие.   -  person Jane Watson    schedule 24.09.2011
comment
Понятно. Спасибо за разъяснение вашего вопроса.   -  person larsks    schedule 24.09.2011


Ответы (3)


Вы не можете распечатать сдутый вывод таким образом. Это не завершается нулем. Вы не можете strlen это либо.

Поскольку ваш ввод представляет собой строку, вы, вероятно, хотите передать только содержимое строки, включая нулевой терминатор. Поэтому установите для avail_in значение strlen(a) + 1.

Вам нужно проверить поля next_out и avail_out после вызова deflate, чтобы увидеть, сколько данных было записано в выходной буфер.

См. документацию здесь по вызову deflate.

Вот ваш измененный код. Обратите внимание, что если вы сжимаете что-то, что не является строкой, вам нужно изменить это, а также строки, которые вы можете сжимать без завершающего нуля и добавлять его обратно после распаковки.

char a[50] = "Hello World!";
char b[50];
char c[50];

// deflate
// zlib struct
z_stream defstream;
defstream.zalloc = Z_NULL;
defstream.zfree = Z_NULL;
defstream.opaque = Z_NULL;
defstream.avail_in = (uInt)strlen(a)+1; // size of input, string + terminator
defstream.next_in = (Bytef *)a; // input char array
defstream.avail_out = (uInt)sizeof(b); // size of output
defstream.next_out = (Bytef *)b; // output char array

deflateInit(&defstream, Z_DEFAULT_COMPRESSION);
deflate(&defstream, Z_FINISH);
deflateEnd(&defstream);

// This is one way of getting the size of the output
printf("Deflated size is: %lu\n", (char*)defstream.next_out - b);

// inflate
// zlib struct
z_stream infstream;
infstream.zalloc = Z_NULL;
infstream.zfree = Z_NULL;
infstream.opaque = Z_NULL;
infstream.avail_in = (uInt)((char*)defstream.next_out - b); // size of input
infstream.next_in = (Bytef *)b; // input char array
infstream.avail_out = (uInt)sizeof(c); // size of output
infstream.next_out = (Bytef *)c; // output char array

inflateInit(&infstream);
inflate(&infstream, Z_NO_FLUSH);
inflateEnd(&infstream);

printf("Inflate:\n%lu\n%s\n", strlen(c), c);
person Guy Sirton    schedule 24.09.2011

В zlib уже есть простая функция надувания/дефляции, которую вы можете использовать.

char a[50] = "Hello, world!";
char b[50];
char c[50];

uLong ucompSize = strlen(a)+1; // "Hello, world!" + NULL delimiter.
uLong compSize = compressBound(ucompSize);

// Deflate
compress((Bytef *)b, &compSize, (Bytef *)a, ucompSize);

// Inflate
uncompress((Bytef *)c, &ucompSize, (Bytef *)b, compSize);

Если вы сомневаетесь, ознакомьтесь с руководством по zlib. Мой код дрянной, извините =/

person Yehia Hafez    schedule 19.05.2012
comment
+1, возможно, паршиво, но это указывает на отупляющее решение, которое всегда предпочтительнее. compress() и uncompress() - это самая простая форма, которую вы можете получить, и вы представляете ее более чем адекватно. - person WhozCraig; 25.06.2013
comment
Проблема с этим служебным методом заключается в том, что вам нужно как-то узнать размер сжатого содержимого... :/ - person Johannes; 01.03.2016
comment
В этом случае вы можете использовать sizeof() для несжатого содержимого. Это базовое использование методов compress() и uncompress(), что является хорошим началом, но есть и более эффективные методы. - person Yehia Hafez; 30.04.2016

Пример zpipe (http://zlib.net/zpipe.c) в значительной степени охватывает это, просто удалите файловые операции (функция с префиксом f) и замените in и out вашими буферами в памяти, хотя это может быть достаточно только заменить in или оставить буферы как есть, в зависимости от вашего использования. Просто обратите внимание, что вам нужно будет изменить размер буфера out, чтобы учесть распаковку данных произвольного размера, если вы планируете иметь фрагменты неизвестного размера.

person Necrolis    schedule 24.09.2011