SDK: Extract find_java static library.

Change-Id: Ic8b2130a327d73c044c0931509385aed19f78a9e
diff --git a/sdkmanager/win_android/Android.mk b/sdkmanager/win_android/Android.mk
index a50b3c7..2f111a0 100644
--- a/sdkmanager/win_android/Android.mk
+++ b/sdkmanager/win_android/Android.mk
@@ -1,13 +1,27 @@
 # Copyright 2011 The Android Open Source Project
 #
 # Android.mk for sdkmanager/win_android
-#
-# This provides "win_android.exe", a replacement for "android.bat" for Windows only.
 
 
-#----- The current C++ sdklauncher -----
-
 LOCAL_PATH := $(call my-dir)
+
+# find_java static library for host
+# ========================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libfindjava
+LOCAL_SRC_FILES := find_java.cpp utils.cpp
+
+LOCAL_CFLAGS += -Wall -Wno-unused-parameter
+LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE -DSH_HISTORY -DUSE_MINGW
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+# "win_android.exe", a host replacement for "android.bat". For the Windows SDK only.
+# ========================================================
+
 include $(CLEAR_VARS)
 
 ifeq ($(HOST_OS),windows)
@@ -15,9 +29,11 @@
 LOCAL_SRC_FILES := \
 	win_android.cpp
 
+LOCAL_MODULE := win_android
+LOCAL_STATIC_LIBRARIES := libfindjava
+
 LOCAL_CFLAGS += -Wall -Wno-unused-parameter
 LOCAL_CFLAGS += -D_XOPEN_SOURCE -D_GNU_SOURCE -DSH_HISTORY -DUSE_MINGW
-LOCAL_MODULE := win_android
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/sdkmanager/win_android/find_java.cpp b/sdkmanager/win_android/find_java.cpp
new file mode 100755
index 0000000..a3b7af8
--- /dev/null
+++ b/sdkmanager/win_android/find_java.cpp
@@ -0,0 +1,63 @@
+/*

+ * Copyright (C) 2011 The Android Open Source Project

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+#ifdef _WIN32

+

+#include "find_java.h"

+

+#define _CRT_SECURE_NO_WARNINGS 1

+

+extern bool gDebug;

+

+// Search java.exe in the path

+bool findJavaInEnvPath(CPath *outJavaPath) {

+    SetLastError(0);

+    const char* envPath = getenv("PATH");

+    if (!envPath) return false;

+

+    CArray<CString> *paths = CString(envPath).split(';');

+    for(int i = 0; i < paths->size(); i++) {

+        CPath p((*paths)[i].cstr());

+        p.addPath("java.exe");

+        if (p.fileExists()) {

+            // Make sure we can actually run "java -version".

+            CString cmd;

+            cmd.setf("\"%s\" -version", p.cstr());

+            int code = execWait(cmd.cstr());

+            if (code == 0) {

+                if (gDebug) msgBox("Java found via env path: %s", p.cstr());

+                outJavaPath->set(p.cstr());

+                delete paths;

+                return true;

+            }

+        }

+    }

+

+    delete paths;

+    return false;

+}

+

+bool findJavaInRegistry(CPath *outJavaPath) {

+    // TODO

+    return false;

+}

+

+bool findJavaInProgramFiles(CPath *outJavaPath) {

+    // TODO

+    return false;

+}

+

+#endif /* _WIN32 */

diff --git a/sdkmanager/win_android/find_java.h b/sdkmanager/win_android/find_java.h
new file mode 100755
index 0000000..41e5720
--- /dev/null
+++ b/sdkmanager/win_android/find_java.h
@@ -0,0 +1,29 @@
+/*

+ * Copyright (C) 2011 The Android Open Source Project

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+#ifndef _H_FIND_JAVA

+#define _H_FIND_JAVA

+

+#ifdef _WIN32

+

+#include "utils.h"

+

+bool findJavaInEnvPath(CPath *outJavaPath);

+bool findJavaInRegistry(CPath *outJavaPath);

+bool findJavaInProgramFiles(CPath *outJavaPath);

+

+#endif /* _WIN32 */

+#endif /* _H_FIND_JAVA */

