util.h: Add Win32 Unicode string conversion functions.

These will be used more extensively in future CLs
and make for cleaner code.

Fuchsia-Topic: advanced-ipc
Original-Change-Id: Iba0ff0f6a534df373ba9720c45ecce905391c904
Change-Id: I49ac43b384e993aa214ef07234dbbfc9060c0f81
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/github.com/ninja-build/ninja/+/975453
Reviewed-by: David Fang <fangism@google.com>
Reviewed-by: Tyler Mandry <tmandry@google.com>
Commit-Queue: David Turner <digit@google.com>
diff --git a/src/ipc_handle-win32.cc b/src/ipc_handle-win32.cc
index 0da7956..2922eb1 100644
--- a/src/ipc_handle-win32.cc
+++ b/src/ipc_handle-win32.cc
@@ -35,16 +35,6 @@
   return Win32ErrorMessage(prefix, GetLastError());
 }
 
-std::wstring Utf8ToWideChar(StringPiece str) {
-  std::wstring result;
-  int count = MultiByteToWideChar(CP_UTF8, 0, str.str_, str.len_, nullptr, 0);
-  if (count > 0) {
-    result.resize(count);
-    MultiByteToWideChar(CP_UTF8, 0, str.str_, str.len_, &result[0], count);
-  }
-  return result;
-}
-
 std::wstring CurrentUserName() {
   wchar_t user[UNLEN + 1];
   DWORD count = UNLEN + 1;
@@ -59,7 +49,7 @@
   std::wstring result = L"\\\\.\\pipe\\basic_ipc-";
   result += CurrentUserName();
   result += L'-';
-  result += Utf8ToWideChar(service_name);
+  result += ConvertToUnicodeString(service_name.str_, service_name.len_);
   return result;
 }
 
diff --git a/src/util.cc b/src/util.cc
index 644413e..f551810 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -186,6 +186,53 @@
   Fatal("Could not format string!");
 }
 
+#ifdef _WIN32
+std::wstring ConvertToUnicodeString(const char* str, size_t size) {
+  std::wstring result;
+  if (size > 0) {
+    int int_size = static_cast<int>(size);
+    if (int_size != size)
+      Fatal("Input UTF-8 string is far too long!");
+
+    int wide_size = MultiByteToWideChar(CP_UTF8, 0, str, int_size, nullptr, 0);
+    if (wide_size <= 0)
+      Win32Fatal("MultiByteToWideChar");
+
+    result.resize(static_cast<size_t>(wide_size));
+    MultiByteToWideChar(CP_UTF8, 0, str, int_size, &result[0], wide_size);
+  }
+  return result;
+}
+
+std::wstring ConvertToUnicodeString(const std::string& str) {
+  return ConvertToUnicodeString(str.c_str(), str.size());
+}
+
+std::string ConvertFromUnicodeString(const wchar_t* str, size_t size) {
+  std::string result;
+  if (size > 0) {
+    int int_size = static_cast<int>(size);
+    if (int_size != size)
+      Fatal("Input Unicode string is far too long!");
+
+    int utf8_size =
+        WideCharToMultiByte(CP_UTF8, 0, str, int_size, NULL, 0, NULL, NULL);
+    if (utf8_size <= 0)
+      Win32Fatal("WideCharToMultiByte");
+
+    result.resize(static_cast<size_t>(utf8_size));
+    WideCharToMultiByte(CP_UTF8, 0, str, int_size, &result[0], utf8_size, NULL,
+                        NULL);
+  }
+  return result;
+}
+
+std::string ConvertFromUnicodeString(const std::wstring& str) {
+  return ConvertFromUnicodeString(str.c_str(), str.size());
+}
+
+#endif  // _WIN32
+
 void CanonicalizePath(string* path, uint64_t* slash_bits) {
   size_t len = path->size();
   char* str = 0;
@@ -674,7 +721,7 @@
     filename.resize(static_cast<size_t>(ret));
     break;
   }
-  return ToUtf8Path(filename);
+  return ConvertFromUnicodeString(filename);
 #elif defined(__APPLE__)
   uint32_t size = 0;
   _NSGetExecutablePath(nullptr, &size);
diff --git a/src/util.h b/src/util.h
index d9c6cf8..c8c5fdb 100644
--- a/src/util.h
+++ b/src/util.h
@@ -149,6 +149,15 @@
 NORETURN void Win32Fatal(const char* function, const char* hint = NULL);
 NORETURN void Win32Fatal(const char* function, unsigned long error,
                          const char* hint = NULL);
+
+/// Convert Win32 unicode string into UTF8 string.
+std::string ConvertFromUnicodeString(const wchar_t* str, size_t size);
+std::string ConvertFromUnicodeString(const std::wstring& str);
+
+/// Convert UTF8 string to a Win32  unicode string.
+std::wstring ConvertToUnicodeString(const char* str, size_t size);
+std::wstring ConvertToUnicodeString(const std::string& str);
+
 #endif  // !_WIN32
 
 NORETURN void ErrnoFatal(const char* function, const char* hint = NULL);
diff --git a/src/util_test.cc b/src/util_test.cc
index 2e39e2f..0e21123 100644
--- a/src/util_test.cc
+++ b/src/util_test.cc
@@ -641,3 +641,14 @@
 #endif
   ASSERT_EQ(expected, IsRunningUnderWine());
 }
+
+#ifdef _WIN32
+TEST(ConvertToUnicodeString, Test) {
+  EXPECT_EQ(std::wstring(L"Bébé"), ConvertToUnicodeString("Bébé"));
+}
+
+TEST(ConvertFromUnicodeString, Test) {
+  EXPECT_EQ(std::string("Bébé"), ConvertFromUnicodeString(L"Bébé"));
+}
+
+#endif  // _WIN32