1c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes/*
2c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes * Copyright (C) 2015 The Android Open Source Project
3c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes *
4c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
5c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes * you may not use this file except in compliance with the License.
6c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes * You may obtain a copy of the License at
7c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes *
8c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
9c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes *
10c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes * Unless required by applicable law or agreed to in writing, software
11c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
12c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes * See the License for the specific language governing permissions and
14c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes * limitations under the License.
15c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes */
16c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
17c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes#include <windows.h>
18c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
194f71319df011d796a60a43fc1bc68e16fbf7d321Elliott Hughes#include "android-base/utf8.h"
20c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
21c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes#include <fcntl.h>
22c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
23c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes#include <string>
24c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
254f71319df011d796a60a43fc1bc68e16fbf7d321Elliott Hughes#include "android-base/logging.h"
26c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
27c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughesnamespace android {
28c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughesnamespace base {
29c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
30d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low// Helper to set errno based on GetLastError() after WideCharToMultiByte()/MultiByteToWideChar().
31d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Lowstatic void SetErrnoFromLastError() {
32d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low  switch (GetLastError()) {
33d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low    case ERROR_NO_UNICODE_TRANSLATION:
34d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low      errno = EILSEQ;
35d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low      break;
36d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low    default:
37d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low      errno = EINVAL;
38d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low      break;
39d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low  }
40d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low}
41d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low
42c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughesbool WideToUTF8(const wchar_t* utf16, const size_t size, std::string* utf8) {
43c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  utf8->clear();
44c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
45c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  if (size == 0) {
46c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    return true;
47c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  }
48c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
49c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // TODO: Consider using std::wstring_convert once libcxx is supported on
50c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // Windows.
51c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
52c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // Only Vista or later has this flag that causes WideCharToMultiByte() to
53c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // return an error on invalid characters.
54c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  const DWORD flags =
55c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes#if (WINVER >= 0x0600)
56c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    WC_ERR_INVALID_CHARS;
57c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes#else
58c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    0;
59c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes#endif
60c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
61c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  const int chars_required = WideCharToMultiByte(CP_UTF8, flags, utf16, size,
62c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes                                                 NULL, 0, NULL, NULL);
63c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  if (chars_required <= 0) {
64d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low    SetErrnoFromLastError();
65c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    return false;
66c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  }
67c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
68c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // This could potentially throw a std::bad_alloc exception.
69c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  utf8->resize(chars_required);
70c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
71c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  const int result = WideCharToMultiByte(CP_UTF8, flags, utf16, size,
72c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes                                         &(*utf8)[0], chars_required, NULL,
73c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes                                         NULL);
74c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  if (result != chars_required) {
75d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low    SetErrnoFromLastError();
76c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    CHECK_LE(result, chars_required) << "WideCharToMultiByte wrote " << result
77c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes        << " chars to buffer of " << chars_required << " chars";
78c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    utf8->clear();
79c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    return false;
80c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  }
81c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
82c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  return true;
83c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes}
84c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
85c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughesbool WideToUTF8(const wchar_t* utf16, std::string* utf8) {
86c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // Compute string length of NULL-terminated string with wcslen().
87c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  return WideToUTF8(utf16, wcslen(utf16), utf8);
88c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes}
89c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
90c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughesbool WideToUTF8(const std::wstring& utf16, std::string* utf8) {
91c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // Use the stored length of the string which allows embedded NULL characters
92c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // to be converted.
93c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  return WideToUTF8(utf16.c_str(), utf16.length(), utf8);
94c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes}
95c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
96c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes// Internal helper function that takes MultiByteToWideChar() flags.
97d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Lowstatic bool UTF8ToWideWithFlags(const char* utf8, const size_t size, std::wstring* utf16,
98d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low                                const DWORD flags) {
99c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  utf16->clear();
100c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
101c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  if (size == 0) {
102c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    return true;
103c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  }
104c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
105c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // TODO: Consider using std::wstring_convert once libcxx is supported on
106c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // Windows.
107c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  const int chars_required = MultiByteToWideChar(CP_UTF8, flags, utf8, size,
108c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes                                                 NULL, 0);
109c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  if (chars_required <= 0) {
110d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low    SetErrnoFromLastError();
111c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    return false;
112c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  }
113c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
114c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // This could potentially throw a std::bad_alloc exception.
115c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  utf16->resize(chars_required);
116c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
117c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  const int result = MultiByteToWideChar(CP_UTF8, flags, utf8, size,
118c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes                                         &(*utf16)[0], chars_required);
119c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  if (result != chars_required) {
120d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low    SetErrnoFromLastError();
121c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    CHECK_LE(result, chars_required) << "MultiByteToWideChar wrote " << result
122c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes        << " chars to buffer of " << chars_required << " chars";
123c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    utf16->clear();
124c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    return false;
125c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  }
126c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
127c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  return true;
128c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes}
129c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
130c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughesbool UTF8ToWide(const char* utf8, const size_t size, std::wstring* utf16) {
131c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // If strictly interpreting as UTF-8 succeeds, return success.
132d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low  if (UTF8ToWideWithFlags(utf8, size, utf16, MB_ERR_INVALID_CHARS)) {
133c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    return true;
134c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  }
135c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
136d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low  const int saved_errno = errno;
137d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low
138c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // Fallback to non-strict interpretation, allowing invalid characters and
139c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // converting as best as possible, and return false to signify a problem.
140d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low  (void)UTF8ToWideWithFlags(utf8, size, utf16, 0);
141d21dc825bbecad6ce480c5e5c574cc77eadcd779Spencer Low  errno = saved_errno;
142c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  return false;
143c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes}
144c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
145c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughesbool UTF8ToWide(const char* utf8, std::wstring* utf16) {
146c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // Compute string length of NULL-terminated string with strlen().
147c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  return UTF8ToWide(utf8, strlen(utf8), utf16);
148c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes}
149c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
150c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughesbool UTF8ToWide(const std::string& utf8, std::wstring* utf16) {
151c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // Use the stored length of the string which allows embedded NULL characters
152c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  // to be converted.
153c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  return UTF8ToWide(utf8.c_str(), utf8.length(), utf16);
154c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes}
155c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
156c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes// Versions of standard library APIs that support UTF-8 strings.
157c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughesnamespace utf8 {
158c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
159c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughesint open(const char* name, int flags, ...) {
160c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  std::wstring name_utf16;
161c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  if (!UTF8ToWide(name, &name_utf16)) {
162c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    return -1;
163c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  }
164c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
165c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  int mode = 0;
166c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  if ((flags & O_CREAT) != 0) {
167c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    va_list args;
168c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    va_start(args, flags);
169c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    mode = va_arg(args, int);
170c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    va_end(args);
171c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  }
172c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
173c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  return _wopen(name_utf16.c_str(), flags, mode);
174c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes}
175c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
176c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughesint unlink(const char* name) {
177c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  std::wstring name_utf16;
178c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  if (!UTF8ToWide(name, &name_utf16)) {
179c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes    return -1;
180c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  }
181c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
182c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes  return _wunlink(name_utf16.c_str());
183c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes}
184c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes
185c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes}  // namespace utf8
186c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes}  // namespace base
187c1fd492ac5c14a42acfbbd9b47ed178fbf1378d3Elliott Hughes}  // namespace android
188