diff --git a/sdkmanager/win_android/utils.cpp b/sdkmanager/win_android/utils.cpp
new file mode 100755
index 0000000..6da1893
--- /dev/null
+++ b/sdkmanager/win_android/utils.cpp
@@ -0,0 +1,192 @@
+/*

+ * Copyright (C) 2011 The Android Open Source Project

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+#ifdef _WIN32

+

+#include "utils.h"

+

+#define _CRT_SECURE_NO_WARNINGS 1

+

+bool gDebug = false;

+

+// Displays a message in an ok+info dialog box.

+void msgBox(const char* text, ...) {

+    CString formatted;

+    va_list ap;

+    va_start(ap, text);

+    formatted.setv(text, ap);

+    va_end(ap);

+

+    MessageBoxA(NULL, formatted.cstr(), "Android SDK Manager", MB_OK | MB_ICONINFORMATION);

+}

+

+// Displays GetLastError prefixed with a description in an error dialog box

+void displayLastError(const char *description, ...) {

+    CString formatted;

+    va_list ap;

+    va_start(ap, description);

+    formatted.setv(description, ap);

+    va_end(ap);

+

+    CString error;

+    error.setLastWin32Error();

+    formatted.add("\r\n");

+    formatted.add(error.cstr());

+    MessageBox(NULL, formatted.cstr(), "Android SDK Manager - Error", MB_OK | MB_ICONERROR);

+}

+

+// Executes the command line. Does not wait for the program to finish.

+// The return code is from CreateProcess (0 means failure), not the running app.

+int execNoWait(const char *app, const char *params, const char *workDir) {

+    STARTUPINFO           startup;

+    PROCESS_INFORMATION   pinfo;

+

+    ZeroMemory(&pinfo, sizeof(pinfo));

+

+    ZeroMemory(&startup, sizeof(startup));

+    startup.cb          = sizeof(startup);

+    startup.dwFlags     = STARTF_USESHOWWINDOW;

+    startup.wShowWindow = SW_HIDE|SW_MINIMIZE;

+

+    int ret = CreateProcessA(

+            (LPSTR) app,                                /* program path */

+            (LPSTR) params,                             /* command-line */

+            NULL,                  /* process handle is not inheritable */

+            NULL,                   /* thread handle is not inheritable */

+            TRUE,                          /* yes, inherit some handles */

+            CREATE_NO_WINDOW,                /* we don't want a console */

+            NULL,                     /* use parent's environment block */

+            workDir,                 /* use parent's starting directory */

+            &startup,                 /* startup info, i.e. std handles */

+            &pinfo);

+

+    if (ret) {

+        CloseHandle(pinfo.hProcess);

+        CloseHandle(pinfo.hThread);

+    }

+

+    return ret;

+}

+

+// Executes command, waits for completion and returns exit code.

+// As indicated in MSDN for CreateProcess, callers should double-quote the program name

+// e.g. cmd="\"c:\program files\myapp.exe\" arg1 arg2";

+int execWait(const char *cmd) {

+    STARTUPINFO           startup;

+    PROCESS_INFORMATION   pinfo;

+

+    ZeroMemory(&pinfo, sizeof(pinfo));

+

+    ZeroMemory(&startup, sizeof(startup));

+    startup.cb          = sizeof(startup);

+    startup.dwFlags     = STARTF_USESHOWWINDOW;

+    startup.wShowWindow = SW_HIDE|SW_MINIMIZE;

+

+    int ret = CreateProcessA(

+            NULL,                                       /* program path */

+            (LPSTR) cmd,                                /* command-line */

+            NULL,                  /* process handle is not inheritable */

+            NULL,                   /* thread handle is not inheritable */

+            TRUE,                          /* yes, inherit some handles */

+            CREATE_NO_WINDOW,                /* we don't want a console */

+            NULL,                     /* use parent's environment block */

+            NULL,                    /* use parent's starting directory */

+            &startup,                 /* startup info, i.e. std handles */

+            &pinfo);

+

+    int result = -1;

+    if (ret) {

+        WaitForSingleObject(pinfo.hProcess, INFINITE);

+

+        DWORD exitCode;

+        if (GetExitCodeProcess(pinfo.hProcess, &exitCode)) {

+            // this should not return STILL_ACTIVE (259)

+            result = exitCode;

+        }

+        CloseHandle(pinfo.hProcess);

+        CloseHandle(pinfo.hThread);

+    }

+

+    return result;

+}

+

+bool getModuleDir(CPath *outDir) {

+    CHAR programDir[MAX_PATH];

+    int ret = GetModuleFileName(NULL, programDir, sizeof(programDir));

+    if (ret != 0) {

+        // Remove the last segment to keep only the directory.

+        int pos = ret - 1;

+        while (pos > 0 && programDir[pos] != '\\') {

+            --pos;

+        }

+        outDir->set(programDir, pos);

+        return true;

+    }

+    return false;

+}

+

+// Disables the FS redirection done by WOW64.

+// Because this runs as a 32-bit app, Windows automagically remaps some

+// folder under the hood (e.g. "Programs Files(x86)" is mapped as "Program Files").

+// This prevents the app from correctly searching for java.exe in these folders.

+// The registry is also remapped.

