Ошибка распаковки данных gzip с использованием Qt - PullRequest
2 голосов
/ 21 апреля 2011

Я распаковываю данные gzip, полученные с http-сервера, используя библиотеку zlib из Qt. Поскольку qUncompress был бесполезен, я следовал приведенному здесь совету: Qt quncompress gzip data и создал свой собственный метод для распаковки данных gzip, например:

 QByteArray gzipDecompress( QByteArray compressData )
 {
    //strip header
    compressData.remove(0, 10);

    const int buffer_size = 16384;
    quint8 buffer[buffer_size];

    z_stream cmpr_stream;
    cmpr_stream.next_in = (unsigned char *)compressData.data();
    cmpr_stream.avail_in = compressData.size();
    cmpr_stream.total_in = 0;

    cmpr_stream.next_out = buffer;
    cmpr_stream.avail_out = buffer_size;
    cmpr_stream.total_out = 0;

    cmpr_stream.zalloc = Z_NULL;
    cmpr_stream.zfree = Z_NULL;
    cmpr_stream.opaque = Z_NULL;

    int status = inflateInit2( &cmpr_stream, -8 );
    if (status != Z_OK) {
        qDebug() << "cmpr_stream error!";
    }

    QByteArray uncompressed;
    do {
        cmpr_stream.next_out = buffer;
        cmpr_stream.avail_out = buffer_size;

        status = inflate( &cmpr_stream, Z_NO_FLUSH );

        if (status == Z_OK || status == Z_STREAM_END)
        {
            QByteArray chunk = QByteArray::fromRawData((char *)buffer, buffer_size - cmpr_stream.avail_out);
            uncompressed.append( chunk );
        }
        else
        {
            inflateEnd(&cmpr_stream);
            break;
        }

        if (status == Z_STREAM_END)
        {
            inflateEnd(&cmpr_stream);
            break;
        }
    }
    while (cmpr_stream.avail_out == 0);

    return uncompressed;
 }

Кажется, что Eveything работает нормально, если распакованные данные помещаются в выходной буфер (т. Е. Меньше 16 КБ). Если этого не произойдет, второй вызов Inflate возвращает Z_DATA_ERROR. Я точно знаю, что данные верны, потому что одна и та же порция данных правильно распаковывается, если выходной буфер сделан достаточно большим.

Сервер не возвращает заголовок с размером несжатых данных (только размер сжатых данных), поэтому я следовал инструкциям по использованию в zlib: http://www.zlib.net/zlib_how.html

И они делают именно то, что я делаю. Есть идеи, чего мне не хватать? члены next_in и util_in в потоке корректно обновляются после первой итерации. О, и если это полезно, сообщение об ошибке при выдаче ошибки данных: «неверное расстояние слишком далеко назад».

Есть мысли? Спасибо.

1 Ответ

3 голосов
/ 21 апреля 2011

В алгоритме сжатия / распаковки Deflate / Inflate используется кольцевой буфер размером 32 КБ. Таким образом, буфер 16 КБ никогда не сможет работать, если распакованные данные больше 16 КБ. (Не совсем так, потому что данные могут быть разделены на блоки, но вы должны предположить, что там могут быть блоки по 32 КБ.) Так что просто установите buffer_size = 32768 и все будет в порядке.

...