LCOV - code coverage report
Current view: top level - js/xpconnect/src - XPCShellImpl.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 819 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 46 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim: set ts=8 sts=4 et sw=4 tw=99: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsXULAppAPI.h"
       8             : #include "jsapi.h"
       9             : #include "jsfriendapi.h"
      10             : #include "jsprf.h"
      11             : #include "mozilla/ChaosMode.h"
      12             : #include "mozilla/dom/ScriptSettings.h"
      13             : #include "mozilla/Preferences.h"
      14             : #include "nsServiceManagerUtils.h"
      15             : #include "nsComponentManagerUtils.h"
      16             : #include "nsIServiceManager.h"
      17             : #include "nsIFile.h"
      18             : #include "nsString.h"
      19             : #include "nsIDirectoryService.h"
      20             : #include "nsDirectoryServiceDefs.h"
      21             : #include "nsAppDirectoryServiceDefs.h"
      22             : #include "nscore.h"
      23             : #include "nsArrayEnumerator.h"
      24             : #include "nsCOMArray.h"
      25             : #include "nsDirectoryServiceUtils.h"
      26             : #include "nsCOMPtr.h"
      27             : #include "nsJSPrincipals.h"
      28             : #include "xpcpublic.h"
      29             : #include "xpcprivate.h"
      30             : #include "BackstagePass.h"
      31             : #include "nsIScriptSecurityManager.h"
      32             : #include "nsIPrincipal.h"
      33             : #include "nsJSUtils.h"
      34             : #include "gfxPrefs.h"
      35             : #include "nsIXULRuntime.h"
      36             : #include "GeckoProfiler.h"
      37             : 
      38             : #include "base/histogram.h"
      39             : 
      40             : #ifdef ANDROID
      41             : #include <android/log.h>
      42             : #endif
      43             : 
      44             : #ifdef XP_WIN
      45             : #include "mozilla/widget/AudioSession.h"
      46             : #include <windows.h>
      47             : #if defined(MOZ_SANDBOX)
      48             : #include "SandboxBroker.h"
      49             : #endif
      50             : #endif
      51             : 
      52             : #ifdef MOZ_CODE_COVERAGE
      53             : #include "mozilla/CodeCoverageHandler.h"
      54             : #endif
      55             : 
      56             : // all this crap is needed to do the interactive shell stuff
      57             : #include <stdlib.h>
      58             : #include <errno.h>
      59             : #ifdef HAVE_IO_H
      60             : #include <io.h>     /* for isatty() */
      61             : #endif
      62             : #ifdef HAVE_UNISTD_H
      63             : #include <unistd.h>     /* for isatty() */
      64             : #endif
      65             : 
      66             : #ifdef MOZ_CRASHREPORTER
      67             : #include "nsExceptionHandler.h"
      68             : #include "nsICrashReporter.h"
      69             : #endif
      70             : 
      71             : #ifdef ENABLE_TESTS
      72             : #include "xpctest_private.h"
      73             : #endif
      74             : 
      75             : using namespace mozilla;
      76             : using namespace JS;
      77             : using mozilla::dom::AutoJSAPI;
      78             : using mozilla::dom::AutoEntryScript;
      79             : 
      80             : class XPCShellDirProvider : public nsIDirectoryServiceProvider2
      81             : {
      82             : public:
      83             :     NS_DECL_ISUPPORTS_INHERITED
      84             :     NS_DECL_NSIDIRECTORYSERVICEPROVIDER
      85             :     NS_DECL_NSIDIRECTORYSERVICEPROVIDER2
      86             : 
      87           0 :     XPCShellDirProvider() { }
      88           0 :     ~XPCShellDirProvider() { }
      89             : 
      90             :     // The platform resource folder
      91             :     void SetGREDirs(nsIFile* greDir);
      92           0 :     void ClearGREDirs() { mGREDir = nullptr;
      93           0 :                           mGREBinDir = nullptr; }
      94             :     // The application resource folder
      95             :     void SetAppDir(nsIFile* appFile);
      96           0 :     void ClearAppDir() { mAppDir = nullptr; }
      97             :     // The app executable
      98             :     void SetAppFile(nsIFile* appFile);
      99           0 :     void ClearAppFile() { mAppFile = nullptr; }
     100             :     // An additional custom plugin dir if specified
     101             :     void SetPluginDir(nsIFile* pluginDir);
     102           0 :     void ClearPluginDir() { mPluginDir = nullptr; }
     103             : 
     104             : private:
     105             :     nsCOMPtr<nsIFile> mGREDir;
     106             :     nsCOMPtr<nsIFile> mGREBinDir;
     107             :     nsCOMPtr<nsIFile> mAppDir;
     108             :     nsCOMPtr<nsIFile> mPluginDir;
     109             :     nsCOMPtr<nsIFile> mAppFile;
     110             : };
     111             : 
     112             : #ifdef XP_WIN
     113             : class MOZ_STACK_CLASS AutoAudioSession
     114             : {
     115             : public:
     116             :     AutoAudioSession() {
     117             :         widget::StartAudioSession();
     118             :     }
     119             : 
     120             :     ~AutoAudioSession() {
     121             :         widget::StopAudioSession();
     122             :     }
     123             : };
     124             : #endif
     125             : 
     126             : #define EXITCODE_RUNTIME_ERROR 3
     127             : #define EXITCODE_FILE_NOT_FOUND 4
     128             : 
     129             : static FILE* gOutFile = nullptr;
     130             : static FILE* gErrFile = nullptr;
     131             : static FILE* gInFile = nullptr;
     132             : 
     133             : static int gExitCode = 0;
     134             : static bool gQuitting = false;
     135             : static bool reportWarnings = true;
     136             : static bool compileOnly = false;
     137             : 
     138             : static JSPrincipals* gJSPrincipals = nullptr;
     139             : static nsAutoString* gWorkingDirectory = nullptr;
     140             : 
     141             : static bool
     142           0 : GetLocationProperty(JSContext* cx, unsigned argc, Value* vp)
     143             : {
     144           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     145           0 :     if (!args.thisv().isObject()) {
     146           0 :         JS_ReportErrorASCII(cx, "Unexpected this value for GetLocationProperty");
     147           0 :         return false;
     148             :     }
     149             : #if !defined(XP_WIN) && !defined(XP_UNIX)
     150             :     //XXX: your platform should really implement this
     151             :     return false;
     152             : #else
     153           0 :     JS::AutoFilename filename;
     154           0 :     if (JS::DescribeScriptedCaller(cx, &filename) && filename.get()) {
     155             : #if defined(XP_WIN)
     156             :         // convert from the system codepage to UTF-16
     157             :         int bufferSize = MultiByteToWideChar(CP_ACP, 0, filename.get(),
     158             :                                              -1, nullptr, 0);
     159             :         nsAutoString filenameString;
     160             :         filenameString.SetLength(bufferSize);
     161             :         MultiByteToWideChar(CP_ACP, 0, filename.get(),
     162             :                             -1, (LPWSTR)filenameString.BeginWriting(),
     163             :                             filenameString.Length());
     164             :         // remove the null terminator
     165             :         filenameString.SetLength(bufferSize - 1);
     166             : 
     167             :         // replace forward slashes with backslashes,
     168             :         // since nsLocalFileWin chokes on them
     169             :         char16_t* start = filenameString.BeginWriting();
     170             :         char16_t* end = filenameString.EndWriting();
     171             : 
     172             :         while (start != end) {
     173             :             if (*start == L'/')
     174             :                 *start = L'\\';
     175             :             start++;
     176             :         }
     177             : #elif defined(XP_UNIX)
     178           0 :         NS_ConvertUTF8toUTF16 filenameString(filename.get());
     179             : #endif
     180             : 
     181           0 :         nsCOMPtr<nsIFile> location;
     182           0 :         nsresult rv = NS_NewLocalFile(filenameString,
     183           0 :                                       false, getter_AddRefs(location));
     184             : 
     185           0 :         if (!location && gWorkingDirectory) {
     186             :             // could be a relative path, try appending it to the cwd
     187             :             // and then normalize
     188           0 :             nsAutoString absolutePath(*gWorkingDirectory);
     189           0 :             absolutePath.Append(filenameString);
     190             : 
     191           0 :             rv = NS_NewLocalFile(absolutePath,
     192           0 :                                  false, getter_AddRefs(location));
     193             :         }
     194             : 
     195           0 :         if (location) {
     196             :             bool symlink;
     197             :             // don't normalize symlinks, because that's kind of confusing
     198           0 :             if (NS_SUCCEEDED(location->IsSymlink(&symlink)) &&
     199           0 :                 !symlink)
     200           0 :                 location->Normalize();
     201           0 :             RootedObject locationObj(cx);
     202           0 :             rv = nsXPConnect::XPConnect()->WrapNative(cx, &args.thisv().toObject(),
     203             :                                                       location,
     204             :                                                       NS_GET_IID(nsIFile),
     205           0 :                                                       locationObj.address());
     206           0 :             if (NS_SUCCEEDED(rv) && locationObj) {
     207           0 :                 args.rval().setObject(*locationObj);
     208             :             }
     209             :         }
     210             :     }
     211             : 
     212           0 :     return true;
     213             : #endif
     214             : }
     215             : 
     216             : static bool
     217           0 : GetLine(JSContext* cx, char* bufp, FILE* file, const char* prompt)
     218             : {
     219           0 :     fputs(prompt, gOutFile);
     220           0 :     fflush(gOutFile);
     221             : 
     222           0 :     char line[4096] = { '\0' };
     223             :     while (true) {
     224           0 :         if (fgets(line, sizeof line, file)) {
     225           0 :             strcpy(bufp, line);
     226           0 :             return true;
     227             :         }
     228           0 :         if (errno != EINTR) {
     229           0 :             return false;
     230             :         }
     231             :     }
     232             : }
     233             : 
     234             : static bool
     235           0 : ReadLine(JSContext* cx, unsigned argc, Value* vp)
     236             : {
     237           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     238             : 
     239             :     // While 4096 might be quite arbitrary, this is something to be fixed in
     240             :     // bug 105707. It is also the same limit as in ProcessFile.
     241             :     char buf[4096];
     242           0 :     RootedString str(cx);
     243             : 
     244             :     /* If a prompt was specified, construct the string */
     245           0 :     if (args.length() > 0) {
     246           0 :         str = JS::ToString(cx, args[0]);
     247           0 :         if (!str)
     248           0 :             return false;
     249             :     } else {
     250           0 :         str = JS_GetEmptyString(cx);
     251             :     }
     252             : 
     253             :     /* Get a line from the infile */
     254           0 :     JSAutoByteString strBytes(cx, str);
     255           0 :     if (!strBytes || !GetLine(cx, buf, gInFile, strBytes.ptr()))
     256           0 :         return false;
     257             : 
     258             :     /* Strip newline character added by GetLine() */
     259           0 :     unsigned int buflen = strlen(buf);
     260           0 :     if (buflen == 0) {
     261           0 :         if (feof(gInFile)) {
     262           0 :             args.rval().setNull();
     263           0 :             return true;
     264             :         }
     265           0 :     } else if (buf[buflen - 1] == '\n') {
     266           0 :         --buflen;
     267             :     }
     268             : 
     269             :     /* Turn buf into a JSString */
     270           0 :     str = JS_NewStringCopyN(cx, buf, buflen);
     271           0 :     if (!str)
     272           0 :         return false;
     273             : 
     274           0 :     args.rval().setString(str);
     275           0 :     return true;
     276             : }
     277             : 
     278             : static bool
     279           0 : Print(JSContext* cx, unsigned argc, Value* vp)
     280             : {
     281           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     282           0 :     args.rval().setUndefined();
     283             : 
     284           0 :     RootedString str(cx);
     285           0 :     nsAutoCString utf8output;
     286             : 
     287           0 :     for (unsigned i = 0; i < args.length(); i++) {
     288           0 :         str = ToString(cx, args[i]);
     289           0 :         if (!str)
     290           0 :             return false;
     291             : 
     292           0 :         JSAutoByteString utf8str;
     293           0 :         if (!utf8str.encodeUtf8(cx, str))
     294           0 :             return false;
     295             : 
     296           0 :         if (i)
     297           0 :             utf8output.Append(' ');
     298           0 :         utf8output.Append(utf8str.ptr(), utf8str.length());
     299             :     }
     300           0 :     utf8output.Append('\n');
     301           0 :     fputs(utf8output.get(), gOutFile);
     302           0 :     fflush(gOutFile);
     303           0 :     return true;
     304             : }
     305             : 
     306             : static bool
     307           0 : Dump(JSContext* cx, unsigned argc, Value* vp)
     308             : {
     309           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     310           0 :     args.rval().setUndefined();
     311             : 
     312           0 :     if (!args.length())
     313           0 :          return true;
     314             : 
     315           0 :     RootedString str(cx, ToString(cx, args[0]));
     316           0 :     if (!str)
     317           0 :         return false;
     318             : 
     319           0 :     JSAutoByteString utf8str;
     320           0 :     if (!utf8str.encodeUtf8(cx, str))
     321           0 :         return false;
     322             : 
     323             : #ifdef ANDROID
     324             :     __android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", utf8str.ptr());
     325             : #endif
     326             : #ifdef XP_WIN
     327             :     if (IsDebuggerPresent()) {
     328             :         nsAutoJSString wstr;
     329             :         if (!wstr.init(cx, str))
     330             :             return false;
     331             :         OutputDebugStringW(wstr.get());
     332             :     }
     333             : #endif
     334           0 :     fputs(utf8str.ptr(), gOutFile);
     335           0 :     fflush(gOutFile);
     336           0 :     return true;
     337             : }
     338             : 
     339             : static bool
     340           0 : Load(JSContext* cx, unsigned argc, Value* vp)
     341             : {
     342           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     343             : 
     344           0 :     JS::Rooted<JSObject*> obj(cx, JS_THIS_OBJECT(cx, vp));
     345           0 :     if (!obj)
     346           0 :         return false;
     347             : 
     348           0 :     if (!JS_IsGlobalObject(obj)) {
     349           0 :         JS_ReportErrorASCII(cx, "Trying to load() into a non-global object");
     350           0 :         return false;
     351             :     }
     352             : 
     353           0 :     RootedString str(cx);
     354           0 :     for (unsigned i = 0; i < args.length(); i++) {
     355           0 :         str = ToString(cx, args[i]);
     356           0 :         if (!str)
     357           0 :             return false;
     358           0 :         JSAutoByteString filename(cx, str);
     359           0 :         if (!filename)
     360           0 :             return false;
     361           0 :         FILE* file = fopen(filename.ptr(), "r");
     362           0 :         if (!file) {
     363           0 :             filename.clear();
     364           0 :             if (!filename.encodeUtf8(cx, str))
     365           0 :                 return false;
     366           0 :             JS_ReportErrorUTF8(cx, "cannot open file '%s' for reading",
     367           0 :                                filename.ptr());
     368           0 :             return false;
     369             :         }
     370           0 :         JS::CompileOptions options(cx);
     371           0 :         options.setUTF8(true)
     372           0 :                .setFileAndLine(filename.ptr(), 1)
     373           0 :                .setIsRunOnce(true);
     374           0 :         JS::Rooted<JSScript*> script(cx);
     375           0 :         JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
     376           0 :         JS::Compile(cx, options, file, &script);
     377           0 :         fclose(file);
     378           0 :         if (!script)
     379           0 :             return false;
     380             : 
     381           0 :         if (!compileOnly) {
     382           0 :             if (!JS_ExecuteScript(cx, script)) {
     383           0 :                 return false;
     384             :             }
     385             :         }
     386             :     }
     387           0 :     args.rval().setUndefined();
     388           0 :     return true;
     389             : }
     390             : 
     391             : static bool
     392           0 : Version(JSContext* cx, unsigned argc, Value* vp)
     393             : {
     394           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     395           0 :     args.rval().setInt32(JS_GetVersion(cx));
     396           0 :     if (args.get(0).isInt32())
     397           0 :         JS_SetVersionForCompartment(js::GetContextCompartment(cx),
     398           0 :                                     JSVersion(args[0].toInt32()));
     399           0 :     return true;
     400             : }
     401             : 
     402             : static bool
     403           0 : Quit(JSContext* cx, unsigned argc, Value* vp)
     404             : {
     405           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     406             : 
     407           0 :     gExitCode = 0;
     408           0 :     if (!ToInt32(cx, args.get(0), &gExitCode))
     409           0 :         return false;
     410             : 
     411           0 :     gQuitting = true;
     412             : //    exit(0);
     413           0 :     return false;
     414             : }
     415             : 
     416             : static bool
     417           0 : DumpXPC(JSContext* cx, unsigned argc, Value* vp)
     418             : {
     419           0 :     JS::CallArgs args = CallArgsFromVp(argc, vp);
     420             : 
     421           0 :     uint16_t depth = 2;
     422           0 :     if (args.length() > 0) {
     423           0 :         if (!JS::ToUint16(cx, args[0], &depth))
     424           0 :             return false;
     425             :     }
     426             : 
     427           0 :     nsXPConnect::XPConnect()->DebugDump(int16_t(depth));
     428           0 :     args.rval().setUndefined();
     429           0 :     return true;
     430             : }
     431             : 
     432             : static bool
     433           0 : GC(JSContext* cx, unsigned argc, Value* vp)
     434             : {
     435           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     436             : 
     437           0 :     JS_GC(cx);
     438             : 
     439           0 :     args.rval().setUndefined();
     440           0 :     return true;
     441             : }
     442             : 
     443             : #ifdef JS_GC_ZEAL
     444             : static bool
     445           0 : GCZeal(JSContext* cx, unsigned argc, Value* vp)
     446             : {
     447           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     448             :     uint32_t zeal;
     449           0 :     if (!ToUint32(cx, args.get(0), &zeal))
     450           0 :         return false;
     451             : 
     452           0 :     JS_SetGCZeal(cx, uint8_t(zeal), JS_DEFAULT_ZEAL_FREQ);
     453           0 :     args.rval().setUndefined();
     454           0 :     return true;
     455             : }
     456             : #endif
     457             : 
     458             : static bool
     459           0 : SendCommand(JSContext* cx, unsigned argc, Value* vp)
     460             : {
     461           0 :     CallArgs args = CallArgsFromVp(argc, vp);
     462             : 
     463           0 :     if (args.length() == 0) {
     464           0 :         JS_ReportErrorASCII(cx, "Function takes at least one argument!");
     465           0 :         return false;
     466             :     }
     467             : 
     468           0 :     RootedString str(cx, ToString(cx, args[0]));
     469           0 :     if (!str) {
     470           0 :         JS_ReportErrorASCII(cx, "Could not convert argument 1 to string!");
     471           0 :         return false;
     472             :     }
     473             : 
     474           0 :     if (args.length() > 1 && JS_TypeOfValue(cx, args[1]) != JSTYPE_FUNCTION) {
     475           0 :         JS_ReportErrorASCII(cx, "Could not convert argument 2 to function!");
     476           0 :         return false;
     477             :     }
     478             : 
     479           0 :     if (!XRE_SendTestShellCommand(cx, str, args.length() > 1 ? args[1].address() : nullptr)) {
     480           0 :         JS_ReportErrorASCII(cx, "Couldn't send command!");
     481           0 :         return false;
     482             :     }
     483             : 
     484           0 :     args.rval().setUndefined();
     485           0 :     return true;
     486             : }
     487             : 
     488             : static bool
     489           0 : Options(JSContext* cx, unsigned argc, Value* vp)
     490             : {
     491           0 :     JS::CallArgs args = CallArgsFromVp(argc, vp);
     492           0 :     ContextOptions oldContextOptions = ContextOptionsRef(cx);
     493             : 
     494           0 :     RootedString str(cx);
     495           0 :     JSAutoByteString opt;
     496           0 :     for (unsigned i = 0; i < args.length(); ++i) {
     497           0 :         str = ToString(cx, args[i]);
     498           0 :         if (!str)
     499           0 :             return false;
     500             : 
     501           0 :         opt.clear();
     502           0 :         if (!opt.encodeUtf8(cx, str))
     503           0 :             return false;
     504             : 
     505           0 :         if (strcmp(opt.ptr(), "strict") == 0)
     506           0 :             ContextOptionsRef(cx).toggleExtraWarnings();
     507           0 :         else if (strcmp(opt.ptr(), "werror") == 0)
     508           0 :             ContextOptionsRef(cx).toggleWerror();
     509           0 :         else if (strcmp(opt.ptr(), "strict_mode") == 0)
     510           0 :             ContextOptionsRef(cx).toggleStrictMode();
     511             :         else {
     512           0 :             JS_ReportErrorUTF8(cx, "unknown option name '%s'. The valid names are "
     513           0 :                                "strict, werror, and strict_mode.", opt.ptr());
     514           0 :             return false;
     515             :         }
     516             :     }
     517             : 
     518           0 :     UniqueChars names;
     519           0 :     if (oldContextOptions.extraWarnings()) {
     520           0 :         names = JS_sprintf_append(Move(names), "%s", "strict");
     521           0 :         if (!names) {
     522           0 :             JS_ReportOutOfMemory(cx);
     523           0 :             return false;
     524             :         }
     525             :     }
     526           0 :     if (oldContextOptions.werror()) {
     527           0 :         names = JS_sprintf_append(Move(names), "%s%s", names ? "," : "", "werror");
     528           0 :         if (!names) {
     529           0 :             JS_ReportOutOfMemory(cx);
     530           0 :             return false;
     531             :         }
     532             :     }
     533           0 :     if (names && oldContextOptions.strictMode()) {
     534           0 :         names = JS_sprintf_append(Move(names), "%s%s", names ? "," : "", "strict_mode");
     535           0 :         if (!names) {
     536           0 :             JS_ReportOutOfMemory(cx);
     537           0 :             return false;
     538             :         }
     539             :     }
     540             : 
     541           0 :     str = JS_NewStringCopyZ(cx, names.get());
     542           0 :     if (!str)
     543           0 :         return false;
     544             : 
     545           0 :     args.rval().setString(str);
     546           0 :     return true;
     547             : }
     548             : 
     549             : static PersistentRootedValue *sScriptedInterruptCallback = nullptr;
     550             : 
     551             : static bool
     552           0 : XPCShellInterruptCallback(JSContext* cx)
     553             : {
     554           0 :     MOZ_ASSERT(sScriptedInterruptCallback->initialized());
     555           0 :     RootedValue callback(cx, *sScriptedInterruptCallback);
     556             : 
     557             :     // If no interrupt callback was set by script, no-op.
     558           0 :     if (callback.isUndefined())
     559           0 :         return true;
     560             : 
     561           0 :     JSAutoCompartment ac(cx, &callback.toObject());
     562           0 :     RootedValue rv(cx);
     563           0 :     if (!JS_CallFunctionValue(cx, nullptr, callback, JS::HandleValueArray::empty(), &rv) ||
     564           0 :         !rv.isBoolean())
     565             :     {
     566           0 :         NS_WARNING("Scripted interrupt callback failed! Terminating script.");
     567           0 :         JS_ClearPendingException(cx);
     568           0 :         return false;
     569             :     }
     570             : 
     571           0 :     return rv.toBoolean();
     572             : }
     573             : 
     574             : static bool
     575           0 : SetInterruptCallback(JSContext* cx, unsigned argc, Value* vp)
     576             : {
     577           0 :     MOZ_ASSERT(sScriptedInterruptCallback->initialized());
     578             : 
     579             :     // Sanity-check args.
     580           0 :     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     581           0 :     if (args.length() != 1) {
     582           0 :         JS_ReportErrorASCII(cx, "Wrong number of arguments");
     583           0 :         return false;
     584             :     }
     585             : 
     586             :     // Allow callers to remove the interrupt callback by passing undefined.
     587           0 :     if (args[0].isUndefined()) {
     588           0 :         *sScriptedInterruptCallback = UndefinedValue();
     589           0 :         return true;
     590             :     }
     591             : 
     592             :     // Otherwise, we should have a callable object.
     593           0 :     if (!args[0].isObject() || !JS::IsCallable(&args[0].toObject())) {
     594           0 :         JS_ReportErrorASCII(cx, "Argument must be callable");
     595           0 :         return false;
     596             :     }
     597             : 
     598           0 :     *sScriptedInterruptCallback = args[0];
     599             : 
     600           0 :     return true;
     601             : }
     602             : 
     603             : static bool
     604           0 : SimulateActivityCallback(JSContext* cx, unsigned argc, Value* vp)
     605             : {
     606             :     // Sanity-check args.
     607           0 :     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     608           0 :     if (args.length() != 1 || !args[0].isBoolean()) {
     609           0 :         JS_ReportErrorASCII(cx, "Wrong number of arguments");
     610           0 :         return false;
     611             :     }
     612           0 :     xpc::SimulateActivityCallback(args[0].toBoolean());
     613           0 :     return true;
     614             : }
     615             : 
     616             : static bool
     617           0 : RegisterAppManifest(JSContext* cx, unsigned argc, Value* vp)
     618             : {
     619           0 :     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     620           0 :     if (args.length() != 1) {
     621           0 :         JS_ReportErrorASCII(cx, "Wrong number of arguments");
     622           0 :         return false;
     623             :     }
     624           0 :     if (!args[0].isObject()) {
     625           0 :         JS_ReportErrorASCII(cx, "Expected object as argument 1 to registerAppManifest");
     626           0 :         return false;
     627             :     }
     628             : 
     629           0 :     Rooted<JSObject*> arg1(cx, &args[0].toObject());
     630           0 :     nsCOMPtr<nsIFile> file;
     631             :     nsresult rv = nsXPConnect::XPConnect()->
     632           0 :         WrapJS(cx, arg1, NS_GET_IID(nsIFile), getter_AddRefs(file));
     633           0 :     if (NS_FAILED(rv)) {
     634           0 :         XPCThrower::Throw(rv, cx);
     635           0 :         return false;
     636             :     }
     637           0 :     rv = XRE_AddManifestLocation(NS_APP_LOCATION, file);
     638           0 :     if (NS_FAILED(rv)) {
     639           0 :         XPCThrower::Throw(rv, cx);
     640           0 :         return false;
     641             :     }
     642           0 :     return true;
     643             : }
     644             : 
     645             : #ifdef ENABLE_TESTS
     646             : static bool
     647           0 : RegisterXPCTestComponents(JSContext* cx, unsigned argc, Value* vp)
     648             : {
     649           0 :     JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
     650           0 :     if (args.length() != 0) {
     651           0 :         JS_ReportErrorASCII(cx, "Wrong number of arguments");
     652           0 :         return false;
     653             :     }
     654           0 :     nsresult rv = XRE_AddStaticComponent(&kXPCTestModule);
     655           0 :     if (NS_FAILED(rv)) {
     656           0 :         XPCThrower::Throw(rv, cx);
     657           0 :         return false;
     658             :     }
     659           0 :     return true;
     660             : }
     661             : #endif
     662             : 
     663             : static const JSFunctionSpec glob_functions[] = {
     664             :     JS_FS("print",           Print,          0,0),
     665             :     JS_FS("readline",        ReadLine,       1,0),
     666             :     JS_FS("load",            Load,           1,0),
     667             :     JS_FS("quit",            Quit,           0,0),
     668             :     JS_FS("version",         Version,        1,0),
     669             :     JS_FS("dumpXPC",         DumpXPC,        1,0),
     670             :     JS_FS("dump",            Dump,           1,0),
     671             :     JS_FS("gc",              GC,             0,0),
     672             : #ifdef JS_GC_ZEAL
     673             :     JS_FS("gczeal",          GCZeal,         1,0),
     674             : #endif
     675             :     JS_FS("options",         Options,        0,0),
     676             :     JS_FS("sendCommand",     SendCommand,    1,0),
     677             :     JS_FS("atob",            xpc::Atob,      1,0),
     678             :     JS_FS("btoa",            xpc::Btoa,      1,0),
     679             :     JS_FS("setInterruptCallback", SetInterruptCallback, 1,0),
     680             :     JS_FS("simulateActivityCallback", SimulateActivityCallback, 1,0),
     681             :     JS_FS("registerAppManifest", RegisterAppManifest, 1, 0),
     682             : #ifdef ENABLE_TESTS
     683             :     JS_FS("registerXPCTestComponents", RegisterXPCTestComponents, 0, 0),
     684             : #endif
     685             :     JS_FS_END
     686             : };
     687             : 
     688             : static bool
     689           0 : env_setProperty(JSContext* cx, HandleObject obj, HandleId id, MutableHandleValue vp,
     690             :                 ObjectOpResult& result)
     691             : {
     692             : /* XXX porting may be easy, but these don't seem to supply setenv by default */
     693             : #if !defined SOLARIS
     694           0 :     RootedString valstr(cx);
     695           0 :     RootedString idstr(cx);
     696             :     int rv;
     697             : 
     698           0 :     RootedValue idval(cx);
     699           0 :     if (!JS_IdToValue(cx, id, &idval))
     700           0 :         return false;
     701             : 
     702           0 :     idstr = ToString(cx, idval);
     703           0 :     valstr = ToString(cx, vp);
     704           0 :     if (!idstr || !valstr)
     705           0 :         return false;
     706           0 :     JSAutoByteString name(cx, idstr);
     707           0 :     if (!name)
     708           0 :         return false;
     709           0 :     JSAutoByteString value(cx, valstr);
     710           0 :     if (!value)
     711           0 :         return false;
     712             : #if defined XP_WIN || defined HPUX || defined OSF1 || defined SCO
     713             :     {
     714             :         char* waste = JS_smprintf("%s=%s", name.ptr(), value.ptr()).release();
     715             :         if (!waste) {
     716             :             JS_ReportOutOfMemory(cx);
     717             :             return false;
     718             :         }
     719             :         rv = putenv(waste);
     720             : #ifdef XP_WIN
     721             :         /*
     722             :          * HPUX9 at least still has the bad old non-copying putenv.
     723             :          *
     724             :          * Per mail from <s.shanmuganathan@digital.com>, OSF1 also has a putenv
     725             :          * that will crash if you pass it an auto char array (so it must place
     726             :          * its argument directly in the char* environ[] array).
     727             :          */
     728             :         free(waste);
     729             : #endif
     730             :     }
     731             : #else
     732           0 :     rv = setenv(name.ptr(), value.ptr(), 1);
     733             : #endif
     734           0 :     if (rv < 0) {
     735           0 :         name.clear();
     736           0 :         value.clear();
     737           0 :         if (!name.encodeUtf8(cx, idstr))
     738           0 :             return false;
     739           0 :         if (!value.encodeUtf8(cx, valstr))
     740           0 :             return false;
     741           0 :         JS_ReportErrorUTF8(cx, "can't set envariable %s to %s", name.ptr(), value.ptr());
     742           0 :         return false;
     743             :     }
     744           0 :     vp.setString(valstr);
     745             : #endif /* !defined SOLARIS */
     746           0 :     return result.succeed();
     747             : }
     748             : 
     749             : static bool
     750           0 : env_enumerate(JSContext* cx, HandleObject obj)
     751             : {
     752             :     static bool reflected;
     753             :     char** evp;
     754             :     char* name;
     755             :     char* value;
     756           0 :     RootedString valstr(cx);
     757             :     bool ok;
     758             : 
     759           0 :     if (reflected)
     760           0 :         return true;
     761             : 
     762           0 :     for (evp = (char**)JS_GetPrivate(obj); (name = *evp) != nullptr; evp++) {
     763           0 :         value = strchr(name, '=');
     764           0 :         if (!value)
     765           0 :             continue;
     766           0 :         *value++ = '\0';
     767           0 :         valstr = JS_NewStringCopyZ(cx, value);
     768           0 :         ok = valstr ? JS_DefineProperty(cx, obj, name, valstr, JSPROP_ENUMERATE) : false;
     769           0 :         value[-1] = '=';
     770           0 :         if (!ok)
     771           0 :             return false;
     772             :     }
     773             : 
     774           0 :     reflected = true;
     775           0 :     return true;
     776             : }
     777             : 
     778             : static bool
     779           0 : env_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp)
     780             : {
     781             :     JSString* idstr;
     782             : 
     783           0 :     RootedValue idval(cx);
     784           0 :     if (!JS_IdToValue(cx, id, &idval))
     785           0 :         return false;
     786             : 
     787           0 :     idstr = ToString(cx, idval);
     788           0 :     if (!idstr)
     789           0 :         return false;
     790           0 :     JSAutoByteString name(cx, idstr);
     791           0 :     if (!name)
     792           0 :         return false;
     793           0 :     const char* value = getenv(name.ptr());
     794           0 :     if (value) {
     795           0 :         RootedString valstr(cx, JS_NewStringCopyZ(cx, value));
     796           0 :         if (!valstr)
     797           0 :             return false;
     798           0 :         if (!JS_DefinePropertyById(cx, obj, id, valstr, JSPROP_ENUMERATE)) {
     799           0 :             return false;
     800             :         }
     801           0 :         *resolvedp = true;
     802             :     }
     803           0 :     return true;
     804             : }
     805             : 
     806             : static const JSClassOps env_classOps = {
     807             :     nullptr, nullptr, nullptr, env_setProperty,
     808             :     env_enumerate, nullptr, env_resolve
     809             : };
     810             : 
     811             : static const JSClass env_class = {
     812             :     "environment", JSCLASS_HAS_PRIVATE,
     813             :     &env_classOps
     814             : };
     815             : 
     816             : /***************************************************************************/
     817             : 
     818             : typedef enum JSShellErrNum {
     819             : #define MSG_DEF(name, number, count, exception, format) \
     820             :     name = number,
     821             : #include "jsshell.msg"
     822             : #undef MSG_DEF
     823             :     JSShellErr_Limit
     824             : } JSShellErrNum;
     825             : 
     826             : static const JSErrorFormatString jsShell_ErrorFormatString[JSShellErr_Limit] = {
     827             : #define MSG_DEF(name, number, count, exception, format) \
     828             :     { #name, format, count } ,
     829             : #include "jsshell.msg"
     830             : #undef MSG_DEF
     831             : };
     832             : 
     833             : static const JSErrorFormatString*
     834           0 : my_GetErrorMessage(void* userRef, const unsigned errorNumber)
     835             : {
     836           0 :     if (errorNumber == 0 || errorNumber >= JSShellErr_Limit)
     837           0 :         return nullptr;
     838             : 
     839           0 :     return &jsShell_ErrorFormatString[errorNumber];
     840             : }
     841             : 
     842             : static bool
     843           0 : ProcessLine(AutoJSAPI& jsapi, const char* buffer, int startline)
     844             : {
     845           0 :     JSContext* cx = jsapi.cx();
     846           0 :     JS::RootedScript script(cx);
     847           0 :     JS::RootedValue result(cx);
     848           0 :     JS::CompileOptions options(cx);
     849           0 :     options.setFileAndLine("typein", startline)
     850           0 :            .setIsRunOnce(true);
     851           0 :     if (!JS_CompileScript(cx, buffer, strlen(buffer), options, &script))
     852           0 :         return false;
     853           0 :     if (compileOnly)
     854           0 :         return true;
     855           0 :     if (!JS_ExecuteScript(cx, script, &result))
     856           0 :         return false;
     857             : 
     858           0 :     if (result.isUndefined())
     859           0 :         return true;
     860           0 :     RootedString str(cx);
     861           0 :     if (!(str = ToString(cx, result)))
     862           0 :         return false;
     863           0 :     JSAutoByteString bytes;
     864           0 :     if (!bytes.encodeLatin1(cx, str))
     865           0 :         return false;
     866             : 
     867           0 :     fprintf(gOutFile, "%s\n", bytes.ptr());
     868           0 :     return true;
     869             : }
     870             : 
     871             : static bool
     872           0 : ProcessFile(AutoJSAPI& jsapi, const char* filename, FILE* file, bool forceTTY)
     873             : {
     874           0 :     JSContext* cx = jsapi.cx();
     875           0 :     JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
     876           0 :     MOZ_ASSERT(global);
     877             : 
     878           0 :     if (forceTTY) {
     879           0 :         file = stdin;
     880           0 :     } else if (!isatty(fileno(file))) {
     881             :         /*
     882             :          * It's not interactive - just execute it.
     883             :          *
     884             :          * Support the UNIX #! shell hack; gobble the first line if it starts
     885             :          * with '#'.  TODO - this isn't quite compatible with sharp variables,
     886             :          * as a legal js program (using sharp variables) might start with '#'.
     887             :          * But that would require multi-character lookahead.
     888             :          */
     889           0 :         int ch = fgetc(file);
     890           0 :         if (ch == '#') {
     891           0 :             while ((ch = fgetc(file)) != EOF) {
     892           0 :                 if (ch == '\n' || ch == '\r')
     893             :                     break;
     894             :             }
     895             :         }
     896           0 :         ungetc(ch, file);
     897             : 
     898           0 :         JS::RootedScript script(cx);
     899           0 :         JS::RootedValue unused(cx);
     900           0 :         JS::CompileOptions options(cx);
     901           0 :         options.setUTF8(true)
     902           0 :                .setFileAndLine(filename, 1)
     903           0 :                .setIsRunOnce(true)
     904           0 :                .setNoScriptRval(true);
     905           0 :         if (!JS::Compile(cx, options, file, &script))
     906           0 :             return false;
     907           0 :         return compileOnly || JS_ExecuteScript(cx, script, &unused);
     908             :     }
     909             : 
     910             :     /* It's an interactive filehandle; drop into read-eval-print loop. */
     911           0 :     int lineno = 1;
     912           0 :     bool hitEOF = false;
     913           0 :     do {
     914             :         char buffer[4096];
     915           0 :         char* bufp = buffer;
     916           0 :         *bufp = '\0';
     917             : 
     918             :         /*
     919             :          * Accumulate lines until we get a 'compilable unit' - one that either
     920             :          * generates an error (before running out of source) or that compiles
     921             :          * cleanly.  This should be whenever we get a complete statement that
     922             :          * coincides with the end of a line.
     923             :          */
     924           0 :         int startline = lineno;
     925           0 :         do {
     926           0 :             if (!GetLine(cx, bufp, file, startline == lineno ? "js> " : "")) {
     927           0 :                 hitEOF = true;
     928           0 :                 break;
     929             :             }
     930           0 :             bufp += strlen(bufp);
     931           0 :             lineno++;
     932           0 :         } while (!JS_BufferIsCompilableUnit(cx, global, buffer, strlen(buffer)));
     933             : 
     934           0 :         if (!ProcessLine(jsapi, buffer, startline))
     935           0 :             jsapi.ReportException();
     936           0 :     } while (!hitEOF && !gQuitting);
     937             : 
     938           0 :     fprintf(gOutFile, "\n");
     939           0 :     return true;
     940             : }
     941             : 
     942             : static bool
     943           0 : Process(AutoJSAPI& jsapi, const char* filename, bool forceTTY)
     944             : {
     945             :     FILE* file;
     946             : 
     947           0 :     if (forceTTY || !filename || strcmp(filename, "-") == 0) {
     948           0 :         file = stdin;
     949             :     } else {
     950           0 :         file = fopen(filename, "r");
     951           0 :         if (!file) {
     952             :             /*
     953             :              * Use Latin1 variant here because the encoding of the return value
     954             :              * of strerror function can be non-UTF-8.
     955             :              */
     956           0 :             JS_ReportErrorNumberLatin1(jsapi.cx(), my_GetErrorMessage, nullptr,
     957             :                                        JSSMSG_CANT_OPEN,
     958           0 :                                        filename, strerror(errno));
     959           0 :             gExitCode = EXITCODE_FILE_NOT_FOUND;
     960           0 :             return false;
     961             :         }
     962             :     }
     963             : 
     964           0 :     bool ok = ProcessFile(jsapi, filename, file, forceTTY);
     965           0 :     if (file != stdin)
     966           0 :         fclose(file);
     967           0 :     return ok;
     968             : }
     969             : 
     970             : static int
     971           0 : usage()
     972             : {
     973           0 :     fprintf(gErrFile, "%s\n", JS_GetImplementationVersion());
     974           0 :     fprintf(gErrFile, "usage: xpcshell [-g gredir] [-a appdir] [-r manifest]... [-WwxiCSsmIp] [-v version] [-f scriptfile] [-e script] [scriptfile] [scriptarg...]\n");
     975           0 :     return 2;
     976             : }
     977             : 
     978             : static bool
     979           0 : printUsageAndSetExitCode()
     980             : {
     981           0 :     gExitCode = usage();
     982           0 :     return false;
     983             : }
     984             : 
     985             : static void
     986           0 : ProcessArgsForCompartment(JSContext* cx, char** argv, int argc)
     987             : {
     988           0 :     for (int i = 0; i < argc; i++) {
     989           0 :         if (argv[i][0] != '-' || argv[i][1] == '\0')
     990             :             break;
     991             : 
     992           0 :         switch (argv[i][1]) {
     993             :           case 'v':
     994             :           case 'f':
     995             :           case 'e':
     996           0 :             if (++i == argc)
     997           0 :                 return;
     998           0 :             break;
     999             :         case 'S':
    1000           0 :             ContextOptionsRef(cx).toggleWerror();
    1001             :             MOZ_FALLTHROUGH; // because -S implies -s
    1002             :         case 's':
    1003           0 :             ContextOptionsRef(cx).toggleExtraWarnings();
    1004           0 :             break;
    1005             :         case 'I':
    1006           0 :             ContextOptionsRef(cx).toggleIon()
    1007           0 :                                  .toggleAsmJS()
    1008           0 :                                  .toggleWasm();
    1009           0 :             break;
    1010             :         }
    1011             :     }
    1012             : }
    1013             : 
    1014             : static bool
    1015           0 : ProcessArgs(AutoJSAPI& jsapi, char** argv, int argc, XPCShellDirProvider* aDirProvider)
    1016             : {
    1017           0 :     JSContext* cx = jsapi.cx();
    1018           0 :     const char rcfilename[] = "xpcshell.js";
    1019             :     FILE* rcfile;
    1020             :     int rootPosition;
    1021           0 :     JS::Rooted<JSObject*> argsObj(cx);
    1022           0 :     char* filename = nullptr;
    1023           0 :     bool isInteractive = true;
    1024           0 :     bool forceTTY = false;
    1025             : 
    1026           0 :     rcfile = fopen(rcfilename, "r");
    1027           0 :     if (rcfile) {
    1028           0 :         printf("[loading '%s'...]\n", rcfilename);
    1029           0 :         bool ok = ProcessFile(jsapi, rcfilename, rcfile, false);
    1030           0 :         fclose(rcfile);
    1031           0 :         if (!ok) {
    1032           0 :             return false;
    1033             :         }
    1034             :     }
    1035             : 
    1036           0 :     JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
    1037             : 
    1038             :     /*
    1039             :      * Scan past all optional arguments so we can create the arguments object
    1040             :      * before processing any -f options, which must interleave properly with
    1041             :      * -v and -w options.  This requires two passes, and without getopt, we'll
    1042             :      * have to keep the option logic here and in the second for loop in sync.
    1043             :      * First of all, find out the first argument position which will be passed
    1044             :      * as a script file to be executed.
    1045             :      */
    1046           0 :     for (rootPosition = 0; rootPosition < argc; rootPosition++) {
    1047           0 :         if (argv[rootPosition][0] != '-' || argv[rootPosition][1] == '\0') {
    1048           0 :             ++rootPosition;
    1049           0 :             break;
    1050             :         }
    1051             : 
    1052             :         bool isPairedFlag =
    1053           0 :             argv[rootPosition][0] != '\0' &&
    1054           0 :             (argv[rootPosition][1] == 'v' ||
    1055           0 :              argv[rootPosition][1] == 'f' ||
    1056           0 :              argv[rootPosition][1] == 'e');
    1057           0 :         if (isPairedFlag && rootPosition < argc - 1) {
    1058           0 :           ++rootPosition; // Skip over the 'foo' portion of |-v foo|, |-f foo|, or |-e foo|.
    1059             :         }
    1060             :     }
    1061             : 
    1062             :     /*
    1063             :      * Create arguments early and define it to root it, so it's safe from any
    1064             :      * GC calls nested below, and so it is available to -f <file> arguments.
    1065             :      */
    1066           0 :     argsObj = JS_NewArrayObject(cx, 0);
    1067           0 :     if (!argsObj)
    1068           0 :         return 1;
    1069           0 :     if (!JS_DefineProperty(cx, global, "arguments", argsObj, 0))
    1070           0 :         return 1;
    1071             : 
    1072           0 :     for (int j = 0, length = argc - rootPosition; j < length; j++) {
    1073           0 :         RootedString str(cx, JS_NewStringCopyZ(cx, argv[rootPosition++]));
    1074           0 :         if (!str ||
    1075           0 :             !JS_DefineElement(cx, argsObj, j, str, JSPROP_ENUMERATE)) {
    1076           0 :             return 1;
    1077             :         }
    1078             :     }
    1079             : 
    1080           0 :     for (int i = 0; i < argc; i++) {
    1081           0 :         if (argv[i][0] != '-' || argv[i][1] == '\0') {
    1082           0 :             filename = argv[i++];
    1083           0 :             isInteractive = false;
    1084           0 :             break;
    1085             :         }
    1086           0 :         switch (argv[i][1]) {
    1087             :         case 'v':
    1088           0 :             if (++i == argc) {
    1089           0 :                 return printUsageAndSetExitCode();
    1090             :             }
    1091           0 :             JS_SetVersionForCompartment(js::GetContextCompartment(cx),
    1092           0 :                                         JSVersion(atoi(argv[i])));
    1093           0 :             break;
    1094             :         case 'W':
    1095           0 :             reportWarnings = false;
    1096           0 :             break;
    1097             :         case 'w':
    1098           0 :             reportWarnings = true;
    1099           0 :             break;
    1100             :         case 'x':
    1101           0 :             break;
    1102             :         case 'd':
    1103             :             /* This used to try to turn on the debugger. */
    1104           0 :             break;
    1105             :         case 'm':
    1106           0 :             break;
    1107             :         case 'f':
    1108           0 :             if (++i == argc) {
    1109           0 :                 return printUsageAndSetExitCode();
    1110             :             }
    1111           0 :             if (!Process(jsapi, argv[i], false))
    1112           0 :                 return false;
    1113             :             /*
    1114             :              * XXX: js -f foo.js should interpret foo.js and then
    1115             :              * drop into interactive mode, but that breaks test
    1116             :              * harness. Just execute foo.js for now.
    1117             :              */
    1118           0 :             isInteractive = false;
    1119           0 :             break;
    1120             :         case 'i':
    1121           0 :             isInteractive = forceTTY = true;
    1122           0 :             break;
    1123             :         case 'e':
    1124             :         {
    1125           0 :             RootedValue rval(cx);
    1126             : 
    1127           0 :             if (++i == argc) {
    1128           0 :                 return printUsageAndSetExitCode();
    1129             :             }
    1130             : 
    1131           0 :             JS::CompileOptions opts(cx);
    1132           0 :             opts.setFileAndLine("-e", 1);
    1133           0 :             JS::Evaluate(cx, opts, argv[i], strlen(argv[i]), &rval);
    1134             : 
    1135           0 :             isInteractive = false;
    1136           0 :             break;
    1137             :         }
    1138             :         case 'C':
    1139           0 :             compileOnly = true;
    1140           0 :             isInteractive = false;
    1141           0 :             break;
    1142             :         case 'S':
    1143             :         case 's':
    1144             :         case 'I':
    1145             :             // These options are processed in ProcessArgsForCompartment.
    1146           0 :             break;
    1147             :         case 'p':
    1148             :         {
    1149             :           // plugins path
    1150           0 :           char* pluginPath = argv[++i];
    1151           0 :           nsCOMPtr<nsIFile> pluginsDir;
    1152           0 :           if (NS_FAILED(XRE_GetFileFromPath(pluginPath, getter_AddRefs(pluginsDir)))) {
    1153           0 :               fprintf(gErrFile, "Couldn't use given plugins dir.\n");
    1154           0 :               return printUsageAndSetExitCode();
    1155             :           }
    1156           0 :           aDirProvider->SetPluginDir(pluginsDir);
    1157           0 :           break;
    1158             :         }
    1159             :         default:
    1160           0 :             return printUsageAndSetExitCode();
    1161             :         }
    1162             :     }
    1163             : 
    1164           0 :     if (filename || isInteractive)
    1165           0 :         return Process(jsapi, filename, forceTTY);
    1166           0 :     return true;
    1167             : }
    1168             : 
    1169             : /***************************************************************************/
    1170             : 
    1171             : static bool
    1172           0 : GetCurrentWorkingDirectory(nsAString& workingDirectory)
    1173             : {
    1174             : #if !defined(XP_WIN) && !defined(XP_UNIX)
    1175             :     //XXX: your platform should really implement this
    1176             :     return false;
    1177             : #elif XP_WIN
    1178             :     DWORD requiredLength = GetCurrentDirectoryW(0, nullptr);
    1179             :     workingDirectory.SetLength(requiredLength);
    1180             :     GetCurrentDirectoryW(workingDirectory.Length(),
    1181             :                          (LPWSTR)workingDirectory.BeginWriting());
    1182             :     // we got a trailing null there
    1183             :     workingDirectory.SetLength(requiredLength);
    1184             :     workingDirectory.Replace(workingDirectory.Length() - 1, 1, L'\\');
    1185             : #elif defined(XP_UNIX)
    1186           0 :     nsAutoCString cwd;
    1187             :     // 1024 is just a guess at a sane starting value
    1188           0 :     size_t bufsize = 1024;
    1189           0 :     char* result = nullptr;
    1190           0 :     while (result == nullptr) {
    1191           0 :         cwd.SetLength(bufsize);
    1192           0 :         result = getcwd(cwd.BeginWriting(), cwd.Length());
    1193           0 :         if (!result) {
    1194           0 :             if (errno != ERANGE)
    1195           0 :                 return false;
    1196             :             // need to make the buffer bigger
    1197           0 :             bufsize *= 2;
    1198             :         }
    1199             :     }
    1200             :     // size back down to the actual string length
    1201           0 :     cwd.SetLength(strlen(result) + 1);
    1202           0 :     cwd.Replace(cwd.Length() - 1, 1, '/');
    1203           0 :     workingDirectory = NS_ConvertUTF8toUTF16(cwd);
    1204             : #endif
    1205           0 :     return true;
    1206             : }
    1207             : 
    1208             : static JSSecurityCallbacks shellSecurityCallbacks;
    1209             : 
    1210             : int
    1211           0 : XRE_XPCShellMain(int argc, char** argv, char** envp,
    1212             :                  const XREShellData* aShellData)
    1213             : {
    1214           0 :     MOZ_ASSERT(aShellData);
    1215             : 
    1216             :     JSContext* cx;
    1217           0 :     int result = 0;
    1218             :     nsresult rv;
    1219             : 
    1220           0 :     gErrFile = stderr;
    1221           0 :     gOutFile = stdout;
    1222           0 :     gInFile = stdin;
    1223             : 
    1224           0 :     NS_LogInit();
    1225             : 
    1226           0 :     mozilla::LogModule::Init();
    1227             : 
    1228             :     // A initializer to initialize histogram collection
    1229             :     // used by telemetry.
    1230             :     auto telStats =
    1231           0 :        mozilla::MakeUnique<base::StatisticsRecorder>();
    1232             : 
    1233             :     char aLocal;
    1234           0 :     profiler_init(&aLocal);
    1235             : 
    1236           0 :     if (PR_GetEnv("MOZ_CHAOSMODE")) {
    1237           0 :         ChaosFeature feature = ChaosFeature::Any;
    1238           0 :         long featureInt = strtol(PR_GetEnv("MOZ_CHAOSMODE"), nullptr, 16);
    1239           0 :         if (featureInt) {
    1240             :             // NOTE: MOZ_CHAOSMODE=0 or a non-hex value maps to Any feature.
    1241           0 :             feature = static_cast<ChaosFeature>(featureInt);
    1242             :         }
    1243           0 :         ChaosMode::SetChaosFeature(feature);
    1244             :     }
    1245             : 
    1246           0 :     if (ChaosMode::isActive(ChaosFeature::Any)) {
    1247           0 :         printf_stderr("*** You are running in chaos test mode. See ChaosMode.h. ***\n");
    1248             :     }
    1249             : 
    1250             :     // The provider needs to outlive the call to shutting down XPCOM.
    1251           0 :     XPCShellDirProvider dirprovider;
    1252             : 
    1253             :     { // Start scoping nsCOMPtrs
    1254           0 :         nsCOMPtr<nsIFile> appFile;
    1255           0 :         rv = XRE_GetBinaryPath(argv[0], getter_AddRefs(appFile));
    1256           0 :         if (NS_FAILED(rv)) {
    1257           0 :             printf("Couldn't find application file.\n");
    1258           0 :             return 1;
    1259             :         }
    1260           0 :         nsCOMPtr<nsIFile> appDir;
    1261           0 :         rv = appFile->GetParent(getter_AddRefs(appDir));
    1262           0 :         if (NS_FAILED(rv)) {
    1263           0 :             printf("Couldn't get application directory.\n");
    1264           0 :             return 1;
    1265             :         }
    1266             : 
    1267           0 :         dirprovider.SetAppFile(appFile);
    1268             : 
    1269           0 :         nsCOMPtr<nsIFile> greDir;
    1270           0 :         if (argc > 1 && !strcmp(argv[1], "-g")) {
    1271           0 :             if (argc < 3)
    1272           0 :                 return usage();
    1273             : 
    1274           0 :             rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(greDir));
    1275           0 :             if (NS_FAILED(rv)) {
    1276           0 :                 printf("Couldn't use given GRE dir.\n");
    1277           0 :                 return 1;
    1278             :             }
    1279             : 
    1280           0 :             dirprovider.SetGREDirs(greDir);
    1281             : 
    1282           0 :             argc -= 2;
    1283           0 :             argv += 2;
    1284             :         } else {
    1285             : #ifdef XP_MACOSX
    1286             :             // On OSX, the GreD needs to point to Contents/Resources in the .app
    1287             :             // bundle. Libraries will be loaded at a relative path to GreD, i.e.
    1288             :             // ../MacOS.
    1289             :             nsCOMPtr<nsIFile> tmpDir;
    1290             :             XRE_GetFileFromPath(argv[0], getter_AddRefs(greDir));
    1291             :             greDir->GetParent(getter_AddRefs(tmpDir));
    1292             :             tmpDir->Clone(getter_AddRefs(greDir));
    1293             :             tmpDir->SetNativeLeafName(NS_LITERAL_CSTRING("Resources"));
    1294             :             bool dirExists = false;
    1295             :             tmpDir->Exists(&dirExists);
    1296             :             if (dirExists) {
    1297             :                 greDir = tmpDir.forget();
    1298             :             }
    1299             :             dirprovider.SetGREDirs(greDir);
    1300             : #else
    1301           0 :             nsAutoString workingDir;
    1302           0 :             if (!GetCurrentWorkingDirectory(workingDir)) {
    1303           0 :                 printf("GetCurrentWorkingDirectory failed.\n");
    1304           0 :                 return 1;
    1305             :             }
    1306           0 :             rv = NS_NewLocalFile(workingDir, true, getter_AddRefs(greDir));
    1307           0 :             if (NS_FAILED(rv)) {
    1308           0 :                 printf("NS_NewLocalFile failed.\n");
    1309           0 :                 return 1;
    1310             :             }
    1311             : #endif
    1312             :         }
    1313             : 
    1314           0 :         if (argc > 1 && !strcmp(argv[1], "-a")) {
    1315           0 :             if (argc < 3)
    1316           0 :                 return usage();
    1317             : 
    1318           0 :             nsCOMPtr<nsIFile> dir;
    1319           0 :             rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(dir));
    1320           0 :             if (NS_SUCCEEDED(rv)) {
    1321           0 :                 appDir = do_QueryInterface(dir, &rv);
    1322           0 :                 dirprovider.SetAppDir(appDir);
    1323             :             }
    1324           0 :             if (NS_FAILED(rv)) {
    1325           0 :                 printf("Couldn't use given appdir.\n");
    1326           0 :                 return 1;
    1327             :             }
    1328           0 :             argc -= 2;
    1329           0 :             argv += 2;
    1330             :         }
    1331             : 
    1332           0 :         while (argc > 1 && !strcmp(argv[1], "-r")) {
    1333           0 :             if (argc < 3)
    1334           0 :                 return usage();
    1335             : 
    1336           0 :             nsCOMPtr<nsIFile> lf;
    1337           0 :             rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(lf));
    1338           0 :             if (NS_FAILED(rv)) {
    1339           0 :                 printf("Couldn't get manifest file.\n");
    1340           0 :                 return 1;
    1341             :             }
    1342           0 :             XRE_AddManifestLocation(NS_APP_LOCATION, lf);
    1343             : 
    1344           0 :             argc -= 2;
    1345           0 :             argv += 2;
    1346             :         }
    1347             : 
    1348             : #ifdef MOZ_CRASHREPORTER
    1349           0 :         const char* val = getenv("MOZ_CRASHREPORTER");
    1350           0 :         if (val && *val) {
    1351           0 :             rv = CrashReporter::SetExceptionHandler(greDir, true);
    1352           0 :             if (NS_FAILED(rv)) {
    1353           0 :                 printf("CrashReporter::SetExceptionHandler failed!\n");
    1354           0 :                 return 1;
    1355             :             }
    1356           0 :             MOZ_ASSERT(CrashReporter::GetEnabled());
    1357             :         }
    1358             : #endif
    1359             : 
    1360           0 :         if (argc > 1 && !strcmp(argv[1], "--greomni")) {
    1361           0 :             nsCOMPtr<nsIFile> greOmni;
    1362           0 :             nsCOMPtr<nsIFile> appOmni;
    1363           0 :             XRE_GetFileFromPath(argv[2], getter_AddRefs(greOmni));
    1364           0 :             if (argc > 3 && !strcmp(argv[3], "--appomni")) {
    1365           0 :                 XRE_GetFileFromPath(argv[4], getter_AddRefs(appOmni));
    1366           0 :                 argc-=2;
    1367           0 :                 argv+=2;
    1368             :             } else {
    1369           0 :                 appOmni = greOmni;
    1370             :             }
    1371             : 
    1372           0 :             XRE_InitOmnijar(greOmni, appOmni);
    1373           0 :             argc-=2;
    1374           0 :             argv+=2;
    1375             :         }
    1376             : 
    1377           0 :         nsCOMPtr<nsIServiceManager> servMan;
    1378           0 :         rv = NS_InitXPCOM2(getter_AddRefs(servMan), appDir, &dirprovider);
    1379           0 :         if (NS_FAILED(rv)) {
    1380           0 :             printf("NS_InitXPCOM2 failed!\n");
    1381           0 :             return 1;
    1382             :         }
    1383             : 
    1384             :         // xpc::ErrorReport::LogToConsoleWithStack needs this to print errors
    1385             :         // to stderr.
    1386           0 :         Preferences::SetBool("browser.dom.window.dump.enabled", true);
    1387             : 
    1388           0 :         AutoJSAPI jsapi;
    1389           0 :         jsapi.Init();
    1390           0 :         cx = jsapi.cx();
    1391             : 
    1392             :         // Override the default XPConnect interrupt callback. We could store the
    1393             :         // old one and restore it before shutting down, but there's not really a
    1394             :         // reason to bother.
    1395           0 :         sScriptedInterruptCallback = new PersistentRootedValue;
    1396           0 :         sScriptedInterruptCallback->init(cx, UndefinedValue());
    1397             : 
    1398           0 :         JS_AddInterruptCallback(cx, XPCShellInterruptCallback);
    1399             : 
    1400           0 :         argc--;
    1401           0 :         argv++;
    1402           0 :         ProcessArgsForCompartment(cx, argv, argc);
    1403             : 
    1404           0 :         nsCOMPtr<nsIPrincipal> systemprincipal;
    1405             :         // Fetch the system principal and store it away in a global, to use for
    1406             :         // script compilation in Load() and ProcessFile() (including interactive
    1407             :         // eval loop)
    1408             :         {
    1409             : 
    1410             :             nsCOMPtr<nsIScriptSecurityManager> securityManager =
    1411           0 :                 do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
    1412           0 :             if (NS_SUCCEEDED(rv) && securityManager) {
    1413           0 :                 rv = securityManager->GetSystemPrincipal(getter_AddRefs(systemprincipal));
    1414           0 :                 if (NS_FAILED(rv)) {
    1415           0 :                     fprintf(gErrFile, "+++ Failed to obtain SystemPrincipal from ScriptSecurityManager service.\n");
    1416             :                 } else {
    1417             :                     // fetch the JS principals and stick in a global
    1418           0 :                     gJSPrincipals = nsJSPrincipals::get(systemprincipal);
    1419           0 :                     JS_HoldPrincipals(gJSPrincipals);
    1420             :                 }
    1421             :             } else {
    1422           0 :                 fprintf(gErrFile, "+++ Failed to get ScriptSecurityManager service, running without principals");
    1423             :             }
    1424             :         }
    1425             : 
    1426           0 :         const JSSecurityCallbacks* scb = JS_GetSecurityCallbacks(cx);
    1427           0 :         MOZ_ASSERT(scb, "We are assuming that nsScriptSecurityManager::Init() has been run");
    1428           0 :         shellSecurityCallbacks = *scb;
    1429           0 :         JS_SetSecurityCallbacks(cx, &shellSecurityCallbacks);
    1430             : 
    1431           0 :         RefPtr<BackstagePass> backstagePass;
    1432           0 :         rv = NS_NewBackstagePass(getter_AddRefs(backstagePass));
    1433           0 :         if (NS_FAILED(rv)) {
    1434           0 :             fprintf(gErrFile, "+++ Failed to create BackstagePass: %8x\n",
    1435           0 :                     static_cast<uint32_t>(rv));
    1436           0 :             return 1;
    1437             :         }
    1438             : 
    1439             :         // Make the default XPCShell global use a fresh zone (rather than the
    1440             :         // System Zone) to improve cross-zone test coverage.
    1441           0 :         JS::CompartmentOptions options;
    1442           0 :         options.creationOptions().setNewZoneInSystemZoneGroup();
    1443           0 :         if (xpc::SharedMemoryEnabled())
    1444           0 :             options.creationOptions().setSharedMemoryAndAtomicsEnabled(true);
    1445           0 :         options.behaviors().setVersion(JSVERSION_LATEST);
    1446           0 :         nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
    1447           0 :         rv = nsXPConnect::XPConnect()->
    1448           0 :             InitClassesWithNewWrappedGlobal(cx,
    1449           0 :                                             static_cast<nsIGlobalObject*>(backstagePass),
    1450             :                                             systemprincipal,
    1451             :                                             0,
    1452             :                                             options,
    1453           0 :                                             getter_AddRefs(holder));
    1454           0 :         if (NS_FAILED(rv))
    1455           0 :             return 1;
    1456             : 
    1457             :         // Initialize graphics prefs on the main thread, if not already done
    1458           0 :         gfxPrefs::GetSingleton();
    1459             :         // Initialize e10s check on the main thread, if not already done
    1460           0 :         BrowserTabsRemoteAutostart();
    1461             : #ifdef XP_WIN
    1462             :         // Plugin may require audio session if installed plugin can initialize
    1463             :         // asynchronized.
    1464             :         AutoAudioSession audioSession;
    1465             : 
    1466             : #if defined(MOZ_SANDBOX)
    1467             :         // Required for sandboxed child processes.
    1468             :         if (aShellData->sandboxBrokerServices) {
    1469             :           SandboxBroker::Initialize(aShellData->sandboxBrokerServices);
    1470             :           SandboxBroker::CacheRulesDirectories();
    1471             :         } else {
    1472             :           NS_WARNING("Failed to initialize broker services, sandboxed "
    1473             :                      "processes will fail to start.");
    1474             :         }
    1475             : #endif
    1476             : #endif
    1477             : 
    1478             : #ifdef MOZ_CODE_COVERAGE
    1479           0 :         CodeCoverageHandler::Init();
    1480             : #endif
    1481             : 
    1482             :         {
    1483           0 :             JS::Rooted<JSObject*> glob(cx, holder->GetJSObject());
    1484           0 :             if (!glob) {
    1485           0 :                 return 1;
    1486             :             }
    1487             : 
    1488             :             // Even if we're building in a configuration where source is
    1489             :             // discarded, there's no reason to do that on XPCShell, and doing so
    1490             :             // might break various automation scripts.
    1491           0 :             JS::CompartmentBehaviorsRef(glob).setDiscardSource(false);
    1492             : 
    1493           0 :             backstagePass->SetGlobalObject(glob);
    1494             : 
    1495           0 :             JSAutoCompartment ac(cx, glob);
    1496             : 
    1497           0 :             if (!JS_InitReflectParse(cx, glob)) {
    1498           0 :                 return 1;
    1499             :             }
    1500             : 
    1501           0 :             if (!JS_DefineFunctions(cx, glob, glob_functions) ||
    1502           0 :                 !JS_DefineProfilingFunctions(cx, glob)) {
    1503           0 :                 return 1;
    1504             :             }
    1505             : 
    1506           0 :             JS::Rooted<JSObject*> envobj(cx);
    1507           0 :             envobj = JS_DefineObject(cx, glob, "environment", &env_class);
    1508           0 :             if (!envobj) {
    1509           0 :                 return 1;
    1510             :             }
    1511             : 
    1512           0 :             JS_SetPrivate(envobj, envp);
    1513             : 
    1514           0 :             nsAutoString workingDirectory;
    1515           0 :             if (GetCurrentWorkingDirectory(workingDirectory))
    1516           0 :                 gWorkingDirectory = &workingDirectory;
    1517             : 
    1518           0 :             JS_DefineProperty(cx, glob, "__LOCATION__", JS::UndefinedHandleValue,
    1519             :                               JSPROP_SHARED,
    1520             :                               GetLocationProperty,
    1521           0 :                               nullptr);
    1522             : 
    1523             :             {
    1524             :                 // We are almost certainly going to run script here, so we need an
    1525             :                 // AutoEntryScript. This is Gecko-specific and not in any spec.
    1526           0 :                 AutoEntryScript aes(backstagePass, "xpcshell argument processing");
    1527             : 
    1528             :                 // If an exception is thrown, we'll set our return code
    1529             :                 // appropriately, and then let the AutoEntryScript destructor report
    1530             :                 // the error to the console.
    1531           0 :                 if (!ProcessArgs(aes, argv, argc, &dirprovider)) {
    1532           0 :                     if (gExitCode) {
    1533           0 :                         result = gExitCode;
    1534           0 :                     } else if (gQuitting) {
    1535           0 :                         result = 0;
    1536             :                     } else {
    1537           0 :                         result = EXITCODE_RUNTIME_ERROR;
    1538             :                     }
    1539             :                 }
    1540             :             }
    1541             : 
    1542           0 :             JS_DropPrincipals(cx, gJSPrincipals);
    1543           0 :             JS_SetAllNonReservedSlotsToUndefined(cx, glob);
    1544           0 :             JS_SetAllNonReservedSlotsToUndefined(cx, JS_GlobalLexicalEnvironment(glob));
    1545           0 :             JS_GC(cx);
    1546             :         }
    1547           0 :         JS_GC(cx);
    1548             : 
    1549           0 :         dirprovider.ClearGREDirs();
    1550           0 :         dirprovider.ClearAppDir();
    1551           0 :         dirprovider.ClearPluginDir();
    1552           0 :         dirprovider.ClearAppFile();
    1553             :     } // this scopes the nsCOMPtrs
    1554             : 
    1555           0 :     if (!XRE_ShutdownTestShell())
    1556           0 :         NS_ERROR("problem shutting down testshell");
    1557             : 
    1558             :     // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM
    1559           0 :     rv = NS_ShutdownXPCOM( nullptr );
    1560           0 :     MOZ_ASSERT(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed");
    1561             : 
    1562           0 :     telStats = nullptr;
    1563             : 
    1564             : #ifdef MOZ_CRASHREPORTER
    1565             :     // Shut down the crashreporter service to prevent leaking some strings it holds.
    1566           0 :     if (CrashReporter::GetEnabled())
    1567           0 :         CrashReporter::UnsetExceptionHandler();
    1568             : #endif
    1569             : 
    1570             :     // This must precede NS_LogTerm(), otherwise xpcshell return non-zero
    1571             :     // during some tests, which causes failures.
    1572           0 :     profiler_shutdown();
    1573             : 
    1574           0 :     NS_LogTerm();
    1575             : 
    1576           0 :     return result;
    1577             : }
    1578             : 
    1579             : void
    1580           0 : XPCShellDirProvider::SetGREDirs(nsIFile* greDir)
    1581             : {
    1582           0 :     mGREDir = greDir;
    1583           0 :     mGREDir->Clone(getter_AddRefs(mGREBinDir));
    1584             : #ifdef XP_MACOSX
    1585             :     nsAutoCString leafName;
    1586             :     mGREDir->GetNativeLeafName(leafName);
    1587             :     if (leafName.Equals("Resources")) {
    1588             :         mGREBinDir->SetNativeLeafName(NS_LITERAL_CSTRING("MacOS"));
    1589             :     }
    1590             : #endif
    1591           0 : }
    1592             : 
    1593             : void
    1594           0 : XPCShellDirProvider::SetAppFile(nsIFile* appFile)
    1595             : {
    1596           0 :     mAppFile = appFile;
    1597           0 : }
    1598             : 
    1599             : void
    1600           0 : XPCShellDirProvider::SetAppDir(nsIFile* appDir)
    1601             : {
    1602           0 :     mAppDir = appDir;
    1603           0 : }
    1604             : 
    1605             : void
    1606           0 : XPCShellDirProvider::SetPluginDir(nsIFile* pluginDir)
    1607             : {
    1608           0 :     mPluginDir = pluginDir;
    1609           0 : }
    1610             : 
    1611             : NS_IMETHODIMP_(MozExternalRefCountType)
    1612           0 : XPCShellDirProvider::AddRef()
    1613             : {
    1614           0 :     return 2;
    1615             : }
    1616             : 
    1617             : NS_IMETHODIMP_(MozExternalRefCountType)
    1618           0 : XPCShellDirProvider::Release()
    1619             : {
    1620           0 :     return 1;
    1621             : }
    1622             : 
    1623           0 : NS_IMPL_QUERY_INTERFACE(XPCShellDirProvider,
    1624             :                         nsIDirectoryServiceProvider,
    1625             :                         nsIDirectoryServiceProvider2)
    1626             : 
    1627             : NS_IMETHODIMP
    1628           0 : XPCShellDirProvider::GetFile(const char* prop, bool* persistent,
    1629             :                              nsIFile* *result)
    1630             : {
    1631           0 :     if (mGREDir && !strcmp(prop, NS_GRE_DIR)) {
    1632           0 :         *persistent = true;
    1633           0 :         return mGREDir->Clone(result);
    1634           0 :     } else if (mGREBinDir && !strcmp(prop, NS_GRE_BIN_DIR)) {
    1635           0 :         *persistent = true;
    1636           0 :         return mGREBinDir->Clone(result);
    1637           0 :     } else if (mAppFile && !strcmp(prop, XRE_EXECUTABLE_FILE)) {
    1638           0 :         *persistent = true;
    1639           0 :         return mAppFile->Clone(result);
    1640           0 :     } else if (mGREDir && !strcmp(prop, NS_APP_PREF_DEFAULTS_50_DIR)) {
    1641           0 :         nsCOMPtr<nsIFile> file;
    1642           0 :         *persistent = true;
    1643           0 :         if (NS_FAILED(mGREDir->Clone(getter_AddRefs(file))) ||
    1644           0 :             NS_FAILED(file->AppendNative(NS_LITERAL_CSTRING("defaults"))) ||
    1645           0 :             NS_FAILED(file->AppendNative(NS_LITERAL_CSTRING("pref"))))
    1646           0 :             return NS_ERROR_FAILURE;
    1647           0 :         file.forget(result);
    1648           0 :         return NS_OK;
    1649             :     }
    1650             : 
    1651           0 :     return NS_ERROR_FAILURE;
    1652             : }
    1653             : 
    1654             : NS_IMETHODIMP
    1655           0 : XPCShellDirProvider::GetFiles(const char* prop, nsISimpleEnumerator* *result)
    1656             : {
    1657           0 :     if (mGREDir && !strcmp(prop, "ChromeML")) {
    1658           0 :         nsCOMArray<nsIFile> dirs;
    1659             : 
    1660           0 :         nsCOMPtr<nsIFile> file;
    1661           0 :         mGREDir->Clone(getter_AddRefs(file));
    1662           0 :         file->AppendNative(NS_LITERAL_CSTRING("chrome"));
    1663           0 :         dirs.AppendObject(file);
    1664             : 
    1665           0 :         nsresult rv = NS_GetSpecialDirectory(NS_APP_CHROME_DIR,
    1666           0 :                                              getter_AddRefs(file));
    1667           0 :         if (NS_SUCCEEDED(rv))
    1668           0 :             dirs.AppendObject(file);
    1669             : 
    1670           0 :         return NS_NewArrayEnumerator(result, dirs);
    1671           0 :     } else if (!strcmp(prop, NS_APP_PREFS_DEFAULTS_DIR_LIST)) {
    1672           0 :         nsCOMArray<nsIFile> dirs;
    1673           0 :         nsCOMPtr<nsIFile> appDir;
    1674             :         bool exists;
    1675           0 :         if (mAppDir &&
    1676           0 :             NS_SUCCEEDED(mAppDir->Clone(getter_AddRefs(appDir))) &&
    1677           0 :             NS_SUCCEEDED(appDir->AppendNative(NS_LITERAL_CSTRING("defaults"))) &&
    1678           0 :             NS_SUCCEEDED(appDir->AppendNative(NS_LITERAL_CSTRING("preferences"))) &&
    1679           0 :             NS_SUCCEEDED(appDir->Exists(&exists)) && exists) {
    1680           0 :             dirs.AppendObject(appDir);
    1681           0 :             return NS_NewArrayEnumerator(result, dirs);
    1682             :         }
    1683           0 :         return NS_ERROR_FAILURE;
    1684           0 :     } else if (!strcmp(prop, NS_APP_PLUGINS_DIR_LIST)) {
    1685           0 :         nsCOMArray<nsIFile> dirs;
    1686             :         // Add the test plugin location passed in by the caller or through
    1687             :         // runxpcshelltests.
    1688           0 :         if (mPluginDir) {
    1689           0 :             dirs.AppendObject(mPluginDir);
    1690             :         // If there was no path specified, default to the one set up by automation
    1691             :         } else {
    1692           0 :             nsCOMPtr<nsIFile> file;
    1693             :             bool exists;
    1694             :             // We have to add this path, buildbot copies the test plugin directory
    1695             :             // to (app)/bin when unpacking test zips.
    1696           0 :             if (mGREDir) {
    1697           0 :                 mGREDir->Clone(getter_AddRefs(file));
    1698           0 :                 if (NS_SUCCEEDED(mGREDir->Clone(getter_AddRefs(file)))) {
    1699           0 :                     file->AppendNative(NS_LITERAL_CSTRING("plugins"));
    1700           0 :                     if (NS_SUCCEEDED(file->Exists(&exists)) && exists) {
    1701           0 :                         dirs.AppendObject(file);
    1702             :                     }
    1703             :                 }
    1704             :             }
    1705             :         }
    1706           0 :         return NS_NewArrayEnumerator(result, dirs);
    1707             :     }
    1708           0 :     return NS_ERROR_FAILURE;
    1709             : }

Generated by: LCOV version 1.13