Comment gonfler un fichier zlib partiel

J’ai les premiers 2/3 contigus d’un fichier qui a été compressé avec la fonction deflate () de zlib. Le dernier tiers a été perdu en transmission. Le fichier original non compressé faisait 600 Ko.

Deflate a été appelé plusieurs fois par l’émetteur lors de la découpe du fichier d’origine en morceaux de 2 Ko et en transmettant Z_NO_FLUSH jusqu’à la fin du fichier lorsque Z_FINISH a été transmis. Le fichier compressé complet résultant a été transmis, mais partiellement perdu comme décrit.

Est-il possible de récupérer une partie du fichier d’origine? Si oui, des suggestions sur comment?

J’utilise à la fois l’implémentation C simple de ZLIB et / ou l’implémentation Python 2.7 de ZLIB.

Bien que je ne connaisse pas le python, j’ai réussi à le faire fonctionner:

#!/usr/bin/python import sys import zlib f = open(sys.argv[1], "rb") g = open(sys.argv[2], "wb") z = zlib.decompressobj() while True: buf = z.unconsumed_tail if buf == "": buf = f.read(8192) if buf == "": break got = z.decompress(buf) if got == "": break g.write(got) 

Cela devrait extraire tout ce qui est disponible dans votre fichier zlib partiel.

Mise à jour: Comme l’a souligné @Mark Adler ; le contenu partiel peut être décompressé à l’aide de zlib.decompressobj :

 >>> decompressor = zlib.decompressobj() >>> decompressor.decompress(part) "let's compress some t" 

part est défini ci-dessous.

— Ancien commentaire suit:

Par défaut, zlib ne gère pas le contenu partiel en Python.

Cela marche:

 >>> compressed = "let's compress some text".encode('zip') >>> compressed 'x\x9c\xcbI-Q/VH\xce\xcf-(J-.V(\xce\xcfMU(I\xad(\x01\x00pX\t%' >>> compressed.decode('zip') "let's compress some text" 

Cela ne marche pas si on le tronque:

 >>> part = compressed[:3*len(compressed)/4] >>> part.decode('zip') Traceback (most recent call last): File "", line 1, in  File ".../lib/python2.7/encodings/zlib_codec.py", lin e 43, in zlib_decode output = zlib.decompress(input) error: Error -5 while decompressing data: incomplete or truncated stream 

La même chose si nous utilisons explicitement zlib :

 >>> import zlib >>> zlib.decompress(compressed) "let's compress some text" >>> zlib.decompress(part) Traceback (most recent call last): File "", line 1, in  error: Error -5 while decompressing data: incomplete or truncated stream 

Ce qui suit semble théoriquement faisable mais nécessite de bricoler avec les routines de bas niveau zlib pour fonctionner. Dans http://www.zlib.net/zlib_how.html, nous trouvons un exemple de programme zpipe.c , et dans sa description ligne par ligne:

CHUNK est simplement la taille de la mémoire tampon pour alimenter et extraire des données des routines zlib. Des tailles de mémoire tampon plus grandes seraient plus efficaces, en particulier pour inflate (). Si la mémoire est disponible, des tailles de mémoire tampon de l’ordre de 128 Ko ou 256 Ko doivent être utilisées.

 #define CHUNK 16384 ... 

Voici ma suggestion: Vous définissez le tampon très petit – si pris en charge, peut-être même sur un seul octet. De cette façon, vous pourrez décompresser autant que possible jusqu’à l’inévitable Z_BUF_ERROR . À ce stade, on supprime généralement les données collectées (recherchez les appels deflate_end qui “nettoient” derrière votre dos), mais dans votre cas, vous pouvez simplement visionner un fichier et le fermer lorsque vous constatez que vous ne pouvez plus continuer.

Les derniers octets de la sortie peuvent contenir une thrash si le mauvais symbole “final” a été décodé, ou zlib peut abandonner prématurément, plutôt que de générer un symbole partiel. Mais vous savez de toute façon que vos données seront incomplètes, cela ne devrait donc pas poser de problème.