1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xulrunner/stub/nsXULStub.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,461 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +#include "nsXPCOMGlue.h" 1.9 +#include "nsINIParser.h" 1.10 +#include "nsXPCOMPrivate.h" // for XP MAXPATHLEN 1.11 +#include "nsXULAppAPI.h" 1.12 +#include "nsIFile.h" 1.13 + 1.14 +#include <stdarg.h> 1.15 + 1.16 +#ifdef XP_WIN 1.17 +#include <windows.h> 1.18 +#include <io.h> 1.19 +#define snprintf _snprintf 1.20 +#define vsnprintf _vsnprintf 1.21 +#define strcasecmp _stricmp 1.22 +#define PATH_SEPARATOR_CHAR '\\' 1.23 +#define R_OK 04 1.24 +#elif defined(XP_MACOSX) 1.25 +#include <unistd.h> 1.26 +#include <sys/stat.h> 1.27 +#include <CoreFoundation/CoreFoundation.h> 1.28 +#define PATH_SEPARATOR_CHAR '/' 1.29 +#else 1.30 +#include <unistd.h> 1.31 +#include <sys/types.h> 1.32 +#include <sys/stat.h> 1.33 +#define PATH_SEPARATOR_CHAR '/' 1.34 +#endif 1.35 + 1.36 +#ifdef XP_WIN 1.37 +#define XRE_DONT_PROTECT_DLL_LOAD 1.38 +#include "nsWindowsWMain.cpp" 1.39 +#endif 1.40 + 1.41 +#define VERSION_MAXLEN 128 1.42 + 1.43 +static void Output(bool isError, const char *fmt, ... ) 1.44 +{ 1.45 + va_list ap; 1.46 + va_start(ap, fmt); 1.47 + 1.48 +#if (defined(XP_WIN) && !MOZ_WINCONSOLE) 1.49 + char msg[2048]; 1.50 + 1.51 + vsnprintf(msg, sizeof(msg), fmt, ap); 1.52 + 1.53 + UINT flags = MB_OK; 1.54 + if (isError) 1.55 + flags |= MB_ICONERROR; 1.56 + else 1.57 + flags |= MB_ICONINFORMATION; 1.58 + 1.59 + wchar_t wide_msg[1024]; 1.60 + MultiByteToWideChar(CP_ACP, 1.61 + 0, 1.62 + msg, 1.63 + -1, 1.64 + wide_msg, 1.65 + sizeof(wide_msg) / sizeof(wchar_t)); 1.66 + 1.67 + MessageBoxW(nullptr, wide_msg, L"XULRunner", flags); 1.68 +#else 1.69 + vfprintf(stderr, fmt, ap); 1.70 +#endif 1.71 + 1.72 + va_end(ap); 1.73 +} 1.74 + 1.75 +/** 1.76 + * Return true if |arg| matches the given argument name. 1.77 + */ 1.78 +static bool IsArg(const char* arg, const char* s) 1.79 +{ 1.80 + if (*arg == '-') 1.81 + { 1.82 + if (*++arg == '-') 1.83 + ++arg; 1.84 + return !strcasecmp(arg, s); 1.85 + } 1.86 + 1.87 +#if defined(XP_WIN) 1.88 + if (*arg == '/') 1.89 + return !strcasecmp(++arg, s); 1.90 +#endif 1.91 + 1.92 + return false; 1.93 +} 1.94 + 1.95 +/** 1.96 + * Return true if |aDir| is a valid file/directory. 1.97 + */ 1.98 +static bool FolderExists(const char* aDir) 1.99 +{ 1.100 +#ifdef XP_WIN 1.101 + wchar_t wideDir[MAX_PATH]; 1.102 + MultiByteToWideChar(CP_UTF8, 0, aDir, -1, wideDir, MAX_PATH); 1.103 + DWORD fileAttrs = GetFileAttributesW(wideDir); 1.104 + return fileAttrs != INVALID_FILE_ATTRIBUTES; 1.105 +#else 1.106 + return access(aDir, R_OK) == 0; 1.107 +#endif 1.108 +} 1.109 + 1.110 +static nsresult GetRealPath(const char* appDataFile, char* *aResult) 1.111 +{ 1.112 +#ifdef XP_WIN 1.113 + wchar_t wAppDataFile[MAX_PATH]; 1.114 + wchar_t wIniPath[MAX_PATH]; 1.115 + MultiByteToWideChar(CP_UTF8, 0, appDataFile, -1, wAppDataFile, MAX_PATH); 1.116 + _wfullpath(wIniPath, wAppDataFile, MAX_PATH); 1.117 + WideCharToMultiByte(CP_UTF8, 0, wIniPath, -1, *aResult, MAX_PATH, 0, 0); 1.118 +#else 1.119 + struct stat fileStat; 1.120 + if (!realpath(appDataFile, *aResult) || stat(*aResult, &fileStat)) 1.121 + return NS_ERROR_FAILURE; 1.122 +#endif 1.123 + if (!*aResult || !**aResult) 1.124 + return NS_ERROR_FAILURE; 1.125 + 1.126 + return NS_OK; 1.127 +} 1.128 + 1.129 +class AutoAppData 1.130 +{ 1.131 +public: 1.132 + AutoAppData(nsIFile* aINIFile) : mAppData(nullptr) { 1.133 + nsresult rv = XRE_CreateAppData(aINIFile, &mAppData); 1.134 + if (NS_FAILED(rv)) 1.135 + mAppData = nullptr; 1.136 + } 1.137 + ~AutoAppData() { 1.138 + if (mAppData) 1.139 + XRE_FreeAppData(mAppData); 1.140 + } 1.141 + 1.142 + operator nsXREAppData*() const { return mAppData; } 1.143 + nsXREAppData* operator -> () const { return mAppData; } 1.144 + 1.145 +private: 1.146 + nsXREAppData* mAppData; 1.147 +}; 1.148 + 1.149 +XRE_CreateAppDataType XRE_CreateAppData; 1.150 +XRE_FreeAppDataType XRE_FreeAppData; 1.151 +XRE_mainType XRE_main; 1.152 + 1.153 +int 1.154 +main(int argc, char **argv) 1.155 +{ 1.156 + nsresult rv; 1.157 + char *lastSlash; 1.158 + 1.159 + char iniPath[MAXPATHLEN]; 1.160 + char tmpPath[MAXPATHLEN]; 1.161 + char greDir[MAXPATHLEN]; 1.162 + bool greFound = false; 1.163 + 1.164 +#if defined(XP_MACOSX) 1.165 + CFBundleRef appBundle = CFBundleGetMainBundle(); 1.166 + if (!appBundle) 1.167 + return 1; 1.168 + 1.169 + CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(appBundle); 1.170 + if (!resourcesURL) 1.171 + return 1; 1.172 + 1.173 + CFURLRef absResourcesURL = CFURLCopyAbsoluteURL(resourcesURL); 1.174 + CFRelease(resourcesURL); 1.175 + if (!absResourcesURL) 1.176 + return 1; 1.177 + 1.178 + CFURLRef iniFileURL = 1.179 + CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, 1.180 + absResourcesURL, 1.181 + CFSTR("application.ini"), 1.182 + false); 1.183 + CFRelease(absResourcesURL); 1.184 + if (!iniFileURL) 1.185 + return 1; 1.186 + 1.187 + CFStringRef iniPathStr = 1.188 + CFURLCopyFileSystemPath(iniFileURL, kCFURLPOSIXPathStyle); 1.189 + CFRelease(iniFileURL); 1.190 + if (!iniPathStr) 1.191 + return 1; 1.192 + 1.193 + CFStringGetCString(iniPathStr, iniPath, sizeof(iniPath), 1.194 + kCFStringEncodingUTF8); 1.195 + CFRelease(iniPathStr); 1.196 + 1.197 +#else 1.198 + 1.199 +#ifdef XP_WIN 1.200 + wchar_t wide_path[MAX_PATH]; 1.201 + if (!::GetModuleFileNameW(nullptr, wide_path, MAX_PATH)) 1.202 + return 1; 1.203 + 1.204 + WideCharToMultiByte(CP_UTF8, 0, wide_path,-1, 1.205 + iniPath, MAX_PATH, nullptr, nullptr); 1.206 + 1.207 +#else 1.208 + // on unix, there is no official way to get the path of the current binary. 1.209 + // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to 1.210 + // multiple applications, we will try a series of techniques: 1.211 + // 1.212 + // 1) use realpath() on argv[0], which works unless we're loaded from the 1.213 + // PATH 1.214 + // 2) manually walk through the PATH and look for ourself 1.215 + // 3) give up 1.216 + 1.217 + struct stat fileStat; 1.218 + strncpy(tmpPath, argv[0], sizeof(tmpPath)); 1.219 + lastSlash = strrchr(tmpPath, '/'); 1.220 + if (lastSlash) { 1.221 + *lastSlash = 0; 1.222 + realpath(tmpPath, iniPath); 1.223 + } else { 1.224 + const char *path = getenv("PATH"); 1.225 + if (!path) 1.226 + return 1; 1.227 + 1.228 + char *pathdup = strdup(path); 1.229 + if (!pathdup) 1.230 + return 1; 1.231 + 1.232 + bool found = false; 1.233 + char *token = strtok(pathdup, ":"); 1.234 + while (token) { 1.235 + sprintf(tmpPath, "%s/%s", token, argv[0]); 1.236 + if (stat(tmpPath, &fileStat) == 0) { 1.237 + found = true; 1.238 + lastSlash = strrchr(tmpPath, '/'); 1.239 + *lastSlash = 0; 1.240 + realpath(tmpPath, iniPath); 1.241 + break; 1.242 + } 1.243 + token = strtok(nullptr, ":"); 1.244 + } 1.245 + free (pathdup); 1.246 + if (!found) 1.247 + return 1; 1.248 + } 1.249 + lastSlash = iniPath + strlen(iniPath); 1.250 + *lastSlash = '/'; 1.251 +#endif 1.252 + 1.253 +#ifndef XP_UNIX 1.254 + lastSlash = strrchr(iniPath, PATH_SEPARATOR_CHAR); 1.255 + if (!lastSlash) 1.256 + return 1; 1.257 +#endif 1.258 + 1.259 + *(++lastSlash) = '\0'; 1.260 + 1.261 + // On Linux/Win, look for XULRunner in appdir/xulrunner 1.262 + 1.263 + snprintf(greDir, sizeof(greDir), 1.264 + "%sxulrunner" XPCOM_FILE_PATH_SEPARATOR XPCOM_DLL, 1.265 + iniPath); 1.266 + 1.267 + greFound = FolderExists(greDir); 1.268 + 1.269 +#ifdef XP_UNIX 1.270 + if (greFound) { 1.271 + char resolved_greDir[MAXPATHLEN] = ""; 1.272 + if (realpath(greDir, resolved_greDir) && *resolved_greDir) { 1.273 + strncpy(greDir, resolved_greDir, MAXPATHLEN); 1.274 + } 1.275 + } 1.276 +#endif 1.277 + 1.278 + strncpy(lastSlash, "application.ini", sizeof(iniPath) - (lastSlash - iniPath)); 1.279 + 1.280 +#endif 1.281 + 1.282 + // If -app parameter was passed in, it is now time to take it under 1.283 + // consideration. 1.284 + const char *appDataFile; 1.285 + appDataFile = getenv("XUL_APP_FILE"); 1.286 + if (!appDataFile || !*appDataFile) 1.287 + if (argc > 1 && IsArg(argv[1], "app")) { 1.288 + if (argc == 2) { 1.289 + Output(false, "specify APP-FILE (optional)\n"); 1.290 + return 1; 1.291 + } 1.292 + argv[1] = argv[0]; 1.293 + ++argv; 1.294 + --argc; 1.295 + 1.296 + appDataFile = argv[1]; 1.297 + argv[1] = argv[0]; 1.298 + ++argv; 1.299 + --argc; 1.300 + 1.301 + char kAppEnv[MAXPATHLEN]; 1.302 + snprintf(kAppEnv, MAXPATHLEN, "XUL_APP_FILE=%s", appDataFile); 1.303 + if (putenv(kAppEnv)) 1.304 + Output(false, "Couldn't set %s.\n", kAppEnv); 1.305 + 1.306 + char *result = (char*) calloc(sizeof(char), MAXPATHLEN); 1.307 + if (NS_FAILED(GetRealPath(appDataFile, &result))) { 1.308 + Output(true, "Invalid application.ini path.\n"); 1.309 + return 1; 1.310 + } 1.311 + 1.312 + // We have a valid application.ini path passed in to the -app parameter 1.313 + // but not yet a valid greDir, so lets look for it also on the same folder 1.314 + // as the stub. 1.315 + if (!greFound) { 1.316 + lastSlash = strrchr(iniPath, PATH_SEPARATOR_CHAR); 1.317 + if (!lastSlash) 1.318 + return 1; 1.319 + 1.320 + *(++lastSlash) = '\0'; 1.321 + 1.322 + snprintf(greDir, sizeof(greDir), "%s" XPCOM_DLL, iniPath); 1.323 + greFound = FolderExists(greDir); 1.324 + } 1.325 + 1.326 + // copy it back. 1.327 + strcpy(iniPath, result); 1.328 + } 1.329 + 1.330 + nsINIParser parser; 1.331 + rv = parser.Init(iniPath); 1.332 + if (NS_FAILED(rv)) { 1.333 + fprintf(stderr, "Could not read application.ini\n"); 1.334 + return 1; 1.335 + } 1.336 + 1.337 + if (!greFound) { 1.338 +#ifdef XP_MACOSX 1.339 + // Check for <bundle>/Contents/Frameworks/XUL.framework/Versions/Current/libmozglue.dylib 1.340 + CFURLRef fwurl = CFBundleCopyPrivateFrameworksURL(appBundle); 1.341 + CFURLRef absfwurl = nullptr; 1.342 + if (fwurl) { 1.343 + absfwurl = CFURLCopyAbsoluteURL(fwurl); 1.344 + CFRelease(fwurl); 1.345 + } 1.346 + 1.347 + if (absfwurl) { 1.348 + CFURLRef xulurl = 1.349 + CFURLCreateCopyAppendingPathComponent(nullptr, absfwurl, 1.350 + CFSTR("XUL.framework/Versions/Current"), 1.351 + true); 1.352 + 1.353 + if (xulurl) { 1.354 + CFURLRef xpcomurl = 1.355 + CFURLCreateCopyAppendingPathComponent(nullptr, xulurl, 1.356 + CFSTR("libmozglue.dylib"), 1.357 + false); 1.358 + 1.359 + if (xpcomurl) { 1.360 + char tbuffer[MAXPATHLEN]; 1.361 + 1.362 + if (CFURLGetFileSystemRepresentation(xpcomurl, true, 1.363 + (UInt8*) tbuffer, 1.364 + sizeof(tbuffer)) && 1.365 + access(tbuffer, R_OK | X_OK) == 0) { 1.366 + if (realpath(tbuffer, greDir)) { 1.367 + greFound = true; 1.368 + } 1.369 + else { 1.370 + greDir[0] = '\0'; 1.371 + } 1.372 + } 1.373 + 1.374 + CFRelease(xpcomurl); 1.375 + } 1.376 + 1.377 + CFRelease(xulurl); 1.378 + } 1.379 + 1.380 + CFRelease(absfwurl); 1.381 + } 1.382 +#endif 1.383 + if (!greFound) { 1.384 + Output(false, "Could not find the Mozilla runtime.\n"); 1.385 + return 1; 1.386 + } 1.387 + } 1.388 + 1.389 + rv = XPCOMGlueStartup(greDir); 1.390 + if (NS_FAILED(rv)) { 1.391 + if (rv == NS_ERROR_OUT_OF_MEMORY) { 1.392 + char applicationName[2000] = "this application"; 1.393 + parser.GetString("App", "Name", applicationName, sizeof(applicationName)); 1.394 + Output(true, "Not enough memory available to start %s.\n", 1.395 + applicationName); 1.396 + } else { 1.397 + Output(true, "Couldn't load XPCOM.\n"); 1.398 + } 1.399 + return 1; 1.400 + } 1.401 + 1.402 + static const nsDynamicFunctionLoad kXULFuncs[] = { 1.403 + { "XRE_CreateAppData", (NSFuncPtr*) &XRE_CreateAppData }, 1.404 + { "XRE_FreeAppData", (NSFuncPtr*) &XRE_FreeAppData }, 1.405 + { "XRE_main", (NSFuncPtr*) &XRE_main }, 1.406 + { nullptr, nullptr } 1.407 + }; 1.408 + 1.409 + rv = XPCOMGlueLoadXULFunctions(kXULFuncs); 1.410 + if (NS_FAILED(rv)) { 1.411 + Output(true, "Couldn't load XRE functions.\n"); 1.412 + return 1; 1.413 + } 1.414 + 1.415 + NS_LogInit(); 1.416 + 1.417 + int retval; 1.418 + 1.419 + { // Scope COMPtr and AutoAppData 1.420 + nsCOMPtr<nsIFile> iniFile; 1.421 +#ifdef XP_WIN 1.422 + // On Windows iniPath is UTF-8 encoded so we need to convert it. 1.423 + rv = NS_NewLocalFile(NS_ConvertUTF8toUTF16(iniPath), false, 1.424 + getter_AddRefs(iniFile)); 1.425 +#else 1.426 + rv = NS_NewNativeLocalFile(nsDependentCString(iniPath), false, 1.427 + getter_AddRefs(iniFile)); 1.428 +#endif 1.429 + if (NS_FAILED(rv)) { 1.430 + Output(true, "Couldn't find application.ini file.\n"); 1.431 + return 1; 1.432 + } 1.433 + 1.434 + AutoAppData appData(iniFile); 1.435 + if (!appData) { 1.436 + Output(true, "Error: couldn't parse application.ini.\n"); 1.437 + return 1; 1.438 + } 1.439 + 1.440 + NS_ASSERTION(appData->directory, "Failed to get app directory."); 1.441 + 1.442 + if (!appData->xreDirectory) { 1.443 + // chop "libxul.so" off the GRE path 1.444 + lastSlash = strrchr(greDir, PATH_SEPARATOR_CHAR); 1.445 + if (lastSlash) { 1.446 + *lastSlash = '\0'; 1.447 + } 1.448 +#ifdef XP_WIN 1.449 + // same as iniPath. 1.450 + NS_NewLocalFile(NS_ConvertUTF8toUTF16(greDir), false, 1.451 + &appData->xreDirectory); 1.452 +#else 1.453 + NS_NewNativeLocalFile(nsDependentCString(greDir), false, 1.454 + &appData->xreDirectory); 1.455 +#endif 1.456 + } 1.457 + 1.458 + retval = XRE_main(argc, argv, appData, 0); 1.459 + } 1.460 + 1.461 + NS_LogTerm(); 1.462 + 1.463 + return retval; 1.464 +}