From e2fd9f528850f5215cbb76247ec3bad273c0236d Mon Sep 17 00:00:00 2001 From: Wohlstand Date: Thu, 24 Mar 2016 12:28:46 +0300 Subject: [PATCH] Allow UTF-8 paths on Windows A paths trouble appears on Windows OS when program which uses luajit is placed in a path which contains non-ASCII characters. Usually on Linux, OS X and other posix and unix-like platforms paths are encoded as UTF-8, therefore no troubles with fopen() function. On modern Windows versions all paths are encoded as UTF-16LE and also fopen() function on Windows always accepts ANSI-encoded paths, therefore because a codepage mismatch, fopen() think that file is not exists. To resolve this trouble need to convert accepted path into UTF-16 from UTF-8 and use _wfopen() which accepts UTF-16 paths. _lua_fopen() and _lua_freopen() functions are made to allow support of UTF-8 paths on Windows, on any other platforms there are a macros over standard fopen/freopen functions. --- src/Makefile | 2 +- src/lib_io.c | 5 +++-- src/lib_package.c | 3 ++- src/lj_clib.c | 3 ++- src/lj_fopen.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/lj_fopen.h | 14 ++++++++++++++ src/lj_load.c | 3 ++- src/lj_trace.c | 3 ++- 8 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 src/lj_fopen.c create mode 100644 src/lj_fopen.h diff --git a/src/Makefile b/src/Makefile index 1cddf188..f0d7431f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -472,7 +472,7 @@ LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o \ lj_mcode.o lj_snap.o lj_record.o lj_crecord.o lj_ffrecord.o \ lj_asm.o lj_trace.o lj_gdbjit.o \ lj_ctype.o lj_cdata.o lj_cconv.o lj_ccall.o lj_ccallback.o \ - lj_carith.o lj_clib.o lj_cparse.o \ + lj_carith.o lj_clib.o lj_cparse.o lj_fopen.o \ lj_lib.o lj_alloc.o lib_aux.o \ $(LJLIB_O) lib_init.o diff --git a/src/lib_io.c b/src/lib_io.c index be317d4b..913865dc 100644 --- a/src/lib_io.c +++ b/src/lib_io.c @@ -16,6 +16,7 @@ #include "lauxlib.h" #include "lualib.h" +#include "lj_fopen.h" #include "lj_obj.h" #include "lj_gc.h" #include "lj_err.h" @@ -82,7 +83,7 @@ static IOFileUD *io_file_open(lua_State *L, const char *mode) { const char *fname = strdata(lj_lib_checkstr(L, 1)); IOFileUD *iof = io_file_new(L); - iof->fp = fopen(fname, mode); + iof->fp = _lua_fopen(fname, mode); if (iof->fp == NULL) luaL_argerror(L, 1, lj_str_pushf(L, "%s: %s", fname, strerror(errno))); return iof; @@ -407,7 +408,7 @@ LJLIB_CF(io_open) GCstr *s = lj_lib_optstr(L, 2); const char *mode = s ? strdata(s) : "r"; IOFileUD *iof = io_file_new(L); - iof->fp = fopen(fname, mode); + iof->fp = _lua_fopen(fname, mode); return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname); } diff --git a/src/lib_package.c b/src/lib_package.c index 1d9fef3d..e2d9bf7e 100644 --- a/src/lib_package.c +++ b/src/lib_package.c @@ -16,6 +16,7 @@ #include "lj_obj.h" #include "lj_err.h" #include "lj_lib.h" +#include "lj_fopen.h" /* ------------------------------------------------------------------------ */ @@ -262,7 +263,7 @@ static int lj_cf_package_unloadlib(lua_State *L) static int readable(const char *filename) { - FILE *f = fopen(filename, "r"); /* try to open file */ + FILE *f = _lua_fopen(filename, "r"); /* try to open file */ if (f == NULL) return 0; /* open failed */ fclose(f); return 1; diff --git a/src/lj_clib.c b/src/lj_clib.c index 8389ee78..a4502dc5 100644 --- a/src/lj_clib.c +++ b/src/lj_clib.c @@ -16,6 +16,7 @@ #include "lj_cconv.h" #include "lj_cdata.h" #include "lj_clib.h" +#include "lj_fopen.h" /* -- OS-specific functions ----------------------------------------------- */ @@ -93,7 +94,7 @@ static const char *clib_check_lds(lua_State *L, const char *buf) /* Quick and dirty solution to resolve shared library name from ld script. */ static const char *clib_resolve_lds(lua_State *L, const char *name) { - FILE *fp = fopen(name, "r"); + FILE *fp = _lua_fopen(name, "r"); const char *p = NULL; if (fp) { char buf[256]; diff --git a/src/lj_fopen.c b/src/lj_fopen.c new file mode 100644 index 00000000..8ad4e922 --- /dev/null +++ b/src/lj_fopen.c @@ -0,0 +1,44 @@ +#include "lj_fopen.h" +/* + * Forces to look for unicode paths on Windows + */ +#ifdef _WIN32 +#include + +FILE *_lua_fopen(const char *filename, const char *mode) +{ + int fn_len_s=strlen(filename); + if(fn_len_s==0) return NULL; + int m_len_s=strlen(mode); + if(m_len_s==0) return NULL; + wchar_t path[MAX_PATH]; + wchar_t wmode[MAX_PATH]; + int new_Len1 = MultiByteToWideChar(CP_UTF8, 0, filename, fn_len_s, path, fn_len_s); + if(new_Len1>=MAX_PATH) return NULL; + path[new_Len1] = L'\0'; + int new_Len2 = MultiByteToWideChar(CP_UTF8, 0, mode, m_len_s, wmode, m_len_s); + if(new_Len2>=MAX_PATH) return NULL; + wmode[new_Len2] = L'\0'; + FILE *f = _wfopen(path, wmode); + return f; +} + +FILE *_lua_freopen(const char *filename, const char *mode, FILE * oldfile) +{ + int fn_len_s=strlen(filename); + if(fn_len_s==0) return NULL; + int m_len_s=strlen(filename); + if(m_len_s==0) return NULL; + wchar_t path[MAX_PATH]; + wchar_t wmode[MAX_PATH]; + int new_Len1 = MultiByteToWideChar(CP_UTF8, 0, filename, fn_len_s, path, fn_len_s); + path[new_Len1] = L'\0'; + int new_Len2 = MultiByteToWideChar(CP_UTF8, 0, mode, m_len_s, wmode, m_len_s); + wmode[new_Len2] = L'\0'; + FILE *f = _wfreopen(path, wmode, oldfile); + LocalFree(path); + LocalFree(wmode); + return f; +} + +#endif diff --git a/src/lj_fopen.h b/src/lj_fopen.h new file mode 100644 index 00000000..788c0955 --- /dev/null +++ b/src/lj_fopen.h @@ -0,0 +1,14 @@ +#ifndef LJ_FILE_OPEN_H +#define LJ_FILE_OPEN_H + +#include + +#ifdef _WIN32 +FILE *_lua_fopen(const char *filename, const char *mode); +FILE *_lua_freopen(const char *filename, const char *mode, FILE *oldfile); +#else +#define _lua_fopen(file, mode) fopen(file, mode) +#define _lua_freopen(file, mode, oldfile) freopen(file, mode, oldfile) +#endif + +#endif // LJ_FILE_OPEN_H diff --git a/src/lj_load.c b/src/lj_load.c index 5a55b716..ca493fc0 100644 --- a/src/lj_load.c +++ b/src/lj_load.c @@ -22,6 +22,7 @@ #include "lj_lex.h" #include "lj_bcdump.h" #include "lj_parse.h" +#include "lj_fopen.h" /* -- Load Lua source code and bytecode ----------------------------------- */ @@ -88,7 +89,7 @@ LUALIB_API int luaL_loadfilex(lua_State *L, const char *filename, int status; const char *chunkname; if (filename) { - ctx.fp = fopen(filename, "rb"); + ctx.fp = _lua_fopen(filename, "rb"); if (ctx.fp == NULL) { lua_pushfstring(L, "cannot open %s: %s", filename, strerror(errno)); return LUA_ERRFILE; diff --git a/src/lj_trace.c b/src/lj_trace.c index 5df84414..549141cc 100644 --- a/src/lj_trace.c +++ b/src/lj_trace.c @@ -30,6 +30,7 @@ #include "lj_vm.h" #include "lj_vmevent.h" #include "lj_target.h" +#include "lj_fopen.h" /* -- Error handling ------------------------------------------------------ */ @@ -109,7 +110,7 @@ static void perftools_addtrace(GCtrace *T) if (!fp) { char fname[40]; sprintf(fname, "/tmp/perf-%d.map", getpid()); - if (!(fp = fopen(fname, "w"))) return; + if (!(fp = _lua_fopen(fname, "w"))) return; setlinebuf(fp); } fprintf(fp, "%lx %x TRACE_%d::%s:%u\n",