mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-06-14 16:57:58 -05:00
Add IW3 zone writing
This commit is contained in:
138
src/ZoneWriting/Writing/Processor/OutputProcessorDeflate.cpp
Normal file
138
src/ZoneWriting/Writing/Processor/OutputProcessorDeflate.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
#include "OutputProcessorDeflate.h"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "Utils/ClassUtils.h"
|
||||
#include "Writing/WritingException.h"
|
||||
|
||||
class OutputProcessorDeflate::Impl
|
||||
{
|
||||
z_stream m_stream{};
|
||||
OutputProcessorDeflate* m_base;
|
||||
|
||||
std::unique_ptr<uint8_t[]> m_buffer;
|
||||
size_t m_buffer_size;
|
||||
|
||||
public:
|
||||
Impl(OutputProcessorDeflate* baseClass, const size_t bufferSize)
|
||||
: m_buffer(std::make_unique<uint8_t[]>(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<const Bytef*>(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();
|
||||
}
|
Reference in New Issue
Block a user