+PVOID disableWow64FsRedirection() {

+

+    // The call we want to make is the following:

+    //    PVOID oldWow64Value;

+    //    Wow64DisableWow64FsRedirection(&oldWow64Value);

+    // However that method may not exist (e.g. on non-64 systems) so

+    // we must not call it directly.

+

+    PVOID oldWow64Value = 0;

+

+    HMODULE hmod = LoadLibrary("kernel32.dll");

+    if (hmod != NULL) {

+        FARPROC proc = GetProcAddress(hmod, "Wow64DisableWow64FsRedirection");

+        if (proc != NULL) {

+            typedef BOOL (WINAPI *disableWow64FuncType)(PVOID *);

+            disableWow64FuncType funcPtr = (disableWow64FuncType)proc;

+            funcPtr(&oldWow64Value);

+        }

+

+        FreeLibrary(hmod);

+    }

+

+    return oldWow64Value;

+}

+

+// Reverts the redirection disabled in disableWow64FsRedirection.

+void revertWow64FsRedirection(PVOID oldWow64Value) {

+

+    // The call we want to make is the following:

+    //    Wow64RevertWow64FsRedirection(oldWow64Value);

+    // However that method may not exist (e.g. on non-64 systems) so

+    // we must not call it directly.

+

+    HMODULE hmod = LoadLibrary("kernel32.dll");

+    if (hmod != NULL) {

+        FARPROC proc = GetProcAddress(hmod, "Wow64RevertWow64FsRedirection");

+        if (proc != NULL) {

+            typedef BOOL (WINAPI *revertWow64FuncType)(PVOID);

+            revertWow64FuncType funcPtr = (revertWow64FuncType)proc;

+            funcPtr(oldWow64Value);

+        }

+

+        FreeLibrary(hmod);

+    }

+}

+

+#endif /* _WIN32 */

diff --git a/sdkmanager/win_android/utils.h b/sdkmanager/win_android/utils.h
new file mode 100755
index 0000000..60d4da8
--- /dev/null
+++ b/sdkmanager/win_android/utils.h
@@ -0,0 +1,321 @@
+/*

+ * Copyright (C) 2011 The Android Open Source Project

+ *

+ * Licensed under the Apache License, Version 2.0 (the "License");

+ * you may not use this file except in compliance with the License.

+ * You may obtain a copy of the License at

+ *

+ *      http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing, software

+ * distributed under the License is distributed on an "AS IS" BASIS,

+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

+ * See the License for the specific language governing permissions and

+ * limitations under the License.

+ */

+

+#ifndef _H_UTILS

+#define _H_UTILS

+

+#ifdef _WIN32

+

+#include <direct.h>

+#include <stdio.h>

+#include <stdarg.h>

+#include <string.h>

+#include <windows.h>

+

+// VS vs MINGW specific includes

+#ifdef USE_VS_CRT

+    #include <crtdbg.h>     // for _ASSERT

+#else

+    #define _ASSERT(x)      // undef

+#endif

+

+extern bool gDebug;

+

+// An array that knows its own size. Not dynamically resizable.

+template <class T> class CArray {

+    T* mPtr;

+    int mSize;

+public:

+    explicit CArray(int size) {

+        mSize = size;

+        mPtr = new T[size];

+    }

+

+    ~CArray() {

+        if (mPtr != NULL) {

+            delete[] mPtr;

+            mPtr = NULL;

+        }

+        mSize = 0;

+    }

+

+    T& operator[](int i) {

+        _ASSERT(i >= 0 && i < mSize);

+        return mPtr[i];

+    }

+

+    int size() const {

+        return mSize;

+    }

+};

+

+// A simple string class wrapper.

