7
votes

Comment Zlib Compressez un QbyEarray?

Je voudrais maintenir l'interopérabilité entre toutes les autres applications de la planète (y compris les applications Web) lors de la compression du texte. Depuis que Qcompress et Quncompress semblent aller contre le grain, j'essaie d'utiliser Zlib directement depuis mon application QT.

J'accepterai la réponse la plus simple (la plus minimale) qui me montre comment utiliser la bibliothèque ZLIB avec un QbyTeArray directement ou strong> modifier la sortie de QCompress afin qu'il puisse être utilisé en dehors d'une application QT. p>

Voici ma tentative embarrassante: p>

# define Bytef                 z_Bytef


1 commentaires

Vous pouvez utiliser les iostreams de Boost: il a un filtre zlib


3 Réponses :


0
votes

Voici un code ICI IC une fois écrit qui obtient comme entrée un pointeur sur un tableau d'octets, le nombre d'octets à compresser et le niveau de compression puis utilise zlib pour compresser l'entrée. Le résultat est renvoyé dans une chaîne.

 enum compressionLevel
 {
    clFast,
    clSmall,
    clDefault
 };

 const size_t ChunkSize = 262144; //256k default size for chunks fed to zlib

 void compressZlib(const char *s, size_t nbytes, std::string &out, compressionLevel l /*= clDefault*/ )
 {
    int level = Z_DEFAULT_COMPRESSION;
    switch (l)
    {
    case clDefault:
        level = Z_DEFAULT_COMPRESSION; break;
    case clSmall:
        level = Z_BEST_COMPRESSION; break;
    case clFast:
        level = Z_BEST_SPEED; break;
    };

    z_stream strm;
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    int ret = deflateInit(&strm, level);
    if (ret != Z_OK)
    {
        throw std::runtime_error("Error while initializing zlib, error code "+ret);
    }
    size_t toCompress = nbytes;
    char *readp = (char*)s;
    size_t writeOffset = out.size();
    out.reserve((size_t)(nbytes * 0.7));
    while (toCompress > 0)
    {
        size_t toRead = std::min(toCompress,ChunkSize);
        int flush = toRead < toCompress ? Z_NO_FLUSH : Z_FINISH;
        strm.avail_in = toRead;
        strm.next_in = (Bytef*)readp;
        char *writep = new char[ChunkSize];
        do{
            strm.avail_out = ChunkSize;
            strm.next_out = (Bytef*)writep;
            deflate(&strm, flush);
            size_t written = ChunkSize - strm.avail_out;
            out.resize(out.size() + written);
            memcpy(&(out[writeOffset]), writep, written);
            writeOffset += written;
        } while (strm.avail_out == 0);
        delete[] writep;
        readp += toRead;
        toCompress -= toRead;
    }
    (void)deflateEnd(&strm);
 }


0 commentaires

8
votes

basé sur Ceci Note dans Quncompress, i pense que c'est assez facile.

Remarque: Si vous souhaitez utiliser cette fonction pour décompresser des données externes comprimées à l'aide de ZLIB, vous devez d'abord préparer un en-tête de quatre octets sur le tableau d'octets contenant les données. L'en-tête doit contenir la longueur attendue (en octets) des données non compressées, exprimées comme un entier non signé, Big-Endian, 32 bits.

Donc, vous pouvez probablement simplement le comprimer comme ceci: xxx


6 commentaires

Vous avez dit "Prepend", mais il semble que votre code supprime les 4 premiers octets au lieu d'insérer la taille à l'avant.


Le code est ce que je voulais dire ça. Quncompress s'attend à ce que 4 octets non standard achètent. Ainsi, QCompress doit avoir recours à 4 octets non standard. Si vous utilisez QCompress et supprimez ces octets, vous devriez alors avoir uniquement les trucs zlib standard.


J'ai déjà essayé ça. Lorsque j'utilise Quncompress (préparé la taille attendue) Zlib se plaint que c'est corrompu.


Ok, mon mauvais. Je pensais que vous aviez besoin de préparer pour utiliser les données avec ZLIB.


@Sosukodo: Pourquoi, si la solution ne fonctionne pas, avez-vous marqué cette réponse comme correcte?


Parce que le code donné dans la réponse fonctionne bien en soi. Il a confirmé le moyen le plus rapide d'obtenir un QbyTarray de Vanilla Zlib-compressé. Le problème que j'avais avec les erreurs de Zlib n'était pas liée à la compression / décompression.



0
votes

Juste pour vous aider avec la dernière section de votre question ici:

Je n'ai aucune idée de ce qu'est un bytef, je commence à regarder dans les sources de Zlib pour enquêter. p> blockQuote>

pour les définitions de octet code> et byTEF code>, regardez les lignes 332 et 333 de zconf.h, ainsi que la ligne 342: P>

QByteArray tdata = QString("Oh noes!").toUtf8();
QByteArray cdata(compressBound(tdata.length()), '\0');
uLongf len = compressBound(tdata.length());
compress(reinterpret_cast<unsigned char*>(cdata.data()), &len, 
         reinterpret_cast<unsigned char*>(tdata.data()), tdata.length());


2 commentaires

Ce code ne parvient pas à compiler en indiquant: Erreur: Static_cast non valide de type 'Char *' Pour taper "Unsigned Char *"


Ok, j'ai remplacé le static_cast <> () avec un REINERPRET_CAST <> () ... qui devrait définitivement compiler.