Я пытаюсь использовать zlib для распаковки (раздувания) некоторых полезных данных IP-пакетов, которые сжимаются с помощью gzip. Тем не менее, у меня есть некоторые трудно понять некоторые документы, предоставляемые zlib, которые охватывают инфляцию. У меня есть массив символов, который заполняет моя программа, но я не могу надуть его следующим кодом:
const u_char payload; /*contains gzip data,
captured prior to this point in the program*/
/*read compressed contents*/
int ret; //return val
z_stream stream;
unsigned char out[MEM_CHUNK]; //output array, MEM_CHUNK defined as 65535
/* allocate inflate state */
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
stream.avail_in = size_payload; // size of input
stream.next_in = (Bytef *)payload; // input char array
stream.avail_out = (uInt)sizeof(out); // size of output
stream.next_out = (Bytef *)out; // output char array
ret = inflateInit(&stream);
inflate(&stream, Z_NO_FLUSH);
inflateEnd(&stream);
printf("Inflate: %s\n\n", out);
в документация zlib, они постоянно раздуваются с помощью цикла do / while, проверяя наличие флага Z_STREAM_END. Я немного запутался здесь, потому что кажется, что они работают из файла, а я нет. Нужен ли мне этот цикл, или я могу предоставить массив символов без зацикливания на inflate?
Любое руководство здесь будет по достоинству оценено. Я довольно новичок в работе со сжатием и C ++.
Благодарю.
Предполагая, что вы даете inflate
соответствующий и полный «сжатый поток», и достаточно места для вывода данных, вам нужно всего лишь вызвать inflate
один раз.
Изменить: это не написано так четко, как в документация zlib, но он говорит:
inflate
распаковывает как можно больше данных и останавливается, когда
входной буфер становится пустым или выходной буфер заполнен. Это может
ввести некоторую задержку вывода (чтение ввода без производства каких-либо
вывод) кроме случаев, когда принудительно смывает.
Конечно, для любого потока, который еще не «находится в памяти и завершен», вы хотите запускать его блок за блоком, так как он будет иметь меньшее общее время выполнения (вы можете распаковать его во время получения данных [из сети или файловой системы). предварительное получение кэширования] для следующего блока).
Вот вся функция из вашего примера кода. Я удалил текстовые компоненты со страницы, чтобы сконцентрировать код, и пометил разделы буквами // A
, // B
и т. д., затем отметили, пытались объяснить разделы ниже.
int inf(FILE *source, FILE *dest)
{
int ret;
unsigned have;
z_stream strm;
unsigned char in[CHUNK]; // A
unsigned char out[CHUNK];
/* allocate inflate state */
strm.zalloc = Z_NULL; // B
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm); // C
if (ret != Z_OK)
return ret;
/* decompress until deflate stream ends or end of file */
do {
strm.avail_in = fread(in, 1, CHUNK, source); // D
if (ferror(source)) {
(void)inflateEnd(&strm); // E
return Z_ERRNO;
}
if (strm.avail_in == 0) // F
break;
strm.next_in = in; // G/* run inflate() on input until output buffer not full */
do {
strm.avail_out = CHUNK; // H
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH); // I
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
switch (ret) {
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return ret;
}
have = CHUNK - strm.avail_out; // J
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
(void)inflateEnd(&strm);
return Z_ERRNO;
}
} while (strm.avail_out == 0); // K
/* done when inflate() says it's done */
} while (ret != Z_STREAM_END); // L
/* clean up and return */
(void)inflateEnd(&strm);
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
: in
является входным буфером (мы читаем из файла в этот буфер, а затем передаем его inflate
Некоторое время спустя out
это выходной буфер, который используется inflate
хранить выходные данные.
В: Настроить z_stream
объект называется strm
, Это содержит различные поля, большинство из которых здесь не важны (таким образом, установлено значение Z_NULL). Важными из них являются avail_in
а также next_in
так же как avail_out
а также next_out
(которые устанавливаются позже).
С: Начать процесс инфляции. Это устанавливает некоторые внутренние структуры данных и просто делает inflate
сама функция «готова к запуску».
DСчитать объем данных из файла. Сохранить количество прочитанных байтов в strm.avail_in
и фактические данные входят в in
,
Е: Если мы ошиблись, закончите inflate
позвонив inflateEnd
, Работа выполнена.
F: Нет данных, мы закончили.
г: Установить, откуда поступают наши данные (next_in
установлен на входной буфер, in
).
ЧАС: Мы сейчас находимся в цикле, чтобы раздуть вещи. Здесь мы устанавливаем выходной буфер: next_out
а также avail_out
указать, куда выводится и сколько места там, соответственно.
я: Вызов inflate
сам. Это распакует часть входного буфера, пока вывод не будет заполнен.
J: Подсчитать, сколько данных доступно на этом шаге (have
количество байтов).
К: Пока у нас не осталось места, когда inflate
готово — это означает, что вывод завершен для данных в in
буфер, а не из свободного места в буфере выхода. Пришло время прочитать еще данные из входного файла.
L: Если код ошибки от inflate
Звонок «счастлив», иди снова.
Теперь, очевидно, если вы читаете из сети и распаковываете в память, вам нужно заменить fread
а также fwrite
с некоторыми подходящими read from network
а также memcpy
вместо этого введите звонки. Я не могу точно сказать вам, что это такое, так как вы не предоставили ничего, чтобы объяснить, откуда ваши данные — вы звоните recv
или же read
или же WSARecv
, или что-то другое? — и куда это идет?
Других решений пока нет …