+class CString {

+protected:

+    char *mStr;

+public:

+    CString()                              { mStr = NULL; }

+    CString(const CString &str)            { mStr = str.mStr == NULL ? NULL : _strdup(str.mStr); }

+    explicit CString(const char *str)      { mStr = NULL; set(str); }

+    CString(const char *start, int length) { mStr = NULL; set(start, length); }

+

+    CString& set(const char *str) {

+        _free();

+        if (str != NULL) {

+            mStr = _strdup(str);

+        }

+        return *this;

+    }

+

+    CString& set(const char *start, int length) {

+        _free();

+        if (start != NULL) {

+            mStr = (char *)malloc(length + 1);

+            strncpy(mStr, start, length);

+            mStr[length] = 0;

+        }

+        return *this;

+    }

+

+    CString& setv(const char *str, va_list ap) {

+        _free();

+        // _vscprintf(str, ap) is only available with the MSVCRT, not MinGW.

+        // Instead we'll iterate till we have enough space to generate the string.

+        int len = strlen(str) + 1024;

+        mStr = (char *)malloc(len);

+        strcpy(mStr, str); // provide a default in case vsnprintf totally fails

+        for (int guard = 0; guard < 10; guard++) {

+            int ret = vsnprintf(mStr, len, str, ap);

+            if (ret == -1) {

+                // Some implementations don't give the proper size needed

+                // so double the space and try again.

+                len *= 2;

+            } else if (ret >= len) {

+                len = ret + 1;

+            } else {

+                // There was enough space to write.

+                break;

+            }

+            mStr = (char *)realloc((void *)mStr, len);

+            strcpy(mStr, str); // provide a default in case vsnprintf totally fails

+        }

+        return *this;

+    }

+

+    CString& setf(const char *str, ...) {

+        _free();

+        va_list ap;

+        va_start(ap, str);

+        setv(str, ap);

+        va_end(ap);

+        return *this;

+    }

+

+    virtual ~CString() { _free(); }

+

+    // Returns the C string owned by this CString. It will be

+    // invalid as soon as this CString is deleted or out of scope.

+    const char * cstr() const {

+        return mStr;

+    }

+

+    bool isEmpty() const {

+        return mStr == NULL || *mStr == 0;

+    }

+

+    int length() const {

+        return mStr == NULL ? 0 : strlen(mStr);

+    }

+

+    CString& add(const char *s) {

+        if (mStr == NULL) {

+            set(s);

+        } else {

+            mStr = (char *)realloc((void *)mStr, strlen(mStr) + strlen(s) + 1);

+            strcat(mStr, s);

+        }

+        return *this;

+    }

+

+    CArray<CString> * split(char sep) const {

+        if (mStr == NULL) {

+            return new CArray<CString>(0);

+        }

+        const char *last = NULL;

+        int n = 0;

+        for (const char *s = mStr; *s; s++) {

+            if (*s == sep && s != mStr && (last == NULL || s > last+1)) {

+                n++;

+                last = s;

+            }

+        }

+

+        CArray<CString> *result = new CArray<CString>(n);

+        last = NULL;

+        n = 0;

+        for (const char *s = mStr; *s; s++) {

+            if (*s == sep) {

+                if (s != mStr && (last == NULL || s > last+1)) {

+                    const char *start = last ? last : mStr;

+                    (*result)[n++].set(start, s-start);

+                }

+                last = s+1;

+            }

+        }

+

+        return result;

+    }

+

+    CString& setLastWin32Error() {

+        DWORD err = GetLastError();

+        LPSTR errStr;

+        if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | /* dwFlags */

+                          FORMAT_MESSAGE_FROM_SYSTEM,

+                          NULL,                             /* lpSource */

+                          err,                              /* dwMessageId */

+                          0,                                /* dwLanguageId */

+                          (LPSTR)&errStr,                   /* lpBuffer */

+                          0,                                /* nSize */

+                          NULL) != 0) {                     /* va_list args */

+            set(errStr);

+            LocalFree(errStr);

+        }

+        return *this;

+    }

+

+private:

+    void _free() {

+        if (mStr != NULL) {

+            free((void *)mStr);

+            mStr = NULL;

+        }

+    }

+

+};

+

+// A simple path class wrapper.

