Skip to content

Commit a31b1c5

Browse files
committed
Centralise code to map between UTF-8 and UTF-16 on Windows.
In various places we need to call the Windows API, and because Swift uses UTF-8 for its string representation, we can’t call the ANSI API functions (because the code page used for the ANSI functions varies depending on the system locale setting). Instead, we need to use the wide character APIs. This means that we need to convert UTF-8 to wide character and vice-versa in various places in the runtime. rdar://103397975
1 parent 28ee477 commit a31b1c5

File tree

4 files changed

+146
-44
lines changed

4 files changed

+146
-44
lines changed

include/swift/Runtime/Win32.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//===--- Win32.h - Win32 utility functions ----------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Utility functions that are specific to the Windows port.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_RUNTIME_WIN32_H
18+
#define SWIFT_RUNTIME_WIN32_H
19+
20+
#ifdef _WIN32
21+
22+
#include "swift/shims/Visibility.h"
23+
24+
#include <wchar.h>
25+
26+
namespace swift {
27+
namespace win32 {
28+
29+
/// Convert a wide string to UTF-8.
30+
///
31+
/// @param str The string to convert.
32+
///
33+
/// @returns The string, converted to UTF-8. The caller is responsible
34+
/// for freeing this string with @c free() when done with it.
35+
///
36+
/// If @a str cannot be converted to UTF-8, a fatal error occurs.
37+
SWIFT_RUNTIME_STDLIB_INTERNAL
38+
char *copyUTF8FromWide(const wchar_t *str);
39+
40+
/// Convert a UTF-8 string to a wide string.
41+
///
42+
/// @param str The string to convert.
43+
///
44+
/// @returns The string, converted to UTF-16. The caller is responsible
45+
/// for freeing this string with @c free() when done with it.
46+
///
47+
/// If @a str cannot be converted to UTF-16, a fatal error occurs.
48+
SWIFT_RUNTIME_STDLIB_INTERNAL
49+
wchar_t *copyWideFromUTF8(const char *str);
50+
51+
}
52+
}
53+
#endif // defined(_WIN32)
54+
55+
#endif // SWIFT_RUNTIME_WIN32_H

stdlib/public/CommandLineSupport/CommandLine.cpp

Lines changed: 2 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <string>
2626

2727
#include "swift/Runtime/Debug.h"
28+
#include "swift/Runtime/Win32.h"
2829

2930
#include "swift/shims/GlobalObjects.h"
3031
#include "swift/shims/RuntimeStubs.h"
@@ -193,48 +194,6 @@ static void swift::enumerateUnsafeArgv(const F& body) {
193194
#elif defined(_WIN32)
194195
#include <stdlib.h>
195196

196-
namespace swift {
197-
/// Convert an argument, represented by a wide string, to UTF-8.
198-
///
199-
/// @param str The string to convert.
200-
///
201-
/// @returns The string, converted to UTF-8. The caller is responsible for
202-
/// freeing this string when done with it.
203-
///
204-
/// If @a str cannot be converted to UTF-8, a fatal error occurs.
205-
static char *copyUTF8FromWide(wchar_t *str) {
206-
char *result = nullptr;
207-
208-
int resultLength = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, str,
209-
-1, nullptr, 0, nullptr, nullptr);
210-
if (resultLength <= 0) {
211-
swift::fatalError(0,
212-
"Fatal error: Could not get length of commandline "
213-
"argument '%ls': %lu\n",
214-
str, GetLastError());
215-
}
216-
217-
result = reinterpret_cast<char *>(malloc(resultLength));
218-
if (!result) {
219-
swift::fatalError(0,
220-
"Fatal error: Could not allocate space for commandline "
221-
"argument '%ls': %d\n",
222-
str, errno);
223-
}
224-
225-
resultLength = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, str, -1,
226-
result, resultLength, nullptr, nullptr);
227-
if (resultLength <= 0) {
228-
swift::fatalError(0,
229-
"Fatal error: Conversion to UTF-8 failed for "
230-
"commandline argument '%ls': %lu\n",
231-
str, GetLastError());
232-
}
233-
234-
return result;
235-
}
236-
}
237-
238197
static char **swift::getUnsafeArgvArgc(int *outArgLen) {
239198
return nullptr;
240199
}
@@ -244,7 +203,7 @@ static void swift::enumerateUnsafeArgv(const F& body) {
244203
int argc = 0;
245204
if (LPWSTR *wargv = CommandLineToArgvW(GetCommandLineW(), &argc)) {
246205
std::for_each(wargv, wargv + argc, [=] (wchar_t *warg) {
247-
auto arg = copyUTF8FromWide(warg);
206+
auto arg = swift::win32::copyUTF8FromWide(warg);
248207
body(argc, arg);
249208
free(arg);
250209
});

stdlib/public/runtime/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ set(swift_runtime_sources
7070
SwiftTLSContext.cpp
7171
ThreadingError.cpp
7272
AccessibleFunction.cpp
73-
RuntimeAttribute.cpp)
73+
RuntimeAttribute.cpp
74+
Win32.cpp)
7475

7576
# Acknowledge that the following sources are known.
7677
set(LLVM_OPTIONAL_SOURCES

stdlib/public/runtime/Win32.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//===--- Win32.cpp - Win32 utility functions --------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Utility functions that are specific to the Windows port.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "swift/Runtime/Debug.h"
18+
#include "swift/Runtime/Win32.h"
19+
20+
#ifdef _WIN32
21+
22+
#include <windows.h>
23+
24+
char *
25+
swift::win32::copyUTF8FromWide(const wchar_t *str) {
26+
char *result = nullptr;
27+
int len = ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
28+
str, -1,
29+
nullptr, 0,
30+
nullptr, nullptr);
31+
if (len <= 0) {
32+
swift::fatalError(0, "failed to convert string '%ls' "
33+
"from wide to UTF-8: %lx\n",
34+
str, ::GetLastError());
35+
}
36+
37+
result = reinterpret_cast<char *>(std::malloc(len));
38+
if (!result) {
39+
swift::fatalError(0, "unable to allocate space to convert '%ls': %d\n",
40+
str, errno);
41+
}
42+
43+
len = ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
44+
str, -1,
45+
result, len,
46+
nullptr, nullptr);
47+
48+
if (len <= 0) {
49+
swift::fatalError(0, "failed to convert string '%ls' "
50+
"from wide to UTF-8: %lx\n",
51+
str, ::GetLastError());
52+
}
53+
54+
return result;
55+
}
56+
57+
wchar_t *
58+
swift::win32::copyWideFromUTF8(const char *str) {
59+
wchar_t *result = nullptr;
60+
int len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
61+
str, -1,
62+
nullptr, 0);
63+
if (len <= 0) {
64+
swift::fatalError(0, "failed to convert string '%s' "
65+
"from UTF-8 to wide: %lx\n",
66+
str, ::GetLastError());
67+
}
68+
69+
result = reinterpret_cast<wchar_t *>(std::malloc(len * sizeof(wchar_t)));
70+
if (!result) {
71+
swift::fatalError(0, "unable to allocate space to convert '%s': %d\n",
72+
str, errno);
73+
}
74+
75+
len = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
76+
str, -1,
77+
result, len);
78+
if (len <= 0) {
79+
swift::fatalError(0, "failed to convert string '%s' "
80+
"from UTF-8 to wide: %lx\n",
81+
str, ::GetLastError());
82+
}
83+
84+
return result;
85+
}
86+
87+
#endif // defined(_WIN32)

0 commit comments

Comments
 (0)