backup
This commit is contained in:
@ -5,6 +5,8 @@ set(SRC_FILES
|
||||
"imp/cpp/AsyncOps.cpp"
|
||||
"imp/cpp/SocketOps.cpp"
|
||||
"imp/cpp/ProcessOps.cpp"
|
||||
"imp/cpp/BinaryStreamReader.cpp"
|
||||
"imp/cpp/BinaryStreamWriter.cpp"
|
||||
)
|
||||
|
||||
add_library(IACore STATIC ${SRC_FILES})
|
||||
|
||||
@ -0,0 +1,186 @@
|
||||
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <IACore/FileOps.hpp>
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
UnorderedMap<PCUINT8, PVOID> FileOps::s_mappedFiles;
|
||||
|
||||
VOID FileOps::UnmapFile(IN PCUINT8 mappedPtr)
|
||||
{
|
||||
if (!s_mappedFiles.contains(mappedPtr))
|
||||
return;
|
||||
const auto handle = s_mappedFiles.extract(mappedPtr)->second;
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
|
||||
#elif IA_PLATFORM_UNIX
|
||||
#else
|
||||
# error "IACore FileOps does not support this platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
Expected<PUINT8, String> FileOps::MapFile(IN CONST FilePath &path)
|
||||
{
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
|
||||
const auto handle = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return MakeUnexpected(std::format("Failed to open {} for memory mapping", path.c_str()));
|
||||
|
||||
auto hmap = CreateFileMappingW(handle, NULL, PAGE_READWRITE, 0, 0, NULL);
|
||||
if (hmap == NULL)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
return MakeUnexpected(std::format("Failed to memory map {}", path.c_str()));
|
||||
}
|
||||
|
||||
const auto result = static_cast<PUINT8>(MapViewOfFile(hmap, FILE_MAP_ALL_ACCESS, 0, 0, 0));
|
||||
if (result == NULL)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
CloseHandle(hmap);
|
||||
return MakeUnexpected(std::format("Failed to memory map {}", path.c_str()));
|
||||
}
|
||||
s_mappedFiles[result] = (PVOID) handle;
|
||||
return result;
|
||||
|
||||
#elif IA_PLATFORM_UNIX
|
||||
|
||||
const auto handle = open(path.c_str(), O_RDONLY);
|
||||
if (handle == -1)
|
||||
return MakeUnexpected(std::format("Failed to open {} for memory mapping", path.c_str()));
|
||||
|
||||
void *addr = mmap(nullptr, 0, PROT_WRITE | PROT_READ, MAP_PRIVATE, handle, 0);
|
||||
if (addr == MAP_FAILED)
|
||||
{
|
||||
close(handle);
|
||||
return MakeUnexpected(std::format("Failed to memory map {}", path.c_str()));
|
||||
}
|
||||
const auto result = static_cast<PUINT8>(addr);
|
||||
s_mappedFiles[result] = (PVOID) ((UINT64) handle);
|
||||
return result;
|
||||
|
||||
#else
|
||||
# error "IACore FileOps does not support this platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
Expected<PCUINT8, String> FileOps::MapReadonlyFile(IN CONST FilePath &path)
|
||||
{
|
||||
SIZE_T size;
|
||||
return MapReadonlyFile(path, size);
|
||||
}
|
||||
|
||||
Expected<PCUINT8, String> FileOps::MapReadonlyFile(IN CONST FilePath &path, OUT SIZE_T &size)
|
||||
{
|
||||
#if IA_PLATFORM_WINDOWS
|
||||
|
||||
const auto handle = CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return MakeUnexpected(std::format("Failed to open {} for memory mapping", path.c_str()));
|
||||
|
||||
LARGE_INTEGER fileSize;
|
||||
if (!GetFileSizeEx(handle, &fileSize))
|
||||
{
|
||||
CloseHandle(handle);
|
||||
return MakeUnexpected(std::format("Failed to get size of {} for memory mapping", path.c_str()));
|
||||
}
|
||||
size = static_cast<size_t>(fileSize.QuadPart);
|
||||
if (size == 0)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
return MakeUnexpected(std::format("Failed to get size of {} for memory mapping", path.c_str()));
|
||||
}
|
||||
|
||||
auto hmap = CreateFileMappingW(handle, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hmap == NULL)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
return MakeUnexpected(std::format("Failed to memory map {}", path.c_str()));
|
||||
}
|
||||
|
||||
const auto result = static_cast<PCUINT8>(MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0));
|
||||
if (result == NULL)
|
||||
{
|
||||
CloseHandle(handle);
|
||||
CloseHandle(hmap);
|
||||
return MakeUnexpected(std::format("Failed to memory map {}", path.c_str()));
|
||||
}
|
||||
s_mappedFiles[result] = (PVOID) handle;
|
||||
return result;
|
||||
|
||||
#elif IA_PLATFORM_UNIX
|
||||
|
||||
const auto handle = open(path.c_str(), O_RDONLY);
|
||||
if (handle == -1)
|
||||
return MakeUnexpected(std::format("Failed to open {} for memory mapping", path.c_str()));
|
||||
struct stat sb;
|
||||
if (fstat(handle, &sb) == -1)
|
||||
{
|
||||
close(handle);
|
||||
return MakeUnexpected(std::format("Failed to get stats of {} for memory mapping", path.c_str()));
|
||||
}
|
||||
size = static_cast<size_t>(sb.st_size);
|
||||
if (size == 0)
|
||||
{
|
||||
close(handle);
|
||||
return MakeUnexpected(std::format("Failed to get size of {} for memory mapping", path.c_str()));
|
||||
}
|
||||
void *addr = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, handle, 0);
|
||||
if (addr == MAP_FAILED)
|
||||
{
|
||||
close(handle);
|
||||
return MakeUnexpected(std::format("Failed to memory map {}", path.c_str()));
|
||||
}
|
||||
const auto result = static_cast<PCUINT8>(addr);
|
||||
madvise(addr, size, MADV_SEQUENTIAL);
|
||||
s_mappedFiles[result] = (PVOID) ((UINT64) handle);
|
||||
return result;
|
||||
|
||||
#else
|
||||
# error "IACore FileOps does not support this platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
Expected<StreamWriter, String> FileOps::StreamToFile(IN CONST FilePath &path)
|
||||
{
|
||||
}
|
||||
|
||||
Expected<StreamReader, String> FileOps::StreamFromFile(IN CONST FilePath &path)
|
||||
{
|
||||
}
|
||||
|
||||
Expected<String, String> FileOps::ReadTextFile(IN CONST FilePath &path)
|
||||
{
|
||||
}
|
||||
|
||||
Expected<Vector<UINT8>, String> FileOps::ReadBinaryFile(IN CONST FilePath &path)
|
||||
{
|
||||
}
|
||||
|
||||
Expected<SIZE_T, String> FileOps::WriteTextFile(IN CONST FilePath &path, IN CONST String &contents)
|
||||
{
|
||||
}
|
||||
|
||||
Expected<SIZE_T, String> FileOps::WriteBinaryFile(IN CONST FilePath &path, IN Span<UINT8> contents)
|
||||
{
|
||||
}
|
||||
} // namespace IACore
|
||||
@ -18,5 +18,23 @@
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
|
||||
}
|
||||
BOOL SocketOps::IsPortAvailable(IN UINT16 port, IN INT32 type)
|
||||
{
|
||||
SocketHandle sock = socket(AF_INET, type, IPPROTO_UDP);
|
||||
if (!IS_VALID_SOCKET(sock))
|
||||
return false;
|
||||
|
||||
sockaddr_in addr{};
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
bool isFree = false;
|
||||
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) == 0)
|
||||
isFree = true;
|
||||
|
||||
CLOSE_SOCKET(sock);
|
||||
|
||||
return isFree;
|
||||
}
|
||||
} // namespace IACore
|
||||
59
Src/IACore/imp/cpp/StreamReader.cpp
Normal file
59
Src/IACore/imp/cpp/StreamReader.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <IACore/StreamReader.hpp>
|
||||
#include <IACore/FileOps.hpp>
|
||||
#include <IACore/Logger.hpp>
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
StreamReader::StreamReader(IN CONST FilePath &path) : m_storageType(EStorageType::OWNING_MMAP)
|
||||
{
|
||||
const auto t = FileOps::MapReadonlyFile(path, m_dataSize);
|
||||
if (!t)
|
||||
{
|
||||
Logger::Error("Failed to memory map file {}", path.string());
|
||||
return;
|
||||
}
|
||||
m_data = *t;
|
||||
}
|
||||
|
||||
StreamReader::StreamReader(IN Vector<UINT8> &&data)
|
||||
: m_owningVector(IA_MOVE(data)), m_storageType(EStorageType::OWNING_VECTOR)
|
||||
{
|
||||
m_data = m_owningVector.data();
|
||||
m_dataSize = m_owningVector.size();
|
||||
}
|
||||
|
||||
StreamReader::StreamReader(IN Span<CONST UINT8> data)
|
||||
: m_data(data.data()), m_dataSize(data.size()), m_storageType(EStorageType::NON_OWNING)
|
||||
{
|
||||
}
|
||||
|
||||
StreamReader::~StreamReader()
|
||||
{
|
||||
switch (m_storageType)
|
||||
{
|
||||
case EStorageType::OWNING_MMAP:
|
||||
FileOps::UnmapFile(m_data);
|
||||
break;
|
||||
|
||||
case EStorageType::NON_OWNING:
|
||||
case EStorageType::OWNING_VECTOR:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // namespace IACore
|
||||
88
Src/IACore/imp/cpp/StreamWriter.cpp
Normal file
88
Src/IACore/imp/cpp/StreamWriter.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <IACore/StreamWriter.hpp>
|
||||
#include <IACore/FileOps.hpp>
|
||||
#include <IACore/Logger.hpp>
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
StreamWriter::StreamWriter() : m_storageType(EStorageType::OWNING_VECTOR)
|
||||
{
|
||||
m_owningVector.resize(m_capacity = 256);
|
||||
m_buffer = m_owningVector.data();
|
||||
}
|
||||
|
||||
StreamWriter::StreamWriter(IN Span<UINT8> data)
|
||||
: m_buffer(data.data()), m_capacity(data.size()), m_storageType(EStorageType::NON_OWNING)
|
||||
{
|
||||
}
|
||||
|
||||
StreamWriter::StreamWriter(IN CONST FilePath &path) : m_storageType(EStorageType::OWNING_MMAP)
|
||||
{
|
||||
const auto t = FileOps::MapFile(path);
|
||||
if (!t)
|
||||
{
|
||||
Logger::Error("Failed to memory map file {}", path.string());
|
||||
return;
|
||||
}
|
||||
m_buffer = *t;
|
||||
m_capacity = SIZE_MAX;
|
||||
}
|
||||
|
||||
StreamWriter::~StreamWriter()
|
||||
{
|
||||
switch (m_storageType)
|
||||
{
|
||||
case EStorageType::OWNING_MMAP:
|
||||
FileOps::UnmapFile(m_buffer);
|
||||
break;
|
||||
|
||||
case EStorageType::OWNING_VECTOR:
|
||||
case EStorageType::NON_OWNING:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#define HANDLE_OUT_OF_CAPACITY(_size) \
|
||||
if B_UNLIKELY ((m_cursor + _size) > m_capacity) \
|
||||
{ \
|
||||
if (m_storageType == EStorageType::OWNING_VECTOR) \
|
||||
{ \
|
||||
m_owningVector.resize(m_capacity + (_size << 1)); \
|
||||
m_capacity = m_owningVector.size(); \
|
||||
m_buffer = m_owningVector.data(); \
|
||||
} \
|
||||
else \
|
||||
return false; \
|
||||
}
|
||||
|
||||
BOOL StreamWriter::Write(IN UINT8 byte, IN SIZE_T count)
|
||||
{
|
||||
HANDLE_OUT_OF_CAPACITY(count);
|
||||
memset(&m_buffer[m_cursor], byte, count);
|
||||
m_cursor += count;
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOL StreamWriter::Write(IN PCVOID buffer, IN SIZE_T size)
|
||||
{
|
||||
HANDLE_OUT_OF_CAPACITY(size);
|
||||
memcpy(&m_buffer[m_cursor], buffer, size);
|
||||
m_cursor += size;
|
||||
return true;
|
||||
}
|
||||
} // namespace IACore
|
||||
@ -1,101 +0,0 @@
|
||||
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <IACore/PCH.hpp>
|
||||
|
||||
namespace IACore {
|
||||
|
||||
class BinaryReader {
|
||||
public:
|
||||
// ---------------------------------------------------------------------
|
||||
// Construction (Zero Copy)
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Accepts Vector<UINT8>, std::array, or C-arrays automatically
|
||||
BinaryReader(std::span<const UINT8> data)
|
||||
: m_span(data), m_cursor(0) {}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Core API
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Generic Primitive Reader (Read<UINT32>(), Read<FLOAT32>(), etc.)
|
||||
template <typename T>
|
||||
NO_DISCARD("Check for EOF")
|
||||
Expected<T, String> Read() {
|
||||
constexpr SIZE_T size = sizeof(T);
|
||||
|
||||
if B_UNLIKELY((m_cursor + size > m_span.size())) {
|
||||
return MakeUnexpected(String("Unexpected EOF reading type"));
|
||||
}
|
||||
|
||||
T value;
|
||||
// SAFE: memcpy handles alignment issues on ARM/Android automatically.
|
||||
// Modern compilers optimize this into a single register load instruction.
|
||||
std::memcpy(&value, &m_span[m_cursor], size);
|
||||
|
||||
m_cursor += size;
|
||||
return value;
|
||||
}
|
||||
|
||||
// Batch Read (Copy to external buffer)
|
||||
tl::expected<void, String> Read(PVOID buffer, SIZE_T size) {
|
||||
if B_UNLIKELY((m_cursor + size > m_span.size())) {
|
||||
return tl::make_unexpected(String("Unexpected EOF reading buffer"));
|
||||
}
|
||||
|
||||
std::memcpy(buffer, &m_span[m_cursor], size);
|
||||
m_cursor += size;
|
||||
return {};
|
||||
}
|
||||
|
||||
// String Reader (Null Terminated or Length Prefixed)
|
||||
tl::expected<String, String> ReadString(SIZE_T length) {
|
||||
if B_UNLIKELY((m_cursor + length > m_span.size())) {
|
||||
return tl::make_unexpected(String("Unexpected EOF reading string"));
|
||||
}
|
||||
|
||||
// Create string from current pointer
|
||||
String str(REINTERPRET(&m_span[m_cursor], const char*), length);
|
||||
m_cursor += length;
|
||||
return str;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Navigation
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
VOID Skip(SIZE_T amount) {
|
||||
// Clamp to end
|
||||
m_cursor = std::min(m_cursor + amount, m_span.size());
|
||||
}
|
||||
|
||||
VOID Seek(SIZE_T pos) {
|
||||
if (pos > m_span.size()) m_cursor = m_span.size();
|
||||
else m_cursor = pos;
|
||||
}
|
||||
|
||||
SIZE_T Cursor() CONST { return m_cursor; }
|
||||
SIZE_T Remaining() CONST { return m_span.size() - m_cursor; }
|
||||
BOOL IsEOF() CONST { return m_cursor >= m_span.size(); }
|
||||
|
||||
private:
|
||||
std::span<const UINT8> m_span;
|
||||
SIZE_T m_cursor;
|
||||
};
|
||||
}
|
||||
@ -1,100 +0,0 @@
|
||||
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <IACore/PCH.hpp>
|
||||
|
||||
namespace IACore {
|
||||
|
||||
class BinaryWriter {
|
||||
public:
|
||||
// Mode 1: Append to a Vector (Growing)
|
||||
BinaryWriter(Vector<UINT8>& target) : m_buffer(&target), m_span({}), m_cursor(target.size()), m_isVector(true) {}
|
||||
|
||||
// Mode 2: Write into existing fixed memory (No allocs)
|
||||
BinaryWriter(std::span<UINT8> target) : m_buffer(nullptr), m_span(target), m_cursor(0), m_isVector(false) {}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Core API
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Append T (Handling Endianness automatically if needed)
|
||||
template <typename T>
|
||||
VOID Write(T value) {
|
||||
// If we are Little Endian (x86/ARM), this compiles to a raw MOV/memcpy.
|
||||
// If we need specific Endianness (Network Byte Order), use std::byteswap (C++23)
|
||||
// or a simple swap helper.
|
||||
// For a game engine, we usually stick to Native Endian (LE) for speed.
|
||||
|
||||
CONST SIZE_T size = sizeof(T);
|
||||
|
||||
if (m_isVector) {
|
||||
// Vector guarantees contiguous memory, but push_back is slow for primitives.
|
||||
// We resize and memcpy.
|
||||
SIZE_T currentPos = m_buffer->size();
|
||||
m_buffer->resize(currentPos + size);
|
||||
std::memcpy(m_buffer->data() + currentPos, &value, size);
|
||||
} else {
|
||||
// Fixed Buffer Safety Check
|
||||
if B_UNLIKELY((m_cursor + size > m_span.size())) {
|
||||
IA_PANIC("BinaryWriter Overflow");
|
||||
}
|
||||
std::memcpy(m_span.data() + m_cursor, &value, size);
|
||||
m_cursor += size;
|
||||
}
|
||||
}
|
||||
|
||||
// Random Access Write (Replaces put32, put16, etc.)
|
||||
template <typename T>
|
||||
VOID WriteAt(SIZE_T position, T value) {
|
||||
PUINT8 ptr = GetPtrAt(position);
|
||||
if (ptr) {
|
||||
std::memcpy(ptr, &value, sizeof(T));
|
||||
} else {
|
||||
IA_PANIC("BinaryWriter Out of Bounds Write");
|
||||
}
|
||||
}
|
||||
|
||||
VOID WriteBytes(CONST PVOID data, SIZE_T size) {
|
||||
if (m_isVector) {
|
||||
SIZE_T currentPos = m_buffer->size();
|
||||
m_buffer->resize(currentPos + size);
|
||||
std::memcpy(m_buffer->data() + currentPos, data, size);
|
||||
} else {
|
||||
if B_UNLIKELY((m_cursor + size > m_span.size())) IA_PANIC("Overflow");
|
||||
std::memcpy(m_span.data() + m_cursor, data, size);
|
||||
m_cursor += size;
|
||||
}
|
||||
}
|
||||
|
||||
PUINT8 GetPtrAt(SIZE_T pos) {
|
||||
if (m_isVector) {
|
||||
if (pos >= m_buffer->size()) return nullptr;
|
||||
return m_buffer->data() + pos;
|
||||
} else {
|
||||
if (pos >= m_span.size()) return nullptr;
|
||||
return m_span.data() + pos;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Vector<UINT8>* m_buffer;
|
||||
std::span<UINT8> m_span;
|
||||
SIZE_T m_cursor;
|
||||
BOOL m_isVector;
|
||||
};
|
||||
}
|
||||
@ -16,342 +16,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <IACore/PCH.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <IACore/StreamReader.hpp>
|
||||
#include <IACore/StreamWriter.hpp>
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
class File
|
||||
class FileOps
|
||||
{
|
||||
public:
|
||||
// Modern mapping of flags to standard IO streams
|
||||
enum class EOpenFlags : UINT32
|
||||
{
|
||||
Read = 1 << 0, // std::ios::in
|
||||
Write = 1 << 1, // std::ios::out
|
||||
Binary = 1 << 2, // std::ios::binary
|
||||
Append = 1 << 3, // std::ios::app
|
||||
Trunc = 1 << 4 // std::ios::trunc
|
||||
};
|
||||
STATIC VOID UnmapFile(IN PCUINT8 mappedPtr);
|
||||
STATIC Expected<PUINT8, String> MapFile(IN CONST FilePath &path);
|
||||
STATIC Expected<PCUINT8, String> MapReadonlyFile(IN CONST FilePath &path);
|
||||
STATIC Expected<PCUINT8, String> MapReadonlyFile(IN CONST FilePath &path, OUT SIZE_T &size);
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Static Helper API (The "One-Liners")
|
||||
// ---------------------------------------------------------------------
|
||||
STATIC Expected<StreamWriter, String> StreamToFile(IN CONST FilePath &path);
|
||||
STATIC Expected<StreamReader, String> StreamFromFile(IN CONST FilePath &path);
|
||||
|
||||
// Reads entire file into a binary vector
|
||||
NO_DISCARD("Handle the error")
|
||||
|
||||
STATIC tl::expected<Vector<UINT8>, String> ReadToVector(CONST String &path)
|
||||
{
|
||||
// 1. Check File Existence & Size
|
||||
std::error_code ec;
|
||||
auto fileSize = fs::file_size(path, ec);
|
||||
|
||||
if (ec)
|
||||
{
|
||||
return tl::make_unexpected(String("File not found or inaccessible: ") + path);
|
||||
}
|
||||
|
||||
// 2. Open Stream
|
||||
std::ifstream file(path, std::ios::binary);
|
||||
if (!file.is_open())
|
||||
{
|
||||
return tl::make_unexpected(String("Failed to open file handle: ") + path);
|
||||
}
|
||||
|
||||
// 3. Read
|
||||
Vector<UINT8> buffer;
|
||||
buffer.resize(CAST(fileSize, SIZE_T));
|
||||
file.read(REINTERPRET(buffer.data(), char *), fileSize);
|
||||
if (file.fail())
|
||||
return tl::make_unexpected(String("Read error: ") + path);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Reads entire file into a String
|
||||
NO_DISCARD("Handle the error")
|
||||
|
||||
STATIC tl::expected<String, String> ReadToString(CONST String &path)
|
||||
{
|
||||
// Reuse the binary logic to avoid code duplication, then cast
|
||||
auto result = ReadToVector(path);
|
||||
if (!result)
|
||||
{
|
||||
return tl::make_unexpected(result.error());
|
||||
}
|
||||
|
||||
// Efficient move into string (reinterpret_cast approach or move)
|
||||
// Since Vector<UINT8> and String memory layout isn't guaranteed identical, we copy.
|
||||
// (Though in many STL implementations you could theoretically steal the buffer, copying is safer)
|
||||
String str(result->begin(), result->end());
|
||||
return str;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Path Utilities (Replaces manual parsing)
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// Old: ExtractFilenameFromPath<true/false>
|
||||
// New: true -> filename(), false -> stem()
|
||||
template<BOOL includeExtension = true> STATIC String ExtractFilename(CONST String &pathStr)
|
||||
{
|
||||
fs::path p(pathStr);
|
||||
if CONSTEXPR (includeExtension)
|
||||
{
|
||||
return p.filename().string(); // "sprite.png"
|
||||
}
|
||||
else
|
||||
{
|
||||
return p.stem().string(); // "sprite"
|
||||
}
|
||||
}
|
||||
|
||||
// Old: ExtractDirectoryFromPath
|
||||
STATIC String ExtractDirectory(CONST String &pathStr)
|
||||
{
|
||||
fs::path p(pathStr);
|
||||
return p.parent_path().string(); // "assets/textures"
|
||||
}
|
||||
|
||||
STATIC BOOL Exists(CONST String &pathStr)
|
||||
{
|
||||
std::error_code ec;
|
||||
return fs::exists(pathStr, ec);
|
||||
}
|
||||
|
||||
public:
|
||||
// ---------------------------------------------------------------------
|
||||
// Instance API (For streaming/partial reads)
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
File() = default;
|
||||
|
||||
#ifdef __cplusplus
|
||||
File(CONST String &path, EOpenFlags flags)
|
||||
#else
|
||||
File(CONST String &path, UINT32 flags)
|
||||
#endif
|
||||
{
|
||||
UNUSED(Open(path, flags));
|
||||
}
|
||||
|
||||
~File()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
tl::expected<void, String> Open(CONST String &path, EOpenFlags flags)
|
||||
#else
|
||||
tl::expected<void, String> Open(CONST String &path, UINT32 flags)
|
||||
#endif
|
||||
{
|
||||
Close(); // Ensure previous handle is closed
|
||||
|
||||
std::ios_base::openmode mode = static_cast<std::ios_base::openmode>(0);
|
||||
if ((UINT32) flags & (UINT32) EOpenFlags::Read)
|
||||
mode |= std::ios::in;
|
||||
if ((UINT32) flags & (UINT32) EOpenFlags::Write)
|
||||
mode |= std::ios::out;
|
||||
if ((UINT32) flags & (UINT32) EOpenFlags::Binary)
|
||||
mode |= std::ios::binary;
|
||||
if ((UINT32) flags & (UINT32) EOpenFlags::Append)
|
||||
mode |= std::ios::app;
|
||||
if ((UINT32) flags & (UINT32) EOpenFlags::Trunc)
|
||||
mode |= std::ios::trunc;
|
||||
|
||||
m_fs.open(path, mode);
|
||||
|
||||
if (!m_fs.is_open())
|
||||
{
|
||||
return tl::make_unexpected(String("Failed to open file: ") + path);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
VOID Close()
|
||||
{
|
||||
if (m_fs.is_open())
|
||||
{
|
||||
m_fs.close();
|
||||
}
|
||||
}
|
||||
|
||||
BOOL IsOpen() CONST
|
||||
{
|
||||
return m_fs.is_open();
|
||||
}
|
||||
|
||||
// Returns number of bytes read
|
||||
SIZE_T Read(PVOID buffer, SIZE_T size)
|
||||
{
|
||||
if B_UNLIKELY (!m_fs.is_open())
|
||||
return 0;
|
||||
m_fs.read(REINTERPRET(buffer, char *), size);
|
||||
return static_cast<SIZE_T>(m_fs.gcount());
|
||||
}
|
||||
|
||||
VOID Write(CONST PVOID buffer, SIZE_T size)
|
||||
{
|
||||
if B_UNLIKELY (!m_fs.is_open())
|
||||
return;
|
||||
m_fs.write(REINTERPRET(buffer, const char *), size);
|
||||
}
|
||||
|
||||
std::fstream *GetStreamHandle()
|
||||
{
|
||||
return &m_fs;
|
||||
}
|
||||
STATIC Expected<String, String> ReadTextFile(IN CONST FilePath &path);
|
||||
STATIC Expected<Vector<UINT8>, String> ReadBinaryFile(IN CONST FilePath &path);
|
||||
STATIC Expected<SIZE_T, String> WriteTextFile(IN CONST FilePath &path, IN CONST String &contents);
|
||||
STATIC Expected<SIZE_T, String> WriteBinaryFile(IN CONST FilePath &path, IN Span<UINT8> contents);
|
||||
|
||||
private:
|
||||
std::fstream m_fs;
|
||||
};
|
||||
|
||||
class MMFile
|
||||
{
|
||||
public:
|
||||
MMFile() = default;
|
||||
|
||||
// RAII - Automatically unmap on destruction
|
||||
~MMFile()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
// Disable copy (managing ownership of raw handles is messy)
|
||||
MMFile(const MMFile &) = delete;
|
||||
MMFile &operator=(const MMFile &) = delete;
|
||||
|
||||
// Open and Map
|
||||
bool Map(const std::string &filepath)
|
||||
{
|
||||
Close(); // Cleanup any existing map
|
||||
|
||||
#if IA_PLATFORM_WINDOWS > 0
|
||||
// 1. Open File
|
||||
hFile_ = ::CreateFileA(filepath.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
if (hFile_ == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
// 2. Get File Size
|
||||
LARGE_INTEGER size;
|
||||
if (!::GetFileSizeEx(hFile_, &size))
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
size_ = static_cast<size_t>(size.QuadPart);
|
||||
|
||||
// 3. Create Mapping Object
|
||||
hMapping_ = ::CreateFileMappingA(hFile_, nullptr, PAGE_READWRITE, 0, 0, nullptr);
|
||||
if (!hMapping_)
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 4. Map View
|
||||
data_ = ::MapViewOfFile(hMapping_, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||
if (!data_)
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
#else // LINUX / POSIX
|
||||
// 1. Open File
|
||||
fd_ = ::open(filepath.c_str(), O_RDWR);
|
||||
if (fd_ == -1)
|
||||
return false;
|
||||
|
||||
// 2. Get File Size
|
||||
struct stat sb;
|
||||
if (fstat(fd_, &sb) == -1)
|
||||
{
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
size_ = static_cast<size_t>(sb.st_size);
|
||||
|
||||
// 3. mmap
|
||||
// PROT_READ: Read only
|
||||
// MAP_PRIVATE: Copy-on-write (safe if you accidentally modify, though we return const)
|
||||
data_ = ::mmap(nullptr, size_, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd_, 0);
|
||||
if (data_ == MAP_FAILED)
|
||||
{
|
||||
data_ = nullptr;
|
||||
Close();
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void Close()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (data_)
|
||||
{
|
||||
::UnmapViewOfFile(data_);
|
||||
data_ = nullptr;
|
||||
}
|
||||
if (hMapping_)
|
||||
{
|
||||
::CloseHandle(hMapping_);
|
||||
hMapping_ = nullptr;
|
||||
}
|
||||
if (hFile_ != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
::CloseHandle(hFile_);
|
||||
hFile_ = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
#else
|
||||
if (data_)
|
||||
{
|
||||
::munmap(data_, size_);
|
||||
data_ = nullptr;
|
||||
}
|
||||
if (fd_ != -1)
|
||||
{
|
||||
::close(fd_);
|
||||
fd_ = -1;
|
||||
}
|
||||
#endif
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
// Accessors
|
||||
const void *GetData() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
size_t GetSize() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return data_ != nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
void *data_ = nullptr;
|
||||
size_t size_ = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE hFile_ = INVALID_HANDLE_VALUE;
|
||||
HANDLE hMapping_ = nullptr;
|
||||
#else
|
||||
int fd_ = -1;
|
||||
#endif
|
||||
STATIC UnorderedMap<PCUINT8, PVOID> s_mappedFiles;
|
||||
};
|
||||
} // namespace IACore
|
||||
@ -33,8 +33,10 @@
|
||||
# include <cstring>
|
||||
# include <cstddef>
|
||||
# include <chrono>
|
||||
# include <fstream>
|
||||
# include <iostream>
|
||||
# include <concepts>
|
||||
# include <filesystem>
|
||||
# include <functional>
|
||||
# include <type_traits>
|
||||
# include <initializer_list>
|
||||
@ -546,6 +548,9 @@ using ScopedLock = std::scoped_lock<Mutex>;
|
||||
using UniqueLock = std::unique_lock<Mutex>;
|
||||
using JoiningThread = std::jthread;
|
||||
|
||||
namespace FileSystem = std::filesystem;
|
||||
using FilePath = FileSystem::path;
|
||||
|
||||
template<typename... Args> using FormatterString = std::format_string<Args...>;
|
||||
|
||||
#endif
|
||||
|
||||
@ -73,24 +73,6 @@ namespace IACore
|
||||
}
|
||||
|
||||
private:
|
||||
STATIC BOOL IsPortAvailable(IN UINT16 port, IN INT32 type)
|
||||
{
|
||||
SocketHandle sock = socket(AF_INET, type, IPPROTO_UDP);
|
||||
if (!IS_VALID_SOCKET(sock))
|
||||
return false;
|
||||
|
||||
sockaddr_in addr{};
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
bool isFree = false;
|
||||
if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) == 0)
|
||||
isFree = true;
|
||||
|
||||
CLOSE_SOCKET(sock);
|
||||
|
||||
return isFree;
|
||||
}
|
||||
STATIC BOOL IsPortAvailable(IN UINT16 port, IN INT32 type);
|
||||
};
|
||||
} // namespace IACore
|
||||
104
Src/IACore/inc/IACore/StreamReader.hpp
Normal file
104
Src/IACore/inc/IACore/StreamReader.hpp
Normal file
@ -0,0 +1,104 @@
|
||||
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <IACore/PCH.hpp>
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
class StreamReader
|
||||
{
|
||||
enum class EStorageType
|
||||
{
|
||||
NON_OWNING,
|
||||
OWNING_MMAP,
|
||||
OWNING_VECTOR,
|
||||
};
|
||||
|
||||
public:
|
||||
INLINE Expected<VOID, String> Read(IN PVOID buffer, IN SIZE_T size);
|
||||
template<typename T> NO_DISCARD("Check for EOF") Expected<T, String> Read();
|
||||
|
||||
VOID Skip(SIZE_T amount)
|
||||
{
|
||||
m_cursor = std::min(m_cursor + amount, m_dataSize);
|
||||
}
|
||||
|
||||
VOID Seek(SIZE_T pos)
|
||||
{
|
||||
m_cursor = (pos > m_dataSize) ? m_dataSize : pos;
|
||||
}
|
||||
|
||||
SIZE_T Cursor() CONST
|
||||
{
|
||||
return m_cursor;
|
||||
}
|
||||
|
||||
SIZE_T Size() CONST
|
||||
{
|
||||
return m_dataSize;
|
||||
}
|
||||
|
||||
SIZE_T Remaining() CONST
|
||||
{
|
||||
return m_dataSize - m_cursor;
|
||||
}
|
||||
|
||||
BOOL IsEOF() CONST
|
||||
{
|
||||
return m_cursor >= m_dataSize;
|
||||
}
|
||||
|
||||
public:
|
||||
StreamReader(IN CONST FilePath &path);
|
||||
explicit StreamReader(IN Vector<UINT8> &&data);
|
||||
explicit StreamReader(IN Span<CONST UINT8> data);
|
||||
~StreamReader();
|
||||
|
||||
private:
|
||||
PCUINT8 m_data{};
|
||||
SIZE_T m_cursor{};
|
||||
SIZE_T m_dataSize{};
|
||||
Vector<UINT8> m_owningVector;
|
||||
CONST EStorageType m_storageType;
|
||||
};
|
||||
|
||||
Expected<VOID, String> StreamReader::Read(IN PVOID buffer, IN SIZE_T size)
|
||||
{
|
||||
if B_UNLIKELY ((m_cursor + size > m_dataSize))
|
||||
return MakeUnexpected(String("Unexpected EOF while reading"));
|
||||
|
||||
std::memcpy(buffer, &m_data[m_cursor], size);
|
||||
m_cursor += size;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T> NO_DISCARD("Check for EOF") Expected<T, String> StreamReader::Read()
|
||||
{
|
||||
constexpr SIZE_T size = sizeof(T);
|
||||
|
||||
if B_UNLIKELY ((m_cursor + size > m_dataSize))
|
||||
return MakeUnexpected(String("Unexpected EOF while reading"));
|
||||
|
||||
T value;
|
||||
std::memcpy(&value, &m_data[m_cursor], size);
|
||||
m_cursor += size;
|
||||
|
||||
return value;
|
||||
}
|
||||
} // namespace IACore
|
||||
65
Src/IACore/inc/IACore/StreamWriter.hpp
Normal file
65
Src/IACore/inc/IACore/StreamWriter.hpp
Normal file
@ -0,0 +1,65 @@
|
||||
// IACore-OSS; The Core Library for All IA Open Source Projects
|
||||
// Copyright (C) 2025 IAS (ias@iasoft.dev)
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <IACore/PCH.hpp>
|
||||
|
||||
namespace IACore
|
||||
{
|
||||
class StreamWriter
|
||||
{
|
||||
enum class EStorageType
|
||||
{
|
||||
NON_OWNING,
|
||||
OWNING_MMAP,
|
||||
OWNING_VECTOR,
|
||||
};
|
||||
|
||||
public:
|
||||
BOOL Write(IN UINT8 byte, IN SIZE_T count);
|
||||
BOOL Write(IN PCVOID buffer, IN SIZE_T size);
|
||||
template<typename T> BOOL Write(IN CONST T &value);
|
||||
|
||||
PCUINT8 Data() CONST
|
||||
{
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
SIZE_T Cursor() CONST
|
||||
{
|
||||
return m_cursor;
|
||||
}
|
||||
|
||||
public:
|
||||
StreamWriter();
|
||||
explicit StreamWriter(IN Span<UINT8> data);
|
||||
explicit StreamWriter(IN CONST FilePath &path);
|
||||
~StreamWriter();
|
||||
|
||||
private:
|
||||
PUINT8 m_buffer{};
|
||||
SIZE_T m_cursor{};
|
||||
SIZE_T m_capacity{};
|
||||
Vector<UINT8> m_owningVector;
|
||||
CONST EStorageType m_storageType;
|
||||
};
|
||||
|
||||
template<typename T> BOOL StreamWriter::Write(IN CONST T &value)
|
||||
{
|
||||
return Write(&value, sizeof(T));
|
||||
}
|
||||
} // namespace IACore
|
||||
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <IACore/BinaryReader.hpp>
|
||||
#include <IACore/BinaryStreamReader.hpp>
|
||||
|
||||
#include <IACore/IATest.hpp>
|
||||
|
||||
@ -24,7 +24,7 @@ using namespace IACore;
|
||||
// Test Block Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
IAT_BEGIN_BLOCK(Core, BinaryReader)
|
||||
IAT_BEGIN_BLOCK(Core, BinaryStreamReader)
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 1. Basic Primitive Reading (UINT8)
|
||||
@ -32,7 +32,7 @@ IAT_BEGIN_BLOCK(Core, BinaryReader)
|
||||
BOOL TestReadUint8()
|
||||
{
|
||||
UINT8 data[] = { 0xAA, 0xBB, 0xCC };
|
||||
BinaryReader reader(data);
|
||||
BinaryStreamReader reader(data);
|
||||
|
||||
// Read First Byte
|
||||
auto val1 = reader.Read<UINT8>();
|
||||
@ -54,7 +54,7 @@ IAT_BEGIN_BLOCK(Core, BinaryReader)
|
||||
{
|
||||
// 0x04030201 in Little Endian memory layout
|
||||
UINT8 data[] = { 0x01, 0x02, 0x03, 0x04 };
|
||||
BinaryReader reader(data);
|
||||
BinaryStreamReader reader(data);
|
||||
|
||||
auto val = reader.Read<UINT32>();
|
||||
IAT_CHECK(val.has_value());
|
||||
@ -79,7 +79,7 @@ IAT_BEGIN_BLOCK(Core, BinaryReader)
|
||||
UINT8 data[4];
|
||||
std::memcpy(data, &pi, 4);
|
||||
|
||||
BinaryReader reader(data);
|
||||
BinaryStreamReader reader(data);
|
||||
auto val = reader.Read<FLOAT32>();
|
||||
|
||||
IAT_CHECK(val.has_value());
|
||||
@ -94,7 +94,7 @@ IAT_BEGIN_BLOCK(Core, BinaryReader)
|
||||
BOOL TestReadString()
|
||||
{
|
||||
const char* raw = "HelloIA";
|
||||
BinaryReader reader(std::span<const UINT8>((const UINT8*)raw, 7));
|
||||
BinaryStreamReader reader(std::span<const UINT8>((const UINT8*)raw, 7));
|
||||
|
||||
// Read "Hello" (5 bytes)
|
||||
auto str = reader.ReadString(5);
|
||||
@ -116,7 +116,7 @@ IAT_BEGIN_BLOCK(Core, BinaryReader)
|
||||
{
|
||||
UINT8 src[] = { 1, 2, 3, 4, 5 };
|
||||
UINT8 dst[3] = { 0 };
|
||||
BinaryReader reader(src);
|
||||
BinaryStreamReader reader(src);
|
||||
|
||||
// Read 3 bytes into dst
|
||||
auto res = reader.Read(dst, 3);
|
||||
@ -139,7 +139,7 @@ IAT_BEGIN_BLOCK(Core, BinaryReader)
|
||||
BOOL TestNavigation()
|
||||
{
|
||||
UINT8 data[10] = { 0 }; // Zero init
|
||||
BinaryReader reader(data);
|
||||
BinaryStreamReader reader(data);
|
||||
|
||||
IAT_CHECK_EQ(reader.Remaining(), (SIZE_T)10);
|
||||
|
||||
@ -168,7 +168,7 @@ IAT_BEGIN_BLOCK(Core, BinaryReader)
|
||||
BOOL TestBoundaryChecks()
|
||||
{
|
||||
UINT8 data[] = { 0x00, 0x00 };
|
||||
BinaryReader reader(data);
|
||||
BinaryStreamReader reader(data);
|
||||
|
||||
// Valid read
|
||||
UNUSED(reader.Read<UINT16>());
|
||||
@ -213,7 +213,7 @@ int main(int argc, char* argv[])
|
||||
// Define runner (StopOnFail=false, Verbose=true)
|
||||
ia::iatest::runner<false, true> testRunner;
|
||||
|
||||
// Run the BinaryReader block
|
||||
// Run the BinaryStreamReader block
|
||||
testRunner.testBlock<Core_BinaryReader>();
|
||||
|
||||
return 0;
|
||||
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <IACore/BinaryWriter.hpp>
|
||||
#include <IACore/BinaryStreamWriter.hpp>
|
||||
|
||||
#include <IACore/IATest.hpp>
|
||||
|
||||
@ -24,7 +24,7 @@ using namespace IACore;
|
||||
// Test Block Definition
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
IAT_BEGIN_BLOCK(Core, BinaryWriter)
|
||||
IAT_BEGIN_BLOCK(Core, BinaryStreamWriter)
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 1. Vector Mode (Dynamic Growth)
|
||||
@ -33,7 +33,7 @@ IAT_BEGIN_BLOCK(Core, BinaryWriter)
|
||||
{
|
||||
std::vector<UINT8> buffer;
|
||||
// Start empty
|
||||
BinaryWriter writer(buffer);
|
||||
BinaryStreamWriter writer(buffer);
|
||||
|
||||
// Write 1 Byte
|
||||
writer.Write<UINT8>(0xAA);
|
||||
@ -62,7 +62,7 @@ IAT_BEGIN_BLOCK(Core, BinaryWriter)
|
||||
{
|
||||
// Vector starts with existing data
|
||||
std::vector<UINT8> buffer = { 0x01, 0x02 };
|
||||
BinaryWriter writer(buffer);
|
||||
BinaryStreamWriter writer(buffer);
|
||||
|
||||
// Should append to end, not overwrite 0x01
|
||||
writer.Write<UINT8>(0x03);
|
||||
@ -83,7 +83,7 @@ IAT_BEGIN_BLOCK(Core, BinaryWriter)
|
||||
// Initialize with zeros
|
||||
std::memset(rawData, 0, 10);
|
||||
|
||||
BinaryWriter writer(rawData); // Implicit conversion to span
|
||||
BinaryStreamWriter writer(rawData); // Implicit conversion to span
|
||||
|
||||
// Write UINT8
|
||||
writer.Write<UINT8>(0xFF);
|
||||
@ -106,7 +106,7 @@ IAT_BEGIN_BLOCK(Core, BinaryWriter)
|
||||
BOOL TestWriteBytes()
|
||||
{
|
||||
std::vector<UINT8> buffer;
|
||||
BinaryWriter writer(buffer);
|
||||
BinaryStreamWriter writer(buffer);
|
||||
|
||||
const char* msg = "IA";
|
||||
writer.WriteBytes((PVOID)msg, 2);
|
||||
@ -126,7 +126,7 @@ IAT_BEGIN_BLOCK(Core, BinaryWriter)
|
||||
BOOL TestRandomAccess()
|
||||
{
|
||||
std::vector<UINT8> buffer;
|
||||
BinaryWriter writer(buffer);
|
||||
BinaryStreamWriter writer(buffer);
|
||||
|
||||
// Fill with placeholders
|
||||
writer.Write<UINT32>(0xFFFFFFFF);
|
||||
@ -152,7 +152,7 @@ IAT_BEGIN_BLOCK(Core, BinaryWriter)
|
||||
BOOL TestWriteFloat()
|
||||
{
|
||||
std::vector<UINT8> buffer;
|
||||
BinaryWriter writer(buffer);
|
||||
BinaryStreamWriter writer(buffer);
|
||||
|
||||
FLOAT32 val = 1.234f;
|
||||
writer.Write<FLOAT32>(val);
|
||||
@ -174,7 +174,7 @@ IAT_BEGIN_BLOCK(Core, BinaryWriter)
|
||||
BOOL TestGetPtr()
|
||||
{
|
||||
std::vector<UINT8> buffer = { 0x10, 0x20, 0x30 };
|
||||
BinaryWriter writer(buffer);
|
||||
BinaryStreamWriter writer(buffer);
|
||||
|
||||
PUINT8 p1 = writer.GetPtrAt(1);
|
||||
IAT_CHECK(p1 != nullptr);
|
||||
@ -216,7 +216,7 @@ int main(int argc, char* argv[])
|
||||
ia::iatest::runner<false, true> testRunner;
|
||||
|
||||
// Run the BinaryReader block
|
||||
testRunner.testBlock<Core_BinaryWriter>();
|
||||
testRunner.testBlock<Core_BinaryStreamWriter>();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -13,21 +13,21 @@ set_target_properties(${TEST_NAME_PREFIX}CCompile PROPERTIES
|
||||
|
||||
target_link_libraries(${TEST_NAME_PREFIX}CCompile PRIVATE IACore)
|
||||
|
||||
# ------------------------------------------------
|
||||
# Unit: BinaryReader
|
||||
# ------------------------------------------------
|
||||
add_executable(${TEST_NAME_PREFIX}BinaryReader "BinaryReader.cpp")
|
||||
target_link_libraries(${TEST_NAME_PREFIX}BinaryReader PRIVATE IACore)
|
||||
target_compile_options(${TEST_NAME_PREFIX}BinaryReader PRIVATE -fexceptions)
|
||||
set_target_properties(${TEST_NAME_PREFIX}BinaryReader PROPERTIES USE_EXCEPTIONS ON)
|
||||
|
||||
# ------------------------------------------------
|
||||
# Unit: BinaryWriter
|
||||
# ------------------------------------------------
|
||||
add_executable(${TEST_NAME_PREFIX}BinaryWriter "BinaryWriter.cpp")
|
||||
target_link_libraries(${TEST_NAME_PREFIX}BinaryWriter PRIVATE IACore)
|
||||
target_compile_options(${TEST_NAME_PREFIX}BinaryWriter PRIVATE -fexceptions)
|
||||
set_target_properties(${TEST_NAME_PREFIX}BinaryWriter PROPERTIES USE_EXCEPTIONS ON)
|
||||
## ------------------------------------------------
|
||||
## Unit: BinaryReader
|
||||
## ------------------------------------------------
|
||||
#add_executable(${TEST_NAME_PREFIX}BinaryReader "BinaryReader.cpp")
|
||||
#target_link_libraries(${TEST_NAME_PREFIX}BinaryReader PRIVATE IACore)
|
||||
#target_compile_options(${TEST_NAME_PREFIX}BinaryReader PRIVATE -fexceptions)
|
||||
#set_target_properties(${TEST_NAME_PREFIX}BinaryReader PROPERTIES USE_EXCEPTIONS ON)
|
||||
#
|
||||
## ------------------------------------------------
|
||||
## Unit: BinaryWriter
|
||||
## ------------------------------------------------
|
||||
#add_executable(${TEST_NAME_PREFIX}BinaryWriter "BinaryWriter.cpp")
|
||||
#target_link_libraries(${TEST_NAME_PREFIX}BinaryWriter PRIVATE IACore)
|
||||
#target_compile_options(${TEST_NAME_PREFIX}BinaryWriter PRIVATE -fexceptions)
|
||||
#set_target_properties(${TEST_NAME_PREFIX}BinaryWriter PROPERTIES USE_EXCEPTIONS ON)
|
||||
|
||||
# ------------------------------------------------
|
||||
# Unit: Environment
|
||||
|
||||
Reference in New Issue
Block a user