diff options
| author | Martin Ridgers <[email protected]> | 2021-10-25 08:55:48 +0200 |
|---|---|---|
| committer | Martin Ridgers <[email protected]> | 2021-10-25 08:55:48 +0200 |
| commit | 11a96d0892907155aca82197bad3b8f0a8696057 (patch) | |
| tree | 11311a913e06f04ac35ceb9e1d96434a5bd78080 /zencore | |
| parent | Implemented filecas.cpp for POSIX platforms (diff) | |
| parent | zenserver: Tweaked state initialization so we know when we're running for the... (diff) | |
| download | zen-11a96d0892907155aca82197bad3b8f0a8696057.tar.xz zen-11a96d0892907155aca82197bad3b8f0a8696057.zip | |
Merged main
Diffstat (limited to 'zencore')
| -rw-r--r-- | zencore/compactbinarypackage.cpp | 46 | ||||
| -rw-r--r-- | zencore/compress.cpp | 193 | ||||
| -rw-r--r-- | zencore/include/zencore/compress.h | 2 | ||||
| -rw-r--r-- | zencore/include/zencore/fmtutils.h | 1 | ||||
| -rw-r--r-- | zencore/include/zencore/iobuffer.h | 5 | ||||
| -rw-r--r-- | zencore/include/zencore/refcount.h | 5 | ||||
| -rw-r--r-- | zencore/include/zencore/string.h | 2 | ||||
| -rw-r--r-- | zencore/include/zencore/windows.h | 2 | ||||
| -rw-r--r-- | zencore/iobuffer.cpp | 2 | ||||
| -rw-r--r-- | zencore/string.cpp | 4 |
10 files changed, 247 insertions, 15 deletions
diff --git a/zencore/compactbinarypackage.cpp b/zencore/compactbinarypackage.cpp index 88757d47f..f7ce371c8 100644 --- a/zencore/compactbinarypackage.cpp +++ b/zencore/compactbinarypackage.cpp @@ -635,6 +635,11 @@ namespace legacy { Writer.AddBinary(Attachment.AsBinary()); Writer.AddBinaryAttachment(Attachment.GetHash()); } + else if (Attachment.IsCompressedBinary()) + { + Writer.AddBinary(Attachment.AsCompressedBinary().GetCompressed()); + Writer.AddBinaryAttachment(Attachment.GetHash()); + } else if (Attachment.IsNull()) { Writer.AddBinary(MemoryView()); @@ -695,17 +700,32 @@ namespace legacy { SharedBuffer Buffer = SharedBuffer::MakeView(View, ValueField.GetOuterBuffer()).MakeOwned(); CbField HashField = LoadCompactBinary(Reader, Allocator); const IoHash& Hash = HashField.AsAttachment(); - if (HashField.HasError() || IoHash::HashBuffer(Buffer) != Hash) + if (HashField.HasError()) { return false; } - if (HashField.IsObjectAttachment()) + if (CompressedBuffer Compressed = CompressedBuffer::FromCompressed(Buffer)) { - Package.AddAttachment(CbAttachment(CbObject(std::move(Buffer)), Hash)); + if (IoHash::FromBLAKE3(Compressed.GetRawHash()) != Hash) + { + return false; + } + Package.AddAttachment(CbAttachment(Compressed)); } else { - Package.AddAttachment(CbAttachment(CompositeBuffer(std::move(Buffer)), Hash)); + if (IoHash::HashBuffer(Buffer) != Hash) + { + return false; + } + if (HashField.IsObjectAttachment()) + { + Package.AddAttachment(CbAttachment(CbObject(std::move(Buffer)), Hash)); + } + else + { + Package.AddAttachment(CbAttachment(CompositeBuffer(std::move(Buffer)), Hash)); + } } } } @@ -714,8 +734,22 @@ namespace legacy { const IoHash Hash = ValueField.AsHash(); ZEN_ASSERT(Mapper); - - Package.AddAttachment(CbAttachment((*Mapper)(Hash), Hash)); + if (SharedBuffer AttachmentData = (*Mapper)(Hash)) + { + if (CompressedBuffer Compressed = CompressedBuffer::FromCompressed(AttachmentData)) + { + Package.AddAttachment(CbAttachment(Compressed)); + } + else + { + const CbValidateError ValidationResult = ValidateCompactBinary(AttachmentData.GetView(), CbValidateMode::All); + if (ValidationResult != CbValidateError::None) + { + return false; + } + Package.AddAttachment(CbAttachment(CbObject(std::move(AttachmentData)), Hash)); + } + } } else { diff --git a/zencore/compress.cpp b/zencore/compress.cpp index 8d309e010..4a8d116fa 100644 --- a/zencore/compress.cpp +++ b/zencore/compress.cpp @@ -690,6 +690,90 @@ ValidBufferOrEmpty(BufferType&& CompressedData) return BufferHeader::IsValid(CompressedData) ? CompositeBuffer(std::forward<BufferType>(CompressedData)) : CompositeBuffer(); } +CompositeBuffer +CopyCompressedRange(const BufferHeader& Header, const CompositeBuffer& CompressedData, uint64_t RawOffset, uint64_t RawSize) +{ + if (Header.Method == CompressionMethod::None) + { + UniqueBuffer NewCompressedData = UniqueBuffer::Alloc(RawSize); + CompressedData.CopyTo(NewCompressedData.GetMutableView(), sizeof(Header) + RawOffset); + + BufferHeader NewHeader = Header; + NewHeader.Crc32 = 0; + NewHeader.TotalRawSize = RawSize; + NewHeader.TotalCompressedSize = NewHeader.TotalRawSize + sizeof(BufferHeader); + NewHeader.RawHash = BLAKE3(); + + UniqueBuffer HeaderData = UniqueBuffer::Alloc(sizeof(BufferHeader)); + NewHeader.Write(HeaderData); + + return CompositeBuffer(HeaderData.MoveToShared(), NewCompressedData.MoveToShared()); + } + else + { + UniqueBuffer BlockSizeBuffer; + MemoryView BlockSizeView = + CompressedData.ViewOrCopyRange(sizeof(BufferHeader), Header.BlockCount * sizeof(uint32_t), BlockSizeBuffer); + std::span<uint32_t const> CompressedBlockSizes(reinterpret_cast<const uint32_t*>(BlockSizeView.GetData()), Header.BlockCount); + + const uint64_t BlockSize = uint64_t(1) << Header.BlockSizeExponent; + const uint64_t LastBlockSize = BlockSize - ((Header.BlockCount * BlockSize) - Header.TotalRawSize); + const size_t FirstBlock = uint64_t(RawOffset / BlockSize); + const size_t LastBlock = uint64_t((RawOffset + RawSize - 1) / BlockSize); + uint64_t CompressedOffset = sizeof(BufferHeader) + uint64_t(Header.BlockCount) * sizeof(uint32_t); + + const uint64_t NewBlockCount = LastBlock - FirstBlock + 1; + const uint64_t NewMetaSize = NewBlockCount * sizeof(uint32_t); + uint64_t NewCompressedSize = 0; + uint64_t NewTotalRawSize = 0; + std::vector<uint32_t> NewCompressedBlockSizes; + + NewCompressedBlockSizes.reserve(NewBlockCount); + for (size_t BlockIndex = FirstBlock; BlockIndex <= LastBlock; ++BlockIndex) + { + const uint64_t UncompressedBlockSize = (BlockIndex == Header.BlockCount - 1) ? LastBlockSize : BlockSize; + NewTotalRawSize += UncompressedBlockSize; + + const uint32_t CompressedBlockSize = CompressedBlockSizes[BlockIndex]; + NewCompressedBlockSizes.push_back(CompressedBlockSize); + NewCompressedSize += ByteSwap(CompressedBlockSize); + } + + const uint64_t NewTotalCompressedSize = sizeof(BufferHeader) + NewBlockCount * sizeof(uint32_t) + NewCompressedSize; + UniqueBuffer NewCompressedData = UniqueBuffer::Alloc(NewTotalCompressedSize); + MutableMemoryView NewCompressedBlocks = NewCompressedData.GetMutableView() + sizeof(BufferHeader) + NewMetaSize; + + // Seek to first compressed block + for (size_t BlockIndex = 0; BlockIndex < FirstBlock; ++BlockIndex) + { + const uint64_t CompressedBlockSize = ByteSwap(CompressedBlockSizes[BlockIndex]); + CompressedOffset += CompressedBlockSize; + } + + // Copy blocks + UniqueBuffer CompressedBlockCopy; + const MemoryView CompressedRange = CompressedData.ViewOrCopyRange(CompressedOffset, NewCompressedSize, CompressedBlockCopy); + NewCompressedBlocks.CopyFrom(CompressedRange); + + // Copy block sizes + NewCompressedData.GetMutableView().Mid(sizeof(BufferHeader), NewMetaSize).CopyFrom(MakeMemoryView(NewCompressedBlockSizes)); + + BufferHeader NewHeader; + NewHeader.Crc32 = 0; + NewHeader.Method = Header.Method; + NewHeader.Compressor = Header.Compressor; + NewHeader.CompressionLevel = Header.CompressionLevel; + NewHeader.BlockSizeExponent = Header.BlockSizeExponent; + NewHeader.BlockCount = static_cast<uint32_t>(NewBlockCount); + NewHeader.TotalRawSize = NewTotalRawSize; + NewHeader.TotalCompressedSize = NewTotalCompressedSize; + NewHeader.RawHash = BLAKE3(); + NewHeader.Write(NewCompressedData.GetMutableView().Left(sizeof(BufferHeader) + NewMetaSize)); + + return CompositeBuffer(NewCompressedData.MoveToShared()); + } +} + } // namespace zen::detail namespace zen { @@ -774,6 +858,17 @@ CompressedBuffer::GetRawHash() const return CompressedData ? detail::BufferHeader::Read(CompressedData).RawHash : BLAKE3(); } +CompressedBuffer +CompressedBuffer::CopyRange(uint64_t RawOffset, uint64_t RawSize) const +{ + using namespace detail; + const BufferHeader Header = BufferHeader::Read(CompressedData); + CompressedBuffer Range; + Range.CompressedData = CopyCompressedRange(Header, CompressedData, RawOffset, RawSize); + + return Range; +} + bool CompressedBuffer::TryDecompressTo(MutableMemoryView RawView, uint64_t RawOffset) const { @@ -1040,6 +1135,104 @@ TEST_CASE("CompressedBuffer") ValidateData(Values, ExpectedValues, OffsetCount); } } + + SUBCASE("copy range") + { + const uint64_t BlockSize = 64 * sizeof(uint64_t); + const uint64_t N = 1000; + std::vector<uint64_t> ExpectedValues = GenerateData(N); + + CompressedBuffer Compressed = CompressedBuffer::Compress(SharedBuffer::MakeView(MakeMemoryView(ExpectedValues)), + OodleCompressor::Mermaid, + OodleCompressionLevel::Optimal4, + BlockSize); + + { + const uint64_t OffsetCount = 0; + const uint64_t Count = N; + SharedBuffer Uncompressed = Compressed.CopyRange(OffsetCount * sizeof(uint64_t), Count * sizeof(uint64_t)).Decompress(); + std::span<uint64_t const> Values((const uint64_t*)Uncompressed.GetData(), Uncompressed.GetSize() / sizeof(uint64_t)); + CHECK(Values.size() == Count); + ValidateData(Values, ExpectedValues, OffsetCount); + } + + { + const uint64_t OffsetCount = 64; + const uint64_t Count = N - 64; + SharedBuffer Uncompressed = Compressed.CopyRange(OffsetCount * sizeof(uint64_t), Count * sizeof(uint64_t)).Decompress(); + std::span<uint64_t const> Values((const uint64_t*)Uncompressed.GetData(), Uncompressed.GetSize() / sizeof(uint64_t)); + CHECK(Values.size() == Count); + ValidateData(Values, ExpectedValues, OffsetCount); + } + + { + const uint64_t OffsetCount = 64 * 2 + 32; + const uint64_t Count = N - OffsetCount; + const uint64_t RawOffset = OffsetCount * sizeof(uint64_t); + const uint64_t RawSize = Count * sizeof(uint64_t); + uint64_t FirstBlockOffset = RawOffset % BlockSize; + + SharedBuffer Uncompressed = Compressed.CopyRange(RawOffset, RawSize).Decompress(); + std::span<uint64_t const> AllValues((const uint64_t*)Uncompressed.GetData(), RawSize / sizeof(uint64_t)); + std::span<uint64_t const> Values((const uint64_t*)(((const uint8_t*)(Uncompressed.GetData()) + FirstBlockOffset)), + RawSize / sizeof(uint64_t)); + CHECK(Values.size() == Count); + ValidateData(Values, ExpectedValues, OffsetCount); + } + + { + const uint64_t OffsetCount = 64 * 2 + 63; + const uint64_t Count = N - OffsetCount - 5; + const uint64_t RawOffset = OffsetCount * sizeof(uint64_t); + const uint64_t RawSize = Count * sizeof(uint64_t); + uint64_t FirstBlockOffset = RawOffset % BlockSize; + + SharedBuffer Uncompressed = Compressed.CopyRange(RawOffset, RawSize).Decompress(); + std::span<uint64_t const> AllValues((const uint64_t*)Uncompressed.GetData(), RawSize / sizeof(uint64_t)); + std::span<uint64_t const> Values((const uint64_t*)(((const uint8_t*)(Uncompressed.GetData()) + FirstBlockOffset)), + RawSize / sizeof(uint64_t)); + CHECK(Values.size() == Count); + ValidateData(Values, ExpectedValues, OffsetCount); + } + } + + SUBCASE("copy uncompressed range") + { + const uint64_t BlockSize = 64 * sizeof(uint64_t); + const uint64_t N = 1000; + std::vector<uint64_t> ExpectedValues = GenerateData(N); + + CompressedBuffer Compressed = CompressedBuffer::Compress(SharedBuffer::MakeView(MakeMemoryView(ExpectedValues)), + OodleCompressor::NotSet, + OodleCompressionLevel::None); + + { + const uint64_t OffsetCount = 0; + const uint64_t Count = N; + SharedBuffer Uncompressed = Compressed.CopyRange(OffsetCount * sizeof(uint64_t), Count * sizeof(uint64_t)).Decompress(); + std::span<uint64_t const> Values((const uint64_t*)Uncompressed.GetData(), Uncompressed.GetSize() / sizeof(uint64_t)); + CHECK(Values.size() == Count); + ValidateData(Values, ExpectedValues, OffsetCount); + } + + { + const uint64_t OffsetCount = 1; + const uint64_t Count = N - OffsetCount; + SharedBuffer Uncompressed = Compressed.CopyRange(OffsetCount * sizeof(uint64_t), Count * sizeof(uint64_t)).Decompress(); + std::span<uint64_t const> Values((const uint64_t*)Uncompressed.GetData(), Uncompressed.GetSize() / sizeof(uint64_t)); + CHECK(Values.size() == Count); + ValidateData(Values, ExpectedValues, OffsetCount); + } + + { + const uint64_t OffsetCount = 42; + const uint64_t Count = 100; + SharedBuffer Uncompressed = Compressed.CopyRange(OffsetCount * sizeof(uint64_t), Count * sizeof(uint64_t)).Decompress(); + std::span<uint64_t const> Values((const uint64_t*)Uncompressed.GetData(), Uncompressed.GetSize() / sizeof(uint64_t)); + CHECK(Values.size() == Count); + ValidateData(Values, ExpectedValues, OffsetCount); + } + } } void diff --git a/zencore/include/zencore/compress.h b/zencore/include/zencore/compress.h index 426b4981a..d37ecfa79 100644 --- a/zencore/include/zencore/compress.h +++ b/zencore/include/zencore/compress.h @@ -105,6 +105,8 @@ public: /** Returns the hash of the raw data. Zero on error or if this is null. */ [[nodiscard]] ZENCORE_API BLAKE3 GetRawHash() const; + [[nodiscard]] ZENCORE_API CompressedBuffer CopyRange(uint64_t RawOffset, uint64_t RawSize = ~uint64_t(0)) const; + /** * Returns the compressor and compression level used by this buffer. * diff --git a/zencore/include/zencore/fmtutils.h b/zencore/include/zencore/fmtutils.h index 7e60c2bef..70867fe72 100644 --- a/zencore/include/zencore/fmtutils.h +++ b/zencore/include/zencore/fmtutils.h @@ -6,7 +6,6 @@ #include <zencore/string.h> #include <zencore/uid.h> - ZEN_THIRD_PARTY_INCLUDES_START #include <fmt/format.h> ZEN_THIRD_PARTY_INCLUDES_END diff --git a/zencore/include/zencore/iobuffer.h b/zencore/include/zencore/iobuffer.h index 847bed606..b1d13c58f 100644 --- a/zencore/include/zencore/iobuffer.h +++ b/zencore/include/zencore/iobuffer.h @@ -358,7 +358,10 @@ public: [[nodiscard]] ZENCORE_API bool GetFileReference(IoBufferFileReference& OutRef) const; template<typename T> - [[nodiscard]] const T* Data() const { return reinterpret_cast<const T*>(m_Core->DataPointer()); } + [[nodiscard]] const T* Data() const + { + return reinterpret_cast<const T*>(m_Core->DataPointer()); + } private: RefPtr<IoBufferCore> m_Core = new IoBufferCore; diff --git a/zencore/include/zencore/refcount.h b/zencore/include/zencore/refcount.h index 325863051..92ebebcfe 100644 --- a/zencore/include/zencore/refcount.h +++ b/zencore/include/zencore/refcount.h @@ -117,9 +117,8 @@ public: inline ~Ref() { m_Ref && m_Ref->Release(); } template<typename DerivedType> - requires std::derived_from<DerivedType, T> inline Ref(const Ref<DerivedType>& Rhs) : Ref(Rhs.m_Ref) - { - } + requires std::derived_from<DerivedType, T> + inline Ref(const Ref<DerivedType>& Rhs) : Ref(Rhs.m_Ref) {} [[nodiscard]] inline bool IsNull() const { return m_Ref == nullptr; } inline explicit operator bool() const { return m_Ref != nullptr; } diff --git a/zencore/include/zencore/string.h b/zencore/include/zencore/string.h index 47fd5643d..23193501c 100644 --- a/zencore/include/zencore/string.h +++ b/zencore/include/zencore/string.h @@ -649,7 +649,7 @@ ToLower(const std::string_view& InString) for (char& CurChar : Out) { - CurChar -= (uint8_t(CurChar - 'A') <= ('Z' - 'A')) * ('A' - 'a'); // this should be compiled into branchless logic + CurChar -= (uint8_t(CurChar - 'A') <= ('Z' - 'A')) * ('A' - 'a'); // this should be compiled into branchless logic } return Out; diff --git a/zencore/include/zencore/windows.h b/zencore/include/zencore/windows.h index 621621ae8..68138566b 100644 --- a/zencore/include/zencore/windows.h +++ b/zencore/include/zencore/windows.h @@ -2,6 +2,8 @@ #pragma once +#include <zencore/zencore.h> + ZEN_THIRD_PARTY_INCLUDES_START struct IUnknown; // Workaround for "combaseapi.h(229): error C2187: syntax error: 'identifier' was unexpected here" when using /permissive- diff --git a/zencore/iobuffer.cpp b/zencore/iobuffer.cpp index 04ea7c26b..fd652f580 100644 --- a/zencore/iobuffer.cpp +++ b/zencore/iobuffer.cpp @@ -504,7 +504,7 @@ IoBufferBuilder::MakeFromTemporaryFile(const std::filesystem::path& FileName) Handle = DataFile.Detach(); #else - int Fd = open(FileName.native().c_str(), O_RDONLY); + int Fd = open(FileName.native().c_str(), O_RDONLY); if (Fd < 0) { return {}; diff --git a/zencore/string.cpp b/zencore/string.cpp index 3fa32692e..34ea0a87d 100644 --- a/zencore/string.cpp +++ b/zencore/string.cpp @@ -945,9 +945,9 @@ TEST_CASE("string") CHECK(HashStringAsLowerDjb2("aBCd"sv) == HashStringDjb2(ToLower("aBCd"sv))); } - SUBCASE("tolower") + SUBCASE("tolower") { - CHECK_EQ(ToLower("te!st"sv), "te!st"sv); + CHECK_EQ(ToLower("te!st"sv), "te!st"sv); CHECK_EQ(ToLower("TE%St"sv), "te%st"sv); } |