diff --git a/CMakeLists.txt b/CMakeLists.txt index 6cd54a9..6e18879 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,7 @@ project(DbCoreLib) find_package(Qt5Core CONFIG REQUIRED) find_package(Qt5Test CONFIG REQUIRED) find_package(Qt5LinguistTools CONFIG REQUIRED) +find_package(ZLIB REQUIRED) enable_testing() @@ -11,6 +12,7 @@ set(HEADERS dbcorelib_global.h fifostream.h fixedsizematrix.h + gzipdevice.h randomdevice.h waverecorder.h utils/datastreamutils.h @@ -21,6 +23,7 @@ set(HEADERS set(SOURCES fifostream.cpp + gzipdevice.cpp randomdevice.cpp waverecorder.cpp utils/fileutils.cpp @@ -41,7 +44,7 @@ add_library(dbcorelib SHARED ${HEADERS} ${SOURCES} ${TRANSLATIONS_C}) target_compile_definitions(dbcorelib PRIVATE DBCORELIB_LIBRARY) -target_link_libraries(dbcorelib Qt5::Core) +target_link_libraries(dbcorelib Qt5::Core z) target_include_directories(dbcorelib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) @@ -50,4 +53,4 @@ add_dependencies(libs dbcorelib) add_executable(tst_fixedsizematrix tst_fixedsizematrix.cpp) add_test(tst_fixedsizematrix tst_fixedsizematrix) -target_link_libraries(tst_fixedsizematrix Qt5::Core Qt5::Test dbcorelib) +target_link_libraries(tst_fixedsizematrix stdc++ Qt5::Core Qt5::Test dbcorelib) diff --git a/gzipdevice.cpp b/gzipdevice.cpp new file mode 100644 index 0000000..755a6cb --- /dev/null +++ b/gzipdevice.cpp @@ -0,0 +1,80 @@ +#include "gzipdevice.h" + +#include + +#include + +#include + +GzipDevice::GzipDevice(QFile &file, QObject *parent) : + QIODevice(parent), + m_file(file), + m_strm(std::make_unique()) +{ + if (!m_file.isOpen()) + throw std::runtime_error("file is not open"); + + setOpenMode(QIODevice::ReadOnly); + + // Prepare inflater status + m_strm->zalloc = Z_NULL; + m_strm->zfree = Z_NULL; + m_strm->opaque = Z_NULL; + m_strm->avail_in = 0; + m_strm->next_in = Z_NULL; + + // Initialize inflater + m_result = inflateInit2(m_strm.get(), 15 + 16); + if (m_result != Z_OK) + throw std::runtime_error("could not init z_stream"); +} + +GzipDevice::~GzipDevice() +{ + inflateEnd(m_strm.get()); +} + +bool GzipDevice::isSequential() const +{ + return true; +} + +bool GzipDevice::atEnd() const +{ + return m_result == Z_STREAM_END; +} + +qint64 GzipDevice::readData(char *data, qint64 maxlen) +{ + if (m_strm->avail_in == 0) + { + m_strm->next_in = reinterpret_cast(m_readBuffer); + m_strm->avail_in = m_file.read(m_readBuffer, m_readBufferSize); + } + + m_strm->next_out = reinterpret_cast(data); + m_strm->avail_out = maxlen; + + m_result = inflate(m_strm.get(), Z_NO_FLUSH); + + switch (m_result) { + case Z_NEED_DICT: + throw std::runtime_error("decompression failed: Z_NEED_DICT"); + case Z_DATA_ERROR: + throw std::runtime_error("decompression failed: Z_DATA_ERROR"); + case Z_MEM_ERROR: + throw std::runtime_error("decompression failed: Z_MEM_ERROR"); + case Z_STREAM_ERROR: + throw std::runtime_error("decompression failed: Z_STREAM_ERROR"); + } + + return maxlen-m_strm->avail_out; +} + +qint64 GzipDevice::writeData(const char *data, qint64 len) +{ + Q_UNUSED(data) + Q_UNUSED(len) + throw std::runtime_error("writing not allowed!"); + return -1; +} diff --git a/gzipdevice.h b/gzipdevice.h new file mode 100644 index 0000000..a817380 --- /dev/null +++ b/gzipdevice.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include + +class QFile; + +typedef struct z_stream_s z_stream; + +class GzipDevice : public QIODevice +{ +public: + GzipDevice(QFile &file, QObject *parent = nullptr); + ~GzipDevice() override; + + bool isSequential() const override; + bool atEnd() const override; + +protected: + qint64 readData(char *data, qint64 maxlen) override; + qint64 writeData(const char *data, qint64 len) override; + +private: + QFile &m_file; + static constexpr std::size_t m_readBufferSize { 32 * 1024 }; + char m_readBuffer[m_readBufferSize]; + const std::unique_ptr m_strm; + int m_result; +};