From 846537fdd86426dd98f84744824ced343933218d Mon Sep 17 00:00:00 2001 From: yamachu Date: Wed, 22 Jan 2025 20:21:46 +0900 Subject: [PATCH 1/2] test: added test that uses multibyte for path and resolves modules --- .../experimental.json" | 3 +++ .../test-module-create-require-multibyte.js | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 "test/fixtures/copy/utf/\346\226\260\345\273\272\346\226\207\344\273\266\345\244\271/experimental.json" create mode 100644 test/parallel/test-module-create-require-multibyte.js diff --git "a/test/fixtures/copy/utf/\346\226\260\345\273\272\346\226\207\344\273\266\345\244\271/experimental.json" "b/test/fixtures/copy/utf/\346\226\260\345\273\272\346\226\207\344\273\266\345\244\271/experimental.json" new file mode 100644 index 00000000000000..12611d2385a5a5 --- /dev/null +++ "b/test/fixtures/copy/utf/\346\226\260\345\273\272\346\226\207\344\273\266\345\244\271/experimental.json" @@ -0,0 +1,3 @@ +{ + "ofLife": 42 +} diff --git a/test/parallel/test-module-create-require-multibyte.js b/test/parallel/test-module-create-require-multibyte.js new file mode 100644 index 00000000000000..f9c4b6345dc59e --- /dev/null +++ b/test/parallel/test-module-create-require-multibyte.js @@ -0,0 +1,24 @@ +'use strict'; + +require('../common'); +const fixtures = require('../common/fixtures'); +const assert = require('assert'); + +// This test ensures that the module can be resolved +// even if the path given to createRequire contains multibyte characters. + +const { createRequire } = require('module'); + +{ + const u = fixtures.fileURL('あ.js'); + + const reqToo = createRequire(u); + assert.deepStrictEqual(reqToo('./experimental'), { ofLife: 42 }); +} + +{ + const u = fixtures.fileURL('copy/utf/新建文件夹/index.js'); + + const reqToo = createRequire(u); + assert.deepStrictEqual(reqToo('./experimental'), { ofLife: 42 }); +} From 76bd5d1810204408e67f4853bcd082b2cb89d44b Mon Sep 17 00:00:00 2001 From: yamachu Date: Wed, 22 Jan 2025 20:24:38 +0900 Subject: [PATCH 2/2] src: fix to generate path from wchar_t via wstring. take a similar approach to node_file and allow the creation of paths code point must be specified to convert from wchar_t to utf8. --- src/node_file.cc | 15 +-------------- src/node_modules.cc | 24 ++++++++++++++++++++---- src/util-inl.h | 16 ++++++++++++++++ 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/node_file.cc b/src/node_file.cc index 984bc55ee9b941..8e29bb39887625 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -3146,21 +3146,8 @@ static void GetFormatOfExtensionlessFile( } #ifdef _WIN32 -std::wstring ConvertToWideString(const std::string& str) { - int size_needed = MultiByteToWideChar( - CP_UTF8, 0, &str[0], static_cast(str.size()), nullptr, 0); - std::wstring wstrTo(size_needed, 0); - MultiByteToWideChar(CP_UTF8, - 0, - &str[0], - static_cast(str.size()), - &wstrTo[0], - size_needed); - return wstrTo; -} - #define BufferValueToPath(str) \ - std::filesystem::path(ConvertToWideString(str.ToString())) + std::filesystem::path(ConvertToWideString(str.ToString(), CP_UTF8)) std::string ConvertWideToUTF8(const std::wstring& wstr) { if (wstr.empty()) return std::string(); diff --git a/src/node_modules.cc b/src/node_modules.cc index 4b522a91323c9f..210a01d24e1176 100644 --- a/src/node_modules.cc +++ b/src/node_modules.cc @@ -344,8 +344,16 @@ void BindingData::GetNearestParentPackageJSON( path_value_str.push_back(kPathSeparator); } - auto package_json = - TraverseParent(realm, std::filesystem::path(path_value_str)); + std::filesystem::path path; + +#ifdef _WIN32 + std::wstring wide_path = ConvertToWideString(path_value_str, GetACP()); + path = std::filesystem::path(wide_path); +#else + path = std::filesystem::path(path_value_str); +#endif + + auto package_json = TraverseParent(realm, path); if (package_json != nullptr) { args.GetReturnValue().Set(package_json->Serialize(realm)); @@ -370,8 +378,16 @@ void BindingData::GetNearestParentPackageJSONType( path_value_str.push_back(kPathSeparator); } - auto package_json = - TraverseParent(realm, std::filesystem::path(path_value_str)); + std::filesystem::path path; + +#ifdef _WIN32 + std::wstring wide_path = ConvertToWideString(path_value_str, GetACP()); + path = std::filesystem::path(wide_path); +#else + path = std::filesystem::path(path_value_str); +#endif + + auto package_json = TraverseParent(realm, path); if (package_json == nullptr) { return; diff --git a/src/util-inl.h b/src/util-inl.h index a35e15eeed6576..b5ae5950b62767 100644 --- a/src/util-inl.h +++ b/src/util-inl.h @@ -562,6 +562,22 @@ bool IsWindowsBatchFile(const char* filename) { #endif // _WIN32 } +#ifdef _WIN32 +inline std::wstring ConvertToWideString(const std::string& str, + UINT code_page) { + int size_needed = MultiByteToWideChar( + code_page, 0, &str[0], static_cast(str.size()), nullptr, 0); + std::wstring wstrTo(size_needed, 0); + MultiByteToWideChar(code_page, + 0, + &str[0], + static_cast(str.size()), + &wstrTo[0], + size_needed); + return wstrTo; +} +#endif // _WIN32 + } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS