How to zlib compress QByteArray?

I want to maintain compatibility between any other applications on the planet (including web applications) when compressing text. Since qCompress and qUncompress seem to go against the grain, I am trying to use zlib directly from my Qt application.

I will accept the simplest (most minimal) answer that shows me how to use the zlib library with QByteArray directly OR change the output of qCompress so that it can be used outside of the Qt application.

Here is my uncomfortable attempt:

QByteArray tdata = QString("Oh noes!").toUtf8(); QByteArray cdata; uLongf len = 12 + 1.002*tdata.length(); compress(&cdata, &len, &tdata, tdata.length()); 

And the error:

error: cannot convert 'QByteArray *' to 'Bytef *' for argument '1' for 'int compress (Bytef *, uLongf *, const Bytef *, uLong)'

Then I tried using QByteArray :: constData ()

 compress(cdata.constData(), &len, &tdata, tdata.length()); 

But the following error turned out:

Error: Incorrect conversion from 'const char *' to 'Bytef *'

I have no idea what Bytef is, so I'm starting to search the zlib sources for research. But all I can find is in QtSources / src / 3rdparty / zlib / zconf.h

 # define Bytef z_Bytef 

So now I'm just lost.

+6
source share
3 answers

Based on this post at qUncompress, I think it's pretty easy.

Note. If you want to use this function to decompress external data compressed with zlib, you must first add a four-byte header to the byte array containing the data. The header should contain the expected length (in bytes) of uncompressed data, expressed as an unsigned, 32-bit unsigned integer.

So you can just compress it like this:

 QByteArray tdata = QString("Oh noes!").toUtf8(); QByteArray compressedData = qCompress(tdata); compressedData.remove(0, 4); 
+6
source

Here is some code I once wrote that introduces a pointer to a byte array, the number of bytes to compress and the compression level, and then uses zlib to compress the input. The result is returned in a string.

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

Maybe this will help you solve your problem, I think using cdata.constData (), you can directly call this function

0
source

Just to help you in the last section of your question:

I have no idea what Bytef is, so I'm starting to look for zlib sources for research.

For Byte and Bytef see lines 332 and 333 of zconf.h, as well as line 342:

 332 #if !defined(__MACTYPES__) 333 typedef unsigned char Byte; /* 8 bits */ ... 338 #ifdef SMALL_MEDIUM 339 /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ 340 # define Bytef Byte FAR 341 #else 342 typedef Byte FAR Bytef; 

The FAR definition refers to programming MSDOS in mixed mode, otherwise it is not defined by anything (see lines 328-330 from zconf.h).

So the zlib typedefs Bytef and Byte are basically the same as unsigned char on most platforms. Therefore, you should be able to do the following:

 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()); 
0
source

Source: https://habr.com/ru/post/905663/


All Articles