mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-10-05 19:10:09 +02:00
669 lines
21 KiB
C++
669 lines
21 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is TransforMiiX XSLT processor code.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Jonas Sicking.
|
|
* Portions created by the Initial Developer are Copyright (C) 2002
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Jonas Sicking <jonas@sicking.cc>
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
#include "txStylesheet.h"
|
|
#include "Expr.h"
|
|
#include "txXSLTPatterns.h"
|
|
#include "txToplevelItems.h"
|
|
#include "txInstructions.h"
|
|
#include "XSLTFunctions.h"
|
|
#include "TxLog.h"
|
|
#include "txKey.h"
|
|
|
|
txStylesheet::txStylesheet()
|
|
: mRootFrame(nsnull),
|
|
mNamedTemplates(PR_FALSE),
|
|
mDecimalFormats(PR_TRUE),
|
|
mAttributeSets(PR_FALSE),
|
|
mGlobalVariables(PR_TRUE),
|
|
mKeys(PR_TRUE)
|
|
{
|
|
}
|
|
|
|
nsresult
|
|
txStylesheet::init()
|
|
{
|
|
mRootFrame = new ImportFrame;
|
|
NS_ENSURE_TRUE(mRootFrame, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
// Create default templates
|
|
// element/root template
|
|
mContainerTemplate = new txPushParams;
|
|
NS_ENSURE_TRUE(mContainerTemplate, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
nsAutoPtr<txNodeTest> nt(new txNodeTypeTest(txNodeTypeTest::NODE_TYPE));
|
|
NS_ENSURE_TRUE(nt, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
nsAutoPtr<Expr> nodeExpr(new LocationStep(nt, LocationStep::CHILD_AXIS));
|
|
NS_ENSURE_TRUE(nodeExpr, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
txPushNewContext* pushContext = new txPushNewContext(nodeExpr);
|
|
mContainerTemplate->mNext = pushContext;
|
|
NS_ENSURE_TRUE(pushContext, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
txApplyDefaultElementTemplate* applyTemplates =
|
|
new txApplyDefaultElementTemplate;
|
|
pushContext->mNext = applyTemplates;
|
|
NS_ENSURE_TRUE(applyTemplates, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
txLoopNodeSet* loopNodeSet = new txLoopNodeSet(applyTemplates);
|
|
applyTemplates->mNext = loopNodeSet;
|
|
NS_ENSURE_TRUE(loopNodeSet, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
txPopParams* popParams = new txPopParams;
|
|
pushContext->mBailTarget = loopNodeSet->mNext = popParams;
|
|
NS_ENSURE_TRUE(popParams, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
popParams->mNext = new txReturn();
|
|
NS_ENSURE_TRUE(popParams->mNext, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
// attribute/textnode template
|
|
nt = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE);
|
|
NS_ENSURE_TRUE(nt, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
nodeExpr = new LocationStep(nt, LocationStep::SELF_AXIS);
|
|
NS_ENSURE_TRUE(nodeExpr, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
mCharactersTemplate = new txValueOf(nodeExpr, PR_FALSE);
|
|
NS_ENSURE_TRUE(mCharactersTemplate, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
mCharactersTemplate->mNext = new txReturn();
|
|
NS_ENSURE_TRUE(mCharactersTemplate->mNext, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
// pi/comment/namespace template
|
|
mEmptyTemplate = new txReturn();
|
|
NS_ENSURE_TRUE(mEmptyTemplate, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
txStylesheet::~txStylesheet()
|
|
{
|
|
// Delete all ImportFrames
|
|
delete mRootFrame;
|
|
txListIterator frameIter(&mImportFrames);
|
|
while (frameIter.hasNext()) {
|
|
delete NS_STATIC_CAST(ImportFrame*, frameIter.next());
|
|
}
|
|
|
|
txListIterator instrIter(&mTemplateInstructions);
|
|
while (instrIter.hasNext()) {
|
|
delete NS_STATIC_CAST(txInstruction*, instrIter.next());
|
|
}
|
|
|
|
// We can't make the map own its values because then we wouldn't be able
|
|
// to merge attributesets of the same name
|
|
txExpandedNameMap::iterator attrSetIter(mAttributeSets);
|
|
while (attrSetIter.next()) {
|
|
delete attrSetIter.value();
|
|
}
|
|
}
|
|
|
|
txInstruction*
|
|
txStylesheet::findTemplate(const txXPathNode& aNode,
|
|
const txExpandedName& aMode,
|
|
txIMatchContext* aContext,
|
|
ImportFrame* aImportedBy,
|
|
ImportFrame** aImportFrame)
|
|
{
|
|
NS_ASSERTION(aImportFrame, "missing ImportFrame pointer");
|
|
|
|
*aImportFrame = nsnull;
|
|
txInstruction* matchTemplate = nsnull;
|
|
ImportFrame* endFrame = nsnull;
|
|
txListIterator frameIter(&mImportFrames);
|
|
|
|
if (aImportedBy) {
|
|
ImportFrame* curr = NS_STATIC_CAST(ImportFrame*, frameIter.next());
|
|
while (curr != aImportedBy) {
|
|
curr = NS_STATIC_CAST(ImportFrame*, frameIter.next());
|
|
}
|
|
endFrame = aImportedBy->mFirstNotImported;
|
|
}
|
|
|
|
#ifdef PR_LOGGING
|
|
txPattern* match = 0;
|
|
#endif
|
|
|
|
ImportFrame* frame;
|
|
while (!matchTemplate &&
|
|
(frame = NS_STATIC_CAST(ImportFrame*, frameIter.next())) &&
|
|
frame != endFrame) {
|
|
|
|
// get templatelist for this mode
|
|
txList* templates =
|
|
NS_STATIC_CAST(txList*, frame->mMatchableTemplates.get(aMode));
|
|
|
|
if (templates) {
|
|
txListIterator templateIter(templates);
|
|
|
|
// Find template with highest priority
|
|
MatchableTemplate* templ;
|
|
while (!matchTemplate &&
|
|
(templ =
|
|
NS_STATIC_CAST(MatchableTemplate*, templateIter.next()))) {
|
|
if (templ->mMatch->matches(aNode, aContext)) {
|
|
matchTemplate = templ->mFirstInstruction;
|
|
*aImportFrame = frame;
|
|
#ifdef PR_LOGGING
|
|
match = templ->mMatch;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef PR_LOGGING
|
|
nsAutoString mode, nodeName;
|
|
if (aMode.mLocalName) {
|
|
aMode.mLocalName->ToString(mode);
|
|
}
|
|
txXPathNodeUtils::getNodeName(aNode, nodeName);
|
|
if (matchTemplate) {
|
|
nsAutoString matchAttr;
|
|
#ifdef TX_TO_STRING
|
|
match->toString(matchAttr);
|
|
#endif
|
|
PR_LOG(txLog::xslt, PR_LOG_DEBUG,
|
|
("MatchTemplate, Pattern %s, Mode %s, Node %s\n",
|
|
NS_LossyConvertUCS2toASCII(matchAttr).get(),
|
|
NS_LossyConvertUCS2toASCII(mode).get(),
|
|
NS_LossyConvertUCS2toASCII(nodeName).get()));
|
|
}
|
|
else {
|
|
PR_LOG(txLog::xslt, PR_LOG_DEBUG,
|
|
("No match, Node %s, Mode %s\n",
|
|
NS_LossyConvertUCS2toASCII(nodeName).get(),
|
|
NS_LossyConvertUCS2toASCII(mode).get()));
|
|
}
|
|
#endif
|
|
|
|
if (!matchTemplate) {
|
|
if (txXPathNodeUtils::isElement(aNode) ||
|
|
txXPathNodeUtils::isRoot(aNode)) {
|
|
matchTemplate = mContainerTemplate;
|
|
}
|
|
else if (txXPathNodeUtils::isAttribute(aNode) ||
|
|
txXPathNodeUtils::isText(aNode)) {
|
|
matchTemplate = mCharactersTemplate;
|
|
}
|
|
else {
|
|
matchTemplate = mEmptyTemplate;
|
|
}
|
|
}
|
|
|
|
return matchTemplate;
|
|
}
|
|
|
|
txDecimalFormat*
|
|
txStylesheet::getDecimalFormat(const txExpandedName& aName)
|
|
{
|
|
return NS_STATIC_CAST(txDecimalFormat*, mDecimalFormats.get(aName));
|
|
}
|
|
|
|
txInstruction*
|
|
txStylesheet::getAttributeSet(const txExpandedName& aName)
|
|
{
|
|
return NS_STATIC_CAST(txInstruction*, mAttributeSets.get(aName));
|
|
}
|
|
|
|
txInstruction*
|
|
txStylesheet::getNamedTemplate(const txExpandedName& aName)
|
|
{
|
|
return NS_STATIC_CAST(txInstruction*, mNamedTemplates.get(aName));
|
|
}
|
|
|
|
txOutputFormat*
|
|
txStylesheet::getOutputFormat()
|
|
{
|
|
return &mOutputFormat;
|
|
}
|
|
|
|
txStylesheet::GlobalVariable*
|
|
txStylesheet::getGlobalVariable(const txExpandedName& aName)
|
|
{
|
|
return NS_STATIC_CAST(GlobalVariable*, mGlobalVariables.get(aName));
|
|
}
|
|
|
|
const txExpandedNameMap&
|
|
txStylesheet::getKeyMap()
|
|
{
|
|
return mKeys;
|
|
}
|
|
|
|
PRBool
|
|
txStylesheet::isStripSpaceAllowed(const txXPathNode& aNode, txIMatchContext* aContext)
|
|
{
|
|
PRInt32 frameCount = mStripSpaceTests.Count();
|
|
if (frameCount == 0) {
|
|
return PR_FALSE;
|
|
}
|
|
|
|
txXPathTreeWalker walker(aNode);
|
|
|
|
if (txXPathNodeUtils::isText(walker.getCurrentPosition()) &&
|
|
(!txXPathNodeUtils::isWhitespace(aNode) || !walker.moveToParent())) {
|
|
return PR_FALSE;
|
|
}
|
|
|
|
const txXPathNode& node = walker.getCurrentPosition();
|
|
|
|
if (!txXPathNodeUtils::isElement(node)) {
|
|
return PR_FALSE;
|
|
}
|
|
|
|
// check Whitespace stipping handling list against given Node
|
|
PRInt32 i;
|
|
for (i = 0; i < frameCount; ++i) {
|
|
txStripSpaceTest* sst =
|
|
NS_STATIC_CAST(txStripSpaceTest*, mStripSpaceTests[i]);
|
|
if (sst->matches(node, aContext)) {
|
|
return sst->stripsSpace() && !XMLUtils::getXMLSpacePreserve(node);
|
|
}
|
|
}
|
|
|
|
return PR_FALSE;
|
|
}
|
|
|
|
nsresult
|
|
txStylesheet::doneCompiling()
|
|
{
|
|
nsresult rv = NS_OK;
|
|
// Collect all importframes into a single ordered list
|
|
txListIterator frameIter(&mImportFrames);
|
|
rv = frameIter.addAfter(mRootFrame);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
mRootFrame = nsnull;
|
|
frameIter.next();
|
|
rv = addFrames(frameIter);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// Loop through importframes in decreasing-precedence-order and process
|
|
// all items
|
|
frameIter.reset();
|
|
ImportFrame* frame;
|
|
while ((frame = NS_STATIC_CAST(ImportFrame*, frameIter.next()))) {
|
|
nsVoidArray frameStripSpaceTests;
|
|
|
|
txListIterator itemIter(&frame->mToplevelItems);
|
|
itemIter.resetToEnd();
|
|
txToplevelItem* item;
|
|
while ((item = NS_STATIC_CAST(txToplevelItem*, itemIter.previous()))) {
|
|
switch (item->getType()) {
|
|
case txToplevelItem::attributeSet:
|
|
{
|
|
rv = addAttributeSet(NS_STATIC_CAST(txAttributeSetItem*,
|
|
item));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
break;
|
|
}
|
|
case txToplevelItem::dummy:
|
|
case txToplevelItem::import:
|
|
{
|
|
break;
|
|
}
|
|
case txToplevelItem::output:
|
|
{
|
|
mOutputFormat.merge(NS_STATIC_CAST(txOutputItem*, item)->mFormat);
|
|
break;
|
|
}
|
|
case txToplevelItem::stripSpace:
|
|
{
|
|
rv = addStripSpace(NS_STATIC_CAST(txStripSpaceItem*, item),
|
|
frameStripSpaceTests);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
break;
|
|
}
|
|
case txToplevelItem::templ:
|
|
{
|
|
rv = addTemplate(NS_STATIC_CAST(txTemplateItem*, item),
|
|
frame);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
break;
|
|
}
|
|
case txToplevelItem::variable:
|
|
{
|
|
rv = addGlobalVariable(NS_STATIC_CAST(txVariableItem*,
|
|
item));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
break;
|
|
}
|
|
}
|
|
delete item;
|
|
itemIter.remove(); //remove() moves to the previous
|
|
itemIter.next();
|
|
}
|
|
if (!mStripSpaceTests.AppendElements(frameStripSpaceTests)) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
frameStripSpaceTests.Clear();
|
|
}
|
|
|
|
if (!mDecimalFormats.get(txExpandedName())) {
|
|
nsAutoPtr<txDecimalFormat> format(new txDecimalFormat);
|
|
NS_ENSURE_TRUE(format, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
rv = mDecimalFormats.add(txExpandedName(), format);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
format.forget();
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
txStylesheet::addTemplate(txTemplateItem* aTemplate,
|
|
ImportFrame* aImportFrame)
|
|
{
|
|
NS_ASSERTION(aTemplate, "missing template");
|
|
|
|
txInstruction* instr = aTemplate->mFirstInstruction;
|
|
nsresult rv = mTemplateInstructions.add(instr);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// mTemplateInstructions now owns the instructions
|
|
aTemplate->mFirstInstruction.forget();
|
|
|
|
if (!aTemplate->mName.isNull()) {
|
|
rv = mNamedTemplates.add(aTemplate->mName, instr);
|
|
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) || rv == NS_ERROR_XSLT_ALREADY_SET,
|
|
rv);
|
|
}
|
|
|
|
if (!aTemplate->mMatch) {
|
|
// This is no error, see section 6 Named Templates
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// get the txList for the right mode
|
|
txList* templates =
|
|
NS_STATIC_CAST(txList*,
|
|
aImportFrame->mMatchableTemplates.get(aTemplate->mMode));
|
|
|
|
if (!templates) {
|
|
nsAutoPtr<txList> newList(new txList);
|
|
NS_ENSURE_TRUE(newList, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
rv = aImportFrame->mMatchableTemplates.add(aTemplate->mMode, newList);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
templates = newList.forget();
|
|
}
|
|
|
|
// Add the simple patterns to the list of matchable templates, according
|
|
// to default priority
|
|
txList simpleMatches;
|
|
rv = aTemplate->mMatch->getSimplePatterns(simpleMatches);
|
|
if (simpleMatches.get(0) == aTemplate->mMatch) {
|
|
aTemplate->mMatch.forget();
|
|
}
|
|
|
|
txListIterator simples(&simpleMatches);
|
|
while (simples.hasNext()) {
|
|
// XXX if we fail in this loop, we leak the remaining simple patterns
|
|
nsAutoPtr<txPattern> simple(NS_STATIC_CAST(txPattern*, simples.next()));
|
|
double priority = aTemplate->mPrio;
|
|
if (Double::isNaN(priority)) {
|
|
priority = simple->getDefaultPriority();
|
|
NS_ASSERTION(!Double::isNaN(priority),
|
|
"simple pattern without default priority");
|
|
}
|
|
nsAutoPtr<MatchableTemplate>
|
|
nt(new MatchableTemplate(instr, simple, priority));
|
|
NS_ENSURE_TRUE(nt, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
txListIterator templ(templates);
|
|
while (templ.hasNext()) {
|
|
MatchableTemplate* mt = NS_STATIC_CAST(MatchableTemplate*,
|
|
templ.next());
|
|
if (priority > mt->mPriority) {
|
|
rv = templ.addBefore(nt);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nt.forget();
|
|
break;
|
|
}
|
|
}
|
|
if (nt) {
|
|
rv = templates->add(nt);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nt.forget();
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
txStylesheet::addFrames(txListIterator& aInsertIter)
|
|
{
|
|
ImportFrame* frame = NS_STATIC_CAST(ImportFrame*, aInsertIter.current());
|
|
nsresult rv = NS_OK;
|
|
txListIterator iter(&frame->mToplevelItems);
|
|
txToplevelItem* item;
|
|
while ((item = NS_STATIC_CAST(txToplevelItem*, iter.next()))) {
|
|
if (item->getType() == txToplevelItem::import) {
|
|
txImportItem* import = NS_STATIC_CAST(txImportItem*, item);
|
|
import->mFrame->mFirstNotImported =
|
|
NS_STATIC_CAST(ImportFrame*, aInsertIter.next());
|
|
rv = aInsertIter.addBefore(import->mFrame);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
import->mFrame.forget();
|
|
aInsertIter.previous();
|
|
rv = addFrames(aInsertIter);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
aInsertIter.previous();
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
txStylesheet::addStripSpace(txStripSpaceItem* aStripSpaceItem,
|
|
nsVoidArray& frameStripSpaceTests)
|
|
{
|
|
PRInt32 testCount = aStripSpaceItem->mStripSpaceTests.Count();
|
|
for (; testCount > 0; --testCount) {
|
|
txStripSpaceTest* sst =
|
|
NS_STATIC_CAST(txStripSpaceTest*,
|
|
aStripSpaceItem->mStripSpaceTests[testCount-1]);
|
|
double priority = sst->getDefaultPriority();
|
|
PRInt32 i, frameCount = frameStripSpaceTests.Count();
|
|
for (i = 0; i < frameCount; ++i) {
|
|
txStripSpaceTest* fsst =
|
|
NS_STATIC_CAST(txStripSpaceTest*, frameStripSpaceTests[i]);
|
|
if (fsst->getDefaultPriority() < priority) {
|
|
break;
|
|
}
|
|
}
|
|
if (!frameStripSpaceTests.InsertElementAt(sst, i)) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
|
|
aStripSpaceItem->mStripSpaceTests.RemoveElementAt(testCount-1);
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
txStylesheet::addAttributeSet(txAttributeSetItem* aAttributeSetItem)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
txInstruction* oldInstr =
|
|
NS_STATIC_CAST(txInstruction*,
|
|
mAttributeSets.get(aAttributeSetItem->mName));
|
|
if (!oldInstr) {
|
|
rv = mAttributeSets.add(aAttributeSetItem->mName,
|
|
aAttributeSetItem->mFirstInstruction);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
aAttributeSetItem->mFirstInstruction.forget();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
// We need to prepend the new instructions before the existing ones.
|
|
txInstruction* instr = aAttributeSetItem->mFirstInstruction;
|
|
txInstruction* lastNonReturn = nsnull;
|
|
while (instr->mNext) {
|
|
lastNonReturn = instr;
|
|
instr = instr->mNext;
|
|
}
|
|
|
|
if (!lastNonReturn) {
|
|
// The new attributeset is empty, so lets just ignore it.
|
|
return NS_OK;
|
|
}
|
|
|
|
rv = mAttributeSets.set(aAttributeSetItem->mName,
|
|
aAttributeSetItem->mFirstInstruction);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
aAttributeSetItem->mFirstInstruction.forget();
|
|
|
|
delete lastNonReturn->mNext; // Delete the txReturn...
|
|
lastNonReturn->mNext = oldInstr; // ...and link up the old instructions.
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
txStylesheet::addGlobalVariable(txVariableItem* aVariable)
|
|
{
|
|
if (mGlobalVariables.get(aVariable->mName)) {
|
|
return NS_OK;
|
|
}
|
|
nsAutoPtr<GlobalVariable> var(
|
|
new GlobalVariable(aVariable->mValue, aVariable->mFirstInstruction,
|
|
aVariable->mIsParam));
|
|
NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
nsresult rv = mGlobalVariables.add(aVariable->mName, var);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
var.forget();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
nsresult
|
|
txStylesheet::addKey(const txExpandedName& aName,
|
|
nsAutoPtr<txPattern> aMatch, nsAutoPtr<Expr> aUse)
|
|
{
|
|
nsresult rv = NS_OK;
|
|
|
|
txXSLKey* xslKey = NS_STATIC_CAST(txXSLKey*, mKeys.get(aName));
|
|
if (!xslKey) {
|
|
xslKey = new txXSLKey(aName);
|
|
NS_ENSURE_TRUE(xslKey, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
rv = mKeys.add(aName, xslKey);
|
|
if (NS_FAILED(rv)) {
|
|
delete xslKey;
|
|
return rv;
|
|
}
|
|
}
|
|
if (!xslKey->addKey(aMatch, aUse)) {
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult
|
|
txStylesheet::addDecimalFormat(const txExpandedName& aName,
|
|
nsAutoPtr<txDecimalFormat> aFormat)
|
|
{
|
|
txDecimalFormat* existing =
|
|
NS_STATIC_CAST(txDecimalFormat*, mDecimalFormats.get(aName));
|
|
if (existing) {
|
|
NS_ENSURE_TRUE(existing->isEqual(aFormat),
|
|
NS_ERROR_XSLT_PARSE_FAILURE);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult rv = mDecimalFormats.add(aName, aFormat);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
aFormat.forget();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
txStylesheet::ImportFrame::ImportFrame()
|
|
: mMatchableTemplates(MB_TRUE),
|
|
mFirstNotImported(nsnull)
|
|
{
|
|
}
|
|
|
|
txStylesheet::ImportFrame::~ImportFrame()
|
|
{
|
|
// Delete templates in mMatchableTemplates
|
|
txExpandedNameMap::iterator mapIter(mMatchableTemplates);
|
|
while (mapIter.next()) {
|
|
txListIterator templIter(NS_STATIC_CAST(txList*, mapIter.value()));
|
|
MatchableTemplate* templ;
|
|
while ((templ = NS_STATIC_CAST(MatchableTemplate*, templIter.next()))) {
|
|
delete templ;
|
|
}
|
|
}
|
|
|
|
txListIterator tlIter(&mToplevelItems);
|
|
while (tlIter.hasNext()) {
|
|
delete NS_STATIC_CAST(txToplevelItem*, tlIter.next());
|
|
}
|
|
}
|
|
|
|
txStylesheet::GlobalVariable::GlobalVariable(nsAutoPtr<Expr> aExpr,
|
|
nsAutoPtr<txInstruction> aFirstInstruction,
|
|
PRBool aIsParam)
|
|
: mExpr(aExpr), mFirstInstruction(aFirstInstruction), mIsParam(aIsParam)
|
|
{
|
|
}
|