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

0001 /* This file is part of the KDE libraries
0002    SPDX-FileCopyrightText: 2021 Albert Astals Cid <aacid@kde.org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "kzstdfilter.h"
0008 #include "loggingcategory.h"
0009 
0010 #include <QIODevice>
0011 
0012 #if HAVE_ZSTD_SUPPORT
0013 
0014 extern "C" {
0015 #include <zstd.h>
0016 }
0017 
0018 class Q_DECL_HIDDEN KZstdFilter::Private
0019 {
0020 public:
0021     union {
0022         ZSTD_CStream *cStream;
0023         ZSTD_DStream *dStream;
0024     };
0025     int mode;
0026     bool isInitialized = false;
0027     ZSTD_inBuffer inBuffer;
0028     ZSTD_outBuffer outBuffer;
0029 };
0030 
0031 KZstdFilter::KZstdFilter()
0032     : d(new Private)
0033 {
0034 }
0035 
0036 KZstdFilter::~KZstdFilter()
0037 {
0038 }
0039 
0040 bool KZstdFilter::init(int mode)
0041 {
0042     if (d->isInitialized) {
0043         terminate();
0044     }
0045 
0046     d->inBuffer.size = 0;
0047     d->inBuffer.pos = 0;
0048 
0049     if (mode == QIODevice::ReadOnly) {
0050         d->dStream = ZSTD_createDStream();
0051     } else if (mode == QIODevice::WriteOnly) {
0052         d->cStream = ZSTD_createCStream();
0053     } else {
0054         // qCWarning(KArchiveLog) << "Unsupported mode " << mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
0055         return false;
0056     }
0057     d->mode = mode;
0058     d->isInitialized = true;
0059     return true;
0060 }
0061 
0062 int KZstdFilter::mode() const
0063 {
0064     return d->mode;
0065 }
0066 
0067 bool KZstdFilter::terminate()
0068 {
0069     if (d->mode == QIODevice::ReadOnly) {
0070         ZSTD_freeDStream(d->dStream);
0071     } else if (d->mode == QIODevice::WriteOnly) {
0072         ZSTD_freeCStream(d->cStream);
0073     } else {
0074         // qCWarning(KArchiveLog) << "Unsupported mode " << d->mode << ". Only QIODevice::ReadOnly and QIODevice::WriteOnly supported";
0075         return false;
0076     }
0077     d->isInitialized = false;
0078     return true;
0079 }
0080 
0081 void KZstdFilter::reset()
0082 {
0083     terminate();
0084     init(d->mode);
0085 }
0086 
0087 void KZstdFilter::setOutBuffer(char *data, uint maxlen)
0088 {
0089     d->outBuffer.dst = data;
0090     d->outBuffer.size = maxlen;
0091     d->outBuffer.pos = 0;
0092 }
0093 
0094 void KZstdFilter::setInBuffer(const char *data, unsigned int size)
0095 {
0096     d->inBuffer.src = data;
0097     d->inBuffer.size = size;
0098     d->inBuffer.pos = 0;
0099 }
0100 
0101 int KZstdFilter::inBufferAvailable() const
0102 {
0103     return d->inBuffer.size - d->inBuffer.pos;
0104 }
0105 
0106 int KZstdFilter::outBufferAvailable() const
0107 {
0108     return d->outBuffer.size - d->outBuffer.pos;
0109 }
0110 
0111 KZstdFilter::Result KZstdFilter::uncompress()
0112 {
0113     // qCDebug(KArchiveLog) << "Calling ZSTD_decompressStream with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
0114     const size_t result = ZSTD_decompressStream(d->dStream, &d->outBuffer, &d->inBuffer);
0115     if (ZSTD_isError(result)) {
0116         qCWarning(KArchiveLog) << "ZSTD_decompressStream returned" << result << ZSTD_getErrorName(result);
0117         return KFilterBase::Error;
0118     }
0119 
0120     return result == 0 ? KFilterBase::End : KFilterBase::Ok;
0121 }
0122 
0123 KZstdFilter::Result KZstdFilter::compress(bool finish)
0124 {
0125     // qCDebug(KArchiveLog) << "Calling ZSTD_compressStream2 with avail_in=" << inBufferAvailable() << " avail_out=" << outBufferAvailable();
0126     const size_t result = ZSTD_compressStream2(d->cStream, &d->outBuffer, &d->inBuffer, finish ? ZSTD_e_end : ZSTD_e_continue);
0127     if (ZSTD_isError(result)) {
0128         return KFilterBase::Error;
0129     }
0130 
0131     return finish && result == 0 ? KFilterBase::End : KFilterBase::Ok;
0132 }
0133 
0134 #endif