1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/globals.h"
6#if defined(HOST_OS_WINDOWS)
7
8#include <errno.h> // NOLINT
9#include <time.h> // NOLINT
10
11#include "bin/utils.h"
12#include "bin/utils_win.h"
13#include "platform/assert.h"
14#include "platform/syslog.h"
15
16namespace dart {
17namespace bin {
18
19void FormatMessageIntoBuffer(DWORD code, wchar_t* buffer, int buffer_length) {
20 DWORD message_size = FormatMessageW(
21 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, code,
22 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buffer, buffer_length, NULL);
23 if (message_size == 0) {
24 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
25 Syslog::PrintErr("FormatMessage failed for error code %d (error %d)\n",
26 code, GetLastError());
27 }
28 _snwprintf(buffer, buffer_length, L"OS Error %d", code);
29 }
30 // Ensure string termination.
31 buffer[buffer_length - 1] = 0;
32}
33
34OSError::OSError() : sub_system_(kSystem), code_(0), message_(NULL) {
35 Reload();
36}
37
38void OSError::Reload() {
39 SetCodeAndMessage(kSystem, GetLastError());
40}
41
42void OSError::SetCodeAndMessage(SubSystem sub_system, int code) {
43 set_sub_system(sub_system);
44 set_code(code);
45
46 static const int kMaxMessageLength = 256;
47 wchar_t message[kMaxMessageLength];
48 FormatMessageIntoBuffer(code_, message, kMaxMessageLength);
49 char* utf8 = StringUtilsWin::WideToUtf8(message);
50 SetMessage(utf8);
51}
52
53char* StringUtils::ConsoleStringToUtf8(char* str,
54 intptr_t len,
55 intptr_t* result_len) {
56 int wide_len = MultiByteToWideChar(CP_ACP, 0, str, len, NULL, 0);
57 wchar_t* wide;
58 wide =
59 reinterpret_cast<wchar_t*>(Dart_ScopeAllocate(wide_len * sizeof(*wide)));
60 MultiByteToWideChar(CP_ACP, 0, str, len, wide, wide_len);
61 char* utf8 = StringUtilsWin::WideToUtf8(wide, wide_len, result_len);
62 return utf8;
63}
64
65char* StringUtils::Utf8ToConsoleString(char* utf8,
66 intptr_t len,
67 intptr_t* result_len) {
68 intptr_t wide_len;
69 wchar_t* wide = StringUtilsWin::Utf8ToWide(utf8, len, &wide_len);
70 int system_len =
71 WideCharToMultiByte(CP_ACP, 0, wide, wide_len, NULL, 0, NULL, NULL);
72 char* ansi;
73 ansi =
74 reinterpret_cast<char*>(Dart_ScopeAllocate(system_len * sizeof(*ansi)));
75 if (ansi == NULL) {
76 return NULL;
77 }
78 WideCharToMultiByte(CP_ACP, 0, wide, wide_len, ansi, system_len, NULL, NULL);
79 if (result_len != NULL) {
80 *result_len = system_len;
81 }
82 return ansi;
83}
84
85char* StringUtilsWin::WideToUtf8(wchar_t* wide,
86 intptr_t len,
87 intptr_t* result_len) {
88 // If len is -1 then WideCharToMultiByte will include the terminating
89 // NUL byte in the length.
90 int utf8_len =
91 WideCharToMultiByte(CP_UTF8, 0, wide, len, NULL, 0, NULL, NULL);
92 char* utf8;
93 utf8 = reinterpret_cast<char*>(Dart_ScopeAllocate(utf8_len * sizeof(*utf8)));
94 WideCharToMultiByte(CP_UTF8, 0, wide, len, utf8, utf8_len, NULL, NULL);
95 if (result_len != NULL) {
96 *result_len = utf8_len;
97 }
98 return utf8;
99}
100
101wchar_t* StringUtilsWin::Utf8ToWide(char* utf8,
102 intptr_t len,
103 intptr_t* result_len) {
104 // If len is -1 then MultiByteToWideChar will include the terminating
105 // NUL byte in the length.
106 int wide_len = MultiByteToWideChar(CP_UTF8, 0, utf8, len, NULL, 0);
107 wchar_t* wide;
108 wide =
109 reinterpret_cast<wchar_t*>(Dart_ScopeAllocate(wide_len * sizeof(*wide)));
110 MultiByteToWideChar(CP_UTF8, 0, utf8, len, wide, wide_len);
111 if (result_len != NULL) {
112 *result_len = wide_len;
113 }
114 return wide;
115}
116
117const char* StringUtils::Utf8ToConsoleString(const char* utf8,
118 intptr_t len,
119 intptr_t* result_len) {
120 return const_cast<const char*>(StringUtils::Utf8ToConsoleString(
121 const_cast<char*>(utf8), len, result_len));
122}
123
124const char* StringUtils::ConsoleStringToUtf8(const char* str,
125 intptr_t len,
126 intptr_t* result_len) {
127 return const_cast<const char*>(StringUtils::ConsoleStringToUtf8(
128 const_cast<char*>(str), len, result_len));
129}
130
131const char* StringUtilsWin::WideToUtf8(const wchar_t* wide,
132 intptr_t len,
133 intptr_t* result_len) {
134 return const_cast<const char*>(
135 StringUtilsWin::WideToUtf8(const_cast<wchar_t*>(wide), len, result_len));
136}
137
138const wchar_t* StringUtilsWin::Utf8ToWide(const char* utf8,
139 intptr_t len,
140 intptr_t* result_len) {
141 return const_cast<const wchar_t*>(
142 StringUtilsWin::Utf8ToWide(const_cast<char*>(utf8), len, result_len));
143}
144
145bool ShellUtils::GetUtf8Argv(int argc, char** argv) {
146 wchar_t* command_line = GetCommandLineW();
147 int unicode_argc;
148 wchar_t** unicode_argv = CommandLineToArgvW(command_line, &unicode_argc);
149 if (unicode_argv == NULL) {
150 return false;
151 }
152 // The argc passed to main should have the same argc as we get here.
153 ASSERT(argc == unicode_argc);
154 if (argc < unicode_argc) {
155 unicode_argc = argc;
156 }
157 for (int i = 0; i < unicode_argc; i++) {
158 wchar_t* arg = unicode_argv[i];
159 int arg_len = WideCharToMultiByte(CP_UTF8, 0, arg, -1, NULL, 0, NULL, NULL);
160 char* utf8_arg = reinterpret_cast<char*>(malloc(arg_len));
161 WideCharToMultiByte(CP_UTF8, 0, arg, -1, utf8_arg, arg_len, NULL, NULL);
162 argv[i] = utf8_arg;
163 }
164 LocalFree(unicode_argv);
165 return true;
166}
167
168// Although win32 uses 64-bit integers for representing timestamps,
169// these are packed into a FILETIME structure. The FILETIME
170// structure is just a struct representing a 64-bit integer. The
171// TimeStamp union allows access to both a FILETIME and an integer
172// representation of the timestamp. The Windows timestamp is in
173// 100-nanosecond intervals since January 1, 1601.
174union TimeStamp {
175 FILETIME ft_;
176 int64_t t_;
177};
178
179static int64_t GetCurrentTimeMicros() {
180 static const int64_t kTimeEpoc = 116444736000000000LL;
181 static const int64_t kTimeScaler = 10; // 100 ns to us.
182
183 TimeStamp time;
184 GetSystemTimeAsFileTime(&time.ft_);
185 return (time.t_ - kTimeEpoc) / kTimeScaler;
186}
187
188static int64_t qpc_ticks_per_second = 0;
189
190void TimerUtils::InitOnce() {
191 LARGE_INTEGER ticks_per_sec;
192 if (!QueryPerformanceFrequency(&ticks_per_sec)) {
193 qpc_ticks_per_second = 0;
194 } else {
195 qpc_ticks_per_second = static_cast<int64_t>(ticks_per_sec.QuadPart);
196 }
197}
198
199int64_t TimerUtils::GetCurrentMonotonicMillis() {
200 return GetCurrentMonotonicMicros() / 1000;
201}
202
203int64_t TimerUtils::GetCurrentMonotonicMicros() {
204 if (qpc_ticks_per_second == 0) {
205 // QueryPerformanceCounter not supported, fallback.
206 return GetCurrentTimeMicros();
207 }
208 // Grab performance counter value.
209 LARGE_INTEGER now;
210 QueryPerformanceCounter(&now);
211 int64_t qpc_value = static_cast<int64_t>(now.QuadPart);
212 // Convert to microseconds.
213 int64_t seconds = qpc_value / qpc_ticks_per_second;
214 int64_t leftover_ticks = qpc_value - (seconds * qpc_ticks_per_second);
215 int64_t result = seconds * kMicrosecondsPerSecond;
216 result += ((leftover_ticks * kMicrosecondsPerSecond) / qpc_ticks_per_second);
217 return result;
218}
219
220void TimerUtils::Sleep(int64_t millis) {
221 ::Sleep(millis);
222}
223
224} // namespace bin
225} // namespace dart
226
227#endif // defined(HOST_OS_WINDOWS)
228