diff options
Diffstat (limited to 'xpcom/build/BinaryPath.h')
-rw-r--r-- | xpcom/build/BinaryPath.h | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/xpcom/build/BinaryPath.h b/xpcom/build/BinaryPath.h new file mode 100644 index 0000000000..374763c79e --- /dev/null +++ b/xpcom/build/BinaryPath.h @@ -0,0 +1,188 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_BinaryPath_h +#define mozilla_BinaryPath_h + +#include "nsXPCOMPrivate.h" // for MAXPATHLEN +#ifdef XP_WIN +#include <windows.h> +#elif defined(XP_MACOSX) +#include <CoreFoundation/CoreFoundation.h> +#elif defined(XP_UNIX) +#include <sys/stat.h> +#include <string.h> +#endif + +namespace mozilla { + +class BinaryPath +{ +public: +#ifdef XP_WIN + static nsresult Get(const char* argv0, char aResult[MAXPATHLEN]) + { + wchar_t wide_path[MAXPATHLEN]; + nsresult rv = GetW(argv0, wide_path); + if (NS_FAILED(rv)) { + return rv; + } + WideCharToMultiByte(CP_UTF8, 0, wide_path, -1, + aResult, MAXPATHLEN, nullptr, nullptr); + return NS_OK; + } + +private: + static nsresult GetW(const char* argv0, wchar_t aResult[MAXPATHLEN]) + { + if (::GetModuleFileNameW(0, aResult, MAXPATHLEN)) { + return NS_OK; + } + return NS_ERROR_FAILURE; + } + +#elif defined(XP_MACOSX) + static nsresult Get(const char* argv0, char aResult[MAXPATHLEN]) + { + // Works even if we're not bundled. + CFBundleRef appBundle = CFBundleGetMainBundle(); + if (!appBundle) { + return NS_ERROR_FAILURE; + } + + CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle); + if (!executableURL) { + return NS_ERROR_FAILURE; + } + + nsresult rv; + if (CFURLGetFileSystemRepresentation(executableURL, false, (UInt8*)aResult, + MAXPATHLEN)) { + // Sanitize path in case the app was launched from Terminal via + // './firefox' for example. + size_t readPos = 0; + size_t writePos = 0; + while (aResult[readPos] != '\0') { + if (aResult[readPos] == '.' && aResult[readPos + 1] == '/') { + readPos += 2; + } else { + aResult[writePos] = aResult[readPos]; + readPos++; + writePos++; + } + } + aResult[writePos] = '\0'; + rv = NS_OK; + } else { + rv = NS_ERROR_FAILURE; + } + + CFRelease(executableURL); + return rv; + } + +#elif defined(ANDROID) + static nsresult Get(const char* argv0, char aResult[MAXPATHLEN]) + { + // On Android, we use the GRE_HOME variable that is set by the Java + // bootstrap code. + const char* greHome = getenv("GRE_HOME"); +#if defined(MOZ_WIDGET_GONK) + if (!greHome) { + greHome = "/system/b2g"; + } +#endif + + if (!greHome) { + return NS_ERROR_FAILURE; + } + + snprintf(aResult, MAXPATHLEN, "%s/%s", greHome, "dummy"); + aResult[MAXPATHLEN - 1] = '\0'; + return NS_OK; + } + +#elif defined(XP_UNIX) + static nsresult Get(const char* aArgv0, char aResult[MAXPATHLEN]) + { + struct stat fileStat; + // on unix, there is no official way to get the path of the current binary. + // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to + // multiple applications, we will try a series of techniques: + // + // 1) use realpath() on argv[0], which works unless we're loaded from the + // PATH. Only do so if argv[0] looks like a path (contains a /). + // 2) manually walk through the PATH and look for ourself + // 3) give up + if (strchr(aArgv0, '/') && realpath(aArgv0, aResult) && + stat(aResult, &fileStat) == 0) { + return NS_OK; + } + + const char* path = getenv("PATH"); + if (!path) { + return NS_ERROR_FAILURE; + } + + char* pathdup = strdup(path); + if (!pathdup) { + return NS_ERROR_OUT_OF_MEMORY; + } + + bool found = false; + char* token = strtok(pathdup, ":"); + while (token) { + char tmpPath[MAXPATHLEN]; + sprintf(tmpPath, "%s/%s", token, aArgv0); + if (realpath(tmpPath, aResult) && stat(aResult, &fileStat) == 0) { + found = true; + break; + } + token = strtok(nullptr, ":"); + } + free(pathdup); + if (found) { + return NS_OK; + } + return NS_ERROR_FAILURE; + } + +#else +#error Oops, you need platform-specific code here +#endif + +public: + static nsresult GetFile(const char* aArgv0, nsIFile** aResult) + { + nsCOMPtr<nsIFile> lf; +#ifdef XP_WIN + wchar_t exePath[MAXPATHLEN]; + nsresult rv = GetW(aArgv0, exePath); +#else + char exePath[MAXPATHLEN]; + nsresult rv = Get(aArgv0, exePath); +#endif + if (NS_FAILED(rv)) { + return rv; + } +#ifdef XP_WIN + rv = NS_NewLocalFile(nsDependentString(exePath), true, + getter_AddRefs(lf)); +#else + rv = NS_NewNativeLocalFile(nsDependentCString(exePath), true, + getter_AddRefs(lf)); +#endif + if (NS_FAILED(rv)) { + return rv; + } + NS_ADDREF(*aResult = lf); + return NS_OK; + } +}; + +} // namespace mozilla + +#endif /* mozilla_BinaryPath_h */ |