From b3f322485bd89008aca34bcde001a40828e05303 Mon Sep 17 00:00:00 2001 From: dyphire Date: Wed, 29 Nov 2023 19:24:38 +0800 Subject: [PATCH] feat: use the sorting function `StrCmpLogicalW` provided by win32 API --- src/uosc/lib/utils.lua | 66 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/src/uosc/lib/utils.lua b/src/uosc/lib/utils.lua index d001ed1a..681a7f3e 100644 --- a/src/uosc/lib/utils.lua +++ b/src/uosc/lib/utils.lua @@ -5,7 +5,62 @@ --- In place sorting of filenames ---@param filenames string[] -function sort_filenames(filenames) + +----- winapi start ----- +-- in windows system, we can use the sorting function provided by the win32 API +-- see https://learn.microsoft.com/en-us/windows/win32/api/shlwapi/nf-shlwapi-strcmplogicalw +-- this function was taken from https://github.com/mpvnet-player/mpv.net/issues/575#issuecomment-1817413401 +local winapi = {} + +if state.platform == 'windows' then + -- is_ffi_loaded is false usually means the mpv builds without luajit + local is_ffi_loaded, ffi = pcall(require, 'ffi') + + if is_ffi_loaded then + winapi = { + ffi = ffi, + C = ffi.C, + CP_UTF8 = 65001, + shlwapi = ffi.load('shlwapi'), + } + + -- ffi code from https://github.com/po5/thumbfast, Mozilla Public License Version 2.0 + ffi.cdef[[ + int __stdcall MultiByteToWideChar(unsigned int CodePage, unsigned long dwFlags, const char *lpMultiByteStr, + int cbMultiByte, wchar_t *lpWideCharStr, int cchWideChar); + int __stdcall StrCmpLogicalW(wchar_t *psz1, wchar_t *psz2); + ]] + + winapi.utf8_to_wide = function(utf8_str) + if utf8_str then + local utf16_len = winapi.C.MultiByteToWideChar(winapi.CP_UTF8, 0, utf8_str, -1, nil, 0) + + if utf16_len > 0 then + local utf16_str = winapi.ffi.new('wchar_t[?]', utf16_len) + + if winapi.C.MultiByteToWideChar(winapi.CP_UTF8, 0, utf8_str, -1, utf16_str, utf16_len) > 0 then + return utf16_str + end + end + end + + return '' + end + end +end +----- winapi end ----- + +function sort_filenames_windows(filenames) + table.sort(filenames, function(a, b) + local a_wide = winapi.utf8_to_wide(a) + local b_wide = winapi.utf8_to_wide(b) + return winapi.shlwapi.StrCmpLogicalW(a_wide, b_wide) == -1 + end) + + return filenames +end + +function sort_filenames_lua(filenames) -- alphanum sorting for humans in Lua -- http://notebook.kulchenko.com/algorithms/alphanumeric-natural-sorting-for-humans-in-lua local function padnum(n, d) @@ -24,6 +79,15 @@ function sort_filenames(filenames) return filenames end +function sort_filenames(filenames) + local is_ffi_loaded = pcall(require, 'ffi') + if state.platform == 'windows' and is_ffi_loaded then + sort_filenames_windows(filenames) + else + sort_filenames_lua(filenames) + end +end + -- Creates in-between frames to animate value from `from` to `to` numbers. ---@param from number ---@param to number|fun():number