diff --git a/conf.lua b/conf.lua index 56ae44b8..6dc094b3 100644 --- a/conf.lua +++ b/conf.lua @@ -8,6 +8,7 @@ local love = require("love") if love._os == "Android" and jit then jit.on() end +if love._os == "Windows" then require("io_open_wide") end local errhand = love.errorhandler or love.errhand function love.errorhandler(msg) diff --git a/io_open_wide.lua b/io_open_wide.lua new file mode 100644 index 00000000..ff2f6300 --- /dev/null +++ b/io_open_wide.lua @@ -0,0 +1,75 @@ +-- io.open patch to allow UTF-8 filenames in Windows +-- Copyright (c) 2020 Miku AuahDark +-- You can use portion of this code or as a whole without my permission. + +local ffi = require("ffi") + +if ffi.os ~= "Windows" then + -- Not Windows + return +end + +-- Safety measures from redefining +do + local function index(t, k) + return t[k] + end + + if pcall(index, ffi.C, "GetACP") then + -- Has been patched! + return + end +end + +ffi.cdef[[ +uint32_t __stdcall GetACP(); +]] + +if ffi.C.GetACP() == 65001 then + -- "Use Unicode UTF-8 for worldwide language support" is ticked. + -- Don't bother patching it. + return +end + +ffi.cdef[[ +int32_t __stdcall MultiByteToWideChar( + uint32_t CodePage, + uint32_t dwFlags, + const char *lpMultiByteStr, + int32_t cbMultiByte, + wchar_t *lpWideCharStr, + int32_t cchWideChar +); +void *_wfreopen(wchar_t *path, wchar_t *mode, void *file); +]] + +local MB_ERR_INVALID_CHARS = 0x8 + +local function toWideChar(ch) + local size = ffi.C.MultiByteToWideChar(65001, MB_ERR_INVALID_CHARS, ch, #ch, nil, 0) + if size == 0 then + error("invalid character sequence") + end + + local buf = ffi.new("wchar_t[?]", size + 1) + if ffi.C.MultiByteToWideChar(65001, MB_ERR_INVALID_CHARS, ch, #ch, buf, size) == 0 then + error("char conversion error") + end + + return buf +end + +local open = io.open + +function io.open(path, mode) + local pathw = toWideChar(path) + local modew = toWideChar(mode) + + local file = assert(open("nul", "rb")) + if ffi.C._wfreopen(pathw, modew, file) == nil then + local msg, errno = select(2, file:close()) + return nil, path..": "..msg, errno + end + + return file +end diff --git a/util.lua b/util.lua index 17604d2f..8ca95b57 100644 --- a/util.lua +++ b/util.lua @@ -5,6 +5,7 @@ local love = require("love") local Luaoop = require("libs.Luaoop") require("libs.ls2x") +require("io_open_wide") local color = require("color") local hasLVEP = not(not(package.preload.lvep)) local lvep