web-dev-qa-db-fra.com

Comment décompresser les données zlib sous UNIX?

J'ai créé des données compressées zlib en Python, comme ceci:

import zlib
s = '...'
z = zlib.compress(s)
with open('/tmp/data', 'w') as f:
    f.write(z)

(ou one-liner dans Shell: echo -n '...' | python2 -c 'import sys,zlib; sys.stdout.write(zlib.compress(sys.stdin.read()))' > /tmp/data)

Maintenant, je veux décompresser les données dans Shell. Ni zcat ni uncompress ne fonctionnent:

$ cat /tmp/data | gzip -d -
gzip: stdin: not in gzip format

$ zcat /tmp/data 
gzip: /tmp/data.gz: not in gzip format

$ cat /tmp/data | uncompress -
gzip: stdin: not in gzip format

Il semble que j'ai créé un fichier de type gzip, mais sans en-tête. Malheureusement, je ne vois aucune option pour décompresser ces données brutes dans la page de manuel de gzip, et le paquet zlib ne contient aucun utilitaire exécutable.

Existe-t-il un utilitaire pour décompresser les données zlib brutes?

121
mykhal

Il est également possible de le décompresser en utilisant le standard Shell-script + gzip , si vous n'en avez pas, ou souhaitez utiliser openssl ou autre outils.
L'astuce consiste à ajouter le nombre magique gzip et méthode de compression aux données réelles de zlib.compress:

printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" |cat - /tmp/data |gzip -dc >/tmp/out

Modifications:
@ d0sboots a commenté: Pour les données RAW Deflate, vous devez ajouter 2 octets nuls supplémentaires:
"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x00"

Ce Q sur SO donne plus d'informations sur cette approche. Une réponse suggère qu'il existe également un pied de page de 8 octets.

Les utilisateurs @ Vitali-Kushner et @ mark-bessey ont rapporté le succès même avec des fichiers tronqués, donc un pied de page gzip ne semble pas strictement requis.

@ tobias-kienzler a proposé cette fonction pour bashrc :
zlipd() (printf "\x1f\x8b\x08\x00\x00\x00\x00\x00" |cat - $@ |gzip -dc)

146
wkpark
zlib-flate -uncompress < FILE

J'ai essayé cela et cela a fonctionné pour moi.

zlib-flate peut être trouvé dans le paquet qpdf (dans Debian Squeeze et Fedora 23, selon les commentaires dans d'autres réponses)

(Merci à l'utilisateur @tino qui a fourni ceci en tant que commentaire sous la réponse OpenSSL. Fabriqué en réponse propper pour un accès facile.)

81
Catskul

J'ai trouvé une solution (l'une des possibles), elle utilise openssl:

$ openssl zlib -d < /tmp/data

ou

$ openssl zlib -d -in /tmp/data

* REMARQUE: la fonctionnalité zlib est apparemment disponible dans les versions récentes d'OpenSL> = 1.0.0 (OpenSSL doit être configuré/construit avec l'option zlib ou zlib-dynamic, cette dernière est par défaut)

63
mykhal

Je recommande pigz de Mark Adler , co-auteur de la bibliothèque de compression zlib. Exécutez pigz pour voir les indicateurs disponibles.

Tu remarqueras:

-z --zlib Compress to zlib (.zz) instead of gzip format.

Vous pouvez décompresser en utilisant le -d drapeau:

-d --decompress --uncompress Decompress the compressed input.

En supposant un fichier nommé 'test':

  • pigz -z test - crée un fichier compressé zlib nommé test.zz
  • pigz -d -z test.zz - convertit test.zz en fichier de test décompressé

Sur OSX, vous pouvez exécuter brew install pigz

30
snodnipper

zlib implémente la compression utilisée par gzip, mais pas le format de fichier. Au lieu de cela, vous devez utiliser le module gzip , qui utilise lui-même zlib.

import gzip
s = '...'
with gzip.open('/tmp/data', 'w') as f:
    f.write(s)
11
Jeremy Banks

Cela pourrait le faire:

import glob
import zlib
import sys

for filename in sys.argv:
    with open(filename, 'rb') as compressed:
        with open(filename + '-decompressed', 'wb') as expanded:
            data = zlib.decompress(compressed.read())
            expanded.write(data)

Ensuite, exécutez-le comme ceci:

$ python expander.py data/*
3
Jeremy Banks

Sur macOS, qui est un UNIX complet compatible POSIX (officiellement certifié!), OpenSSL ne prend pas en charge zlib, il n'y a pas non plus zlib-flate Et même si la première solution fonctionne également comme toutes les solutions Python, la première solution nécessite que les données Zip soient dans un fichier et toutes les autres solutions vous obligent à créer un script Python.

Voici une solution basée sur Perl qui peut être utilisée comme une ligne de commande, obtient son entrée via un tuyau STDIN et qui fonctionne immédiatement avec un macOS fraîchement installé:

cat file.compressed | Perl -e 'use Compress::Raw::Zlib;my $d=new Compress::Raw::Zlib::Inflate();my $o;undef $/;$d->inflate(<>,$o);print $o;'

Mieux formaté, le script Perl ressemble à ceci:

use Compress::Raw::Zlib;
my $decompressor = new Compress::Raw::Zlib::Inflate();
my $output;
undef $/;
$decompressor->inflate(<>, $output);
print $output;
3
Mecki

L'exemple de programme zpipe.ctrouvé ici par Mark Adler lui-même (fourni avec la distribution source de la bibliothèque zlib) est très utile pour ces scénarios avec des données zlib brutes. Compiler avec cc -o zpipe zpipe.c -lz et pour décompresser: zpipe -d < raw.zlib > decompressed. Il peut également effectuer la compression sans le -d drapeau.

3
Henno Brandsma

Vous pouvez l'utiliser pour compresser avec zlib:

openssl enc -z -none -e < /file/to/deflate

Et ceci pour dégonfler:

openssl enc -z -none -d < /file/to/deflate
1
Danny R

Pendant le développement du code lié à eIDAS, j'ai trouvé un script bash, qui décode le paramètre SAMLRequest SSO (SingleSignOn), qui est généralement codé par base64 et raw-deflate (php gzdeflate)

#!/bin/bash
# file decode_saml_request.sh

urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }

if [[ $contents == *"SAMLRequest" ]]; then
  # extract param SAMLRequest from URL, strip all following params
  contents=$(cat ${1} | awk -F 'SAMLRequest=' '{print $2}' | awk -F '&' '{print $1}')
else
  # work with raw base64 encoded string
  contents=$(cat ${1})
fi

# add gzip raw-deflate header bytes and gunzip (`gzip -dc` can be replaced by `gunzip`)
printf "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x00" | cat - <(echo `urldecode $contents` | base64 -d) | gzip -dc

Vous pouvez l'utiliser comme

> decode_saml_request.sh /path/to/file_with_sso_url
# or
> echo "y00tLk5MT1VISSxJBAA%3D" | decode_saml_request.sh

Le script est également publié sous le nom de Gist ici: https://Gist.github.com/smarek/77dacb9703ac8b715b5eced5314d5085 donc je ne peux pas maintenir cette réponse mais je maintiendrai le Gist source

0
Marek Sebera