Сжать распакованную строку с помощью zlib - PullRequest
0 голосов
/ 04 апреля 2019

У меня есть закодированная строка, которую мне удалось декодировать, не зная, как она была закодирована изначально.Вот как мне удалось декодировать:

original_str = "LONG_SNIP" # Is clearly a base64 string
decoded_str = base64.b64decode(original_str) # Becomes unreadable mess
decompressed_str = zlib.decompress(decoded_str, -15) # Plain text, success

Я хотел бы отметить, что аргумент zlib '-15' является обязательным (все работает между -8 и -15)

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

Я проверил документацию по zlib и попробовал zlib.compress,а также создание compressobj и попытки сжатия с ним, но безуспешно.

Кажется, что значение '-15' не может быть введено ни в одну функцию, чтобы отменить декомпрессию, которую я делал изначально.

Это то, что я тоже пробовал, но я получаю пустой вывод:

compress = zlib.compressobj( 1, zlib.DEFLATED, -15, zlib.DEF_MEM_LEVEL, 0 ) 
deflated = compress.compress(string_to_compress)
encoded = base64.b64encode(deflated)
print(encoded)

ВОПРОСЫ:

Что означает целочисленный параметр и почему все значения между -8 и -15 дают одинаковый точный результат?

И что еще более важно, как я могу отменить декомпрессию?

Ответы очень ценятся, спасибо!

1 Ответ

1 голос
/ 05 апреля 2019

Второй параметр zlib.decompress() - это аргумент wbits . Из документации :

Параметр wbits контролирует размер буфера истории (или «размер окна»), а также ожидаемый формат заголовка и трейлера. Он похож на параметр для compressobj(), но допускает большее количество диапазонов значений:

  • [...]
  • −8 до −15: в качестве логарифма размера окна используется абсолютное значение wbit. Входными данными должен быть необработанный поток без заголовка или трейлера.
  • [...]

При распаковке потока размер окна не должен быть меньше размера, первоначально использовавшегося для сжатия потока; использование слишком маленького значения может привести к исключению error.

Отрицательные значения просто означают, что в потоке данных нет заголовка или трейлера.

Так что, если какое-либо значение между -8 и -15 работает, размер окна при сжатии был довольно мал для начала. Большие размеры окна требуют больше памяти для большего буфера истории, но ускоряют распаковку. Единственное требование состоит в том, чтобы он был равен или больше, чем тот, который использовался для сжатия данных, потому что иначе ссылки на предыдущие блоки данных, используемые в потоке сжатия, больше не могут быть найдены (я думаю, я уверен, Марк Адлер поправит меня, если я ошибаюсь).

Руководство zlib , похоже, предполагает, что wbits=8 будет фактически автоматически заменено на wbits=9, и, вероятно, то же самое произойдет с -8.

Это переводит в zlib.compresobj() вбит значения между -9 и -15; из документации снова:

  • −9 до −15: в качестве логарифма размера окна используется абсолютное значение wbit, при этом создается необработанный выходной поток без заголовка или конечной контрольной суммы.

Сжатия с наименьшим размером окна должно быть достаточно:

compressor = zlib.compressobj(-1, zlib.DEFLATED, -9)
compressed = compressor.compress(data_to_compress) + compressor.flush()

Демо-версия:

>>> import zlib
>>> compressor = zlib.compressobj(-1, zlib.DEFLATED, -9)
>>> compressor.compress('foo bar baz') + compressor.flush()
'K\xcb\xcfWHJ,\x02\xe2*\x00'
>>> zlib.decompress(_, -8)
'foo bar baz'
...