ElemStack.cpp
上传用户:huihehuasu
上传日期:2007-01-10
资源大小:6948k
文件大小:18k
源码类别:

xml/soap/webservice

开发平台:

C/C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  *
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  *
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  *
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written
  29.  *    permission, please contact apache@apache.org.
  30.  *
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their name, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 1999, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Log: ElemStack.cpp,v $
  58.  * Revision 1.16  2001/08/29 16:42:27  tng
  59.  * No need to new the child QName in ElemStack addChild.  Remove it for performance gain.
  60.  *
  61.  * Revision 1.15  2001/08/07 13:47:47  tng
  62.  * Schema: Fix unmatched end tag for qualified/unqualifed start tag.
  63.  *
  64.  * Revision 1.14  2001/06/18 21:33:57  peiyongz
  65.  * Memory leak fix: to addlevel(), by Erik Rydgren.
  66.  *
  67.  * Revision 1.13  2001/06/12 19:08:27  peiyongz
  68.  * Memory leak: fixed by Erik Rydgren
  69.  *
  70.  * Revision 1.12  2001/05/28 20:55:19  tng
  71.  * Schema: Store Grammar in ElemStack as well.
  72.  *
  73.  * Revision 1.11  2001/05/11 13:26:16  tng
  74.  * Copyright update.
  75.  *
  76.  * Revision 1.10  2001/05/03 20:34:28  tng
  77.  * Schema: SchemaValidator update
  78.  *
  79.  * Revision 1.9  2001/04/19 18:16:57  tng
  80.  * Schema: SchemaValidator update, and use QName in Content Model
  81.  *
  82.  * Revision 1.8  2001/02/16 17:58:02  tng
  83.  * use EmptyNamespaceId for attribute, GlobalNamespaceId for element.
  84.  *
  85.  * Revision 1.7  2000/07/05 05:20:17  roddey
  86.  * Fixed a memory leak when namespaces are enabled.
  87.  *
  88.  * Revision 1.6  2000/05/15 22:31:15  andyh
  89.  * Replace #include<memory.h> with <string.h> everywhere.
  90.  *
  91.  * Revision 1.5  2000/03/02 19:54:28  roddey
  92.  * This checkin includes many changes done while waiting for the
  93.  * 1.1.0 code to be finished. I can't list them all here, but a list is
  94.  * available elsewhere.
  95.  *
  96.  * Revision 1.4  2000/02/08 19:38:58  roddey
  97.  * xmlns:xxx="" should affect the mapping of the prefixes of sibling attributes,
  98.  * which was not being done.
  99.  *
  100.  * Revision 1.3  2000/02/06 07:47:52  rahulj
  101.  * Year 2K copyright swat.
  102.  *
  103.  * Revision 1.2  2000/01/19 00:55:45  roddey
  104.  * Changes to get rid of dependence on old utils standard streams classes
  105.  * and a small fix in the progressive parseFirst() call.
  106.  *
  107.  * Revision 1.1.1.1  1999/11/09 01:08:04  twl
  108.  * Initial checkin
  109.  *
  110.  * Revision 1.4  1999/11/08 20:44:41  rahul
  111.  * Swat for adding in Product name and CVS comment log variable.
  112.  *
  113.  */
  114. // ---------------------------------------------------------------------------
  115. //  Includes
  116. // ---------------------------------------------------------------------------
  117. #include <string.h>
  118. #include <util/EmptyStackException.hpp>
  119. #include <util/NoSuchElementException.hpp>
  120. #include <framework/XMLElementDecl.hpp>
  121. #include <internal/ElemStack.hpp>
  122. #include <validators/common/Grammar.hpp>
  123. // ---------------------------------------------------------------------------
  124. //  ElemStack: Constructors and Destructor
  125. // ---------------------------------------------------------------------------
  126. ElemStack::ElemStack() :
  127.     fEmptyNamespaceId(0)
  128.     , fGlobalPoolId(0)
  129.     , fStack(0)
  130.     , fStackCapacity(32)
  131.     , fStackTop(0)
  132.     , fUnknownNamespaceId(0)
  133.     , fXMLNamespaceId(0)
  134.     , fXMLPoolId(0)
  135.     , fXMLNSNamespaceId(0)
  136.     , fXMLNSPoolId(0)
  137. {
  138.     // Do an initial allocation of the stack and zero it out
  139.     fStack = new StackElem*[fStackCapacity];
  140.     memset(fStack, 0, fStackCapacity * sizeof(StackElem*));
  141. }
  142. ElemStack::~ElemStack()
  143. {
  144.     //
  145.     //  Start working from the bottom of the stack and clear it out as we
  146.     //  go up. Once we hit an uninitialized one, we can break out.
  147.     //
  148.     for (unsigned int stackInd = 0; stackInd < fStackCapacity; stackInd++)
  149.     {
  150.         // If this entry has been set, then lets clean it up
  151.         if (!fStack[stackInd])
  152.             break;
  153.         delete [] fStack[stackInd]->fChildren;
  154.         delete [] fStack[stackInd]->fMap;
  155.         delete fStack[stackInd];
  156.     }
  157.     // Delete the stack array itself now
  158.     delete [] fStack;
  159. }
  160. // ---------------------------------------------------------------------------
  161. //  ElemStack: Stack access
  162. // ---------------------------------------------------------------------------
  163. unsigned int ElemStack::addLevel()
  164. {
  165.     // See if we need to expand the stack
  166.     if (fStackTop == fStackCapacity)
  167.         expandStack();
  168.     // If this element has not been initialized yet, then initialize it
  169.     if (!fStack[fStackTop])
  170.     {
  171.         fStack[fStackTop] = new StackElem;
  172.         fStack[fStackTop]->fChildCapacity = 0;
  173.         fStack[fStackTop]->fChildren = 0;
  174.         fStack[fStackTop]->fMapCapacity = 0;
  175.         fStack[fStackTop]->fMap = 0;
  176.     }
  177.     else
  178.     {
  179.         // Cleanup the old element before reuse
  180.         unsigned int childCount = fStack[fStackTop]->fChildCount;
  181.     }
  182.     // Set up the new top row
  183.     fStack[fStackTop]->fThisElement = 0;
  184.     fStack[fStackTop]->fReaderNum = 0xFFFFFFFF;
  185.     fStack[fStackTop]->fChildCount = 0;
  186.     fStack[fStackTop]->fMapCount = 0;
  187.     fStack[fStackTop]->fValidationFlag = false;
  188.     fStack[fStackTop]->fCurrentURI = fUnknownNamespaceId;
  189.     fStack[fStackTop]->fCurrentScope = Grammar::TOP_LEVEL_SCOPE;
  190.     fStack[fStackTop]->fCurrentGrammar = 0;
  191.     // Bump the top of stack
  192.     fStackTop++;
  193.     return fStackTop-1;
  194. }
  195. unsigned int
  196. ElemStack::addLevel(XMLElementDecl* const toSet, const unsigned int readerNum)
  197. {
  198.     // See if we need to expand the stack
  199.     if (fStackTop == fStackCapacity)
  200.         expandStack();
  201.     // If this element has not been initialized yet, then initialize it
  202.     if (!fStack[fStackTop])
  203.     {
  204.         fStack[fStackTop] = new StackElem;
  205.         fStack[fStackTop]->fChildCapacity = 0;
  206.         fStack[fStackTop]->fChildren = 0;
  207.         fStack[fStackTop]->fMapCapacity = 0;
  208.         fStack[fStackTop]->fMap = 0;
  209.     }
  210.     else
  211.     {
  212.         // Cleanup the old element before reuse
  213.         unsigned int childCount = fStack[fStackTop]->fChildCount;
  214.     }
  215.     // Set up the new top row
  216.     fStack[fStackTop]->fThisElement = 0;
  217.     fStack[fStackTop]->fReaderNum = 0xFFFFFFFF;
  218.     fStack[fStackTop]->fChildCount = 0;
  219.     fStack[fStackTop]->fMapCount = 0;
  220.     fStack[fStackTop]->fValidationFlag = false;
  221.     fStack[fStackTop]->fCurrentURI = fUnknownNamespaceId;
  222.     fStack[fStackTop]->fCurrentScope = Grammar::TOP_LEVEL_SCOPE;
  223.     fStack[fStackTop]->fCurrentGrammar = 0;
  224.     // And store the new stuff
  225.     fStack[fStackTop]->fThisElement = toSet;
  226.     fStack[fStackTop]->fReaderNum = readerNum;
  227.     // Bump the top of stack
  228.     fStackTop++;
  229.     return fStackTop-1;
  230. }
  231. const XMLElementDecl& ElemStack::elemAt(const unsigned int index) const
  232. {
  233.     if (!fStackTop)
  234.         ThrowXML(EmptyStackException, XMLExcepts::ElemStack_EmptyStack);
  235.     if (index >= fStack[fStackTop-1]->fChildCount)
  236.         ThrowXML(ArrayIndexOutOfBoundsException, XMLExcepts::ElemStack_BadIndex);
  237.     return *(fStack[fStackTop-1]->fThisElement);
  238. }
  239. const ElemStack::StackElem* ElemStack::popTop()
  240. {
  241.     // Watch for an underflow error
  242.     if (!fStackTop)
  243.         ThrowXML(EmptyStackException, XMLExcepts::ElemStack_StackUnderflow);
  244.     fStackTop--;
  245.     return fStack[fStackTop];
  246. }
  247. void
  248. ElemStack::setElement(XMLElementDecl* const toSet, const unsigned int readerNum)
  249. {
  250.     if (!fStackTop)
  251.         ThrowXML(EmptyStackException, XMLExcepts::ElemStack_EmptyStack);
  252.     fStack[fStackTop - 1]->fThisElement = toSet;
  253.     fStack[fStackTop - 1]->fReaderNum = readerNum;
  254. }
  255. // ---------------------------------------------------------------------------
  256. //  ElemStack: Stack top access
  257. // ---------------------------------------------------------------------------
  258. unsigned int ElemStack::addChild(QName* const child, const bool toParent)
  259. {
  260.     if (!fStackTop)
  261.         ThrowXML(EmptyStackException, XMLExcepts::ElemStack_EmptyStack);
  262.     //
  263.     //  If they want to add to the parent, then we have to have at least two
  264.     //  elements on the stack.
  265.     //
  266.     if (toParent && (fStackTop < 2))
  267.         ThrowXML(NoSuchElementException, XMLExcepts::ElemStack_NoParentPushed);
  268.     // Get a convenience pointer to the stack top row
  269.     StackElem* curRow = toParent
  270.                         ? fStack[fStackTop - 2] : fStack[fStackTop - 1];
  271.     // See if we need to expand this row's child array
  272.     if (curRow->fChildCount == curRow->fChildCapacity)
  273.     {
  274.         // Increase the capacity by a quarter and allocate a new row
  275.         const unsigned int newCapacity = curRow->fChildCapacity ?
  276.                                          (unsigned int)(curRow->fChildCapacity * 1.25) :
  277.                                          32;
  278.         QName** newRow = new QName*[newCapacity];
  279.         //
  280.         //  Copy over the old contents. We don't have to initialize the new
  281.         //  part because The current child count is used to know how much of
  282.         //  it is valid.
  283.         //
  284.         //  Only both doing this if there is any current content, since
  285.         //  this code also does the initial faulting in of the array when
  286.         //  both the current capacity and child count are zero.
  287.         //
  288.         if (curRow->fChildCount)
  289.         {
  290.              unsigned int index = 0;
  291.              for (; index < curRow->fChildCount; index++)
  292.                  newRow[index] = curRow->fChildren[index];
  293.         }
  294.         // Clean up the old children and store the new info
  295.         delete [] curRow->fChildren;
  296.         curRow->fChildren = newRow;
  297.         curRow->fChildCapacity = newCapacity;
  298.     }
  299.     // Add this id to the end of the row's child id array and bump the count
  300.     curRow->fChildren[curRow->fChildCount++] = child;
  301.     // Return the level of the index we just filled (before the bump)
  302.     return curRow->fChildCount - 1;
  303. }
  304. const ElemStack::StackElem* ElemStack::topElement() const
  305. {
  306.     if (!fStackTop)
  307.         ThrowXML(EmptyStackException, XMLExcepts::ElemStack_EmptyStack);
  308.     return fStack[fStackTop - 1];
  309. }
  310. // ---------------------------------------------------------------------------
  311. //  ElemStack: Prefix map methods
  312. // ---------------------------------------------------------------------------
  313. void ElemStack::addPrefix(  const   XMLCh* const    prefixToAdd
  314.                             , const unsigned int    uriId)
  315. {
  316.     if (!fStackTop)
  317.         ThrowXML(EmptyStackException, XMLExcepts::ElemStack_EmptyStack);
  318.     // Get a convenience pointer to the stack top row
  319.     StackElem* curRow = fStack[fStackTop - 1];
  320.     // Map the prefix to its unique id
  321.     const unsigned int prefId = fPrefixPool.addOrFind(prefixToAdd);
  322.     //
  323.     //  Add a new element to the prefix map for this element. If its full,
  324.     //  then expand it out.
  325.     //
  326.     if (curRow->fMapCount == curRow->fMapCapacity)
  327.         expandMap(curRow);
  328.     //
  329.     //  And now add a new element for this prefix. Watch for the special case
  330.     //  of xmlns=="", and force it to ""=[globalid]
  331.     //
  332.     curRow->fMap[curRow->fMapCount].fPrefId = prefId;
  333.     if ((prefId == fGlobalPoolId) && (uriId == fEmptyNamespaceId))
  334.         curRow->fMap[curRow->fMapCount].fURIId = fEmptyNamespaceId;
  335.     else
  336.         curRow->fMap[curRow->fMapCount].fURIId = uriId;
  337.     // Bump the map count now
  338.     curRow->fMapCount++;
  339. }
  340. unsigned int ElemStack::mapPrefixToURI( const   XMLCh* const    prefixToMap
  341.                                         , const MapModes        mode
  342.                                         ,       bool&           unknown) const
  343. {
  344.     // Assume we find it
  345.     unknown = false;
  346.     //
  347.     //  Map the prefix to its unique id, from the prefix string pool. If its
  348.     //  not a valid prefix, then its a failure.
  349.     //
  350.     unsigned int prefixId = fPrefixPool.getId(prefixToMap);
  351.     if (!prefixId)
  352.     {
  353.         unknown = true;
  354.         return fUnknownNamespaceId;
  355.     }
  356.     //
  357.     //  If the prefix is empty, and we are in attribute mode, then we assign
  358.     //  it to the empty namespace because the default namespace does not
  359.     //  apply to attributes.
  360.     //
  361.     if (!*prefixToMap && (mode == Mode_Attribute))
  362.         return fEmptyNamespaceId;
  363.     //
  364.     //  Check for the special prefixes 'xml' and 'xmlns' since they cannot
  365.     //  be overridden.
  366.     //
  367.     if (prefixId == fXMLPoolId)
  368.         return fXMLNamespaceId;
  369.     else if (prefixId == fXMLNSPoolId)
  370.         return fXMLNSNamespaceId;
  371.     //
  372.     //  Start at the stack top and work backwards until we come to some
  373.     //  element that mapped this prefix.
  374.     //
  375.     int startAt = (int)(fStackTop - 1);
  376.     for (int index = startAt; index >= 0; index--)
  377.     {
  378.         // Get a convenience pointer to the current element
  379.         StackElem* curRow = fStack[index];
  380.         // If no prefixes mapped at this level, then go the next one
  381.         if (!curRow->fMapCount)
  382.             continue;
  383.         // Search the map at this level for the passed prefix
  384.         for (unsigned int mapIndex = 0; mapIndex < curRow->fMapCount; mapIndex++)
  385.         {
  386.             if (curRow->fMap[mapIndex].fPrefId == prefixId)
  387.                 return curRow->fMap[mapIndex].fURIId;
  388.         }
  389.     }
  390.     //
  391.     //  If the prefix is an empty string, then we will return the special
  392.     //  global namespace id. This can be overridden, but no one has or we
  393.     //  would have not gotten here.
  394.     //
  395.     if (!*prefixToMap)
  396.         return fEmptyNamespaceId;
  397.     // Oh well, don't have a clue so return the unknown id
  398.     unknown = true;
  399.     return fUnknownNamespaceId;
  400. }
  401. // ---------------------------------------------------------------------------
  402. //  ElemStack: Miscellaneous methods
  403. // ---------------------------------------------------------------------------
  404. void ElemStack::reset(  const   unsigned int    emptyId
  405.                         , const unsigned int    unknownId
  406.                         , const unsigned int    xmlId
  407.                         , const unsigned int    xmlNSId)
  408. {
  409.     // Flush the prefix pool and put back in the standard prefixes
  410.     fPrefixPool.flushAll();
  411.     fGlobalPoolId = fPrefixPool.addOrFind(XMLUni::fgZeroLenString);
  412.     fXMLPoolId = fPrefixPool.addOrFind(XMLUni::fgXMLString);
  413.     fXMLNSPoolId = fPrefixPool.addOrFind(XMLUni::fgXMLNSString);
  414.     // Reset the stack top to clear the stack
  415.     fStackTop = 0;
  416.     // And store the new special URI ids
  417.     fEmptyNamespaceId = emptyId;
  418.     fUnknownNamespaceId = unknownId;
  419.     fXMLNamespaceId = xmlId;
  420.     fXMLNSNamespaceId = xmlNSId;
  421. }
  422. // ---------------------------------------------------------------------------
  423. //  ElemStack: Private helpers
  424. // ---------------------------------------------------------------------------
  425. void ElemStack::expandMap(StackElem* const toExpand)
  426. {
  427.     // For convenience get the old map size
  428.     const unsigned int oldCap = toExpand->fMapCapacity;
  429.     //
  430.     //  Expand the capacity by 25%, or initialize it to 16 if its currently
  431.     //  empty. Then allocate a new temp buffer.
  432.     //
  433.     const unsigned int newCapacity = oldCap ?
  434.                                      (unsigned int)(oldCap * 1.25) : 16;
  435.     PrefMapElem* newMap = new PrefMapElem[newCapacity];
  436.     //
  437.     //  Copy over the old stuff. We DON'T have to zero out the new stuff
  438.     //  since this is a by value map and the current map index controls what
  439.     //  is relevant.
  440.     //
  441.     memcpy(newMap, toExpand->fMap, oldCap * sizeof(PrefMapElem));
  442.     // Delete the old map and store the new stuff
  443.     delete [] toExpand->fMap;
  444.     toExpand->fMap = newMap;
  445.     toExpand->fMapCapacity = newCapacity;
  446. }
  447. void ElemStack::expandStack()
  448. {
  449.     // Expand the capacity by 25% and allocate a new buffer
  450.     const unsigned int newCapacity = (unsigned int)(fStackCapacity * 1.25);
  451.     StackElem** newStack = new StackElem*[newCapacity];
  452.     // Copy over the old stuff
  453.     memcpy(newStack, fStack, fStackCapacity * sizeof(StackElem*));
  454.     //
  455.     //  And zero out the new stuff. Though we use a stack top, we reuse old
  456.     //  stack contents so we need to know if elements have been initially
  457.     //  allocated or not as we push new stuff onto the stack.
  458.     //
  459.     memset
  460.     (
  461.         &newStack[fStackCapacity]
  462.         , 0
  463.         , (newCapacity - fStackCapacity) * sizeof(StackElem*)
  464.     );
  465.     // Delete the old array and update our members
  466.     delete [] fStack;
  467.     fStack = newStack;
  468.     fStackCapacity = newCapacity;
  469. }