#include "file.h" #include #include #include #include namespace { std::atomic nextFileId(0); } idFile::idFile() : uniqID(++nextFileId) { } unsigned int idFile::ReadOfs(const std::int64_t offset, void* data, const unsigned int length) { const std::int64_t position = Tell(); if (Seek(offset, FS_SEEK_SET) != 0) return 0; const unsigned int result = Read(data, length); Seek(position, FS_SEEK_SET); return result; } unsigned int idFile::WriteOfs(const std::int64_t offset, const void* data, const unsigned int length) { const std::int64_t position = Tell(); if (Seek(offset, FS_SEEK_SET) != 0) return 0; const unsigned int result = Write(data, length); Seek(position, FS_SEEK_SET); return result; } unsigned int idFile::Printf(const char* format, ...) { va_list arguments; va_start(arguments, format); const unsigned int result = VPrintf(format, arguments); va_end(arguments); return result; } unsigned int idFile::VPrintf(const char* format, char* arguments) { char text[4096]; const int length = _vsnprintf_s(text, sizeof(text), _TRUNCATE, format, arguments); return length > 0 ? Write(text, static_cast(length)) : 0; } unsigned int idFile::WriteFloatString(const char* format, ...) { va_list arguments; va_start(arguments, format); const unsigned int result = VPrintf(format, arguments); va_end(arguments); return result; } unsigned int idFile::ReadString(idStr& string) { std::uint32_t length = 0; unsigned int bytes = ReadLittle(length); if (length == 0) { string.Clear(); return bytes; } char* text = static_cast(std::malloc(length + 1)); if (text == nullptr) return bytes; const unsigned int read = Read(text, length); text[read] = '\0'; string = text; std::free(text); return bytes + read; } unsigned int idFile::WriteString(const idStr& string) { return WriteString(string.c_str()); } unsigned int idFile::WriteString(const char* string) { const char* const safeString = string != nullptr ? string : ""; const std::uint32_t length = static_cast( std::strlen(safeString)); return WriteLittle(length) + Write(safeString, length); } idFile_Memory::idFile_Memory() : idFile(), name(), mode(FS_WRITE), maxSize(0), fileSize(0), allocated(0), timestamp(0), filePtr(nullptr), curPtr(nullptr), ownsData(true) { } idFile_Memory::idFile_Memory(const char* fileName) : idFile_Memory() { name = fileName; } idFile_Memory::~idFile_Memory() { if (ownsData) std::free(filePtr); } void idFile_Memory::SetReadOnlyData(const char* data, const unsigned int length) { if (ownsData) std::free(filePtr); maxSize = fileSize = allocated = length; mode = FS_READ; filePtr = const_cast(data); curPtr = filePtr; ownsData = false; } void idFile_Memory::SetWritableData(char* data, const unsigned int length) { if (ownsData) std::free(filePtr); maxSize = allocated = length; fileSize = 0; mode = FS_WRITE; filePtr = curPtr = data; ownsData = false; } unsigned int idFile_Memory::Read(void* data, const unsigned int length) { if (data == nullptr || filePtr == nullptr || curPtr == nullptr) return 0; const unsigned int position = static_cast(curPtr - filePtr); const unsigned int available = position < fileSize ? fileSize - position : 0; const unsigned int amount = (std::min)(length, available); std::memcpy(data, curPtr, amount); curPtr += amount; return amount; } unsigned int idFile_Memory::Write(const void* data, const unsigned int length) { if (mode == FS_READ || data == nullptr) return 0; unsigned int position = filePtr != nullptr && curPtr != nullptr ? static_cast(curPtr - filePtr) : 0; if (maxSize != 0 && position + length > maxSize) return 0; if (position + length > allocated) { const unsigned int target = (std::max)(position + length, allocated == 0 ? 256u : allocated * 2u); const unsigned int oldFileSize = fileSize; SetLength(target); fileSize = oldFileSize; position = curPtr != nullptr ? static_cast(curPtr - filePtr) : 0; } std::memcpy(curPtr, data, length); curPtr += length; fileSize = (std::max)(fileSize, position + length); return length; } unsigned int idFile_Memory::ReadOfs(const std::int64_t offset, void* data, const unsigned int length) { if (offset < 0 || static_cast(offset) > fileSize) return 0; const unsigned int position = static_cast(offset); const unsigned int amount = (std::min)(length, fileSize - position); std::memcpy(data, filePtr + position, amount); return amount; } unsigned int idFile_Memory::WriteOfs(const std::int64_t offset, const void* data, const unsigned int length) { if (offset < 0) return 0; const std::int64_t oldPosition = Tell(); if (Seek(offset, FS_SEEK_SET) != 0) return 0; const unsigned int result = Write(data, length); Seek(oldPosition, FS_SEEK_SET); return result; } void idFile_Memory::SetLength(const unsigned int length) { if (length > allocated) { if (maxSize != 0 && length > maxSize) return; const std::size_t position = filePtr != nullptr && curPtr != nullptr ? static_cast(curPtr - filePtr) : 0; char* replacement = static_cast(std::malloc(length)); if (replacement == nullptr && length != 0) return; if (filePtr != nullptr) std::memcpy(replacement, filePtr, (std::min)(fileSize, length)); if (ownsData) std::free(filePtr); filePtr = replacement; curPtr = filePtr + (std::min)(position, static_cast(length)); allocated = length; ownsData = true; } fileSize = length; if (curPtr != nullptr && curPtr > filePtr + fileSize) curPtr = filePtr + fileSize; } std::int64_t idFile_Memory::Tell() const { return filePtr != nullptr && curPtr != nullptr ? curPtr - filePtr : 0; } int idFile_Memory::Seek(const std::int64_t offset, const fsOrigin_t origin) { std::int64_t target = offset; if (origin == FS_SEEK_CUR) target += Tell(); else if (origin == FS_SEEK_END) target += fileSize; if (target < 0 || static_cast(target) > fileSize) return -1; curPtr = filePtr + static_cast(target); return 0; } void idFile_Memory::Clear(const bool freeMemory) { fileSize = 0; if (freeMemory && ownsData) { std::free(filePtr); filePtr = curPtr = nullptr; allocated = 0; } else { curPtr = filePtr; } } void idFile_Memory::SetMaxLength(const unsigned int length) { const unsigned int oldSize = fileSize; SetLength(length); maxSize = length; fileSize = oldSize; } void idFile_Memory::MakeReadOnly() { mode = FS_READ; Seek(0, FS_SEEK_SET); } void idFile_Memory::MakeWritable() { mode = FS_WRITE; Seek(0, FS_SEEK_SET); }