aboutsummaryrefslogtreecommitdiff
path: root/zencore
diff options
context:
space:
mode:
Diffstat (limited to 'zencore')
-rw-r--r--zencore/compress.cpp304
-rw-r--r--zencore/include/zencore/compress.h64
2 files changed, 268 insertions, 100 deletions
diff --git a/zencore/compress.cpp b/zencore/compress.cpp
index 805e962cd..ba62e7de2 100644
--- a/zencore/compress.cpp
+++ b/zencore/compress.cpp
@@ -7,6 +7,9 @@
#include <zencore/crc32.h>
#include <zencore/endian.h>
+#include "../3rdparty/Oodle/include/oodle2.h"
+#pragma comment(lib, "oo2core_win64.lib")
+
#include <doctest/doctest.h>
#include <lz4.h>
#include <functional>
@@ -19,6 +22,19 @@ static constexpr uint64_t DefaultBlockSize = 256 * 1024;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/** Method used to compress the data in a compressed buffer. */
+enum class CompressionMethod : uint8_t
+{
+ /** Header is followed by one uncompressed block. */
+ None = 0,
+ /** Header is followed by an array of compressed block sizes then the compressed blocks. */
+ Oodle = 3,
+ /** Header is followed by an array of compressed block sizes then the compressed blocks. */
+ LZ4 = 4,
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
/** Header used on every compressed buffer. Always stored in big-endian format. */
struct BufferHeader
{
@@ -28,7 +44,8 @@ struct BufferHeader
uint32_t Crc32 = 0; // A CRC-32 used to check integrity of the buffer. Uses the polynomial 0x04c11db7
CompressionMethod Method =
CompressionMethod::None; // The method used to compress the buffer. Affects layout of data following the header
- uint8_t Reserved[2]{}; // The reserved bytes must be initialized to zero
+ uint8_t Compressor = 0; // The method-specific compressor used to compress the buffer.
+ uint8_t CompressionLevel = 0; // The method-specific compression level used to compress the buffer.
uint8_t BlockSizeExponent = 0; // The power of two size of every uncompressed block except the last. Size is 1 << BlockSizeExponent
uint32_t BlockCount = 0; // The number of blocks that follow the header
uint64_t TotalRawSize = 0; // The total size of the uncompressed data
@@ -95,10 +112,15 @@ static_assert(sizeof(BufferHeader) == 64, "BufferHeader is the wrong size.");
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-class CompressionMethodBase
+class BaseEncoder
+{
+public:
+ virtual CompositeBuffer Compress(const CompositeBuffer& RawData, uint64_t BlockSize = DefaultBlockSize) const = 0;
+};
+
+class BaseDecoder
{
public:
- virtual CompositeBuffer Compress(const CompositeBuffer& RawData, uint64_t BlockSize = DefaultBlockSize) const = 0;
virtual CompositeBuffer Decompress(const BufferHeader& Header, const CompositeBuffer& CompressedData) const = 0;
virtual bool TryDecompressTo(const BufferHeader& Header, const CompositeBuffer& CompressedData, MutableMemoryView RawView) const = 0;
virtual uint64_t GetHeaderSize(const BufferHeader& Header) const = 0;
@@ -106,7 +128,7 @@ public:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-class MethodNone final : public CompressionMethodBase
+class NoneEncoder final : public BaseEncoder
{
public:
[[nodiscard]] CompositeBuffer Compress(const CompositeBuffer& RawData, uint64_t /* BlockSize */) const final
@@ -122,7 +144,11 @@ public:
Header.Write(HeaderData);
return CompositeBuffer(HeaderData.MoveToShared(), RawData.MakeOwned());
}
+};
+class NoneDecoder final : public BaseDecoder
+{
+public:
[[nodiscard]] CompositeBuffer Decompress(const BufferHeader& Header, const CompositeBuffer& CompressedData) const final
{
if (Header.Method == CompressionMethod::None && Header.TotalCompressedSize == CompressedData.GetSize() &&
@@ -152,24 +178,17 @@ public:
//////////////////////////////////////////////////////////////////////////
-class MethodBlockBase : public CompressionMethodBase
+class BlockEncoder : public BaseEncoder
{
public:
- CompositeBuffer Compress(const CompositeBuffer& RawData, uint64_t BlockSize = DefaultBlockSize) const final;
- CompositeBuffer Decompress(const BufferHeader& Header, const CompositeBuffer& CompressedData) const final;
- [[nodiscard]] bool TryDecompressTo(const BufferHeader& Header,
- const CompositeBuffer& CompressedData,
- MutableMemoryView RawView) const final;
- [[nodiscard]] uint64_t GetHeaderSize(const BufferHeader& Header) const final
- {
- return sizeof(BufferHeader) + sizeof(uint32_t) * uint64_t(Header.BlockCount);
- }
+ CompositeBuffer Compress(const CompositeBuffer& RawData, uint64_t BlockSize = DefaultBlockSize) const final;
protected:
- virtual CompressionMethod GetMethod() const = 0;
- virtual uint64_t CompressBlockBound(uint64_t RawSize) const = 0;
- virtual bool CompressBlock(MutableMemoryView& CompressedData, MemoryView RawData) const = 0;
- virtual bool DecompressBlock(MutableMemoryView RawData, MemoryView CompressedData) const = 0;
+ virtual CompressionMethod GetMethod() const = 0;
+ virtual uint8_t GetCompressor() const = 0;
+ virtual uint8_t GetCompressionLevel() const = 0;
+ virtual uint64_t CompressBlockBound(uint64_t RawSize) const = 0;
+ virtual bool CompressBlock(MutableMemoryView& CompressedData, MemoryView RawData) const = 0;
private:
uint64_t GetCompressedBlocksBound(uint64_t BlockCount, uint64_t BlockSize, uint64_t RawSize) const
@@ -187,7 +206,7 @@ private:
};
CompositeBuffer
-MethodBlockBase::Compress(const CompositeBuffer& RawData, const uint64_t BlockSize) const
+BlockEncoder::Compress(const CompositeBuffer& RawData, const uint64_t BlockSize) const
{
ZEN_ASSERT(IsPow2(BlockSize) && BlockSize <= (1 << 31));
@@ -242,7 +261,7 @@ MethodBlockBase::Compress(const CompositeBuffer& RawData, const uint64_t BlockSi
if (RawSize <= MetaSize + CompressedSize)
{
CompressedData.Reset();
- return MethodNone().Compress(RawData, BlockSize);
+ return NoneEncoder().Compress(RawData, BlockSize);
}
// Write the header and calculate the CRC-32.
@@ -254,6 +273,8 @@ MethodBlockBase::Compress(const CompositeBuffer& RawData, const uint64_t BlockSi
BufferHeader Header;
Header.Method = GetMethod();
+ Header.Compressor = GetCompressor();
+ Header.CompressionLevel = GetCompressionLevel();
Header.BlockSizeExponent = static_cast<uint8_t>(zen::FloorLog2_64(BlockSize));
Header.BlockCount = static_cast<uint32_t>(BlockCount);
Header.TotalRawSize = RawSize;
@@ -265,8 +286,24 @@ MethodBlockBase::Compress(const CompositeBuffer& RawData, const uint64_t BlockSi
return CompositeBuffer(SharedBuffer::MakeView(CompositeView, CompressedData.MoveToShared()));
}
+class BlockDecoder : public BaseDecoder
+{
+public:
+ CompositeBuffer Decompress(const BufferHeader& Header, const CompositeBuffer& CompressedData) const final;
+ [[nodiscard]] bool TryDecompressTo(const BufferHeader& Header,
+ const CompositeBuffer& CompressedData,
+ MutableMemoryView RawView) const final;
+ [[nodiscard]] uint64_t GetHeaderSize(const BufferHeader& Header) const final
+ {
+ return sizeof(BufferHeader) + sizeof(uint32_t) * uint64_t(Header.BlockCount);
+ }
+
+protected:
+ virtual bool DecompressBlock(MutableMemoryView RawData, MemoryView CompressedData) const = 0;
+};
+
CompositeBuffer
-MethodBlockBase::Decompress(const BufferHeader& Header, const CompositeBuffer& CompressedData) const
+BlockDecoder::Decompress(const BufferHeader& Header, const CompositeBuffer& CompressedData) const
{
if (Header.BlockCount == 0 || Header.TotalCompressedSize != CompressedData.GetSize())
{
@@ -383,7 +420,7 @@ MethodBlockBase::Decompress(const BufferHeader& Header, const CompositeBuffer& C
}
bool
-MethodBlockBase::TryDecompressTo(const BufferHeader& Header, const CompositeBuffer& CompressedData, MutableMemoryView RawView) const
+BlockDecoder::TryDecompressTo(const BufferHeader& Header, const CompositeBuffer& CompressedData, MutableMemoryView RawView) const
{
if (Header.TotalRawSize != RawView.GetSize() || Header.TotalCompressedSize != CompressedData.GetSize())
{
@@ -436,35 +473,115 @@ MethodBlockBase::TryDecompressTo(const BufferHeader& Header, const CompositeBuff
//////////////////////////////////////////////////////////////////////////
-class MethodLZ4 final : public MethodBlockBase
+struct OodleInit
{
+ OodleInit()
+ {
+ OodleConfigValues Config;
+ Oodle_GetConfigValues(&Config);
+ // Always read/write Oodle v9 binary data.
+ Config.m_OodleLZ_BackwardsCompatible_MajorVersion = 9;
+ Oodle_SetConfigValues(&Config);
+ }
+};
+
+OodleInit InitOodle;
+
+class OodleEncoder final : public BlockEncoder
+{
+public:
+ OodleEncoder(OodleCompressor InCompressor, OodleCompressionLevel InCompressionLevel)
+ : Compressor(InCompressor)
+ , CompressionLevel(InCompressionLevel)
+ {
+ }
+
protected:
- CompressionMethod GetMethod() const final { return CompressionMethod::LZ4; }
+ CompressionMethod GetMethod() const final { return CompressionMethod::Oodle; }
+ uint8_t GetCompressor() const final { return static_cast<uint8_t>(Compressor); }
+ uint8_t GetCompressionLevel() const final { return static_cast<uint8_t>(CompressionLevel); }
uint64_t CompressBlockBound(uint64_t RawSize) const final
{
- if (RawSize <= LZ4_MAX_INPUT_SIZE)
+ return static_cast<uint64_t>(OodleLZ_GetCompressedBufferSizeNeeded(OodleLZ_Compressor_Kraken, static_cast<OO_SINTa>(RawSize)));
+ }
+
+ bool CompressBlock(MutableMemoryView& CompressedData, MemoryView RawData) const final
+ {
+ const OodleLZ_Compressor LZCompressor = GetOodleLZCompressor(Compressor);
+ const OodleLZ_CompressionLevel LZCompressionLevel = GetOodleLZCompressionLevel(CompressionLevel);
+ if (LZCompressor == OodleLZ_Compressor_Invalid || LZCompressionLevel == OodleLZ_CompressionLevel_Invalid ||
+ LZCompressionLevel == OodleLZ_CompressionLevel_None)
{
- return static_cast<uint64_t>(LZ4_compressBound(static_cast<int>(RawSize)));
+ return false;
}
- return 0;
+
+ const OO_SINTa RawSize = static_cast<OO_SINTa>(RawData.GetSize());
+ if (static_cast<OO_SINTa>(CompressedData.GetSize()) < OodleLZ_GetCompressedBufferSizeNeeded(LZCompressor, RawSize))
+ {
+ return false;
+ }
+
+ const OO_SINTa Size = OodleLZ_Compress(LZCompressor, RawData.GetData(), RawSize, CompressedData.GetData(), LZCompressionLevel);
+ CompressedData.LeftInline(static_cast<uint64_t>(Size));
+ return Size > 0;
}
- bool CompressBlock(MutableMemoryView& CompressedData, MemoryView RawData) const final
+ static OodleLZ_Compressor GetOodleLZCompressor(OodleCompressor Compressor)
{
- if (RawData.GetSize() <= LZ4_MAX_INPUT_SIZE)
+ switch (Compressor)
{
- const int Size =
- LZ4_compress_default(static_cast<const char*>(RawData.GetData()),
- static_cast<char*>(CompressedData.GetData()),
- static_cast<int>(RawData.GetSize()),
- static_cast<int>(zen::Min<uint64_t>(CompressedData.GetSize(), std::numeric_limits<int>::max())));
- CompressedData.LeftInline(static_cast<uint64_t>(Size));
- return Size > 0;
+ case OodleCompressor::Selkie:
+ return OodleLZ_Compressor_Selkie;
+ case OodleCompressor::Mermaid:
+ return OodleLZ_Compressor_Mermaid;
+ case OodleCompressor::Kraken:
+ return OodleLZ_Compressor_Kraken;
+ case OodleCompressor::Leviathan:
+ return OodleLZ_Compressor_Leviathan;
+ case OodleCompressor::NotSet:
+ default:
+ return OodleLZ_Compressor_Invalid;
}
- return false;
}
+ static OodleLZ_CompressionLevel GetOodleLZCompressionLevel(OodleCompressionLevel Level)
+ {
+ const int IntLevel = (int)Level;
+ if (IntLevel < (int)OodleLZ_CompressionLevel_Min || IntLevel > (int)OodleLZ_CompressionLevel_Max)
+ {
+ return OodleLZ_CompressionLevel_Invalid;
+ }
+ return OodleLZ_CompressionLevel(IntLevel);
+ }
+
+private:
+ const OodleCompressor Compressor;
+ const OodleCompressionLevel CompressionLevel;
+};
+
+class OodleDecoder final : public BlockDecoder
+{
+protected:
+ bool DecompressBlock(MutableMemoryView RawData, MemoryView CompressedData) const final
+ {
+ const OO_SINTa RawSize = static_cast<OO_SINTa>(RawData.GetSize());
+ const OO_SINTa Size = OodleLZ_Decompress(CompressedData.GetData(),
+ static_cast<OO_SINTa>(CompressedData.GetSize()),
+ RawData.GetData(),
+ RawSize,
+ OodleLZ_FuzzSafe_Yes,
+ OodleLZ_CheckCRC_Yes,
+ OodleLZ_Verbosity_None);
+ return Size == RawSize;
+ }
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+class LZ4Decoder final : public BlockDecoder
+{
+protected:
bool DecompressBlock(MutableMemoryView RawData, MemoryView CompressedData) const final
{
if (CompressedData.GetSize() <= std::numeric_limits<int>::max())
@@ -481,11 +598,12 @@ protected:
//////////////////////////////////////////////////////////////////////////
-static const CompressionMethodBase*
-GetMethod(CompressionMethod Method)
+static const BaseDecoder*
+GetDecoder(CompressionMethod Method)
{
- static MethodNone None;
- static MethodLZ4 LZ4;
+ static NoneDecoder None;
+ static OodleDecoder Oodle;
+ static LZ4Decoder LZ4;
switch (Method)
{
@@ -493,25 +611,13 @@ GetMethod(CompressionMethod Method)
return nullptr;
case CompressionMethod::None:
return &None;
+ case CompressionMethod::Oodle:
+ return &Oodle;
case CompressionMethod::LZ4:
return &LZ4;
}
}
-static const char*
-GetMethodName(CompressionMethod Method)
-{
- switch (Method)
- {
- default:
- return "error";
- case CompressionMethod::None:
- return "None";
- case CompressionMethod::LZ4:
- return "LZ4";
- }
-}
-
//////////////////////////////////////////////////////////////////////////
bool
@@ -522,10 +628,10 @@ BufferHeader::IsValid(const CompositeBuffer& CompressedData)
const BufferHeader Header = Read(CompressedData);
if (Header.Magic == BufferHeader::ExpectedMagic)
{
- if (const CompressionMethodBase* const Method = GetMethod(Header.Method))
+ if (const BaseDecoder* const Decoder = GetDecoder(Header.Method))
{
UniqueBuffer HeaderCopy;
- const MemoryView HeaderView = CompressedData.ViewOrCopyRange(0, Method->GetHeaderSize(Header), HeaderCopy);
+ const MemoryView HeaderView = CompressedData.ViewOrCopyRange(0, Decoder->GetHeaderSize(Header), HeaderCopy);
if (Header.Crc32 == BufferHeader::CalculateCrc32(HeaderView))
{
return true;
@@ -550,22 +656,37 @@ ValidBufferOrEmpty(BufferType&& CompressedData)
namespace zen {
CompressedBuffer
-CompressedBuffer::Compress(CompressionMethod Method, const CompositeBuffer& RawData)
+CompressedBuffer::Compress(const CompositeBuffer& RawData,
+ OodleCompressor Compressor,
+ OodleCompressionLevel CompressionLevel,
+ uint64_t BlockSize)
{
using namespace detail;
+ if (BlockSize == 0)
+ {
+ BlockSize = DefaultBlockSize;
+ }
+
CompressedBuffer Local;
- if (const CompressionMethodBase* const Impl = GetMethod(Method))
+ if (CompressionLevel == OodleCompressionLevel::None)
{
- Local.CompressedData = Impl->Compress(RawData);
+ Local.CompressedData = NoneEncoder().Compress(RawData, BlockSize);
+ }
+ else
+ {
+ Local.CompressedData = OodleEncoder(Compressor, CompressionLevel).Compress(RawData, BlockSize);
}
return Local;
}
CompressedBuffer
-CompressedBuffer::Compress(CompressionMethod Method, const SharedBuffer& RawData)
+CompressedBuffer::Compress(const SharedBuffer& RawData,
+ OodleCompressor Compressor,
+ OodleCompressionLevel CompressionLevel,
+ uint64_t BlockSize)
{
- return Compress(Method, CompositeBuffer(RawData));
+ return Compress(CompositeBuffer(RawData), Compressor, CompressionLevel, BlockSize);
}
CompressedBuffer
@@ -619,9 +740,9 @@ CompressedBuffer::TryDecompressTo(MutableMemoryView RawView) const
if (CompressedData)
{
const BufferHeader Header = BufferHeader::Read(CompressedData);
- if (const CompressionMethodBase* const Method = GetMethod(Header.Method))
+ if (const BaseDecoder* const Decoder = GetDecoder(Header.Method))
{
- return Method->TryDecompressTo(Header, CompressedData, RawView);
+ return Decoder->TryDecompressTo(Header, CompressedData, RawView);
}
}
return false;
@@ -634,14 +755,14 @@ CompressedBuffer::Decompress() const
if (CompressedData)
{
const BufferHeader Header = BufferHeader::Read(CompressedData);
- if (const CompressionMethodBase* const Method = GetMethod(Header.Method))
+ if (const BaseDecoder* const Decoder = GetDecoder(Header.Method))
{
if (Header.Method == CompressionMethod::None)
{
- return Method->Decompress(Header, CompressedData).Flatten();
+ return Decoder->Decompress(Header, CompressedData).Flatten();
}
UniqueBuffer RawData = UniqueBuffer::Alloc(Header.TotalRawSize);
- if (Method->TryDecompressTo(Header, CompressedData, RawData))
+ if (Decoder->TryDecompressTo(Header, CompressedData, RawData))
{
return RawData.MoveToShared();
}
@@ -657,18 +778,35 @@ CompressedBuffer::DecompressToComposite() const
if (CompressedData)
{
const BufferHeader Header = BufferHeader::Read(CompressedData);
- if (const CompressionMethodBase* const Method = GetMethod(Header.Method))
+ if (const BaseDecoder* const Decoder = GetDecoder(Header.Method))
{
- return Method->Decompress(Header, CompressedData);
+ return Decoder->Decompress(Header, CompressedData);
}
}
return CompositeBuffer();
}
-const char*
-CompressedBuffer::GetFormatName() const
+bool
+CompressedBuffer::TryGetCompressParameters(OodleCompressor& OutCompressor, OodleCompressionLevel& OutCompressionLevel) const
{
- return detail::GetMethodName(CompressedData ? detail::BufferHeader::Read(CompressedData).Method : CompressionMethod::None);
+ using namespace detail;
+ if (CompressedData)
+ {
+ switch (const BufferHeader Header = BufferHeader::Read(CompressedData); Header.Method)
+ {
+ case CompressionMethod::None:
+ OutCompressor = OodleCompressor::NotSet;
+ OutCompressionLevel = OodleCompressionLevel::None;
+ return true;
+ case CompressionMethod::Oodle:
+ OutCompressor = OodleCompressor(Header.Compressor);
+ OutCompressionLevel = OodleCompressionLevel(Header.CompressionLevel);
+ return true;
+ default:
+ break;
+ }
+ }
+ return false;
}
/**
@@ -682,13 +820,14 @@ CompressedBuffer::GetFormatName() const
TEST_CASE("CompressedBuffer")
{
- uint8_t Zeroes[256]{};
- uint8_t Ones[256];
+ uint8_t Zeroes[1024]{};
+ uint8_t Ones[1024];
memset(Ones, 1, sizeof Ones);
{
- CompressedBuffer Buffer =
- CompressedBuffer::Compress(CompressionMethod::None, CompositeBuffer(SharedBuffer::MakeView(MakeMemoryView(Zeroes))));
+ CompressedBuffer Buffer = CompressedBuffer::Compress(CompositeBuffer(SharedBuffer::MakeView(MakeMemoryView(Zeroes))),
+ OodleCompressor::NotSet,
+ OodleCompressionLevel::None);
CHECK(Buffer.GetRawSize() == sizeof(Zeroes));
CHECK(Buffer.GetCompressedSize() == (sizeof(Zeroes) + sizeof(detail::BufferHeader)));
@@ -706,8 +845,9 @@ TEST_CASE("CompressedBuffer")
{
CompressedBuffer Buffer = CompressedBuffer::Compress(
- CompressionMethod::None,
- CompositeBuffer(SharedBuffer::MakeView(MakeMemoryView(Zeroes)), SharedBuffer::MakeView(MakeMemoryView(Ones))));
+ CompositeBuffer(SharedBuffer::MakeView(MakeMemoryView(Zeroes)), SharedBuffer::MakeView(MakeMemoryView(Ones))),
+ OodleCompressor::NotSet,
+ OodleCompressionLevel::None);
CHECK(Buffer.GetRawSize() == (sizeof(Zeroes) + sizeof(Ones)));
CHECK(Buffer.GetCompressedSize() == (sizeof(Zeroes) + sizeof(Ones) + sizeof(detail::BufferHeader)));
@@ -724,11 +864,10 @@ TEST_CASE("CompressedBuffer")
}
{
- CompressedBuffer Buffer =
- CompressedBuffer::Compress(CompressionMethod::LZ4, CompositeBuffer(SharedBuffer::MakeView(MakeMemoryView(Zeroes))));
+ CompressedBuffer Buffer = CompressedBuffer::Compress(CompositeBuffer(SharedBuffer::MakeView(MakeMemoryView(Zeroes))));
CHECK(Buffer.GetRawSize() == sizeof(Zeroes));
- CHECK(Buffer.GetCompressedSize() == (15 + sizeof(detail::BufferHeader)));
+ CHECK(Buffer.GetCompressedSize() < sizeof(Zeroes));
CompositeBuffer Compressed = Buffer.GetCompressed();
CompressedBuffer BufferD = CompressedBuffer::FromCompressed(Compressed);
@@ -743,11 +882,10 @@ TEST_CASE("CompressedBuffer")
{
CompressedBuffer Buffer = CompressedBuffer::Compress(
- CompressionMethod::LZ4,
CompositeBuffer(SharedBuffer::MakeView(MakeMemoryView(Zeroes)), SharedBuffer::MakeView(MakeMemoryView(Ones))));
CHECK(Buffer.GetRawSize() == (sizeof(Zeroes) + sizeof(Ones)));
- CHECK(Buffer.GetCompressedSize() == (20 + sizeof(detail::BufferHeader)));
+ CHECK(Buffer.GetCompressedSize() < (sizeof(Zeroes) + sizeof(Ones)));
CompositeBuffer Compressed = Buffer.GetCompressed();
CompressedBuffer BufferD = CompressedBuffer::FromCompressed(Compressed);
diff --git a/zencore/include/zencore/compress.h b/zencore/include/zencore/compress.h
index 1ab61e1be..6a65071d3 100644
--- a/zencore/include/zencore/compress.h
+++ b/zencore/include/zencore/compress.h
@@ -9,13 +9,30 @@
namespace zen {
-/** Method used to compress the data in a compressed buffer. */
-enum class CompressionMethod : uint8_t
+enum class OodleCompressor : uint8_t
{
- /** Header is followed by one uncompressed block. */
- None = 0,
- /** Header is followed by an array of compressed block sizes then the compressed blocks. */
- LZ4 = 4,
+ NotSet = 0,
+ Selkie = 1,
+ Mermaid = 2,
+ Kraken = 3,
+ Leviathan = 4,
+};
+
+enum class OodleCompressionLevel : int8_t
+{
+ HyperFast4 = -4,
+ HyperFast3 = -3,
+ HyperFast2 = -2,
+ HyperFast1 = -1,
+ None = 0,
+ SuperFast = 1,
+ VeryFast = 2,
+ Fast = 3,
+ Normal = 4,
+ Optimal1 = 5,
+ Optimal2 = 6,
+ Optimal3 = 7,
+ Optimal4 = 8,
};
/**
@@ -28,14 +45,26 @@ class CompressedBuffer
{
public:
/**
- * Compress the buffer using the requested compression format.
+ * Compress the buffer using the specified compressor and compression level.
+ *
+ * Data that does not compress will be return uncompressed, as if with level None.
+ *
+ * @note Using a level of None will return a buffer that references owned raw data.
*
- * @param FormatName One of NAME_None, NAME_Default, NAME_LZ4.
- * @param RawData Raw data to compress. NAME_None will reference owned raw data.
+ * @param RawData The raw data to be compressed.
+ * @param Compressor The compressor to encode with. May use NotSet if level is None.
+ * @param CompressionLevel The compression level to encode with.
+ * @param BlockSize The power-of-two block size to encode raw data in. 0 is default.
* @return An owned compressed buffer, or null on error.
*/
- [[nodiscard]] ZENCORE_API static CompressedBuffer Compress(CompressionMethod Method, const CompositeBuffer& RawData);
- [[nodiscard]] ZENCORE_API static CompressedBuffer Compress(CompressionMethod Method, const SharedBuffer& RawData);
+ [[nodiscard]] ZENCORE_API static CompressedBuffer Compress(const CompositeBuffer& RawData,
+ OodleCompressor Compressor = OodleCompressor::Mermaid,
+ OodleCompressionLevel CompressionLevel = OodleCompressionLevel::VeryFast,
+ uint64_t BlockSize = 0);
+ [[nodiscard]] ZENCORE_API static CompressedBuffer Compress(const SharedBuffer& RawData,
+ OodleCompressor Compressor = OodleCompressor::Mermaid,
+ OodleCompressionLevel CompressionLevel = OodleCompressionLevel::VeryFast,
+ uint64_t BlockSize = 0);
/**
* Construct from a compressed buffer previously created by Compress().
@@ -77,15 +106,16 @@ public:
[[nodiscard]] ZENCORE_API BLAKE3 GetRawHash() const;
/**
- * Returns the name of the compression format used by this buffer.
+ * Returns the compressor and compression level used by this buffer.
*
- * The format name may differ from the format name specified when creating the compressed buffer
- * because an incompressible buffer is stored with NAME_None, and a request of NAME_Default will
- * be stored in a specific format such as NAME_LZ4.
+ * The compressor and compression level may differ from those specified when creating the buffer
+ * because an incompressible buffer is stored with no compression. Parameters cannot be accessed
+ * if this is null or uses a method other than Oodle, in which case this returns false.
*
- * @return The format name, or NAME_None if this null, or NAME_Error if the format is unknown.
+ * @return True if parameters were written, otherwise false.
*/
- [[nodiscard]] ZENCORE_API const char* GetFormatName() const;
+ [[nodiscard]] ZENCORE_API bool TryGetCompressParameters(OodleCompressor& OutCompressor,
+ OodleCompressionLevel& OutCompressionLevel) const;
/**
* Decompress into a memory view that is exactly GetRawSize() bytes.