/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (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.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * $Id$
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <string.h>
#include <xercesc/util/EmptyStackException.hpp>
#include <xercesc/util/NoSuchElementException.hpp>
#include <xercesc/framework/XMLElementDecl.hpp>
#include <xercesc/internal/ElemStack.hpp>
#include <xercesc/validators/common/Grammar.hpp>

XERCES_CPP_NAMESPACE_BEGIN

// ---------------------------------------------------------------------------
//  ElemStack: Constructors and Destructor
// ---------------------------------------------------------------------------
ElemStack::ElemStack(MemoryManager* const manager) :

    fEmptyNamespaceId(0)
    , fGlobalPoolId(0)
    , fPrefixPool(109, manager)
    , fGlobalNamespaces(0)
    , fStack(0)
    , fStackCapacity(32)
    , fStackTop(0)
    , fUnknownNamespaceId(0)
    , fXMLNamespaceId(0)
    , fXMLPoolId(0)
    , fXMLNSNamespaceId(0)
    , fXMLNSPoolId(0)
    , fNamespaceMap(0)
    , fMemoryManager(manager)
{
    // Do an initial allocation of the stack and zero it out
    fStack = (StackElem**) fMemoryManager->allocate
    (
        fStackCapacity * sizeof(StackElem*)
    );//new StackElem*[fStackCapacity];
    memset(fStack, 0, fStackCapacity * sizeof(StackElem*));

    fNamespaceMap = new (fMemoryManager) ValueVectorOf<PrefMapElem*>(16, fMemoryManager);
}

ElemStack::~ElemStack()
{
    if(fGlobalNamespaces)
    {
        fMemoryManager->deallocate(fGlobalNamespaces->fMap);
        delete fGlobalNamespaces;
    }

    //
    //  Start working from the bottom of the stack and clear it out as we
    //  go up. Once we hit an uninitialized one, we can break out.
    //
    for (XMLSize_t stackInd = 0; stackInd < fStackCapacity; stackInd++)
    {
        // If this entry has been set, then lets clean it up
        if (!fStack[stackInd])
            break;

        fMemoryManager->deallocate(fStack[stackInd]->fChildren);//delete [] fStack[stackInd]->fChildren;
        fMemoryManager->deallocate(fStack[stackInd]->fMap);//delete [] fStack[stackInd]->fMap;
        fMemoryManager->deallocate(fStack[stackInd]->fSchemaElemName);
        delete fStack[stackInd];
    }

    // Delete the stack array itself now
    fMemoryManager->deallocate(fStack);//delete [] fStack;
    delete fNamespaceMap;
}


// ---------------------------------------------------------------------------
//  ElemStack: Stack access
// ---------------------------------------------------------------------------
XMLSize_t ElemStack::addLevel()
{
    // See if we need to expand the stack
    if (fStackTop == fStackCapacity)
        expandStack();

    // If this element has not been initialized yet, then initialize it
    if (!fStack[fStackTop])
    {
        fStack[fStackTop] = new (fMemoryManager) StackElem;
        fStack[fStackTop]->fChildCapacity = 0;
        fStack[fStackTop]->fChildren = 0;
        fStack[fStackTop]->fMapCapacity = 0;
        fStack[fStackTop]->fMap = 0;
        fStack[fStackTop]->fSchemaElemName = 0;
        fStack[fStackTop]->fSchemaElemNameMaxLen = 0;
    }

    // Set up the new top row
    fStack[fStackTop]->fThisElement = 0;
    fStack[fStackTop]->fReaderNum = 0xFFFFFFFF;
    fStack[fStackTop]->fChildCount = 0;
    fStack[fStackTop]->fMapCount = 0;
    fStack[fStackTop]->fValidationFlag = false;
    fStack[fStackTop]->fCommentOrPISeen = false;
    fStack[fStackTop]->fReferenceEscaped = false;
    fStack[fStackTop]->fCurrentURI = fUnknownNamespaceId;
    fStack[fStackTop]->fCurrentScope = Grammar::TOP_LEVEL_SCOPE;
    fStack[fStackTop]->fCurrentGrammar = 0;

    // Bump the top of stack
    fStackTop++;

    return fStackTop-1;
}


XMLSize_t ElemStack::addLevel(XMLElementDecl* const toSet, const XMLSize_t readerNum)
{
    // See if we need to expand the stack
    if (fStackTop == fStackCapacity)
        expandStack();

    // If this element has not been initialized yet, then initialize it
    if (!fStack[fStackTop])
    {
        fStack[fStackTop] = new (fMemoryManager) StackElem;
        fStack[fStackTop]->fChildCapacity = 0;
        fStack[fStackTop]->fChildren = 0;
        fStack[fStackTop]->fMapCapacity = 0;
        fStack[fStackTop]->fMap = 0;
        fStack[fStackTop]->fSchemaElemName = 0;
        fStack[fStackTop]->fSchemaElemNameMaxLen = 0;
    }

    // Set up the new top row
    fStack[fStackTop]->fThisElement = toSet;
    fStack[fStackTop]->fReaderNum = readerNum;
    fStack[fStackTop]->fChildCount = 0;
    fStack[fStackTop]->fMapCount = 0;
    fStack[fStackTop]->fValidationFlag = false;
    fStack[fStackTop]->fCommentOrPISeen = false;
    fStack[fStackTop]->fReferenceEscaped = false;
    fStack[fStackTop]->fCurrentURI = fUnknownNamespaceId;
    fStack[fStackTop]->fCurrentScope = Grammar::TOP_LEVEL_SCOPE;
    fStack[fStackTop]->fCurrentGrammar = 0;

    // Bump the top of stack
    fStackTop++;

    return fStackTop-1;
}



const ElemStack::StackElem* ElemStack::popTop()
{
    // Watch for an underflow error
    if (!fStackTop)
        ThrowXMLwithMemMgr(EmptyStackException, XMLExcepts::ElemStack_StackUnderflow, fMemoryManager);

    fStackTop--;
    return fStack[fStackTop];
}


void
ElemStack::setElement(XMLElementDecl* const toSet, const XMLSize_t readerNum)
{
    if (!fStackTop)
        ThrowXMLwithMemMgr(EmptyStackException, XMLExcepts::ElemStack_EmptyStack, fMemoryManager);

    fStack[fStackTop - 1]->fThisElement = toSet;
    fStack[fStackTop - 1]->fReaderNum = readerNum;
}


// ---------------------------------------------------------------------------
//  ElemStack: Stack top access
// ---------------------------------------------------------------------------
XMLSize_t ElemStack::addChild(QName* const child, const bool toParent)
{
    if (!fStackTop)
        ThrowXMLwithMemMgr(EmptyStackException, XMLExcepts::ElemStack_EmptyStack, fMemoryManager);

    //
    //  If they want to add to the parent, then we have to have at least two
    //  elements on the stack.
    //
    if (toParent && (fStackTop < 2))
        ThrowXMLwithMemMgr(NoSuchElementException, XMLExcepts::ElemStack_NoParentPushed, fMemoryManager);

    // Get a convenience pointer to the stack top row
    StackElem* curRow = toParent
                        ? fStack[fStackTop - 2] : fStack[fStackTop - 1];

    // See if we need to expand this row's child array
    if (curRow->fChildCount == curRow->fChildCapacity)
    {
        // Increase the capacity by a quarter and allocate a new row
        const XMLSize_t newCapacity = curRow->fChildCapacity ?
                                      (XMLSize_t)(curRow->fChildCapacity * 1.25) :
                                      32;
        QName** newRow = (QName**) fMemoryManager->allocate
        (
            newCapacity * sizeof(QName*)
        );//new QName*[newCapacity];

        //
        //  Copy over the old contents. We don't have to initialize the new
        //  part because The current child count is used to know how much of
        //  it is valid.
        //
        //  Only both doing this if there is any current content, since
        //  this code also does the initial faulting in of the array when
        //  both the current capacity and child count are zero.
        //
        for (XMLSize_t index = 0; index < curRow->fChildCount; index++)
            newRow[index] = curRow->fChildren[index];

        // Clean up the old children and store the new info
        fMemoryManager->deallocate(curRow->fChildren);//delete [] curRow->fChildren;
        curRow->fChildren = newRow;
        curRow->fChildCapacity = newCapacity;
    }

    // Add this id to the end of the row's child id array and bump the count
    curRow->fChildren[curRow->fChildCount++] = child;

    // Return the level of the index we just filled (before the bump)
    return curRow->fChildCount - 1;
}

const ElemStack::StackElem* ElemStack::topElement() const
{
    if (!fStackTop)
        ThrowXMLwithMemMgr(EmptyStackException, XMLExcepts::ElemStack_EmptyStack, fMemoryManager);

    return fStack[fStackTop - 1];
}


// ---------------------------------------------------------------------------
//  ElemStack: Prefix map methods
// ---------------------------------------------------------------------------
void ElemStack::addGlobalPrefix(const XMLCh* const    prefixToAdd
                              , const unsigned int    uriId)
{
    if (!fGlobalNamespaces)
    {
        fGlobalNamespaces = new (fMemoryManager) StackElem;
        fGlobalNamespaces->fChildCapacity = 0;
        fGlobalNamespaces->fChildren = 0;
        fGlobalNamespaces->fMapCapacity = 0;
        fGlobalNamespaces->fMap = 0;
        fGlobalNamespaces->fMapCount = 0;
        fGlobalNamespaces->fSchemaElemName = 0;
        fGlobalNamespaces->fSchemaElemNameMaxLen = 0;
        fGlobalNamespaces->fThisElement = 0;
        fGlobalNamespaces->fReaderNum = 0xFFFFFFFF;
        fGlobalNamespaces->fChildCount = 0;
        fGlobalNamespaces->fValidationFlag = false;
        fGlobalNamespaces->fCommentOrPISeen = false;
        fGlobalNamespaces->fReferenceEscaped = false;
        fGlobalNamespaces->fCurrentURI = fUnknownNamespaceId;
        fGlobalNamespaces->fCurrentScope = Grammar::TOP_LEVEL_SCOPE;
        fGlobalNamespaces->fCurrentGrammar = 0;
    }

    // Map the prefix to its unique id
    const unsigned int prefId = fPrefixPool.addOrFind(prefixToAdd);

    //
    //  Add a new element to the prefix map for this element. If its full,
    //  then expand it out.
    //
    if (fGlobalNamespaces->fMapCount == fGlobalNamespaces->fMapCapacity)
        expandMap(fGlobalNamespaces);

    //
    //  And now add a new element for this prefix. Watch for the special case
    //  of xmlns=="", and force it to ""=[globalid]
    //
    fGlobalNamespaces->fMap[fGlobalNamespaces->fMapCount].fPrefId = prefId;
    if ((prefId == fGlobalPoolId) && (uriId == fEmptyNamespaceId))
        fGlobalNamespaces->fMap[fGlobalNamespaces->fMapCount].fURIId = fEmptyNamespaceId;
    else
        fGlobalNamespaces->fMap[fGlobalNamespaces->fMapCount].fURIId = uriId;

    // Bump the map count now
    fGlobalNamespaces->fMapCount++;
}

void ElemStack::addPrefix(  const   XMLCh* const    prefixToAdd
                            , const unsigned int    uriId)
{
    if (!fStackTop)
        ThrowXMLwithMemMgr(EmptyStackException, XMLExcepts::ElemStack_EmptyStack, fMemoryManager);

    // Get a convenience pointer to the stack top row
    StackElem* curRow = fStack[fStackTop - 1];

    // Map the prefix to its unique id
    const unsigned int prefId = fPrefixPool.addOrFind(prefixToAdd);

    //
    //  Add a new element to the prefix map for this element. If its full,
    //  then expand it out.
    //
    if (curRow->fMapCount == curRow->fMapCapacity)
        expandMap(curRow);

    //
    //  And now add a new element for this prefix. Watch for the special case
    //  of xmlns=="", and force it to ""=[globalid]
    //
    curRow->fMap[curRow->fMapCount].fPrefId = prefId;
    if ((prefId == fGlobalPoolId) && (uriId == fEmptyNamespaceId))
        curRow->fMap[curRow->fMapCount].fURIId = fEmptyNamespaceId;
    else
        curRow->fMap[curRow->fMapCount].fURIId = uriId;

    // Bump the map count now
    curRow->fMapCount++;
}


unsigned int ElemStack::mapPrefixToURI( const   XMLCh* const    prefixToMap
                                        ,       bool&           unknown) const
{
    // Assume we find it
    unknown = false;

    //
    //  Map the prefix to its unique id, from the prefix string pool. If its
    //  not a valid prefix, then its a failure.
    //
    unsigned int prefixId = (!prefixToMap || !*prefixToMap)?fGlobalPoolId : fPrefixPool.getId(prefixToMap);
    if (prefixId == 0)
    {
        unknown = true;
        return fUnknownNamespaceId;
    }
    //
    //  Check for the special prefixes 'xml' and 'xmlns' since they cannot
    //  be overridden.
    //
    else if (prefixId == fXMLPoolId)
        return fXMLNamespaceId;
    else if (prefixId == fXMLNSPoolId)
        return fXMLNSNamespaceId;

    //
    //  Start at the stack top and work backwards until we come to some
    //  element that mapped this prefix.
    //
    for (XMLSize_t index = fStackTop; index > 0; index--)
    {
        // Get a convenience pointer to the current element
        StackElem* curRow = fStack[index-1];

        // Search the map at this level for the passed prefix
        for (XMLSize_t mapIndex = 0; mapIndex < curRow->fMapCount; mapIndex++)
        {
            if (curRow->fMap[mapIndex].fPrefId == prefixId)
                return curRow->fMap[mapIndex].fURIId;
        }
    }
    //  If the prefix wasn't found, try in the global namespaces
    if(fGlobalNamespaces)
    {
        for (XMLSize_t mapIndex = 0; mapIndex < fGlobalNamespaces->fMapCount; mapIndex++)
        {
            if (fGlobalNamespaces->fMap[mapIndex].fPrefId == prefixId)
                return fGlobalNamespaces->fMap[mapIndex].fURIId;
        }
    }

    //
    //  If the prefix is an empty string, then we will return the special
    //  global namespace id. This can be overridden, but no one has or we
    //  would have not gotten here.
    //
    if (!*prefixToMap)
        return fEmptyNamespaceId;

    // Oh well, don't have a clue so return the unknown id
    unknown = true;
    return fUnknownNamespaceId;
}


ValueVectorOf<PrefMapElem*>* ElemStack::getNamespaceMap() const
{
    fNamespaceMap->removeAllElements();

    //  Start at the stack top and work backwards until we come to some
    //  element that mapped this prefix.
    for (XMLSize_t index = fStackTop; index > 0; index--)
    {
        // Get a convenience pointer to the current element
        StackElem* curRow = fStack[index-1];

        // If no prefixes mapped at this level, then go the next one
        if (!curRow->fMapCount)
            continue;

        // Search the map at this level for the passed prefix
        for (XMLSize_t mapIndex = 0; mapIndex < curRow->fMapCount; mapIndex++)
            fNamespaceMap->addElement(&(curRow->fMap[mapIndex]));
    }
    //  Add the global namespaces
    if(fGlobalNamespaces)
    {
        for (XMLSize_t mapIndex = 0; mapIndex < fGlobalNamespaces->fMapCount; mapIndex++)
            fNamespaceMap->addElement(&(fGlobalNamespaces->fMap[mapIndex]));
    }

    return fNamespaceMap;
}

// ---------------------------------------------------------------------------
//  ElemStack: Miscellaneous methods
// ---------------------------------------------------------------------------
void ElemStack::reset(  const   unsigned int    emptyId
                        , const unsigned int    unknownId
                        , const unsigned int    xmlId
                        , const unsigned int    xmlNSId)
{
    if(fGlobalNamespaces)
    {
        fMemoryManager->deallocate(fGlobalNamespaces->fMap);
        delete fGlobalNamespaces;
        fGlobalNamespaces = 0;
    }

    // Reset the stack top to clear the stack
    fStackTop = 0;

    // if first time, put in the standard prefixes
    if (fXMLPoolId == 0) {

        fGlobalPoolId = fPrefixPool.addOrFind(XMLUni::fgZeroLenString);
        fXMLPoolId = fPrefixPool.addOrFind(XMLUni::fgXMLString);
        fXMLNSPoolId = fPrefixPool.addOrFind(XMLUni::fgXMLNSString);
    }

    // And store the new special URI ids
    fEmptyNamespaceId = emptyId;
    fUnknownNamespaceId = unknownId;
    fXMLNamespaceId = xmlId;
    fXMLNSNamespaceId = xmlNSId;
}


// ---------------------------------------------------------------------------
//  ElemStack: Private helpers
// ---------------------------------------------------------------------------
void ElemStack::expandMap(StackElem* const toExpand)
{
    // For convenience get the old map size
    const XMLSize_t oldCap = toExpand->fMapCapacity;

    //
    //  Expand the capacity by 25%, or initialize it to 16 if its currently
    //  empty. Then allocate a new temp buffer.
    //
    const XMLSize_t  newCapacity = oldCap ?
                                     (XMLSize_t )(oldCap * 1.25) : 16;
    PrefMapElem* newMap = (PrefMapElem*) fMemoryManager->allocate
    (
        newCapacity * sizeof(PrefMapElem)
    );//new PrefMapElem[newCapacity];

    //
    //  Copy over the old stuff. We DON'T have to zero out the new stuff
    //  since this is a by value map and the current map index controls what
    //  is relevant.
    //
    memcpy(newMap, toExpand->fMap, oldCap * sizeof(PrefMapElem));

    // Delete the old map and store the new stuff
    fMemoryManager->deallocate(toExpand->fMap);//delete [] toExpand->fMap;
    toExpand->fMap = newMap;
    toExpand->fMapCapacity = newCapacity;
}

void ElemStack::expandStack()
{
    // Expand the capacity by 25% and allocate a new buffer
    const XMLSize_t newCapacity = (XMLSize_t)(fStackCapacity * 1.25);
    StackElem** newStack = (StackElem**) fMemoryManager->allocate
    (
        newCapacity * sizeof(StackElem*)
    );//new StackElem*[newCapacity];

    // Copy over the old stuff
    memcpy(newStack, fStack, fStackCapacity * sizeof(StackElem*));

    //
    //  And zero out the new stuff. Though we use a stack top, we reuse old
    //  stack contents so we need to know if elements have been initially
    //  allocated or not as we push new stuff onto the stack.
    //
    memset
    (
        &newStack[fStackCapacity]
        , 0
        , (newCapacity - fStackCapacity) * sizeof(StackElem*)
    );

    // Delete the old array and update our members
    fMemoryManager->deallocate(fStack);//delete [] fStack;
    fStack = newStack;
    fStackCapacity = newCapacity;
}



// ---------------------------------------------------------------------------
//  WFElemStack: Constructors and Destructor
// ---------------------------------------------------------------------------
WFElemStack::WFElemStack(MemoryManager* const manager) :

    fEmptyNamespaceId(0)
    , fGlobalPoolId(0)
    , fStackCapacity(32)
    , fStackTop(0)
    , fUnknownNamespaceId(0)
    , fXMLNamespaceId(0)
    , fXMLPoolId(0)
    , fXMLNSNamespaceId(0)
    , fXMLNSPoolId(0)
    , fMapCapacity(0)
    , fMap(0)
    , fStack(0)
    , fPrefixPool(109, manager)
    , fMemoryManager(manager)
{
    // Do an initial allocation of the stack and zero it out
    fStack = (StackElem**) fMemoryManager->allocate
    (
        fStackCapacity * sizeof(StackElem*)
    );//new StackElem*[fStackCapacity];
    memset(fStack, 0, fStackCapacity * sizeof(StackElem*));
}

WFElemStack::~WFElemStack()
{
    //
    //  Start working from the bottom of the stack and clear it out as we
    //  go up. Once we hit an uninitialized one, we can break out.
    //
    for (XMLSize_t stackInd = 0; stackInd < fStackCapacity; stackInd++)
    {
        // If this entry has been set, then lets clean it up
        if (!fStack[stackInd])
            break;

        fMemoryManager->deallocate(fStack[stackInd]->fThisElement);//delete [] fStack[stackInd]->fThisElement;
        delete fStack[stackInd];
    }

    if (fMap)
        fMemoryManager->deallocate(fMap);//delete [] fMap;

    // Delete the stack array itself now
    fMemoryManager->deallocate(fStack);//delete [] fStack;
}


// ---------------------------------------------------------------------------
//  WFElemStack: Stack access
// ---------------------------------------------------------------------------
XMLSize_t WFElemStack::addLevel()
{
    // See if we need to expand the stack
    if (fStackTop == fStackCapacity)
        expandStack();

    
    // If this element has not been initialized yet, then initialize it
    if (!fStack[fStackTop])
    {
        fStack[fStackTop] = new (fMemoryManager) StackElem;
        fStack[fStackTop]->fThisElement = 0;
        fStack[fStackTop]->fElemMaxLength = 0;
    }

    // Set up the new top row
    fStack[fStackTop]->fReaderNum = 0xFFFFFFFF;
    fStack[fStackTop]->fCurrentURI = fUnknownNamespaceId;
    fStack[fStackTop]->fTopPrefix = -1;

    if (fStackTop != 0)
        fStack[fStackTop]->fTopPrefix = fStack[fStackTop - 1]->fTopPrefix;

    // Bump the top of stack
    fStackTop++;

    return fStackTop-1;
}


XMLSize_t
WFElemStack::addLevel(const XMLCh* const toSet,
                      const unsigned int toSetLen,
                      const unsigned int readerNum)
{
    // See if we need to expand the stack
    if (fStackTop == fStackCapacity)
        expandStack();

    // If this element has not been initialized yet, then initialize it
    if (!fStack[fStackTop])
    {
        fStack[fStackTop] = new (fMemoryManager) StackElem;
        fStack[fStackTop]->fThisElement = 0;
        fStack[fStackTop]->fElemMaxLength = 0;
    }

    // Set up the new top row
    fStack[fStackTop]->fCurrentURI = fUnknownNamespaceId;
    fStack[fStackTop]->fTopPrefix = -1;

    // And store the new stuff
    if (toSetLen > fStack[fStackTop]->fElemMaxLength) {

        fMemoryManager->deallocate(fStack[fStackTop]->fThisElement);//delete [] fStack[fStackTop]->fThisElement;
        fStack[fStackTop]->fElemMaxLength = toSetLen;
        fStack[fStackTop]->fThisElement = (XMLCh*) fMemoryManager->allocate
        (
            (toSetLen + 1) * sizeof(XMLCh)
        );//new XMLCh[toSetLen + 1];
    }

    XMLString::moveChars(fStack[fStackTop]->fThisElement, toSet, toSetLen + 1);
    fStack[fStackTop]->fReaderNum = readerNum;

    if (fStackTop != 0)
        fStack[fStackTop]->fTopPrefix = fStack[fStackTop - 1]->fTopPrefix;

    // Bump the top of stack
    fStackTop++;

    return fStackTop-1;
}



const WFElemStack::StackElem* WFElemStack::popTop()
{
    // Watch for an underflow error
    if (!fStackTop)
        ThrowXMLwithMemMgr(EmptyStackException, XMLExcepts::ElemStack_StackUnderflow, fMemoryManager);

    fStackTop--;
    return fStack[fStackTop];
}


void
WFElemStack::setElement(const XMLCh* const toSet,
                      const unsigned int toSetLen,
                      const unsigned int readerNum)
{
    if (!fStackTop)
        ThrowXMLwithMemMgr(EmptyStackException, XMLExcepts::ElemStack_EmptyStack, fMemoryManager);

    if (toSetLen > fStack[fStackTop - 1]->fElemMaxLength) {

        fMemoryManager->deallocate(fStack[fStackTop - 1]->fThisElement);//delete [] fStack[fStackTop - 1]->fThisElement;
        fStack[fStackTop - 1]->fElemMaxLength = toSetLen;
        fStack[fStackTop - 1]->fThisElement = (XMLCh*) fMemoryManager->allocate
        (
            (toSetLen + 1) * sizeof(XMLCh)
        );//new XMLCh[toSetLen + 1];
    }

    XMLString::moveChars(fStack[fStackTop - 1]->fThisElement, toSet, toSetLen + 1);
    fStack[fStackTop - 1]->fReaderNum = readerNum;
}


// ---------------------------------------------------------------------------
//  WFElemStack: Stack top access
// ---------------------------------------------------------------------------
const WFElemStack::StackElem* WFElemStack::topElement() const
{
    if (!fStackTop)
        ThrowXMLwithMemMgr(EmptyStackException, XMLExcepts::ElemStack_EmptyStack, fMemoryManager);

    return fStack[fStackTop - 1];
}


// ---------------------------------------------------------------------------
//  WFElemStack: Prefix map methods
// ---------------------------------------------------------------------------
void WFElemStack::addPrefix(  const   XMLCh* const    prefixToAdd
                              , const unsigned int    uriId)
{
    if (!fStackTop)
        ThrowXMLwithMemMgr(EmptyStackException, XMLExcepts::ElemStack_EmptyStack, fMemoryManager);

    // Get a convenience pointer to the stack top row
    StackElem* curRow = fStack[fStackTop - 1];

    // Map the prefix to its unique id
    const unsigned int prefId = fPrefixPool.addOrFind(prefixToAdd);

    //
    //  Add a new element to the prefix map for this element. If its full,
    //  then expand it out.
    //
    if ((unsigned int)curRow->fTopPrefix + 1 == fMapCapacity)
        expandMap();

    //
    //  And now add a new element for this prefix. Watch for the special case
    //  of xmlns=="", and force it to ""=[globalid]
    //
    fMap[curRow->fTopPrefix + 1].fPrefId = prefId;
    if ((prefId == fGlobalPoolId) && (uriId == fEmptyNamespaceId))
        fMap[curRow->fTopPrefix + 1].fURIId = fEmptyNamespaceId;
    else
        fMap[curRow->fTopPrefix + 1].fURIId = uriId;

    // Bump the map count now
    curRow->fTopPrefix++;
}


unsigned int WFElemStack::mapPrefixToURI( const   XMLCh* const    prefixToMap
                                          ,       bool&           unknown) const
{
    // Assume we find it
    unknown = false;

    //
    //  Map the prefix to its unique id, from the prefix string pool. If its
    //  not a valid prefix, then its a failure.
    //
    unsigned int prefixId = fPrefixPool.getId(prefixToMap);
    if (!prefixId)
    {
        unknown = true;
        return fUnknownNamespaceId;
    }

    //
    //  Check for the special prefixes 'xml' and 'xmlns' since they cannot
    //  be overridden.
    //
    if (prefixId == fXMLPoolId)
        return fXMLNamespaceId;
    else if (prefixId == fXMLNSPoolId)
        return fXMLNSNamespaceId;

    //
    //  Start at the stack top and work backwards until we come to some
    //  element that mapped this prefix.
    //
    //  Get a convenience pointer to the stack top row
    StackElem* curRow = fStack[fStackTop - 1];
    for (int mapIndex = curRow->fTopPrefix; mapIndex >=0; mapIndex--)
    {
        if (fMap[mapIndex].fPrefId == prefixId)
            return fMap[mapIndex].fURIId;
    }

    //
    //  If the prefix is an empty string, then we will return the special
    //  global namespace id. This can be overridden, but no one has or we
    //  would have not gotten here.
    //
    if (!*prefixToMap)
        return fEmptyNamespaceId;

    // Oh well, don't have a clue so return the unknown id
    unknown = true;
    return fUnknownNamespaceId;
}


// ---------------------------------------------------------------------------
//  WFElemStack: Miscellaneous methods
// ---------------------------------------------------------------------------
void WFElemStack::reset(  const   unsigned int    emptyId
                          , const unsigned int    unknownId
                          , const unsigned int    xmlId
                          , const unsigned int    xmlNSId)
{
    // Reset the stack top to clear the stack
    fStackTop = 0;

    // if first time, put in the standard prefixes
    if (fXMLPoolId == 0) {

        fGlobalPoolId = fPrefixPool.addOrFind(XMLUni::fgZeroLenString);
        fXMLPoolId = fPrefixPool.addOrFind(XMLUni::fgXMLString);
        fXMLNSPoolId = fPrefixPool.addOrFind(XMLUni::fgXMLNSString);
    }

    // And store the new special URI ids
    fEmptyNamespaceId = emptyId;
    fUnknownNamespaceId = unknownId;
    fXMLNamespaceId = xmlId;
    fXMLNSNamespaceId = xmlNSId;
}


// ---------------------------------------------------------------------------
//  WFElemStack: Private helpers
// ---------------------------------------------------------------------------
void WFElemStack::expandMap()
{
    //
    //  Expand the capacity by 25%, or initialize it to 16 if its currently
    //  empty. Then allocate a new temp buffer.
    //
    const XMLSize_t newCapacity = fMapCapacity ?
                                  (XMLSize_t)(fMapCapacity * 1.25) : 16;
    PrefMapElem* newMap = (PrefMapElem*) fMemoryManager->allocate
    (
        newCapacity * sizeof(PrefMapElem)
    );//new PrefMapElem[newCapacity];

    //
    //  Copy over the old stuff. We DON'T have to zero out the new stuff
    //  since this is a by value map and the current map index controls what
    //  is relevant.
    //
    if (fMapCapacity) {

        memcpy(newMap, fMap, fMapCapacity * sizeof(PrefMapElem));
        fMemoryManager->deallocate(fMap);//delete [] fMap;
    }

    fMap = newMap;
    fMapCapacity = newCapacity;
}

void WFElemStack::expandStack()
{
    // Expand the capacity by 25% and allocate a new buffer
    const XMLSize_t newCapacity = (XMLSize_t)(fStackCapacity * 1.25);
    StackElem** newStack = (StackElem**) fMemoryManager->allocate
    (
        newCapacity * sizeof(StackElem*)
    );//new StackElem*[newCapacity];

    // Copy over the old stuff
    memcpy(newStack, fStack, fStackCapacity * sizeof(StackElem*));

    //
    //  And zero out the new stuff. Though we use a stack top, we reuse old
    //  stack contents so we need to know if elements have been initially
    //  allocated or not as we push new stuff onto the stack.
    //
    memset
    (
        &newStack[fStackCapacity]
        , 0
        , (newCapacity - fStackCapacity) * sizeof(StackElem*)
    );

    // Delete the old array and update our members
    fMemoryManager->deallocate(fStack);//delete [] fStack;
    fStack = newStack;
    fStackCapacity = newCapacity;
}


XERCES_CPP_NAMESPACE_END
