From dea6da687d514c6aa92a331fec99d2c595ee5d45 Mon Sep 17 00:00:00 2001 From: nikitalita <69168929+nikitalita@users.noreply.github.com> Date: Fri, 27 Oct 2023 14:48:40 -0700 Subject: [PATCH] feat: add BSSystemFile, BSLog (#209) --- CommonLibSF/include/RE/B/BSLog.h | 65 ++++++++++ CommonLibSF/include/RE/B/BSSystemFile.h | 85 +++++++++++++ CommonLibSF/include/RE/IDs.h | 30 +++++ CommonLibSF/include/RE/Starfield.h | 2 + CommonLibSF/include/SFSE/Impl/WinAPI.h | 6 + CommonLibSF/src/RE/B/BSLog.cpp | 84 ++++++++++++ CommonLibSF/src/RE/B/BSSystemFile.cpp | 162 ++++++++++++++++++++++++ 7 files changed, 434 insertions(+) create mode 100644 CommonLibSF/include/RE/B/BSLog.h create mode 100644 CommonLibSF/include/RE/B/BSSystemFile.h create mode 100644 CommonLibSF/src/RE/B/BSLog.cpp create mode 100644 CommonLibSF/src/RE/B/BSSystemFile.cpp diff --git a/CommonLibSF/include/RE/B/BSLog.h b/CommonLibSF/include/RE/B/BSLog.h new file mode 100644 index 00000000..9388096e --- /dev/null +++ b/CommonLibSF/include/RE/B/BSLog.h @@ -0,0 +1,65 @@ +#pragma once +#include "RE/B/BSFixedString.h" +#include "RE/B/BSLock.h" +#include "RE/B/BSSystemFile.h" + +namespace RE +{ + class BSLog + { + ~BSLog(); + BSLog() = delete; + BSLog(const BSLog&) = delete; + BSLog(BSLog&&) = delete; + BSLog( + const char* a_logName, + const char* a_logFolderPath, + bool a_timeStamped, + std::uint32_t a_logNumber, + std::uint32_t a_bufferSize, + std::uint32_t a_blocks_allocated); + + void CycleLog(); + void FlushBuffer(bool a_forceFlush); + void FlushBufferToFile(bool a_forceFlush); + void WriteEntry(const char* a_string, bool a_shouldFlush); + void WriteData(char* data, std::uint32_t size, bool a_shouldFlush); + + static void MakeLogFilename(char* a_name, const char* a_dir, std::uint32_t a_logNumber, BSFixedString& r_fileName, bool a_appendLogNumber); + static void GenerateTimeStamp(char* a_buffer); + + private: + BSLog* ctor( + const char* a_logName, + const char* a_logFolderPath, + bool a_timeStamped, + std::uint32_t a_logNumber, + std::uint32_t a_bufferSize, + std::uint32_t a_blocks_allocated); + void dtor(); + + public: + // members + BSFixedString logName; // 00 + BSFixedString logFolderPath; // 08 + uint32_t logNumber; // 10 + uint32_t bytesAllocated; // 14 + BSSpinLock writeLock; // 18 + BSSystemFile sysfile; // 20 + std::uint64_t unk30; // 30 + std::uint64_t unk38; // 38 + std::byte unk40[448]; // 40 -- likely a scrapheap + bool isAllocated; // 200 + std::uint8_t pad201; // 201 + std::uint16_t pad202; // 202 + std::uint32_t pad204; // 204 + std::byte unk208[0x32]; // 208 + int unk240; // 240 + bool isInUse; // 244 + bool isActive; // 245 + bool timestamped; // 246 + bool unk247; // 247 + std::byte unk248[0x38]; // 248 + }; + static_assert(sizeof(BSLog) == 0x280); +} \ No newline at end of file diff --git a/CommonLibSF/include/RE/B/BSSystemFile.h b/CommonLibSF/include/RE/B/BSSystemFile.h new file mode 100644 index 00000000..9c6b45ea --- /dev/null +++ b/CommonLibSF/include/RE/B/BSSystemFile.h @@ -0,0 +1,85 @@ +#pragma once + +namespace RE +{ + class BSSystemFile + { + public: + enum class ErrorCode : std::uint32_t + { + kOk = 0, + kUnknownError = 1, + kFileNotFound = 2, + kAlreadyExists = 3, + kPathNotFound = 4, + kAccessDenied = 5, + kOtherFileError = 6 + }; + enum class AccessMode : std::uint32_t + { + kRead = 0, + kReadWrite = 1, + kWriteOnly = 2 + }; + enum class OpenMode : std::uint32_t + { + kOpenExisting = 0, + kOpenAlways = 1, + kCreateAlways = 2, + kTruncateExisting = 3, + kCreateIfNotExist = 4 + }; + enum class ShareMode : std::uint32_t + { + kExclusive = 0, + kShareRead = 1, + kShareWrite = 2, + kShareReadWrite = 3 + }; + + enum class SeekMode : std::uint32_t + { + kBegin = 0, + kCurrent = 1, + kEnd = 2 + }; + + ~BSSystemFile(); + BSSystemFile(); + BSSystemFile( + const char* a_path, + AccessMode a_accessMode, + OpenMode a_openMode, + bool a_read, + [[maybe_unused]] std::uint64_t a_unk1, + bool a_write, + ShareMode a_shareMode); + + explicit BSSystemFile(BSSystemFile& a_lhs); + explicit BSSystemFile(BSSystemFile&& a_rhs); + + BSSystemFile& operator=(BSSystemFile& a_lhs); + + void Flush(); + void Invalidate(); + ErrorCode GetSize(std::uint64_t& r_size); + ErrorCode GetErrorCode(); + ErrorCode Read(void* a_buffer, std::uint64_t a_toRead, std::uint64_t& r_read); + ErrorCode Seek(std::int64_t a_offset, SeekMode a_seekMode, std::uint64_t& r_newPosition); + void SetErrorCode(ErrorCode a_errorCode); + ErrorCode Truncate(std::uint64_t a_bytesToTruncate); + ErrorCode Write(const void* a_buffer, std::uint64_t a_toWrite, std::uint64_t& r_written); + + static std::uint32_t RenameFile(const char* a_path, const char* a_replace); + static std::uint32_t DeleteFileA(const char* a_path); + + private: + void DoClose(); + ErrorCode DoOpen(const char* a_path, AccessMode a_accessMode, OpenMode a_openMode, ShareMode a_shareMode); + ErrorCode DoSeek(std::int64_t a_offset, SeekMode a_seekMode, std::uint64_t& r_newPosition); + + std::uint32_t flags; // 00 + void* file; // 08 + }; + static_assert(sizeof(BSSystemFile) == 0x10); +} diff --git a/CommonLibSF/include/RE/IDs.h b/CommonLibSF/include/RE/IDs.h index e5221f2d..d1eecaf8 100644 --- a/CommonLibSF/include/RE/IDs.h +++ b/CommonLibSF/include/RE/IDs.h @@ -36,6 +36,19 @@ namespace RE::ID inline constexpr REL::ID ctor{ 101725 }; } + namespace BSLog + { + inline constexpr REL::ID ctor{ 184813 }; + inline constexpr REL::ID dtor{ 184816 }; + inline constexpr REL::ID CycleLog{ 184822 }; + inline constexpr REL::ID FlushBuffer{ 184823 }; + inline constexpr REL::ID FlushBufferToFile{ 184824 }; + inline constexpr REL::ID GenerateTimeStamp{ 184825 }; + inline constexpr REL::ID MakeLogFilename{ 184826 }; + inline constexpr REL::ID WriteData{ 184832 }; + inline constexpr REL::ID WriteEntry{ 184833 }; + } + namespace BSNonReentrantSpinLock { inline constexpr REL::ID lock{ 73879 }; @@ -125,6 +138,23 @@ namespace RE::ID inline constexpr REL::ID GetEntry_wchar_t_{ 198220 }; } + namespace BSSystemFile + { + inline constexpr REL::ID ctor{ 198445 }; + inline constexpr REL::ID dtor{ 198446 }; + inline constexpr REL::ID DoClose{ 198452 }; + inline constexpr REL::ID DeleteFileA{ 198451 }; + inline constexpr REL::ID DoOpen{ 198454 }; + inline constexpr REL::ID DoSeek{ 198456 }; + inline constexpr REL::ID DoSetEndOfFile{ 198457 }; + inline constexpr REL::ID Flush{ 78151 }; + inline constexpr REL::ID GetSize{ 85176 }; + inline constexpr REL::ID Read{ 75362 }; + inline constexpr REL::ID RenameFile{ 198459 }; + inline constexpr REL::ID Truncate{ 195959 }; + inline constexpr REL::ID Write{ 75363 }; + inline constexpr REL::ID operatorEqCopy{ 198448 }; + } namespace BSTEventSource { diff --git a/CommonLibSF/include/RE/Starfield.h b/CommonLibSF/include/RE/Starfield.h index fd58379c..2e9a70d4 100644 --- a/CommonLibSF/include/RE/Starfield.h +++ b/CommonLibSF/include/RE/Starfield.h @@ -65,9 +65,11 @@ #include "RE/B/BSInputEventUser.h" #include "RE/B/BSIntrusiveRefCounted.h" #include "RE/B/BSLock.h" +#include "RE/B/BSLog.h" #include "RE/B/BSReflection.h" #include "RE/B/BSStringPool.h" #include "RE/B/BSStringT.h" +#include "RE/B/BSSystemFile.h" #include "RE/B/BSTArray.h" #include "RE/B/BSTEvent.h" #include "RE/B/BSTList.h" diff --git a/CommonLibSF/include/SFSE/Impl/WinAPI.h b/CommonLibSF/include/SFSE/Impl/WinAPI.h index 7b595eea..106de25b 100644 --- a/CommonLibSF/include/SFSE/Impl/WinAPI.h +++ b/CommonLibSF/include/SFSE/Impl/WinAPI.h @@ -99,6 +99,12 @@ namespace SFSE::WinAPI inline constexpr auto FILE_MAP_TARGETS_INVALID{ 0x40000000u }; inline constexpr auto FILE_MAP_RESERVE{ 0x80000000u }; + // file open mode flags + inline constexpr auto GENERIC_READ{ 0x80000000L }; + inline constexpr auto GENERIC_WRITE{ 0x40000000L }; + inline constexpr auto GENERIC_EXECUTE{ 0x20000000L }; + inline constexpr auto GENERIC_ALL{ 0x10000000L }; + // known folder flags inline constexpr auto KF_FLAG_DEFAULT{ 0x00000000u }; inline constexpr auto KF_FLAG_FORCE_APP_DATA_REDIRECTION{ 0x00080000u }; diff --git a/CommonLibSF/src/RE/B/BSLog.cpp b/CommonLibSF/src/RE/B/BSLog.cpp new file mode 100644 index 00000000..f1a57149 --- /dev/null +++ b/CommonLibSF/src/RE/B/BSLog.cpp @@ -0,0 +1,84 @@ +#include "RE/B/BSLog.h" + +namespace RE +{ + BSLog::~BSLog() + { + dtor(); + } + + BSLog::BSLog( + const char* a_logName, + const char* a_logFolderPath, + bool a_timeStamped, + std::uint32_t a_logNumber, + std::uint32_t a_bufferSize, + std::uint32_t a_blocks_allocated) + { + ctor(a_logName, a_logFolderPath, a_timeStamped, a_logNumber, a_bufferSize, a_blocks_allocated); + } + + BSLog* BSLog::ctor(const char* a_logName, const char* a_logFolderPath, bool a_timeStamped, std::uint32_t a_logNumber, std::uint32_t a_bufferSize, std::uint32_t a_blocks_allocated) + { + using func_t = decltype(&BSLog::ctor); + REL::Relocation func{ ID::BSLog::ctor }; + return func(this, a_logName, a_logFolderPath, a_timeStamped, a_logNumber, a_bufferSize, a_blocks_allocated); + } + + void BSLog::dtor() + { + using func_t = decltype(&BSLog::dtor); + REL::Relocation func{ ID::BSLog::dtor }; + return func(this); + } + + void BSLog::CycleLog() + { + using func_t = decltype(&BSLog::CycleLog); + REL::Relocation func{ ID::BSLog::CycleLog }; + return func(this); + } + + void BSLog::FlushBuffer(bool forceFlush) + { + using func_t = decltype(&BSLog::FlushBuffer); + REL::Relocation func{ ID::BSLog::FlushBuffer }; + return func(this, forceFlush); + } + + void BSLog::FlushBufferToFile(bool forceFlush) + { + using func_t = decltype(&BSLog::FlushBufferToFile); + REL::Relocation func{ ID::BSLog::FlushBufferToFile }; + return func(this, forceFlush); + } + + void BSLog::WriteEntry(const char* a_string, bool shouldFlush) + { + using func_t = decltype(&BSLog::WriteEntry); + REL::Relocation func{ ID::BSLog::WriteEntry }; + return func(this, a_string, shouldFlush); + } + + void BSLog::WriteData(char* data, std::uint32_t size, bool shouldFlush) + { + using func_t = decltype(&BSLog::WriteData); + REL::Relocation func{ ID::BSLog::WriteData }; + return func(this, data, size, shouldFlush); + } + + void BSLog::MakeLogFilename(char* a_name, const char* a_dir, std::uint32_t a_logNumber, BSFixedString& r_fileName, bool a_appendLogNumber) + { + using func_t = decltype(&BSLog::MakeLogFilename); + REL::Relocation func{ ID::BSLog::MakeLogFilename }; + return func(a_name, a_dir, a_logNumber, r_fileName, a_appendLogNumber); + } + + void BSLog::GenerateTimeStamp(char* a_buffer) + { + using func_t = decltype(&BSLog::GenerateTimeStamp); + REL::Relocation func{ ID::BSLog::GenerateTimeStamp }; + return func(a_buffer); + } + +} \ No newline at end of file diff --git a/CommonLibSF/src/RE/B/BSSystemFile.cpp b/CommonLibSF/src/RE/B/BSSystemFile.cpp new file mode 100644 index 00000000..4e1f2b75 --- /dev/null +++ b/CommonLibSF/src/RE/B/BSSystemFile.cpp @@ -0,0 +1,162 @@ +#include "RE/B/BSSystemFile.h" + +namespace RE +{ + BSSystemFile::~BSSystemFile() + { + DoClose(); + } + + BSSystemFile::BSSystemFile() : + flags(1), + file(WinAPI::INVALID_HANDLE_VALUE) + { + } + + BSSystemFile::BSSystemFile( + const char* a_path, + AccessMode a_accessMode, + OpenMode a_openMode, + bool a_read, + [[maybe_unused]] std::uint64_t a_unk1, + bool a_write, + ShareMode a_shareMode) : + file(WinAPI::INVALID_HANDLE_VALUE) + { + flags = 0; + if (a_read) { + flags |= WinAPI::GENERIC_READ; + } + if (a_write) { + flags |= WinAPI::GENERIC_WRITE; + } + auto ret = DoOpen(a_path, a_accessMode, a_openMode, a_shareMode); + SetErrorCode(ret); + } + + BSSystemFile::BSSystemFile(BSSystemFile& a_lhs) : + file(a_lhs.file), + flags(a_lhs.flags) + { + a_lhs.Invalidate(); + } + + BSSystemFile::BSSystemFile(BSSystemFile&& a_rhs) : + file(a_rhs.file), + flags(a_rhs.flags) + { + a_rhs.Invalidate(); + } + + BSSystemFile& BSSystemFile::operator=(BSSystemFile& a_lhs) + { + // close the file if the handle is valid + if (file != WinAPI::INVALID_HANDLE_VALUE) { + DoClose(); + } + file = a_lhs.file; + flags = a_lhs.flags; + a_lhs.Invalidate(); + return *this; + } + + void BSSystemFile::Flush() + { + using func_t = decltype(&BSSystemFile::Flush); + REL::Relocation func{ ID::BSSystemFile::Flush }; + return func(this); + } + + void BSSystemFile::Invalidate() + { + file = WinAPI::INVALID_HANDLE_VALUE; + flags = 1; + } + + BSSystemFile::ErrorCode BSSystemFile::GetSize(std::uint64_t& r_size) + { + using func_t = decltype(&BSSystemFile::GetSize); + REL::Relocation func{ ID::BSSystemFile::GetSize }; + return func(this, r_size); + } + + BSSystemFile::ErrorCode BSSystemFile::GetErrorCode() + { + return static_cast(flags & 0x3FFFFFFF); + } + + BSSystemFile::ErrorCode BSSystemFile::Read(void* a_buffer, std::uint64_t a_toRead, std::uint64_t& r_read) + { + using func_t = decltype(&BSSystemFile::Read); + REL::Relocation func{ ID::BSSystemFile::Read }; + return func(this, a_buffer, a_toRead, r_read); + } + + BSSystemFile::ErrorCode BSSystemFile::Seek(std::int64_t a_offset, SeekMode a_seekMode, std::uint64_t& r_newPosition) + { + // All usages of Seek were inlined + auto ret = DoSeek(a_offset, a_seekMode, r_newPosition); + SetErrorCode(ret); + return ret; + } + + void BSSystemFile::SetErrorCode(ErrorCode a_errorCode) + { + flags &= WinAPI::GENERIC_READ; + flags |= static_cast(a_errorCode); + } + + BSSystemFile::ErrorCode BSSystemFile::Truncate(std::uint64_t a_bytesToTruncate) + { + using func_t = decltype(&BSSystemFile::Truncate); + REL::Relocation func{ ID::BSSystemFile::Truncate }; + return func(this, a_bytesToTruncate); + } + + BSSystemFile::ErrorCode BSSystemFile::Write(const void* a_buffer, std::uint64_t a_toWrite, std::uint64_t& r_written) + { + using func_t = decltype(&BSSystemFile::Write); + REL::Relocation func{ ID::BSSystemFile::Write }; + return func(this, a_buffer, a_toWrite, r_written); + } + + std::uint32_t BSSystemFile::RenameFile(const char* a_path, const char* a_replace) + { + using func_t = decltype(&BSSystemFile::RenameFile); + REL::Relocation func{ ID::BSSystemFile::RenameFile }; + return func(a_path, a_replace); + } + + std::uint32_t BSSystemFile::DeleteFileA(const char* a_path) + { + using func_t = decltype(&BSSystemFile::DeleteFileA); + REL::Relocation func{ ID::BSSystemFile::DeleteFileA }; + return func(a_path); + } + + void BSSystemFile::DoClose() + { + using func_t = decltype(&BSSystemFile::DoClose); + REL::Relocation func{ ID::BSSystemFile::DoClose }; + return func(this); + } + + BSSystemFile::ErrorCode BSSystemFile::DoOpen( + const char* a_path, + AccessMode a_accessMode, + OpenMode a_openMode, + ShareMode a_shareMode) + { + using func_t = decltype(&BSSystemFile::DoOpen); + REL::Relocation func{ ID::BSSystemFile::DoOpen }; + return func(this, a_path, a_accessMode, a_openMode, a_shareMode); + } + + BSSystemFile::ErrorCode BSSystemFile::DoSeek(std::int64_t a_offset, SeekMode a_seekMode, std::uint64_t& r_newPosition) + { + using func_t = decltype(&BSSystemFile::DoSeek); + REL::Relocation func{ ID::BSSystemFile::DoSeek }; + return func(this, a_offset, a_seekMode, r_newPosition); + } + +}