michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/ArrayUtils.h" michael@0: michael@0: #include "ManifestParser.h" michael@0: michael@0: #include michael@0: michael@0: #include "prio.h" michael@0: #include "prprf.h" michael@0: #if defined(XP_WIN) michael@0: #include michael@0: #elif defined(MOZ_WIDGET_COCOA) michael@0: #include michael@0: #include "nsCocoaFeatures.h" michael@0: #elif defined(MOZ_WIDGET_GTK) michael@0: #include michael@0: #endif michael@0: michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: #include "AndroidBridge.h" michael@0: #endif michael@0: michael@0: #include "mozilla/Services.h" michael@0: michael@0: #include "nsCRT.h" michael@0: #include "nsConsoleMessage.h" michael@0: #include "nsTextFormatter.h" michael@0: #include "nsVersionComparator.h" michael@0: #include "nsXPCOMCIDInternal.h" michael@0: michael@0: #include "nsIConsoleService.h" michael@0: #include "nsIScriptError.h" michael@0: #include "nsIXULAppInfo.h" michael@0: #include "nsIXULRuntime.h" michael@0: michael@0: using namespace mozilla; michael@0: michael@0: struct ManifestDirective michael@0: { michael@0: const char* directive; michael@0: int argc; michael@0: michael@0: // Some directives should only be delivered for NS_COMPONENT_LOCATION michael@0: // manifests. michael@0: bool componentonly; michael@0: michael@0: bool ischrome; michael@0: michael@0: bool allowbootstrap; michael@0: michael@0: // The platform/contentaccessible flags only apply to content directives. michael@0: bool contentflags; michael@0: michael@0: // Function to handle this directive. This isn't a union because C++ still michael@0: // hasn't learned how to initialize unions in a sane way. michael@0: void (nsComponentManagerImpl::*mgrfunc) michael@0: (nsComponentManagerImpl::ManifestProcessingContext& cx, michael@0: int lineno, char *const * argv); michael@0: void (nsChromeRegistry::*regfunc) michael@0: (nsChromeRegistry::ManifestProcessingContext& cx, michael@0: int lineno, char *const *argv, michael@0: bool platform, bool contentaccessible); michael@0: michael@0: bool isContract; michael@0: }; michael@0: static const ManifestDirective kParsingTable[] = { michael@0: { "manifest", 1, false, true, true, false, michael@0: &nsComponentManagerImpl::ManifestManifest, nullptr }, michael@0: { "binary-component", 1, true, false, false, false, michael@0: &nsComponentManagerImpl::ManifestBinaryComponent, nullptr }, michael@0: { "interfaces", 1, true, false, false, false, michael@0: &nsComponentManagerImpl::ManifestXPT, nullptr }, michael@0: { "component", 2, true, false, false, false, michael@0: &nsComponentManagerImpl::ManifestComponent, nullptr }, michael@0: { "contract", 2, true, false, false, false, michael@0: &nsComponentManagerImpl::ManifestContract, nullptr, true}, michael@0: { "category", 3, true, false, false, false, michael@0: &nsComponentManagerImpl::ManifestCategory, nullptr }, michael@0: { "content", 2, true, true, true, true, michael@0: nullptr, &nsChromeRegistry::ManifestContent }, michael@0: { "locale", 3, true, true, true, false, michael@0: nullptr, &nsChromeRegistry::ManifestLocale }, michael@0: { "skin", 3, false, true, true, false, michael@0: nullptr, &nsChromeRegistry::ManifestSkin }, michael@0: { "overlay", 2, true, true, false, false, michael@0: nullptr, &nsChromeRegistry::ManifestOverlay }, michael@0: { "style", 2, false, true, false, false, michael@0: nullptr, &nsChromeRegistry::ManifestStyle }, michael@0: { "override", 2, true, true, true, false, michael@0: nullptr, &nsChromeRegistry::ManifestOverride }, michael@0: { "resource", 2, true, true, false, false, michael@0: nullptr, &nsChromeRegistry::ManifestResource } michael@0: }; michael@0: michael@0: static const char kWhitespace[] = "\t "; michael@0: michael@0: static bool IsNewline(char c) michael@0: { michael@0: return c == '\n' || c == '\r'; michael@0: } michael@0: michael@0: namespace { michael@0: struct AutoPR_smprintf_free michael@0: { michael@0: AutoPR_smprintf_free(char* buf) michael@0: : mBuf(buf) michael@0: { michael@0: } michael@0: michael@0: ~AutoPR_smprintf_free() michael@0: { michael@0: if (mBuf) michael@0: PR_smprintf_free(mBuf); michael@0: } michael@0: michael@0: operator char*() const { michael@0: return mBuf; michael@0: } michael@0: michael@0: char* mBuf; michael@0: }; michael@0: michael@0: } // anonymous namespace michael@0: michael@0: void LogMessage(const char* aMsg, ...) michael@0: { michael@0: nsCOMPtr console = michael@0: do_GetService(NS_CONSOLESERVICE_CONTRACTID); michael@0: if (!console) michael@0: return; michael@0: michael@0: va_list args; michael@0: va_start(args, aMsg); michael@0: AutoPR_smprintf_free formatted(PR_vsmprintf(aMsg, args)); michael@0: va_end(args); michael@0: michael@0: nsCOMPtr error = michael@0: new nsConsoleMessage(NS_ConvertUTF8toUTF16(formatted).get()); michael@0: console->LogMessage(error); michael@0: } michael@0: michael@0: void LogMessageWithContext(FileLocation &aFile, michael@0: uint32_t aLineNumber, const char* aMsg, ...) michael@0: { michael@0: va_list args; michael@0: va_start(args, aMsg); michael@0: AutoPR_smprintf_free formatted(PR_vsmprintf(aMsg, args)); michael@0: va_end(args); michael@0: if (!formatted) michael@0: return; michael@0: michael@0: nsCString file; michael@0: aFile.GetURIString(file); michael@0: michael@0: nsCOMPtr error = michael@0: do_CreateInstance(NS_SCRIPTERROR_CONTRACTID); michael@0: if (!error) { michael@0: // This can happen early in component registration. Fall back to a michael@0: // generic console message. michael@0: LogMessage("Warning: in '%s', line %i: %s", file.get(), michael@0: aLineNumber, (char*) formatted); michael@0: return; michael@0: } michael@0: michael@0: nsCOMPtr console = michael@0: do_GetService(NS_CONSOLESERVICE_CONTRACTID); michael@0: if (!console) michael@0: return; michael@0: michael@0: nsresult rv = error->Init(NS_ConvertUTF8toUTF16(formatted), michael@0: NS_ConvertUTF8toUTF16(file), EmptyString(), michael@0: aLineNumber, 0, nsIScriptError::warningFlag, michael@0: "chrome registration"); michael@0: if (NS_FAILED(rv)) michael@0: return; michael@0: michael@0: console->LogMessage(error); michael@0: } michael@0: michael@0: /** michael@0: * Check for a modifier flag of the following forms: michael@0: * "flag" (same as "true") michael@0: * "flag=yes|true|1" michael@0: * "flag="no|false|0" michael@0: * @param aFlag The flag to compare. michael@0: * @param aData The tokenized data to check; this is lowercased michael@0: * before being passed in. michael@0: * @param aResult If the flag is found, the value is assigned here. michael@0: * @return Whether the flag was handled. michael@0: */ michael@0: static bool michael@0: CheckFlag(const nsSubstring& aFlag, const nsSubstring& aData, bool& aResult) michael@0: { michael@0: if (!StringBeginsWith(aData, aFlag)) michael@0: return false; michael@0: michael@0: if (aFlag.Length() == aData.Length()) { michael@0: // the data is simply "flag", which is the same as "flag=yes" michael@0: aResult = true; michael@0: return true; michael@0: } michael@0: michael@0: if (aData.CharAt(aFlag.Length()) != '=') { michael@0: // the data is "flag2=", which is not anything we care about michael@0: return false; michael@0: } michael@0: michael@0: if (aData.Length() == aFlag.Length() + 1) { michael@0: aResult = false; michael@0: return true; michael@0: } michael@0: michael@0: switch (aData.CharAt(aFlag.Length() + 1)) { michael@0: case '1': michael@0: case 't': //true michael@0: case 'y': //yes michael@0: aResult = true; michael@0: return true; michael@0: michael@0: case '0': michael@0: case 'f': //false michael@0: case 'n': //no michael@0: aResult = false; michael@0: return true; michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: enum TriState { michael@0: eUnspecified, michael@0: eBad, michael@0: eOK michael@0: }; michael@0: michael@0: /** michael@0: * Check for a modifier flag of the following form: michael@0: * "flag=string" michael@0: * "flag!=string" michael@0: * @param aFlag The flag to compare. michael@0: * @param aData The tokenized data to check; this is lowercased michael@0: * before being passed in. michael@0: * @param aValue The value that is expected. michael@0: * @param aResult If this is "ok" when passed in, this is left alone. michael@0: * Otherwise if the flag is found it is set to eBad or eOK. michael@0: * @return Whether the flag was handled. michael@0: */ michael@0: static bool michael@0: CheckStringFlag(const nsSubstring& aFlag, const nsSubstring& aData, michael@0: const nsSubstring& aValue, TriState& aResult) michael@0: { michael@0: if (aData.Length() < aFlag.Length() + 1) michael@0: return false; michael@0: michael@0: if (!StringBeginsWith(aData, aFlag)) michael@0: return false; michael@0: michael@0: bool comparison = true; michael@0: if (aData[aFlag.Length()] != '=') { michael@0: if (aData[aFlag.Length()] == '!' && michael@0: aData.Length() >= aFlag.Length() + 2 && michael@0: aData[aFlag.Length() + 1] == '=') michael@0: comparison = false; michael@0: else michael@0: return false; michael@0: } michael@0: michael@0: if (aResult != eOK) { michael@0: nsDependentSubstring testdata = Substring(aData, aFlag.Length() + (comparison ? 1 : 2)); michael@0: if (testdata.Equals(aValue)) michael@0: aResult = comparison ? eOK : eBad; michael@0: else michael@0: aResult = comparison ? eBad : eOK; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: /** michael@0: * Check for a modifier flag of the following form: michael@0: * "flag=version" michael@0: * "flag<=version" michael@0: * "flag=version" michael@0: * "flag>version" michael@0: * @param aFlag The flag to compare. michael@0: * @param aData The tokenized data to check; this is lowercased michael@0: * before being passed in. michael@0: * @param aValue The value that is expected. If this is empty then no michael@0: * comparison will match. michael@0: * @param aResult If this is eOK when passed in, this is left alone. michael@0: * Otherwise if the flag is found it is set to eBad or eOK. michael@0: * @return Whether the flag was handled. michael@0: */ michael@0: michael@0: #define COMPARE_EQ 1 << 0 michael@0: #define COMPARE_LT 1 << 1 michael@0: #define COMPARE_GT 1 << 2 michael@0: michael@0: static bool michael@0: CheckVersionFlag(const nsString& aFlag, const nsString& aData, michael@0: const nsString& aValue, TriState& aResult) michael@0: { michael@0: if (aData.Length() < aFlag.Length() + 2) michael@0: return false; michael@0: michael@0: if (!StringBeginsWith(aData, aFlag)) michael@0: return false; michael@0: michael@0: if (aValue.Length() == 0) { michael@0: if (aResult != eOK) michael@0: aResult = eBad; michael@0: return true; michael@0: } michael@0: michael@0: uint32_t comparison; michael@0: nsAutoString testdata; michael@0: michael@0: switch (aData[aFlag.Length()]) { michael@0: case '=': michael@0: comparison = COMPARE_EQ; michael@0: testdata = Substring(aData, aFlag.Length() + 1); michael@0: break; michael@0: michael@0: case '<': michael@0: if (aData[aFlag.Length() + 1] == '=') { michael@0: comparison = COMPARE_EQ | COMPARE_LT; michael@0: testdata = Substring(aData, aFlag.Length() + 2); michael@0: } michael@0: else { michael@0: comparison = COMPARE_LT; michael@0: testdata = Substring(aData, aFlag.Length() + 1); michael@0: } michael@0: break; michael@0: michael@0: case '>': michael@0: if (aData[aFlag.Length() + 1] == '=') { michael@0: comparison = COMPARE_EQ | COMPARE_GT; michael@0: testdata = Substring(aData, aFlag.Length() + 2); michael@0: } michael@0: else { michael@0: comparison = COMPARE_GT; michael@0: testdata = Substring(aData, aFlag.Length() + 1); michael@0: } michael@0: break; michael@0: michael@0: default: michael@0: return false; michael@0: } michael@0: michael@0: if (testdata.Length() == 0) michael@0: return false; michael@0: michael@0: if (aResult != eOK) { michael@0: int32_t c = mozilla::CompareVersions(NS_ConvertUTF16toUTF8(aValue).get(), michael@0: NS_ConvertUTF16toUTF8(testdata).get()); michael@0: if ((c == 0 && comparison & COMPARE_EQ) || michael@0: (c < 0 && comparison & COMPARE_LT) || michael@0: (c > 0 && comparison & COMPARE_GT)) michael@0: aResult = eOK; michael@0: else michael@0: aResult = eBad; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: // In-place conversion of ascii characters to lower case michael@0: static void michael@0: ToLowerCase(char* token) michael@0: { michael@0: for (; *token; ++token) michael@0: *token = NS_ToLower(*token); michael@0: } michael@0: michael@0: namespace { michael@0: michael@0: struct CachedDirective michael@0: { michael@0: int lineno; michael@0: char* argv[4]; michael@0: }; michael@0: michael@0: } // anonymous namespace michael@0: michael@0: michael@0: void michael@0: ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOnly) michael@0: { michael@0: nsComponentManagerImpl::ManifestProcessingContext mgrcx(type, file, aChromeOnly); michael@0: nsChromeRegistry::ManifestProcessingContext chromecx(type, file); michael@0: nsresult rv; michael@0: michael@0: NS_NAMED_LITERAL_STRING(kPlatform, "platform"); michael@0: NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible"); michael@0: NS_NAMED_LITERAL_STRING(kApplication, "application"); michael@0: NS_NAMED_LITERAL_STRING(kAppVersion, "appversion"); michael@0: NS_NAMED_LITERAL_STRING(kGeckoVersion, "platformversion"); michael@0: NS_NAMED_LITERAL_STRING(kOs, "os"); michael@0: NS_NAMED_LITERAL_STRING(kOsVersion, "osversion"); michael@0: NS_NAMED_LITERAL_STRING(kABI, "abi"); michael@0: #if defined(MOZ_WIDGET_ANDROID) michael@0: NS_NAMED_LITERAL_STRING(kTablet, "tablet"); michael@0: #endif michael@0: michael@0: // Obsolete michael@0: NS_NAMED_LITERAL_STRING(kXPCNativeWrappers, "xpcnativewrappers"); michael@0: michael@0: nsAutoString appID; michael@0: nsAutoString appVersion; michael@0: nsAutoString geckoVersion; michael@0: nsAutoString osTarget; michael@0: nsAutoString abi; michael@0: michael@0: nsCOMPtr xapp (do_GetService(XULAPPINFO_SERVICE_CONTRACTID)); michael@0: if (xapp) { michael@0: nsAutoCString s; michael@0: rv = xapp->GetID(s); michael@0: if (NS_SUCCEEDED(rv)) michael@0: CopyUTF8toUTF16(s, appID); michael@0: michael@0: rv = xapp->GetVersion(s); michael@0: if (NS_SUCCEEDED(rv)) michael@0: CopyUTF8toUTF16(s, appVersion); michael@0: michael@0: rv = xapp->GetPlatformVersion(s); michael@0: if (NS_SUCCEEDED(rv)) michael@0: CopyUTF8toUTF16(s, geckoVersion); michael@0: michael@0: nsCOMPtr xruntime (do_QueryInterface(xapp)); michael@0: if (xruntime) { michael@0: rv = xruntime->GetOS(s); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: ToLowerCase(s); michael@0: CopyUTF8toUTF16(s, osTarget); michael@0: } michael@0: michael@0: rv = xruntime->GetXPCOMABI(s); michael@0: if (NS_SUCCEEDED(rv) && osTarget.Length()) { michael@0: ToLowerCase(s); michael@0: CopyUTF8toUTF16(s, abi); michael@0: abi.Insert(char16_t('_'), 0); michael@0: abi.Insert(osTarget, 0); michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsAutoString osVersion; michael@0: #if defined(XP_WIN) michael@0: #pragma warning(push) michael@0: #pragma warning(disable:4996) // VC12+ deprecates GetVersionEx michael@0: OSVERSIONINFO info = { sizeof(OSVERSIONINFO) }; michael@0: if (GetVersionEx(&info)) { michael@0: nsTextFormatter::ssprintf(osVersion, MOZ_UTF16("%ld.%ld"), michael@0: info.dwMajorVersion, michael@0: info.dwMinorVersion); michael@0: } michael@0: #pragma warning(pop) michael@0: #elif defined(MOZ_WIDGET_COCOA) michael@0: SInt32 majorVersion = nsCocoaFeatures::OSXVersionMajor(); michael@0: SInt32 minorVersion = nsCocoaFeatures::OSXVersionMinor(); michael@0: nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(), michael@0: majorVersion, michael@0: minorVersion); michael@0: #elif defined(MOZ_WIDGET_GTK) michael@0: nsTextFormatter::ssprintf(osVersion, MOZ_UTF16("%ld.%ld"), michael@0: gtk_major_version, michael@0: gtk_minor_version); michael@0: #elif defined(MOZ_WIDGET_ANDROID) michael@0: bool isTablet = false; michael@0: if (mozilla::AndroidBridge::Bridge()) { michael@0: mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build$VERSION", "RELEASE", osVersion); michael@0: isTablet = mozilla::widget::android::GeckoAppShell::IsTablet(); michael@0: } michael@0: #endif michael@0: michael@0: // Because contracts must be registered after CIDs, we save and process them michael@0: // at the end. michael@0: nsTArray contracts; michael@0: michael@0: char *token; michael@0: char *newline = buf; michael@0: uint32_t line = 0; michael@0: michael@0: // outer loop tokenizes by newline michael@0: while (*newline) { michael@0: while (*newline && IsNewline(*newline)) { michael@0: ++newline; michael@0: ++line; michael@0: } michael@0: if (!*newline) michael@0: break; michael@0: michael@0: token = newline; michael@0: while (*newline && !IsNewline(*newline)) michael@0: ++newline; michael@0: michael@0: if (*newline) { michael@0: *newline = '\0'; michael@0: ++newline; michael@0: } michael@0: ++line; michael@0: michael@0: if (*token == '#') // ignore lines that begin with # as comments michael@0: continue; michael@0: michael@0: char *whitespace = token; michael@0: token = nsCRT::strtok(whitespace, kWhitespace, &whitespace); michael@0: if (!token) continue; michael@0: michael@0: const ManifestDirective* directive = nullptr; michael@0: for (const ManifestDirective* d = kParsingTable; michael@0: d < ArrayEnd(kParsingTable); michael@0: ++d) { michael@0: if (!strcmp(d->directive, token)) { michael@0: directive = d; michael@0: break; michael@0: } michael@0: } michael@0: michael@0: if (!directive) { michael@0: LogMessageWithContext(file, line, michael@0: "Ignoring unrecognized chrome manifest directive '%s'.", michael@0: token); michael@0: continue; michael@0: } michael@0: michael@0: if (!directive->allowbootstrap && NS_BOOTSTRAPPED_LOCATION == type) { michael@0: LogMessageWithContext(file, line, michael@0: "Bootstrapped manifest not allowed to use '%s' directive.", michael@0: token); michael@0: continue; michael@0: } michael@0: michael@0: if (directive->componentonly && NS_SKIN_LOCATION == type) { michael@0: LogMessageWithContext(file, line, michael@0: "Skin manifest not allowed to use '%s' directive.", michael@0: token); michael@0: continue; michael@0: } michael@0: michael@0: NS_ASSERTION(directive->argc < 4, "Need to reset argv array length"); michael@0: char* argv[4]; michael@0: for (int i = 0; i < directive->argc; ++i) michael@0: argv[i] = nsCRT::strtok(whitespace, kWhitespace, &whitespace); michael@0: michael@0: if (!argv[directive->argc - 1]) { michael@0: LogMessageWithContext(file, line, michael@0: "Not enough arguments for chrome manifest directive '%s', expected %i.", michael@0: token, directive->argc); michael@0: continue; michael@0: } michael@0: michael@0: bool ok = true; michael@0: TriState stAppVersion = eUnspecified; michael@0: TriState stGeckoVersion = eUnspecified; michael@0: TriState stApp = eUnspecified; michael@0: TriState stOsVersion = eUnspecified; michael@0: TriState stOs = eUnspecified; michael@0: TriState stABI = eUnspecified; michael@0: #if defined(MOZ_WIDGET_ANDROID) michael@0: TriState stTablet = eUnspecified; michael@0: #endif michael@0: bool platform = false; michael@0: bool contentAccessible = false; michael@0: michael@0: while (nullptr != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) && ok) { michael@0: ToLowerCase(token); michael@0: NS_ConvertASCIItoUTF16 wtoken(token); michael@0: michael@0: if (CheckStringFlag(kApplication, wtoken, appID, stApp) || michael@0: CheckStringFlag(kOs, wtoken, osTarget, stOs) || michael@0: CheckStringFlag(kABI, wtoken, abi, stABI) || michael@0: CheckVersionFlag(kOsVersion, wtoken, osVersion, stOsVersion) || michael@0: CheckVersionFlag(kAppVersion, wtoken, appVersion, stAppVersion) || michael@0: CheckVersionFlag(kGeckoVersion, wtoken, geckoVersion, stGeckoVersion)) michael@0: continue; michael@0: michael@0: #if defined(MOZ_WIDGET_ANDROID) michael@0: bool tablet = false; michael@0: if (CheckFlag(kTablet, wtoken, tablet)) { michael@0: stTablet = (tablet == isTablet) ? eOK : eBad; michael@0: continue; michael@0: } michael@0: #endif michael@0: michael@0: if (directive->contentflags && michael@0: (CheckFlag(kPlatform, wtoken, platform) || michael@0: CheckFlag(kContentAccessible, wtoken, contentAccessible))) michael@0: continue; michael@0: michael@0: bool xpcNativeWrappers = true; // Dummy for CheckFlag. michael@0: if (CheckFlag(kXPCNativeWrappers, wtoken, xpcNativeWrappers)) { michael@0: LogMessageWithContext(file, line, michael@0: "Ignoring obsolete chrome registration modifier '%s'.", michael@0: token); michael@0: continue; michael@0: } michael@0: michael@0: LogMessageWithContext(file, line, michael@0: "Unrecognized chrome manifest modifier '%s'.", michael@0: token); michael@0: ok = false; michael@0: } michael@0: michael@0: if (!ok || michael@0: stApp == eBad || michael@0: stAppVersion == eBad || michael@0: stGeckoVersion == eBad || michael@0: stOs == eBad || michael@0: stOsVersion == eBad || michael@0: #ifdef MOZ_WIDGET_ANDROID michael@0: stTablet == eBad || michael@0: #endif michael@0: stABI == eBad) michael@0: continue; michael@0: michael@0: if (directive->regfunc) { michael@0: if (GeckoProcessType_Default != XRE_GetProcessType()) michael@0: continue; michael@0: michael@0: if (!nsChromeRegistry::gChromeRegistry) { michael@0: nsCOMPtr cr = michael@0: mozilla::services::GetChromeRegistryService(); michael@0: if (!nsChromeRegistry::gChromeRegistry) { michael@0: LogMessageWithContext(file, line, michael@0: "Chrome registry isn't available yet."); michael@0: continue; michael@0: } michael@0: } michael@0: michael@0: (nsChromeRegistry::gChromeRegistry->*(directive->regfunc)) michael@0: (chromecx, line, argv, platform, contentAccessible); michael@0: } michael@0: else if (directive->ischrome || !aChromeOnly) { michael@0: if (directive->isContract) { michael@0: CachedDirective* cd = contracts.AppendElement(); michael@0: cd->lineno = line; michael@0: cd->argv[0] = argv[0]; michael@0: cd->argv[1] = argv[1]; michael@0: } michael@0: else michael@0: (nsComponentManagerImpl::gComponentManager->*(directive->mgrfunc)) michael@0: (mgrcx, line, argv); michael@0: } michael@0: } michael@0: michael@0: for (uint32_t i = 0; i < contracts.Length(); ++i) { michael@0: CachedDirective& d = contracts[i]; michael@0: nsComponentManagerImpl::gComponentManager->ManifestContract michael@0: (mgrcx, d.lineno, d.argv); michael@0: } michael@0: }