aboutsummaryrefslogtreecommitdiff
path: root/src/zenutil/basicfile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zenutil/basicfile.cpp')
-rw-r--r--src/zenutil/basicfile.cpp1033
1 files changed, 0 insertions, 1033 deletions
diff --git a/src/zenutil/basicfile.cpp b/src/zenutil/basicfile.cpp
deleted file mode 100644
index 391c150c6..000000000
--- a/src/zenutil/basicfile.cpp
+++ /dev/null
@@ -1,1033 +0,0 @@
-// Copyright Epic Games, Inc. All Rights Reserved.
-
-#include "zenutil/basicfile.h"
-
-#include <zencore/compactbinary.h>
-#include <zencore/except.h>
-#include <zencore/filesystem.h>
-#include <zencore/fmtutils.h>
-#include <zencore/memory/memory.h>
-#include <zencore/testing.h>
-#include <zencore/testutils.h>
-
-#if ZEN_PLATFORM_WINDOWS
-# include <zencore/windows.h>
-#else
-# include <fcntl.h>
-# include <sys/file.h>
-# include <sys/stat.h>
-# include <unistd.h>
-#endif
-
-#include <fmt/format.h>
-#include <gsl/gsl-lite.hpp>
-
-namespace zen {
-
-BasicFile::~BasicFile()
-{
- Close();
-}
-
-void
-BasicFile::Open(const std::filesystem::path& FileName, Mode Mode)
-{
- std::error_code Ec;
- Open(FileName, Mode, Ec);
-
- if (Ec)
- {
- throw std::system_error(Ec, fmt::format("failed to open file '{}', mode: {:x}", FileName, uint32_t(Mode)));
- }
-}
-
-void
-BasicFile::Open(const std::filesystem::path& FileName, Mode InMode, std::error_code& Ec)
-{
- Ec.clear();
-
- Mode Mode = InMode & Mode::kModeMask;
-
-#if ZEN_PLATFORM_WINDOWS
- DWORD dwCreationDisposition = 0;
- DWORD dwDesiredAccess = 0;
- switch (Mode)
- {
- case Mode::kRead:
- dwCreationDisposition |= OPEN_EXISTING;
- dwDesiredAccess |= GENERIC_READ;
- break;
- case Mode::kWrite:
- dwCreationDisposition |= OPEN_ALWAYS;
- dwDesiredAccess |= (GENERIC_READ | GENERIC_WRITE);
- break;
- case Mode::kDelete:
- dwCreationDisposition |= OPEN_ALWAYS;
- dwDesiredAccess |= (GENERIC_READ | GENERIC_WRITE | DELETE);
- break;
- case Mode::kTruncate:
- dwCreationDisposition |= CREATE_ALWAYS;
- dwDesiredAccess |= (GENERIC_READ | GENERIC_WRITE);
- break;
- case Mode::kTruncateDelete:
- dwCreationDisposition |= CREATE_ALWAYS;
- dwDesiredAccess |= (GENERIC_READ | GENERIC_WRITE | DELETE);
- break;
- }
-
- const DWORD dwShareMode = FILE_SHARE_READ | (EnumHasAllFlags(InMode, Mode::kPreventWrite) ? 0 : FILE_SHARE_WRITE) |
- (EnumHasAllFlags(InMode, Mode::kPreventDelete) ? 0 : FILE_SHARE_DELETE);
- const DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
- const HANDLE hTemplateFile = nullptr;
- const HANDLE FileHandle = CreateFile(FileName.c_str(),
- dwDesiredAccess,
- dwShareMode,
- /* lpSecurityAttributes */ nullptr,
- dwCreationDisposition,
- dwFlagsAndAttributes,
- hTemplateFile);
-
- if (FileHandle == INVALID_HANDLE_VALUE)
- {
- Ec = MakeErrorCodeFromLastError();
-
- return;
- }
-#else
- int OpenFlags = O_CLOEXEC;
- switch (Mode)
- {
- case Mode::kRead:
- OpenFlags |= O_RDONLY;
- break;
- case Mode::kWrite:
- case Mode::kDelete:
- OpenFlags |= (O_RDWR | O_CREAT);
- break;
- case Mode::kTruncate:
- case Mode::kTruncateDelete:
- OpenFlags |= (O_RDWR | O_CREAT | O_TRUNC);
- break;
- }
-
- int Fd = open(FileName.c_str(), OpenFlags, 0666);
- if (Fd < 0)
- {
- Ec = MakeErrorCodeFromLastError();
- return;
- }
- if (Mode != Mode::kRead)
- {
- fchmod(Fd, 0666);
- }
-
- void* FileHandle = (void*)(uintptr_t(Fd));
-#endif
-
- m_FileHandle = FileHandle;
-}
-
-void
-BasicFile::Open(const std::filesystem::path& FileName, Mode Mode, std::function<bool(std::error_code& Ec)>&& RetryCallback)
-{
- std::error_code Ec;
- Open(FileName, Mode, Ec);
- while (Ec && RetryCallback(Ec))
- {
- Ec.clear();
- Open(FileName, Mode, Ec);
- }
- if (Ec)
- {
- throw std::system_error(Ec, fmt::format("failed to open file '{}', mode: {:x}", FileName, uint32_t(Mode)));
- }
-}
-
-void
-BasicFile::Close()
-{
- if (m_FileHandle)
- {
-#if ZEN_PLATFORM_WINDOWS
- ::CloseHandle(m_FileHandle);
-#else
- int Fd = int(uintptr_t(m_FileHandle));
- close(Fd);
-#endif
- m_FileHandle = nullptr;
- }
-}
-
-IoBuffer
-BasicFile::ReadRange(uint64_t FileOffset, uint64_t ByteCount)
-{
- return IoBufferBuilder::MakeFromFileHandle(m_FileHandle, FileOffset, ByteCount);
-}
-
-void
-BasicFile::Read(void* Data, uint64_t BytesToRead, uint64_t FileOffset)
-{
- const uint64_t MaxChunkSize = 2u * 1024 * 1024 * 1024;
-
- while (BytesToRead)
- {
- const uint64_t NumberOfBytesToRead = Min(BytesToRead, MaxChunkSize);
- int32_t Error = 0;
- size_t BytesRead = 0;
-
-#if ZEN_PLATFORM_WINDOWS
- OVERLAPPED Ovl{};
-
- Ovl.Offset = DWORD(FileOffset & 0xffff'ffffu);
- Ovl.OffsetHigh = DWORD(FileOffset >> 32);
-
- DWORD dwNumberOfBytesRead = 0;
- BOOL Success = ::ReadFile(m_FileHandle, Data, DWORD(NumberOfBytesToRead), &dwNumberOfBytesRead, &Ovl);
- if (Success)
- {
- BytesRead = size_t(dwNumberOfBytesRead);
- }
- else
- {
- Error = zen::GetLastError();
- }
-#else
- static_assert(sizeof(off_t) >= sizeof(uint64_t), "sizeof(off_t) does not support large files");
- int Fd = int(uintptr_t(m_FileHandle));
- ssize_t ReadResult = pread(Fd, Data, NumberOfBytesToRead, FileOffset);
- if (ReadResult != -1)
- {
- BytesRead = size_t(ReadResult);
- }
- else
- {
- Error = zen::GetLastError();
- }
-#endif
-
- if (Error || (BytesRead != NumberOfBytesToRead))
- {
- std::error_code DummyEc;
- throw std::system_error(std::error_code(Error, std::system_category()),
- fmt::format("ReadFile/pread failed (offset {:#x}, size {:#x}) file: '{}' (size {:#x})",
- FileOffset,
- NumberOfBytesToRead,
- PathFromHandle(m_FileHandle, DummyEc),
- FileSizeFromHandle(m_FileHandle)));
- }
-
- BytesToRead -= NumberOfBytesToRead;
- FileOffset += NumberOfBytesToRead;
- Data = reinterpret_cast<uint8_t*>(Data) + NumberOfBytesToRead;
- }
-}
-
-IoBuffer
-BasicFile::ReadAll()
-{
- if (const uint64_t Size = FileSize())
- {
- IoBuffer Buffer(Size);
- Read(Buffer.MutableData(), Size, 0);
- return Buffer;
- }
- else
- {
- return {};
- }
-}
-
-void
-BasicFile::StreamFile(std::function<void(const void* Data, uint64_t Size)>&& ChunkFun)
-{
- StreamByteRange(0, FileSize(), std::move(ChunkFun));
-}
-
-void
-BasicFile::StreamByteRange(uint64_t FileOffset, uint64_t Size, std::function<void(const void* Data, uint64_t Size)>&& ChunkFun)
-{
- const uint64_t ChunkSize = 128 * 1024;
- IoBuffer ReadBuffer{ChunkSize};
- void* BufferPtr = ReadBuffer.MutableData();
-
- uint64_t RemainBytes = Size;
- uint64_t CurrentOffset = FileOffset;
-
- while (RemainBytes)
- {
- const uint64_t ThisChunkBytes = zen::Min(ChunkSize, RemainBytes);
-
- Read(BufferPtr, ThisChunkBytes, CurrentOffset);
-
- ChunkFun(BufferPtr, ThisChunkBytes);
-
- CurrentOffset += ThisChunkBytes;
- RemainBytes -= ThisChunkBytes;
- }
-}
-
-uint64_t
-BasicFile::Write(CompositeBuffer Data, uint64_t FileOffset, std::error_code& Ec)
-{
- uint64_t WrittenBytes = 0;
- for (const SharedBuffer& Buffer : Data.GetSegments())
- {
- MemoryView BlockView = Buffer.GetView();
- Write(BlockView, FileOffset + WrittenBytes, Ec);
-
- if (Ec)
- {
- return WrittenBytes;
- }
-
- WrittenBytes += BlockView.GetSize();
- }
-
- return WrittenBytes;
-}
-
-void
-BasicFile::Write(MemoryView Data, uint64_t FileOffset, std::error_code& Ec)
-{
- Write(Data.GetData(), Data.GetSize(), FileOffset, Ec);
-}
-
-void
-BasicFile::Write(const void* Data, uint64_t Size, uint64_t FileOffset, std::error_code& Ec)
-{
- Ec.clear();
-
- const uint64_t MaxChunkSize = 2u * 1024 * 1024 * 1024;
-
- while (Size)
- {
- const uint64_t NumberOfBytesToWrite = Min(Size, MaxChunkSize);
-
-#if ZEN_PLATFORM_WINDOWS
- OVERLAPPED Ovl{};
-
- Ovl.Offset = DWORD(FileOffset & 0xffff'ffffu);
- Ovl.OffsetHigh = DWORD(FileOffset >> 32);
-
- DWORD dwNumberOfBytesWritten = 0;
-
- BOOL Success = ::WriteFile(m_FileHandle, Data, DWORD(NumberOfBytesToWrite), &dwNumberOfBytesWritten, &Ovl);
-#else
- static_assert(sizeof(off_t) >= sizeof(uint64_t), "sizeof(off_t) does not support large files");
- int Fd = int(uintptr_t(m_FileHandle));
- int BytesWritten = pwrite(Fd, Data, NumberOfBytesToWrite, FileOffset);
- bool Success = (BytesWritten > 0);
-#endif
-
- if (!Success)
- {
- Ec = MakeErrorCodeFromLastError();
-
- return;
- }
-
- Size -= NumberOfBytesToWrite;
- FileOffset += NumberOfBytesToWrite;
- Data = reinterpret_cast<const uint8_t*>(Data) + NumberOfBytesToWrite;
- }
-}
-
-void
-BasicFile::Write(MemoryView Data, uint64_t FileOffset)
-{
- Write(Data.GetData(), Data.GetSize(), FileOffset);
-}
-
-void
-BasicFile::Write(const void* Data, uint64_t Size, uint64_t Offset)
-{
- std::error_code Ec;
- Write(Data, Size, Offset, Ec);
-
- if (Ec)
- {
- std::error_code Dummy;
- throw std::system_error(Ec, fmt::format("Failed to write to file '{}'", zen::PathFromHandle(m_FileHandle, Dummy)));
- }
-}
-
-void
-BasicFile::WriteAll(IoBuffer Data, std::error_code& Ec)
-{
- Write(Data.Data(), Data.Size(), 0, Ec);
-}
-
-void
-BasicFile::Flush()
-{
- if (m_FileHandle == nullptr)
- {
- return;
- }
-#if ZEN_PLATFORM_WINDOWS
- FlushFileBuffers(m_FileHandle);
-#else
- int Fd = int(uintptr_t(m_FileHandle));
- fsync(Fd);
-#endif
-}
-
-uint64_t
-BasicFile::FileSize() const
-{
-#if ZEN_PLATFORM_WINDOWS
- ULARGE_INTEGER liFileSize;
- liFileSize.LowPart = ::GetFileSize(m_FileHandle, &liFileSize.HighPart);
- if (liFileSize.LowPart == INVALID_FILE_SIZE)
- {
- int Error = zen::GetLastError();
- if (Error)
- {
- std::error_code Dummy;
- ThrowSystemError(Error, fmt::format("Failed to get file size from file '{}'", PathFromHandle(m_FileHandle, Dummy)));
- }
- }
- return uint64_t(liFileSize.QuadPart);
-#else
- int Fd = int(uintptr_t(m_FileHandle));
- static_assert(sizeof(decltype(stat::st_size)) == sizeof(uint64_t), "fstat() doesn't support large files");
- struct stat Stat;
- if (fstat(Fd, &Stat) == -1)
- {
- std::error_code Dummy;
- ThrowSystemError(GetLastError(), fmt::format("Failed to get file size from file '{}'", PathFromHandle(m_FileHandle, Dummy)));
- }
- return uint64_t(Stat.st_size);
-#endif
-}
-
-uint64_t
-BasicFile::FileSize(std::error_code& Ec) const
-{
-#if ZEN_PLATFORM_WINDOWS
- ULARGE_INTEGER liFileSize;
- liFileSize.LowPart = ::GetFileSize(m_FileHandle, &liFileSize.HighPart);
- if (liFileSize.LowPart == INVALID_FILE_SIZE)
- {
- int Error = zen::GetLastError();
- if (Error)
- {
- Ec = MakeErrorCode(Error);
- return 0;
- }
- }
- return uint64_t(liFileSize.QuadPart);
-#else
- int Fd = int(uintptr_t(m_FileHandle));
- static_assert(sizeof(decltype(stat::st_size)) == sizeof(uint64_t), "fstat() doesn't support large files");
- struct stat Stat;
- if (fstat(Fd, &Stat) == -1)
- {
- Ec = MakeErrorCodeFromLastError();
- return 0;
- }
- return uint64_t(Stat.st_size);
-#endif
-}
-
-void
-BasicFile::SetFileSize(uint64_t FileSize)
-{
-#if ZEN_PLATFORM_WINDOWS
- LARGE_INTEGER liFileSize;
- liFileSize.QuadPart = FileSize;
- BOOL OK = ::SetFilePointerEx(m_FileHandle, liFileSize, 0, FILE_BEGIN);
- if (OK == FALSE)
- {
- int Error = zen::GetLastError();
- if (Error)
- {
- std::error_code Dummy;
- ThrowSystemError(Error,
- fmt::format("Failed to set file pointer to {} for file {}", FileSize, PathFromHandle(m_FileHandle, Dummy)));
- }
- }
- OK = ::SetEndOfFile(m_FileHandle);
- if (OK == FALSE)
- {
- int Error = zen::GetLastError();
- if (Error)
- {
- std::error_code Dummy;
- ThrowSystemError(Error,
- fmt::format("Failed to set end of file to {} for file {}", FileSize, PathFromHandle(m_FileHandle, Dummy)));
- }
- }
-#elif ZEN_PLATFORM_MAC
- int Fd = int(intptr_t(m_FileHandle));
- if (ftruncate(Fd, (off_t)FileSize) < 0)
- {
- int Error = zen::GetLastError();
- if (Error)
- {
- std::error_code Dummy;
- ThrowSystemError(Error,
- fmt::format("Failed to set truncate file to {} for file {}", FileSize, PathFromHandle(m_FileHandle, Dummy)));
- }
- }
-#else
- int Fd = int(intptr_t(m_FileHandle));
- if (ftruncate64(Fd, (off64_t)FileSize) < 0)
- {
- int Error = zen::GetLastError();
- if (Error)
- {
- std::error_code Dummy;
- ThrowSystemError(Error,
- fmt::format("Failed to set truncate file to {} for file {}", FileSize, PathFromHandle(m_FileHandle, Dummy)));
- }
- }
- if (FileSize > 0)
- {
- int Error = posix_fallocate64(Fd, 0, (off64_t)FileSize);
- if (Error)
- {
- std::error_code Dummy;
- ThrowSystemError(Error,
- fmt::format("Failed to allocate space of {} for file {}", FileSize, PathFromHandle(m_FileHandle, Dummy)));
- }
- }
-#endif
-}
-
-void
-BasicFile::Attach(void* Handle)
-{
- ZEN_ASSERT(Handle != nullptr);
- ZEN_ASSERT(m_FileHandle == nullptr);
- m_FileHandle = Handle;
-}
-
-void*
-BasicFile::Detach()
-{
- void* FileHandle = m_FileHandle;
- m_FileHandle = 0;
- return FileHandle;
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-TemporaryFile::~TemporaryFile()
-{
- Close();
-}
-
-void
-TemporaryFile::Close()
-{
- if (m_FileHandle)
- {
-#if ZEN_PLATFORM_WINDOWS
- // Mark file for deletion when final handle is closed
-
- FILE_DISPOSITION_INFO Fdi{.DeleteFile = TRUE};
-
- SetFileInformationByHandle(m_FileHandle, FileDispositionInfo, &Fdi, sizeof Fdi);
-#else
- std::error_code Ec;
- std::filesystem::path FilePath = zen::PathFromHandle(m_FileHandle, Ec);
- if (!Ec)
- {
- unlink(FilePath.c_str());
- }
-#endif
-
- BasicFile::Close();
- }
-}
-
-void
-TemporaryFile::CreateTemporary(std::filesystem::path TempDirName, std::error_code& Ec)
-{
- StringBuilder<64> TempName;
- Oid::NewOid().ToString(TempName);
-
- m_TempPath = TempDirName / TempName.c_str();
-
- Open(m_TempPath, BasicFile::Mode::kTruncateDelete, Ec);
-}
-
-void
-TemporaryFile::MoveTemporaryIntoPlace(std::filesystem::path FinalFileName, std::error_code& Ec)
-{
- // We intentionally call the base class Close() since otherwise we'll end up
- // deleting the temporary file
- BasicFile::Close();
-
- std::filesystem::rename(m_TempPath, FinalFileName, Ec);
-
- if (Ec)
- {
- // Try to re-open the temp file so we clean up after us when TemporaryFile is destructed
- std::error_code DummyEc;
- Open(m_TempPath, BasicFile::Mode::kWrite, DummyEc);
- }
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-void
-TemporaryFile::SafeWriteFile(const std::filesystem::path& Path, MemoryView Data)
-{
- TemporaryFile TempFile;
- std::error_code Ec;
- SafeWriteFile(Path, Data, Ec);
- if (Ec)
- {
- throw std::system_error(Ec, fmt::format("Failed to safely write file '{}'", Path));
- }
-}
-
-void
-TemporaryFile::SafeWriteFile(const std::filesystem::path& Path, MemoryView Data, std::error_code& OutEc)
-{
- TemporaryFile TempFile;
- if (TempFile.CreateTemporary(Path.parent_path(), OutEc); !OutEc)
- {
- if (TempFile.Write(Data, 0, OutEc); !OutEc)
- {
- TempFile.MoveTemporaryIntoPlace(Path, OutEc);
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-LockFile::LockFile()
-{
-}
-
-LockFile::~LockFile()
-{
-#if ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC
- int Fd = int(intptr_t(m_FileHandle));
- flock(Fd, LOCK_UN | LOCK_NB);
-#endif
-}
-
-void
-LockFile::Create(std::filesystem::path FileName, CbObject Payload, std::error_code& Ec)
-{
-#if ZEN_PLATFORM_WINDOWS
- Ec.clear();
-
- const DWORD dwCreationDisposition = CREATE_ALWAYS;
- DWORD dwDesiredAccess = GENERIC_READ | GENERIC_WRITE | DELETE;
- const DWORD dwShareMode = FILE_SHARE_READ;
- const DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE;
- HANDLE hTemplateFile = nullptr;
-
- HANDLE FileHandle = CreateFile(FileName.c_str(),
- dwDesiredAccess,
- dwShareMode,
- /* lpSecurityAttributes */ nullptr,
- dwCreationDisposition,
- dwFlagsAndAttributes,
- hTemplateFile);
-
- if (FileHandle == INVALID_HANDLE_VALUE)
- {
- Ec = zen::MakeErrorCodeFromLastError();
-
- return;
- }
-#elif ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC
- int Fd = open(FileName.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0666);
- if (Fd < 0)
- {
- Ec = zen::MakeErrorCodeFromLastError();
- return;
- }
- fchmod(Fd, 0666);
-
- int LockRet = flock(Fd, LOCK_EX | LOCK_NB);
- if (LockRet < 0)
- {
- Ec = zen::MakeErrorCodeFromLastError();
- close(Fd);
- return;
- }
-
- void* FileHandle = (void*)uintptr_t(Fd);
-#endif
-
- m_FileHandle = FileHandle;
-
- BasicFile::Write(Payload.GetBuffer(), 0, Ec);
-}
-
-void
-LockFile::Update(CbObject Payload, std::error_code& Ec)
-{
- BasicFile::Write(Payload.GetBuffer(), 0, Ec);
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-BasicFileBuffer::BasicFileBuffer(BasicFile& Base, uint64_t BufferSize)
-: m_Base(Base)
-, m_Buffer(nullptr)
-, m_BufferSize(BufferSize)
-, m_Size(Base.FileSize())
-, m_BufferStart(0)
-, m_BufferEnd(0)
-{
- m_Buffer = (uint8_t*)Memory::Alloc(m_BufferSize);
-}
-
-BasicFileBuffer::~BasicFileBuffer()
-{
- Memory::Free(m_Buffer);
-}
-
-void
-BasicFileBuffer::Read(void* Data, uint64_t Size, uint64_t FileOffset)
-{
- if (m_Buffer == nullptr || (Size > m_BufferSize) || (FileOffset + Size > m_Size))
- {
- m_Base.Read(Data, Size, FileOffset);
- return;
- }
- uint8_t* WritePtr = ((uint8_t*)Data);
- uint64_t Begin = FileOffset;
- uint64_t End = FileOffset + Size;
- if (FileOffset <= m_BufferStart)
- {
- if (End > m_BufferStart)
- {
- uint64_t Count = Min(m_BufferEnd, End) - m_BufferStart;
- memcpy(WritePtr + End - Count - FileOffset, m_Buffer, Count);
- End -= Count;
- if (Begin == End)
- {
- return;
- }
- }
- }
- else if (FileOffset < m_BufferEnd)
- {
- uint64_t Count = Min(m_BufferEnd, End) - FileOffset;
- memcpy(WritePtr + Begin - FileOffset, m_Buffer + Begin - m_BufferStart, Count);
- Begin += Count;
- if (Begin == End)
- {
- return;
- }
- }
- m_BufferStart = Begin;
- m_BufferEnd = Min(Begin + m_BufferSize, m_Size);
- m_Base.Read(m_Buffer, m_BufferEnd - m_BufferStart, m_BufferStart);
- uint64_t Count = Min(m_BufferEnd, End) - m_BufferStart;
- memcpy(WritePtr + Begin - FileOffset, m_Buffer, Count);
- ZEN_ASSERT(Begin + Count == End);
-}
-
-MemoryView
-BasicFileBuffer::MakeView(uint64_t Size, uint64_t FileOffset)
-{
- if (FileOffset < m_BufferStart || (FileOffset + Size) > m_BufferEnd)
- {
- if (m_Buffer == nullptr || (Size > m_BufferSize) || (FileOffset + Size > m_Size))
- {
- return {};
- }
- m_BufferStart = FileOffset;
- m_BufferEnd = Min(m_BufferStart + m_BufferSize, m_Size);
- m_Base.Read(m_Buffer, m_BufferEnd - m_BufferStart, m_BufferStart);
- }
- return MemoryView(m_Buffer + (FileOffset - m_BufferStart), Size);
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-BasicFileWriter::BasicFileWriter(BasicFile& Base, uint64_t BufferSize)
-: m_Base(Base)
-, m_Buffer(nullptr)
-, m_BufferSize(BufferSize)
-, m_BufferStart(0)
-, m_BufferEnd(0)
-{
- m_Buffer = (uint8_t*)Memory::Alloc(m_BufferSize);
-}
-
-BasicFileWriter::~BasicFileWriter()
-{
- Flush();
- Memory::Free(m_Buffer);
-}
-
-void
-BasicFileWriter::Write(const void* Data, uint64_t Size, uint64_t FileOffset)
-{
- if (m_Buffer == nullptr || (Size >= m_BufferSize))
- {
- m_Base.Write(Data, Size, FileOffset);
- return;
- }
-
- // Note that this only supports buffering of sequential writes!
-
- if (FileOffset != m_BufferEnd)
- {
- Flush();
- m_BufferStart = m_BufferEnd = FileOffset;
- }
-
- const uint8_t* DataPtr = (const uint8_t*)Data;
- while (Size)
- {
- const uint64_t RemainingBufferCapacity = m_BufferStart + m_BufferSize - m_BufferEnd;
- const uint64_t BlockWriteBytes = Min(RemainingBufferCapacity, Size);
- const uint64_t BufferWriteOffset = FileOffset - m_BufferStart;
-
- ZEN_ASSERT_SLOW(BufferWriteOffset < m_BufferSize);
- ZEN_ASSERT_SLOW((BufferWriteOffset + BlockWriteBytes) <= m_BufferSize);
-
- memcpy(m_Buffer + BufferWriteOffset, DataPtr, BlockWriteBytes);
-
- Size -= BlockWriteBytes;
- m_BufferEnd += BlockWriteBytes;
- FileOffset += BlockWriteBytes;
- DataPtr += BlockWriteBytes;
-
- if ((m_BufferEnd - m_BufferStart) == m_BufferSize)
- {
- Flush();
- }
- }
-}
-
-void
-BasicFileWriter::Flush()
-{
- const uint64_t BufferedBytes = m_BufferEnd - m_BufferStart;
-
- if (BufferedBytes == 0)
- return;
-
- const uint64_t WriteOffset = m_BufferStart;
- m_BufferStart = m_BufferEnd;
-
- m_Base.Write(m_Buffer, BufferedBytes, WriteOffset);
-}
-
-//////////////////////////////////////////////////////////////////////////
-
-/*
- ___________ __
- \__ ___/___ _______/ |_ ______
- | |_/ __ \ / ___/\ __\/ ___/
- | |\ ___/ \___ \ | | \___ \
- |____| \___ >____ > |__| /____ >
- \/ \/ \/
-*/
-
-#if ZEN_WITH_TESTS
-
-TEST_CASE("BasicFile")
-{
- ScopedCurrentDirectoryChange _;
-
- BasicFile File1;
- CHECK_THROWS(File1.Open("zonk", BasicFile::Mode::kRead));
- CHECK_NOTHROW(File1.Open("zonk", BasicFile::Mode::kTruncate));
- CHECK_NOTHROW(File1.Write("abcd", 4, 0));
- CHECK(File1.FileSize() == 4);
- {
- IoBuffer Data = File1.ReadAll();
- CHECK(Data.Size() == 4);
- CHECK_EQ(memcmp(Data.Data(), "abcd", 4), 0);
- }
- CHECK_NOTHROW(File1.Write("efgh", 4, 2));
- CHECK(File1.FileSize() == 6);
- {
- IoBuffer Data = File1.ReadAll();
- CHECK(Data.Size() == 6);
- CHECK_EQ(memcmp(Data.Data(), "abefgh", 6), 0);
- }
-}
-
-TEST_CASE("TemporaryFile")
-{
- ScopedCurrentDirectoryChange _;
-
- SUBCASE("DeleteOnClose")
- {
- std::filesystem::path Path;
- {
- TemporaryFile TmpFile;
- std::error_code Ec;
- TmpFile.CreateTemporary(std::filesystem::current_path(), Ec);
- CHECK(!Ec);
- Path = TmpFile.GetPath();
- CHECK(std::filesystem::exists(Path));
- }
- CHECK(std::filesystem::exists(Path) == false);
- }
-
- SUBCASE("MoveIntoPlace")
- {
- TemporaryFile TmpFile;
- std::error_code Ec;
- TmpFile.CreateTemporary(std::filesystem::current_path(), Ec);
- CHECK(!Ec);
- std::filesystem::path TempPath = TmpFile.GetPath();
- std::filesystem::path FinalPath = std::filesystem::current_path() / "final";
- CHECK(std::filesystem::exists(TempPath));
- TmpFile.MoveTemporaryIntoPlace(FinalPath, Ec);
- CHECK(!Ec);
- CHECK(std::filesystem::exists(TempPath) == false);
- CHECK(std::filesystem::exists(FinalPath));
- }
-}
-
-TEST_CASE("BasicFileBuffer")
-{
- ScopedCurrentDirectoryChange _;
- {
- BasicFile File1;
- const std::string_view Data = "0123456789abcdef";
- File1.Open("buffered", BasicFile::Mode::kTruncate);
- for (uint32_t I = 0; I < 16; ++I)
- {
- File1.Write(Data.data(), Data.size(), I * Data.size());
- }
- }
- SUBCASE("EvenBuffer")
- {
- BasicFile File1;
- File1.Open("buffered", BasicFile::Mode::kRead);
- BasicFileBuffer File1Buffer(File1, 16);
- // Non-primed
- {
- char Buffer[16] = {0};
- File1Buffer.Read(Buffer, 16, 1 * 16);
- std::string_view Verify(Buffer, 16);
- CHECK(Verify == "0123456789abcdef");
- }
- // Primed
- {
- char Buffer[16] = {0};
- File1Buffer.Read(Buffer, 16, 1 * 16);
- std::string_view Verify(Buffer, 16);
- CHECK(Verify == "0123456789abcdef");
- }
- }
- SUBCASE("UnevenBuffer")
- {
- BasicFile File1;
- File1.Open("buffered", BasicFile::Mode::kRead);
- BasicFileBuffer File1Buffer(File1, 16);
- // Non-primed
- {
- char Buffer[16] = {0};
- File1Buffer.Read(Buffer, 16, 7);
- std::string_view Verify(Buffer, 16);
- CHECK(Verify == "789abcdef0123456");
- }
- // Primed
- {
- char Buffer[16] = {0};
- File1Buffer.Read(Buffer, 16, 7);
- std::string_view Verify(Buffer, 16);
- CHECK(Verify == "789abcdef0123456");
- }
- }
- SUBCASE("BiggerThanBuffer")
- {
- BasicFile File1;
- File1.Open("buffered", BasicFile::Mode::kRead);
- BasicFileBuffer File1Buffer(File1, 16);
- char Buffer[17] = {0};
- File1Buffer.Read(Buffer, 17, 0 * 16);
- std::string_view Verify(Buffer, 17);
- CHECK(Verify == "0123456789abcdef0");
- }
- SUBCASE("InsideBuffer")
- {
- BasicFile File1;
- File1.Open("buffered", BasicFile::Mode::kRead);
- BasicFileBuffer File1Buffer(File1, 16);
- char Buffer[16] = {0};
- File1Buffer.Read(Buffer, 16, 0 * 16);
-
- File1Buffer.Read(Buffer, 8, 2);
- std::string_view Verify(Buffer, 8);
- CHECK(Verify == "23456789");
- }
- SUBCASE("BeginningOfBuffer")
- {
- BasicFile File1;
- File1.Open("buffered", BasicFile::Mode::kRead);
- BasicFileBuffer File1Buffer(File1, 16);
- char Buffer[16] = {0};
- File1Buffer.Read(Buffer, 16, 8);
-
- File1Buffer.Read(Buffer, 8, 8);
- std::string_view Verify(Buffer, 8);
- CHECK(Verify == "89abcdef");
- }
- SUBCASE("EndOfBuffer")
- {
- BasicFile File1;
- File1.Open("buffered", BasicFile::Mode::kRead);
- BasicFileBuffer File1Buffer(File1, 16);
- char Buffer[16] = {0};
- File1Buffer.Read(Buffer, 16, 0 * 16);
-
- File1Buffer.Read(Buffer, 8, 8);
- std::string_view Verify(Buffer, 8);
- CHECK(Verify == "89abcdef");
- }
- SUBCASE("OverEnd")
- {
- BasicFile File1;
- File1.Open("buffered", BasicFile::Mode::kRead);
- BasicFileBuffer File1Buffer(File1, 16);
- char Buffer[16] = {0};
- File1Buffer.Read(Buffer, 16, 0 * 16);
-
- File1Buffer.Read(Buffer, 16, 8);
- std::string_view Verify(Buffer, 16);
- CHECK(Verify == "89abcdef01234567");
- }
- SUBCASE("OverBegin")
- {
- BasicFile File1;
- File1.Open("buffered", BasicFile::Mode::kRead);
- BasicFileBuffer File1Buffer(File1, 16);
- char Buffer[16] = {0};
- File1Buffer.Read(Buffer, 16, 1 * 16);
-
- File1Buffer.Read(Buffer, 16, 8);
- std::string_view Verify(Buffer, 16);
- CHECK(Verify == "89abcdef01234567");
- }
- SUBCASE("EndOfFile")
- {
- BasicFile File1;
- File1.Open("buffered", BasicFile::Mode::kRead);
- BasicFileBuffer File1Buffer(File1, 16);
- char Buffer[16] = {0};
- File1Buffer.Read(Buffer, 16, 0 * 16);
-
- File1Buffer.Read(Buffer, 8, 256 - 8);
- std::string_view Verify(Buffer, 8);
- CHECK(Verify == "89abcdef");
- }
-}
-
-void
-basicfile_forcelink()
-{
-}
-
-#endif
-
-} // namespace zen