blob: 5d077f5ce6ba2f14a36bb23af8c8eadd6836cd8c [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xalan" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 1999, International
* Business Machines, Inc., http://www.ibm.com. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
#include "ElemNumber.hpp"
#include <xercesc/sax/AttributeList.hpp>
#include <XalanDOM/XalanDocument.hpp>
#include <PlatformSupport/DOMStringHelper.hpp>
#include <PlatformSupport/DoubleSupport.hpp>
#include <PlatformSupport/XalanNumberFormat.hpp>
#include <PlatformSupport/XalanSimplePrefixResolver.hpp>
#include <PlatformSupport/XalanUnicode.hpp>
#include <DOMSupport/DOMServices.hpp>
#include <Include/XalanAutoPtr.hpp>
#include <XPath/ElementPrefixResolverProxy.hpp>
#include <XPath/XPath.hpp>
#include <XPath/XObjectFactory.hpp>
#include "AVT.hpp"
#include "Constants.hpp"
#include "CountersTable.hpp"
#include "StylesheetConstructionContext.hpp"
#include "StylesheetExecutionContext.hpp"
#if !defined(XALAN_NO_NAMESPACES)
using std::vector;
#endif
ElemNumber::ElemNumber(
StylesheetConstructionContext& constructionContext,
Stylesheet& stylesheetTree,
const AttributeList& atts,
int lineNumber,
int columnNumber) :
ElemTemplateElement(constructionContext,
stylesheetTree,
lineNumber,
columnNumber,
Constants::ELEMNAME_NUMBER),
m_countMatchPattern(0),
m_fromMatchPattern(0),
m_valueExpr(0),
m_level(Constants::NUMBERLEVEL_SINGLE),
m_format_avt(0),
m_lang_avt(0),
m_lettervalue_avt(0),
m_groupingSeparator_avt(0),
m_groupingSize_avt(0)
{
const unsigned int nAttrs = atts.getLength();
for(unsigned int i = 0; i < nAttrs; i++)
{
const XalanDOMChar* const aname = atts.getName(i);
if(equals(aname, Constants::ATTRNAME_LEVEL))
{
const XalanDOMChar* const levelValue = atts.getValue(i);
if(equals(Constants::ATTRVAL_MULTI, levelValue))
m_level = Constants::NUMBERLEVEL_MULTI;
else if(equals(levelValue,Constants::ATTRVAL_ANY))
m_level = Constants::NUMBERLEVEL_ANY;
else if(equals(levelValue,Constants::ATTRVAL_SINGLE))
m_level = Constants::NUMBERLEVEL_SINGLE;
else
constructionContext.error(
"The attribute 'level' has an illegal value",
0,
this);
}
else if(equals(aname, Constants::ATTRNAME_COUNT))
{
m_countMatchPattern = constructionContext.createMatchPattern(getLocator(), atts.getValue(i), *this);
}
else if(equals(aname, Constants::ATTRNAME_FROM))
{
m_fromMatchPattern = constructionContext.createMatchPattern(getLocator(), atts.getValue(i), *this);
}
else if(equals(aname, Constants::ATTRNAME_VALUE))
{
m_valueExpr = constructionContext.createXPath(getLocator(), atts.getValue(i), *this);
}
else if(equals(aname, Constants::ATTRNAME_FORMAT))
{
m_format_avt = new AVT(getLocator(), aname, atts.getType(i),
atts.getValue(i), *this, constructionContext);
}
else if(equals(aname, Constants::ATTRNAME_LANG))
{
m_lang_avt = new AVT(getLocator(), aname, atts.getType(i),
atts.getValue(i), *this, constructionContext);
}
else if(equals(aname, Constants::ATTRNAME_LETTERVALUE))
{
m_lettervalue_avt = new AVT(getLocator(), aname, atts.getType(i),
atts.getValue(i), *this, constructionContext);
}
else if(equals(aname,Constants::ATTRNAME_GROUPINGSEPARATOR))
{
m_groupingSeparator_avt = new AVT(getLocator(), aname, atts.getType(i),
atts.getValue(i), *this, constructionContext);
}
else if(equals(aname,Constants::ATTRNAME_GROUPINGSIZE))
{
m_groupingSize_avt = new AVT(getLocator(), aname, atts.getType(i),
atts.getValue(i), *this, constructionContext);
}
else if(!isAttrOK(aname, atts, i, constructionContext))
{
constructionContext.error(
"xsl:number has an illegal attribute",
0,
this);
}
}
}
ElemNumber::~ElemNumber()
{
#if defined(XALAN_CANNOT_DELETE_CONST)
delete (AVT*)m_format_avt;
delete (AVT*)m_lang_avt;
delete (AVT*)m_lettervalue_avt;
delete (AVT*)m_groupingSeparator_avt;
delete (AVT*)m_groupingSize_avt;
#else
delete m_format_avt;
delete m_lang_avt;
delete m_lettervalue_avt;
delete m_groupingSeparator_avt;
delete m_groupingSize_avt;
#endif
}
const XalanDOMString&
ElemNumber::getElementName() const
{
return Constants::ELEMNAME_NUMBER_WITH_PREFIX_STRING;
}
void
ElemNumber::execute(StylesheetExecutionContext& executionContext) const
{
ElemTemplateElement::execute(executionContext);
typedef XPathExecutionContext::GetAndReleaseCachedString GetAndReleaseCachedString;
GetAndReleaseCachedString theGuard(executionContext);
XalanDOMString& countString = theGuard.get();
getCountString(executionContext, countString);
if (!isEmpty(countString))
{
executionContext.characters(toCharArray(countString), 0, length(countString));
}
}
XalanNode*
ElemNumber::findAncestor(
StylesheetExecutionContext& executionContext,
const XPath* fromMatchPattern,
const XPath* countMatchPattern,
XalanNode* context,
const XalanElement* /* namespaceContext */) const
{
XalanNode* contextCopy = context;
while(contextCopy != 0)
{
if(0 != fromMatchPattern)
{
if(fromMatchPattern->getMatchScore(contextCopy, *this,
executionContext) !=
XPath::eMatchScoreNone)
{
break;
}
}
if(0 != countMatchPattern)
{
if(countMatchPattern->getMatchScore(contextCopy, *this,
executionContext) !=
XPath::eMatchScoreNone)
{
break;
}
}
contextCopy = DOMServices::getParentOfNode(*contextCopy);
}
return contextCopy;
}
XalanNode*
ElemNumber::findPrecedingOrAncestorOrSelf(
StylesheetExecutionContext& executionContext,
const XPath* fromMatchPattern,
const XPath* countMatchPattern,
XalanNode* context,
const XalanElement* /* namespaceContext */) const
{
XalanNode* contextCopy = context;
while(contextCopy != 0)
{
if(0 != fromMatchPattern)
{
if(fromMatchPattern->getMatchScore(contextCopy, *this,
executionContext) !=
XPath::eMatchScoreNone)
{
contextCopy = 0;
break;
}
}
if(0 != countMatchPattern)
{
if(countMatchPattern->getMatchScore(contextCopy, *this,
executionContext) !=
XPath::eMatchScoreNone)
{
break;
}
}
XalanNode* const prevSibling = contextCopy->getPreviousSibling();
if(prevSibling == 0)
{
contextCopy = DOMServices::getParentOfNode(*contextCopy);
}
else
{
// Now go down the chain of children of this sibling
contextCopy = prevSibling->getLastChild();
if (contextCopy == 0)
contextCopy = prevSibling;
}
}
return contextCopy;
}
const XPath*
ElemNumber::getCountMatchPattern(
StylesheetExecutionContext& executionContext,
XalanNode* contextNode) const
{
const XPath* countMatchPattern = 0;
switch(contextNode->getNodeType())
{
case XalanNode::ELEMENT_NODE:
{
// Check to see if we have any fiddling to do with the match pattern
// we create...
const XalanDOMString& theNamespaceURI = contextNode->getNamespaceURI();
const XalanDOMString& theNodeName = contextNode->getNodeName();
if (isEmpty(theNamespaceURI) == true)
{
// No namespace URI means no prefix, so this is easy...
assert(isEmpty(contextNode->getLocalName()) == true);
// We can pass any PrefixResolver instance, so just
// pass ourself...
countMatchPattern =
executionContext.createMatchPattern(theNodeName, *this);
}
else if (length(theNodeName) != length(contextNode->getLocalName()))
{
// OK, there's a prefix, so create a prefix resolver so the
// prefix can be properly resolved...
const XalanElement* const theElement =
#if defined(XALAN_OLD_STYLE_CASTS)
(const XalanElement*)contextNode;
#else
static_cast<const XalanElement*>(contextNode);
#endif
const ElementPrefixResolverProxy theProxy(theElement);
countMatchPattern =
executionContext.createMatchPattern(theNodeName, theProxy);
}
else
{
// OK, this is ugly. We have to get a unique prefix and
// construct a match pattern with that prefix...
StylesheetExecutionContext::GetAndReleaseCachedString thePrefix(executionContext);
executionContext.getUniqueNamespaceValue(thePrefix.get());
StylesheetExecutionContext::GetAndReleaseCachedString theMatchPatternString(executionContext);
assign(theMatchPatternString.get(), thePrefix.get());
append(theMatchPatternString.get(), XalanDOMChar(XalanUnicode::charColon));
append(theMatchPatternString.get(), theNodeName);
// Use this class to resolve the synthesized prefix to the
// appropriate namespace URI. We could see if a prefix is
// already in scope for the namespace URI, but it would take
// more effort to find that out than it would to just
// create this simple resolver.
const XalanSimplePrefixResolver theResolver(
thePrefix.get(),
theNamespaceURI,
getURI());
countMatchPattern =
executionContext.createMatchPattern(
theMatchPatternString.get(),
theResolver);
}
}
break;
case XalanNode::ATTRIBUTE_NODE:
{
const XalanAttr* const theAttribute =
#if defined(XALAN_OLD_STYLE_CASTS)
(const XalanAttr*)contextNode;
#else
static_cast<const XalanAttr*>(contextNode);
#endif
assert(theAttribute->getOwnerElement() != 0);
const XalanDOMString& theNodeName = theAttribute->getNodeName();
const ElementPrefixResolverProxy theProxy(theAttribute->getOwnerElement());
StylesheetExecutionContext::GetAndReleaseCachedString theMatchPatternString(executionContext);
assign(theMatchPatternString.get(), s_atString);
append(theMatchPatternString.get(), theNodeName);
countMatchPattern = executionContext.createMatchPattern(
theMatchPatternString.get(),
theProxy);
}
break;
case XalanNode::CDATA_SECTION_NODE:
case XalanNode::TEXT_NODE:
countMatchPattern = executionContext.createMatchPattern(
s_textString, *this);
break;
case XalanNode::COMMENT_NODE:
countMatchPattern = executionContext.createMatchPattern(
s_commentString, *this);
break;
case XalanNode::DOCUMENT_NODE:
countMatchPattern = executionContext.createMatchPattern(
s_slashString, *this);
break;
case XalanNode::PROCESSING_INSTRUCTION_NODE:
{
StylesheetExecutionContext::GetAndReleaseCachedString theMatchPatternString(executionContext);
assign(theMatchPatternString.get(), s_piString);
append(theMatchPatternString.get(), contextNode->getNodeName());
append(theMatchPatternString.get(), s_leftParenString);
countMatchPattern = executionContext.createMatchPattern(
theMatchPatternString.get(),
*this);
}
break;
default:
break;
}
return countMatchPattern;
}
inline void
ElemNumber::getCountString(
StylesheetExecutionContext& executionContext,
XalanNode* sourceNode,
const MutableNodeRefList& ancestors,
CountersTable& ctable,
int numberList[],
NodeRefListBase::size_type numberListLength,
XalanDOMString& theResult) const
{
for(NodeRefListBase::size_type i = 0; i < numberListLength; i++)
{
XalanNode* const target = ancestors.item(numberListLength - i - 1);
numberList[i] = ctable.countNode(
executionContext,
this,
target);
}
formatNumberList(
executionContext,
numberList,
numberListLength,
sourceNode,
theResult);
}
void
ElemNumber::getCountString(
StylesheetExecutionContext& executionContext,
XalanDOMString& theResult) const
{
XalanNode* sourceNode = executionContext.getCurrentNode();
assert(sourceNode != 0);
if(0 != m_valueExpr)
{
const XObjectPtr countObj(m_valueExpr->execute(sourceNode, *this, executionContext));
assert(countObj.null() == false);
const double theValue = countObj->num();
int theNumber = 0;
if (DoubleSupport::isNaN(theValue) == false)
{
theNumber = int(DoubleSupport::round(theValue));
}
formatNumberList(
executionContext,
&theNumber,
1,
sourceNode,
theResult);
}
else
{
CountersTable& ctable = executionContext.getCountersTable();
if(Constants::NUMBERLEVEL_ANY == m_level)
{
const int theNumber =
ctable.countNode(executionContext, this, sourceNode);
formatNumberList(
executionContext,
&theNumber,
1,
sourceNode,
theResult);
}
else
{
typedef XPathExecutionContext::BorrowReturnMutableNodeRefList BorrowReturnMutableNodeRefList;
BorrowReturnMutableNodeRefList ancestors(executionContext);
getMatchingAncestors(
executionContext,
sourceNode,
Constants::NUMBERLEVEL_SINGLE == m_level,
*ancestors.get());
const NodeRefListBase::size_type lastIndex = ancestors->getLength();
if(lastIndex > 0)
{
const NodeRefListBase::size_type theStackArrayThreshold = 100;
if (lastIndex < theStackArrayThreshold)
{
int numberList[theStackArrayThreshold];
getCountString(
executionContext,
sourceNode,
*ancestors.get(),
ctable,
numberList,
lastIndex,
theResult);
}
else
{
IntArrayType numberList;
numberList.resize(lastIndex);
getCountString(
executionContext,
sourceNode,
*ancestors.get(),
ctable,
&*numberList.begin(),
lastIndex,
theResult);
}
}
}
}
}
XalanNode*
ElemNumber::getPreviousNode(
StylesheetExecutionContext& executionContext,
XalanNode* pos) const
{
// Create an XPathGuard, since we may need to
// create a new XPath...
StylesheetExecutionContext::XPathGuard xpathGuard(
executionContext);
const XPath* countMatchPattern = m_countMatchPattern;
if (countMatchPattern == 0)
{
// Get the XPath...
xpathGuard.reset(getCountMatchPattern(executionContext, pos));
countMatchPattern = xpathGuard.get();
}
if(Constants::NUMBERLEVEL_ANY == m_level)
{
const XPath* const fromMatchPattern = m_fromMatchPattern;
// Do a backwards document-order walk 'till a node is found that matches
// the 'from' pattern, or a node is found that matches the 'count' pattern,
// or the top of the tree is found.
while(0 != pos)
{
// Get the previous sibling, if there is no previous sibling,
// then count the parent, but if there is a previous sibling,
// dive down to the lowest right-hand (last) child of that sibling.
XalanNode* next = pos->getPreviousSibling();
if(0 == next)
{
next = pos->getParentNode();
if(0 != next &&
next->getNodeType() == XalanNode::DOCUMENT_NODE ||
(0 != fromMatchPattern &&
fromMatchPattern->getMatchScore(
next,
*this,
executionContext) != XPath::eMatchScoreNone))
{
pos = 0; // return 0 from function.
break; // from while loop
}
}
else
{
// dive down to the lowest right child.
XalanNode* child = next;
while(0 != child)
{
child = next->getLastChild();
if(0 != child)
next = child;
}
}
pos = next;
if(0 != pos &&
(0 == countMatchPattern ||
countMatchPattern->getMatchScore(
pos,
*this,
executionContext) != XPath::eMatchScoreNone))
{
break;
}
}
}
else // NUMBERLEVEL_MULTI or NUMBERLEVEL_SINGLE
{
while(0 != pos)
{
pos = pos->getPreviousSibling();
if(0 != pos &&
(0 == countMatchPattern ||
countMatchPattern->getMatchScore(
pos,
*this,
executionContext) != XPath::eMatchScoreNone))
{
break;
}
}
}
return pos;
}
XalanNode*
ElemNumber::getTargetNode(
StylesheetExecutionContext& executionContext,
XalanNode* sourceNode) const
{
XalanNode* target = 0;
// Create an XPathGuard, since we may need to
// create a new XPath...
StylesheetExecutionContext::XPathGuard xpathGuard(
executionContext);
const XPath* countMatchPattern = m_countMatchPattern;
if (countMatchPattern == 0)
{
// Get the XPath...
xpathGuard.reset(getCountMatchPattern(executionContext, sourceNode));
countMatchPattern = xpathGuard.get();
}
if(Constants::NUMBERLEVEL_ANY == m_level)
{
target = findPrecedingOrAncestorOrSelf(
executionContext,
m_fromMatchPattern,
countMatchPattern,
sourceNode,
this);
}
else
{
target = findAncestor(
executionContext,
m_fromMatchPattern,
countMatchPattern,
sourceNode,
this);
}
return target;
}
void
ElemNumber::getMatchingAncestors(
StylesheetExecutionContext& executionContext,
XalanNode* node,
bool stopAtFirstFound,
MutableNodeRefList& ancestors) const
{
// Create an XPathGuard, since we may need to
// create a new XPath...
StylesheetExecutionContext::XPathGuard xpathGuard(
executionContext);
const XPath* countMatchPattern = m_countMatchPattern;
if (countMatchPattern == 0)
{
// Get the XPath...
xpathGuard.reset(getCountMatchPattern(executionContext, node));
countMatchPattern = xpathGuard.get();
}
while(0 != node)
{
if((0 != m_fromMatchPattern) &&
(m_fromMatchPattern->getMatchScore(node, *this, executionContext) !=
XPath::eMatchScoreNone))
{
// The following if statement gives level="single" different
// behavior from level="multiple", which seems incorrect according
// to the XSLT spec. For now we are leaving this in to replicate
// the same behavior in XT, but, for all intents and purposes we
// think this is a bug, or there is something about level="single"
// that we still don't understand.
if(!stopAtFirstFound)
break;
}
if(0 == countMatchPattern)
executionContext.error(
"Programmer error! countMatchPattern should never be 0!",
node,
getLocator());
if(countMatchPattern->getMatchScore(node, *this, executionContext) !=
XPath::eMatchScoreNone)
{
ancestors.addNode(node);
if(stopAtFirstFound)
break;
}
node = DOMServices::getParentOfNode(*node);
}
}
XalanNumberFormat*
ElemNumber::getNumberFormatter(
StylesheetExecutionContext& executionContext,
XalanNode* contextNode) const
{
// Helper to format local specific numbers to strings.
XalanAutoPtr<XalanNumberFormat> formatter(executionContext.createXalanNumberFormat());
typedef XPathExecutionContext::GetAndReleaseCachedString GetAndReleaseCachedString;
GetAndReleaseCachedString theGuard1(executionContext);
XalanDOMString& digitGroupSepValue = theGuard1.get();
if (0 != m_groupingSeparator_avt)
m_groupingSeparator_avt->evaluate(digitGroupSepValue, contextNode,
*this, executionContext);
if (length(digitGroupSepValue) > 1)
{
executionContext.error(
"The grouping-separator value must be one character in length",
contextNode,
getLocator());
}
GetAndReleaseCachedString theGuard2(executionContext);
XalanDOMString& nDigitsPerGroupValue = theGuard2.get();
if (0 != m_groupingSize_avt)
m_groupingSize_avt->evaluate(nDigitsPerGroupValue, contextNode, *this,
executionContext);
// TODO: Handle digit-group attributes
// 7.7.1 If one is empty, it is ignored (numb81 conf test)
if(!isEmpty(digitGroupSepValue) && !isEmpty(nDigitsPerGroupValue))
{
formatter->setGroupingUsed(true);
formatter->setGroupingSeparator(digitGroupSepValue);
formatter->setGroupingSize(DOMStringToUnsignedLong(nDigitsPerGroupValue));
}
return formatter.release();
}
void
ElemNumber::formatNumberList(
StylesheetExecutionContext& executionContext,
const int theList[],
NodeRefListBase::size_type theListLength,
XalanNode* contextNode,
XalanDOMString& theResult) const
{
assert(theListLength > 0);
// Pathological cases
if (contextNode == 0) return;
XalanDOMChar numberType = XalanUnicode::charDigit_1;
XalanDOMString::size_type numberWidth = 1;
typedef vector<XalanDOMString> StringVectorType;
typedef StringVectorType::iterator StringVectorTypeIterator;
// Construct an array of tokens. We need to be able to check if the last
// token in non-alphabetic, in which case the penultimate non-alphabetic is
// the repeating separator.
//
// We should be able to replace this with a vector of the indexes in
// the evaluated string where the tokens start. But for now, this will
// have to do...
StringVectorType tokenVector;
{
typedef XPathExecutionContext::GetAndReleaseCachedString GetAndReleaseCachedString;
GetAndReleaseCachedString theGuard1(executionContext);
XalanDOMString& formatValue = theGuard1.get();
if (m_format_avt != 0)
{
m_format_avt->evaluate(formatValue, contextNode, *this, executionContext);
}
if(isEmpty(formatValue) == true)
{
formatValue = XalanUnicode::charDigit_1;
}
NumberFormatStringTokenizer formatTokenizer(formatValue);
const NumberFormatStringTokenizer::size_type theTokenCount = formatTokenizer.countTokens();
tokenVector.resize(theTokenCount);
// Tokenize directly into the vector...
for(NumberFormatStringTokenizer::size_type i = 0; i < theTokenCount; ++i)
{
formatTokenizer.nextToken(tokenVector[i]);
}
assert(theTokenCount == tokenVector.size());
}
// These are iterators which will either point to tokenVector.end(),
// or the appropriate string in the vector...
StringVectorTypeIterator leaderStrIt = tokenVector.end();
StringVectorTypeIterator trailerStrIt = leaderStrIt;
StringVectorTypeIterator sepStringIt = leaderStrIt;
const StringVectorTypeIterator endIt = leaderStrIt;
StringVectorTypeIterator it = tokenVector.begin();
const StringVectorType::size_type theVectorSize =
tokenVector.size();
if (theVectorSize > 0)
{
if(!isXMLLetterOrDigit(charAt(*it, 0)))
{
leaderStrIt = it;
// Move the iterator up one, so it
// points at the first numbering token...
++it;
}
if (theVectorSize > 1)
{
if(!isXMLLetterOrDigit(charAt(tokenVector.back(), 0)))
{
// Move the iterator back one, so it's pointing
// at the trailing string...
--trailerStrIt;
}
}
}
// Now we're left with a sequence of alpha,non-alpha tokens, format them
// with the corresponding entry in the format string, or the last one if no
// more matching ones
if (leaderStrIt != endIt)
{
theResult += *leaderStrIt;
}
typedef XPathExecutionContext::GetAndReleaseCachedString GetAndReleaseCachedString;
GetAndReleaseCachedString theGuard2(executionContext);
XalanDOMString& theIntermediateResult = theGuard2.get();
for(unsigned int i = 0; i < theListLength; i++)
{
if (it != trailerStrIt)
{
assert(isXMLLetterOrDigit(charAt(*it, 0)));
numberWidth = length(*it);
numberType = charAt(*it, numberWidth - 1);
++it;
}
if (it != trailerStrIt)
{
assert(!isXMLLetterOrDigit(charAt(*it, 0)));
sepStringIt = it;
++it;
}
getFormattedNumber(
executionContext,
contextNode,
numberType,
numberWidth,
theList[i],
theIntermediateResult);
theResult += theIntermediateResult;
// All but the last one
if (i < theListLength - 1)
{
if (sepStringIt != endIt)
{
theResult += *sepStringIt;
}
else
{
theResult += s_defaultSeparatorString;
}
clear(theIntermediateResult);
}
}
if (trailerStrIt != endIt)
{
theResult += *trailerStrIt;
}
}
void
ElemNumber::evaluateLetterValueAVT(
StylesheetExecutionContext& executionContext,
XalanNode* contextNode,
XalanDOMString& value) const
{
if (m_lettervalue_avt == 0)
{
clear(value);
}
else
{
m_lettervalue_avt->evaluate(
value,
contextNode,
*this,
executionContext);
}
}
void
ElemNumber::traditionalAlphaCount(
int theValue,
const XalanNumberingResourceBundle& theResourceBundle,
XalanDOMString& theResult) const
{
typedef XalanNumberingResourceBundle::IntVectorType IntVectorType;
typedef XalanNumberingResourceBundle::DigitsTableVectorType DigitsTableVectorType;
typedef XalanNumberingResourceBundle::eNumberingMethod eNumberingMethod;
typedef XalanNumberingResourceBundle::eMultiplierOrder eMultiplierOrder;
bool fError = false;
// if this number is larger than the largest number we can represent, error!
//if (val > theResourceBundle.getMaxNumericalValue())
//return XSLTErrorResources.ERROR_STRING;
XalanDOMCharVectorType table;
// index in table of the last character that we stored
IntVectorType::size_type lookupIndex = 1; // start off with anything other than zero to make correction work
// Create a buffer to hold the result
// TODO: size of the table can be determined by computing
// logs of the radix. For now, we fake it.
XalanDOMChar buf[100];
//some languages go left to right(ie. english), right to left (ie. Hebrew),
//top to bottom (ie.Japanese), etc... Handle them differently
//String orientation = thisBundle.getString(Constants.LANG_ORIENTATION);
// next character to set in the buffer
int charPos = 0;
// array of number groups: ie.1000, 100, 10, 1
const IntVectorType& groups = theResourceBundle.getNumberGroups();
const IntVectorType::size_type groupsSize = groups.size();
// array of tables of hundreds, tens, digits. Indexes into the vectors
// in the digits table.
const IntVectorType& tables = theResourceBundle.getDigitsTableTable();
const DigitsTableVectorType& digitsTable = theResourceBundle.getDigitsTable();
assert(tables.size() == digitsTable.size());
// some languages have additive alphabetical notation,
// some multiplicative-additive, etc... Handle them differently.
const eNumberingMethod numbering = theResourceBundle.getNumberingMethod();
// do multiplicative part first
if (numbering == XalanNumberingResourceBundle::eMultiplicativeAdditive)
{
const eMultiplierOrder mult_order = theResourceBundle.getMultiplierOrder();
const IntVectorType& multiplier = theResourceBundle.getMultipliers();
const IntVectorType::size_type multiplierSize = multiplier.size();
const XalanDOMCharVectorType& zeroChar = theResourceBundle.getZeroChar();
const XalanDOMCharVectorType::size_type zeroCharSize = zeroChar.size();
const XalanDOMCharVectorType& multiplierChars = theResourceBundle.getMultiplierChars();
IntVectorType::size_type i = 0;
// skip to correct multiplier
while (i < multiplierSize && theValue < multiplier[i])
{
i++;
}
do
{
if (i >= multiplierSize)
break; //number is smaller than multipliers
// some languages (ie chinese) put a zero character (and only one) when
// the multiplier is multiplied by zero. (ie, 1001 is 1X1000 + 0X100 + 0X10 + 1)
// 0X100 is replaced by the zero character, we don't need one for 0X10
if (theValue < multiplier[i])
{
if (zeroCharSize == 0)
{
i++;
}
else
{
if (buf[charPos - 1] != zeroChar[0])
{
buf[charPos++] = zeroChar[0];
}
i++;
}
}
else if (theValue >= multiplier[i])
{
int mult = theValue / multiplier[i];
theValue = theValue % multiplier[i]; // save this.
IntVectorType::size_type k = 0;
while (k < groupsSize)
{
lookupIndex = 1; // initialize for each table
if (mult / groups[k] <= 0) // look for right table
{
k++;
}
else
{
assert(digitsTable.size() > DigitsTableVectorType::size_type(tables[k]));
// get the table
const XalanDOMCharVectorType& THEletters =
digitsTable[tables[k]];
const XalanDOMCharVectorType::size_type THElettersSize =
THEletters.size();
table.resize(THElettersSize + 1);
const IntVectorType::size_type tableSize = table.size();
XalanDOMCharVectorType::size_type j = 0;
for (; j < THElettersSize; j++)
{
table[j + 1] = THEletters[j];
}
table[0] = THEletters[j - 1]; // don't need this
// index in "table" of the next char to emit
lookupIndex = mult / groups[k];
//this should not happen
if (lookupIndex == 0 && mult == 0)
{
break;
}
assert(i < multiplierChars.size());
const XalanDOMChar multiplierChar = multiplierChars[i];
// put out the next character of output
if (lookupIndex < tableSize)
{
if(mult_order == XalanNumberingResourceBundle::ePrecedes)
{
buf[charPos++] = multiplierChar;
buf[charPos++] = table[lookupIndex];
}
else
{
// don't put out 1 (ie 1X10 is just 10)
if (lookupIndex == 1 && i == multiplierSize - 1)
{
}
else
{
buf[charPos++] = table[lookupIndex];
}
buf[charPos++] = multiplierChar;
}
break; // all done!
}
else
{
fError = true;
break;
}
} //end else
} // end while
i++;
} // end else if
} // end do while
while (i < multiplierSize && fError == false);
}
// Now do additive part...
IntVectorType::size_type count = 0;
// do this for each table of hundreds, tens, digits...
while (count < groupsSize)
{
if (theValue / groups[count] <= 0)
{
// look for correct table
count++;
}
else
{
const XalanDOMCharVectorType& theletters =
digitsTable[tables[count]];
const XalanDOMCharVectorType::size_type thelettersSize =
theletters.size();
table.resize(thelettersSize + 1);
const IntVectorType::size_type tableSize = table.size();
XalanDOMCharVectorType::size_type j = 0;
// need to start filling the table up at index 1
for (; j < thelettersSize; j++)
{
table[j + 1] = theletters[j];
}
table[0] = theletters[j - 1]; // don't need this
// index in "table" of the next char to emit
lookupIndex = theValue / groups[count];
// shift input by one "column"
theValue = theValue % groups[count];
// this should not happen
if (lookupIndex == 0 && theValue == 0)
break;
if (lookupIndex < tableSize)
{
// put out the next character of output
buf[charPos++] = table[lookupIndex]; // left to right or top to bottom
}
else
{
fError = true;
break;
}
count++;
}
} // end while
if (fError == true)
{
theResult = XALAN_STATIC_UCODE_STRING("#error");
}
else
{
assign(theResult, buf, charPos);
}
}
const XalanDOMChar elalphaNumberType = 0x03B1;
void
ElemNumber::getFormattedNumber(
StylesheetExecutionContext& executionContext,
XalanNode* contextNode,
XalanDOMChar numberType,
XalanDOMString::size_type numberWidth,
int listElement,
XalanDOMString& theResult) const
{
switch(numberType)
{
case XalanUnicode::charLetter_A:
int2alphaCount(listElement, s_alphaCountTable, theResult);
break;
case XalanUnicode::charLetter_a:
int2alphaCount(listElement, s_alphaCountTable, theResult);
theResult = toLowerCaseASCII(theResult);
break;
case XalanUnicode::charLetter_I:
long2roman(executionContext, contextNode, listElement, true, theResult);
break;
case XalanUnicode::charLetter_i:
long2roman(executionContext, contextNode, listElement, true, theResult);
theResult = toLowerCaseASCII(theResult);
break;
case 0x3042:
case 0x3044:
case 0x30A2:
case 0x30A4:
case 0x4E00:
case 0x58F9:
case 0x0E51:
case 0x05D0:
case 0x10D0:
case 0x0430:
executionContext.error(
"Numbering format not supported yet",
contextNode,
getLocator());
break;
// Handle the special case of Greek letters for now
case elalphaNumberType:
{
// A string to hold the result.
StylesheetExecutionContext::GetAndReleaseCachedString theGuard(executionContext);
XalanDOMString& letterVal = theGuard.get();
evaluateLetterValueAVT(executionContext, contextNode, letterVal);
if (equals(letterVal, Constants::ATTRVAL_TRADITIONAL) == true)
{
NumberingResourceBundleMapType::const_iterator i = s_resourceBundles.find(0x03B1);
if (i != s_resourceBundles.end())
{
traditionalAlphaCount(listElement, (*i).second, theResult);
}
}
else if (equals(letterVal, Constants::ATTRVAL_ALPHABETIC) == true)
{
int2alphaCount(listElement, s_elalphaCountTable, theResult);
}
else
{
executionContext.error(
"The legal values for letter-value are 'alphabetic' and 'traditional'",
contextNode,
getLocator());
}
}
break;
default: // "1"
{
StylesheetExecutionContext::XalanNumberFormatAutoPtr formatter(
getNumberFormatter(executionContext, contextNode));
formatter->format(listElement, theResult);
const XalanDOMString::size_type lengthNumString = length(theResult);
if (numberWidth > lengthNumString)
{
const XalanDOMString::size_type nPadding = numberWidth - lengthNumString;
const XalanDOMString padString = formatter->format(0);
reserve(theResult, nPadding * length(padString) + lengthNumString + 1);
for(XalanDOMString::size_type i = 0; i < nPadding; i++)
{
insert(theResult, 0, padString);
}
}
}
break;
}
}
void
ElemNumber::int2singlealphaCount(
int val,
const XalanDOMString& table,
XalanDOMString& theResult)
{
assert(int(length(table)) == length(table));
const int radix = int(length(table));
// TODO: throw error on out of range input
if (val > radix)
{
theResult = XalanDOMString(XALAN_STATIC_UCODE_STRING("#E(") +
LongToDOMString(val) +
XALAN_STATIC_UCODE_STRING(")"));
}
else
{
const XalanDOMChar theChar = charAt(table, val - 1);
assign(theResult, &theChar, 1);
}
}
void
ElemNumber::int2alphaCount(
int val,
const XalanDOMString& table,
XalanDOMString& theResult)
{
assert(int(length(table)) == length(table));
const int radix = int(length(table));
// Create a buffer to hold the result
// TODO: size of the table can be determined by computing
// logs of the radix. For now, we fake it.
const int buflen = 100;
XalanDOMChar buf[buflen + 1];
#if defined(XALAN_STRICT_ANSI_HEADERS)
std::memset(buf, 0, (buflen + 1) * sizeof(XalanDOMChar));
#else
memset(buf, 0, (buflen + 1) * sizeof(XalanDOMChar));
#endif
// next character to set in the buffer
int charPos = buflen - 1 ; // work backward through buf[]
// index in table of the last character that we stored
int lookupIndex = 1; // start off with anything other than zero to make correction work
// Correction number
//
// Correction can take on exactly two values:
//
// 0 if the next character is to be emitted is usual
//
// radix - 1
// if the next char to be emitted should be one less than
// you would expect
//
// For example, consider radix 10, where 1="A" and 10="J"
//
// In this scheme, we count: A, B, C ... H, I, J (not A0 and certainly
// not AJ), A1
//
// So, how do we keep from emitting AJ for 10? After correctly emitting the
// J, lookupIndex is zero. We now compute a correction number of 9 (radix-1).
// In the following line, we'll compute (val+correction) % radix, which is,
// (val+9)/10. By this time, val is 1, so we compute (1+9) % 10, which
// is 10 % 10 or zero. So, we'll prepare to emit "JJ", but then we'll
// later suppress the leading J as representing zero (in the mod system,
// it can represent either 10 or zero). In summary, the correction value of
// "radix-1" acts like "-1" when run through the mod operator, but with the
// desireable characteristic that it never produces a negative number.
int correction = 0;
// TODO: throw error on out of range input
do
{
// most of the correction calculation is explained above, the reason for the
// term after the "|| " is that it correctly propagates carries across
// multiple columns.
correction = ((lookupIndex == 0) ||
(correction != 0 && lookupIndex == radix - 1 )) ? (radix - 1) : 0;
// index in "table" of the next char to emit
lookupIndex = (val + correction) % radix;
// shift input by one "column"
val = (val / radix);
// if the next value we'd put out would be a leading zero, we're done.
if (lookupIndex == 0 && val == 0)
break;
// put out the next character of output
buf[charPos--] = charAt(table, lookupIndex);
}
while (val > 0);
assign(theResult, buf + charPos + 1, buflen - charPos - 1);
}
void
ElemNumber::tradAlphaCount(
int /* val */,
XalanDOMString& /* theResult */)
{
// @@ JMD: We don't do languages yet, so this is just a placeholder
assert(false);
}
void
ElemNumber::long2roman(
StylesheetExecutionContext& executionContext,
XalanNode* contextNode,
long val,
bool prefixesAreOK,
XalanDOMString& theResult) const
{
if(val < 0)
{
executionContext.error(
"I and i can only format positive numbers",
contextNode,
getLocator());
}
else
{
long2roman(val, prefixesAreOK, theResult);
}
}
void
ElemNumber::long2roman(
long val,
bool prefixesAreOK,
XalanDOMString& theResult)
{
if(val < 0)
{
theResult = XalanDOMString(XALAN_STATIC_UCODE_STRING("#E(") +
LongToDOMString(val) +
XALAN_STATIC_UCODE_STRING(")"));
}
else if(val == 0)
{
theResult = XALAN_STATIC_UCODE_STRING("0");
}
else if (val <= 3999L)
{
clear(theResult);
int place = 0;
do
{
while (val >= s_romanConvertTable[place].m_postValue)
{
theResult += s_romanConvertTable[place].m_postLetter;
val -= s_romanConvertTable[place].m_postValue;
}
if (prefixesAreOK)
{
if (val >= s_romanConvertTable[place].m_preValue)
{
theResult += s_romanConvertTable[place].m_preLetter;
val -= s_romanConvertTable[place].m_preValue;
}
}
++place;
}
while (val > 0);
}
else
{
theResult = XALAN_STATIC_UCODE_STRING("#error");
}
}
ElemNumber::NumberFormatStringTokenizer::NumberFormatStringTokenizer(
const XalanDOMString& theString) :
m_currentPosition(0),
m_maxPosition(length(theString)),
m_string(&theString)
{
}
void
ElemNumber::NumberFormatStringTokenizer::setString(const XalanDOMString& theString)
{
m_string = &theString;
m_currentPosition = 0;
m_maxPosition = length(theString);
}
XalanDOMString
ElemNumber::NumberFormatStringTokenizer::nextToken()
{
if (m_currentPosition >= m_maxPosition)
{
return XalanDOMString();
}
const size_type start = m_currentPosition;
if (isXMLLetterOrDigit(charAt(*m_string, m_currentPosition)))
{
while (m_currentPosition < m_maxPosition &&
isXMLLetterOrDigit(charAt(*m_string, m_currentPosition)))
{
m_currentPosition++;
}
}
else
{
while (m_currentPosition < m_maxPosition &&
!isXMLLetterOrDigit(charAt(*m_string, m_currentPosition)))
{
m_currentPosition++;
}
}
return XalanDOMString(*m_string, start, m_currentPosition);
}
void
ElemNumber::NumberFormatStringTokenizer::nextToken(XalanDOMString& theToken)
{
if (m_currentPosition >= m_maxPosition)
{
clear(theToken);
}
const size_type start = m_currentPosition;
if (isXMLLetterOrDigit(charAt(*m_string, m_currentPosition)))
{
while (m_currentPosition < m_maxPosition &&
isXMLLetterOrDigit(charAt(*m_string, m_currentPosition)))
{
m_currentPosition++;
}
}
else
{
while (m_currentPosition < m_maxPosition &&
!isXMLLetterOrDigit(charAt(*m_string, m_currentPosition)))
{
m_currentPosition++;
}
}
substring(*m_string, theToken, start, m_currentPosition);
}
ElemNumber::NumberFormatStringTokenizer::size_type
ElemNumber::NumberFormatStringTokenizer::countTokens() const
{
size_type count = 0;
size_type currpos = m_currentPosition;
// Tokens consist of sequences of alphabetic characters and sequences of
// non-alphabetic characters
while (currpos < m_maxPosition)
{
if (isXMLLetterOrDigit(charAt(*m_string, currpos)))
{
while (currpos < m_maxPosition &&
isXMLLetterOrDigit(charAt(*m_string, currpos)))
{
currpos++;
}
}
else
{
while (currpos < m_maxPosition &&
!isXMLLetterOrDigit(charAt(*m_string, currpos)))
{
currpos++;
}
}
count++;
}
return count;
}
static const XalanDOMChar alphaCountTable[] =
{
XalanUnicode::charLetter_Z,
XalanUnicode::charLetter_A,
XalanUnicode::charLetter_B,
XalanUnicode::charLetter_C,
XalanUnicode::charLetter_D,
XalanUnicode::charLetter_E,
XalanUnicode::charLetter_F,
XalanUnicode::charLetter_G,
XalanUnicode::charLetter_H,
XalanUnicode::charLetter_I,
XalanUnicode::charLetter_J,
XalanUnicode::charLetter_K,
XalanUnicode::charLetter_L,
XalanUnicode::charLetter_M,
XalanUnicode::charLetter_N,
XalanUnicode::charLetter_O,
XalanUnicode::charLetter_P,
XalanUnicode::charLetter_Q,
XalanUnicode::charLetter_R,
XalanUnicode::charLetter_S,
XalanUnicode::charLetter_T,
XalanUnicode::charLetter_U,
XalanUnicode::charLetter_V,
XalanUnicode::charLetter_W,
XalanUnicode::charLetter_X,
XalanUnicode::charLetter_Y,
0
};
static const XalanDOMChar elalphaCountTable[] =
{
0x03c9,
0x03b1,
0x03b2,
0x03b3,
0x03b4,
0x03b5,
0x03b6,
0x03b7,
0x03b8,
0x03b9,
0x03ba,
0x03bb,
0x03bc,
0x03bd,
0x03be,
0x03bf,
0x03c0,
0x03c1,
0x03c2,
0x03c3,
0x03c4,
0x03c5,
0x03c6,
0x03c7,
0x03c8,
0
};
static XalanDOMString s_atString;
static XalanDOMString s_textString;
static XalanDOMString s_commentString;
static XalanDOMString s_slashString;
static XalanDOMString s_piString;
static XalanDOMString s_leftParenString;
static XalanDOMString s_dotString;
static XalanDOMString s_oneString;
static XalanDOMString s_defaultSeparatorString;
static XalanDOMString s_alphaCountTable;
static XalanDOMString s_elalphaCountTable;
static ElemNumber::DecimalToRomanVectorType s_romanConvertTable;
static ElemNumber::NumberingResourceBundleMapType s_resourceBundles;
const XalanDOMString& ElemNumber::s_atString = ::s_atString;
const XalanDOMString& ElemNumber::s_textString = ::s_textString;
const XalanDOMString& ElemNumber::s_commentString = ::s_commentString;
const XalanDOMString& ElemNumber::s_slashString = ::s_slashString;
const XalanDOMString& ElemNumber::s_piString = ::s_piString;
const XalanDOMString& ElemNumber::s_leftParenString = ::s_leftParenString;
const XalanDOMString& ElemNumber::s_dotString = ::s_dotString;
const XalanDOMString& ElemNumber::s_oneString = ::s_oneString;
const XalanDOMString& ElemNumber::s_defaultSeparatorString = ::s_defaultSeparatorString;
const XalanDOMString& ElemNumber::s_alphaCountTable = ::s_alphaCountTable;
const XalanDOMString& ElemNumber::s_elalphaCountTable = ::s_elalphaCountTable;
const ElemNumber::DecimalToRomanVectorType& ElemNumber::s_romanConvertTable =
::s_romanConvertTable;
const ElemNumber::NumberingResourceBundleMapType& ElemNumber::s_resourceBundles =
::s_resourceBundles;
static void
addTraditionalElalphaBundle(ElemNumber::NumberingResourceBundleMapType& theBundleMap)
{
// The following are a bunch of static data the comprise the contents of the bundle.
static const XalanDOMChar elalphaAlphabet[] =
{
0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8,
0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0,
0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8,
0x03c9, 0
};
static const XalanDOMChar elalphaTraditionalAlphabet[] =
{
XalanUnicode::charLetter_A, XalanUnicode::charLetter_B, XalanUnicode::charLetter_C,
XalanUnicode::charLetter_D, XalanUnicode::charLetter_E, XalanUnicode::charLetter_F,
XalanUnicode::charLetter_G, XalanUnicode::charLetter_H, XalanUnicode::charLetter_I,
XalanUnicode::charLetter_J, XalanUnicode::charLetter_K, XalanUnicode::charLetter_L,
XalanUnicode::charLetter_M, XalanUnicode::charLetter_N, XalanUnicode::charLetter_O,
XalanUnicode::charLetter_P, XalanUnicode::charLetter_Q, XalanUnicode::charLetter_R,
XalanUnicode::charLetter_S, XalanUnicode::charLetter_T, XalanUnicode::charLetter_U,
XalanUnicode::charLetter_V, XalanUnicode::charLetter_W, XalanUnicode::charLetter_X,
XalanUnicode::charLetter_Y, XalanUnicode::charLetter_Z, 0
};
static const int elalphaNumberGroups[] =
{
100, 10, 1
};
const size_t elalphaNumberGroupsCount = sizeof(elalphaNumberGroups) / sizeof(int);
static const int elalphaMultipliers[] = { 1000 };
const size_t elalphaMultipliersCount = sizeof(elalphaMultipliers) / sizeof(int);
static const XalanDOMChar elalphaMultiplierChars[] = { 0x03d9, 0 };
static const XalanDOMChar elalphaDigits[] =
{
0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03db, 0x03b6, 0x03b7, 0x03b8, 0
};
static const XalanDOMChar elalphaTens[] =
{
0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0, 0x03df, 0
};
static const XalanDOMChar elalphaHundreds[] =
{
0x03c1, 0x03c2, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03e1, 0
};
typedef XalanNumberingResourceBundle::DigitsTableVectorType DigitsTableVectorType;
typedef XalanNumberingResourceBundle::IntVectorType IntVectorType;
// Create the table of characters for the various digit positions...
DigitsTableVectorType theElalphaDigitsTable;
// Since we know the size, create the empty vectors in the table...
theElalphaDigitsTable.resize(3);
// Swap the empty tables with temporary ones...
XalanDOMCharVectorType(elalphaDigits, elalphaDigits + length(elalphaDigits)).swap(theElalphaDigitsTable[0]);
XalanDOMCharVectorType(elalphaTens, elalphaTens + length(elalphaTens)).swap(theElalphaDigitsTable[1]);
XalanDOMCharVectorType(elalphaHundreds, elalphaHundreds + length(elalphaHundreds)).swap(theElalphaDigitsTable[2]);
// This table will indicate which positions the vectors of digits are in
// the table...
IntVectorType theDigitsTableTable;
theDigitsTableTable.reserve(3);
// Push the positions on in reverse order, since that's how things work...
theDigitsTableTable.push_back(2);
theDigitsTableTable.push_back(1);
theDigitsTableTable.push_back(0);
const XalanDOMString theLanguageString("el");
const XalanNumberingResourceBundle theElaphaBundle(
theLanguageString,
theLanguageString,
theLanguageString,
XalanDOMCharVectorType(elalphaAlphabet, elalphaAlphabet + length(elalphaAlphabet)),
XalanDOMCharVectorType(elalphaTraditionalAlphabet, elalphaTraditionalAlphabet + length(elalphaTraditionalAlphabet)),
XalanNumberingResourceBundle::eLeftToRight,
XalanNumberingResourceBundle::eMultiplicativeAdditive,
XalanNumberingResourceBundle::ePrecedes,
~0,
IntVectorType(elalphaNumberGroups, elalphaNumberGroups + elalphaNumberGroupsCount),
IntVectorType(elalphaMultipliers, elalphaMultipliers + elalphaMultipliersCount),
XalanDOMCharVectorType(),
XalanDOMCharVectorType(elalphaMultiplierChars, elalphaMultiplierChars + length(elalphaMultiplierChars)),
theElalphaDigitsTable,
theDigitsTableTable);
typedef ElemNumber::NumberingResourceBundleMapType::value_type value_type;
theBundleMap[elalphaNumberType] = theElaphaBundle;
}
void
ElemNumber::initialize()
{
::s_atString = XALAN_STATIC_UCODE_STRING("@");
::s_textString = XALAN_STATIC_UCODE_STRING("text()");
::s_commentString = XALAN_STATIC_UCODE_STRING("comment()");
::s_slashString = XALAN_STATIC_UCODE_STRING("/");
::s_piString = XALAN_STATIC_UCODE_STRING("pi(");
::s_leftParenString = XALAN_STATIC_UCODE_STRING(")");
::s_dotString = XALAN_STATIC_UCODE_STRING(".");
::s_oneString = XALAN_STATIC_UCODE_STRING("1");
::s_defaultSeparatorString = XALAN_STATIC_UCODE_STRING(".");
::s_alphaCountTable = alphaCountTable;
::s_elalphaCountTable = elalphaCountTable;
::s_romanConvertTable.reserve(7);
::s_romanConvertTable.push_back(
DecimalToRoman(
1000L,
StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("M")),
900L,
StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("CM"))));
::s_romanConvertTable.push_back(
DecimalToRoman(
500L,
StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("D")),
400,
StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("CD"))));
::s_romanConvertTable.push_back(
DecimalToRoman(
100L,
StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("C")),
90L,
StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("XC"))));
::s_romanConvertTable.push_back(
DecimalToRoman(
50L,
StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("L")),
40L,
StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("XL"))));
::s_romanConvertTable.push_back(
DecimalToRoman(
10L,
StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("X")),
9L,
StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("IX"))));
::s_romanConvertTable.push_back(
DecimalToRoman(
5L,
StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("V")),
4L,
StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("IV"))));
::s_romanConvertTable.push_back(
DecimalToRoman(
1L,
StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("I")),
1L,
StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("I"))));
addTraditionalElalphaBundle(::s_resourceBundles);
}
void
ElemNumber::terminate()
{
releaseMemory(::s_atString);
releaseMemory(::s_textString);
releaseMemory(::s_commentString);
releaseMemory(::s_slashString);
releaseMemory(::s_piString);
releaseMemory(::s_leftParenString);
releaseMemory(::s_dotString);
releaseMemory(::s_oneString);
releaseMemory(::s_defaultSeparatorString);
releaseMemory(::s_alphaCountTable);
releaseMemory(::s_elalphaCountTable);
DecimalToRomanVectorType().swap(::s_romanConvertTable);
NumberingResourceBundleMapType().swap(::s_resourceBundles);
}