ZlibByteArray.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 #include "config.h"
00054
00055 #include <QString>
00056
00057 #ifdef HAVE_LIMITS_H
00058 #include <limits.h>
00059 #elif defined(HAVE_SYS_LIMITS_H)
00060 #include <sys/limits.h>
00061 #endif
00062
00063
00064
00065 #ifndef UINT_MAX
00066 #if (SIZEOF_INT == 2)
00067 #define UINT_MAX 0xffffu
00068 #elif (SIZEOF_INT == 4)
00069 #define UINT_MAX 0xffffffffu
00070 #elif (SIZEOF_INT == 8)
00071 #define UINT_MAX 0xffffffffffffffffu
00072 #else
00073 #error "Your platform uses a sizeof(int) that we don't understand."
00074 #endif
00075 #endif
00076
00077 #include "zlib.h"
00078 #include <ZlibByteArray.h>
00079
00080
00081
00082 ZlibByteArray::ZlibByteArray(QByteArray data)
00083 : QByteArray(data)
00084 {
00085 }
00086
00087
00088 int
00089 ZlibByteArray::methodBits(CompressionMethod method)
00090 {
00091
00092 return (method == Gzip ? 15+16 : 15);
00093 }
00094
00095
00096 QString
00097 ZlibByteArray::methodString(CompressionMethod method)
00098 {
00099 switch (method) {
00100 case None: return "None";
00101 case Zlib: return "Zlib";
00102 case Gzip: return "Gzip";
00103 default: return "Unknown";
00104 }
00105 }
00106
00107
00108 bool
00109 ZlibByteArray::isZlibAvailable()
00110 {
00111 static int isZlibAvailable = -1;
00112 if (isZlibAvailable >= 0)
00113 return isZlibAvailable;
00114
00115
00116
00117
00118
00119 QString libVersion(zlibVersion());
00120 QString headerVersion(ZLIB_VERSION);
00121 if (libVersion.isEmpty() || headerVersion.isEmpty() ||
00122 libVersion.at(0) != headerVersion.at(0))
00123 isZlibAvailable = 0;
00124 else
00125 isZlibAvailable = 1;
00126
00127 return isZlibAvailable;
00128 }
00129
00130
00131
00132 bool
00133 ZlibByteArray::isGzipSupported()
00134 {
00135 static int isGzipSupported = -1;
00136 if (isGzipSupported >= 0)
00137 return isGzipSupported;
00138
00139 QString version(zlibVersion());
00140 if (version.startsWith("0.") ||
00141 version.startsWith("1.0") ||
00142 version.startsWith("1.1"))
00143 isGzipSupported = 0;
00144 else
00145 isGzipSupported = 1;
00146
00147 return isGzipSupported;
00148 }
00149
00150
00151
00152
00153
00154 QByteArray
00155 ZlibByteArray::compress(const CompressionMethod method,
00156 QString *errmsg) const
00157 {
00158 return compress(QByteArray(data()), method, errmsg);
00159 }
00160
00161
00162
00163
00164 QByteArray
00165 ZlibByteArray::compress(const QByteArray in,
00166 const CompressionMethod method,
00167 QString *errmsg)
00168 {
00169 QByteArray out;
00170 QString errorstr;
00171 struct z_stream_s *stream = NULL;
00172 size_t out_size;
00173 size_t out_len;
00174 size_t in_len = in.length();
00175 off_t offset;
00176
00177 if (method == None)
00178 return in;
00179 if (method == Gzip && !isGzipSupported()) {
00180
00181 if (errmsg)
00182 *errmsg = QString("Gzip not supported with zlib %1")
00183 .arg(ZLIB_VERSION);
00184 return QByteArray();
00185 }
00186
00187 stream = new struct z_stream_s;
00188 stream->zalloc = Z_NULL;
00189 stream->zfree = Z_NULL;
00190 stream->opaque = NULL;
00191 stream->next_in = (unsigned char*)in.data();
00192 stream->avail_in = in_len;
00193
00194 if (deflateInit2(stream, Z_BEST_COMPRESSION, Z_DEFLATED,
00195 methodBits(method),
00196 8, Z_DEFAULT_STRATEGY) != Z_OK) {
00197 errorstr = QString("Error from deflateInit2: %1")
00198 .arg(stream->msg ? stream->msg : "<no message>");
00199 goto err;
00200 }
00201
00202
00203 out_size = in_len / 2;
00204 if (out_size < 1024) out_size = 1024;
00205
00206 out.resize(out_size);
00207 stream->next_out = (unsigned char*)out.data();
00208 stream->avail_out = out_size;
00209
00210 while (1) {
00211 switch (deflate(stream, Z_FINISH))
00212 {
00213 case Z_STREAM_END:
00214 goto done;
00215 case Z_OK:
00216
00217 if (stream->avail_out >= stream->avail_in+16)
00218 break;
00219 case Z_BUF_ERROR:
00220 offset = stream->next_out - ((unsigned char*)out.data());
00221 out_size *= 2;
00222 out.resize(out_size);
00223 stream->next_out = (unsigned char*)(out.data() + offset);
00224 if (out_size - offset > UINT_MAX) {
00225 errorstr =
00226 "Ran over unsigned int limit of zlib while uncompressing";
00227 goto err;
00228 }
00229 stream->avail_out = (unsigned int)(out_size - offset);
00230 break;
00231 default:
00232 errorstr = QString("%1 compression didn't finish: %2")
00233 .arg(methodString(method))
00234 .arg(stream->msg ? stream->msg : "<no message>");
00235 goto err;
00236 }
00237 }
00238 done:
00239 out_len = stream->total_out;
00240 if (deflateEnd(stream)!=Z_OK) {
00241 errorstr = "Error freeing zlib structures";
00242 goto err;
00243 }
00244 out.resize(out_len);
00245 delete stream;
00246 return out;
00247 err:
00248 if (stream) {
00249 deflateEnd(stream);
00250 delete stream;
00251 }
00252 if (errmsg)
00253 *errmsg = errorstr;
00254 return QByteArray();
00255 }
00256
00257
00258
00259
00260
00261 QByteArray
00262 ZlibByteArray::uncompress(const CompressionMethod method,
00263 QString *errmsg) const
00264 {
00265 return uncompress(QByteArray(data()), method, errmsg);
00266 }
00267
00268
00269
00270
00271 QByteArray
00272 ZlibByteArray::uncompress(const QByteArray in,
00273 const CompressionMethod method,
00274 QString *errmsg)
00275 {
00276 QByteArray out;
00277 QString errorstr;
00278 struct z_stream_s *stream = NULL;
00279 size_t out_size;
00280 size_t out_len;
00281 size_t in_len = in.length();
00282 off_t offset;
00283 int r;
00284
00285 if (method == None)
00286 return in;
00287 if (method == Gzip && !isGzipSupported()) {
00288
00289 if (errmsg)
00290 *errmsg = QString("Gzip not supported with zlib %1")
00291 .arg(ZLIB_VERSION);
00292 return QByteArray();
00293 }
00294
00295 stream = new struct z_stream_s;
00296 stream->zalloc = Z_NULL;
00297 stream->zfree = Z_NULL;
00298 stream->opaque = NULL;
00299 stream->msg = NULL;
00300 stream->next_in = (unsigned char*) in.data();
00301 stream->avail_in = in_len;
00302
00303 if (inflateInit2(stream,
00304 methodBits(method)) != Z_OK) {
00305 errorstr = QString("Error from inflateInit2: %1")
00306 .arg(stream->msg ? stream->msg : "<no message>");
00307 goto err;
00308 }
00309
00310 out_size = in_len * 2;
00311 if (out_size < 1024) out_size = 1024;
00312
00313 out.resize(out_size);
00314 stream->next_out = (unsigned char*)out.data();
00315 stream->avail_out = out_size;
00316
00317 while (1) {
00318 switch (inflate(stream, Z_FINISH))
00319 {
00320 case Z_STREAM_END:
00321 if (stream->avail_in == 0)
00322 goto done;
00323
00324 if ((r = inflateEnd(stream)) != Z_OK) {
00325 errorstr = "Error freeing zlib structures";
00326 goto err;
00327 }
00328 if (inflateInit2(stream, methodBits(method)) != Z_OK) {
00329 errorstr = QString("Error from second inflateInit2: %1")
00330 .arg(stream->msg ? stream->msg : "<no message>");
00331 goto err;
00332 }
00333 break;
00334 case Z_OK:
00335 if (stream->avail_in == 0)
00336 goto done;
00337
00338 if (stream->avail_out >= stream->avail_in+16)
00339 break;
00340 case Z_BUF_ERROR:
00341 if (stream->avail_out > 0) {
00342 errorstr = QString("Possible truncated or corrupt %1 data")
00343 .arg(methodString(method));
00344 goto err;
00345 }
00346 offset = stream->next_out - (unsigned char*)out.data();
00347 out_size *= 2;
00348 out.resize(out_size);
00349 stream->next_out = (unsigned char*)(out.data() + offset);
00350 if (out_size - offset > UINT_MAX) {
00351 errorstr =
00352 "Ran over unsigned int limit of zlib while uncompressing";
00353 goto err;
00354 }
00355 stream->avail_out = (unsigned int)(out_size - offset);
00356 break;
00357 default:
00358 errorstr = QString("%1 decompression returned an error: %2")
00359 .arg(methodString(method))
00360 .arg(stream->msg ? stream->msg : "<no message>");
00361 goto err;
00362 }
00363 }
00364 done:
00365 out_len = stream->next_out - (unsigned char*)out.data();
00366 r = inflateEnd(stream);
00367 delete stream;
00368 if (r != Z_OK) {
00369 errorstr = "Error freeing zlib structure";
00370 goto err;
00371 }
00372 out.resize(out_len);
00373 return out;
00374 err:
00375 if (stream) {
00376 inflateEnd(stream);
00377 delete stream;
00378 }
00379 if (errmsg)
00380 *errmsg = errorstr;
00381 return QByteArray();
00382 }
00383