File: gzipcompressor.cpp

package info (click to toggle)
qflipper 1.3.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 12,320 kB
  • sloc: cpp: 18,500; sh: 247; ansic: 191; xml: 38; python: 14; makefile: 5
file content (117 lines) | stat: -rw-r--r-- 2,953 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "gzipcompressor.h"

#include <QtConcurrent/QtConcurrentRun>
#include <QLoggingCategory>
#include <QFutureWatcher>
#include <QIODevice>
#include <QDebug>

#include <zlib.h>

Q_DECLARE_LOGGING_CATEGORY(LOG_UNZIP)

#define CHUNK_SIZE 1024

GZipCompressor::GZipCompressor(QIODevice *in, QIODevice *out, QObject *parent):
    QObject(parent),
    m_in(in),
    m_out(out),
    m_progress(0)
{
    if(!m_in->open(QIODevice::ReadOnly)) {
        setError(BackendError::DiskError, m_in->errorString());
        return;

    } else if(!m_out->open(QIODevice::WriteOnly)) {
        setError(BackendError::DiskError, m_out->errorString());
        return;
    }

    auto *watcher = new QFutureWatcher<void>(this);

    connect(watcher, &QFutureWatcherBase::finished, this, [=]() {
        qCDebug(LOG_UNZIP).noquote() << "Compression finished:" << errorString();
        watcher->deleteLater();
        emit finished();
    });
#if QT_VERSION < 0x060000
    watcher->setFuture(QtConcurrent::run(this, &GZipCompressor::doCompress));
#else
    watcher->setFuture(QtConcurrent::run(&GZipCompressor::doCompress, this));
#endif
}

double GZipCompressor::progress() const
{
    return m_progress;
}

void GZipCompressor::setProgress(double progress)
{
    if(qFuzzyCompare(m_progress, progress)) {
        return;
    }

    m_progress = progress;
    emit progressChanged();
}

void GZipCompressor::doCompress()
{
    const auto totalSize = m_in->bytesAvailable();

    if(!totalSize) {
        setError(BackendError::DataError, QStringLiteral("The input file is empty"));
        return;
    }

    qCDebug(LOG_UNZIP) << "Compressing file with size of" << totalSize << "bytes...";

    z_stream stream;
    stream.zalloc = Z_NULL;
    stream.zfree = Z_NULL;
    stream.opaque = Z_NULL;

    const auto err = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 | 16, 8, Z_DEFAULT_STRATEGY);
    if(err != Z_OK) {
        setError(BackendError::UnknownError, QStringLiteral("Failed to initialise deflate method"));
        return;
    }

    char inbuf[CHUNK_SIZE];
    char outbuf[CHUNK_SIZE];
    int flushMode;

    do {
        const auto n = m_in->read(inbuf, CHUNK_SIZE);
        stream.avail_in = n;
        stream.next_in = (Bytef*)inbuf;
        flushMode = m_in->bytesAvailable() ? Z_NO_FLUSH : Z_FINISH;

        do {
            stream.avail_out = CHUNK_SIZE;
            stream.next_out = (Bytef*)outbuf;

            const auto err = deflate(&stream, flushMode);

            if(err == Z_STREAM_ERROR) {
                deflateEnd(&stream);
                setError(BackendError::DataError, QStringLiteral("Error during compression"));
                return;
            }

            m_out->write(outbuf, CHUNK_SIZE - stream.avail_out);

        } while(!stream.avail_out);

    } while(flushMode != Z_FINISH);

    deflateEnd(&stream);
    closeFiles();
}

void GZipCompressor::closeFiles()
{
    m_in->close();
    m_out->close();
}