+class CPath : public CString {

+public:

+    CPath()                              : CString()    { }

+    CPath(const CPath &str)              : CString(str) { }

+    explicit CPath(const char *str)      : CString(str) { }

+    CPath(const char *start, int length) : CString(start, length) { }

+

+    // Appends a path segment, adding a \ as necessary.

+    CPath& addPath(const CString &s) {

+        return addPath(s.cstr());

+    }

+

+    // Appends a path segment, adding a \ as necessary.

+    CPath& addPath(const char *s) {

+        _ASSERT(s != NULL);

+        if (s != NULL && s[0] != 0) {

+            int n = length();

+            if (n > 0 && s[0] != '\\' && mStr[n-1] != '\\') add("\\");

+            add(s);

+        }

+        return *this;

+    }

+

+    // Returns true if file exist and is not a directory.

+    // There's no garantee we have rights to access it.

+    bool fileExists() const {

+        if (mStr == NULL) return false;

+        DWORD attribs = GetFileAttributesA(mStr);

+        return attribs != INVALID_FILE_ATTRIBUTES &&

+             !(attribs & FILE_ATTRIBUTE_DIRECTORY);

+    }

+

+    // Returns true if file exist and is a directory.

+    // There's no garantee we have rights to access it.

+    bool dirExists() const {

+        if (mStr == NULL) return false;

+        DWORD attribs = GetFileAttributesA(mStr);

+        return attribs != INVALID_FILE_ATTRIBUTES &&

+              (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;

+    }

+

+    // Returns a copy of the directory portion of the path, if any

+    CPath dirName() const {

+        CPath result;

+        if (mStr != NULL) {

+            char *pos = strrchr(mStr, '\\');

+            if (pos != NULL) {

+                result.set(mStr, pos - mStr);

+            }

+        }

+        return result;

+    }

+

+    // Returns a pointer to the baseName part of the path.

+    // It becomes invalid if the path changes.

+    const char * baseName() const {

+        if (mStr != NULL) {

+            char *pos = strrchr(mStr, '\\');

+            if (pos != NULL) {

+                return pos + 1;

+            }

+        }

+        return NULL;

+    }

+

+    // If the path ends with the given searchName, replace in-place by the new name

+    void replaceName(const char *searchName, const char* newName) {

+        if (mStr == NULL) return;

+        int n = length();

+        int sn = strlen(searchName);

+        if (n < sn) return;

+        // if mStr ends with searchName

+        if (strcmp(mStr + n - sn, searchName) == 0) {

+            int sn2 = strlen(newName);

+            if (sn2 > sn) {

+                mStr = (char *)realloc((void *)mStr, n + sn2 - sn + 1);

+            }

+            strcpy(mStr + n - sn, newName);

+            mStr[n + sn2 - sn] = 0;

+        }

+    }

+};

+

+// Displays a message in an ok+info dialog box.

+void msgBox(const char* text, ...);

+

+// Displays GetLastError prefixed with a description in an error dialog box

+void displayLastError(const char *description, ...);

+

+// Executes the command line. Does not wait for the program to finish.

+// The return code is from CreateProcess (0 means failure), not the running app.

+int execNoWait(const char *app, const char *params, const char *workDir);

+

+// Executes command, waits for completion and returns exit code.

+// As indicated in MSDN for CreateProcess, callers should double-quote the program name

+// e.g. cmd="\"c:\program files\myapp.exe\" arg1 arg2";

+int execWait(const char *cmd);

+

+bool getModuleDir(CPath *outDir);

+

+// Disables the FS redirection done by WOW64.

+// Because this runs as a 32-bit app, Windows automagically remaps some

+// folder under the hood (e.g. "Programs Files(x86)" is mapped as "Program Files").

+// This prevents the app from correctly searching for java.exe in these folders.

+// The registry is also remapped.

+PVOID disableWow64FsRedirection();

+

+// Reverts the redirection disabled in disableWow64FsRedirection.

+void revertWow64FsRedirection(PVOID oldWow64Value);

+

+#endif /* _WIN32 */

+#endif /* _H_UTILS */

diff --git a/sdkmanager/win_android/win_android.cpp b/sdkmanager/win_android/win_android.cpp
index 2c957e0..6417051 100644
--- a/sdkmanager/win_android/win_android.cpp
+++ b/sdkmanager/win_android/win_android.cpp
@@ -27,20 +27,9 @@
 

 #ifdef _WIN32

 

-#define _CRT_SECURE_NO_WARNINGS 1

+#include "utils.h"

+#include "find_java.h"

 

-#include <direct.h>

-#include <stdio.h>

-#include <stdarg.h>

-#include <string.h>

-#include <windows.h>

-

-// VS vs MINGW specific includes

-#ifdef USE_MINGW

-    #define _ASSERT(x)      // undef

-#else

-    #include <crtdbg.h>     // for _ASSERT

-#endif

 

 // A NULL-terminated list of directory to create in the temp folder.

 static const char * sMkDirList[] = {

@@ -69,467 +58,6 @@
     NULL,

 };

 

-static bool gDebug = false;

-

-

-// An array that knows its own size. Not dynamically resizable.

-template <class T> class CArray {

-    T* mPtr;

-    int mSize;

-public:

-    explicit CArray(int size) {

-        mSize = size;

-        mPtr = new T[size];

-    }

-

-    ~CArray() {

-        if (mPtr != NULL) {

-            delete[] mPtr;

-            mPtr = NULL;

-        }

-        mSize = 0;

-    }

-

-    T& operator[](int i) {

-        _ASSERT(i >= 0 && i < mSize);

-        return mPtr[i];

-    }

-

-    int size() const {

-        return mSize;

-    }

-};

-

-// A simple string class wrapper.

-class CString {

-protected:

-    char *mStr;

-public:

-    CString()                              { mStr = NULL; }

-    CString(const CString &str)            { mStr = str.mStr == NULL ? NULL : _strdup(str.mStr); }

-    explicit CString(const char *str)      { mStr = NULL; set(str); }

-    CString(const char *start, int length) { mStr = NULL; set(start, length); }

-

-    CString& set(const char *str) {

-        _free();

-        if (str != NULL) {

-            mStr = _strdup(str);

-        }

-        return *this;

-    }

-

-    CString& set(const char *start, int length) {

-        _free();

-        if (start != NULL) {

-            mStr = (char *)malloc(length + 1);

-            strncpy(mStr, start, length);

-            mStr[length] = 0;

-        }

-        return *this;

-    }

-

-    CString& setv(const char *str, va_list ap) {

-        _free();

-        // _vscprintf(str, ap) is only available with the MSVCRT, not MinGW.

-        // Instead we'll iterate till we have enough space to generate the string.

-        int len = strlen(str) + 1024;

-        mStr = (char *)malloc(len);

-        strcpy(mStr, str); // provide a default in case vsnprintf totally fails

-        for (int guard = 0; guard < 10; guard++) {

-            int ret = vsnprintf(mStr, len, str, ap);

-            if (ret == -1) {

-                // Some implementations don't give the proper size needed

-                // so double the space and try again.

-                len *= 2;

-            } else if (ret >= len) {

-                len = ret + 1;

-            } else {

-                // There was enough space to write.

-                break;

-            }

-            mStr = (char *)realloc((void *)mStr, len);

-            strcpy(mStr, str); // provide a default in case vsnprintf totally fails

-        }

-        return *this;

-    }

-

-    CString& setf(const char *str, ...) {

-        _free();

-        va_list ap;

-        va_start(ap, str);

-        setv(str, ap);

-        va_end(ap);

-        return *this;

-    }

-

-    virtual ~CString() { _free(); }

-

-    // Returns the C string owned by this CString. It will be

-    // invalid as soon as this CString is deleted or out of scope.

-    const char * cstr() const {

-        return mStr;

-    }

-

-    bool isEmpty() const {

-        return mStr == NULL || *mStr == 0;

-    }

-

-    int length() const {

-        return mStr == NULL ? 0 : strlen(mStr);

-    }

-

-    CString& add(const char *s) {

-        if (mStr == NULL) {

-            set(s);

-        } else {

-            mStr = (char *)realloc((void *)mStr, strlen(mStr) + strlen(s) + 1);

-            strcat(mStr, s);

-        }

-        return *this;

-    }

-

-    CArray<CString> * split(char sep) const {

-        if (mStr == NULL) {

-            return new CArray<CString>(0);

-        }

-        const char *last = NULL;

-        int n = 0;

-        for (const char *s = mStr; *s; s++) {

-            if (*s == sep && s != mStr && (last == NULL || s > last+1)) {

-                n++;

-                last = s;

-            }

-        }

-

-        CArray<CString> *result = new CArray<CString>(n);

-        last = NULL;

-        n = 0;

-        for (const char *s = mStr; *s; s++) {

-            if (*s == sep) {

-                if (s != mStr && (last == NULL || s > last+1)) {

-                    const char *start = last ? last : mStr;

-                    (*result)[n++].set(start, s-start);

-                }

-                last = s+1;

-            }

-        }

-

-        return result;

-    }

-

-private:

-    void _free() {

-        if (mStr != NULL) {

-            free((void *)mStr);

-            mStr = NULL;

-        }

-    }

-

-};

-

-// A simple path class wrapper.

-class CPath : public CString {

-public:

-    CPath()                              : CString()    { }

-    CPath(const CPath &str)              : CString(str) { }

-    explicit CPath(const char *str)      : CString(str) { }

-    CPath(const char *start, int length) : CString(start, length) { }

-

-    // Appends a path segment, adding a \ as necessary.

-    CPath& addPath(const CString &s) {

-        return addPath(s.cstr());

-    }

-

-    // Appends a path segment, adding a \ as necessary.

-    CPath& addPath(const char *s) {

-        _ASSERT(s != NULL);

-        if (s != NULL && s[0] != 0) {

-            int n = length();

-            if (n > 0 && s[0] != '\\' && mStr[n-1] != '\\') add("\\");

-            add(s);

-        }

-        return *this;

-    }

-

-    // Returns true if file exist and is not a directory.

-    // There's no garantee we have rights to access it.

-    bool fileExists() const {

-        if (mStr == NULL) return false;

-        DWORD attribs = GetFileAttributesA(mStr);

-        return attribs != INVALID_FILE_ATTRIBUTES &&

-             !(attribs & FILE_ATTRIBUTE_DIRECTORY);

-    }

-

-    // Returns true if file exist and is a directory.

-    // There's no garantee we have rights to access it.

-    bool dirExists() const {

-        if (mStr == NULL) return false;

-        DWORD attribs = GetFileAttributesA(mStr);

-        return attribs != INVALID_FILE_ATTRIBUTES &&

-              (attribs & FILE_ATTRIBUTE_DIRECTORY) != 0;

-    }

-

-    // Returns a copy of the directory portion of the path, if any

-    CPath dirName() const {

-        CPath result;

-        if (mStr != NULL) {

-            char *pos = strrchr(mStr, '\\');

-            if (pos != NULL) {

-                result.set(mStr, pos - mStr);

-            }

-        }

-        return result;

-    }

-

-    // Returns a pointer to the baseName part of the path.

-    // It becomes invalid if the path changes.

-    const char * baseName() const {

-        if (mStr != NULL) {

-            char *pos = strrchr(mStr, '\\');

-            if (pos != NULL) {

-                return pos + 1;

-            }

-        }

-        return NULL;

-    }

-

-    // If the path ends with the given searchName, replace in-place by the new name

-    void replaceName(const char *searchName, const char* newName) {

-        if (mStr == NULL) return;

-        int n = length();

-        int sn = strlen(searchName);

-        if (n < sn) return;

-        // if mStr ends with searchName

-        if (strcmp(mStr + n - sn, searchName) == 0) {

-            int sn2 = strlen(newName);

-            if (sn2 > sn) {

-                mStr = (char *)realloc((void *)mStr, n + sn2 - sn + 1);

-            }

-            strcpy(mStr + n - sn, newName);

-            mStr[n + sn2 - sn] = 0;

-        }

-    }

-};

-

-// ========= UTILITIES ==============

-

-// Displays a message in an ok+info dialog box.

-static void msgBox(const char* text, ...) {

-    CString formatted;

-    va_list ap;

-    va_start(ap, text);

-    formatted.setv(text, ap);

-    va_end(ap);

-

-    MessageBoxA(NULL, formatted.cstr(), "Android SDK Manager", MB_OK | MB_ICONINFORMATION);

-}

-

-static void displayLastError(const char *description, ...) {

-    CString formatted;

-    va_list ap;

-    va_start(ap, description);

-    formatted.setv(description, ap);

-    va_end(ap);

-

-    DWORD err = GetLastError();

-    LPSTR errStr;

-    if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | /* dwFlags */

-                      FORMAT_MESSAGE_FROM_SYSTEM,

-                      NULL,                             /* lpSource */

-                      err,                              /* dwMessageId */

-                      0,                                /* dwLanguageId */

-                      (LPSTR)&errStr,                   /* lpBuffer */

-                      0,                                /* nSize */

-                      NULL) != 0) {                     /* va_list args */

-        formatted.add("\r\n");

-        formatted.add(errStr);

-        MessageBox(NULL, formatted.cstr(), "Android SDK Manager - Error", MB_OK | MB_ICONERROR);

-        LocalFree(errStr);

-    }

