Windows, JNI, refactor: prepare moving a function

Prepare moving AsExecutableForCreateProcess into a
shared location where the Bazel client code can
also access it, since this logic is needed there
too.

This change is a simple refactor, it doesn't
affect any logic.

--
PiperOrigin-RevId: 144623656
MOS_MIGRATED_REVID=144623656
diff --git a/src/main/native/windows_processes.cc b/src/main/native/windows_processes.cc
index 503b4b7..35eea00 100644
--- a/src/main/native/windows_processes.cc
+++ b/src/main/native/windows_processes.cc
@@ -22,6 +22,7 @@
 #include <windows.h>
 
 #include <atomic>
+#include <functional>
 #include <memory>
 #include <string>
 #include <type_traits>  // static_assert
@@ -163,13 +164,17 @@
 //
 // 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).
+// (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
@@ -181,25 +186,26 @@
 // `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 AsExecutableForCreateProcess(JNIEnv* env, jstring path,
-                                                std::string* result) {
-  std::string spath = GetJavaUTFString(env, path);
-  if (spath.empty()) {
+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 (spath[0] == '"') {
+  if (path[0] == '"') {
     return std::string("argv[0] should not be quoted");
   }
-  if (spath[0] == '\\' ||  // absolute, but without drive letter
-      spath.find("/") != std::string::npos ||       // has "/"
-      spath.find("\\.\\") != std::string::npos ||   // not normalized
-      spath.find("\\..\\") != std::string::npos ||  // not normalized
+  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
-      (spath.size() >= MAX_PATH && spath.find_first_of('\\') == string::npos) ||
+      (path.size() >= MAX_PATH &&
+       path.find_first_of('\\') == std::string::npos) ||
       // not just a file name, but also not absolute
-      (spath.find_first_of('\\') != string::npos &&
-       !(isalpha(spath[0]) && spath[1] == ':' && spath[2] == '\\'))) {
-    return std::string("argv[0]='" + spath +
+      (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. "
@@ -209,18 +215,18 @@
   // MAX_PATH), or an absolute, normalized, Windows-style path (of any length).
 
   // Fast-track: the path is already short.
-  if (spath.size() < MAX_PATH) {
+  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(spath, result);
+    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"\\\\?\\") + GetJavaWstring(env, path);
+  std::wstring wlong = std::wstring(L"\\\\?\\") + path_as_wstring();
 
   // Experience shows that:
   // - GetShortPathNameW's result has a "\\?\" prefix if and only if the input
@@ -236,14 +242,14 @@
   DWORD wshort_size = ::GetShortPathNameW(wlong.c_str(), NULL, 0);
   if (wshort_size == 0) {
     return windows_util::GetLastErrorString(
-        std::string("GetShortPathName failed (path=") + spath + ")");
+        std::string("GetShortPathName failed (path=") + path + ")");
   }
 
   if (wshort_size >= kMaxShortPath) {
     return windows_util::GetLastErrorString(
         std::string(
             "GetShortPathName would not shorten the path enough (path=") +
-        spath + ")");
+        path + ")");
   }
 
   // Convert the result to UTF-8.
@@ -253,7 +259,7 @@
       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=") + spath + ")";
+    return std::string("wcstombs failed (path=") + path + ")";
   }
   mbs_short[mbs_size - 1] = 0;
 
@@ -261,6 +267,13 @@
   return "";
 }
 
+static std::string AsExecutableForCreateProcess(JNIEnv* env, jstring path,
+                                                std::string* result) {
+  return AsExecutablePathForCreateProcess(
+      GetJavaUTFString(env, path),
+      [env, path]() { return GetJavaWstring(env, path); }, result);
+}
+
 extern "C" JNIEXPORT jlong JNICALL
 Java_com_google_devtools_build_lib_windows_WindowsProcesses_nativeCreateProcess(
     JNIEnv* env, jclass clazz, jstring java_argv0, jstring java_argv_rest,