From 7bb894eb0d862eedaf0c0eab0bb204512060487d Mon Sep 17 00:00:00 2001 From: shermp <14854761+shermp@users.noreply.github.com> Date: Wed, 10 Apr 2019 22:25:29 +1200 Subject: [PATCH] Create cross platform fopen() wrapper --- minivhd.c | 13 +------------ vhdutil.c | 32 +++++++++++++++++++++++++++++++- vhdutil.h | 4 +++- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/minivhd.c b/minivhd.c index 48e03d0..65b277e 100644 --- a/minivhd.c +++ b/minivhd.c @@ -197,21 +197,10 @@ static VHDError vhd_load_parent(VHDMeta* vhdm, FILE* f, const char* child_filepa /* (Hopefully) get the absolute path of the parent VHD */ cwk_path_get_absolute(child_dir, u8_rel_path, abs_path, sizeof abs_path); free(u8_rel_path); -#ifdef _WIN32 - uint16_t w_filemode[3] = {0x0072, 0x0062, 0x0000}; /* "rb" */ - char *w_abs_path = NULL; - vhd_utf_convert(VHD_UTF_16_LE, abs_path, &w_abs_path); - FILE* par_f = _wfopen((uint16_t*)w_abs_path, w_filemode); + FILE* par_f = vhd_fopen(abs_path, "rb"); if (par_f) { vhdm->parent.f = par_f; } - free(w_abs_path); -#else - FILE* par_f = fopen(abs_path, "rb"); - if (par_f) { - vhdm->parent.f = par_f; - } -#endif vhdm->parent.meta = calloc(1, sizeof(VHDMeta)); return VHD_RET_OK; } diff --git a/vhdutil.c b/vhdutil.c index 241a1fb..71f73a8 100644 --- a/vhdutil.c +++ b/vhdutil.c @@ -1,12 +1,14 @@ #include +#include #include -#include "vhdutil.h" +#include #ifdef _WIN32 #include #else #include #include #endif +#include "vhdutil.h" int vhd_utf_convert(VHDUtfType toUTF, void* in_str, char** out_str) { @@ -56,4 +58,32 @@ size_t vhd_u16_strlen(uint16_t* u16_str) { u16_str += 1; } return count; +} + +FILE* vhd_fopen(char* utf8_path, char* mode) +{ +#ifdef _WIN32 + errno_t err = 0; + char* u16_path = NULL; + WCHAR u16_mode[5] = {0}; + /* Convert mode to UTF-16LE. Thankfully it's ASCII, which make the conversion simple... + Note, we're on Windows, so guaranteed to be little endian, therefore, no byte swapping needed. */ + int mode_len = strlen(mode); + if (mode_len > 0 && mode_len < 5) { + for (int i = 0; i < mode_len; i++) { + u16_mode[i] = (WCHAR)mode[i]; + } + } + /* Convert utf8_path to UTF-16LE */ + vhd_utf_convert(VHD_UTF_16_LE, utf8_path, &u16_path); + FILE* f = _wfopen((LPCWCH)u16_path, u16_mode); + if (f == NULL) {_get_errno(&err);} + free(u16_path); + /* We want to mimic (_w)fopen() behavior */ + if (err) {_set_errno(err);} + return f; +#else + /* Non-Windows OS's speak UTF-8 for fopen() */ + return fopen(utf8_path, mode); +#endif } \ No newline at end of file diff --git a/vhdutil.h b/vhdutil.h index 59a2ce0..492cb9f 100644 --- a/vhdutil.h +++ b/vhdutil.h @@ -15,4 +15,6 @@ int vhd_utf_convert(VHDUtfType toUTF, void* in_str, char** out_str); /* Count the number of "characters" in a null terminated UTF-16 string. Not a true character count, as surrogate pairs are counted as two "characters". Appears to be the Windows definition of a character for filepath purposes. */ -size_t vhd_u16_strlen(uint16_t* u16_str); \ No newline at end of file +size_t vhd_u16_strlen(uint16_t* u16_str); +/* Cross platform function to open a (potentially) non-ascii filepath */ +FILE* vhd_fopen(char* utf8_path, char* mode); \ No newline at end of file