-}

-

-// Executes the command line. Does not wait for the program to finish.

-// The return code is from CreateProcess (0 means failure), not the running app.

-static int execNoWait(const char *app, const char *params, const char *workDir) {

-    STARTUPINFO           startup;

-    PROCESS_INFORMATION   pinfo;

-

-    ZeroMemory(&pinfo, sizeof(pinfo));

-

-    ZeroMemory(&startup, sizeof(startup));

-    startup.cb          = sizeof(startup);

-    startup.dwFlags     = STARTF_USESHOWWINDOW;

-    startup.wShowWindow = SW_HIDE|SW_MINIMIZE;

-

-    int ret = CreateProcessA(

-            (LPSTR) app,                                /* program path */

-            (LPSTR) params,                             /* command-line */

-            NULL,                  /* process handle is not inheritable */

-            NULL,                   /* thread handle is not inheritable */

-            TRUE,                          /* yes, inherit some handles */

-            CREATE_NO_WINDOW,                /* we don't want a console */

-            NULL,                     /* use parent's environment block */

-            workDir,                 /* use parent's starting directory */

-            &startup,                 /* startup info, i.e. std handles */

-            &pinfo);

-

-    if (ret) {

-        CloseHandle(pinfo.hProcess);

-        CloseHandle(pinfo.hThread);

-    }

-

-    return ret;

-}

