xpcom/components/ManifestParser.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "mozilla/ArrayUtils.h"
michael@0 7
michael@0 8 #include "ManifestParser.h"
michael@0 9
michael@0 10 #include <string.h>
michael@0 11
michael@0 12 #include "prio.h"
michael@0 13 #include "prprf.h"
michael@0 14 #if defined(XP_WIN)
michael@0 15 #include <windows.h>
michael@0 16 #elif defined(MOZ_WIDGET_COCOA)
michael@0 17 #include <CoreServices/CoreServices.h>
michael@0 18 #include "nsCocoaFeatures.h"
michael@0 19 #elif defined(MOZ_WIDGET_GTK)
michael@0 20 #include <gtk/gtk.h>
michael@0 21 #endif
michael@0 22
michael@0 23 #ifdef MOZ_WIDGET_ANDROID
michael@0 24 #include "AndroidBridge.h"
michael@0 25 #endif
michael@0 26
michael@0 27 #include "mozilla/Services.h"
michael@0 28
michael@0 29 #include "nsCRT.h"
michael@0 30 #include "nsConsoleMessage.h"
michael@0 31 #include "nsTextFormatter.h"
michael@0 32 #include "nsVersionComparator.h"
michael@0 33 #include "nsXPCOMCIDInternal.h"
michael@0 34
michael@0 35 #include "nsIConsoleService.h"
michael@0 36 #include "nsIScriptError.h"
michael@0 37 #include "nsIXULAppInfo.h"
michael@0 38 #include "nsIXULRuntime.h"
michael@0 39
michael@0 40 using namespace mozilla;
michael@0 41
michael@0 42 struct ManifestDirective
michael@0 43 {
michael@0 44 const char* directive;
michael@0 45 int argc;
michael@0 46
michael@0 47 // Some directives should only be delivered for NS_COMPONENT_LOCATION
michael@0 48 // manifests.
michael@0 49 bool componentonly;
michael@0 50
michael@0 51 bool ischrome;
michael@0 52
michael@0 53 bool allowbootstrap;
michael@0 54
michael@0 55 // The platform/contentaccessible flags only apply to content directives.
michael@0 56 bool contentflags;
michael@0 57
michael@0 58 // Function to handle this directive. This isn't a union because C++ still
michael@0 59 // hasn't learned how to initialize unions in a sane way.
michael@0 60 void (nsComponentManagerImpl::*mgrfunc)
michael@0 61 (nsComponentManagerImpl::ManifestProcessingContext& cx,
michael@0 62 int lineno, char *const * argv);
michael@0 63 void (nsChromeRegistry::*regfunc)
michael@0 64 (nsChromeRegistry::ManifestProcessingContext& cx,
michael@0 65 int lineno, char *const *argv,
michael@0 66 bool platform, bool contentaccessible);
michael@0 67
michael@0 68 bool isContract;
michael@0 69 };
michael@0 70 static const ManifestDirective kParsingTable[] = {
michael@0 71 { "manifest", 1, false, true, true, false,
michael@0 72 &nsComponentManagerImpl::ManifestManifest, nullptr },
michael@0 73 { "binary-component", 1, true, false, false, false,
michael@0 74 &nsComponentManagerImpl::ManifestBinaryComponent, nullptr },
michael@0 75 { "interfaces", 1, true, false, false, false,
michael@0 76 &nsComponentManagerImpl::ManifestXPT, nullptr },
michael@0 77 { "component", 2, true, false, false, false,
michael@0 78 &nsComponentManagerImpl::ManifestComponent, nullptr },
michael@0 79 { "contract", 2, true, false, false, false,
michael@0 80 &nsComponentManagerImpl::ManifestContract, nullptr, true},
michael@0 81 { "category", 3, true, false, false, false,
michael@0 82 &nsComponentManagerImpl::ManifestCategory, nullptr },
michael@0 83 { "content", 2, true, true, true, true,
michael@0 84 nullptr, &nsChromeRegistry::ManifestContent },
michael@0 85 { "locale", 3, true, true, true, false,
michael@0 86 nullptr, &nsChromeRegistry::ManifestLocale },
michael@0 87 { "skin", 3, false, true, true, false,
michael@0 88 nullptr, &nsChromeRegistry::ManifestSkin },
michael@0 89 { "overlay", 2, true, true, false, false,
michael@0 90 nullptr, &nsChromeRegistry::ManifestOverlay },
michael@0 91 { "style", 2, false, true, false, false,
michael@0 92 nullptr, &nsChromeRegistry::ManifestStyle },
michael@0 93 { "override", 2, true, true, true, false,
michael@0 94 nullptr, &nsChromeRegistry::ManifestOverride },
michael@0 95 { "resource", 2, true, true, false, false,
michael@0 96 nullptr, &nsChromeRegistry::ManifestResource }
michael@0 97 };
michael@0 98
michael@0 99 static const char kWhitespace[] = "\t ";
michael@0 100
michael@0 101 static bool IsNewline(char c)
michael@0 102 {
michael@0 103 return c == '\n' || c == '\r';
michael@0 104 }
michael@0 105
michael@0 106 namespace {
michael@0 107 struct AutoPR_smprintf_free
michael@0 108 {
michael@0 109 AutoPR_smprintf_free(char* buf)
michael@0 110 : mBuf(buf)
michael@0 111 {
michael@0 112 }
michael@0 113
michael@0 114 ~AutoPR_smprintf_free()
michael@0 115 {
michael@0 116 if (mBuf)
michael@0 117 PR_smprintf_free(mBuf);
michael@0 118 }
michael@0 119
michael@0 120 operator char*() const {
michael@0 121 return mBuf;
michael@0 122 }
michael@0 123
michael@0 124 char* mBuf;
michael@0 125 };
michael@0 126
michael@0 127 } // anonymous namespace
michael@0 128
michael@0 129 void LogMessage(const char* aMsg, ...)
michael@0 130 {
michael@0 131 nsCOMPtr<nsIConsoleService> console =
michael@0 132 do_GetService(NS_CONSOLESERVICE_CONTRACTID);
michael@0 133 if (!console)
michael@0 134 return;
michael@0 135
michael@0 136 va_list args;
michael@0 137 va_start(args, aMsg);
michael@0 138 AutoPR_smprintf_free formatted(PR_vsmprintf(aMsg, args));
michael@0 139 va_end(args);
michael@0 140
michael@0 141 nsCOMPtr<nsIConsoleMessage> error =
michael@0 142 new nsConsoleMessage(NS_ConvertUTF8toUTF16(formatted).get());
michael@0 143 console->LogMessage(error);
michael@0 144 }
michael@0 145
michael@0 146 void LogMessageWithContext(FileLocation &aFile,
michael@0 147 uint32_t aLineNumber, const char* aMsg, ...)
michael@0 148 {
michael@0 149 va_list args;
michael@0 150 va_start(args, aMsg);
michael@0 151 AutoPR_smprintf_free formatted(PR_vsmprintf(aMsg, args));
michael@0 152 va_end(args);
michael@0 153 if (!formatted)
michael@0 154 return;
michael@0 155
michael@0 156 nsCString file;
michael@0 157 aFile.GetURIString(file);
michael@0 158
michael@0 159 nsCOMPtr<nsIScriptError> error =
michael@0 160 do_CreateInstance(NS_SCRIPTERROR_CONTRACTID);
michael@0 161 if (!error) {
michael@0 162 // This can happen early in component registration. Fall back to a
michael@0 163 // generic console message.
michael@0 164 LogMessage("Warning: in '%s', line %i: %s", file.get(),
michael@0 165 aLineNumber, (char*) formatted);
michael@0 166 return;
michael@0 167 }
michael@0 168
michael@0 169 nsCOMPtr<nsIConsoleService> console =
michael@0 170 do_GetService(NS_CONSOLESERVICE_CONTRACTID);
michael@0 171 if (!console)
michael@0 172 return;
michael@0 173
michael@0 174 nsresult rv = error->Init(NS_ConvertUTF8toUTF16(formatted),
michael@0 175 NS_ConvertUTF8toUTF16(file), EmptyString(),
michael@0 176 aLineNumber, 0, nsIScriptError::warningFlag,
michael@0 177 "chrome registration");
michael@0 178 if (NS_FAILED(rv))
michael@0 179 return;
michael@0 180
michael@0 181 console->LogMessage(error);
michael@0 182 }
michael@0 183
michael@0 184 /**
michael@0 185 * Check for a modifier flag of the following forms:
michael@0 186 * "flag" (same as "true")
michael@0 187 * "flag=yes|true|1"
michael@0 188 * "flag="no|false|0"
michael@0 189 * @param aFlag The flag to compare.
michael@0 190 * @param aData The tokenized data to check; this is lowercased
michael@0 191 * before being passed in.
michael@0 192 * @param aResult If the flag is found, the value is assigned here.
michael@0 193 * @return Whether the flag was handled.
michael@0 194 */
michael@0 195 static bool
michael@0 196 CheckFlag(const nsSubstring& aFlag, const nsSubstring& aData, bool& aResult)
michael@0 197 {
michael@0 198 if (!StringBeginsWith(aData, aFlag))
michael@0 199 return false;
michael@0 200
michael@0 201 if (aFlag.Length() == aData.Length()) {
michael@0 202 // the data is simply "flag", which is the same as "flag=yes"
michael@0 203 aResult = true;
michael@0 204 return true;
michael@0 205 }
michael@0 206
michael@0 207 if (aData.CharAt(aFlag.Length()) != '=') {
michael@0 208 // the data is "flag2=", which is not anything we care about
michael@0 209 return false;
michael@0 210 }
michael@0 211
michael@0 212 if (aData.Length() == aFlag.Length() + 1) {
michael@0 213 aResult = false;
michael@0 214 return true;
michael@0 215 }
michael@0 216
michael@0 217 switch (aData.CharAt(aFlag.Length() + 1)) {
michael@0 218 case '1':
michael@0 219 case 't': //true
michael@0 220 case 'y': //yes
michael@0 221 aResult = true;
michael@0 222 return true;
michael@0 223
michael@0 224 case '0':
michael@0 225 case 'f': //false
michael@0 226 case 'n': //no
michael@0 227 aResult = false;
michael@0 228 return true;
michael@0 229 }
michael@0 230
michael@0 231 return false;
michael@0 232 }
michael@0 233
michael@0 234 enum TriState {
michael@0 235 eUnspecified,
michael@0 236 eBad,
michael@0 237 eOK
michael@0 238 };
michael@0 239
michael@0 240 /**
michael@0 241 * Check for a modifier flag of the following form:
michael@0 242 * "flag=string"
michael@0 243 * "flag!=string"
michael@0 244 * @param aFlag The flag to compare.
michael@0 245 * @param aData The tokenized data to check; this is lowercased
michael@0 246 * before being passed in.
michael@0 247 * @param aValue The value that is expected.
michael@0 248 * @param aResult If this is "ok" when passed in, this is left alone.
michael@0 249 * Otherwise if the flag is found it is set to eBad or eOK.
michael@0 250 * @return Whether the flag was handled.
michael@0 251 */
michael@0 252 static bool
michael@0 253 CheckStringFlag(const nsSubstring& aFlag, const nsSubstring& aData,
michael@0 254 const nsSubstring& aValue, TriState& aResult)
michael@0 255 {
michael@0 256 if (aData.Length() < aFlag.Length() + 1)
michael@0 257 return false;
michael@0 258
michael@0 259 if (!StringBeginsWith(aData, aFlag))
michael@0 260 return false;
michael@0 261
michael@0 262 bool comparison = true;
michael@0 263 if (aData[aFlag.Length()] != '=') {
michael@0 264 if (aData[aFlag.Length()] == '!' &&
michael@0 265 aData.Length() >= aFlag.Length() + 2 &&
michael@0 266 aData[aFlag.Length() + 1] == '=')
michael@0 267 comparison = false;
michael@0 268 else
michael@0 269 return false;
michael@0 270 }
michael@0 271
michael@0 272 if (aResult != eOK) {
michael@0 273 nsDependentSubstring testdata = Substring(aData, aFlag.Length() + (comparison ? 1 : 2));
michael@0 274 if (testdata.Equals(aValue))
michael@0 275 aResult = comparison ? eOK : eBad;
michael@0 276 else
michael@0 277 aResult = comparison ? eBad : eOK;
michael@0 278 }
michael@0 279
michael@0 280 return true;
michael@0 281 }
michael@0 282
michael@0 283 /**
michael@0 284 * Check for a modifier flag of the following form:
michael@0 285 * "flag=version"
michael@0 286 * "flag<=version"
michael@0 287 * "flag<version"
michael@0 288 * "flag>=version"
michael@0 289 * "flag>version"
michael@0 290 * @param aFlag The flag to compare.
michael@0 291 * @param aData The tokenized data to check; this is lowercased
michael@0 292 * before being passed in.
michael@0 293 * @param aValue The value that is expected. If this is empty then no
michael@0 294 * comparison will match.
michael@0 295 * @param aResult If this is eOK when passed in, this is left alone.
michael@0 296 * Otherwise if the flag is found it is set to eBad or eOK.
michael@0 297 * @return Whether the flag was handled.
michael@0 298 */
michael@0 299
michael@0 300 #define COMPARE_EQ 1 << 0
michael@0 301 #define COMPARE_LT 1 << 1
michael@0 302 #define COMPARE_GT 1 << 2
michael@0 303
michael@0 304 static bool
michael@0 305 CheckVersionFlag(const nsString& aFlag, const nsString& aData,
michael@0 306 const nsString& aValue, TriState& aResult)
michael@0 307 {
michael@0 308 if (aData.Length() < aFlag.Length() + 2)
michael@0 309 return false;
michael@0 310
michael@0 311 if (!StringBeginsWith(aData, aFlag))
michael@0 312 return false;
michael@0 313
michael@0 314 if (aValue.Length() == 0) {
michael@0 315 if (aResult != eOK)
michael@0 316 aResult = eBad;
michael@0 317 return true;
michael@0 318 }
michael@0 319
michael@0 320 uint32_t comparison;
michael@0 321 nsAutoString testdata;
michael@0 322
michael@0 323 switch (aData[aFlag.Length()]) {
michael@0 324 case '=':
michael@0 325 comparison = COMPARE_EQ;
michael@0 326 testdata = Substring(aData, aFlag.Length() + 1);
michael@0 327 break;
michael@0 328
michael@0 329 case '<':
michael@0 330 if (aData[aFlag.Length() + 1] == '=') {
michael@0 331 comparison = COMPARE_EQ | COMPARE_LT;
michael@0 332 testdata = Substring(aData, aFlag.Length() + 2);
michael@0 333 }
michael@0 334 else {
michael@0 335 comparison = COMPARE_LT;
michael@0 336 testdata = Substring(aData, aFlag.Length() + 1);
michael@0 337 }
michael@0 338 break;
michael@0 339
michael@0 340 case '>':
michael@0 341 if (aData[aFlag.Length() + 1] == '=') {
michael@0 342 comparison = COMPARE_EQ | COMPARE_GT;
michael@0 343 testdata = Substring(aData, aFlag.Length() + 2);
michael@0 344 }
michael@0 345 else {
michael@0 346 comparison = COMPARE_GT;
michael@0 347 testdata = Substring(aData, aFlag.Length() + 1);
michael@0 348 }
michael@0 349 break;
michael@0 350
michael@0 351 default:
michael@0 352 return false;
michael@0 353 }
michael@0 354
michael@0 355 if (testdata.Length() == 0)
michael@0 356 return false;
michael@0 357
michael@0 358 if (aResult != eOK) {
michael@0 359 int32_t c = mozilla::CompareVersions(NS_ConvertUTF16toUTF8(aValue).get(),
michael@0 360 NS_ConvertUTF16toUTF8(testdata).get());
michael@0 361 if ((c == 0 && comparison & COMPARE_EQ) ||
michael@0 362 (c < 0 && comparison & COMPARE_LT) ||
michael@0 363 (c > 0 && comparison & COMPARE_GT))
michael@0 364 aResult = eOK;
michael@0 365 else
michael@0 366 aResult = eBad;
michael@0 367 }
michael@0 368
michael@0 369 return true;
michael@0 370 }
michael@0 371
michael@0 372 // In-place conversion of ascii characters to lower case
michael@0 373 static void
michael@0 374 ToLowerCase(char* token)
michael@0 375 {
michael@0 376 for (; *token; ++token)
michael@0 377 *token = NS_ToLower(*token);
michael@0 378 }
michael@0 379
michael@0 380 namespace {
michael@0 381
michael@0 382 struct CachedDirective
michael@0 383 {
michael@0 384 int lineno;
michael@0 385 char* argv[4];
michael@0 386 };
michael@0 387
michael@0 388 } // anonymous namespace
michael@0 389
michael@0 390
michael@0 391 void
michael@0 392 ParseManifest(NSLocationType type, FileLocation &file, char* buf, bool aChromeOnly)
michael@0 393 {
michael@0 394 nsComponentManagerImpl::ManifestProcessingContext mgrcx(type, file, aChromeOnly);
michael@0 395 nsChromeRegistry::ManifestProcessingContext chromecx(type, file);
michael@0 396 nsresult rv;
michael@0 397
michael@0 398 NS_NAMED_LITERAL_STRING(kPlatform, "platform");
michael@0 399 NS_NAMED_LITERAL_STRING(kContentAccessible, "contentaccessible");
michael@0 400 NS_NAMED_LITERAL_STRING(kApplication, "application");
michael@0 401 NS_NAMED_LITERAL_STRING(kAppVersion, "appversion");
michael@0 402 NS_NAMED_LITERAL_STRING(kGeckoVersion, "platformversion");
michael@0 403 NS_NAMED_LITERAL_STRING(kOs, "os");
michael@0 404 NS_NAMED_LITERAL_STRING(kOsVersion, "osversion");
michael@0 405 NS_NAMED_LITERAL_STRING(kABI, "abi");
michael@0 406 #if defined(MOZ_WIDGET_ANDROID)
michael@0 407 NS_NAMED_LITERAL_STRING(kTablet, "tablet");
michael@0 408 #endif
michael@0 409
michael@0 410 // Obsolete
michael@0 411 NS_NAMED_LITERAL_STRING(kXPCNativeWrappers, "xpcnativewrappers");
michael@0 412
michael@0 413 nsAutoString appID;
michael@0 414 nsAutoString appVersion;
michael@0 415 nsAutoString geckoVersion;
michael@0 416 nsAutoString osTarget;
michael@0 417 nsAutoString abi;
michael@0 418
michael@0 419 nsCOMPtr<nsIXULAppInfo> xapp (do_GetService(XULAPPINFO_SERVICE_CONTRACTID));
michael@0 420 if (xapp) {
michael@0 421 nsAutoCString s;
michael@0 422 rv = xapp->GetID(s);
michael@0 423 if (NS_SUCCEEDED(rv))
michael@0 424 CopyUTF8toUTF16(s, appID);
michael@0 425
michael@0 426 rv = xapp->GetVersion(s);
michael@0 427 if (NS_SUCCEEDED(rv))
michael@0 428 CopyUTF8toUTF16(s, appVersion);
michael@0 429
michael@0 430 rv = xapp->GetPlatformVersion(s);
michael@0 431 if (NS_SUCCEEDED(rv))
michael@0 432 CopyUTF8toUTF16(s, geckoVersion);
michael@0 433
michael@0 434 nsCOMPtr<nsIXULRuntime> xruntime (do_QueryInterface(xapp));
michael@0 435 if (xruntime) {
michael@0 436 rv = xruntime->GetOS(s);
michael@0 437 if (NS_SUCCEEDED(rv)) {
michael@0 438 ToLowerCase(s);
michael@0 439 CopyUTF8toUTF16(s, osTarget);
michael@0 440 }
michael@0 441
michael@0 442 rv = xruntime->GetXPCOMABI(s);
michael@0 443 if (NS_SUCCEEDED(rv) && osTarget.Length()) {
michael@0 444 ToLowerCase(s);
michael@0 445 CopyUTF8toUTF16(s, abi);
michael@0 446 abi.Insert(char16_t('_'), 0);
michael@0 447 abi.Insert(osTarget, 0);
michael@0 448 }
michael@0 449 }
michael@0 450 }
michael@0 451
michael@0 452 nsAutoString osVersion;
michael@0 453 #if defined(XP_WIN)
michael@0 454 #pragma warning(push)
michael@0 455 #pragma warning(disable:4996) // VC12+ deprecates GetVersionEx
michael@0 456 OSVERSIONINFO info = { sizeof(OSVERSIONINFO) };
michael@0 457 if (GetVersionEx(&info)) {
michael@0 458 nsTextFormatter::ssprintf(osVersion, MOZ_UTF16("%ld.%ld"),
michael@0 459 info.dwMajorVersion,
michael@0 460 info.dwMinorVersion);
michael@0 461 }
michael@0 462 #pragma warning(pop)
michael@0 463 #elif defined(MOZ_WIDGET_COCOA)
michael@0 464 SInt32 majorVersion = nsCocoaFeatures::OSXVersionMajor();
michael@0 465 SInt32 minorVersion = nsCocoaFeatures::OSXVersionMinor();
michael@0 466 nsTextFormatter::ssprintf(osVersion, NS_LITERAL_STRING("%ld.%ld").get(),
michael@0 467 majorVersion,
michael@0 468 minorVersion);
michael@0 469 #elif defined(MOZ_WIDGET_GTK)
michael@0 470 nsTextFormatter::ssprintf(osVersion, MOZ_UTF16("%ld.%ld"),
michael@0 471 gtk_major_version,
michael@0 472 gtk_minor_version);
michael@0 473 #elif defined(MOZ_WIDGET_ANDROID)
michael@0 474 bool isTablet = false;
michael@0 475 if (mozilla::AndroidBridge::Bridge()) {
michael@0 476 mozilla::AndroidBridge::Bridge()->GetStaticStringField("android/os/Build$VERSION", "RELEASE", osVersion);
michael@0 477 isTablet = mozilla::widget::android::GeckoAppShell::IsTablet();
michael@0 478 }
michael@0 479 #endif
michael@0 480
michael@0 481 // Because contracts must be registered after CIDs, we save and process them
michael@0 482 // at the end.
michael@0 483 nsTArray<CachedDirective> contracts;
michael@0 484
michael@0 485 char *token;
michael@0 486 char *newline = buf;
michael@0 487 uint32_t line = 0;
michael@0 488
michael@0 489 // outer loop tokenizes by newline
michael@0 490 while (*newline) {
michael@0 491 while (*newline && IsNewline(*newline)) {
michael@0 492 ++newline;
michael@0 493 ++line;
michael@0 494 }
michael@0 495 if (!*newline)
michael@0 496 break;
michael@0 497
michael@0 498 token = newline;
michael@0 499 while (*newline && !IsNewline(*newline))
michael@0 500 ++newline;
michael@0 501
michael@0 502 if (*newline) {
michael@0 503 *newline = '\0';
michael@0 504 ++newline;
michael@0 505 }
michael@0 506 ++line;
michael@0 507
michael@0 508 if (*token == '#') // ignore lines that begin with # as comments
michael@0 509 continue;
michael@0 510
michael@0 511 char *whitespace = token;
michael@0 512 token = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
michael@0 513 if (!token) continue;
michael@0 514
michael@0 515 const ManifestDirective* directive = nullptr;
michael@0 516 for (const ManifestDirective* d = kParsingTable;
michael@0 517 d < ArrayEnd(kParsingTable);
michael@0 518 ++d) {
michael@0 519 if (!strcmp(d->directive, token)) {
michael@0 520 directive = d;
michael@0 521 break;
michael@0 522 }
michael@0 523 }
michael@0 524
michael@0 525 if (!directive) {
michael@0 526 LogMessageWithContext(file, line,
michael@0 527 "Ignoring unrecognized chrome manifest directive '%s'.",
michael@0 528 token);
michael@0 529 continue;
michael@0 530 }
michael@0 531
michael@0 532 if (!directive->allowbootstrap && NS_BOOTSTRAPPED_LOCATION == type) {
michael@0 533 LogMessageWithContext(file, line,
michael@0 534 "Bootstrapped manifest not allowed to use '%s' directive.",
michael@0 535 token);
michael@0 536 continue;
michael@0 537 }
michael@0 538
michael@0 539 if (directive->componentonly && NS_SKIN_LOCATION == type) {
michael@0 540 LogMessageWithContext(file, line,
michael@0 541 "Skin manifest not allowed to use '%s' directive.",
michael@0 542 token);
michael@0 543 continue;
michael@0 544 }
michael@0 545
michael@0 546 NS_ASSERTION(directive->argc < 4, "Need to reset argv array length");
michael@0 547 char* argv[4];
michael@0 548 for (int i = 0; i < directive->argc; ++i)
michael@0 549 argv[i] = nsCRT::strtok(whitespace, kWhitespace, &whitespace);
michael@0 550
michael@0 551 if (!argv[directive->argc - 1]) {
michael@0 552 LogMessageWithContext(file, line,
michael@0 553 "Not enough arguments for chrome manifest directive '%s', expected %i.",
michael@0 554 token, directive->argc);
michael@0 555 continue;
michael@0 556 }
michael@0 557
michael@0 558 bool ok = true;
michael@0 559 TriState stAppVersion = eUnspecified;
michael@0 560 TriState stGeckoVersion = eUnspecified;
michael@0 561 TriState stApp = eUnspecified;
michael@0 562 TriState stOsVersion = eUnspecified;
michael@0 563 TriState stOs = eUnspecified;
michael@0 564 TriState stABI = eUnspecified;
michael@0 565 #if defined(MOZ_WIDGET_ANDROID)
michael@0 566 TriState stTablet = eUnspecified;
michael@0 567 #endif
michael@0 568 bool platform = false;
michael@0 569 bool contentAccessible = false;
michael@0 570
michael@0 571 while (nullptr != (token = nsCRT::strtok(whitespace, kWhitespace, &whitespace)) && ok) {
michael@0 572 ToLowerCase(token);
michael@0 573 NS_ConvertASCIItoUTF16 wtoken(token);
michael@0 574
michael@0 575 if (CheckStringFlag(kApplication, wtoken, appID, stApp) ||
michael@0 576 CheckStringFlag(kOs, wtoken, osTarget, stOs) ||
michael@0 577 CheckStringFlag(kABI, wtoken, abi, stABI) ||
michael@0 578 CheckVersionFlag(kOsVersion, wtoken, osVersion, stOsVersion) ||
michael@0 579 CheckVersionFlag(kAppVersion, wtoken, appVersion, stAppVersion) ||
michael@0 580 CheckVersionFlag(kGeckoVersion, wtoken, geckoVersion, stGeckoVersion))
michael@0 581 continue;
michael@0 582
michael@0 583 #if defined(MOZ_WIDGET_ANDROID)
michael@0 584 bool tablet = false;
michael@0 585 if (CheckFlag(kTablet, wtoken, tablet)) {
michael@0 586 stTablet = (tablet == isTablet) ? eOK : eBad;
michael@0 587 continue;
michael@0 588 }
michael@0 589 #endif
michael@0 590
michael@0 591 if (directive->contentflags &&
michael@0 592 (CheckFlag(kPlatform, wtoken, platform) ||
michael@0 593 CheckFlag(kContentAccessible, wtoken, contentAccessible)))
michael@0 594 continue;
michael@0 595
michael@0 596 bool xpcNativeWrappers = true; // Dummy for CheckFlag.
michael@0 597 if (CheckFlag(kXPCNativeWrappers, wtoken, xpcNativeWrappers)) {
michael@0 598 LogMessageWithContext(file, line,
michael@0 599 "Ignoring obsolete chrome registration modifier '%s'.",
michael@0 600 token);
michael@0 601 continue;
michael@0 602 }
michael@0 603
michael@0 604 LogMessageWithContext(file, line,
michael@0 605 "Unrecognized chrome manifest modifier '%s'.",
michael@0 606 token);
michael@0 607 ok = false;
michael@0 608 }
michael@0 609
michael@0 610 if (!ok ||
michael@0 611 stApp == eBad ||
michael@0 612 stAppVersion == eBad ||
michael@0 613 stGeckoVersion == eBad ||
michael@0 614 stOs == eBad ||
michael@0 615 stOsVersion == eBad ||
michael@0 616 #ifdef MOZ_WIDGET_ANDROID
michael@0 617 stTablet == eBad ||
michael@0 618 #endif
michael@0 619 stABI == eBad)
michael@0 620 continue;
michael@0 621
michael@0 622 if (directive->regfunc) {
michael@0 623 if (GeckoProcessType_Default != XRE_GetProcessType())
michael@0 624 continue;
michael@0 625
michael@0 626 if (!nsChromeRegistry::gChromeRegistry) {
michael@0 627 nsCOMPtr<nsIChromeRegistry> cr =
michael@0 628 mozilla::services::GetChromeRegistryService();
michael@0 629 if (!nsChromeRegistry::gChromeRegistry) {
michael@0 630 LogMessageWithContext(file, line,
michael@0 631 "Chrome registry isn't available yet.");
michael@0 632 continue;
michael@0 633 }
michael@0 634 }
michael@0 635
michael@0 636 (nsChromeRegistry::gChromeRegistry->*(directive->regfunc))
michael@0 637 (chromecx, line, argv, platform, contentAccessible);
michael@0 638 }
michael@0 639 else if (directive->ischrome || !aChromeOnly) {
michael@0 640 if (directive->isContract) {
michael@0 641 CachedDirective* cd = contracts.AppendElement();
michael@0 642 cd->lineno = line;
michael@0 643 cd->argv[0] = argv[0];
michael@0 644 cd->argv[1] = argv[1];
michael@0 645 }
michael@0 646 else
michael@0 647 (nsComponentManagerImpl::gComponentManager->*(directive->mgrfunc))
michael@0 648 (mgrcx, line, argv);
michael@0 649 }
michael@0 650 }
michael@0 651
michael@0 652 for (uint32_t i = 0; i < contracts.Length(); ++i) {
michael@0 653 CachedDirective& d = contracts[i];
michael@0 654 nsComponentManagerImpl::gComponentManager->ManifestContract
michael@0 655 (mgrcx, d.lineno, d.argv);
michael@0 656 }
michael@0 657 }

mercurial