7#include "akonadiprivate_debug.h"
8#include "compressionstream_p.h"
20class LZMAErrorCategory :
public std::error_category
23 const char *
name() const noexcept
override
27 std::string message(
int ev)
const noexcept override
29 switch (
static_cast<lzma_ret
>(ev)) {
31 return "Operation completed successfully";
33 return "End of stream was reached";
35 return "Input stream has no integrity check";
36 case LZMA_UNSUPPORTED_CHECK:
37 return "Cannot calculate the integrity check";
39 return "Integrity check type is now available";
41 return "Cannot allocate memory";
42 case LZMA_MEMLIMIT_ERROR:
43 return "Memory usage limit was reached";
44 case LZMA_FORMAT_ERROR:
45 return "File format not recognized";
46 case LZMA_OPTIONS_ERROR:
47 return "Invalid or unsupported options";
49 return "Data is corrupt";
51 return "No progress is possible";
53 return "Programming error";
60const LZMAErrorCategory &lzmaErrorCategory()
62 static const LZMAErrorCategory lzmaErrorCategory{};
63 return lzmaErrorCategory;
71struct is_error_code_enum<lzma_ret> : std::true_type {
74std::error_condition make_error_condition(lzma_ret ret)
76 return std::error_condition(
static_cast<int>(ret), lzmaErrorCategory());
81std::error_code make_error_code(lzma_ret e)
83 return {
static_cast<int>(e), lzmaErrorCategory()};
86class Akonadi::Compressor
92 return lzma_auto_decoder(&mStream, 100 * 1024 * 1024 , 0);
94 return lzma_easy_encoder(&mStream, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC32);
98 void setInputBuffer(
const char *data, qint64 size)
100 mStream.next_in =
reinterpret_cast<const uint8_t *
>(data);
101 mStream.avail_in = size;
104 void setOutputBuffer(
char *data, qint64 maxSize)
106 mStream.next_out =
reinterpret_cast<uint8_t *
>(data);
107 mStream.avail_out = maxSize;
110 size_t inputBufferAvailable()
const
112 return mStream.avail_in;
115 size_t outputBufferAvailable()
const
117 return mStream.avail_out;
120 std::error_code finalize()
126 std::error_code inflate()
128 return lzma_code(&mStream, LZMA_RUN);
131 std::error_code deflate(
bool finish)
133 return lzma_code(&mStream, finish ? LZMA_FINISH : LZMA_RUN);
137 lzma_stream mStream = LZMA_STREAM_INIT;
147CompressionStream::~CompressionStream()
149 CompressionStream::close();
152bool CompressionStream::isSequential()
const
157bool CompressionStream::open(OpenMode mode)
160 qCWarning(AKONADIPRIVATE_LOG) <<
"Invalid open mode for CompressionStream.";
164 mCompressor = std::make_unique<Compressor>();
166 qCWarning(AKONADIPRIVATE_LOG) <<
"Failed to initialize LZMA stream coder:" << err.message();
171 mBuffer.resize(BUFSIZ);
172 mCompressor->setOutputBuffer(mBuffer.data(), mBuffer.size());
178void CompressionStream::close()
188 mResult = mCompressor->finalize();
193std::error_code CompressionStream::error()
const
195 return mResult == LZMA_STREAM_END ? LZMA_OK : mResult;
198bool CompressionStream::atEnd()
const
200 return mResult == LZMA_STREAM_END &&
QIODevice::atEnd() && mStream->atEnd();
203qint64 CompressionStream::readData(
char *data, qint64 dataSize)
207 if (mResult == LZMA_STREAM_END) {
209 }
else if (mResult != LZMA_OK) {
213 mCompressor->setOutputBuffer(data, dataSize);
215 while (dataSize > 0) {
216 if (mCompressor->inputBufferAvailable() == 0) {
217 mBuffer.resize(BUFSIZ);
218 const auto compressedDataRead = mStream->read(mBuffer.data(), mBuffer.size());
220 if (compressedDataRead > 0) {
221 mCompressor->setInputBuffer(mBuffer.data(), compressedDataRead);
227 mResult = mCompressor->inflate();
229 if (mResult != LZMA_OK && mResult != LZMA_STREAM_END) {
230 qCWarning(AKONADIPRIVATE_LOG) <<
"Error while decompressing LZMA stream:" << mResult.message();
234 const auto decompressedDataRead = dataSize - mCompressor->outputBufferAvailable();
235 dataRead += decompressedDataRead;
236 dataSize -= decompressedDataRead;
238 if (mResult == LZMA_STREAM_END) {
239 if (mStream->atEnd()) {
244 mCompressor->setOutputBuffer(data + dataRead, dataSize);
250qint64 CompressionStream::writeData(
const char *data, qint64 dataSize)
252 if (mResult != LZMA_OK) {
256 bool finish = (data ==
nullptr);
258 mCompressor->setInputBuffer(data, dataSize);
261 size_t dataWritten = 0;
263 while (dataSize > 0 || finish) {
264 mResult = mCompressor->deflate(finish);
266 if (mResult != LZMA_OK && mResult != LZMA_STREAM_END) {
267 qCWarning(AKONADIPRIVATE_LOG) <<
"Error while compressing LZMA stream:" << mResult.message();
271 if (mCompressor->inputBufferAvailable() == 0 || (mResult == LZMA_STREAM_END)) {
272 const auto wrote = dataSize - mCompressor->inputBufferAvailable();
274 dataWritten += wrote;
278 mCompressor->setInputBuffer(data + dataWritten, dataSize);
282 if (mCompressor->outputBufferAvailable() == 0 || (mResult == LZMA_STREAM_END) || finish) {
283 const auto toWrite = mBuffer.size() - mCompressor->outputBufferAvailable();
285 const auto writtenSize = mStream->write(mBuffer.constData(), toWrite);
286 if (writtenSize != toWrite) {
287 qCWarning(AKONADIPRIVATE_LOG) <<
"Failed to write compressed data to output device:" << mStream->errorString();
288 setErrorString(QStringLiteral(
"Failed to write compressed data to output device."));
293 if (mResult == LZMA_STREAM_END) {
297 mBuffer.resize(BUFSIZ);
298 mCompressor->setOutputBuffer(mBuffer.data(), mBuffer.size());
305bool CompressionStream::isCompressed(
QIODevice *data)
307 constexpr std::array<uchar, 6> magic = {0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00};
314 if (data->
peek(buf,
sizeof(buf)) !=
sizeof(buf)) {
318 return memcmp(magic.data(), buf,
sizeof(buf)) == 0;
321#include "moc_compressionstream_p.cpp"
Helper integration between Akonadi and Qt.
QString name(StandardAction id)
virtual bool atEnd() const const
bool isOpen() const const
bool isReadable() const const
virtual bool open(QIODeviceBase::OpenMode mode)
QByteArray peek(qint64 maxSize)