Domanda

Io sono l'interfacciamento con un server che richiede che i dati inviati ad esso è compresso con Deflate algoritmo (Huffman codifica + LZ77) e invia i dati che ho bisogno di gonfiare .

So che Python include Zlib, e che le librerie C di chiamate di assistenza Zlib a gonfiare e Deflate , ma questi a quanto pare non sono forniti dal modulo Python zlib. Esso fornisce Compress e Decompress , ma quando faccio una chiamata come il seguente:

result_data = zlib.decompress( base64_decoded_compressed_string )

ricevo il seguente errore:

Error -3 while decompressing data: incorrect header check

Gzip meglio fa; quando si effettua una chiamata come ad esempio:

result_data = gzip.GzipFile( fileobj = StringIO.StringIO( base64_decoded_compressed_string ) ).read()

ricevo l'errore:

IOError: Not a gzipped file

che ha un senso in quanto i dati è un Sgonfiato file non un vero e proprio Gzipped file.

Ora so che c'è un Deflate implementazione disponibili (Pyflate), ma non so di un gonfiare implementazione.

Sembra che ci sono alcune opzioni:

  1. Trova un'implementazione esistente (ideale) di gonfiare e Deflate in Python
  2. Scrivi la mia estensione Python alla libreria zlib c che comprende gonfiare e Deflate
  3. Chiama un'altra cosa che può essere eseguito da linea di comando (ad esempio uno script Ruby, dal momento che gonfiare / Deflate chiamate in zlib sono completamente avvolti in Ruby)

Sto cercando una soluzione, ma manca una soluzione sarò grato per approfondimenti, opinioni costruttive, e le idee.

Ulteriori informazioni : Il risultato di sgonfiamento (e codifica) una stringa deve, ai fini ho bisogno, dare lo stesso risultato come il seguente frammento di codice C #, in cui il parametro di ingresso è un array di byte UTF corrispondente ai dati per comprimere:

public static string DeflateAndEncodeBase64(byte[] data)
{
    if (null == data || data.Length < 1) return null;
    string compressedBase64 = "";

    //write into a new memory stream wrapped by a deflate stream
    using (MemoryStream ms = new MemoryStream())
    {
        using (DeflateStream deflateStream = new DeflateStream(ms, CompressionMode.Compress, true))
        {
            //write byte buffer into memorystream
            deflateStream.Write(data, 0, data.Length);
            deflateStream.Close();

            //rewind memory stream and write to base 64 string
            byte[] compressedBytes = new byte[ms.Length];
            ms.Seek(0, SeekOrigin.Begin);
            ms.Read(compressedBytes, 0, (int)ms.Length);
            compressedBase64 = Convert.ToBase64String(compressedBytes);
        }
    }
    return compressedBase64;
}

L'esecuzione di questo codice di .NET per la stringa "sgonfiare e mi codificare" dà il risultato

7b0HYBxJliUmL23Ke39K9UrX4HShCIBgEyTYkEAQ7MGIzeaS7B1pRyMpqyqBymVWZV1mFkDM7Z28995777333nvvvfe6O51OJ/ff/z9cZmQBbPbOStrJniGAqsgfP358Hz8iZvl5mbV5mi1nab6cVrM8XeT/Dw==

Quando "sgonfiare e mi codificare" è gestito attraverso il Python Zlib.compress () e poi Base64 codificato, il risultato è "eJxLSU3LSSxJVUjMS1FIzUvOT0lVyE0FAFXHB6k =".

E 'chiaro che zlib.compress () non è un'implementazione dello stesso algoritmo come algoritmo Deflate standard.

Ulteriori informazioni :

I primi 2 byte del NET sgonfiare dati ( "7b0HY ..."), dopo la decodifica b64 sono 0xEDBD, che non corrisponde ai dati Gzip (0x1f8b), dati bzip2 (0x425A), o Zlib (0x789C) i dati.

I primi 2 byte dei dati compressi Python ( "eJxLS ..."), dopo la decodifica b64 sono 0x789C. Questo è un colpo di testa zlib.

RISOLTO

Per gestire la sgonfiare grezzo e gonfiare, senza intestazione e checksum, le seguenti cose necessarie per accadere:

deflate / compressa. Nudo i primi due byte (intestazione) e gli ultimi quattro byte (checksum)

On gonfiare / decompressione: c'è un secondo argomento per la dimensione della finestra. Se il valore è negativo sopprime le intestazioni. qui sono i miei metodi attualmente, tra cui la codifica Base64 / decodifica - e funziona correttamente:

import zlib
import base64

def decode_base64_and_inflate( b64string ):
    decoded_data = base64.b64decode( b64string )
    return zlib.decompress( decoded_data , -15)

