diff --git a/src/core/RagePhoto.c b/src/core/RagePhoto.c index 80b6de2..0d6d386 100644 --- a/src/core/RagePhoto.c +++ b/src/core/RagePhoto.c @@ -1,6 +1,6 @@ /***************************************************************************** * libragephoto RAGE Photo Parser -* Copyright (C) 2021-2024 Syping +* Copyright (C) 2021-2025 Syping * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -22,7 +22,6 @@ #include #include -#ifdef RAGEPHOTO_BENCHMARK #ifdef _WIN32 #ifndef VC_EXTRALEAN #define VC_EXTRALEAN @@ -30,22 +29,19 @@ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif +#include +#include #include -#else +#endif + +#ifdef RAGEPHOTO_BENCHMARK +#ifndef _WIN32 #include #endif #endif -#if defined(UNICODE_ICONV) +#ifdef UNICODE_ICONV #include -#elif defined(UNICODE_WINCVT) -#ifndef VC_EXTRALEAN -#define VC_EXTRALEAN -#endif -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include #endif /* RAGEPHOTO LIBRARY GLOBALS */ @@ -53,6 +49,40 @@ int libraryflags = 0; const char* nullchar = ""; /* BEGIN OF STATIC LIBRARY FUNCTIONS */ +static inline FILE* openFile(const char *filename, char accessMode) +{ + if (accessMode != 'r' && accessMode != 'w') + return NULL; +#ifdef _WIN32 + int wideCharSize = MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0); + if (wideCharSize <= 0) + return NULL; + wchar_t *wideCharFilename = (wchar_t*)malloc(wideCharSize * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, filename, -1, wideCharFilename, wideCharSize); + HANDLE hFile = CreateFileW(wideCharFilename, + accessMode == 'r' ? GENERIC_READ : GENERIC_WRITE, + accessMode == 'r' ? FILE_SHARE_READ : 0, + NULL, + accessMode == 'r' ? OPEN_EXISTING : CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + free(wideCharFilename); + int fd = _open_osfhandle((intptr_t)hFile, accessMode == 'r' ? _O_RDONLY | _O_BINARY : _O_WRONLY | _O_BINARY); + if (fd == -1) { + CloseHandle(hFile); + return NULL; + } + FILE *file = _fdopen(fd, accessMode == 'r' ? "rb" : "wb"); + if (!file) { + _close(fd); + return NULL; + } +#else + FILE *file = fopen(filename, accessMode == 'r' ? "rb" : "wb"); +#endif + return file; +} + static inline size_t readBuffer(const char *input, void *output, size_t *pos, size_t outputLen, size_t inputLen) { size_t readLen = 0; @@ -601,12 +631,7 @@ bool ragephoto_load(ragephoto_t instance_t, const char *data, size_t size) bool ragephoto_loadfile(ragephoto_t instance_t, const char *filename) { RagePhotoInstance *instance = (RagePhotoInstance*)instance_t; -#if defined(_WIN32) - FILE *file = NULL; - fopen_s(&file, filename, "rb"); -#else - FILE *file = fopen(filename, "rb"); -#endif + FILE *file = openFile(filename, 'r'); if (!file) return false; #if defined(_WIN64) @@ -1010,12 +1035,7 @@ bool ragephoto_savefilef(ragephoto_t instance_t, const char *filename, uint32_t free(data); return false; } -#ifdef _WIN32 - FILE *file = NULL; - fopen_s(&file, filename, "wb"); -#else - FILE *file = fopen(filename, "wb"); -#endif + FILE *file = openFile(filename, 'w'); if (!file) { free(data); return false; diff --git a/src/core/RagePhoto.cpp b/src/core/RagePhoto.cpp index eee0570..f035bde 100644 --- a/src/core/RagePhoto.cpp +++ b/src/core/RagePhoto.cpp @@ -1,6 +1,6 @@ /***************************************************************************** * libragephoto RAGE Photo Parser -* Copyright (C) 2021-2024 Syping +* Copyright (C) 2021-2025 Syping * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -28,6 +28,18 @@ #include #include +#ifdef _WIN32 +#ifndef VC_EXTRALEAN +#define VC_EXTRALEAN +#endif +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#endif + #ifdef RAGEPHOTO_BENCHMARK #include #endif @@ -37,14 +49,12 @@ #include #elif defined UNICODE_ICONV #include -#elif defined UNICODE_WINCVT -#ifndef VC_EXTRALEAN -#define VC_EXTRALEAN #endif -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include + +#if defined(_WIN32) && (RAGEPHOTO_CXX_STD >= 17) && (__cplusplus >= 201703L) +#include +#elif defined(_WIN32) +#include #endif /* CLASSIC RAGEPHOTO TYPEDEF */ @@ -55,6 +65,18 @@ int libraryflags = 0; const char* nullchar = ""; /* BEGIN OF STATIC LIBRARY FUNCTIONS */ +#if defined(_WIN32) && ((RAGEPHOTO_CXX_STD < 17) || (__cplusplus < 201703L)) +inline std::unique_ptr convertPath(const char* path) +{ + int wideCharSize = MultiByteToWideChar(CP_UTF8, 0, path, -1, nullptr, 0); + if (wideCharSize <= 0) + return std::unique_ptr(new wchar_t[1]()); + std::unique_ptr wideCharPath(new wchar_t[wideCharSize]); + MultiByteToWideChar(CP_UTF8, 0, path, -1, wideCharPath.get(), wideCharSize); + return wideCharPath; +} +#endif + inline size_t readBuffer(const char *input, void *output, size_t *pos, size_t outputLen, size_t inputLen) { size_t readLen = 0; @@ -589,9 +611,15 @@ bool RagePhoto::load(const std::string &data) return load(data.data(), data.size(), m_data, m_parser); } -bool RagePhoto::loadFile(const std::string &filename) +bool RagePhoto::loadFile(const char *filename) { +#if defined(_WIN32) && (RAGEPHOTO_CXX_STD >= 17) && (__cplusplus >= 201703L) + std::ifstream ifs(std::filesystem::u8path(filename), std::ios::in | std::ios::binary); +#elif defined(_WIN32) + std::ifstream ifs(convertPath(filename).get(), std::ios::in | std::ios::binary); +#else std::ifstream ifs(filename, std::ios::in | std::ios::binary); +#endif if (ifs.is_open()) { std::string sdata(std::istreambuf_iterator{ifs}, {}); ifs.close(); @@ -974,7 +1002,13 @@ bool RagePhoto::saveFile(const char *filename, uint32_t photoFormat) bool ok; const std::string sdata = save(photoFormat, &ok); if (ok) { +#if defined(_WIN32) && (RAGEPHOTO_CXX_STD >= 17) && (__cplusplus >= 201703L) + std::ofstream ofs(std::filesystem::u8path(filename), std::ios::out | std::ios::binary | std::ios::trunc); +#elif defined(_WIN32) + std::ofstream ofs(convertPath(filename).get(), std::ios::out | std::ios::binary | std::ios::trunc); +#else std::ofstream ofs(filename, std::ios::out | std::ios::binary | std::ios::trunc); +#endif if (!ofs.is_open()) { m_data->error = Error::Uninitialised; // 0 return false; diff --git a/src/core/ragephoto_cxx.hpp b/src/core/ragephoto_cxx.hpp index d5f05d4..c205266 100644 --- a/src/core/ragephoto_cxx.hpp +++ b/src/core/ragephoto_cxx.hpp @@ -1,6 +1,6 @@ /***************************************************************************** * libragephoto RAGE Photo Parser -* Copyright (C) 2021-2024 Syping +* Copyright (C) 2021-2025 Syping * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -119,7 +119,7 @@ public: /** Loads a Photo from a file. * \param filename File to load */ - bool loadFile(const std::string &filename); + bool loadFile(const char *filename); int32_t error() const; /**< Returns the last error occurred. */ uint32_t format() const; /**< Returns the Photo Format (GTA V or RDR 2). */ const std::string jpeg() const; /**< Returns the Photo JPEG data. */