From 72bdee7fbf2eb3eb3f33da6e9f6da60f8990cc0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Wed, 11 Mar 2026 14:55:09 +0800 Subject: [PATCH] Global (Windows): prefers RtlUnicodeToUTF8N instead of WideCharToMultiByte --- src/common/impl/io_windows.c | 8 +++-- src/common/io.h | 7 +++- src/common/windows/unicode.c | 36 +++++++++++++-------- src/detection/cpu/cpu_windows.c | 4 +-- src/detection/localip/localip_windows.c | 11 +++---- src/detection/netio/netio_windows.c | 7 ++-- src/detection/terminalshell/terminalshell.c | 6 ++-- 7 files changed, 45 insertions(+), 34 deletions(-) diff --git a/src/common/impl/io_windows.c b/src/common/impl/io_windows.c index bdaaea198..90f067471 100644 --- a/src/common/impl/io_windows.c +++ b/src/common/impl/io_windows.c @@ -131,11 +131,13 @@ HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool d HANDLE openat(HANDLE dfd, const char* fileName, bool directory) { wchar_t fileNameW[MAX_PATH]; - int len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, fileName, -1, fileNameW, ARRAY_SIZE(fileNameW)); - if (len == 0) return INVALID_HANDLE_VALUE; + ULONG len; + if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG) sizeof(fileNameW), &len, fileName, (ULONG)strlen(fileName) + 1))) + return INVALID_HANDLE_VALUE; // Implies `fileNameW[len] = L'\0';` and `len` includes the null terminator + len /= sizeof(wchar_t); // convert from bytes to characters - for (int i = 0; i < len - 1; ++i) + for (uint32_t i = 0; i < len - 1; ++i) { if (fileNameW[i] == L'/') fileNameW[i] = L'\\'; diff --git a/src/common/io.h b/src/common/io.h index 340ccff60..d287f2da9 100644 --- a/src/common/io.h +++ b/src/common/io.h @@ -7,6 +7,7 @@ #include #include #include + #include "common/windows/nt.h" typedef HANDLE FFNativeFD; #define FF_INVALID_FD INVALID_HANDLE_VALUE #else @@ -117,7 +118,11 @@ static inline bool ffPathExists(const char* path, FFPathType pathType) { #ifdef _WIN32 - DWORD attr = GetFileAttributesA(path); + wchar_t wPath[MAX_PATH]; + if (!NT_SUCCESS(RtlUTF8ToUnicodeN(wPath, (ULONG) sizeof(wPath), NULL, path, (ULONG)strlen(path) + 1))) + return false; + + DWORD attr = GetFileAttributesW(wPath); if(attr == INVALID_FILE_ATTRIBUTES) return false; diff --git a/src/common/windows/unicode.c b/src/common/windows/unicode.c index 0f78a7281..24aa3d564 100644 --- a/src/common/windows/unicode.c +++ b/src/common/windows/unicode.c @@ -1,6 +1,6 @@ #include "unicode.h" -#include +#include "common/windows/nt.h" void ffStrbufSetNWS(FFstrbuf* result, uint32_t length, const wchar_t* source) { @@ -10,15 +10,19 @@ void ffStrbufSetNWS(FFstrbuf* result, uint32_t length, const wchar_t* source) return; } - int size_needed = WideCharToMultiByte(CP_UTF8, 0, source, (int)length, NULL, 0, NULL, NULL); - if (size_needed <= 0) + ULONG size_needed = 0; + NTSTATUS status = RtlUnicodeToUTF8N(NULL, 0, &size_needed, source, length * sizeof(wchar_t)); + + if (size_needed == 0) { - ffStrbufSetF(result, "WCTMB failed: %u", (unsigned) GetLastError()); + ffStrbufSetF(result, "RtlUnicodeToUTF8N failed: %X", (unsigned) status); return; } - ffStrbufEnsureFixedLengthFree(result, (uint32_t)size_needed); - WideCharToMultiByte(CP_UTF8, 0, source, (int)length, result->chars, size_needed, NULL, NULL); - result->length = (uint32_t)size_needed; + + ffStrbufEnsureFixedLengthFree(result, size_needed); + RtlUnicodeToUTF8N(result->chars, size_needed, &size_needed, source, length * sizeof(wchar_t)); + + result->length = size_needed; result->chars[size_needed] = '\0'; } @@ -27,12 +31,18 @@ void ffStrbufAppendNWS(FFstrbuf* result, uint32_t length, const wchar_t* source) if(!length) return; - int size_needed = WideCharToMultiByte(CP_UTF8, 0, source, (int)length, NULL, 0, NULL, NULL); - if (size_needed <= 0) - return; + ULONG size_needed = 0; + NTSTATUS status = RtlUnicodeToUTF8N(NULL, 0, &size_needed, source, length * sizeof(wchar_t)); - ffStrbufEnsureFree(result, (uint32_t)size_needed); - WideCharToMultiByte(CP_UTF8, 0, source, (int)length, result->chars + result->length, size_needed, NULL, NULL); - result->length += (uint32_t)size_needed; + if (size_needed == 0) + { + ffStrbufAppendF(result, "RtlUnicodeToUTF8N failed: %X", (unsigned) status); + return; + } + + ffStrbufEnsureFree(result, size_needed); + RtlUnicodeToUTF8N(result->chars + result->length, size_needed, &size_needed, source, length * sizeof(wchar_t)); + + result->length += size_needed; result->chars[result->length] = '\0'; } diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index c0555ec21..31f1f5627 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -38,10 +38,8 @@ const char* detectThermalTemp(const FFCPUOptions* options, double* result) if (options->tempSensor.length > 0) { - int written = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, options->tempSensor.chars, (int) options->tempSensor.length, querySpec.Name, (int)(ARRAY_SIZE(querySpec.Name) - 1)); - if (written == 0) + if (!NT_SUCCESS(RtlUTF8ToUnicodeN(querySpec.Name, (ULONG) sizeof(querySpec.Name), NULL, options->tempSensor.chars, (ULONG)options->tempSensor.length + 1))) return "Invalid temp sensor string"; - querySpec.Name[written] = L'\0'; } DWORD dataSize = 0; diff --git a/src/detection/localip/localip_windows.c b/src/detection/localip/localip_windows.c index 35e502bbc..5439472ad 100644 --- a/src/detection/localip/localip_windows.c +++ b/src/detection/localip/localip_windows.c @@ -99,11 +99,10 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) continue; } - char name[128]; - WideCharToMultiByte(CP_UTF8, 0, adapter->FriendlyName, -1, name, ARRAY_SIZE(name), NULL, NULL); - FF_DEBUG("Adapter %u name: '%s'", (unsigned)adapter->IfIndex, name); + FF_STRBUF_AUTO_DESTROY name = ffStrbufCreateWS(adapter->FriendlyName); + FF_DEBUG("Adapter %u name: '%s'", (unsigned)adapter->IfIndex, name.chars); - if (options->namePrefix.length && strncmp(name, options->namePrefix.chars, options->namePrefix.length) != 0) + if (options->namePrefix.length && !ffStrbufStartsWith(&name, &options->namePrefix)) { FF_DEBUG("Skipping adapter %u (name doesn't match prefix '%.*s')", (unsigned)adapter->IfIndex, (int)options->namePrefix.length, options->namePrefix.chars); @@ -121,10 +120,10 @@ const char* ffDetectLocalIps(const FFLocalIpOptions* options, FFlist* results) } processedCount++; - FF_DEBUG("Creating result item for adapter %u ('%s')", (unsigned)adapter->IfIndex, name); + FF_DEBUG("Creating result item for adapter %u ('%s')", (unsigned)adapter->IfIndex, name.chars); FFLocalIpResult* item = (FFLocalIpResult*) ffListAdd(results); - ffStrbufInitS(&item->name, name); + ffStrbufInitMove(&item->name, &name); ffStrbufInit(&item->ipv4); ffStrbufInit(&item->ipv6); ffStrbufInit(&item->mac); diff --git a/src/detection/netio/netio_windows.c b/src/detection/netio/netio_windows.c index ff592a90f..37b4dff33 100644 --- a/src/detection/netio/netio_windows.c +++ b/src/detection/netio/netio_windows.c @@ -46,9 +46,8 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options) if (options->defaultRouteOnly && !isDefaultRoute) continue; - char name[128]; - WideCharToMultiByte(CP_UTF8, 0, adapter->FriendlyName, -1, name, ARRAY_SIZE(name), NULL, NULL); - if (options->namePrefix.length && strncmp(name, options->namePrefix.chars, options->namePrefix.length) != 0) + FF_STRBUF_AUTO_DESTROY name = ffStrbufCreateWS(adapter->FriendlyName); + if (options->namePrefix.length && !ffStrbufStartsWith(&name, &options->namePrefix)) continue; MIB_IF_ROW2 ifRow = { .InterfaceIndex = adapter->IfIndex }; @@ -56,7 +55,7 @@ const char* ffNetIOGetIoCounters(FFlist* result, FFNetIOOptions* options) { FFNetIOResult* counters = (FFNetIOResult*) ffListAdd(result); *counters = (FFNetIOResult) { - .name = ffStrbufCreateS(name), + .name = ffStrbufCreateMove(&name), .txBytes = ifRow.OutOctets, .rxBytes = ifRow.InOctets, .txPackets = (ifRow.OutUcastPkts + ifRow.OutNUcastPkts), diff --git a/src/detection/terminalshell/terminalshell.c b/src/detection/terminalshell/terminalshell.c index 8f15e9e1b..6df1eedd1 100644 --- a/src/detection/terminalshell/terminalshell.c +++ b/src/detection/terminalshell/terminalshell.c @@ -25,10 +25,8 @@ static bool getFileVersion(const FFstrbuf* exePath, const wchar_t* stringName, FFstrbuf* version) { wchar_t exePathW[PATH_MAX + 1]; - int len = MultiByteToWideChar(CP_UTF8, 0, exePath->chars, (int)exePath->length, exePathW, ARRAY_SIZE(exePathW)); - if (len <= 0) return false; - assert(len < (int) ARRAY_SIZE(exePathW)); - exePathW[len] = L'\0'; + if (!NT_SUCCESS(RtlUTF8ToUnicodeN(exePathW, (ULONG) sizeof(exePathW), NULL, exePath->chars, (ULONG)exePath->length + 1))) + return false; return ffGetFileVersion(exePathW, stringName, version); }