Skip to content

Try to implement native sorting algorithm using luajit on Windows failed #99

Closed
@dyphire

Description

@dyphire

mpvnet-player/mpv.net#575 (comment) mentioned a method to implement native sorting algorithms on Windows for Lua.
But an error occurred when I applied the following patch to file-browser.lua, causing it to fail.

---
 scripts/file-browser.lua | 58 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 57 insertions(+), 1 deletion(-)

diff --git a/scripts/file-browser.lua b/scripts/file-browser.lua
index c59e7c8..23f2eea 100644
--- a/scripts/file-browser.lua
+++ b/scripts/file-browser.lua
@@ -474,7 +474,55 @@ end
 --sorts the table lexicographically ignoring case and accounting for leading/non-leading zeroes
 --the number format functionality was proposed by github user twophyro, and was presumably taken
 --from here: http://notebook.kulchenko.com/algorithms/alphanumeric-natural-sorting-for-humans-in-lua
-function API.sort(t)
+--this function was taken from https://github.com/mpvnet-player/mpv.net/issues/575#issuecomment-1817413401
+local winapi = {}
+local is_windows = package.config:sub(1,1) == "\\"
+
+if is_windows then
+    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
+
+function API.sort_windows(t)
+    table.sort(t, function(a, b)
+        local a_wide = winapi.utf8_to_wide(a.type:sub(1, 1) .. (a.label or a.name))
+        local b_wide = winapi.utf8_to_wide(b.type:sub(1, 1) .. (b.label or b.name))
+        return winapi.shlwapi.StrCmpLogicalW(a_wide, b_wide) == -1
+    end)
+end
+
+function API.sort_lua(t)
     local function padnum(n, d)
         return #d > 0 and ("%03d%s%.12f"):format(#n, n, tonumber(d) / (10 ^ #d))
             or ("%03d%s"):format(#n, n)
@@ -492,6 +540,14 @@ function API.sort(t)
     return t
 end
 
+function API.sort(t)
+    if is_windows and is_ffi_loaded then
+        API.sort_windows(t)
+    else
+        API.sort_lua(t)
+    end
+end
+
 function API.valid_dir(dir)
     if o.filter_dot_dirs and string.sub(dir, 1, 1) == "." then return false end
     return true
-- 

This is the error log:

[   5.537][v][file_browser] opening directory: G:/ 
[   5.537][v][file_browser] scanning files in G:/ 
[   5.537][d][file_browser] finding parser for G:/ 
[   5.537][d][file_browser] attempting parser: filter 
[   5.537][d][file_browser] finding parser for G:/ 
[   5.537][d][file_browser] attempting parser: sort 
[   5.537][d][file_browser] attempting parser: cmd-dir 
[   5.537][d][cplayer] Run command: subprocess, flags=64, args=[args="cmd,/U,/c,dir,/b,/ad,G:\\", playback_only="no", capture_size="67108864", capture_stdout="yes", capture_stderr="yes", detach="no", env="", stdin_data="", passthrough_stdin="no"]
[   5.558][d][cplayer] Run command: subprocess, flags=64, args=[args="cmd,/U,/c,dir,/b,/a-d,G:\\", playback_only="no", capture_size="67108864", capture_stdout="yes", capture_stderr="yes", detach="no", env="", stdin_data="", passthrough_stdin="no"]
[   5.576][e][file_browser] [windir] 找不到文件
[   5.576][e][file_browser]  
[   5.576][d][file_browser] attempting parser: file 
[   5.576][d][file_browser] no successful parsers found 
[   5.576][w][file_browser] could not read directory G:/ 

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions