Win32 原生目录选择器(koffi)在读中文路径时会错误截断,丢失后半段字符 #563
pht88888888
started this conversation in
Ideas
Replies: 1 comment
|
Fix candidate (tests included, cherry-pick ready): #580 — branch |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
复现步骤
在 Windows 上,通过 DSH GUI 的「添加工作区 / 选择文件夹」用系统原生对话框选一个含中文的路径,例如 C:\Users\XIAOPAN\Desktop\安卓开发。
确认返回失败:workspace-invalid-path: cannot create a workspace at "C:\Users\XIAOPAN\Desktop\安卓": ENOENT。
报错路径比所选路径少了「开发」两个字。
期望行为:选择器返回完整路径 C:\Users\XIAOPAN\Desktop\安卓开发。
实际行为:返回被截断的路径 C:\Users\XIAOPAN\Desktop\安卓,该路径不存在,导致工作区创建失败。
根因 readUtf16 把 COM 返回的 PWSTR(UTF-16LE)从内存读成 JS 字符串,按 2 字节一个码元扫描 NUL 终止符:
js
复制
function readUtf16(koffi: Koffi, address: unknown): string {
const bytes = Buffer.from(koffi.view(address, 32768))
let end = 0
while (end + 1 < bytes.length && bytes[end] !== 0) end += 2
return bytes.toString('utf16le', 0, end)
}
终止条件 bytes[end] !== 0 只检查了码元的低字节,而非「低字节和高字节都为 0」。对于 UTF-16LE 编码的 BMP 字符,若其低字节恰好为 0x00(即形如 U+XX00 的字符,例如「开」= U+5F00 → 字节 00 5F),循环会把它误判为 NUL 终止符,提前停止。
以 安卓开发 为例(UTF-16LE):
安 卓 低字节非零 → 正常读完
开 = 00 5F → 低字节 0x00 → 误判为结束 → 截断于此处
结果只得到 安卓。这正是报错的 ...Desktop\安卓。
影响范围
不仅「开」字:任何路径中含「UTF-16LE 低字节为 0」的字符(U+XX00 这类码元)都会从该字符处截断。
本质是 CJK(乃至所有非 ASCII)路径的通用缺陷:路径越靠后踩中一个低字节为 0 的字符,后面全部丢失。
不影响纯 ASCII 路径(如 C:\Users\XIAOPAN\Desktop\projects),因为 ASCII 字符低字节非零。
建议修复 终止判断应识别「2 字节全为 0」才是真正的 UTF-16 NUL:
js
复制
while (end + 1 < bytes.length && !(bytes[end] === 0 && bytes[end + 1] === 0)) end += 2
同样地,readUtf16 的 koffi.view(address, 32768) 还写死了 32 KB 上限,超长路径会被静默截断,建议改为按指针动态长度或加大上限并校验边界。
All reactions