File indexing completed on 2025-02-16 13:00:38
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