Domanda

Sto lavorando su un client NMDC (p2p, DC ++ e amici) con Qt. Il protocollo stesso è piuttosto semplice:

$command parameters|

Tranne compressione :

  

" ZPipe funziona inviando un comando $ ZOn | al cliente. Dopo $ ZOn seguirà un flusso compresso ZLib contenente comandi. Questo flusso terminerà con un EOF definito da ZLib. (non c'è $ ZOff nello stream compresso!) "

Ecco il codice pertinente:

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);
}

Quindi, come posso ottenere i valori di stream_is_complete , uncompressed_stream e remainder_of_data ? Non riesco a cercare i "$" successivi perché il flusso può contenerlo. Ho provato a cercare qualcosa che assomiglia a un EOF nella documentazione di zlib, ma non esiste nulla del genere, infatti, ogni stream termina con un carattere apparentemente casuale.

Ho anche giocato con qUncompress (), ma questo richiede un flusso completo, niente di meno, niente di più.

È stato utile?

Soluzione

Stai usando zlib direttamente?

Totalmente non testato ...

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
}

Questo decomprime in modo incrementale (si gonfia) da qbuffer a qout e si interrompe quando gonfia dice " non più " ;.

Forse sarebbe meglio prendere in prestito da QuaZip invece.

Altri suggerimenti

La fine del file non è speciale per zlib. Il problema che vedo con il tuo codice è che usi "quotAll ()", che in realtà non ha alcun mezzo per segnalare "errori", come la fine del file.

Dovresti provare a utilizzare " read () " invece, in un ciclo. Se leggi lo stream e restituisce 0 byte letti, puoi essere sicuro di aver raggiunto la fine dello stream (l'altra estremità ha chiuso la connessione). Il buffer che hai letto, unendo quelli di tutti i precedenti "leggi" nel ciclo, ti darà il buffer completo.

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