Нахождение конца сжатого потока zlib - PullRequest
2 голосов
/ 28 октября 2009

Я работаю на клиенте NMDC (p2p, DC ++ и друзья) с Qt. Сам протокол довольно прост:

$command parameters|

За исключением сжатия :

"ZPipe работает, посылая команду $ ZOn | клиенту. После $ ZOn последует сжатый поток ZLib, содержащий команды. Этот поток завершится EOF, который определяет ZLib. (В сжатом потоке нет $ ZOff !) "

Вот соответствующий код:

QTcpSocket *conn;
bool compressed;
QByteArray zbuffer;
QByteArray buffer;

// ...

void NMDCConnection::on_conn_readyRead() {
    // this gets called whenever we get new data from the hub

    if(compressed) {            // gets set when we receive $ZOn
        zbuffer.append(conn->readAll());


        // Magic happens here


        if( stream_is_complete ) {
            buffer.append(uncompressed_stream);
            buffer.append(remainder_of_data);
            compressed = false;
        }
    } else { 
        buffer.append(conn->readAll());
    };
    parse(buffer);
}

Итак, как мне получить значения для stream_is_complete, uncompressed_stream и remainder_of_data? Я не могу найти следующий «$», потому что поток может содержать его. Я попытался найти что-то похожее на EOF в документации zlib, но на самом деле такого не бывает, каждый поток заканчивается на первый взгляд случайным символом.

Я также играл с qUncompress (), но для этого нужен полный поток, ни меньше, ни больше.

Ответы [ 2 ]

1 голос
/ 28 октября 2009

Вы используете zlib напрямую?

Полностью не проверено ...

z_stream zstrm;
QByteArray zout;
// when you see a $ZOn|, initialize the z_stream struct
parse() {
    ...
    if (I see a $ZOn|) {
        zstrm.next_in = Z_NULL;
        zstrm.avail_in = 0;
        zstrm.zalloc = Z_NULL;
        zstrm.zfree = Z_NULL;
        zstrm.opaque = 0;
        inflateInit(&zstrm);
        compressed = true;
    }
}
void NMDCConnection::on_conn_readyRead() {
    if (compressed) {
        zbuffer.append(conn->readAll());
        int rc;
        do {
            zstrm.next_in = zbuffer.data();
            zstrm.avail_in = zbuffer.size();
            zout.resize(zstrm.total_out + BLOCK_SIZE);
            zstrm.next_out = zout.data() + zstrm.total_out;
            zstrm.avail_out = BLOCK_SIZE;
            rc = inflate(&zstrm, Z_SYNC_FLUSH);
            zbuffer.remove(0, zstrm.next_in - zbuffer.data());
        } while (rc == Z_OK && zstrm->avail_out == 0);
        if (rc == Z_STREAM_END) {
            zout.truncate(zstrm.total_out);
            buffer.append(zout);
            zout.clear();
            buffer.append(zbuffer);
            zbuffer.clear();
            compress = false;
            inflateEnd(&zstrm);
        }
        else if (rc != Z_OK) {
            // ERROR!  look at zstrm.msg
        }
    }
    else // whatever
}

Это постепенно распаковывает (раздувает) с qbuffer до qout и останавливается, когда inflate говорит "не более".

Может быть, лучше взять взаймы у QuaZip .

0 голосов
/ 28 октября 2009

Конец файла не является особенным для zlib. Проблема, которую я вижу с вашим кодом, заключается в том, что вы используете «readAll ()», который на самом деле не имеет никаких средств для сообщения об «ошибках», таких как конец файла.

Вы должны попытаться использовать "read ()" вместо этого в цикле. Если вы читаете поток и он возвращает 0 байтов, вы можете быть уверены, что достигли конца потока (другой конец закрыл соединение). Буфер, который вы прочитали, объединяющий все предыдущие «чтения» в цикле, даст вам полный буфер.

...