Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #include "mozilla/ArrayUtils.h"
7 : #include "mozilla/Move.h"
8 : #include "mozilla/UniquePtr.h"
9 :
10 : #include "txStylesheetCompiler.h"
11 : #include "txStylesheetCompileHandlers.h"
12 : #include "nsGkAtoms.h"
13 : #include "txURIUtils.h"
14 : #include "nsWhitespaceTokenizer.h"
15 : #include "txStylesheet.h"
16 : #include "txInstructions.h"
17 : #include "txToplevelItems.h"
18 : #include "txExprParser.h"
19 : #include "txLog.h"
20 : #include "txPatternParser.h"
21 : #include "txStringUtils.h"
22 : #include "txXSLTFunctions.h"
23 : #include "nsICategoryManager.h"
24 : #include "nsServiceManagerUtils.h"
25 : #include "nsTArray.h"
26 :
27 : using namespace mozilla;
28 : using mozilla::net::ReferrerPolicy;
29 :
30 0 : txStylesheetCompiler::txStylesheetCompiler(const nsAString& aStylesheetURI,
31 : ReferrerPolicy aReferrerPolicy,
32 0 : txACompileObserver* aObserver)
33 0 : : txStylesheetCompilerState(aObserver)
34 : {
35 0 : mStatus = init(aStylesheetURI, aReferrerPolicy, nullptr, nullptr);
36 0 : }
37 :
38 0 : txStylesheetCompiler::txStylesheetCompiler(const nsAString& aStylesheetURI,
39 : txStylesheet* aStylesheet,
40 : txListIterator* aInsertPosition,
41 : ReferrerPolicy aReferrerPolicy,
42 0 : txACompileObserver* aObserver)
43 0 : : txStylesheetCompilerState(aObserver)
44 : {
45 0 : mStatus = init(aStylesheetURI, aReferrerPolicy, aStylesheet,
46 : aInsertPosition);
47 0 : }
48 :
49 : void
50 0 : txStylesheetCompiler::setBaseURI(const nsString& aBaseURI)
51 : {
52 0 : NS_ASSERTION(mObjectStack.size() == 1 && !mObjectStack.peek(),
53 : "Execution already started");
54 :
55 0 : if (NS_FAILED(mStatus)) {
56 0 : return;
57 : }
58 :
59 0 : mElementContext->mBaseURI = aBaseURI;
60 : }
61 :
62 : nsresult
63 0 : txStylesheetCompiler::startElement(int32_t aNamespaceID, nsIAtom* aLocalName,
64 : nsIAtom* aPrefix,
65 : txStylesheetAttr* aAttributes,
66 : int32_t aAttrCount)
67 : {
68 0 : if (NS_FAILED(mStatus)) {
69 : // ignore content after failure
70 : // XXX reevaluate once expat stops on failure
71 0 : return NS_OK;
72 : }
73 :
74 0 : nsresult rv = flushCharacters();
75 0 : NS_ENSURE_SUCCESS(rv, rv);
76 :
77 : // look for new namespace mappings
78 0 : bool hasOwnNamespaceMap = false;
79 : int32_t i;
80 0 : for (i = 0; i < aAttrCount; ++i) {
81 0 : txStylesheetAttr* attr = aAttributes + i;
82 0 : if (attr->mNamespaceID == kNameSpaceID_XMLNS) {
83 0 : rv = ensureNewElementContext();
84 0 : NS_ENSURE_SUCCESS(rv, rv);
85 :
86 0 : if (!hasOwnNamespaceMap) {
87 0 : mElementContext->mMappings =
88 0 : new txNamespaceMap(*mElementContext->mMappings);
89 0 : hasOwnNamespaceMap = true;
90 : }
91 :
92 0 : if (attr->mLocalName == nsGkAtoms::xmlns) {
93 0 : mElementContext->mMappings->mapNamespace(nullptr, attr->mValue);
94 : }
95 : else {
96 0 : mElementContext->mMappings->
97 0 : mapNamespace(attr->mLocalName, attr->mValue);
98 : }
99 : }
100 : }
101 :
102 : return startElementInternal(aNamespaceID, aLocalName, aPrefix,
103 0 : aAttributes, aAttrCount);
104 : }
105 :
106 : nsresult
107 0 : txStylesheetCompiler::startElement(const char16_t *aName,
108 : const char16_t **aAttrs,
109 : int32_t aAttrCount)
110 : {
111 0 : if (NS_FAILED(mStatus)) {
112 : // ignore content after failure
113 : // XXX reevaluate once expat stops on failure
114 0 : return NS_OK;
115 : }
116 :
117 0 : nsresult rv = flushCharacters();
118 0 : NS_ENSURE_SUCCESS(rv, rv);
119 :
120 0 : UniquePtr<txStylesheetAttr[]> atts;
121 0 : if (aAttrCount > 0) {
122 0 : atts = MakeUnique<txStylesheetAttr[]>(aAttrCount);
123 : }
124 :
125 0 : bool hasOwnNamespaceMap = false;
126 : int32_t i;
127 0 : for (i = 0; i < aAttrCount; ++i) {
128 0 : rv = XMLUtils::splitExpatName(aAttrs[i * 2],
129 0 : getter_AddRefs(atts[i].mPrefix),
130 0 : getter_AddRefs(atts[i].mLocalName),
131 0 : &atts[i].mNamespaceID);
132 0 : NS_ENSURE_SUCCESS(rv, rv);
133 0 : atts[i].mValue.Append(aAttrs[i * 2 + 1]);
134 :
135 0 : nsCOMPtr<nsIAtom> prefixToBind;
136 0 : if (atts[i].mPrefix == nsGkAtoms::xmlns) {
137 0 : prefixToBind = atts[i].mLocalName;
138 : }
139 0 : else if (atts[i].mNamespaceID == kNameSpaceID_XMLNS) {
140 0 : prefixToBind = nsGkAtoms::_empty;
141 : }
142 :
143 0 : if (prefixToBind) {
144 0 : rv = ensureNewElementContext();
145 0 : NS_ENSURE_SUCCESS(rv, rv);
146 :
147 0 : if (!hasOwnNamespaceMap) {
148 0 : mElementContext->mMappings =
149 0 : new txNamespaceMap(*mElementContext->mMappings);
150 0 : hasOwnNamespaceMap = true;
151 : }
152 :
153 0 : rv = mElementContext->mMappings->
154 0 : mapNamespace(prefixToBind, atts[i].mValue);
155 0 : NS_ENSURE_SUCCESS(rv, rv);
156 : }
157 : }
158 :
159 0 : nsCOMPtr<nsIAtom> prefix, localname;
160 : int32_t namespaceID;
161 0 : rv = XMLUtils::splitExpatName(aName, getter_AddRefs(prefix),
162 0 : getter_AddRefs(localname), &namespaceID);
163 0 : NS_ENSURE_SUCCESS(rv, rv);
164 :
165 0 : return startElementInternal(namespaceID, localname, prefix, atts.get(),
166 0 : aAttrCount);
167 : }
168 :
169 : nsresult
170 0 : txStylesheetCompiler::startElementInternal(int32_t aNamespaceID,
171 : nsIAtom* aLocalName,
172 : nsIAtom* aPrefix,
173 : txStylesheetAttr* aAttributes,
174 : int32_t aAttrCount)
175 : {
176 0 : nsresult rv = NS_OK;
177 : int32_t i;
178 0 : for (i = mInScopeVariables.Length() - 1; i >= 0; --i) {
179 0 : ++mInScopeVariables[i]->mLevel;
180 : }
181 :
182 : // Update the elementcontext if we have special attributes
183 0 : for (i = 0; i < aAttrCount; ++i) {
184 0 : txStylesheetAttr* attr = aAttributes + i;
185 :
186 : // id
187 0 : if (mEmbedStatus == eNeedEmbed &&
188 0 : attr->mLocalName == nsGkAtoms::id &&
189 0 : attr->mNamespaceID == kNameSpaceID_None &&
190 0 : attr->mValue.Equals(mTarget)) {
191 : // We found the right ID, signal to compile the
192 : // embedded stylesheet.
193 0 : mEmbedStatus = eInEmbed;
194 : }
195 :
196 : // xml:space
197 0 : if (attr->mNamespaceID == kNameSpaceID_XML &&
198 0 : attr->mLocalName == nsGkAtoms::space) {
199 0 : rv = ensureNewElementContext();
200 0 : NS_ENSURE_SUCCESS(rv, rv);
201 :
202 0 : if (TX_StringEqualsAtom(attr->mValue, nsGkAtoms::preserve)) {
203 0 : mElementContext->mPreserveWhitespace = true;
204 : }
205 0 : else if (TX_StringEqualsAtom(attr->mValue, nsGkAtoms::_default)) {
206 0 : mElementContext->mPreserveWhitespace = false;
207 : }
208 : else {
209 0 : return NS_ERROR_XSLT_PARSE_FAILURE;
210 : }
211 : }
212 :
213 : // xml:base
214 0 : if (attr->mNamespaceID == kNameSpaceID_XML &&
215 0 : attr->mLocalName == nsGkAtoms::base &&
216 0 : !attr->mValue.IsEmpty()) {
217 0 : rv = ensureNewElementContext();
218 0 : NS_ENSURE_SUCCESS(rv, rv);
219 :
220 0 : nsAutoString uri;
221 0 : URIUtils::resolveHref(attr->mValue, mElementContext->mBaseURI, uri);
222 0 : mElementContext->mBaseURI = uri;
223 : }
224 :
225 : // extension-element-prefixes
226 0 : if ((attr->mNamespaceID == kNameSpaceID_XSLT &&
227 0 : attr->mLocalName == nsGkAtoms::extensionElementPrefixes &&
228 0 : aNamespaceID != kNameSpaceID_XSLT) ||
229 0 : (attr->mNamespaceID == kNameSpaceID_None &&
230 0 : attr->mLocalName == nsGkAtoms::extensionElementPrefixes &&
231 0 : aNamespaceID == kNameSpaceID_XSLT &&
232 0 : (aLocalName == nsGkAtoms::stylesheet ||
233 0 : aLocalName == nsGkAtoms::transform))) {
234 0 : rv = ensureNewElementContext();
235 0 : NS_ENSURE_SUCCESS(rv, rv);
236 :
237 0 : nsWhitespaceTokenizer tok(attr->mValue);
238 0 : while (tok.hasMoreTokens()) {
239 0 : int32_t namespaceID = mElementContext->mMappings->
240 0 : lookupNamespaceWithDefault(tok.nextToken());
241 :
242 0 : if (namespaceID == kNameSpaceID_Unknown)
243 0 : return NS_ERROR_XSLT_PARSE_FAILURE;
244 :
245 0 : if (!mElementContext->mInstructionNamespaces.
246 0 : AppendElement(namespaceID)) {
247 0 : return NS_ERROR_OUT_OF_MEMORY;
248 : }
249 : }
250 :
251 0 : attr->mLocalName = nullptr;
252 : }
253 :
254 : // version
255 0 : if ((attr->mNamespaceID == kNameSpaceID_XSLT &&
256 0 : attr->mLocalName == nsGkAtoms::version &&
257 0 : aNamespaceID != kNameSpaceID_XSLT) ||
258 0 : (attr->mNamespaceID == kNameSpaceID_None &&
259 0 : attr->mLocalName == nsGkAtoms::version &&
260 0 : aNamespaceID == kNameSpaceID_XSLT &&
261 0 : (aLocalName == nsGkAtoms::stylesheet ||
262 0 : aLocalName == nsGkAtoms::transform))) {
263 0 : rv = ensureNewElementContext();
264 0 : NS_ENSURE_SUCCESS(rv, rv);
265 :
266 0 : if (attr->mValue.EqualsLiteral("1.0")) {
267 0 : mElementContext->mForwardsCompatibleParsing = false;
268 : }
269 : else {
270 0 : mElementContext->mForwardsCompatibleParsing = true;
271 : }
272 : }
273 : }
274 :
275 : // Find the right elementhandler and execute it
276 0 : bool isInstruction = false;
277 0 : int32_t count = mElementContext->mInstructionNamespaces.Length();
278 0 : for (i = 0; i < count; ++i) {
279 0 : if (mElementContext->mInstructionNamespaces[i] == aNamespaceID) {
280 0 : isInstruction = true;
281 0 : break;
282 : }
283 : }
284 :
285 : const txElementHandler* handler;
286 0 : do {
287 0 : handler = isInstruction ?
288 0 : mHandlerTable->find(aNamespaceID, aLocalName) :
289 0 : mHandlerTable->mLREHandler;
290 :
291 0 : rv = (handler->mStartFunction)(aNamespaceID, aLocalName, aPrefix,
292 0 : aAttributes, aAttrCount, *this);
293 0 : } while (rv == NS_XSLT_GET_NEW_HANDLER);
294 :
295 0 : NS_ENSURE_SUCCESS(rv, rv);
296 :
297 0 : if (!fcp()) {
298 0 : for (i = 0; i < aAttrCount; ++i) {
299 0 : txStylesheetAttr& attr = aAttributes[i];
300 0 : if (attr.mLocalName &&
301 0 : (attr.mNamespaceID == kNameSpaceID_XSLT ||
302 0 : (aNamespaceID == kNameSpaceID_XSLT &&
303 0 : attr.mNamespaceID == kNameSpaceID_None))) {
304 : // XXX ErrorReport: unknown attribute
305 0 : return NS_ERROR_XSLT_PARSE_FAILURE;
306 : }
307 : }
308 : }
309 :
310 0 : rv = pushPtr(const_cast<txElementHandler*>(handler), eElementHandler);
311 0 : NS_ENSURE_SUCCESS(rv, rv);
312 :
313 0 : mElementContext->mDepth++;
314 :
315 0 : return NS_OK;
316 : }
317 :
318 : nsresult
319 0 : txStylesheetCompiler::endElement()
320 : {
321 0 : if (NS_FAILED(mStatus)) {
322 : // ignore content after failure
323 : // XXX reevaluate once expat stops on failure
324 0 : return NS_OK;
325 : }
326 :
327 0 : nsresult rv = flushCharacters();
328 0 : NS_ENSURE_SUCCESS(rv, rv);
329 :
330 : int32_t i;
331 0 : for (i = mInScopeVariables.Length() - 1; i >= 0; --i) {
332 0 : txInScopeVariable* var = mInScopeVariables[i];
333 0 : if (!--(var->mLevel)) {
334 0 : nsAutoPtr<txInstruction> instr(new txRemoveVariable(var->mName));
335 0 : rv = addInstruction(Move(instr));
336 0 : NS_ENSURE_SUCCESS(rv, rv);
337 :
338 0 : mInScopeVariables.RemoveElementAt(i);
339 0 : delete var;
340 : }
341 : }
342 :
343 : const txElementHandler* handler =
344 : const_cast<const txElementHandler*>
345 0 : (static_cast<txElementHandler*>(popPtr(eElementHandler)));
346 0 : rv = (handler->mEndFunction)(*this);
347 0 : NS_ENSURE_SUCCESS(rv, rv);
348 :
349 0 : if (!--mElementContext->mDepth) {
350 : // this will delete the old object
351 0 : mElementContext = static_cast<txElementContext*>(popObject());
352 : }
353 :
354 0 : return NS_OK;
355 : }
356 :
357 : nsresult
358 0 : txStylesheetCompiler::characters(const nsAString& aStr)
359 : {
360 0 : if (NS_FAILED(mStatus)) {
361 : // ignore content after failure
362 : // XXX reevaluate once expat stops on failure
363 0 : return NS_OK;
364 : }
365 :
366 0 : mCharacters.Append(aStr);
367 :
368 0 : return NS_OK;
369 : }
370 :
371 : nsresult
372 0 : txStylesheetCompiler::doneLoading()
373 : {
374 0 : MOZ_LOG(txLog::xslt, LogLevel::Info,
375 : ("Compiler::doneLoading: %s\n",
376 : NS_LossyConvertUTF16toASCII(mStylesheetURI).get()));
377 0 : if (NS_FAILED(mStatus)) {
378 0 : return mStatus;
379 : }
380 :
381 0 : mDoneWithThisStylesheet = true;
382 :
383 0 : return maybeDoneCompiling();
384 : }
385 :
386 : void
387 0 : txStylesheetCompiler::cancel(nsresult aError, const char16_t *aErrorText,
388 : const char16_t *aParam)
389 : {
390 0 : MOZ_LOG(txLog::xslt, LogLevel::Info,
391 : ("Compiler::cancel: %s, module: %d, code %d\n",
392 : NS_LossyConvertUTF16toASCII(mStylesheetURI).get(),
393 : NS_ERROR_GET_MODULE(aError),
394 : NS_ERROR_GET_CODE(aError)));
395 0 : if (NS_SUCCEEDED(mStatus)) {
396 0 : mStatus = aError;
397 : }
398 :
399 0 : if (mObserver) {
400 0 : mObserver->onDoneCompiling(this, mStatus, aErrorText, aParam);
401 : // This will ensure that we don't call onDoneCompiling twice. Also
402 : // ensures that we don't keep the observer alive longer then necessary.
403 0 : mObserver = nullptr;
404 : }
405 0 : }
406 :
407 : txStylesheet*
408 0 : txStylesheetCompiler::getStylesheet()
409 : {
410 0 : return mStylesheet;
411 : }
412 :
413 : nsresult
414 0 : txStylesheetCompiler::loadURI(const nsAString& aUri,
415 : const nsAString& aReferrerUri,
416 : ReferrerPolicy aReferrerPolicy,
417 : txStylesheetCompiler* aCompiler)
418 : {
419 0 : MOZ_LOG(txLog::xslt, LogLevel::Info,
420 : ("Compiler::loadURI forwards %s thru %s\n",
421 : NS_LossyConvertUTF16toASCII(aUri).get(),
422 : NS_LossyConvertUTF16toASCII(mStylesheetURI).get()));
423 0 : if (mStylesheetURI.Equals(aUri)) {
424 0 : return NS_ERROR_XSLT_LOAD_RECURSION;
425 : }
426 0 : return mObserver ?
427 0 : mObserver->loadURI(aUri, aReferrerUri, aReferrerPolicy, aCompiler) :
428 0 : NS_ERROR_FAILURE;
429 : }
430 :
431 : void
432 0 : txStylesheetCompiler::onDoneCompiling(txStylesheetCompiler* aCompiler,
433 : nsresult aResult,
434 : const char16_t *aErrorText,
435 : const char16_t *aParam)
436 : {
437 0 : if (NS_FAILED(aResult)) {
438 0 : cancel(aResult, aErrorText, aParam);
439 0 : return;
440 : }
441 :
442 0 : mChildCompilerList.RemoveElement(aCompiler);
443 :
444 0 : maybeDoneCompiling();
445 : }
446 :
447 : nsresult
448 0 : txStylesheetCompiler::flushCharacters()
449 : {
450 : // Bail if we don't have any characters. The handler will detect
451 : // ignoreable whitespace
452 0 : if (mCharacters.IsEmpty()) {
453 0 : return NS_OK;
454 : }
455 :
456 0 : nsresult rv = NS_OK;
457 :
458 0 : do {
459 0 : rv = (mHandlerTable->mTextHandler)(mCharacters, *this);
460 0 : } while (rv == NS_XSLT_GET_NEW_HANDLER);
461 :
462 0 : NS_ENSURE_SUCCESS(rv, rv);
463 :
464 0 : mCharacters.Truncate();
465 :
466 0 : return NS_OK;
467 : }
468 :
469 : nsresult
470 0 : txStylesheetCompiler::ensureNewElementContext()
471 : {
472 : // Do we already have a new context?
473 0 : if (!mElementContext->mDepth) {
474 0 : return NS_OK;
475 : }
476 :
477 : nsAutoPtr<txElementContext>
478 0 : context(new txElementContext(*mElementContext));
479 0 : nsresult rv = pushObject(mElementContext);
480 0 : NS_ENSURE_SUCCESS(rv, rv);
481 :
482 0 : mElementContext.forget();
483 0 : mElementContext = Move(context);
484 :
485 0 : return NS_OK;
486 : }
487 :
488 : nsresult
489 0 : txStylesheetCompiler::maybeDoneCompiling()
490 : {
491 0 : if (!mDoneWithThisStylesheet || !mChildCompilerList.IsEmpty()) {
492 0 : return NS_OK;
493 : }
494 :
495 0 : if (mIsTopCompiler) {
496 0 : nsresult rv = mStylesheet->doneCompiling();
497 0 : if (NS_FAILED(rv)) {
498 0 : cancel(rv);
499 0 : return rv;
500 : }
501 : }
502 :
503 0 : if (mObserver) {
504 0 : mObserver->onDoneCompiling(this, mStatus);
505 : // This will ensure that we don't call onDoneCompiling twice. Also
506 : // ensures that we don't keep the observer alive longer then necessary.
507 0 : mObserver = nullptr;
508 : }
509 :
510 0 : return NS_OK;
511 : }
512 :
513 : /**
514 : * txStylesheetCompilerState
515 : */
516 :
517 :
518 0 : txStylesheetCompilerState::txStylesheetCompilerState(txACompileObserver* aObserver)
519 : : mHandlerTable(nullptr),
520 : mSorter(nullptr),
521 : mDOE(false),
522 : mSearchingForFallback(false),
523 : mDisAllowed(0),
524 : mObserver(aObserver),
525 : mEmbedStatus(eNoEmbed),
526 : mDoneWithThisStylesheet(false),
527 : mNextInstrPtr(nullptr),
528 0 : mToplevelIterator(nullptr)
529 : {
530 : // Embedded stylesheets have another handler, which is set in
531 : // txStylesheetCompiler::init if the baseURI has a fragment identifier.
532 0 : mHandlerTable = gTxRootHandler;
533 :
534 0 : }
535 :
536 : nsresult
537 0 : txStylesheetCompilerState::init(const nsAString& aStylesheetURI,
538 : ReferrerPolicy aReferrerPolicy,
539 : txStylesheet* aStylesheet,
540 : txListIterator* aInsertPosition)
541 : {
542 0 : NS_ASSERTION(!aStylesheet || aInsertPosition,
543 : "must provide insertposition if loading subsheet");
544 0 : mStylesheetURI = aStylesheetURI;
545 0 : mReferrerPolicy = aReferrerPolicy;
546 : // Check for fragment identifier of an embedded stylesheet.
547 0 : int32_t fragment = aStylesheetURI.FindChar('#') + 1;
548 0 : if (fragment > 0) {
549 0 : int32_t fragmentLength = aStylesheetURI.Length() - fragment;
550 0 : if (fragmentLength > 0) {
551 : // This is really an embedded stylesheet, not just a
552 : // "url#". We may want to unescape the fragment.
553 0 : mTarget = Substring(aStylesheetURI, (uint32_t)fragment,
554 0 : fragmentLength);
555 0 : mEmbedStatus = eNeedEmbed;
556 0 : mHandlerTable = gTxEmbedHandler;
557 : }
558 : }
559 0 : nsresult rv = NS_OK;
560 0 : if (aStylesheet) {
561 0 : mStylesheet = aStylesheet;
562 0 : mToplevelIterator = *aInsertPosition;
563 0 : mIsTopCompiler = false;
564 : }
565 : else {
566 0 : mStylesheet = new txStylesheet;
567 0 : rv = mStylesheet->init();
568 0 : NS_ENSURE_SUCCESS(rv, rv);
569 :
570 : mToplevelIterator =
571 0 : txListIterator(&mStylesheet->mRootFrame->mToplevelItems);
572 0 : mToplevelIterator.next(); // go to the end of the list
573 0 : mIsTopCompiler = true;
574 : }
575 :
576 0 : mElementContext = new txElementContext(aStylesheetURI);
577 0 : NS_ENSURE_TRUE(mElementContext->mMappings, NS_ERROR_OUT_OF_MEMORY);
578 :
579 : // Push the "old" txElementContext
580 0 : rv = pushObject(0);
581 0 : NS_ENSURE_SUCCESS(rv, rv);
582 :
583 0 : return NS_OK;
584 : }
585 :
586 :
587 0 : txStylesheetCompilerState::~txStylesheetCompilerState()
588 : {
589 0 : while (!mObjectStack.isEmpty()) {
590 0 : delete popObject();
591 : }
592 :
593 : int32_t i;
594 0 : for (i = mInScopeVariables.Length() - 1; i >= 0; --i) {
595 0 : delete mInScopeVariables[i];
596 : }
597 0 : }
598 :
599 : nsresult
600 0 : txStylesheetCompilerState::pushHandlerTable(txHandlerTable* aTable)
601 : {
602 0 : nsresult rv = pushPtr(mHandlerTable, eHandlerTable);
603 0 : NS_ENSURE_SUCCESS(rv, rv);
604 :
605 0 : mHandlerTable = aTable;
606 :
607 0 : return NS_OK;
608 : }
609 :
610 : void
611 0 : txStylesheetCompilerState::popHandlerTable()
612 : {
613 0 : mHandlerTable = static_cast<txHandlerTable*>(popPtr(eHandlerTable));
614 0 : }
615 :
616 : nsresult
617 0 : txStylesheetCompilerState::pushSorter(txPushNewContext* aSorter)
618 : {
619 0 : nsresult rv = pushPtr(mSorter, ePushNewContext);
620 0 : NS_ENSURE_SUCCESS(rv, rv);
621 :
622 0 : mSorter = aSorter;
623 :
624 0 : return NS_OK;
625 : }
626 :
627 : void
628 0 : txStylesheetCompilerState::popSorter()
629 : {
630 0 : mSorter = static_cast<txPushNewContext*>(popPtr(ePushNewContext));
631 0 : }
632 :
633 : nsresult
634 0 : txStylesheetCompilerState::pushChooseGotoList()
635 : {
636 0 : nsresult rv = pushObject(mChooseGotoList);
637 0 : NS_ENSURE_SUCCESS(rv, rv);
638 :
639 0 : mChooseGotoList.forget();
640 0 : mChooseGotoList = new txList;
641 :
642 0 : return NS_OK;
643 : }
644 :
645 : void
646 0 : txStylesheetCompilerState::popChooseGotoList()
647 : {
648 : // this will delete the old value
649 0 : mChooseGotoList = static_cast<txList*>(popObject());
650 0 : }
651 :
652 : nsresult
653 0 : txStylesheetCompilerState::pushObject(txObject* aObject)
654 : {
655 0 : return mObjectStack.push(aObject);
656 : }
657 :
658 : txObject*
659 0 : txStylesheetCompilerState::popObject()
660 : {
661 0 : return static_cast<txObject*>(mObjectStack.pop());
662 : }
663 :
664 : nsresult
665 0 : txStylesheetCompilerState::pushPtr(void* aPtr, enumStackType aType)
666 : {
667 : #ifdef TX_DEBUG_STACK
668 : MOZ_LOG(txLog::xslt, LogLevel::Debug, ("pushPtr: 0x%x type %u\n", aPtr, aType));
669 : #endif
670 0 : mTypeStack.AppendElement(aType);
671 0 : return mOtherStack.push(aPtr);
672 : }
673 :
674 : void*
675 0 : txStylesheetCompilerState::popPtr(enumStackType aType)
676 : {
677 0 : uint32_t stacklen = mTypeStack.Length();
678 0 : if (stacklen == 0) {
679 0 : MOZ_CRASH("Attempt to pop when type stack is empty");
680 : }
681 :
682 0 : enumStackType type = mTypeStack.ElementAt(stacklen - 1);
683 0 : mTypeStack.RemoveElementAt(stacklen - 1);
684 0 : void* value = mOtherStack.pop();
685 :
686 : #ifdef TX_DEBUG_STACK
687 : MOZ_LOG(txLog::xslt, LogLevel::Debug, ("popPtr: 0x%x type %u requested %u\n", value, type, aType));
688 : #endif
689 :
690 0 : if (type != aType) {
691 0 : MOZ_CRASH("Expected type does not match top element type");
692 : }
693 :
694 0 : return value;
695 : }
696 :
697 : nsresult
698 0 : txStylesheetCompilerState::addToplevelItem(txToplevelItem* aItem)
699 : {
700 0 : return mToplevelIterator.addBefore(aItem);
701 : }
702 :
703 : nsresult
704 0 : txStylesheetCompilerState::openInstructionContainer(txInstructionContainer* aContainer)
705 : {
706 0 : NS_PRECONDITION(!mNextInstrPtr, "can't nest instruction-containers");
707 :
708 0 : mNextInstrPtr = aContainer->mFirstInstruction.StartAssignment();
709 0 : return NS_OK;
710 : }
711 :
712 : void
713 0 : txStylesheetCompilerState::closeInstructionContainer()
714 : {
715 0 : NS_ASSERTION(mGotoTargetPointers.IsEmpty(),
716 : "GotoTargets still exists, did you forget to add txReturn?");
717 0 : mNextInstrPtr = 0;
718 0 : }
719 :
720 : nsresult
721 0 : txStylesheetCompilerState::addInstruction(nsAutoPtr<txInstruction>&& aInstruction)
722 : {
723 0 : NS_PRECONDITION(mNextInstrPtr, "adding instruction outside container");
724 :
725 0 : txInstruction* newInstr = aInstruction;
726 :
727 0 : *mNextInstrPtr = aInstruction.forget();
728 0 : mNextInstrPtr = newInstr->mNext.StartAssignment();
729 :
730 0 : uint32_t i, count = mGotoTargetPointers.Length();
731 0 : for (i = 0; i < count; ++i) {
732 0 : *mGotoTargetPointers[i] = newInstr;
733 : }
734 0 : mGotoTargetPointers.Clear();
735 :
736 0 : return NS_OK;
737 : }
738 :
739 : nsresult
740 0 : txStylesheetCompilerState::loadIncludedStylesheet(const nsAString& aURI)
741 : {
742 0 : MOZ_LOG(txLog::xslt, LogLevel::Info,
743 : ("CompilerState::loadIncludedStylesheet: %s\n",
744 : NS_LossyConvertUTF16toASCII(aURI).get()));
745 0 : if (mStylesheetURI.Equals(aURI)) {
746 0 : return NS_ERROR_XSLT_LOAD_RECURSION;
747 : }
748 0 : NS_ENSURE_TRUE(mObserver, NS_ERROR_NOT_IMPLEMENTED);
749 :
750 0 : nsAutoPtr<txToplevelItem> item(new txDummyItem);
751 0 : NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY);
752 :
753 0 : nsresult rv = mToplevelIterator.addBefore(item);
754 0 : NS_ENSURE_SUCCESS(rv, rv);
755 :
756 0 : item.forget();
757 :
758 : // step back to the dummy-item
759 0 : mToplevelIterator.previous();
760 :
761 0 : txACompileObserver* observer = static_cast<txStylesheetCompiler*>(this);
762 :
763 : RefPtr<txStylesheetCompiler> compiler =
764 : new txStylesheetCompiler(aURI, mStylesheet, &mToplevelIterator,
765 0 : mReferrerPolicy, observer);
766 0 : NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY);
767 :
768 : // step forward before calling the observer in case of syncronous loading
769 0 : mToplevelIterator.next();
770 :
771 0 : if (mChildCompilerList.AppendElement(compiler) == nullptr) {
772 0 : return NS_ERROR_OUT_OF_MEMORY;
773 : }
774 :
775 0 : rv = mObserver->loadURI(aURI, mStylesheetURI, mReferrerPolicy, compiler);
776 0 : if (NS_FAILED(rv)) {
777 0 : mChildCompilerList.RemoveElement(compiler);
778 : }
779 :
780 0 : return rv;
781 : }
782 :
783 : nsresult
784 0 : txStylesheetCompilerState::loadImportedStylesheet(const nsAString& aURI,
785 : txStylesheet::ImportFrame* aFrame)
786 : {
787 0 : MOZ_LOG(txLog::xslt, LogLevel::Info,
788 : ("CompilerState::loadImportedStylesheet: %s\n",
789 : NS_LossyConvertUTF16toASCII(aURI).get()));
790 0 : if (mStylesheetURI.Equals(aURI)) {
791 0 : return NS_ERROR_XSLT_LOAD_RECURSION;
792 : }
793 0 : NS_ENSURE_TRUE(mObserver, NS_ERROR_NOT_IMPLEMENTED);
794 :
795 0 : txListIterator iter(&aFrame->mToplevelItems);
796 0 : iter.next(); // go to the end of the list
797 :
798 0 : txACompileObserver* observer = static_cast<txStylesheetCompiler*>(this);
799 :
800 : RefPtr<txStylesheetCompiler> compiler =
801 : new txStylesheetCompiler(aURI, mStylesheet, &iter, mReferrerPolicy,
802 0 : observer);
803 0 : NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY);
804 :
805 0 : if (mChildCompilerList.AppendElement(compiler) == nullptr) {
806 0 : return NS_ERROR_OUT_OF_MEMORY;
807 : }
808 :
809 0 : nsresult rv = mObserver->loadURI(aURI, mStylesheetURI, mReferrerPolicy,
810 0 : compiler);
811 0 : if (NS_FAILED(rv)) {
812 0 : mChildCompilerList.RemoveElement(compiler);
813 : }
814 :
815 0 : return rv;
816 : }
817 :
818 : nsresult
819 0 : txStylesheetCompilerState::addGotoTarget(txInstruction** aTargetPointer)
820 : {
821 0 : if (mGotoTargetPointers.AppendElement(aTargetPointer) == nullptr) {
822 0 : return NS_ERROR_OUT_OF_MEMORY;
823 : }
824 :
825 0 : return NS_OK;
826 : }
827 :
828 : nsresult
829 0 : txStylesheetCompilerState::addVariable(const txExpandedName& aName)
830 : {
831 0 : txInScopeVariable* var = new txInScopeVariable(aName);
832 0 : if (!mInScopeVariables.AppendElement(var)) {
833 0 : delete var;
834 0 : return NS_ERROR_OUT_OF_MEMORY;
835 : }
836 :
837 0 : return NS_OK;
838 : }
839 :
840 : nsresult
841 0 : txStylesheetCompilerState::resolveNamespacePrefix(nsIAtom* aPrefix,
842 : int32_t& aID)
843 : {
844 0 : NS_ASSERTION(aPrefix && aPrefix != nsGkAtoms::_empty,
845 : "caller should handle default namespace ''");
846 0 : aID = mElementContext->mMappings->lookupNamespace(aPrefix);
847 0 : return (aID != kNameSpaceID_Unknown) ? NS_OK : NS_ERROR_FAILURE;
848 : }
849 :
850 : /**
851 : * Error Function to be used for unknown extension functions.
852 : *
853 : */
854 0 : class txErrorFunctionCall : public FunctionCall
855 : {
856 : public:
857 0 : explicit txErrorFunctionCall(nsIAtom* aName)
858 0 : : mName(aName)
859 : {
860 0 : }
861 :
862 : TX_DECL_FUNCTION
863 :
864 : private:
865 : nsCOMPtr<nsIAtom> mName;
866 : };
867 :
868 : nsresult
869 0 : txErrorFunctionCall::evaluate(txIEvalContext* aContext,
870 : txAExprResult** aResult)
871 : {
872 0 : *aResult = nullptr;
873 :
874 0 : return NS_ERROR_XPATH_BAD_EXTENSION_FUNCTION;
875 : }
876 :
877 : Expr::ResultType
878 0 : txErrorFunctionCall::getReturnType()
879 : {
880 : // It doesn't really matter what we return here, but it might
881 : // be a good idea to try to keep this as unoptimizable as possible
882 0 : return ANY_RESULT;
883 : }
884 :
885 : bool
886 0 : txErrorFunctionCall::isSensitiveTo(ContextSensitivity aContext)
887 : {
888 : // It doesn't really matter what we return here, but it might
889 : // be a good idea to try to keep this as unoptimizable as possible
890 0 : return true;
891 : }
892 :
893 : #ifdef TX_TO_STRING
894 : nsresult
895 0 : txErrorFunctionCall::getNameAtom(nsIAtom** aAtom)
896 : {
897 0 : NS_IF_ADDREF(*aAtom = mName);
898 :
899 0 : return NS_OK;
900 : }
901 : #endif
902 :
903 : static nsresult
904 0 : TX_ConstructXSLTFunction(nsIAtom* aName, int32_t aNamespaceID,
905 : txStylesheetCompilerState* aState,
906 : FunctionCall** aFunction)
907 : {
908 0 : if (aName == nsGkAtoms::document) {
909 0 : *aFunction =
910 0 : new DocumentFunctionCall(aState->mElementContext->mBaseURI);
911 : }
912 0 : else if (aName == nsGkAtoms::key) {
913 0 : if (!aState->allowed(txIParseContext::KEY_FUNCTION)) {
914 0 : return NS_ERROR_XSLT_CALL_TO_KEY_NOT_ALLOWED;
915 : }
916 0 : *aFunction =
917 0 : new txKeyFunctionCall(aState->mElementContext->mMappings);
918 : }
919 0 : else if (aName == nsGkAtoms::formatNumber) {
920 0 : *aFunction =
921 : new txFormatNumberFunctionCall(aState->mStylesheet,
922 0 : aState->mElementContext->mMappings);
923 : }
924 0 : else if (aName == nsGkAtoms::current) {
925 0 : *aFunction = new CurrentFunctionCall();
926 : }
927 0 : else if (aName == nsGkAtoms::unparsedEntityUri) {
928 0 : return NS_ERROR_NOT_IMPLEMENTED;
929 : }
930 0 : else if (aName == nsGkAtoms::generateId) {
931 0 : *aFunction = new GenerateIdFunctionCall();
932 : }
933 0 : else if (aName == nsGkAtoms::systemProperty) {
934 0 : *aFunction = new txXSLTEnvironmentFunctionCall(
935 : txXSLTEnvironmentFunctionCall::SYSTEM_PROPERTY,
936 0 : aState->mElementContext->mMappings);
937 : }
938 0 : else if (aName == nsGkAtoms::elementAvailable) {
939 0 : *aFunction = new txXSLTEnvironmentFunctionCall(
940 : txXSLTEnvironmentFunctionCall::ELEMENT_AVAILABLE,
941 0 : aState->mElementContext->mMappings);
942 : }
943 0 : else if (aName == nsGkAtoms::functionAvailable) {
944 0 : *aFunction = new txXSLTEnvironmentFunctionCall(
945 : txXSLTEnvironmentFunctionCall::FUNCTION_AVAILABLE,
946 0 : aState->mElementContext->mMappings);
947 : }
948 : else {
949 0 : return NS_ERROR_XPATH_UNKNOWN_FUNCTION;
950 : }
951 :
952 0 : MOZ_ASSERT(*aFunction);
953 0 : return NS_OK;
954 : }
955 :
956 : typedef nsresult (*txFunctionFactory)(nsIAtom* aName,
957 : int32_t aNamespaceID,
958 : txStylesheetCompilerState* aState,
959 : FunctionCall** aResult);
960 : struct txFunctionFactoryMapping
961 : {
962 : const char* const mNamespaceURI;
963 : int32_t mNamespaceID;
964 : txFunctionFactory mFactory;
965 : };
966 :
967 : extern nsresult
968 : TX_ConstructEXSLTFunction(nsIAtom *aName,
969 : int32_t aNamespaceID,
970 : txStylesheetCompilerState* aState,
971 : FunctionCall **aResult);
972 :
973 : static txFunctionFactoryMapping kExtensionFunctions[] = {
974 : { "", kNameSpaceID_Unknown, TX_ConstructXSLTFunction },
975 : { "http://exslt.org/common", kNameSpaceID_Unknown,
976 : TX_ConstructEXSLTFunction },
977 : { "http://exslt.org/sets", kNameSpaceID_Unknown,
978 : TX_ConstructEXSLTFunction },
979 : { "http://exslt.org/strings", kNameSpaceID_Unknown,
980 : TX_ConstructEXSLTFunction },
981 : { "http://exslt.org/math", kNameSpaceID_Unknown,
982 : TX_ConstructEXSLTFunction },
983 : { "http://exslt.org/dates-and-times", kNameSpaceID_Unknown,
984 : TX_ConstructEXSLTFunction }
985 : };
986 :
987 : extern nsresult
988 : TX_ResolveFunctionCallXPCOM(const nsCString &aContractID, int32_t aNamespaceID,
989 : nsIAtom *aName, nsISupports *aState,
990 : FunctionCall **aFunction);
991 :
992 0 : struct txXPCOMFunctionMapping
993 : {
994 : int32_t mNamespaceID;
995 : nsCString mContractID;
996 : };
997 :
998 : static nsTArray<txXPCOMFunctionMapping> *sXPCOMFunctionMappings = nullptr;
999 :
1000 : static nsresult
1001 0 : findFunction(nsIAtom* aName, int32_t aNamespaceID,
1002 : txStylesheetCompilerState* aState, FunctionCall** aResult)
1003 : {
1004 0 : if (kExtensionFunctions[0].mNamespaceID == kNameSpaceID_Unknown) {
1005 : uint32_t i;
1006 0 : for (i = 0; i < ArrayLength(kExtensionFunctions); ++i) {
1007 0 : txFunctionFactoryMapping& mapping = kExtensionFunctions[i];
1008 0 : NS_ConvertASCIItoUTF16 namespaceURI(mapping.mNamespaceURI);
1009 0 : mapping.mNamespaceID =
1010 0 : txNamespaceManager::getNamespaceID(namespaceURI);
1011 : }
1012 : }
1013 :
1014 : uint32_t i;
1015 0 : for (i = 0; i < ArrayLength(kExtensionFunctions); ++i) {
1016 0 : const txFunctionFactoryMapping& mapping = kExtensionFunctions[i];
1017 0 : if (mapping.mNamespaceID == aNamespaceID) {
1018 0 : return mapping.mFactory(aName, aNamespaceID, aState, aResult);
1019 : }
1020 : }
1021 :
1022 0 : if (!sXPCOMFunctionMappings) {
1023 0 : sXPCOMFunctionMappings = new nsTArray<txXPCOMFunctionMapping>;
1024 : }
1025 :
1026 0 : txXPCOMFunctionMapping *map = nullptr;
1027 0 : uint32_t count = sXPCOMFunctionMappings->Length();
1028 0 : for (i = 0; i < count; ++i) {
1029 0 : map = &sXPCOMFunctionMappings->ElementAt(i);
1030 0 : if (map->mNamespaceID == aNamespaceID) {
1031 0 : break;
1032 : }
1033 : }
1034 :
1035 0 : if (i == count) {
1036 : nsresult rv;
1037 : nsCOMPtr<nsICategoryManager> catman =
1038 0 : do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
1039 0 : NS_ENSURE_SUCCESS(rv, rv);
1040 :
1041 0 : nsAutoString namespaceURI;
1042 0 : rv = txNamespaceManager::getNamespaceURI(aNamespaceID, namespaceURI);
1043 0 : NS_ENSURE_SUCCESS(rv, rv);
1044 :
1045 0 : nsXPIDLCString contractID;
1046 0 : rv = catman->GetCategoryEntry("XSLT-extension-functions",
1047 0 : NS_ConvertUTF16toUTF8(namespaceURI).get(),
1048 0 : getter_Copies(contractID));
1049 0 : if (rv == NS_ERROR_NOT_AVAILABLE) {
1050 0 : return NS_ERROR_XPATH_UNKNOWN_FUNCTION;
1051 : }
1052 0 : NS_ENSURE_SUCCESS(rv, rv);
1053 :
1054 0 : map = sXPCOMFunctionMappings->AppendElement();
1055 0 : if (!map) {
1056 0 : return NS_ERROR_OUT_OF_MEMORY;
1057 : }
1058 :
1059 0 : map->mNamespaceID = aNamespaceID;
1060 0 : map->mContractID = contractID;
1061 : }
1062 :
1063 0 : return TX_ResolveFunctionCallXPCOM(map->mContractID, aNamespaceID, aName,
1064 0 : nullptr, aResult);
1065 : }
1066 :
1067 : extern bool
1068 0 : TX_XSLTFunctionAvailable(nsIAtom* aName, int32_t aNameSpaceID)
1069 : {
1070 : RefPtr<txStylesheetCompiler> compiler =
1071 0 : new txStylesheetCompiler(EmptyString(),
1072 0 : mozilla::net::RP_Unset, nullptr);
1073 0 : NS_ENSURE_TRUE(compiler, false);
1074 :
1075 0 : nsAutoPtr<FunctionCall> fnCall;
1076 :
1077 0 : return NS_SUCCEEDED(findFunction(aName, aNameSpaceID, compiler,
1078 : getter_Transfers(fnCall)));
1079 : }
1080 :
1081 : nsresult
1082 0 : txStylesheetCompilerState::resolveFunctionCall(nsIAtom* aName, int32_t aID,
1083 : FunctionCall **aFunction)
1084 : {
1085 0 : *aFunction = nullptr;
1086 :
1087 0 : nsresult rv = findFunction(aName, aID, this, aFunction);
1088 0 : if (rv == NS_ERROR_XPATH_UNKNOWN_FUNCTION &&
1089 0 : (aID != kNameSpaceID_None || fcp())) {
1090 0 : *aFunction = new txErrorFunctionCall(aName);
1091 0 : rv = NS_OK;
1092 : }
1093 :
1094 0 : return rv;
1095 : }
1096 :
1097 : bool
1098 0 : txStylesheetCompilerState::caseInsensitiveNameTests()
1099 : {
1100 0 : return false;
1101 : }
1102 :
1103 : void
1104 0 : txStylesheetCompilerState::SetErrorOffset(uint32_t aOffset)
1105 : {
1106 : // XXX implement me
1107 0 : }
1108 :
1109 : /* static */
1110 : void
1111 0 : txStylesheetCompilerState::shutdown()
1112 : {
1113 0 : delete sXPCOMFunctionMappings;
1114 0 : sXPCOMFunctionMappings = nullptr;
1115 0 : }
1116 :
1117 0 : txElementContext::txElementContext(const nsAString& aBaseURI)
1118 : : mPreserveWhitespace(false),
1119 : mForwardsCompatibleParsing(true),
1120 : mBaseURI(aBaseURI),
1121 0 : mMappings(new txNamespaceMap),
1122 0 : mDepth(0)
1123 : {
1124 0 : mInstructionNamespaces.AppendElement(kNameSpaceID_XSLT);
1125 0 : }
1126 :
1127 0 : txElementContext::txElementContext(const txElementContext& aOther)
1128 0 : : mPreserveWhitespace(aOther.mPreserveWhitespace),
1129 0 : mForwardsCompatibleParsing(aOther.mForwardsCompatibleParsing),
1130 : mBaseURI(aOther.mBaseURI),
1131 : mMappings(aOther.mMappings),
1132 0 : mDepth(0)
1133 : {
1134 0 : mInstructionNamespaces = aOther.mInstructionNamespaces;
1135 0 : }
|