aboutsummaryrefslogtreecommitdiff
path: root/src/zencore/include
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2023-05-23 10:13:47 +0200
committerGitHub <[email protected]>2023-05-23 10:13:47 +0200
commit633dee5f8688c104a04f0ec719b756dbbad7142f (patch)
treef0ce192964f6d6b9fd506f4963e261320803e2ac /src/zencore/include
parentMemoryView::RightChop -> const (diff)
downloadzen-633dee5f8688c104a04f0ec719b756dbbad7142f.tar.xz
zen-633dee5f8688c104a04f0ec719b756dbbad7142f.zip
streaming decompression support (#142)
Added CompressedBufferReader support from UE. This provides some streaming decompression support which can be employed to reduce memory and other resource usage.
Diffstat (limited to 'src/zencore/include')
-rw-r--r--src/zencore/include/zencore/compositebuffer.h14
-rw-r--r--src/zencore/include/zencore/compress.h118
-rw-r--r--src/zencore/include/zencore/intmath.h26
-rw-r--r--src/zencore/include/zencore/stream.h27
-rw-r--r--src/zencore/include/zencore/zencore.h4
5 files changed, 185 insertions, 4 deletions
diff --git a/src/zencore/include/zencore/compositebuffer.h b/src/zencore/include/zencore/compositebuffer.h
index 4e4b4d002..cc03dd156 100644
--- a/src/zencore/include/zencore/compositebuffer.h
+++ b/src/zencore/include/zencore/compositebuffer.h
@@ -62,8 +62,12 @@ public:
[[nodiscard]] ZENCORE_API CompositeBuffer MakeOwned() &&;
/** Returns the concatenation of the segments into a contiguous buffer. */
- [[nodiscard]] ZENCORE_API SharedBuffer Flatten() const&;
- [[nodiscard]] ZENCORE_API SharedBuffer Flatten() &&;
+ [[nodiscard]] inline SharedBuffer Flatten() const& { return ToShared(); }
+ [[nodiscard]] inline SharedBuffer Flatten() && { return ToShared(); }
+
+ /** Returns the concatenation of the segments into a contiguous buffer. */
+ [[nodiscard]] ZENCORE_API SharedBuffer ToShared() const&;
+ [[nodiscard]] ZENCORE_API SharedBuffer ToShared() &&;
/** Returns the middle part of the buffer by taking the size starting at the offset. */
[[nodiscard]] ZENCORE_API CompositeBuffer Mid(uint64_t Offset, uint64_t Size = ~uint64_t(0)) const;
@@ -76,8 +80,12 @@ public:
* @param Offset The byte offset in this buffer that the range starts at.
* @param Size The number of bytes in the range to view or copy.
* @param CopyBuffer The buffer to write the copy into if a copy is required.
+ * @param Allocator The optional allocator to use when the copy buffer is required.
*/
- [[nodiscard]] ZENCORE_API MemoryView ViewOrCopyRange(uint64_t Offset, uint64_t Size, UniqueBuffer& CopyBuffer) const;
+ [[nodiscard]] ZENCORE_API MemoryView ViewOrCopyRange(uint64_t Offset,
+ uint64_t Size,
+ UniqueBuffer& CopyBuffer,
+ std::function<UniqueBuffer(uint64_t Size)> Allocator = UniqueBuffer::Alloc) const;
/**
* Copies a range of the buffer to a contiguous region of memory.
diff --git a/src/zencore/include/zencore/compress.h b/src/zencore/include/zencore/compress.h
index 99ce20d8a..44431f299 100644
--- a/src/zencore/include/zencore/compress.h
+++ b/src/zencore/include/zencore/compress.h
@@ -6,9 +6,18 @@
#include "zencore/blake3.h"
#include "zencore/compositebuffer.h"
+#include "zencore/intmath.h"
+
+#include <limits>
namespace zen {
+class Archive;
+
+namespace detail {
+ struct BufferHeader;
+}
+
enum class OodleCompressor : uint8_t
{
NotSet = 0,
@@ -160,6 +169,115 @@ private:
CompositeBuffer CompressedData;
};
+namespace detail {
+ /** A reusable context for the compressed buffer decoder. */
+ struct DecoderContext
+ {
+ /** The offset in the source at which the compressed buffer begins, otherwise MAX_uint64. */
+ uint64_t HeaderOffset = MAX_uint64;
+ /** The size of the header if known, otherwise 0. */
+ uint64_t HeaderSize = 0;
+ /** The CRC-32 from the header, otherwise 0. */
+ uint32_t HeaderCrc32 = 0;
+ /** Index of the block stored in RawBlock, otherwise MAX_uint32. */
+ uint32_t RawBlockIndex = MAX_uint32;
+
+ /** A buffer used to store the header when HeaderOffset is not MAX_uint64. */
+ UniqueBuffer Header;
+ /** A buffer used to store a raw block when a partial block read is requested. */
+ UniqueBuffer RawBlock;
+ /** A buffer used to store a compressed block when it was not in contiguous memory. */
+ UniqueBuffer CompressedBlock;
+ };
+} // namespace detail
+
+/**
+ * A type that stores the state needed to decompress a compressed buffer.
+ *
+ * The compressed buffer can be in memory or can be loaded from a seekable archive.
+ *
+ * The reader can be reused across multiple source buffers, which allows its temporary buffers to
+ * be reused if they are the right size.
+ *
+ * It is only safe to use the reader from one thread at a time.
+ *
+ * @see CompressedBuffer
+ */
+class CompressedBufferReader
+{
+public:
+ /** Construct a reader with no source. */
+ CompressedBufferReader() = default;
+
+ /** Construct a reader that will read from an archive as needed. */
+ explicit CompressedBufferReader(Archive& Archive);
+
+ /** Construct a reader from an in-memory compressed buffer. */
+ explicit CompressedBufferReader(const CompressedBuffer& Buffer);
+
+ /** Release any temporary buffers that have been allocated by the reader. */
+ void ResetBuffers();
+
+ /** Clears the reference to the source without releasing temporary buffers. */
+ void ResetSource();
+
+ void SetSource(Archive& Archive);
+ void SetSource(const CompressedBuffer& Buffer);
+
+ [[nodiscard]] inline bool HasSource() const { return SourceArchive || SourceBuffer; }
+
+ /** Returns the size of the compressed data. Zero on error. */
+ [[nodiscard]] uint64_t GetCompressedSize();
+
+ /** Returns the size of the raw data. Zero on error. */
+ [[nodiscard]] uint64_t GetRawSize();
+
+ /** Returns the hash of the raw data. Zero on error. */
+ [[nodiscard]] IoHash GetRawHash();
+
+ /**
+ * Returns the compressor and compression level used by this buffer.
+ *
+ * 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 True if parameters were written, otherwise false.
+ */
+ [[nodiscard]] bool TryGetCompressParameters(OodleCompressor& OutCompressor,
+ OodleCompressionLevel& OutCompressionLevel,
+ uint64_t& OutBlockSize);
+
+ /**
+ * Decompress into a memory view that is less than or equal to the available raw size.
+ *
+ * @param RawView The view to write to. The size to read is equal to the view size.
+ * @param RawOffset The offset into the raw data from which to decompress.
+ * @return True if the requested range was decompressed, otherwise false.
+ */
+ [[nodiscard]] bool TryDecompressTo(MutableMemoryView RawView, uint64_t RawOffset = 0);
+
+ /**
+ * Decompress into an owned buffer.
+ *
+ * RawOffset must be at most the raw buffer size. RawSize may be MAX_uint64 to read the whole
+ * buffer from RawOffset, and must otherwise fit within the bounds of the buffer.
+ *
+ * @param RawOffset The offset into the raw data from which to decompress.
+ * @param RawSize The size of the raw data to read from the offset.
+ * @return An owned buffer containing the raw data, or null on error.
+ */
+ [[nodiscard]] SharedBuffer Decompress(uint64_t RawOffset = 0, uint64_t RawSize = MAX_uint64);
+ [[nodiscard]] CompositeBuffer DecompressToComposite(uint64_t RawOffset = 0, uint64_t RawSize = MAX_uint64);
+
+private:
+ bool TryReadHeader(detail::BufferHeader& OutHeader, MemoryView& OutHeaderView);
+
+ Archive* SourceArchive = nullptr;
+ const CompressedBuffer* SourceBuffer = nullptr;
+ detail::DecoderContext Context;
+};
+
void compress_forcelink(); // internal
} // namespace zen
diff --git a/src/zencore/include/zencore/intmath.h b/src/zencore/include/zencore/intmath.h
index f24caed6e..0d87e1b78 100644
--- a/src/zencore/include/zencore/intmath.h
+++ b/src/zencore/include/zencore/intmath.h
@@ -7,6 +7,32 @@
#include <stdint.h>
//////////////////////////////////////////////////////////////////////////
+// UE Numeric constants
+
+#define MIN_uint8 ((uint8_t)0x00)
+#define MIN_uint16 ((uint16_t)0x0000)
+#define MIN_uint32 ((uint32_t)0x00000000)
+#define MIN_uint64 ((uint64_t)0x0000000000000000)
+#define MIN_int8 ((int8_t)-128)
+#define MIN_int16 ((int16_t)-32768)
+#define MIN_int32 ((int32_t)0x80000000)
+#define MIN_int64 ((int64_t)0x8000000000000000)
+
+#define MAX_uint8 ((uint8_t)0xff)
+#define MAX_uint16 ((uint16_t)0xffff)
+#define MAX_uint32 ((uint32_t)0xffffffff)
+#define MAX_uint64 ((uint64_t)0xffffffffffffffff)
+#define MAX_int8 ((int8_t)0x7f)
+#define MAX_int16 ((int16_t)0x7fff)
+#define MAX_int32 ((int32_t)0x7fffffff)
+#define MAX_int64 ((int64_t)0x7fffffffffffffff)
+
+#define MIN_flt (1.175494351e-38F) /* min positive value */
+#define MAX_flt (3.402823466e+38F)
+#define MIN_dbl (2.2250738585072014e-308) /* min positive value */
+#define MAX_dbl (1.7976931348623158e+308)
+
+//////////////////////////////////////////////////////////////////////////
#if ZEN_COMPILER_MSC || ZEN_PLATFORM_WINDOWS
# pragma intrinsic(_BitScanReverse)
diff --git a/src/zencore/include/zencore/stream.h b/src/zencore/include/zencore/stream.h
index 9e4996249..a9d35ef1b 100644
--- a/src/zencore/include/zencore/stream.h
+++ b/src/zencore/include/zencore/stream.h
@@ -79,12 +79,37 @@ public:
inline uint64_t CurrentOffset() const { return m_Offset; }
inline void Skip(size_t ByteCount) { m_Offset += ByteCount; };
-private:
+protected:
const uint8_t* m_BufferBase;
uint64_t m_BufferSize;
uint64_t m_Offset = 0;
};
+/**
+ * Archive base class implementation
+ *
+ * Roughly mimics UE's FArchive class, but without all the non-essential functionality
+ */
+class Archive
+{
+public:
+ /** Attempts to set the current offset into backing data storage, this will do nothing if there is no storage. */
+ virtual void Seek(uint64_t InPos) = 0;
+ virtual int64_t Tell() = 0;
+ virtual void Serialize(void* V, int64_t Length) = 0;
+ inline bool IsError() { return false; }
+};
+
+class BufferReader : public Archive, private BinaryReader
+{
+public:
+ BufferReader(const void* Buffer, uint64_t Size) : BinaryReader(Buffer, Size) {}
+
+ virtual void Seek(uint64_t InPos) override;
+ virtual int64_t Tell() override;
+ virtual void Serialize(void* V, int64_t Length) override;
+};
+
void stream_forcelink(); // internal
} // namespace zen
diff --git a/src/zencore/include/zencore/zencore.h b/src/zencore/include/zencore/zencore.h
index 02e9dd5d6..47ff2ebc2 100644
--- a/src/zencore/include/zencore/zencore.h
+++ b/src/zencore/include/zencore/zencore.h
@@ -68,6 +68,10 @@
# pragma warning(disable : 4324) // warning C4324: '<type>': structure was padded due to alignment specifier
# pragma warning(default : 4668) // warning C4668: 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives'
# pragma warning(default : 4100) // warning C4100: 'identifier' : unreferenced formal parameter
+# pragma warning( \
+ disable : 4373) // '%$S': virtual function overrides '%$pS', previous versions of the compiler did not override when parameters
+ // only differed by const/volatile qualifiers
+ // https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-3-c4373
#endif
#ifndef ZEN_THIRD_PARTY_INCLUDES_START