LCOV - code coverage report
Current view: top level - xpcom/components - ManifestParser.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 228 291 78.4 %
Date: 2017-07-14 16:53:18 Functions: 9 9 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       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 "mozilla/ArrayUtils.h"
       8             : #include "mozilla/Printf.h"
       9             : #include "mozilla/UniquePtr.h"
      10             : 
      11             : #include "ManifestParser.h"
      12             : 
      13             : #include <string.h>
      14             : 
      15             : #include "prio.h"
      16             : #if defined(XP_WIN)
      17             : #include <windows.h>
      18             : #elif defined(MOZ_WIDGET_COCOA)
      19             : #include <CoreServices/CoreServices.h>
      20             : #include "nsCocoaFeatures.h"
      21             : #elif defined(MOZ_WIDGET_GTK)
      22             : #include <gtk/gtk.h>
      23             : #endif
      24             : 
      25             : #ifdef MOZ_WIDGET_ANDROID
      26             : #include "AndroidBridge.h"
      27             : #endif
      28             : 
      29             : #include "mozilla/Services.h"
      30             : 
      31             : #include "nsCRT.h"
      32             : #include "nsConsoleMessage.h"
      33             : #include "nsTextFormatter.h"
      34             : #include "nsVersionComparator.h"
      35             : #include "nsXPCOMCIDInternal.h"
      36             : 
      37             : #include "nsIConsoleService.h"
      38             : #include "nsIScriptError.h"
      39             : #include "nsIXULAppInfo.h"
      40             : #include "nsIXULRuntime.h"
      41             : 
      42             : using namespace mozilla;
      43             : 
      44             : struct ManifestDirective
      45             : {
      46             :   const char* directive;
      47             :   int argc;
      48             : 
      49             :   // Binary components are only allowed for APP locations.
      50             :   bool apponly;
      51             : 
      52             :   // Some directives should only be delivered for APP or EXTENSION locations.
      53             :   bool componentonly;
      54             : 
      55             :   bool ischrome;
      56             : 
      57             :   bool allowbootstrap;
      58             : 
      59             :   // The contentaccessible flags only apply to content directives.
      60             :   bool contentflags;
      61             : 
      62             :   // Function to handle this directive. This isn't a union because C++ still
      63             :   // hasn't learned how to initialize unions in a sane way.
      64             :   void (nsComponentManagerImpl::*mgrfunc)(
      65             :     nsComponentManagerImpl::ManifestProcessingContext& aCx,
      66             :     int aLineNo, char* const* aArgv);
      67             :   void (nsChromeRegistry::*regfunc)(
      68             :     nsChromeRegistry::ManifestProcessingContext& aCx,
      69             :     int aLineNo, char* const* aArgv, int aFlags);
      70             :   void* xptonlyfunc;
      71             : 
      72             :   bool isContract;
      73             : };
      74             : static const ManifestDirective kParsingTable[] = {
      75             :   {
      76             :     "manifest",         1, false, false, true, true, false,
      77             :     &nsComponentManagerImpl::ManifestManifest, nullptr, nullptr
      78             :   },
      79             :   {
      80             :     "binary-component", 1, true, true, false, false, false,
      81             :     &nsComponentManagerImpl::ManifestBinaryComponent, nullptr, nullptr
      82             :   },
      83             :   {
      84             :     "interfaces",       1, false, true, false, false, false,
      85             :     &nsComponentManagerImpl::ManifestXPT, nullptr, nullptr
      86             :   },
      87             :   {
      88             :     "component",        2, false, true, false, false, false,
      89             :     &nsComponentManagerImpl::ManifestComponent, nullptr, nullptr
      90             :   },
      91             :   {
      92             :     "contract",         2, false, true, false, false, false,
      93             :     &nsComponentManagerImpl::ManifestContract, nullptr, nullptr, true
      94             :   },
      95             :   {
      96             :     "category",         3, false, true, false, false, false,
      97             :     &nsComponentManagerImpl::ManifestCategory, nullptr, nullptr
      98             :   },
      99             :   {
     100             :     "content",          2, false, true, true, true,  true,
     101             :     nullptr, &nsChromeRegistry::ManifestContent, nullptr
     102             :   },
     103             :   {
     104             :     "locale",           3, false, true, true, true, false,
     105             :     nullptr, &nsChromeRegistry::ManifestLocale, nullptr
     106             :   },
     107             :   {
     108             :     "skin",             3, false, false, true, true, false,
     109             :     nullptr, &nsChromeRegistry::ManifestSkin, nullptr
     110             :   },
     111             :   {
     112             :     "overlay",          2, false, true, true, false, false,
     113             :     nullptr, &nsChromeRegistry::ManifestOverlay, nullptr
     114             :   },
     115             :   {
     116             :     "style",            2, false, false, true, false, false,
     117             :     nullptr, &nsChromeRegistry::ManifestStyle, nullptr
     118             :   },
     119             :   {
     120             :     // NB: note that while skin manifests can use this, they are only allowed
     121             :     // to use it for chrome://../skin/ URLs
     122             :     "override",         2, false, false, true, true, false,
     123             :     nullptr, &nsChromeRegistry::ManifestOverride, nullptr
     124             :   },
     125             :   {
     126             :     "resource",         2, false, true, true, true, false,
     127             :     nullptr, &nsChromeRegistry::ManifestResource, nullptr
     128             :   }
     129             : };
     130             : 
     131             : static const char kWhitespace[] = "\t ";
     132             : 
     133             : static bool
     134      147425 : IsNewline(char aChar)
     135             : {
     136      147425 :   return aChar == '\n' || aChar == '\r';
     137             : }
     138             : 
     139             : /**
     140             :  * If we are pre-loading XPTs, this method may do nothing because the
     141             :  * console service is not initialized.
     142             :  */
     143             : void
     144           1 : LogMessage(const char* aMsg, ...)
     145             : {
     146           1 :   if (!nsComponentManagerImpl::gComponentManager) {
     147           0 :     return;
     148             :   }
     149             : 
     150             :   nsCOMPtr<nsIConsoleService> console =
     151           2 :     do_GetService(NS_CONSOLESERVICE_CONTRACTID);
     152           1 :   if (!console) {
     153           0 :     return;
     154             :   }
     155             : 
     156             :   va_list args;
     157           1 :   va_start(args, aMsg);
     158           2 :   SmprintfPointer formatted(mozilla::Vsmprintf(aMsg, args));
     159           1 :   va_end(args);
     160             : 
     161             :   nsCOMPtr<nsIConsoleMessage> error =
     162           3 :     new nsConsoleMessage(NS_ConvertUTF8toUTF16(formatted.get()).get());
     163           1 :   console->LogMessage(error);
     164             : }
     165             : 
     166             : /**
     167             :  * If we are pre-loading XPTs, this method may do nothing because the
     168             :  * console service is not initialized.
     169             :  */
     170             : void
     171           2 : LogMessageWithContext(FileLocation& aFile,
     172             :                       uint32_t aLineNumber, const char* aMsg, ...)
     173             : {
     174             :   va_list args;
     175           2 :   va_start(args, aMsg);
     176           4 :   SmprintfPointer formatted(mozilla::Vsmprintf(aMsg, args));
     177           2 :   va_end(args);
     178           2 :   if (!formatted) {
     179           0 :     return;
     180             :   }
     181             : 
     182           2 :   if (!nsComponentManagerImpl::gComponentManager) {
     183           0 :     return;
     184             :   }
     185             : 
     186           4 :   nsCString file;
     187           2 :   aFile.GetURIString(file);
     188             : 
     189             :   nsCOMPtr<nsIScriptError> error =
     190           4 :     do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
     191           2 :   if (!error) {
     192             :     // This can happen early in component registration. Fall back to a
     193             :     // generic console message.
     194           0 :     LogMessage("Warning: in '%s', line %i: %s", file.get(),
     195           0 :                aLineNumber, formatted.get());
     196           0 :     return;
     197             :   }
     198             : 
     199             :   nsCOMPtr<nsIConsoleService> console =
     200           4 :     do_GetService(NS_CONSOLESERVICE_CONTRACTID);
     201           2 :   if (!console) {
     202           0 :     return;
     203             :   }
     204             : 
     205           8 :   nsresult rv = error->Init(NS_ConvertUTF8toUTF16(formatted.get()),
     206           6 :                             NS_ConvertUTF8toUTF16(file), EmptyString(),
     207             :                             aLineNumber, 0, nsIScriptError::warningFlag,
     208           4 :                             "chrome registration");
     209           2 :   if (NS_FAILED(rv)) {
     210           0 :     return;
     211             :   }
     212             : 
     213           2 :   console->LogMessage(error);
     214             : }
     215             : 
     216             : /**
     217             :  * Check for a modifier flag of the following forms:
     218             :  *   "flag"   (same as "true")
     219             :  *   "flag=yes|true|1"
     220             :  *   "flag="no|false|0"
     221             :  * @param aFlag The flag to compare.
     222             :  * @param aData The tokenized data to check; this is lowercased
     223             :  *              before being passed in.
     224             :  * @param aResult If the flag is found, the value is assigned here.
     225             :  * @return Whether the flag was handled.
     226             :  */
     227             : static bool
     228          17 : CheckFlag(const nsAString& aFlag, const nsAString& aData, bool& aResult)
     229             : {
     230          17 :   if (!StringBeginsWith(aData, aFlag)) {
     231           0 :     return false;
     232             :   }
     233             : 
     234          17 :   if (aFlag.Length() == aData.Length()) {
     235             :     // the data is simply "flag", which is the same as "flag=yes"
     236           0 :     aResult = true;
     237           0 :     return true;
     238             :   }
     239             : 
     240          17 :   if (aData.CharAt(aFlag.Length()) != '=') {
     241             :     // the data is "flag2=", which is not anything we care about
     242           0 :     return false;
     243             :   }
     244             : 
     245          17 :   if (aData.Length() == aFlag.Length() + 1) {
     246           0 :     aResult = false;
     247           0 :     return true;
     248             :   }
     249             : 
     250          17 :   switch (aData.CharAt(aFlag.Length() + 1)) {
     251             :     case '1':
     252             :     case 't': //true
     253             :     case 'y': //yes
     254          17 :       aResult = true;
     255          17 :       return true;
     256             : 
     257             :     case '0':
     258             :     case 'f': //false
     259             :     case 'n': //no
     260           0 :       aResult = false;
     261           0 :       return true;
     262             :   }
     263             : 
     264           0 :   return false;
     265             : }
     266             : 
     267             : enum TriState
     268             : {
     269             :   eUnspecified,
     270             :   eBad,
     271             :   eOK
     272             : };
     273             : 
     274             : /**
     275             :  * Check for a modifier flag of the following form:
     276             :  *   "flag=string"
     277             :  *   "flag!=string"
     278             :  * @param aFlag The flag to compare.
     279             :  * @param aData The tokenized data to check; this is lowercased
     280             :  *              before being passed in.
     281             :  * @param aValue The value that is expected.
     282             :  * @param aResult If this is "ok" when passed in, this is left alone.
     283             :  *                Otherwise if the flag is found it is set to eBad or eOK.
     284             :  * @return Whether the flag was handled.
     285             :  */
     286             : static bool
     287         563 : CheckStringFlag(const nsAString& aFlag, const nsAString& aData,
     288             :                 const nsAString& aValue, TriState& aResult)
     289             : {
     290         563 :   if (aData.Length() < aFlag.Length() + 1) {
     291          29 :     return false;
     292             :   }
     293             : 
     294         534 :   if (!StringBeginsWith(aData, aFlag)) {
     295         291 :     return false;
     296             :   }
     297             : 
     298         243 :   bool comparison = true;
     299         243 :   if (aData[aFlag.Length()] != '=') {
     300          12 :     if (aData[aFlag.Length()] == '!' &&
     301           6 :         aData.Length() >= aFlag.Length() + 2 &&
     302           0 :         aData[aFlag.Length() + 1] == '=') {
     303           0 :       comparison = false;
     304             :     } else {
     305           6 :       return false;
     306             :     }
     307             :   }
     308             : 
     309         237 :   if (aResult != eOK) {
     310             :     nsDependentSubstring testdata =
     311         450 :       Substring(aData, aFlag.Length() + (comparison ? 1 : 2));
     312         225 :     if (testdata.Equals(aValue)) {
     313          61 :       aResult = comparison ? eOK : eBad;
     314             :     } else {
     315         164 :       aResult = comparison ? eBad : eOK;
     316             :     }
     317             :   }
     318             : 
     319         237 :   return true;
     320             : }
     321             : 
     322             : static bool
     323         119 : CheckOsFlag(const nsAString& aFlag, const nsAString& aData,
     324             :             const nsAString& aValue, TriState& aResult)
     325             : {
     326         119 :   bool result = CheckStringFlag(aFlag, aData, aValue, aResult);
     327             : #if defined(XP_UNIX) && !defined(XP_DARWIN) && !defined(ANDROID)
     328         119 :   if (result && aResult == eBad) {
     329          24 :     result = CheckStringFlag(aFlag, aData, NS_LITERAL_STRING("likeunix"), aResult);
     330             :   }
     331             : #endif
     332         119 :   return result;
     333             : }
     334             : 
     335             : /**
     336             :  * Check for a modifier flag of the following form:
     337             :  *   "flag=version"
     338             :  *   "flag<=version"
     339             :  *   "flag<version"
     340             :  *   "flag>=version"
     341             :  *   "flag>version"
     342             :  * @param aFlag The flag to compare.
     343             :  * @param aData The tokenized data to check; this is lowercased
     344             :  *              before being passed in.
     345             :  * @param aValue The value that is expected. If this is empty then no
     346             :  *               comparison will match.
     347             :  * @param aResult If this is eOK when passed in, this is left alone.
     348             :  *                Otherwise if the flag is found it is set to eBad or eOK.
     349             :  * @return Whether the flag was handled.
     350             :  */
     351             : 
     352             : #define COMPARE_EQ    1 << 0
     353             : #define COMPARE_LT    1 << 1
     354             : #define COMPARE_GT    1 << 2
     355             : 
     356             : static bool
     357          57 : CheckVersionFlag(const nsString& aFlag, const nsString& aData,
     358             :                  const nsString& aValue, TriState& aResult)
     359             : {
     360          57 :   if (aData.Length() < aFlag.Length() + 2) {
     361           0 :     return false;
     362             :   }
     363             : 
     364          57 :   if (!StringBeginsWith(aData, aFlag)) {
     365          51 :     return false;
     366             :   }
     367             : 
     368           6 :   if (aValue.Length() == 0) {
     369           0 :     if (aResult != eOK) {
     370           0 :       aResult = eBad;
     371             :     }
     372           0 :     return true;
     373             :   }
     374             : 
     375             :   uint32_t comparison;
     376          12 :   nsAutoString testdata;
     377             : 
     378           6 :   switch (aData[aFlag.Length()]) {
     379             :     case '=':
     380           4 :       comparison = COMPARE_EQ;
     381           4 :       testdata = Substring(aData, aFlag.Length() + 1);
     382           4 :       break;
     383             : 
     384             :     case '<':
     385           0 :       if (aData[aFlag.Length() + 1] == '=') {
     386           0 :         comparison = COMPARE_EQ | COMPARE_LT;
     387           0 :         testdata = Substring(aData, aFlag.Length() + 2);
     388             :       } else {
     389           0 :         comparison = COMPARE_LT;
     390           0 :         testdata = Substring(aData, aFlag.Length() + 1);
     391             :       }
     392           0 :       break;
     393             : 
     394             :     case '>':
     395           2 :       if (aData[aFlag.Length() + 1] == '=') {
     396           2 :         comparison = COMPARE_EQ | COMPARE_GT;
     397           2 :         testdata = Substring(aData, aFlag.Length() + 2);
     398             :       } else {
     399           0 :         comparison = COMPARE_GT;
     400           0 :         testdata = Substring(aData, aFlag.Length() + 1);
     401             :       }
     402           2 :       break;
     403             : 
     404             :     default:
     405           0 :       return false;
     406             :   }
     407             : 
     408           6 :   if (testdata.Length() == 0) {
     409           0 :     return false;
     410             :   }
     411             : 
     412           6 :   if (aResult != eOK) {
     413          12 :     int32_t c = mozilla::CompareVersions(NS_ConvertUTF16toUTF8(aValue).get(),
     414          18 :                                          NS_ConvertUTF16toUTF8(testdata).get());
     415           6 :     if ((c == 0 && comparison & COMPARE_EQ) ||
     416           6 :         (c < 0 && comparison & COMPARE_LT) ||
     417           0 :         (c > 0 && comparison & COMPARE_GT)) {
     418           0 :       aResult = eOK;
     419             :     } else {
     420           6 :       aResult = eBad;
     421             :     }
     422             :   }
     423             : 
     424           6 :   return true;
     425             : }
     426             : 
     427             : // In-place conversion of ascii characters to lower case
     428             : static void
     429        7644 : ToLowerCase(char* aToken)
     430             : {
     431       15052 :   for (; *aToken; ++aToken) {
     432        7408 :     *aToken = NS_ToLower(*aToken);
     433             :   }
     434         236 : }
     435             : 
     436             : namespace {
     437             : 
     438             : struct CachedDirective
     439             : {
     440             :   int lineno;
     441             :   char* argv[4];
     442             : };
     443             : 
     444             : } // namespace
     445             : 
     446             : 
     447             : /**
     448             :  * For XPT-Only mode, the parser handles only directives of "manifest"
     449             :  * and "interfaces", and always call the function given by |xptonlyfunc|
     450             :  * variable of struct |ManifestDirective|.
     451             :  *
     452             :  * This function is safe to be called before the component manager is
     453             :  * ready if aXPTOnly is true for it don't invoke any component during
     454             :  * parsing.
     455             :  */
     456             : void
     457         311 : ParseManifest(NSLocationType aType, FileLocation& aFile, char* aBuf,
     458             :               bool aChromeOnly, bool aXPTOnly)
     459             : {
     460             :   nsComponentManagerImpl::ManifestProcessingContext mgrcx(aType, aFile,
     461         622 :                                                           aChromeOnly);
     462         622 :   nsChromeRegistry::ManifestProcessingContext chromecx(aType, aFile);
     463             :   nsresult rv;
     464             : 
     465         311 :   NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible");
     466         311 :   NS_NAMED_LITERAL_STRING(kRemoteEnabled, "remoteenabled");
     467         311 :   NS_NAMED_LITERAL_STRING(kRemoteRequired, "remoterequired");
     468         311 :   NS_NAMED_LITERAL_STRING(kApplication, "application");
     469         311 :   NS_NAMED_LITERAL_STRING(kAppVersion, "appversion");
     470         311 :   NS_NAMED_LITERAL_STRING(kGeckoVersion, "platformversion");
     471         311 :   NS_NAMED_LITERAL_STRING(kOs, "os");
     472         311 :   NS_NAMED_LITERAL_STRING(kOsVersion, "osversion");
     473         311 :   NS_NAMED_LITERAL_STRING(kABI, "abi");
     474         311 :   NS_NAMED_LITERAL_STRING(kProcess, "process");
     475             : #if defined(MOZ_WIDGET_ANDROID)
     476             :   NS_NAMED_LITERAL_STRING(kTablet, "tablet");
     477             : #endif
     478             : 
     479         311 :   NS_NAMED_LITERAL_STRING(kMain, "main");
     480         311 :   NS_NAMED_LITERAL_STRING(kContent, "content");
     481             : 
     482             :   // Obsolete
     483         311 :   NS_NAMED_LITERAL_STRING(kXPCNativeWrappers, "xpcnativewrappers");
     484             : 
     485         622 :   nsAutoString appID;
     486         622 :   nsAutoString appVersion;
     487         622 :   nsAutoString geckoVersion;
     488         622 :   nsAutoString osTarget;
     489         622 :   nsAutoString abi;
     490         622 :   nsAutoString process;
     491             : 
     492         622 :   nsCOMPtr<nsIXULAppInfo> xapp;
     493         311 :   if (!aXPTOnly) {
     494             :     // Avoid to create any component for XPT only mode.
     495             :     // No xapp means no ID, version, ..., modifiers checking.
     496         311 :     xapp = do_GetService(XULAPPINFO_SERVICE_CONTRACTID);
     497             :   }
     498         311 :   if (xapp) {
     499         622 :     nsAutoCString s;
     500         311 :     rv = xapp->GetID(s);
     501         311 :     if (NS_SUCCEEDED(rv)) {
     502         311 :       CopyUTF8toUTF16(s, appID);
     503             :     }
     504             : 
     505         311 :     rv = xapp->GetVersion(s);
     506         311 :     if (NS_SUCCEEDED(rv)) {
     507         311 :       CopyUTF8toUTF16(s, appVersion);
     508             :     }
     509             : 
     510         311 :     rv = xapp->GetPlatformVersion(s);
     511         311 :     if (NS_SUCCEEDED(rv)) {
     512         311 :       CopyUTF8toUTF16(s, geckoVersion);
     513             :     }
     514             : 
     515         622 :     nsCOMPtr<nsIXULRuntime> xruntime(do_QueryInterface(xapp));
     516         311 :     if (xruntime) {
     517         311 :       rv = xruntime->GetOS(s);
     518         311 :       if (NS_SUCCEEDED(rv)) {
     519         311 :         ToLowerCase(s);
     520         311 :         CopyUTF8toUTF16(s, osTarget);
     521             :       }
     522             : 
     523         311 :       rv = xruntime->GetXPCOMABI(s);
     524         311 :       if (NS_SUCCEEDED(rv) && osTarget.Length()) {
     525         311 :         ToLowerCase(s);
     526         311 :         CopyUTF8toUTF16(s, abi);
     527         311 :         abi.Insert(char16_t('_'), 0);
     528         311 :         abi.Insert(osTarget, 0);
     529             :       }
     530             :     }
     531             :   }
     532             : 
     533         622 :   nsAutoString osVersion;
     534             : #if defined(XP_WIN)
     535             : #pragma warning(push)
     536             : #pragma warning(disable:4996) // VC12+ deprecates GetVersionEx
     537             :   OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
     538             :   if (GetVersionEx(&info)) {
     539             :     nsTextFormatter::ssprintf(osVersion, u"%ld.%ld",
     540             :                               info.dwMajorVersion,
     541             :                               info.dwMinorVersion);
     542             :   }
     543             : #pragma warning(pop)
     544             : #elif defined(MOZ_WIDGET_COCOA)
     545             :   SInt32 majorVersion = nsCocoaFeatures::OSXVersionMajor();
     546             :   SInt32 minorVersion = nsCocoaFeatures::OSXVersionMinor();
     547             :   nsTextFormatter::ssprintf(osVersion, u"%ld.%ld",
     548             :                             majorVersion,
     549             :                             minorVersion);
     550             : #elif defined(MOZ_WIDGET_GTK)
     551         311 :   nsTextFormatter::ssprintf(osVersion, u"%ld.%ld",
     552             :                             gtk_major_version,
     553         311 :                             gtk_minor_version);
     554             : #elif defined(MOZ_WIDGET_ANDROID)
     555             :   bool isTablet = false;
     556             :   if (mozilla::AndroidBridge::Bridge()) {
     557             :     mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build$VERSION",
     558             :                                                            "RELEASE",
     559             :                                                            osVersion);
     560             :     isTablet = java::GeckoAppShell::IsTablet();
     561             :   }
     562             : #endif
     563             : 
     564         311 :   if (XRE_IsContentProcess()) {
     565         196 :     process = kContent;
     566             :   } else {
     567         115 :     process = kMain;
     568             :   }
     569             : 
     570             :   // Because contracts must be registered after CIDs, we save and process them
     571             :   // at the end.
     572         622 :   nsTArray<CachedDirective> contracts;
     573             : 
     574             :   char* token;
     575         311 :   char* newline = aBuf;
     576         311 :   uint32_t line = 0;
     577             : 
     578             :   // outer loop tokenizes by newline
     579        4885 :   while (*newline) {
     580        2521 :     while (*newline && IsNewline(*newline)) {
     581         111 :       ++newline;
     582         111 :       ++line;
     583             :     }
     584        2299 :     if (!*newline) {
     585          12 :       break;
     586             :     }
     587             : 
     588        2287 :     token = newline;
     589      287785 :     while (*newline && !IsNewline(*newline)) {
     590      142749 :       ++newline;
     591             :     }
     592             : 
     593        2287 :     if (*newline) {
     594        2278 :       *newline = '\0';
     595        2278 :       ++newline;
     596             :     }
     597        2287 :     ++line;
     598             : 
     599        2287 :     if (*token == '#') { // ignore lines that begin with # as comments
     600         493 :       continue;
     601             :     }
     602             : 
     603        2161 :     char* whitespace = token;
     604        2161 :     token = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
     605        2161 :     if (!token) {
     606           0 :       continue;
     607             :     }
     608             : 
     609        2161 :     const ManifestDirective* directive = nullptr;
     610       18722 :     for (const ManifestDirective* d = kParsingTable;
     611        9361 :          d < ArrayEnd(kParsingTable);
     612             :          ++d) {
     613       11522 :       if (!strcmp(d->directive, token) &&
     614        2161 :           (!aXPTOnly || d->xptonlyfunc)) {
     615        2161 :         directive = d;
     616        2161 :         break;
     617             :       }
     618             :     }
     619             : 
     620        2161 :     if (!directive) {
     621             :       LogMessageWithContext(aFile, line,
     622             :                             "Ignoring unrecognized chrome manifest directive '%s'.",
     623           0 :                             token);
     624           0 :       continue;
     625             :     }
     626             : 
     627        2161 :     if (!directive->allowbootstrap && NS_BOOTSTRAPPED_LOCATION == aType) {
     628             :       LogMessageWithContext(aFile, line,
     629             :                             "Bootstrapped manifest not allowed to use '%s' directive.",
     630           0 :                             token);
     631           0 :       continue;
     632             :     }
     633             : 
     634             : #ifndef MOZ_BINARY_EXTENSIONS
     635        2161 :     if (directive->apponly && NS_APP_LOCATION != aType) {
     636             :       LogMessageWithContext(aFile, line,
     637           0 :                             "Only application manifests may use the '%s' directive.", token);
     638           0 :       continue;
     639             :     }
     640             : #endif
     641             : 
     642        2161 :     if (directive->componentonly && NS_SKIN_LOCATION == aType) {
     643             :       LogMessageWithContext(aFile, line,
     644             :                             "Skin manifest not allowed to use '%s' directive.",
     645           0 :                             token);
     646           0 :       continue;
     647             :     }
     648             : 
     649        2161 :     NS_ASSERTION(directive->argc < 4, "Need to reset argv array length");
     650             :     char* argv[4];
     651        5941 :     for (int i = 0; i < directive->argc; ++i) {
     652        3780 :       argv[i] = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
     653             :     }
     654             : 
     655        2161 :     if (!argv[directive->argc - 1]) {
     656             :       LogMessageWithContext(aFile, line,
     657             :                             "Not enough arguments for chrome manifest directive '%s', expected %i.",
     658           0 :                             token, directive->argc);
     659           0 :       continue;
     660             :     }
     661             : 
     662        2161 :     bool ok = true;
     663        2161 :     TriState stAppVersion = eUnspecified;
     664        2161 :     TriState stGeckoVersion = eUnspecified;
     665        2161 :     TriState stApp = eUnspecified;
     666        2161 :     TriState stOsVersion = eUnspecified;
     667        2161 :     TriState stOs = eUnspecified;
     668        2161 :     TriState stABI = eUnspecified;
     669        2161 :     TriState stProcess = eUnspecified;
     670             : #if defined(MOZ_WIDGET_ANDROID)
     671             :     TriState stTablet = eUnspecified;
     672             : #endif
     673        2161 :     int flags = 0;
     674             : 
     675        2633 :     while ((token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) &&
     676             :            ok) {
     677         236 :       ToLowerCase(token);
     678         236 :       NS_ConvertASCIItoUTF16 wtoken(token);
     679             : 
     680         591 :       if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
     681         211 :           CheckOsFlag(kOs, wtoken, osTarget, stOs) ||
     682         184 :           CheckStringFlag(kABI, wtoken, abi, stABI) ||
     683         115 :           CheckStringFlag(kProcess, wtoken, process, stProcess) ||
     684          40 :           CheckVersionFlag(kOsVersion, wtoken, osVersion, stOsVersion) ||
     685         270 :           CheckVersionFlag(kAppVersion, wtoken, appVersion, stAppVersion) ||
     686          17 :           CheckVersionFlag(kGeckoVersion, wtoken, geckoVersion, stGeckoVersion)) {
     687         219 :         continue;
     688             :       }
     689             : 
     690             : #if defined(MOZ_WIDGET_ANDROID)
     691             :       bool tablet = false;
     692             :       if (CheckFlag(kTablet, wtoken, tablet)) {
     693             :         stTablet = (tablet == isTablet) ? eOK : eBad;
     694             :         continue;
     695             :       }
     696             : #endif
     697             : 
     698          17 :       if (directive->contentflags) {
     699             :         bool flag;
     700          17 :         if (CheckFlag(kContentAccessible, wtoken, flag)) {
     701          17 :           if (flag)
     702          17 :             flags |= nsChromeRegistry::CONTENT_ACCESSIBLE;
     703          34 :           continue;
     704             :         }
     705           0 :         if (CheckFlag(kRemoteEnabled, wtoken, flag)) {
     706           0 :           if (flag)
     707           0 :             flags |= nsChromeRegistry::REMOTE_ALLOWED;
     708           0 :           continue;
     709             :         }
     710           0 :         if (CheckFlag(kRemoteRequired, wtoken, flag)) {
     711           0 :           if (flag)
     712           0 :             flags |= nsChromeRegistry::REMOTE_REQUIRED;
     713           0 :           continue;
     714             :         }
     715             :       }
     716             : 
     717           0 :       bool xpcNativeWrappers = true; // Dummy for CheckFlag.
     718           0 :       if (CheckFlag(kXPCNativeWrappers, wtoken, xpcNativeWrappers)) {
     719             :         LogMessageWithContext(aFile, line,
     720             :                               "Ignoring obsolete chrome registration modifier '%s'.",
     721           0 :                               token);
     722           0 :         continue;
     723             :       }
     724             : 
     725             :       LogMessageWithContext(aFile, line,
     726             :                             "Unrecognized chrome manifest modifier '%s'.",
     727           0 :                             token);
     728           0 :       ok = false;
     729             :     }
     730             : 
     731        4322 :     if (!ok ||
     732        4268 :         stApp == eBad ||
     733        4214 :         stAppVersion == eBad ||
     734        4214 :         stGeckoVersion == eBad ||
     735        4196 :         stOs == eBad ||
     736        4178 :         stOsVersion == eBad ||
     737             : #ifdef MOZ_WIDGET_ANDROID
     738             :         stTablet == eBad ||
     739             : #endif
     740        4178 :         stABI == eBad ||
     741        2089 :         stProcess == eBad) {
     742         113 :       continue;
     743             :     }
     744             : 
     745        2048 :     if (directive->regfunc) {
     746         231 :       if (GeckoProcessType_Default != XRE_GetProcessType()) {
     747         128 :         continue;
     748             :       }
     749             : 
     750         103 :       if (!nsChromeRegistry::gChromeRegistry) {
     751             :         nsCOMPtr<nsIChromeRegistry> cr =
     752           2 :           mozilla::services::GetChromeRegistryService();
     753           1 :         if (!nsChromeRegistry::gChromeRegistry) {
     754             :           LogMessageWithContext(aFile, line,
     755           0 :                                 "Chrome registry isn't available yet.");
     756           0 :           continue;
     757             :         }
     758             :       }
     759             : 
     760         206 :       (nsChromeRegistry::gChromeRegistry->*(directive->regfunc))(
     761         309 :         chromecx, line, argv, flags);
     762        1817 :     } else if (directive->ischrome || !aChromeOnly) {
     763        1817 :       if (directive->isContract) {
     764         439 :         CachedDirective* cd = contracts.AppendElement();
     765         439 :         cd->lineno = line;
     766         439 :         cd->argv[0] = argv[0];
     767         439 :         cd->argv[1] = argv[1];
     768             :       } else {
     769        2756 :         (nsComponentManagerImpl::gComponentManager->*(directive->mgrfunc))(
     770        4134 :           mgrcx, line, argv);
     771             :       }
     772             :     }
     773             :   }
     774             : 
     775         750 :   for (uint32_t i = 0; i < contracts.Length(); ++i) {
     776         439 :     CachedDirective& d = contracts[i];
     777         439 :     nsComponentManagerImpl::gComponentManager->ManifestContract(mgrcx,
     778             :                                                                 d.lineno,
     779         439 :                                                                 d.argv);
     780             :   }
     781         311 : }

Generated by: LCOV version 1.13