Windows, JNI, refactor: move a method

This change moves AsExecutablePathForCreateProcess
to windows_util. This is a follow-up to
unknown commit.

--
PiperOrigin-RevId: 144623760
MOS_MIGRATED_REVID=144623760
diff --git a/src/main/native/windows_processes.cc b/src/main/native/windows_processes.cc
index 35eea00..97f22b4 100644
--- a/src/main/native/windows_processes.cc
+++ b/src/main/native/windows_processes.cc
@@ -156,120 +156,9 @@
 
 static jlong PtrAsJlong(void* p) { return reinterpret_cast<jlong>(p); }
 
-static void QuotePath(const std::string& path, std::string* result) {
-  *result = std::string("\"") + path + "\"";
-}
-
-// Computes a path suitable as the executable part in CreateProcessA's cmdline.
-//
-// The null-terminated executable path for CreateProcessA has to fit into
-// MAX_PATH, therefore the limit for the executable's path is MAX_PATH - 1
-// (not including null terminator). This method attempts to convert the input
-// `path` to a short format to fit it into the MAX_PATH - 1 limit.
-//
-// `path` must be either an absolute, normalized, Windows-style path with drive
-// letter (e.g. "c:\foo\bar.exe", but no "\foo\bar.exe"), or must be just a file
-// name (e.g. "cmd.exe") that's shorter than MAX_PATH (without null-terminator).
-// In both cases, `path` must be unquoted.
-//
-// `path_as_wstring` must be a function that retrieves `path` as (or converts it
-// to) a wstring, without performing any transformations on the path.
-//
-// If this function succeeds, it returns an empty string (indicating no error),
-// and sets `result` to the resulting path, which is always quoted, and is
-// always at most MAX_PATH + 1 long (MAX_PATH - 1 without null terminator, plus
-// two quotes). If there's any error, this function returns the error message.
-//
-// If `path` is at most MAX_PATH - 1 long (not including null terminator), the
-// result will be that (plus quotes).
-// Otherwise this method attempts to compute an 8dot3 style short name for
-// `path`, and if that succeeds and the result is at most MAX_PATH - 1 long (not
-// including null terminator), then that will be the result (plus quotes).
-// Otherwise this function fails and returns an error message.
-static std::string AsExecutablePathForCreateProcess(
-    const std::string& path, std::function<std::wstring()> path_as_wstring,
-    std::string* result) {
-  if (path.empty()) {
-    return std::string("argv[0] should not be empty");
-  }
-  if (path[0] == '"') {
-    return std::string("argv[0] should not be quoted");
-  }
-  if (path[0] == '\\' ||  // absolute, but without drive letter
-      path.find("/") != std::string::npos ||       // has "/"
-      path.find("\\.\\") != std::string::npos ||   // not normalized
-      path.find("\\..\\") != std::string::npos ||  // not normalized
-      // at least MAX_PATH long, but just a file name
-      (path.size() >= MAX_PATH &&
-       path.find_first_of('\\') == std::string::npos) ||
-      // not just a file name, but also not absolute
-      (path.find_first_of('\\') != std::string::npos &&
-       !(isalpha(path[0]) && path[1] == ':' && path[2] == '\\'))) {
-    return std::string("argv[0]='" + path +
-                       "'; should have been either an absolute, "
-                       "normalized, Windows-style path with drive letter (e.g. "
-                       "'c:\\foo\\bar.exe'), or just a file name (e.g. "
-                       "'cmd.exe') shorter than MAX_PATH.");
-  }
-  // At this point we know the path is either just a file name (shorter than
-  // MAX_PATH), or an absolute, normalized, Windows-style path (of any length).
-
-  // Fast-track: the path is already short.
-  if (path.size() < MAX_PATH) {
-    // Quote the path in case it's something like "c:\foo\app name.exe".
-    // Do this unconditionally, there's no harm in quoting. Quotes are not
-    // allowed inside paths so we don't need to escape quotes.
-    QuotePath(path, result);
-    return "";
-  }
-  // At this point we know that the path is at least MAX_PATH long and that it's
-  // absolute, normalized, and Windows-style.
-
-  // Retrieve string as UTF-16 path, add "\\?\" prefix.
-  std::wstring wlong = std::wstring(L"\\\\?\\") + path_as_wstring();
-
-  // Experience shows that:
-  // - GetShortPathNameW's result has a "\\?\" prefix if and only if the input
-  //   did too (though this behavior is not documented on MSDN)
-  // - CreateProcess{A,W} only accept an executable of MAX_PATH - 1 length
-  // Therefore for our purposes the acceptable shortened length is
-  // MAX_PATH + 4 (null-terminated). That is, MAX_PATH - 1 for the shortened
-  // path, plus a potential "\\?\" prefix that's only there if `wlong` also had
-  // it and which we'll omit from `result`, plus a null terminator.
-  static const size_t kMaxShortPath = MAX_PATH + 4;
-
-  WCHAR wshort[kMaxShortPath];
-  DWORD wshort_size = ::GetShortPathNameW(wlong.c_str(), NULL, 0);
-  if (wshort_size == 0) {
-    return windows_util::GetLastErrorString(
-        std::string("GetShortPathName failed (path=") + path + ")");
-  }
-
-  if (wshort_size >= kMaxShortPath) {
-    return windows_util::GetLastErrorString(
-        std::string(
-            "GetShortPathName would not shorten the path enough (path=") +
-        path + ")");
-  }
-
-  // Convert the result to UTF-8.
-  char mbs_short[MAX_PATH];
-  size_t mbs_size = wcstombs(
-      mbs_short,
-      wshort + 4,  // we know it has a "\\?\" prefix, because `wlong` also did
-      MAX_PATH);
-  if (mbs_size < 0 || mbs_size >= MAX_PATH) {
-    return std::string("wcstombs failed (path=") + path + ")";
-  }
-  mbs_short[mbs_size - 1] = 0;
-
-  QuotePath(mbs_short, result);
-  return "";
-}
-
 static std::string AsExecutableForCreateProcess(JNIEnv* env, jstring path,
                                                 std::string* result) {
-  return AsExecutablePathForCreateProcess(
+  return windows_util::AsExecutablePathForCreateProcess(
       GetJavaUTFString(env, path),
       [env, path]() { return GetJavaWstring(env, path); }, result);
 }
diff --git a/src/main/native/windows_util.cc b/src/main/native/windows_util.cc
index 53ca6ae..051290d 100644
--- a/src/main/native/windows_util.cc
+++ b/src/main/native/windows_util.cc
@@ -16,6 +16,7 @@
 #include <stdlib.h>
 #include <windows.h>
 
+#include <functional>
 #include <memory>
 #include <string>
 
@@ -23,8 +24,10 @@
 
 namespace windows_util {
 
+using std::function;
 using std::string;
 using std::unique_ptr;
+using std::wstring;
 
 string GetLastErrorString(const string& cause) {
   DWORD last_error = GetLastError();
@@ -57,4 +60,87 @@
   return cause + ": " + result;
 }
 
+static void QuotePath(const string& path, string* result) {
+  *result = string("\"") + path + "\"";
+}
+
+string AsExecutablePathForCreateProcess(const string& path,
+                                        function<wstring()> path_as_wstring,
+                                        string* result) {
+  if (path.empty()) {
+    return string("argv[0] should not be empty");
+  }
+  if (path[0] == '"') {
+    return string("argv[0] should not be quoted");
+  }
+  if (path[0] == '\\' ||                 // absolute, but without drive letter
+      path.find("/") != string::npos ||  // has "/"
+      path.find("\\.\\") != string::npos ||   // not normalized
+      path.find("\\..\\") != string::npos ||  // not normalized
+      // at least MAX_PATH long, but just a file name
+      (path.size() >= MAX_PATH && path.find_first_of('\\') == string::npos) ||
+      // not just a file name, but also not absolute
+      (path.find_first_of('\\') != string::npos &&
+       !(isalpha(path[0]) && path[1] == ':' && path[2] == '\\'))) {
+    return string("argv[0]='" + path +
+                  "'; should have been either an absolute, "
+                  "normalized, Windows-style path with drive letter (e.g. "
+                  "'c:\\foo\\bar.exe'), or just a file name (e.g. "
+                  "'cmd.exe') shorter than MAX_PATH.");
+  }
+  // At this point we know the path is either just a file name (shorter than
+  // MAX_PATH), or an absolute, normalized, Windows-style path (of any length).
+
+  // Fast-track: the path is already short.
+  if (path.size() < MAX_PATH) {
+    // Quote the path in case it's something like "c:\foo\app name.exe".
+    // Do this unconditionally, there's no harm in quoting. Quotes are not
+    // allowed inside paths so we don't need to escape quotes.
+    QuotePath(path, result);
+    return "";
+  }
+  // At this point we know that the path is at least MAX_PATH long and that it's
+  // absolute, normalized, and Windows-style.
+
+  // Retrieve string as UTF-16 path, add "\\?\" prefix.
+  wstring wlong = wstring(L"\\\\?\\") + path_as_wstring();
+
+  // Experience shows that:
+  // - GetShortPathNameW's result has a "\\?\" prefix if and only if the input
+  //   did too (though this behavior is not documented on MSDN)
+  // - CreateProcess{A,W} only accept an executable of MAX_PATH - 1 length
+  // Therefore for our purposes the acceptable shortened length is
+  // MAX_PATH + 4 (null-terminated). That is, MAX_PATH - 1 for the shortened
+  // path, plus a potential "\\?\" prefix that's only there if `wlong` also had
+  // it and which we'll omit from `result`, plus a null terminator.
+  static const size_t kMaxShortPath = MAX_PATH + 4;
+
+  WCHAR wshort[kMaxShortPath];
+  DWORD wshort_size = ::GetShortPathNameW(wlong.c_str(), NULL, 0);
+  if (wshort_size == 0) {
+    return windows_util::GetLastErrorString(
+        string("GetShortPathName failed (path=") + path + ")");
+  }
+
+  if (wshort_size >= kMaxShortPath) {
+    return windows_util::GetLastErrorString(
+        string("GetShortPathName would not shorten the path enough (path=") +
+        path + ")");
+  }
+
+  // Convert the result to UTF-8.
+  char mbs_short[MAX_PATH];
+  size_t mbs_size = wcstombs(
+      mbs_short,
+      wshort + 4,  // we know it has a "\\?\" prefix, because `wlong` also did
+      MAX_PATH);
+  if (mbs_size < 0 || mbs_size >= MAX_PATH) {
+    return string("wcstombs failed (path=") + path + ")";
+  }
+  mbs_short[mbs_size - 1] = 0;
+
+  QuotePath(mbs_short, result);
+  return "";
+}
+
 }  // namespace windows_util
diff --git a/src/main/native/windows_util.h b/src/main/native/windows_util.h
index 8af07bb..127bb97 100644
--- a/src/main/native/windows_util.h
+++ b/src/main/native/windows_util.h
@@ -19,16 +19,49 @@
 
 #include <jni.h>
 
+#include <functional>
 #include <memory>
 #include <string>
 
 namespace windows_util {
 
+using std::function;
 using std::string;
 using std::unique_ptr;
+using std::wstring;
 
 string GetLastErrorString(const string& cause);
 
+// Computes a path suitable as the executable part in CreateProcessA's cmdline.
+//
+// The null-terminated executable path for CreateProcessA has to fit into
+// MAX_PATH, therefore the limit for the executable's path is MAX_PATH - 1
+// (not including null terminator). This method attempts to convert the input
+// `path` to a short format to fit it into the MAX_PATH - 1 limit.
+//
+// `path` must be either an absolute, normalized, Windows-style path with drive
+// letter (e.g. "c:\foo\bar.exe", but no "\foo\bar.exe"), or must be just a file
+// name (e.g. "cmd.exe") that's shorter than MAX_PATH (without null-terminator).
+// In both cases, `path` must be unquoted.
+//
+// `path_as_wstring` must be a function that retrieves `path` as (or converts it
+// to) a wstring, without performing any transformations on the path.
+//
+// If this function succeeds, it returns an empty string (indicating no error),
+// and sets `result` to the resulting path, which is always quoted, and is
+// always at most MAX_PATH + 1 long (MAX_PATH - 1 without null terminator, plus
+// two quotes). If there's any error, this function returns the error message.
+//
+// If `path` is at most MAX_PATH - 1 long (not including null terminator), the
+// result will be that (plus quotes).
+// Otherwise this method attempts to compute an 8dot3 style short name for
+// `path`, and if that succeeds and the result is at most MAX_PATH - 1 long (not
+// including null terminator), then that will be the result (plus quotes).
+// Otherwise this function fails and returns an error message.
+string AsExecutablePathForCreateProcess(const string& path,
+                                        function<wstring()> path_as_wstring,
+                                        string* result);
+
 }  // namespace windows_util
 
 #endif  // BAZEL_SRC_MAIN_NATIVE_WINDOWS_UTIL_H__