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 : }
|