diff --git a/Source/engine/assets.cpp b/Source/engine/assets.cpp index 3639d49dc..c1045aaa3 100644 --- a/Source/engine/assets.cpp +++ b/Source/engine/assets.cpp @@ -144,7 +144,7 @@ AssetRef FindAsset(const char *filename) AssetHandle OpenAsset(AssetRef &&ref, bool threadsafe) { #ifdef UNPACKED_MPQS - return AssetHandle { CreateFileStream(ref.path.c_str(), std::fstream::in | std::fstream::binary) }; + return AssetHandle { OpenFile(ref.path.c_str(), "rb") }; #else if (ref.archive != nullptr) return AssetHandle { SDL_RWops_FromMpqFile(*ref.archive, ref.fileNumber, ref.filename, threadsafe) }; diff --git a/Source/engine/assets.hpp b/Source/engine/assets.hpp index 90246623e..34ac808b4 100644 --- a/Source/engine/assets.hpp +++ b/Source/engine/assets.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -40,23 +41,47 @@ struct AssetRef { }; struct AssetHandle { - std::optional handle; + FILE *handle = nullptr; + + AssetHandle() = default; + + AssetHandle(FILE *handle) + : handle(handle) + { + } + + AssetHandle(AssetHandle &&other) noexcept + : handle(other.handle) + { + other.handle = nullptr; + } + + AssetHandle &operator=(AssetHandle &&other) noexcept + { + handle = other.handle; + other.handle = nullptr; + return *this; + } + + ~AssetHandle() + { + if (handle != nullptr) + std::fclose(handle); + } [[nodiscard]] bool ok() const { - return handle && !handle->fail(); + return handle != nullptr && std::ferror(handle) == 0; } bool read(void *buffer, size_t len) { - handle->read(static_cast(buffer), len); - return !handle->fail(); + return std::fread(buffer, len, 1, handle) == 1; } bool seek(std::ios::pos_type pos) { - handle->seekg(pos); - return !handle->fail(); + return std::fseek(handle, pos, SEEK_SET) == 0; } [[nodiscard]] const char *error() const diff --git a/Source/utils/file_util.cpp b/Source/utils/file_util.cpp index e1937ef9e..6565e6667 100644 --- a/Source/utils/file_util.cpp +++ b/Source/utils/file_util.cpp @@ -225,4 +225,20 @@ std::optional CreateFileStream(const char *path, std::ios::openmod #endif } +FILE *OpenFile(const char *path, const char *mode) +{ +#if (defined(_WIN64) || defined(_WIN32)) && !defined(NXDK) + std::unique_ptr pathUtf16; + std::unique_ptr modeUtf16; + if ((pathUtf16 = ToWideChar(path)) == nullptr + || (modeUtf16 = ToWideChar(mode)) == nullptr) { + LogError("UTF-8 -> UTF-16 conversion error code {}", ::GetLastError()); + return {}; + } + return _wfopen(pathUtf16.get(), modeUtf16.get()); +#else + return std::fopen(path, mode); +#endif +} + } // namespace devilution diff --git a/Source/utils/file_util.h b/Source/utils/file_util.h index cec0a7fde..0fe7e15cb 100644 --- a/Source/utils/file_util.h +++ b/Source/utils/file_util.h @@ -23,6 +23,7 @@ bool GetFileSize(const char *path, std::uintmax_t *size); bool ResizeFile(const char *path, std::uintmax_t size); void RemoveFile(const char *path); std::optional CreateFileStream(const char *path, std::ios::openmode mode); +FILE *OpenFile(const char *path, const char *mode); #if (defined(_WIN64) || defined(_WIN32)) && !defined(NXDK) std::unique_ptr ToWideChar(string_view path);