-

-

-// Executes command, waits for completion and returns exit code.

-// As indicated in MSDN for CreateProcess, callers should double-quote the program name

-// e.g. cmd="\"c:\program files\myapp.exe\" arg1 arg2";

-static int execWait(const char *cmd) {

-    STARTUPINFO           startup;

-    PROCESS_INFORMATION   pinfo;

-

-    ZeroMemory(&pinfo, sizeof(pinfo));

-

-    ZeroMemory(&startup, sizeof(startup));

-    startup.cb          = sizeof(startup);

-    startup.dwFlags     = STARTF_USESHOWWINDOW;

-    startup.wShowWindow = SW_HIDE|SW_MINIMIZE;

-

-    int ret = CreateProcessA(

-            NULL,                                       /* program path */

-            (LPSTR) cmd,                                /* command-line */

-            NULL,                  /* process handle is not inheritable */

-            NULL,                   /* thread handle is not inheritable */

-            TRUE,                          /* yes, inherit some handles */

-            CREATE_NO_WINDOW,                /* we don't want a console */

-            NULL,                     /* use parent's environment block */

-            NULL,                    /* use parent's starting directory */

-            &startup,                 /* startup info, i.e. std handles */

-            &pinfo);

-

-    int result = -1;

-    if (ret) {

-        WaitForSingleObject(pinfo.hProcess, INFINITE);

-

-        DWORD exitCode;

-        if (GetExitCodeProcess(pinfo.hProcess, &exitCode)) {

-            // this should not return STILL_ACTIVE (259)

-            result = exitCode;

-        }

-        CloseHandle(pinfo.hProcess);

-        CloseHandle(pinfo.hThread);

-    }

-

-    return result;

-}

