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
14extern "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
33class Q_DECL_HIDDEN KBzip2Filter::Private
34{
35public:
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
48KBzip2Filter::KBzip2Filter()
49 : d(new Private)
50{
51}
52
53KBzip2Filter::~KBzip2Filter()
54{
55 delete d;
56}
57
58bool 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
87int KBzip2Filter::mode() const
88{
89 return d->mode;
90}
91
92bool 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
114void KBzip2Filter::reset()
115{
116 // bzip2 doesn't seem to have a reset call...
117 terminate();
118 init(mode: d->mode);
119}
120
121void KBzip2Filter::setOutBuffer(char *data, uint maxlen)
122{
123 d->zStream.avail_out = maxlen;
124 d->zStream.next_out = data;
125}
126
127void 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
133int KBzip2Filter::inBufferAvailable() const
134{
135 return d->zStream.avail_in;
136}
137
138int KBzip2Filter::outBufferAvailable() const
139{
140 return d->zStream.avail_out;
141}
142
143KBzip2Filter::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
175KBzip2Filter::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

source code of karchive/src/kbzip2filter.cpp