Почему изменение порядка пакетов gzip повреждает вывод?

Я использую идею кода gzip, опубликованного в zlib. Для инициализации я использую deflateInit2(p_strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY). Я заархивирую поток. Каждый пакет с Z_FULL_FLUSH, кроме из последнего, который я использую Z_FINISH. После архивирования каждого пакета я переупорядочиваю пакеты.

данные в пакетах ---> [zip] ---> [изменение порядка] ---> ...

Если я раздую данные после архивирования, я получу точный файл перед архивированием. Если я раздую данные после переупорядочения пакетов (опять же: каждый пакет выкачивается с помощью Z_FULL_FLUSH, кроме последнего Z_FINISH), я получаю файл, который очень похож на исходный файл до сжатия. Разница в конце файла: в нем не хватает байтов. Это потому, что когда я его раздуваю, я получаю ошибку для последнего пакета (Z_DATA_ERROR). Если я раздую, скажем, кусками по 50 КБ, раздутый файл после переупорядочения будет тем же файлом, что и входной, меньше ‹ 50 КБ (весь последний пакет исчез из-за ошибки). Если я уменьшу размер фрагмента наполнения до 8 байт, я все равно получу Z_DATA_ERROR, но теперь я потеряю меньше данных при надувании (в моем примере мне не хватает одного байта из исходного файла).

Я не переупорядочиваю последний пакет (Z_FINISH). Я попытался отправить все пакеты с Z_FULL_FLUSH, а затем отправить еще один «пустой» пакет (только Z_FINISH, который составляет 10 байт).

Почему это происходит? Если я использую Z_FULL_FLUSH, почему нагнетатель не может правильно его надуть? помнит ли он порядок сдутых пакетов?

Любая информация поможет, спасибо.


person hudac    schedule 30.10.2013    source источник
comment
Почему у вас сложилось впечатление, что zip устойчив к переупорядочению пакетов?   -  person Raymond Chen    schedule 30.10.2013
comment
Это просто работает, я раздуваю файл, и он работает (кроме последнего фрагмента раздувания). И тут я понял, что за это отвечает Z_FULL_FLUSH...   -  person hudac    schedule 30.10.2013


Ответы (2)


Поскольку вы используете Z_FULL_FLUSH, который стирает историю при каждом сбросе, вы можете изменить порядок пакетов, кроме последнего. Пакет, который вы сделали Z_FINISH, должен быть последним пакетом. При этом никаких данных не требуется. Вы можете передать все свои данные из последнего пакета, используя Z_FULL_FLUSH, а затем сделать один последний пакет без входных данных и Z_FINISH. Это позволит вам переупорядочивать пакеты перед этим пустым, сколько вам угодно. Просто всегда имейте последний в конце.

Причина в том, что формат deflate является самозавершающимся, так что последняя часть отмечает конец потока. Если вы переупорядочите его где-нибудь посередине, то инфляция прекратится, когда он попадет в этот пакет.

Заголовок и трейлер gzip должны быть сохранены в начале и в конце, а CRC в трейлере обновлен соответствующим образом. Проверка CRC в конце зависит от порядка данных.

Почему вы пытаетесь делать то, что вы пытаетесь сделать? Что вы оптимизируете?

person Mark Adler    schedule 30.10.2013
comment
Спасибо, На самом деле я не переупорядочиваю последний пакет (забыл написать). Я также пытался отправить все пакеты с Z_FULL_FLUSH, а затем отправить последние данные (0 входных данных, 10 выходных данных gzip) - но это тоже не работает :\ ... - person hudac; 30.10.2013
comment
Я делаю переупорядочивание пакетов для оптимизации. - person hudac; 30.10.2013
comment
Так что теоретически кажется, что я не делаю ничего плохого, не так ли? Я не переупорядочиваю первый/последний пакет. Может ли информация, которую я предоставил ранее, помочь мне понять, что что-то в заголовках CRC/last gzip не подходит? (Входной файл и увеличенный выходной файл идентичны, за исключением нескольких байтов в конце последнего. Это количество байтов определяется размером фрагментов, которые я пытаюсь увеличить). Извините, это не совсем оптимизация. Я получаю каждый пакет от другого компонента не в том порядке, в котором я хочу его отправить, поэтому я переупорядочиваю его так, как хочу. - person hudac; 30.10.2013
comment
Сначала заставьте его работать с необработанным дефлированием, используя -15 вместо windowBits. Тогда вам не нужно беспокоиться о CRC. Затем, если вы правильно извлекаете все байты из deflate() после Z_FULL_FLUSH (вам нужно продолжать вызывать deflate(), пока он не вернет stream_avail != 0), переупорядочение пакетов, отличных от последнего пакета, должно быть надувным, снова используя -15 в inflateInit2(). - person Mark Adler; 30.10.2013
comment
Спасибо! Я попробую это, когда смогу, и скажу, сработало ли это. - person hudac; 31.10.2013
comment
К сожалению, опечатка в моем последнем комментарии - должно быть: пока не вернет stream->avail_out != 0. - person Mark Adler; 31.10.2013
comment
Это работает, но не очень помогает, потому что мне нужно windowBits иметь заголовок и трейлер gzip.. Add 16 to windowBits to write a simple gzip header and trailer around the compressed data - person hudac; 03.11.2013
comment
Хорошо! Зайти так далеко очень помогает. Теперь вы можете самостоятельно добавить заголовок и трейлер gzip. Заголовок 1f 8b 08 00 00 00 00 00 00 ff будет работать. Завершающий элемент представляет собой два четырехбайтовых значения, записанных в порядке прямого байта. Первый — это CRC-32, который вы можете рассчитать с помощью функции crc32() в zlib. Вы должны передать ему несжатое содержимое ваших пакетов в том порядке, в котором они появляются в потоке gzip. Вторые четыре байта — это общая несжатая длина (по модулю 2^32, если больше 4 ГБ). Тогда у вас есть поток gzip. - person Mark Adler; 03.11.2013
comment
Спасибо! На самом деле я нашел, куда заархивировать данные после переупорядочения. Я попробую ваше решение позже! - person hudac; 10.11.2013

GZip — это потоковый протокол. Сжатие зависит от предыдущей истории потока. Вы не можете изменить порядок.

person user207421    schedule 30.10.2013
comment
В этом случае вы можете изменить его порядок. Целью Z_FULL_FLUSH является обеспечение точек останова в потоке. - person Mark Adler; 30.10.2013