Skip to content

Commit

Permalink
src: use wide string for findPackageJson onWindows
Browse files Browse the repository at this point in the history
Fix error when searching for package.json with non-ASCII characters in
paths

Fixes: #55773
  • Loading branch information
islandryu committed Nov 15, 2024
1 parent b02cd41 commit d0e4106
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 58 deletions.
49 changes: 0 additions & 49 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3125,55 +3125,6 @@ static void GetFormatOfExtensionlessFile(
return args.GetReturnValue().Set(EXTENSIONLESS_FORMAT_JAVASCRIPT);
}

#ifdef _WIN32
std::wstring ConvertToWideString(const std::string& str) {
int size_needed = MultiByteToWideChar(
CP_UTF8, 0, &str[0], static_cast<int>(str.size()), nullptr, 0);
std::wstring wstrTo(size_needed, 0);
MultiByteToWideChar(CP_UTF8,
0,
&str[0],
static_cast<int>(str.size()),
&wstrTo[0],
size_needed);
return wstrTo;
}

#define BufferValueToPath(str) \
std::filesystem::path(ConvertToWideString(str.ToString()))

std::string ConvertWideToUTF8(const std::wstring& wstr) {
if (wstr.empty()) return std::string();

int size_needed = WideCharToMultiByte(CP_UTF8,
0,
&wstr[0],
static_cast<int>(wstr.size()),
nullptr,
0,
nullptr,
nullptr);
std::string strTo(size_needed, 0);
WideCharToMultiByte(CP_UTF8,
0,
&wstr[0],
static_cast<int>(wstr.size()),
&strTo[0],
size_needed,
nullptr,
nullptr);
return strTo;
}

#define PathToString(path) ConvertWideToUTF8(path.wstring());

#else // _WIN32

#define BufferValueToPath(str) std::filesystem::path(str.ToStringView());
#define PathToString(path) path.native();

#endif // _WIN32

static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();
Expand Down
15 changes: 6 additions & 9 deletions src/node_modules.cc
Original file line number Diff line number Diff line change
Expand Up @@ -337,14 +337,13 @@ void BindingData::GetNearestParentPackageJSON(
bool slashCheck = path_value.ToStringView().ends_with(kPathSeparator);

ToNamespacedPath(realm->env(), &path_value);

std::string path_value_str = path_value.ToString();
std::filesystem::path path = BufferValueToPath(path_value);
if (slashCheck) {
path_value_str.push_back(kPathSeparator);
path += kPathSeparator;
}

auto package_json =
TraverseParent(realm, std::filesystem::path(path_value_str));
TraverseParent(realm, path);

if (package_json != nullptr) {
args.GetReturnValue().Set(package_json->Serialize(realm));
Expand All @@ -363,14 +362,12 @@ void BindingData::GetNearestParentPackageJSONType(
bool slashCheck = path_value.ToStringView().ends_with(kPathSeparator);

ToNamespacedPath(realm->env(), &path_value);

std::string path_value_str = path_value.ToString();
std::filesystem::path path = BufferValueToPath(path_value);
if (slashCheck) {
path_value_str.push_back(kPathSeparator);
path += kPathSeparator;
}

auto package_json =
TraverseParent(realm, std::filesystem::path(path_value_str));
auto package_json = TraverseParent(realm, path);

if (package_json == nullptr) {
return;
Expand Down
39 changes: 39 additions & 0 deletions src/util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -885,4 +885,43 @@ v8::Maybe<int> GetValidFileMode(Environment* env,
return v8::Just(mode);
}

#ifdef _WIN32
std::wstring ConvertToWideString(const std::string& str) {
int size_needed = MultiByteToWideChar(
CP_UTF8, 0, &str[0], static_cast<int>(str.size()), nullptr, 0);
std::wstring wstrTo(size_needed, 0);
MultiByteToWideChar(CP_UTF8,
0,
&str[0],
static_cast<int>(str.size()),
&wstrTo[0],
size_needed);
return wstrTo;
}

std::string ConvertWideToUTF8(const std::wstring& wstr) {
if (wstr.empty()) return std::string();

int size_needed = WideCharToMultiByte(CP_UTF8,
0,
&wstr[0],
static_cast<int>(wstr.size()),
nullptr,
0,
nullptr,
nullptr);
std::string strTo(size_needed, 0);
WideCharToMultiByte(CP_UTF8,
0,
&wstr[0],
static_cast<int>(wstr.size()),
&strTo[0],
size_needed,
nullptr,
nullptr);
return strTo;
}

#endif // _WIN32

} // namespace node
22 changes: 22 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@
#include <unordered_map>
#include <utility>
#include <vector>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif

#ifdef __GNUC__
#define MUST_USE_RESULT __attribute__((warn_unused_result))
Expand Down Expand Up @@ -1013,6 +1018,23 @@ v8::Maybe<int> GetValidFileMode(Environment* env,
// case insensitive.
inline bool IsWindowsBatchFile(const char* filename);

#ifdef _WIN32
std::wstring ConvertToWideString(const std::string& str);

#define BufferValueToPath(str) \
std::filesystem::path(ConvertToWideString(str.ToString()))

std::string ConvertWideToUTF8(const std::wstring& wstr);

#define PathToString(path) ConvertWideToUTF8(path.wstring());

#else // _WIN32

#define BufferValueToPath(str) std::filesystem::path(str.ToStringView());
#define PathToString(path) path.native();

#endif // _WIN32

} // namespace node

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
Expand Down
20 changes: 20 additions & 0 deletions test/parallel/test-non-ascii.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';

const fs = require('node:fs');
const common = require('../common');
const tmpdir = require('../common/tmpdir');
const { describe, it } = require('node:test');
const assert = require('node:assert');

describe('None ASCII', () => {
it('should be able to run on a directory with non-ASCII characters', async () => {
fs.mkdirSync(tmpdir.resolve('12月'), { recursive: true });
fs.writeFileSync(
tmpdir.resolve('12月/index.js'),
"console.log('12月');",
);
await common.spawnPromisified(process.execPath, [tmpdir.resolve('12月/index.js')]).then(common.mustCall((result) => {
assert.strictEqual(result.stdout, '12月' + '\n');
}));
});
});

0 comments on commit d0e4106

Please sign in to comment.