1/* This file is part of the KDE libraries
2 SPDX-FileCopyrightText: 2021 Albert Astals Cid <aacid@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6
7#include "kzstdfilter.h"
8#include "loggingcategory.h"
9
10#include <QIODevice>
11
12#if HAVE_ZSTD_SUPPORT
13
14extern "C" {
15#include <zstd.h>
16}
17
18class Q_DECL_HIDDEN KZstdFilter::Private
19{
20public:
21 union {
22 ZSTD_CStream *cStream;
23 ZSTD_DStream *dStream;
24 };
25 int mode;
26 bool isInitialized = false;
27 ZSTD_inBuffer inBuffer;
28 ZSTD_outBuffer outBuffer;
29};
30
31KZstdFilter::KZstdFilter()
32 : d(new Private)
33{
34}
35
36KZstdFilter::~KZstdFilter()
37{
38}
39
40bool KZstdFilter::init(int mode)
41{
42 if (d->isInitialized) {
43 terminate();
44 }
45
46 d->inBuffer.size = 0;
47 d->inBuffer.pos = 0;
48
49 if (mode == QIODevice::ReadOnly) {
50 d->dStream = ZSTD_createDStream();
51 } else if (mode == QIODevice::WriteOnly) {
52 d->cStream = ZSTD_createCStream();
53 } else {
54 // qCWarning(KArchiveLog) << "Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
55 return false;
56 }
57 d->mode = mode;
58 d->isInitialized = true;
59 return true;
60}
61
62int KZstdFilter::mode() const
63{
64 return d->mode;
65}
66
67bool KZstdFilter::terminate()
68{
69 if (d->mode == QIODevice::ReadOnly) {
70 ZSTD_freeDStream(zds: d->dStream);
71 } else if (d->mode == QIODevice::WriteOnly) {
72 ZSTD_freeCStream(zcs: d->cStream);
73 } else {
74 // qCWarning(KArchiveLog) << "Unsupported mode " << d->mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
75 return false;
76 }
77 d->isInitialized = false;
78 return true;
79}
80
81void KZstdFilter::reset()
82{
83 terminate();
84 init(mode: d->mode);
85}
86
87void KZstdFilter::setOutBuffer(char *data, uint maxlen)
88{
89 d->outBuffer.dst = data;
90 d->outBuffer.size = maxlen;
91 d->outBuffer.pos = 0;
92}
93
94void KZstdFilter::setInBuffer(const char *data, unsigned int size)
95{
96 d->inBuffer.src = data;
97 d->inBuffer.size = size;
98 d->inBuffer.pos = 0;
99}
100
101int KZstdFilter::inBufferAvailable() const
102{
103 return d->inBuffer.size - d->inBuffer.pos;
104}
105
106int KZstdFilter::outBufferAvailable() const
107{
108 return d->outBuffer.size - d->outBuffer.pos;
109}
110
111KZstdFilter::Result KZstdFilter::uncompress()
112{
113 // qCDebug(KArchiveLog) << "Calling ZSTD_decompressStream with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
114 const size_t result = ZSTD_decompressStream(zds: d->dStream, output: &d->outBuffer, input: &d->inBuffer);
115 if (ZSTD_isError(code: result)) {
116 qCWarning(KArchiveLog) << "ZSTD_decompressStream returned" << result << ZSTD_getErrorName(code: result);
117 return KFilterBase::Error;
118 }
119
120 return result == 0 ? KFilterBase::End : KFilterBase::Ok;
121}
122
123KZstdFilter::Result KZstdFilter::compress(bool finish)
124{
125 // qCDebug(KArchiveLog) << "Calling ZSTD_compressStream2 with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
126 const size_t result = ZSTD_compressStream2(cctx: d->cStream, output: &d->outBuffer, input: &d->inBuffer, endOp: finish ? ZSTD_e_end : ZSTD_e_continue);
127 if (ZSTD_isError(code: result)) {
128 return KFilterBase::Error;
129 }
130
131 return finish && result == 0 ? KFilterBase::End : KFilterBase::Ok;
132}
133
134#endif
135

source code of karchive/src/kzstdfilter.cpp