From e2de507e0261c9b138cd3cf5356c21eca3e7a28d Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Mon, 16 Dec 2019 20:09:38 -0500 Subject: Issue #1323 - Move XULRunner back to topsrcdir --- xulrunner/stub/nsXULStub.cpp | 445 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 445 insertions(+) create mode 100644 xulrunner/stub/nsXULStub.cpp (limited to 'xulrunner/stub/nsXULStub.cpp') diff --git a/xulrunner/stub/nsXULStub.cpp b/xulrunner/stub/nsXULStub.cpp new file mode 100644 index 000000000..8638ae43e --- /dev/null +++ b/xulrunner/stub/nsXULStub.cpp @@ -0,0 +1,445 @@ +/* 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/. */ + +#include "nsXPCOMGlue.h" +#include "nsINIParser.h" +#include "nsXPCOMPrivate.h" // for XP MAXPATHLEN +#include "nsXULAppAPI.h" +#include "nsIFile.h" + +#include + +#ifdef XP_WIN +#include +#include +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define snprintf _snprintf +#define vsnprintf _vsnprintf +#endif +#define strcasecmp _stricmp +#define PATH_SEPARATOR_CHAR '\\' +#define R_OK 04 +#elif defined(XP_MACOSX) +#include +#include +#include +#define PATH_SEPARATOR_CHAR '/' +#else +#include +#include +#include +#define PATH_SEPARATOR_CHAR '/' +#endif + +#ifdef XP_WIN +#define XRE_DONT_PROTECT_DLL_LOAD +#include "nsWindowsWMain.cpp" +#endif + +#define VERSION_MAXLEN 128 + +static void Output(bool isError, const char *fmt, ... ) +{ + va_list ap; + va_start(ap, fmt); + +#if (defined(XP_WIN) && !MOZ_WINCONSOLE) + char msg[2048]; + + vsnprintf(msg, sizeof(msg), fmt, ap); + + UINT flags = MB_OK; + if (isError) + flags |= MB_ICONERROR; + else + flags |= MB_ICONINFORMATION; + + wchar_t wide_msg[1024]; + MultiByteToWideChar(CP_ACP, + 0, + msg, + -1, + wide_msg, + sizeof(wide_msg) / sizeof(wchar_t)); + + MessageBoxW(nullptr, wide_msg, L"XULRunner", flags); +#else + vfprintf(stderr, fmt, ap); +#endif + + va_end(ap); +} + +/** + * Return true if |arg| matches the given argument name. + */ +static bool IsArg(const char* arg, const char* s) +{ + if (*arg == '-') + { + if (*++arg == '-') + ++arg; + return !strcasecmp(arg, s); + } + +#if defined(XP_WIN) + if (*arg == '/') + return !strcasecmp(++arg, s); +#endif + + return false; +} + +/** + * Return true if |aDir| is a valid file/directory. + */ +static bool FolderExists(const char* aDir) +{ +#ifdef XP_WIN + wchar_t wideDir[MAX_PATH]; + MultiByteToWideChar(CP_UTF8, 0, aDir, -1, wideDir, MAX_PATH); + DWORD fileAttrs = GetFileAttributesW(wideDir); + return fileAttrs != INVALID_FILE_ATTRIBUTES; +#else + return access(aDir, R_OK) == 0; +#endif +} + +static nsresult GetRealPath(const char* appDataFile, char* *aResult) +{ +#ifdef XP_WIN + wchar_t wAppDataFile[MAX_PATH]; + wchar_t wIniPath[MAX_PATH]; + MultiByteToWideChar(CP_UTF8, 0, appDataFile, -1, wAppDataFile, MAX_PATH); + _wfullpath(wIniPath, wAppDataFile, MAX_PATH); + WideCharToMultiByte(CP_UTF8, 0, wIniPath, -1, *aResult, MAX_PATH, 0, 0); +#else + struct stat fileStat; + if (!realpath(appDataFile, *aResult) || stat(*aResult, &fileStat)) + return NS_ERROR_FAILURE; +#endif + if (!*aResult || !**aResult) + return NS_ERROR_FAILURE; + + return NS_OK; +} + +class AutoAppData +{ +public: + AutoAppData(nsIFile* aINIFile) : mAppData(nullptr) { + nsresult rv = XRE_CreateAppData(aINIFile, &mAppData); + if (NS_FAILED(rv)) + mAppData = nullptr; + } + ~AutoAppData() { + if (mAppData) + XRE_FreeAppData(mAppData); + } + + operator nsXREAppData*() const { return mAppData; } + nsXREAppData* operator -> () const { return mAppData; } + +private: + nsXREAppData* mAppData; +}; + +XRE_CreateAppDataType XRE_CreateAppData; +XRE_FreeAppDataType XRE_FreeAppData; +XRE_mainType XRE_main; + +int +main(int argc, char **argv) +{ + nsresult rv; + char *lastSlash; + + char iniPath[MAXPATHLEN]; + char tmpPath[MAXPATHLEN]; + char greDir[MAXPATHLEN]; + bool greFound = false; + +#if defined(XP_MACOSX) + CFBundleRef appBundle = CFBundleGetMainBundle(); + if (!appBundle) + return 1; + + CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(appBundle); + if (!resourcesURL) + return 1; + + CFURLRef absResourcesURL = CFURLCopyAbsoluteURL(resourcesURL); + CFRelease(resourcesURL); + if (!absResourcesURL) + return 1; + + CFURLRef iniFileURL = + CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, + absResourcesURL, + CFSTR("application.ini"), + false); + CFRelease(absResourcesURL); + if (!iniFileURL) + return 1; + + CFStringRef iniPathStr = + CFURLCopyFileSystemPath(iniFileURL, kCFURLPOSIXPathStyle); + CFRelease(iniFileURL); + if (!iniPathStr) + return 1; + + CFStringGetCString(iniPathStr, iniPath, sizeof(iniPath), + kCFStringEncodingUTF8); + CFRelease(iniPathStr); + +#else + +#ifdef XP_WIN + wchar_t wide_path[MAX_PATH]; + if (!::GetModuleFileNameW(nullptr, wide_path, MAX_PATH)) + return 1; + + WideCharToMultiByte(CP_UTF8, 0, wide_path,-1, + iniPath, MAX_PATH, nullptr, nullptr); + +#else + // 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 + // 2) manually walk through the PATH and look for ourself + // 3) give up + + struct stat fileStat; + strncpy(tmpPath, argv[0], sizeof(tmpPath)); + lastSlash = strrchr(tmpPath, '/'); + if (lastSlash) { + *lastSlash = 0; + realpath(tmpPath, iniPath); + } else { + const char *path = getenv("PATH"); + if (!path) + return 1; + + char *pathdup = strdup(path); + if (!pathdup) + return 1; + + bool found = false; + char *token = strtok(pathdup, ":"); + while (token) { + sprintf(tmpPath, "%s/%s", token, argv[0]); + if (stat(tmpPath, &fileStat) == 0) { + found = true; + lastSlash = strrchr(tmpPath, '/'); + *lastSlash = 0; + realpath(tmpPath, iniPath); + break; + } + token = strtok(nullptr, ":"); + } + free (pathdup); + if (!found) + return 1; + } + lastSlash = iniPath + strlen(iniPath); + *lastSlash = '/'; +#endif + +#ifndef XP_UNIX + lastSlash = strrchr(iniPath, PATH_SEPARATOR_CHAR); + if (!lastSlash) + return 1; +#endif + + *(++lastSlash) = '\0'; + + // On Linux/Win, look for XULRunner in appdir/xulrunner + + snprintf(greDir, sizeof(greDir), + "%sxulrunner" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL, + iniPath); + + greFound = FolderExists(greDir); + +#ifdef XP_UNIX + if (greFound) { + char resolved_greDir[MAXPATHLEN] = ""; + if (realpath(greDir, resolved_greDir) && *resolved_greDir) { + strncpy(greDir, resolved_greDir, MAXPATHLEN); + } + } +#endif + + strncpy(lastSlash, "application.ini", sizeof(iniPath) - (lastSlash - iniPath)); + +#endif + + // If -app parameter was passed in, it is now time to take it under + // consideration. + const char *appDataFile; + appDataFile = getenv("XUL_APP_FILE"); + if (!appDataFile || !*appDataFile) + if (argc > 1 && IsArg(argv[1], "app")) { + if (argc == 2) { + Output(false, "specify APP-FILE (optional)\n"); + return 1; + } + argv[1] = argv[0]; + ++argv; + --argc; + + appDataFile = argv[1]; + argv[1] = argv[0]; + ++argv; + --argc; + + char kAppEnv[MAXPATHLEN]; + snprintf(kAppEnv, MAXPATHLEN, "XUL_APP_FILE=%s", appDataFile); + if (putenv(kAppEnv)) + Output(false, "Couldn't set %s.\n", kAppEnv); + + char *result = (char*) calloc(sizeof(char), MAXPATHLEN); + if (NS_FAILED(GetRealPath(appDataFile, &result))) { + Output(true, "Invalid application.ini path.\n"); + return 1; + } + + // We have a valid application.ini path passed in to the -app parameter + // but not yet a valid greDir, so lets look for it also on the same folder + // as the stub. + if (!greFound) { + lastSlash = strrchr(iniPath, PATH_SEPARATOR_CHAR); + if (!lastSlash) + return 1; + + *(++lastSlash) = '\0'; + + snprintf(greDir, sizeof(greDir), "%s" XPCOM_DLL, iniPath); + greFound = FolderExists(greDir); + } + + // copy it back. + strcpy(iniPath, result); + } + + nsINIParser parser; + rv = parser.Init(iniPath); + if (NS_FAILED(rv)) { + fprintf(stderr, "Could not read application.ini\n"); + return 1; + } + + if (!greFound) { +#ifdef XP_MACOSX + // The bundle can be found next to the executable, in the MacOS dir. + CFURLRef exurl = CFBundleCopyExecutableURL(appBundle); + CFURLRef absexurl = nullptr; + if (exurl) { + absexurl = CFURLCopyAbsoluteURL(exurl); + CFRelease(exurl); + } + + if (absexurl) { + char tbuffer[MAXPATHLEN]; + + if (CFURLGetFileSystemRepresentation(absexurl, true, + (UInt8*) tbuffer, + sizeof(tbuffer)) && + access(tbuffer, R_OK | X_OK) == 0) { + if (realpath(tbuffer, greDir)) { + greFound = true; + } + else { + greDir[0] = '\0'; + } + } + + CFRelease(absexurl); + } +#endif + if (!greFound) { + Output(false, "Could not find the Mozilla runtime.\n"); + return 1; + } + } + + rv = XPCOMGlueStartup(greDir); + if (NS_FAILED(rv)) { + if (rv == NS_ERROR_OUT_OF_MEMORY) { + char applicationName[2000] = "this application"; + parser.GetString("App", "Name", applicationName, sizeof(applicationName)); + Output(true, "Not enough memory available to start %s.\n", + applicationName); + } else { + Output(true, "Couldn't load XPCOM.\n"); + } + return 1; + } + + static const nsDynamicFunctionLoad kXULFuncs[] = { + { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData }, + { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData }, + { "XRE_main", (NSFuncPtr*) &XRE_main }, + { nullptr, nullptr } + }; + + rv = XPCOMGlueLoadXULFunctions(kXULFuncs); + if (NS_FAILED(rv)) { + Output(true, "Couldn't load XRE functions.\n"); + return 1; + } + + NS_LogInit(); + + int retval; + + { // Scope COMPtr and AutoAppData + nsCOMPtr iniFile; +#ifdef XP_WIN + // On Windows iniPath is UTF-8 encoded so we need to convert it. + rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(iniPath), false, + getter_AddRefs(iniFile)); +#else + rv = NS_NewNativeLocalFile(nsDependentCString(iniPath), false, + getter_AddRefs(iniFile)); +#endif + if (NS_FAILED(rv)) { + Output(true, "Couldn't find application.ini file.\n"); + return 1; + } + + AutoAppData appData(iniFile); + if (!appData) { + Output(true, "Error: couldn't parse application.ini.\n"); + return 1; + } + + NS_ASSERTION(appData->directory, "Failed to get app directory."); + + if (!appData->xreDirectory) { + // chop "libxul.so" off the GRE path + lastSlash = strrchr(greDir, PATH_SEPARATOR_CHAR); + if (lastSlash) { + *lastSlash = '\0'; + } +#ifdef XP_WIN + // same as iniPath. + NS_NewLocalFile(NS_ConvertUTF8toUTF16(greDir), false, + &appData->xreDirectory); +#else + NS_NewNativeLocalFile(nsDependentCString(greDir), false, + &appData->xreDirectory); +#endif + } + + retval = XRE_main(argc, argv, appData, 0); + } + + NS_LogTerm(); + + return retval; +} -- cgit v1.2.3