// Copyright Epic Games, Inc. All Rights Reserved. #include #include #include #include #include #include #include namespace zen { static const uint8_t MaxData[20] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; const IoHash IoHash::Max = IoHash::MakeFrom(MaxData); // Initialized to all 0xff const IoHash IoHash::Zero{}; // Initialized to all zeros IoHash IoHash::HashBuffer(const void* data, size_t byteCount) { BLAKE3 b3 = BLAKE3::HashMemory(data, byteCount); IoHash io; memcpy(io.Hash, b3.Hash, sizeof io.Hash); return io; } IoHash IoHash::HashBuffer(const CompositeBuffer& Buffer, std::atomic* ProcessedBytes) { IoHashStream Hasher; for (const SharedBuffer& Segment : Buffer.GetSegments()) { size_t SegmentSize = Segment.GetSize(); static const uint64_t BufferingSize = 256u * 1024u; IoBufferFileReference FileRef; if (SegmentSize >= (BufferingSize + BufferingSize / 2) && Segment.GetFileReference(FileRef)) { ScanFile(FileRef.FileHandle, FileRef.FileChunkOffset, FileRef.FileChunkSize, BufferingSize, [&Hasher, ProcessedBytes](const void* Data, size_t Size) { Hasher.Append(Data, Size); if (ProcessedBytes != nullptr) { ProcessedBytes->fetch_add(Size); } }); } else { Hasher.Append(Segment.GetData(), SegmentSize); if (ProcessedBytes != nullptr) { ProcessedBytes->fetch_add(SegmentSize); } } } return Hasher.GetHash(); } IoHash IoHash::HashBuffer(const IoBuffer& Buffer, std::atomic* ProcessedBytes) { IoHashStream Hasher; size_t BufferSize = Buffer.GetSize(); static const uint64_t BufferingSize = 256u * 1024u; IoBufferFileReference FileRef; if (BufferSize >= (BufferingSize + BufferingSize / 2) && Buffer.GetFileReference(FileRef)) { ScanFile(FileRef.FileHandle, FileRef.FileChunkOffset, FileRef.FileChunkSize, BufferingSize, [&Hasher, ProcessedBytes](const void* Data, size_t Size) { Hasher.Append(Data, Size); if (ProcessedBytes != nullptr) { ProcessedBytes->fetch_add(Size); } }); } else { Hasher.Append(Buffer.GetData(), BufferSize); if (ProcessedBytes != nullptr) { ProcessedBytes->fetch_add(BufferSize); } } return Hasher.GetHash(); } IoHash IoHash::FromHexString(const char* string) { return FromHexString({string, sizeof(IoHash::Hash) * 2}); } IoHash IoHash::FromHexString(std::string_view string) { ZEN_ASSERT(string.size() == 2 * sizeof(IoHash::Hash)); IoHash io; ParseHexBytes(string.data(), string.size(), io.Hash); return io; } bool IoHash::TryParse(std::string_view Str, IoHash& Hash) { using namespace std::literals; if (Str.size() == IoHash::StringLength) { return ParseHexBytes(Str.data(), Str.size(), Hash.Hash); } if (Str.starts_with("0x"sv)) { return TryParse(Str.substr(2), Hash); } return false; } const char* IoHash::ToHexString(char* outString /* 40 characters + NUL terminator */) const { ToHexBytes(Hash, sizeof(IoHash), outString); outString[2 * sizeof(IoHash)] = '\0'; return outString; } StringBuilderBase& IoHash::ToHexString(StringBuilderBase& outBuilder) const { String_t Str; ToHexString(Str); outBuilder.AppendRange(Str, &Str[StringLength]); return outBuilder; } std::string IoHash::ToHexString() const { String_t Str; ToHexString(Str); return Str; } } // namespace zen