#include "OutputProcessorDeflate.h" #include #include #include #include #include "Utils/ClassUtils.h" #include "Writing/WritingException.h" class OutputProcessorDeflate::Impl { z_stream m_stream{}; OutputProcessorDeflate* m_base; std::unique_ptr m_buffer; size_t m_buffer_size; public: Impl(OutputProcessorDeflate* baseClass, const size_t bufferSize) : m_buffer(std::make_unique(bufferSize)), m_buffer_size(bufferSize) { m_base = baseClass; m_stream.zalloc = Z_NULL; m_stream.zfree = Z_NULL; m_stream.opaque = Z_NULL; m_stream.avail_in = 0; m_stream.next_in = Z_NULL; m_stream.next_out = m_buffer.get(); m_stream.avail_out = m_buffer_size; const int ret = deflateInit(&m_stream, Z_DEFAULT_COMPRESSION); if (ret != Z_OK) { throw std::runtime_error("Initializing deflate failed"); } } ~Impl() { deflateEnd(&m_stream); } Impl(const Impl& other) = delete; Impl(Impl&& other) noexcept = default; Impl& operator=(const Impl& other) = delete; Impl& operator=(Impl&& other) noexcept = default; void Write(const void* buffer, const size_t length) { m_stream.next_in = static_cast(buffer); m_stream.avail_in = length; while (m_stream.avail_in > 0) { if (m_stream.avail_out == 0) { m_base->m_base_stream->Write(m_buffer.get(), m_buffer_size); m_stream.next_out = m_buffer.get(); m_stream.avail_out = m_buffer_size; } const auto ret = deflate(&m_stream, Z_NO_FLUSH); if (ret != Z_OK) throw WritingException("Failed to deflate memory of zone."); } } void Flush() { m_stream.avail_in = 0; m_stream.next_in = Z_NULL; while(true) { if (m_stream.avail_out < m_buffer_size) { m_base->m_base_stream->Write(m_buffer.get(), m_buffer_size - m_stream.avail_out); m_stream.next_out = m_buffer.get(); m_stream.avail_out = m_buffer_size; } const auto ret = deflate(&m_stream, Z_FINISH); if(ret == Z_OK) continue; if (ret != Z_STREAM_END) throw WritingException("Failed to flush deflate memory of zone."); break; } if (m_stream.avail_out < m_buffer_size) { m_base->m_base_stream->Write(m_buffer.get(), m_buffer_size - m_stream.avail_out); m_stream.next_out = m_buffer.get(); m_stream.avail_out = m_buffer_size; } } _NODISCARD int64_t Pos() const { return m_base->m_base_stream->Pos(); } }; OutputProcessorDeflate::OutputProcessorDeflate() : m_impl(new Impl(this, DEFAULT_BUFFER_SIZE)) { } OutputProcessorDeflate::OutputProcessorDeflate(const size_t bufferSize) : m_impl(new Impl(this, bufferSize)) { } OutputProcessorDeflate::~OutputProcessorDeflate() { delete m_impl; m_impl = nullptr; } void OutputProcessorDeflate::Write(const void* buffer, const size_t length) { m_impl->Write(buffer, length); } void OutputProcessorDeflate::Flush() { m_impl->Flush(); } int64_t OutputProcessorDeflate::Pos() { return m_impl->Pos(); }