File indexing completed on 2024-04-21 03:52:31

0001 /* This file is part of the KDE libraries
0002    SPDX-FileCopyrightText: 2000-2005 David Faure <faure@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "kbzip2filter.h"
0008 #include "loggingcategory.h"
0009 
0010 #if HAVE_BZIP2_SUPPORT
0011 
0012 // we don't need that
0013 #define BZ_NO_STDIO
0014 extern "C" {
0015 #include <bzlib.h>
0016 }
0017 
0018 #if NEED_BZ2_PREFIX
0019 #define bzDecompressInit(x, y, z) BZ2_bzDecompressInit(x, y, z)
0020 #define bzDecompressEnd(x) BZ2_bzDecompressEnd(x)
0021 #define bzCompressEnd(x) BZ2_bzCompressEnd(x)
0022 #define bzDecompress(x) BZ2_bzDecompress(x)
0023 #define bzCompress(x, y) BZ2_bzCompress(x, y)
0024 #define bzCompressInit(x, y, z, a) BZ2_bzCompressInit(x, y, z, a);
0025 #endif
0026 
0027 #include <QDebug>
0028 
0029 #include <QIODevice>
0030 
0031 // For docu on this, see /usr/doc/bzip2-0.9.5d/bzip2-0.9.5d/manual_3.html
0032 
0033 class Q_DECL_HIDDEN KBzip2Filter::Private
0034 {
0035 public:
0036     Private()
0037         : isInitialized(false)
0038     {
0039         memset(&zStream, 0, sizeof(zStream));
0040         mode = 0;
0041     }
0042 
0043     bz_stream zStream;
0044     int mode;
0045     bool isInitialized;
0046 };
0047 
0048 KBzip2Filter::KBzip2Filter()
0049     : d(new Private)
0050 {
0051 }
0052 
0053 KBzip2Filter::~KBzip2Filter()
0054 {
0055     delete d;
0056 }
0057 
0058 bool KBzip2Filter::init(int mode)
0059 {
0060     if (d->isInitialized) {
0061         terminate();
0062     }
0063 
0064     d->zStream.next_in = nullptr;
0065     d->zStream.avail_in = 0;
0066     if (mode == QIODevice::ReadOnly) {
0067         const int result = bzDecompressInit(&d->zStream, 0, 0);
0068         if (result != BZ_OK) {
0069             // qCDebug(KArchiveLog) << "bzDecompressInit returned " << result;
0070             return false;
0071         }
0072     } else if (mode == QIODevice::WriteOnly) {
0073         const int result = bzCompressInit(&d->zStream, 5, 0, 0);
0074         if (result != BZ_OK) {
0075             // qCDebug(KArchiveLog) << "bzDecompressInit returned " << result;
0076             return false;
0077         }
0078     } else {
0079         // qCWarning(KArchiveLog) << "Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
0080         return false;
0081     }
0082     d->mode = mode;
0083     d->isInitialized = true;
0084     return true;
0085 }
0086 
0087 int KBzip2Filter::mode() const
0088 {
0089     return d->mode;
0090 }
0091 
0092 bool KBzip2Filter::terminate()
0093 {
0094     if (d->mode == QIODevice::ReadOnly) {
0095         const int result = bzDecompressEnd(&d->zStream);
0096         if (result != BZ_OK) {
0097             // qCDebug(KArchiveLog) << "bzDecompressEnd returned " << result;
0098             return false;
0099         }
0100     } else if (d->mode == QIODevice::WriteOnly) {
0101         const int result = bzCompressEnd(&d->zStream);
0102         if (result != BZ_OK) {
0103             // qCDebug(KArchiveLog) << "bzCompressEnd returned " << result;
0104             return false;
0105         }
0106     } else {
0107         // qCWarning(KArchiveLog) << "Unsupported mode " << d->mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
0108         return false;
0109     }
0110     d->isInitialized = false;
0111     return true;
0112 }
0113 
0114 void KBzip2Filter::reset()
0115 {
0116     // bzip2 doesn't seem to have a reset call...
0117     terminate();
0118     init(d->mode);
0119 }
0120 
0121 void KBzip2Filter::setOutBuffer(char *data, uint maxlen)
0122 {
0123     d->zStream.avail_out = maxlen;
0124     d->zStream.next_out = data;
0125 }
0126 
0127 void KBzip2Filter::setInBuffer(const char *data, unsigned int size)
0128 {
0129     d->zStream.avail_in = size;
0130     d->zStream.next_in = const_cast<char *>(data);
0131 }
0132 
0133 int KBzip2Filter::inBufferAvailable() const
0134 {
0135     return d->zStream.avail_in;
0136 }
0137 
0138 int KBzip2Filter::outBufferAvailable() const
0139 {
0140     return d->zStream.avail_out;
0141 }
0142 
0143 KBzip2Filter::Result KBzip2Filter::uncompress()
0144 {
0145     // qCDebug(KArchiveLog) << "Calling bzDecompress with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
0146     int result = bzDecompress(&d->zStream);
0147     if (result < BZ_OK) {
0148         bzDecompressEnd(&d->zStream);
0149     }
0150 
0151     switch (result) {
0152     case BZ_OK:
0153         return KFilterBase::Ok;
0154     case BZ_STREAM_END:
0155         return KFilterBase::End;
0156     case BZ_MEM_ERROR:
0157         qCWarning(KArchiveLog) << "bzDecompress error, insufficient memory";
0158         break;
0159     case BZ_DATA_ERROR:
0160         qCWarning(KArchiveLog) << "bzDecompress error, data integrity error";
0161         break;
0162     case BZ_DATA_ERROR_MAGIC:
0163         qCWarning(KArchiveLog) << "bzDecompress error, stream does not start with the right magic bytes";
0164         break;
0165     case BZ_PARAM_ERROR:
0166         qCWarning(KArchiveLog) << "bzDecompress error, parameter error";
0167         break;
0168     default:
0169         qCWarning(KArchiveLog) << "bzDecompress error, returned:" << result;
0170         break;
0171     }
0172     return KFilterBase::Error;
0173 }
0174 
0175 KBzip2Filter::Result KBzip2Filter::compress(bool finish)
0176 {
0177     // qCDebug(KArchiveLog) << "Calling bzCompress with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
0178     int result = bzCompress(&d->zStream, finish ? BZ_FINISH : BZ_RUN);
0179 
0180     switch (result) {
0181     case BZ_OK:
0182     case BZ_FLUSH_OK:
0183     case BZ_RUN_OK:
0184     case BZ_FINISH_OK:
0185         return KFilterBase::Ok;
0186         break;
0187     case BZ_STREAM_END:
0188         // qCDebug(KArchiveLog) << "  bzCompress returned " << result;
0189         return KFilterBase::End;
0190         break;
0191     default:
0192         // qCDebug(KArchiveLog) << "  bzCompress returned " << result;
0193         return KFilterBase::Error;
0194         break;
0195     }
0196 }
0197 
0198 #endif /* HAVE_BZIP2_SUPPORT */