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 | |