| 1 | /* This file is part of the KDE libraries |
| 2 | SPDX-FileCopyrightText: 2000-2005 David Faure <faure@kde.org> |
| 3 | |
| 4 | SPDX-License-Identifier: LGPL-2.0-or-later |
| 5 | */ |
| 6 | |
| 7 | #include "kbzip2filter.h" |
| 8 | #include "loggingcategory.h" |
| 9 | |
| 10 | #if HAVE_BZIP2_SUPPORT |
| 11 | |
| 12 | // we don't need that |
| 13 | #define BZ_NO_STDIO |
| 14 | extern "C" { |
| 15 | #include <bzlib.h> |
| 16 | } |
| 17 | |
| 18 | #if NEED_BZ2_PREFIX |
| 19 | #define bzDecompressInit(x, y, z) BZ2_bzDecompressInit(x, y, z) |
| 20 | #define bzDecompressEnd(x) BZ2_bzDecompressEnd(x) |
| 21 | #define bzCompressEnd(x) BZ2_bzCompressEnd(x) |
| 22 | #define bzDecompress(x) BZ2_bzDecompress(x) |
| 23 | #define bzCompress(x, y) BZ2_bzCompress(x, y) |
| 24 | #define bzCompressInit(x, y, z, a) BZ2_bzCompressInit(x, y, z, a); |
| 25 | #endif |
| 26 | |
| 27 | #include <QDebug> |
| 28 | |
| 29 | #include <QIODevice> |
| 30 | |
| 31 | // For docu on this, see /usr/doc/bzip2-0.9.5d/bzip2-0.9.5d/manual_3.html |
| 32 | |
| 33 | class Q_DECL_HIDDEN KBzip2Filter::Private |
| 34 | { |
| 35 | public: |
| 36 | Private() |
| 37 | : isInitialized(false) |
| 38 | { |
| 39 | memset(s: &zStream, c: 0, n: sizeof(zStream)); |
| 40 | mode = 0; |
| 41 | } |
| 42 | |
| 43 | bz_stream zStream; |
| 44 | int mode; |
| 45 | bool isInitialized; |
| 46 | }; |
| 47 | |
| 48 | KBzip2Filter::KBzip2Filter() |
| 49 | : d(new Private) |
| 50 | { |
| 51 | } |
| 52 | |
| 53 | KBzip2Filter::~KBzip2Filter() |
| 54 | { |
| 55 | delete d; |
| 56 | } |
| 57 | |
| 58 | bool KBzip2Filter::init(int mode) |
| 59 | { |
| 60 | if (d->isInitialized) { |
| 61 | terminate(); |
| 62 | } |
| 63 | |
| 64 | d->zStream.next_in = nullptr; |
| 65 | d->zStream.avail_in = 0; |
| 66 | if (mode == QIODevice::ReadOnly) { |
| 67 | const int result = bzDecompressInit(&d->zStream, 0, 0); |
| 68 | if (result != BZ_OK) { |
| 69 | // qCDebug(KArchiveLog) << "bzDecompressInit returned " << result; |
| 70 | return false; |
| 71 | } |
| 72 | } else if (mode == QIODevice::WriteOnly) { |
| 73 | const int result = bzCompressInit(&d->zStream, 5, 0, 0); |
| 74 | if (result != BZ_OK) { |
| 75 | // qCDebug(KArchiveLog) << "bzDecompressInit returned " << result; |
| 76 | return false; |
| 77 | } |
| 78 | } else { |
| 79 | // qCWarning(KArchiveLog) << "Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported"; |
| 80 | return false; |
| 81 | } |
| 82 | d->mode = mode; |
| 83 | d->isInitialized = true; |
| 84 | return true; |
| 85 | } |
| 86 | |
| 87 | int KBzip2Filter::mode() const |
| 88 | { |
| 89 | return d->mode; |
| 90 | } |
| 91 | |
| 92 | bool KBzip2Filter::terminate() |
| 93 | { |
| 94 | if (d->mode == QIODevice::ReadOnly) { |
| 95 | const int result = bzDecompressEnd(&d->zStream); |
| 96 | if (result != BZ_OK) { |
| 97 | // qCDebug(KArchiveLog) << "bzDecompressEnd returned " << result; |
| 98 | return false; |
| 99 | } |
| 100 | } else if (d->mode == QIODevice::WriteOnly) { |
| 101 | const int result = bzCompressEnd(&d->zStream); |
| 102 | if (result != BZ_OK) { |
| 103 | // qCDebug(KArchiveLog) << "bzCompressEnd returned " << result; |
| 104 | return false; |
| 105 | } |
| 106 | } else { |
| 107 | // qCWarning(KArchiveLog) << "Unsupported mode " << d->mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported"; |
| 108 | return false; |
| 109 | } |
| 110 | d->isInitialized = false; |
| 111 | return true; |
| 112 | } |
| 113 | |
| 114 | void KBzip2Filter::reset() |
| 115 | { |
| 116 | // bzip2 doesn't seem to have a reset call... |
| 117 | terminate(); |
| 118 | init(mode: d->mode); |
| 119 | } |
| 120 | |
| 121 | void KBzip2Filter::setOutBuffer(char *data, uint maxlen) |
| 122 | { |
| 123 | d->zStream.avail_out = maxlen; |
| 124 | d->zStream.next_out = data; |
| 125 | } |
| 126 | |
| 127 | void KBzip2Filter::setInBuffer(const char *data, unsigned int size) |
| 128 | { |
| 129 | d->zStream.avail_in = size; |
| 130 | d->zStream.next_in = const_cast<char *>(data); |
| 131 | } |
| 132 | |
| 133 | int KBzip2Filter::inBufferAvailable() const |
| 134 | { |
| 135 | return d->zStream.avail_in; |
| 136 | } |
| 137 | |
| 138 | int KBzip2Filter::outBufferAvailable() const |
| 139 | { |
| 140 | return d->zStream.avail_out; |
| 141 | } |
| 142 | |
| 143 | KBzip2Filter::Result KBzip2Filter::uncompress() |
| 144 | { |
| 145 | // qCDebug(KArchiveLog) << "Calling bzDecompress with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable(); |
| 146 | int result = bzDecompress(&d->zStream); |
| 147 | if (result < BZ_OK) { |
| 148 | bzDecompressEnd(&d->zStream); |
| 149 | } |
| 150 | |
| 151 | switch (result) { |
| 152 | case BZ_OK: |
| 153 | return KFilterBase::Ok; |
| 154 | case BZ_STREAM_END: |
| 155 | return KFilterBase::End; |
| 156 | case BZ_MEM_ERROR: |
| 157 | qCWarning(KArchiveLog) << "bzDecompress error, insufficient memory" ; |
| 158 | break; |
| 159 | case BZ_DATA_ERROR: |
| 160 | qCWarning(KArchiveLog) << "bzDecompress error, data integrity error" ; |
| 161 | break; |
| 162 | case BZ_DATA_ERROR_MAGIC: |
| 163 | qCWarning(KArchiveLog) << "bzDecompress error, stream does not start with the right magic bytes" ; |
| 164 | break; |
| 165 | case BZ_PARAM_ERROR: |
| 166 | qCWarning(KArchiveLog) << "bzDecompress error, parameter error" ; |
| 167 | break; |
| 168 | default: |
| 169 | qCWarning(KArchiveLog) << "bzDecompress error, returned:" << result; |
| 170 | break; |
| 171 | } |
| 172 | return KFilterBase::Error; |
| 173 | } |
| 174 | |
| 175 | KBzip2Filter::Result KBzip2Filter::compress(bool finish) |
| 176 | { |
| 177 | // qCDebug(KArchiveLog) << "Calling bzCompress with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable(); |
| 178 | int result = bzCompress(&d->zStream, finish ? BZ_FINISH : BZ_RUN); |
| 179 | |
| 180 | switch (result) { |
| 181 | case BZ_OK: |
| 182 | case BZ_FLUSH_OK: |
| 183 | case BZ_RUN_OK: |
| 184 | case BZ_FINISH_OK: |
| 185 | return KFilterBase::Ok; |
| 186 | break; |
| 187 | case BZ_STREAM_END: |
| 188 | // qCDebug(KArchiveLog) << " bzCompress returned " << result; |
| 189 | return KFilterBase::End; |
| 190 | break; |
| 191 | default: |
| 192 | // qCDebug(KArchiveLog) << " bzCompress returned " << result; |
| 193 | return KFilterBase::Error; |
| 194 | break; |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | #endif /* HAVE_BZIP2_SUPPORT */ |
| 199 | |