-

-static bool getModuleDir(CPath *outDir) {

-    CHAR programDir[MAX_PATH];

-    int ret = GetModuleFileName(NULL, programDir, sizeof(programDir));

-    if (ret != 0) {

-        // Remove the last segment to keep only the directory.

-        int pos = ret - 1;

-        while (pos > 0 && programDir[pos] != '\\') {

-            --pos;

-        }

-        outDir->set(programDir, pos);

-        return true;

-    }

-    return false;

-}

-

-// Disable the FS redirection done by WOW64.

-// Because this runs as a 32-bit app, Windows automagically remaps some

-// folder under the hood (e.g. "Programs Files(x86)" is mapped as "Program Files").

-// This prevents the app from correctly searching for java.exe in these folders.

-// The registry is also remapped.

-static PVOID disableWow64FsRedirection() {

-

-    // The call we want to make is the following:

-    //    PVOID oldWow64Value;

-    //    Wow64DisableWow64FsRedirection(&oldWow64Value);

-    // However that method may not exist (e.g. on non-64 systems) so

-    // we must not call it directly.

-

-    PVOID oldWow64Value = 0;

-

-    HMODULE hmod = LoadLibrary("kernel32.dll");

-    if (hmod != NULL) {

-        FARPROC proc = GetProcAddress(hmod, "Wow64DisableWow64FsRedirection");

-        if (proc != NULL) {

-            typedef BOOL (WINAPI *disableWow64FuncType)(PVOID *);

-            disableWow64FuncType funcPtr = (disableWow64FuncType)proc;

-            funcPtr(&oldWow64Value);

-        }

-

-        FreeLibrary(hmod);

-    }

-

-    return oldWow64Value;

-}

-

-//Reverts the redirection disabled in disableWow64FsRedirection.

-static void revertWow64FsRedirection(PVOID oldWow64Value) {

-

-    // The call we want to make is the following:

-    //    Wow64RevertWow64FsRedirection(oldWow64Value);

-    // However that method may not exist (e.g. on non-64 systems) so

-    // we must not call it directly.

-

-    HMODULE hmod = LoadLibrary("kernel32.dll");

-    if (hmod != NULL) {

-        FARPROC proc = GetProcAddress(hmod, "Wow64RevertWow64FsRedirection");

-        if (proc != NULL) {

-            typedef BOOL (WINAPI *revertWow64FuncType)(PVOID);

-            revertWow64FuncType funcPtr = (revertWow64FuncType)proc;

-            funcPtr(oldWow64Value);

-        }

-

-        FreeLibrary(hmod);

-    }

-}

-

-

-// =============================

-

-// Search java.exe in the path

-static bool findJavaInEnvPath(CPath *outJavaPath) {

-    SetLastError(0);

-    const char* envPath = getenv("PATH");

-    if (!envPath) return false;

-

-    CArray<CString> *paths = CString(envPath).split(';');

-    for(int i = 0; i < paths->size(); i++) {

-        CPath p((*paths)[i].cstr());

-        p.addPath("java.exe");

-        if (p.fileExists()) {

-            // Make sure we can actually run "java -version".

-            CString cmd;

-            cmd.setf("\"%s\" -version", p.cstr());

-            int code = execWait(cmd.cstr());

-            if (code == 0) {

-                if (gDebug) msgBox("Java found via env path: %s", p.cstr());

-                outJavaPath->set(p.cstr());

-                delete paths;

-                return true;

-            }

-        }

-    }

-

-    delete paths;

-    return false;

-}

-

-static bool findJavaInRegistry(CPath *outJavaPath) {

-    // TODO

-    return false;

-}

-

-static bool findJavaInProgramFiles(CPath *outJavaPath) {

-    // TODO

-    return false;

-}

 

 // Creates a directory named dirLeafName in the TEMP directory.

 // Returns the path in outDir on success.