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