Back to index

lightning-sunbird  0.9+nobinonly
txStylesheetCompiler.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is TransforMiiX XSLT processor code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Jonas Sicking.
00019  * Portions created by the Initial Developer are Copyright (C) 2002
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Jonas Sicking <jonas@sicking.cc>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either the GNU General Public License Version 2 or later (the "GPL"), or
00027  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 #include "txStylesheetCompiler.h"
00040 #include "txStylesheetCompileHandlers.h"
00041 #include "txAtoms.h"
00042 #include "txURIUtils.h"
00043 #include "txTokenizer.h"
00044 #include "txStylesheet.h"
00045 #include "txInstructions.h"
00046 #include "txToplevelItems.h"
00047 #include "ExprParser.h"
00048 #include "TxLog.h"
00049 #include "txPatternParser.h"
00050 #include "txStringUtils.h"
00051 #include "XSLTFunctions.h"
00052 
00053 txStylesheetCompiler::txStylesheetCompiler(const nsAString& aStylesheetURI,
00054                                            txACompileObserver* aObserver)
00055     : txStylesheetCompilerState(aObserver)
00056 {
00057     mStatus = init(aStylesheetURI, nsnull, nsnull);
00058 }
00059 
00060 txStylesheetCompiler::txStylesheetCompiler(const nsAString& aStylesheetURI,
00061                                            txStylesheet* aStylesheet,
00062                                            txListIterator* aInsertPosition,
00063                                            txACompileObserver* aObserver)
00064     : txStylesheetCompilerState(aObserver)
00065 {
00066     mStatus = init(aStylesheetURI, aStylesheet, aInsertPosition);
00067 }
00068 
00069 nsrefcnt
00070 txStylesheetCompiler::AddRef()
00071 {
00072     return ++mRefCnt;
00073 }
00074 
00075 nsrefcnt
00076 txStylesheetCompiler::Release()
00077 {
00078     if (--mRefCnt == 0) {
00079         mRefCnt = 1; //stabilize
00080         delete this;
00081         return 0;
00082     }
00083     return mRefCnt;
00084 }
00085 
00086 void
00087 txStylesheetCompiler::setBaseURI(const nsString& aBaseURI)
00088 {
00089     NS_ASSERTION(mObjectStack.size() == 1 && !mObjectStack.peek(),
00090                  "Execution already started");
00091 
00092     if (NS_FAILED(mStatus)) {
00093         return;
00094     }
00095 
00096     mElementContext->mBaseURI = aBaseURI;
00097 }
00098 
00099 nsresult
00100 txStylesheetCompiler::startElement(PRInt32 aNamespaceID, nsIAtom* aLocalName,
00101                                    nsIAtom* aPrefix,
00102                                    txStylesheetAttr* aAttributes,
00103                                    PRInt32 aAttrCount)
00104 {
00105     if (NS_FAILED(mStatus)) {
00106         // ignore content after failure
00107         // XXX reevaluate once expat stops on failure
00108         return NS_OK;
00109     }
00110 
00111     nsresult rv = flushCharacters();
00112     NS_ENSURE_SUCCESS(rv, rv);
00113 
00114     // look for new namespace mappings
00115     PRBool hasOwnNamespaceMap = PR_FALSE;
00116     PRInt32 i;
00117     for (i = 0; i < aAttrCount; ++i) {
00118         txStylesheetAttr* attr = aAttributes + i;
00119         if (attr->mNamespaceID == kNameSpaceID_XMLNS) {
00120             rv = ensureNewElementContext();
00121             NS_ENSURE_SUCCESS(rv, rv);
00122 
00123             if (!hasOwnNamespaceMap) {
00124                 mElementContext->mMappings =
00125                     new txNamespaceMap(*mElementContext->mMappings);
00126                 NS_ENSURE_TRUE(mElementContext->mMappings,
00127                                NS_ERROR_OUT_OF_MEMORY);
00128                 hasOwnNamespaceMap = PR_TRUE;
00129             }
00130 
00131             if (attr->mLocalName == txXMLAtoms::xmlns) {
00132                 mElementContext->mMappings->mapNamespace(nsnull, attr->mValue);
00133             }
00134             else {
00135                 mElementContext->mMappings->
00136                     mapNamespace(attr->mLocalName, attr->mValue);
00137             }
00138         }
00139     }
00140 
00141     return startElementInternal(aNamespaceID, aLocalName, aPrefix,
00142                                 aAttributes, aAttrCount);
00143 }
00144 
00145 nsresult
00146 txStylesheetCompiler::startElement(const PRUnichar *aName,
00147                                    const PRUnichar **aAttrs,
00148                                    PRInt32 aAttrCount, PRInt32 aIDOffset)
00149 {
00150     if (NS_FAILED(mStatus)) {
00151         // ignore content after failure
00152         // XXX reevaluate once expat stops on failure
00153         return NS_OK;
00154     }
00155 
00156     nsresult rv = flushCharacters();
00157     NS_ENSURE_SUCCESS(rv, rv);
00158 
00159     nsAutoArrayPtr<txStylesheetAttr> atts;
00160     if (aAttrCount > 0) {
00161         atts = new txStylesheetAttr[aAttrCount];
00162         NS_ENSURE_TRUE(atts, NS_ERROR_OUT_OF_MEMORY);
00163     }
00164 
00165     PRBool hasOwnNamespaceMap = PR_FALSE;
00166     PRInt32 i;
00167     for (i = 0; i < aAttrCount; ++i) {
00168         rv = XMLUtils::splitExpatName(aAttrs[i * 2],
00169                                       getter_AddRefs(atts[i].mPrefix),
00170                                       getter_AddRefs(atts[i].mLocalName),
00171                                       &atts[i].mNamespaceID);
00172         NS_ENSURE_SUCCESS(rv, rv);
00173         atts[i].mValue.Append(aAttrs[i * 2 + 1]);
00174 
00175         nsCOMPtr<nsIAtom> prefixToBind;
00176         if (atts[i].mPrefix == txXMLAtoms::xmlns) {
00177             prefixToBind = atts[i].mLocalName;
00178         }
00179         else if (atts[i].mNamespaceID == kNameSpaceID_XMLNS) {
00180             prefixToBind = txXMLAtoms::_empty;
00181         }
00182 
00183         if (prefixToBind) {
00184             rv = ensureNewElementContext();
00185             NS_ENSURE_SUCCESS(rv, rv);
00186 
00187             if (!hasOwnNamespaceMap) {
00188                 mElementContext->mMappings =
00189                     new txNamespaceMap(*mElementContext->mMappings);
00190                 NS_ENSURE_TRUE(mElementContext->mMappings,
00191                                NS_ERROR_OUT_OF_MEMORY);
00192                 hasOwnNamespaceMap = PR_TRUE;
00193             }
00194 
00195             rv = mElementContext->mMappings->
00196                 mapNamespace(prefixToBind, atts[i].mValue);
00197             NS_ENSURE_SUCCESS(rv, rv);
00198         }
00199     }
00200 
00201     nsCOMPtr<nsIAtom> prefix, localname;
00202     PRInt32 namespaceID;
00203     rv = XMLUtils::splitExpatName(aName, getter_AddRefs(prefix),
00204                                   getter_AddRefs(localname), &namespaceID);
00205     NS_ENSURE_SUCCESS(rv, rv);
00206 
00207     PRInt32 idOffset = aIDOffset;
00208     if (idOffset > 0) {
00209         idOffset /= 2;
00210     }
00211     return startElementInternal(namespaceID, localname, prefix, atts,
00212                                 aAttrCount, idOffset);
00213 }
00214 
00215 nsresult
00216 txStylesheetCompiler::startElementInternal(PRInt32 aNamespaceID,
00217                                            nsIAtom* aLocalName,
00218                                            nsIAtom* aPrefix,
00219                                            txStylesheetAttr* aAttributes,
00220                                            PRInt32 aAttrCount,
00221                                            PRInt32 aIDOffset)
00222 {
00223     nsresult rv = NS_OK;
00224     PRInt32 i;
00225     for (i = mInScopeVariables.Count() - 1; i >= 0; --i) {
00226         ++(NS_STATIC_CAST(txInScopeVariable*, mInScopeVariables[i]))->mLevel;
00227     }
00228 
00229     // Update the elementcontext if we have special attributes
00230     for (i = 0; i < aAttrCount; ++i) {
00231         txStylesheetAttr* attr = aAttributes + i;
00232 
00233         // xml:space
00234         if (attr->mNamespaceID == kNameSpaceID_XML &&
00235             attr->mLocalName == txXMLAtoms::space) {
00236             rv = ensureNewElementContext();
00237             NS_ENSURE_SUCCESS(rv, rv);
00238 
00239             if (TX_StringEqualsAtom(attr->mValue, txXMLAtoms::preserve)) {
00240                 mElementContext->mPreserveWhitespace = MB_TRUE;
00241             }
00242             else if (TX_StringEqualsAtom(attr->mValue, txXMLAtoms::_default)) {
00243                 mElementContext->mPreserveWhitespace = MB_FALSE;
00244             }
00245             else {
00246                 return NS_ERROR_XSLT_PARSE_FAILURE;
00247             }
00248         }
00249 
00250         // xml:base
00251         if (attr->mNamespaceID == kNameSpaceID_XML &&
00252             attr->mLocalName == txXMLAtoms::base &&
00253             !attr->mValue.IsEmpty()) {
00254             rv = ensureNewElementContext();
00255             NS_ENSURE_SUCCESS(rv, rv);
00256             
00257             nsAutoString uri;
00258             URIUtils::resolveHref(attr->mValue, mElementContext->mBaseURI, uri);
00259             mElementContext->mBaseURI = uri;
00260         }
00261 
00262         // extension-element-prefixes
00263         if ((attr->mNamespaceID == kNameSpaceID_XSLT &&
00264              attr->mLocalName == txXSLTAtoms::extensionElementPrefixes &&
00265              aNamespaceID != kNameSpaceID_XSLT) ||
00266             (attr->mNamespaceID == kNameSpaceID_None &&
00267              attr->mLocalName == txXSLTAtoms::extensionElementPrefixes &&
00268              aNamespaceID == kNameSpaceID_XSLT &&
00269              (aLocalName == txXSLTAtoms::stylesheet ||
00270               aLocalName == txXSLTAtoms::transform))) {
00271             rv = ensureNewElementContext();
00272             NS_ENSURE_SUCCESS(rv, rv);
00273 
00274             txTokenizer tok(attr->mValue);
00275             while (tok.hasMoreTokens()) {
00276                 PRInt32 namespaceID = mElementContext->mMappings->
00277                     lookupNamespaceWithDefault(tok.nextToken());
00278                 
00279                 if (namespaceID == kNameSpaceID_Unknown)
00280                     return NS_ERROR_XSLT_PARSE_FAILURE;
00281 
00282                 if (!mElementContext->mInstructionNamespaces.
00283                         AppendElement(NS_INT32_TO_PTR(namespaceID))) {
00284                     return NS_ERROR_OUT_OF_MEMORY;
00285                 }
00286             }
00287         }
00288 
00289         // version
00290         if ((attr->mNamespaceID == kNameSpaceID_XSLT &&
00291              attr->mLocalName == txXSLTAtoms::version &&
00292              aNamespaceID != kNameSpaceID_XSLT) ||
00293             (attr->mNamespaceID == kNameSpaceID_None &&
00294              attr->mLocalName == txXSLTAtoms::version &&
00295              aNamespaceID == kNameSpaceID_XSLT &&
00296              (aLocalName == txXSLTAtoms::stylesheet ||
00297               aLocalName == txXSLTAtoms::transform))) {
00298             rv = ensureNewElementContext();
00299             NS_ENSURE_SUCCESS(rv, rv);
00300 
00301             if (attr->mValue.EqualsLiteral("1.0")) {
00302                 mElementContext->mForwardsCompatibleParsing = MB_FALSE;
00303             }
00304             else {
00305                 mElementContext->mForwardsCompatibleParsing = MB_TRUE;
00306             }
00307         }
00308     }
00309 
00310     // Find the right elementhandler and execute it
00311     MBool isInstruction = MB_FALSE;
00312     PRInt32 count = mElementContext->mInstructionNamespaces.Count();
00313     for (i = 0; i < count; ++i) {
00314         if (NS_PTR_TO_INT32(mElementContext->mInstructionNamespaces[i]) ==
00315             aNamespaceID) {
00316             isInstruction = MB_TRUE;
00317             break;
00318         }
00319     }
00320 
00321     if (mEmbedStatus == eNeedEmbed) {
00322         // handle embedded stylesheets
00323         if (aIDOffset >= 0 && aAttributes[aIDOffset].mValue.Equals(mTarget)) {
00324             // We found the right ID, signal to compile the 
00325             // embedded stylesheet.
00326             mEmbedStatus = eInEmbed;
00327         }
00328     }
00329     const txElementHandler* handler;
00330     do {
00331         handler = isInstruction ?
00332                   mHandlerTable->find(aNamespaceID, aLocalName) :
00333                   mHandlerTable->mLREHandler;
00334 
00335         rv = (handler->mStartFunction)(aNamespaceID, aLocalName, aPrefix,
00336                                        aAttributes, aAttrCount, *this);
00337     } while (rv == NS_XSLT_GET_NEW_HANDLER);
00338 
00339     NS_ENSURE_SUCCESS(rv, rv);
00340 
00341     rv = pushPtr(NS_CONST_CAST(txElementHandler*, handler));
00342     NS_ENSURE_SUCCESS(rv, rv);
00343 
00344     mElementContext->mDepth++;
00345 
00346     return NS_OK;
00347 }
00348 
00349 nsresult
00350 txStylesheetCompiler::endElement()
00351 {
00352     if (NS_FAILED(mStatus)) {
00353         // ignore content after failure
00354         // XXX reevaluate once expat stops on failure
00355         return NS_OK;
00356     }
00357 
00358     nsresult rv = flushCharacters();
00359     NS_ENSURE_SUCCESS(rv, rv);
00360 
00361     PRInt32 i;
00362     for (i = mInScopeVariables.Count() - 1; i >= 0; --i) {
00363         txInScopeVariable* var =
00364             NS_STATIC_CAST(txInScopeVariable*, mInScopeVariables[i]);
00365         if (!--(var->mLevel)) {
00366             nsAutoPtr<txInstruction> instr(new txRemoveVariable(var->mName));
00367             NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY);
00368 
00369             rv = addInstruction(instr);
00370             NS_ENSURE_SUCCESS(rv, rv);
00371             
00372             mInScopeVariables.RemoveElementAt(i);
00373             delete var;
00374         }
00375     }
00376 
00377     const txElementHandler* handler =
00378         NS_CONST_CAST(const txElementHandler*,
00379                       NS_STATIC_CAST(txElementHandler*, popPtr()));
00380     rv = (handler->mEndFunction)(*this);
00381     NS_ENSURE_SUCCESS(rv, rv);
00382 
00383     if (!--mElementContext->mDepth) {
00384         // this will delete the old object
00385         mElementContext = NS_STATIC_CAST(txElementContext*, popObject());
00386     }
00387 
00388     return NS_OK;
00389 }
00390 
00391 nsresult
00392 txStylesheetCompiler::characters(const nsAString& aStr)
00393 {
00394     if (NS_FAILED(mStatus)) {
00395         // ignore content after failure
00396         // XXX reevaluate once expat stops on failure
00397         return NS_OK;
00398     }
00399 
00400     mCharacters.Append(aStr);
00401 
00402     return NS_OK;
00403 }
00404 
00405 nsresult
00406 txStylesheetCompiler::doneLoading()
00407 {
00408     PR_LOG(txLog::xslt, PR_LOG_ALWAYS,
00409            ("Compiler::doneLoading: %s\n",
00410             NS_LossyConvertUCS2toASCII(mStylesheetURI).get()));
00411     if (NS_FAILED(mStatus)) {
00412         return mStatus;
00413     }
00414 
00415     mDoneWithThisStylesheet = PR_TRUE;
00416 
00417     return maybeDoneCompiling();
00418 }
00419 
00420 void
00421 txStylesheetCompiler::cancel(nsresult aError, const PRUnichar *aErrorText,
00422                              const PRUnichar *aParam)
00423 {
00424     PR_LOG(txLog::xslt, PR_LOG_ALWAYS,
00425            ("Compiler::cancel: %s, module: %d, code %d\n",
00426             NS_LossyConvertUCS2toASCII(mStylesheetURI).get(),
00427             NS_ERROR_GET_MODULE(aError),
00428             NS_ERROR_GET_CODE(aError)));
00429     if (NS_SUCCEEDED(mStatus)) {
00430         mStatus = aError;
00431     }
00432 
00433     if (mObserver) {
00434         mObserver->onDoneCompiling(this, mStatus, aErrorText, aParam);
00435         // This will ensure that we don't call onDoneCompiling twice. Also
00436         // ensures that we don't keep the observer alive longer then necessary.
00437         mObserver = nsnull;
00438     }
00439 }
00440 
00441 txStylesheet*
00442 txStylesheetCompiler::getStylesheet()
00443 {
00444     return mStylesheet;
00445 }
00446 
00447 nsresult
00448 txStylesheetCompiler::loadURI(const nsAString& aUri,
00449                               const nsAString& aReferrerUri,
00450                               txStylesheetCompiler* aCompiler)
00451 {
00452     PR_LOG(txLog::xslt, PR_LOG_ALWAYS,
00453            ("Compiler::loadURI forwards %s thru %s\n",
00454             NS_LossyConvertUCS2toASCII(aUri).get(),
00455             NS_LossyConvertUCS2toASCII(mStylesheetURI).get()));
00456     if (mStylesheetURI.Equals(aUri)) {
00457         return NS_ERROR_XSLT_LOAD_RECURSION;
00458     }
00459     return mObserver ? mObserver->loadURI(aUri, aReferrerUri, aCompiler) :
00460                        NS_ERROR_FAILURE;
00461 }
00462 
00463 void
00464 txStylesheetCompiler::onDoneCompiling(txStylesheetCompiler* aCompiler,
00465                                       nsresult aResult,
00466                                       const PRUnichar *aErrorText,
00467                                       const PRUnichar *aParam)
00468 {
00469     if (NS_FAILED(aResult)) {
00470         cancel(aResult, aErrorText, aParam);
00471         return;
00472     }
00473 
00474     mChildCompilerList.RemoveElement(aCompiler);
00475 
00476     maybeDoneCompiling();
00477 }
00478 
00479 nsresult
00480 txStylesheetCompiler::flushCharacters()
00481 {
00482     // Bail if we don't have any characters. The handler will detect
00483     // ignoreable whitespace
00484     if (mCharacters.IsEmpty()) {
00485         return NS_OK;
00486     }
00487 
00488     nsresult rv = NS_OK;
00489 
00490     do {
00491         rv = (mHandlerTable->mTextHandler)(mCharacters, *this);
00492     } while (rv == NS_XSLT_GET_NEW_HANDLER);
00493 
00494     NS_ENSURE_SUCCESS(rv, rv);
00495 
00496     mCharacters.Truncate();
00497 
00498     return NS_OK;
00499 }
00500 
00501 nsresult
00502 txStylesheetCompiler::ensureNewElementContext()
00503 {
00504     // Do we already have a new context?
00505     if (!mElementContext->mDepth) {
00506         return NS_OK;
00507     }
00508     
00509     nsAutoPtr<txElementContext>
00510         context(new txElementContext(*mElementContext));
00511     NS_ENSURE_TRUE(context, NS_ERROR_OUT_OF_MEMORY);
00512 
00513     nsresult rv = pushObject(mElementContext);
00514     NS_ENSURE_SUCCESS(rv, rv);
00515 
00516     mElementContext.forget();
00517     mElementContext = context;
00518 
00519     return NS_OK;
00520 }
00521 
00522 nsresult
00523 txStylesheetCompiler::maybeDoneCompiling()
00524 {
00525     if (!mDoneWithThisStylesheet || mChildCompilerList.Count()) {
00526         return NS_OK;
00527     }
00528     
00529     if (mIsTopCompiler) {
00530         nsresult rv = mStylesheet->doneCompiling();
00531         if (NS_FAILED(rv)) {
00532             cancel(rv);
00533             return rv;
00534         }
00535     }
00536     
00537     if (mObserver) {
00538         mObserver->onDoneCompiling(this, mStatus);
00539         // This will ensure that we don't call onDoneCompiling twice. Also
00540         // ensures that we don't keep the observer alive longer then necessary.
00541         mObserver = nsnull;
00542     }
00543 
00544     return NS_OK;
00545 }
00546 
00552 txStylesheetCompilerState::txStylesheetCompilerState(txACompileObserver* aObserver)
00553     : mHandlerTable(nsnull),
00554       mSorter(nsnull),
00555       mDOE(PR_FALSE),
00556       mSearchingForFallback(PR_FALSE),
00557       mObserver(aObserver),
00558       mEmbedStatus(eNoEmbed),
00559       mDoneWithThisStylesheet(PR_FALSE),
00560       mNextInstrPtr(nsnull),
00561       mToplevelIterator(nsnull)
00562 {
00563     // Embedded stylesheets have another handler, which is set in
00564     // txStylesheetCompiler::init if the baseURI has a fragment identifier.
00565     mHandlerTable = gTxRootHandler;
00566 
00567 }
00568 
00569 nsresult
00570 txStylesheetCompilerState::init(const nsAString& aStylesheetURI,
00571                                 txStylesheet* aStylesheet,
00572                                 txListIterator* aInsertPosition)
00573 {
00574     NS_ASSERTION(!aStylesheet || aInsertPosition,
00575                  "must provide insertposition if loading subsheet");
00576     mStylesheetURI = aStylesheetURI;
00577     // Check for fragment identifier of an embedded stylesheet.
00578     PRInt32 fragment = aStylesheetURI.FindChar('#') + 1;
00579     if (fragment > 0) {
00580         PRInt32 fragmentLength = aStylesheetURI.Length() - fragment;
00581         if (fragmentLength > 0) {
00582             // This is really an embedded stylesheet, not just a
00583             // "url#". We may want to unescape the fragment.
00584             mTarget = Substring(aStylesheetURI, (PRUint32)fragment,
00585                                 fragmentLength);
00586             mEmbedStatus = eNeedEmbed;
00587             mHandlerTable = gTxEmbedHandler;
00588         }
00589     }
00590     nsresult rv = NS_OK;
00591     if (aStylesheet) {
00592         mStylesheet = aStylesheet;
00593         mToplevelIterator = *aInsertPosition;
00594         mIsTopCompiler = PR_FALSE;
00595     }
00596     else {
00597         mStylesheet = new txStylesheet;
00598         NS_ENSURE_TRUE(mStylesheet, NS_ERROR_OUT_OF_MEMORY);
00599         
00600         rv = mStylesheet->init();
00601         NS_ENSURE_SUCCESS(rv, rv);
00602         
00603         mToplevelIterator =
00604             txListIterator(&mStylesheet->mRootFrame->mToplevelItems);
00605         mToplevelIterator.next(); // go to the end of the list
00606         mIsTopCompiler = PR_TRUE;
00607     }
00608    
00609     mElementContext = new txElementContext(aStylesheetURI);
00610     NS_ENSURE_TRUE(mElementContext && mElementContext->mMappings,
00611                    NS_ERROR_OUT_OF_MEMORY);
00612 
00613     // Push the "old" txElementContext
00614     rv = pushObject(0);
00615     NS_ENSURE_SUCCESS(rv, rv);
00616     
00617     return NS_OK;
00618 }
00619 
00620 
00621 txStylesheetCompilerState::~txStylesheetCompilerState()
00622 {
00623     while (!mObjectStack.isEmpty()) {
00624         delete popObject();
00625     }
00626     
00627     PRInt32 i;
00628     for (i = mInScopeVariables.Count() - 1; i >= 0; --i) {
00629         delete NS_STATIC_CAST(txInScopeVariable*, mInScopeVariables[i]);
00630     }
00631 }
00632 
00633 nsresult
00634 txStylesheetCompilerState::pushHandlerTable(txHandlerTable* aTable)
00635 {
00636     nsresult rv = pushPtr(mHandlerTable);
00637     NS_ENSURE_SUCCESS(rv, rv);
00638 
00639     mHandlerTable = aTable;
00640 
00641     return NS_OK;
00642 }
00643 
00644 void
00645 txStylesheetCompilerState::popHandlerTable()
00646 {
00647     mHandlerTable = NS_STATIC_CAST(txHandlerTable*, popPtr());
00648 }
00649 
00650 nsresult
00651 txStylesheetCompilerState::pushSorter(txPushNewContext* aSorter)
00652 {
00653     nsresult rv = pushPtr(mSorter);
00654     NS_ENSURE_SUCCESS(rv, rv);
00655 
00656     mSorter = aSorter;
00657 
00658     return NS_OK;
00659 }
00660 
00661 void
00662 txStylesheetCompilerState::popSorter()
00663 {
00664     mSorter = NS_STATIC_CAST(txPushNewContext*, popPtr());
00665 }
00666 
00667 nsresult
00668 txStylesheetCompilerState::pushChooseGotoList()
00669 {
00670     nsresult rv = pushObject(mChooseGotoList);
00671     NS_ENSURE_SUCCESS(rv, rv);
00672 
00673     mChooseGotoList.forget();
00674     mChooseGotoList = new txList;
00675     NS_ENSURE_TRUE(mChooseGotoList, NS_ERROR_OUT_OF_MEMORY);
00676 
00677     return NS_OK;
00678 }
00679 
00680 void
00681 txStylesheetCompilerState::popChooseGotoList()
00682 {
00683     // this will delete the old value
00684     mChooseGotoList = NS_STATIC_CAST(txList*, popObject());
00685 }
00686 
00687 nsresult
00688 txStylesheetCompilerState::pushObject(TxObject* aObject)
00689 {
00690     return mObjectStack.push(aObject);
00691 }
00692 
00693 TxObject*
00694 txStylesheetCompilerState::popObject()
00695 {
00696     return NS_STATIC_CAST(TxObject*, mObjectStack.pop());
00697 }
00698 
00699 nsresult
00700 txStylesheetCompilerState::pushPtr(void* aPtr)
00701 {
00702 #ifdef TX_DEBUG_STACK
00703     PR_LOG(txLog::xslt, PR_LOG_DEBUG, ("pushPtr: %d\n", aPtr));
00704 #endif
00705     return mOtherStack.push(aPtr);
00706 }
00707 
00708 void*
00709 txStylesheetCompilerState::popPtr()
00710 {
00711     void* value = mOtherStack.pop();
00712 #ifdef TX_DEBUG_STACK
00713     PR_LOG(txLog::xslt, PR_LOG_DEBUG, ("popPtr: %d\n", value));
00714 #endif
00715     return value;
00716 }
00717 
00718 nsresult
00719 txStylesheetCompilerState::addToplevelItem(txToplevelItem* aItem)
00720 {
00721     return mToplevelIterator.addBefore(aItem);
00722 }
00723 
00724 nsresult
00725 txStylesheetCompilerState::openInstructionContainer(txInstructionContainer* aContainer)
00726 {
00727     NS_PRECONDITION(!mNextInstrPtr, "can't nest instruction-containers");
00728 
00729     mNextInstrPtr = aContainer->mFirstInstruction.StartAssignment();
00730     return NS_OK;
00731 }
00732 
00733 void
00734 txStylesheetCompilerState::closeInstructionContainer()
00735 {
00736     NS_ASSERTION(mGotoTargetPointers.Count() == 0,
00737                  "GotoTargets still exists, did you forget to add txReturn?");
00738     mNextInstrPtr = 0;
00739 }
00740 
00741 nsresult
00742 txStylesheetCompilerState::addInstruction(nsAutoPtr<txInstruction> aInstruction)
00743 {
00744     NS_PRECONDITION(mNextInstrPtr, "adding instruction outside container");
00745 
00746     txInstruction* newInstr = aInstruction;
00747 
00748     *mNextInstrPtr = aInstruction.forget();
00749     mNextInstrPtr = &newInstr->mNext;
00750     
00751     PRInt32 i, count = mGotoTargetPointers.Count();
00752     for (i = 0; i < count; ++i) {
00753         *NS_STATIC_CAST(txInstruction**, mGotoTargetPointers[i]) = newInstr;
00754     }
00755     mGotoTargetPointers.Clear();
00756 
00757     return NS_OK;
00758 }
00759 
00760 nsresult
00761 txStylesheetCompilerState::loadIncludedStylesheet(const nsAString& aURI)
00762 {
00763     PR_LOG(txLog::xslt, PR_LOG_ALWAYS,
00764            ("CompilerState::loadIncludedStylesheet: %s\n",
00765             NS_LossyConvertUCS2toASCII(aURI).get()));
00766     if (mStylesheetURI.Equals(aURI)) {
00767         return NS_ERROR_XSLT_LOAD_RECURSION;
00768     }
00769     NS_ENSURE_TRUE(mObserver, NS_ERROR_NOT_IMPLEMENTED);
00770 
00771     nsAutoPtr<txToplevelItem> item(new txDummyItem);
00772     NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY);
00773 
00774     nsresult rv = mToplevelIterator.addBefore(item);
00775     NS_ENSURE_SUCCESS(rv, rv);
00776     
00777     item.forget();
00778 
00779     // step back to the dummy-item
00780     mToplevelIterator.previous();
00781     
00782     txACompileObserver* observer = NS_STATIC_CAST(txStylesheetCompiler*, this);
00783 
00784     nsRefPtr<txStylesheetCompiler> compiler =
00785         new txStylesheetCompiler(aURI, mStylesheet, &mToplevelIterator,
00786                                  observer);
00787     NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY);
00788 
00789     // step forward before calling the observer in case of syncronous loading
00790     mToplevelIterator.next();
00791 
00792     if (!mChildCompilerList.AppendElement(compiler)) {
00793         return NS_ERROR_OUT_OF_MEMORY;
00794     }
00795 
00796     rv = mObserver->loadURI(aURI, mStylesheetURI, compiler);
00797     if (NS_FAILED(rv)) {
00798         mChildCompilerList.RemoveElement(compiler);
00799     }
00800 
00801     return rv;
00802 }
00803 
00804 nsresult
00805 txStylesheetCompilerState::loadImportedStylesheet(const nsAString& aURI,
00806                                                   txStylesheet::ImportFrame* aFrame)
00807 {
00808     PR_LOG(txLog::xslt, PR_LOG_ALWAYS,
00809            ("CompilerState::loadImportedStylesheet: %s\n",
00810             NS_LossyConvertUCS2toASCII(aURI).get()));
00811     if (mStylesheetURI.Equals(aURI)) {
00812         return NS_ERROR_XSLT_LOAD_RECURSION;
00813     }
00814     NS_ENSURE_TRUE(mObserver, NS_ERROR_NOT_IMPLEMENTED);
00815 
00816     txListIterator iter(&aFrame->mToplevelItems);
00817     iter.next(); // go to the end of the list
00818 
00819     txACompileObserver* observer = NS_STATIC_CAST(txStylesheetCompiler*, this);
00820 
00821     nsRefPtr<txStylesheetCompiler> compiler =
00822         new txStylesheetCompiler(aURI, mStylesheet, &iter, observer);
00823     NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY);
00824 
00825     if (!mChildCompilerList.AppendElement(compiler)) {
00826         return NS_ERROR_OUT_OF_MEMORY;
00827     }
00828 
00829     nsresult rv = mObserver->loadURI(aURI, mStylesheetURI, compiler);
00830     if (NS_FAILED(rv)) {
00831         mChildCompilerList.RemoveElement(compiler);
00832     }
00833 
00834     return rv;  
00835 }
00836 
00837 nsresult
00838 txStylesheetCompilerState::addGotoTarget(txInstruction** aTargetPointer)
00839 {
00840     if (!mGotoTargetPointers.AppendElement(aTargetPointer)) {
00841         return NS_ERROR_OUT_OF_MEMORY;
00842     }
00843     
00844     return NS_OK;
00845 }
00846 
00847 nsresult
00848 txStylesheetCompilerState::addVariable(const txExpandedName& aName)
00849 {
00850     txInScopeVariable* var = new txInScopeVariable(aName);
00851     NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY);
00852 
00853     if (!mInScopeVariables.AppendElement(var)) {
00854         delete var;
00855         return NS_ERROR_OUT_OF_MEMORY;
00856     }
00857 
00858     return NS_OK;
00859 }
00860 
00861 nsresult
00862 txStylesheetCompilerState::resolveNamespacePrefix(nsIAtom* aPrefix,
00863                                                   PRInt32& aID)
00864 {
00865     NS_ASSERTION(aPrefix && aPrefix != txXMLAtoms::_empty,
00866                  "caller should handle default namespace ''");
00867     aID = mElementContext->mMappings->lookupNamespace(aPrefix);
00868     return (aID != kNameSpaceID_Unknown) ? NS_OK : NS_ERROR_FAILURE;
00869 }
00870 
00875 class txErrorFunctionCall : public FunctionCall
00876 {
00877 public:
00878     txErrorFunctionCall(nsIAtom* aName, const PRInt32 aID)
00879         : mName(aName),
00880           mID(aID)
00881     {
00882     }
00883 
00884     TX_DECL_FUNCTION;
00885 
00886 private:
00887     nsCOMPtr<nsIAtom> mName;
00888     PRInt32 mID;
00889 };
00890 
00891 nsresult
00892 txErrorFunctionCall::evaluate(txIEvalContext* aContext,
00893                               txAExprResult** aResult)
00894 {
00895     *aResult = nsnull;
00896 
00897     return NS_ERROR_XPATH_BAD_EXTENSION_FUNCTION;
00898 }
00899 
00900 #ifdef TX_TO_STRING
00901 nsresult
00902 txErrorFunctionCall::getNameAtom(nsIAtom** aAtom)
00903 {
00904     NS_IF_ADDREF(*aAtom = mName);
00905 
00906     return NS_OK;
00907 }
00908 #endif
00909 
00910 nsresult
00911 txStylesheetCompilerState::resolveFunctionCall(nsIAtom* aName, PRInt32 aID,
00912                                                FunctionCall*& aFunction)
00913 {
00914     aFunction = nsnull;
00915 
00916     if (aID == kNameSpaceID_None) {
00917         if (aName == txXSLTAtoms::document) {
00918             aFunction = new DocumentFunctionCall(mElementContext->mBaseURI);
00919             NS_ENSURE_TRUE(aFunction, NS_ERROR_OUT_OF_MEMORY);
00920     
00921             return NS_OK;
00922         }
00923         if (aName == txXSLTAtoms::key) {
00924             aFunction = new txKeyFunctionCall(mElementContext->mMappings);
00925             NS_ENSURE_TRUE(aFunction, NS_ERROR_OUT_OF_MEMORY);
00926     
00927             return NS_OK;
00928         }
00929         if (aName == txXSLTAtoms::formatNumber) {
00930             aFunction = new txFormatNumberFunctionCall(mStylesheet,
00931                                                        mElementContext->mMappings);
00932             NS_ENSURE_TRUE(aFunction, NS_ERROR_OUT_OF_MEMORY);
00933     
00934             return NS_OK;
00935         }
00936         if (aName == txXSLTAtoms::current) {
00937             aFunction = new CurrentFunctionCall();
00938             NS_ENSURE_TRUE(aFunction, NS_ERROR_OUT_OF_MEMORY);
00939     
00940             return NS_OK;
00941         }
00942         if (aName == txXSLTAtoms::unparsedEntityUri) {
00943     
00944             return NS_ERROR_NOT_IMPLEMENTED;
00945         }
00946         if (aName == txXSLTAtoms::generateId) {
00947             aFunction = new GenerateIdFunctionCall();
00948             NS_ENSURE_TRUE(aFunction, NS_ERROR_OUT_OF_MEMORY);
00949     
00950             return NS_OK;
00951         }
00952         if (aName == txXSLTAtoms::systemProperty) {
00953             aFunction = new SystemPropertyFunctionCall(mElementContext->mMappings);
00954             NS_ENSURE_TRUE(aFunction, NS_ERROR_OUT_OF_MEMORY);
00955     
00956             return NS_OK;
00957         }
00958         if (aName == txXSLTAtoms::elementAvailable) {
00959             aFunction =
00960                 new ElementAvailableFunctionCall(mElementContext->mMappings);
00961             NS_ENSURE_TRUE(aFunction, NS_ERROR_OUT_OF_MEMORY);
00962     
00963             return NS_OK;
00964         }
00965         if (aName == txXSLTAtoms::functionAvailable) {
00966             aFunction =
00967                 new FunctionAvailableFunctionCall(mElementContext->mMappings);
00968             NS_ENSURE_TRUE(aFunction, NS_ERROR_OUT_OF_MEMORY);
00969     
00970             return NS_OK;
00971         }
00972         if (!fcp()) {
00973             return NS_ERROR_XPATH_UNKNOWN_FUNCTION;
00974         }
00975     }
00976 
00977     aFunction = new txErrorFunctionCall(aName, aID);
00978 
00979     return aFunction ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00980 }
00981 
00982 PRBool
00983 txStylesheetCompilerState::caseInsensitiveNameTests()
00984 {
00985     return PR_FALSE;
00986 }
00987 
00988 void
00989 txStylesheetCompilerState::SetErrorOffset(PRUint32 aOffset)
00990 {
00991     // XXX implement me
00992 }
00993 
00994 txElementContext::txElementContext(const nsAString& aBaseURI)
00995     : mPreserveWhitespace(PR_FALSE),
00996       mForwardsCompatibleParsing(PR_TRUE),
00997       mBaseURI(aBaseURI),
00998       mMappings(new txNamespaceMap),
00999       mDepth(0)
01000 {
01001     mInstructionNamespaces.AppendElement(NS_INT32_TO_PTR(kNameSpaceID_XSLT));
01002 }
01003 
01004 txElementContext::txElementContext(const txElementContext& aOther)
01005     : mPreserveWhitespace(aOther.mPreserveWhitespace),
01006       mForwardsCompatibleParsing(aOther.mForwardsCompatibleParsing),
01007       mBaseURI(aOther.mBaseURI),
01008       mMappings(aOther.mMappings),
01009       mDepth(0)
01010 {
01011       mInstructionNamespaces = aOther.mInstructionNamespaces;
01012 }