def deflate_and_base64_encode( string_val ):
    zlibbed_str = zlib.compress( string_val )
    compressed_string = zlibbed_str[2:-4]
    return base64.b64encode( compressed_string )
È stato utile?

Soluzione

Questo è un add-on per la risposta di MizardX, dando qualche spiegazione e lo sfondo.

http : //www.chiramattel.com/george/blog/2007/09/09/deflatestream-block-length-does-not-match.html

Secondo RFC 1950 , un flusso zlib costruito nel modo predefinito è composto di :

  • un'intestazione 2-byte (ad esempio 0x78 0x9C)
  • un flusso di sgonfiare - vedi RFC 1951
  • un checksum Adler-32 dei dati non compressi (4 byte)

Il C # DeflateStream funziona su (avete indovinato) un flusso di sgonfiare. il codice di MizardX sta dicendo il modulo zlib che i dati è un flusso sgonfiare crudo.

Osservazioni: (1) Si spera metodo C # "sgonfiaggio" produrre una stringa più verifica solo con brevi input (2) utilizzando il flusso sgonfiare prima senza il checksum Adler-32? Po 'rischioso, a meno che non sostituito con qualcosa di meglio.

Aggiornamenti

messaggio di errore Block length does not match with its complement

Se si sta tentando di gonfiare alcuni dati compressi con il C # DeflateStream e si ottiene quel messaggio, allora è molto probabile che si stanno dando un un flusso zlib, non un flusso di sgonfiare.

Come si usa un DeflateStream da parte di un file?

Copia Inoltre / incolla il messaggio di errore in una ricerca su Google e si ottengono numerosi successi (tra cui quella la parte anteriore di questa risposta), dicendo più o meno la stessa cosa.

Deflater ... utilizzato dal "sito" ... C # DeflateStream "è piuttosto semplice ed è stato testato contro l'implementazione Java". Quale dei seguenti possibili costruttori Java Deflater è il sito web utilizzando?

  

public Deflater(int level, boolean nowrap)

     

Crea un nuovo compressore utilizzando il livello di compressione specificata. Se 'nowrap' è vero allora l'intestazione ZLIB e campi di checksum non saranno utilizzati al fine di supportare il formato di compressione utilizzato sia in GZIP e PKZIP.

     

public Deflater(int level)

     

Crea un nuovo compressore utilizzando il livello di compressione specificata. dati compressi saranno generati in formato ZLIB.

     

public Deflater()

     

Crea un nuovo compressore con il livello di compressione di default. dati compressi saranno generati in formato zlib.

A una linea deflater dopo gettare via l'intestazione zlib 2 byte e il checksum a 4 byte:

uncompressed_string.encode('zlib')[2:-4] # does not work in Python 3.x

o

zlib.compress(uncompressed_string)[2:-4]

Altri suggerimenti

È comunque possibile utilizzare la zlib modulo di gonfiare / sgonfiare i dati. Il gzip modulo utilizza internamente, ma aggiunge un file di intestazione di farne un gzip-file. Guardando il file gzip.py , qualcosa di simile potrebbe funzionare:

import zlib

def deflate(data, compresslevel=9):
    compress = zlib.compressobj(
            compresslevel,        # level: 0-9
            zlib.DEFLATED,        # method: must be DEFLATED
            -zlib.MAX_WBITS,      # window size in bits:
                                  #   -15..-8: negate, suppress header
                                  #   8..15: normal
                                  #   16..30: subtract 16, gzip header
            zlib.DEF_MEM_LEVEL,   # mem level: 1..8/9
            0                     # strategy:
                                  #   0 = Z_DEFAULT_STRATEGY
                                  #   1 = Z_FILTERED
                                  #   2 = Z_HUFFMAN_ONLY
                                  #   3 = Z_RLE
                                  #   4 = Z_FIXED
    )
    deflated = compress.compress(data)
    deflated += compress.flush()
    return deflated

def inflate(data):
    decompress = zlib.decompressobj(
            -zlib.MAX_WBITS  # see above
    )
    inflated = decompress.decompress(data)
    inflated += decompress.flush()
    return inflated

Non so se questo corrisponde esattamente a ciò che il server richiede, ma queste due funzioni sono in grado di andata e ritorno tutti i dati che ho provato.

I parametri mappe direttamente a ciò che viene passato alle funzioni di libreria zlib.

Python C
zlib.compressobj(...)deflateInit(...)
compressobj.compress(...)deflate(...)
zlib.decompressobj(...)inflateInit(...)
decompressobj.decompress(...)inflate(...)

I costruttori creano la struttura e popolarlo con i valori di default, e passarlo insieme alle init-funzioni. I metodi compress / decompress aggiornare la struttura e passarlo al inflate / deflate.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top