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

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: DFAContentModel.cpp,v $
  58.  * Revision 1.28  2001/12/06 17:52:17  tng
  59.  * Performance Enhancement.  The QName that was passed to the CMLeaf
  60.  * constructor was always being copied, even though the CMLeaf objects
  61.  * only existed during construction of a DFA.  In most cases the original
  62.  * QName that was passed into the CMLeaf constructor continued to exist long
  63.  * after the CMLeaf was destroyed; in some cases the QName was constructed
  64.  * specifically to be passed to the CMLeaf constructor.  Added a second CMLeaf constructor that indicated the QName passed in was to be adopted; otherwise the CMLeaf constructor just sets a reference to the QName passed in.
  65.  * By Henry Zongaro.
  66.  *
  67.  * Revision 1.27  2001/11/21 14:30:13  knoaman
  68.  * Fix for UPA checking.
  69.  *
  70.  * Revision 1.26  2001/11/07 21:10:46  tng
  71.  * Performance: move getRawName() to outer loop so that it is called only once per outer loop.
  72.  *
  73.  * Revision 1.25  2001/10/04 15:08:55  knoaman
  74.  * Add support for circular import.
  75.  *
  76.  * Revision 1.24  2001/09/14 14:50:22  tng
  77.  * Schema: Fix some wildcard bugs, and some retrieving qualified/unqualified element decl problems.
  78.  *
  79.  * Revision 1.23  2001/08/24 12:48:48  tng
  80.  * Schema: AllContentModel
  81.  *
  82.  * Revision 1.22  2001/08/22 16:58:55  tng
  83.  * typo: should issue the name of second element.
  84.  *
  85.  * Revision 1.21  2001/08/21 16:50:23  tng
  86.  * Schema: Unique Particle Attribution Constraint Checking.
  87.  *
  88.  * Revision 1.20  2001/08/21 16:06:11  tng
  89.  * Schema: Unique Particle Attribution Constraint Checking.
  90.  *
  91.  * Revision 1.19  2001/08/17 16:12:51  peiyongz
  92.  * Fix to memory leak in buildDFA(),  patch from Nick Chiang (nchiang@ss8.com)
  93.  *
  94.  * Revision 1.18  2001/08/16 21:52:40  peiyongz
  95.  * stateTable created to optimize the identification of new state created.
  96.  *
  97.  * Revision 1.17  2001/07/31 17:45:25  peiyongz
  98.  * Fix: memory leak in postTreeBuildInit()
  99.  *
  100.  * Revision 1.16  2001/07/24 20:00:33  peiyongz
  101.  * Memory Leak fix: Bugzilla #2707 reported by Francois Rioux
  102.  *
  103.  * + |                              DESCRIPTION                                   |
  104.  * + There are some memory leaks in the buildDFA method :
  105.  * +    the first QName allocated object
  106.  * +    the nodeOrgContent
  107.  * +    fHeadNode
  108.  *
  109.  * Revision 1.15  2001/07/09 15:22:36  knoaman
  110.  * complete <any> declaration.
  111.  *
  112.  * Revision 1.14  2001/06/13 20:50:56  peiyongz
  113.  * fIsMixed: to handle mixed Content Model
  114.  *
  115.  * Revision 1.13  2001/06/12 19:07:14  peiyongz
  116.  * Memory leak: fixed by Erik Rydgren
  117.  *
  118.  * Revision 1.12  2001/06/12 17:30:49  knoaman
  119.  * Fix Typo
  120.  *
  121.  * Revision 1.11  2001/06/07 21:08:20  tng
  122.  * Fix unsigned/signed warning from Linux.  By Pei Yong Zhang.
  123.  *
  124.  * Revision 1.10  2001/05/28 20:52:44  tng
  125.  * Schema: move static data gInvalidTrans, gEOCFakeId, gEpsilonFakeId to XMLContentModel for others to access
  126.  *
  127.  * Revision 1.9  2001/05/11 13:27:18  tng
  128.  * Copyright update.
  129.  *
  130.  * Revision 1.8  2001/05/03 21:02:29  tng
  131.  * Schema: Add SubstitutionGroupComparator and update exception messages.  By Pei Yong Zhang.
  132.  *
  133.  * Revision 1.7  2001/04/19 18:17:30  tng
  134.  * Schema: SchemaValidator update, and use QName in Content Model
  135.  *
  136.  * Revision 1.6  2001/03/21 21:56:27  tng
  137.  * Schema: Add Schema Grammar, Schema Validator, and split the DTDValidator into DTDValidator, DTDScanner, and DTDGrammar.
  138.  *
  139.  * Revision 1.5  2001/03/21 19:29:51  tng
  140.  * Schema: Content Model Updates, by Pei Yong Zhang.
  141.  *
  142.  * Revision 1.4  2001/02/27 18:32:31  tng
  143.  * Schema: Use XMLElementDecl instead of DTDElementDecl in Content Model.
  144.  *
  145.  * Revision 1.3  2001/02/27 14:48:51  tng
  146.  * Schema: Add CMAny and ContentLeafNameTypeVector, by Pei Yong Zhang
  147.  *
  148.  * Revision 1.2  2001/02/16 14:58:57  tng
  149.  * Schema: Update Makefile, configure files, project files, and include path in
  150.  * certain cpp files because of the move of the common Content Model files.  By Pei Yong Zhang.
  151.  *
  152.  * Revision 1.1  2001/02/16 14:17:29  tng
  153.  * Schema: Move the common Content Model files that are shared by DTD
  154.  * and schema from 'DTD' folder to 'common' folder.  By Pei Yong Zhang.
  155.  *
  156.  * Revision 1.5  2000/03/28 19:43:25  roddey
  157.  * Fixes for signed/unsigned warnings. New work for two way transcoding
  158.  * stuff.
  159.  *
  160.  * Revision 1.4  2000/03/08 23:52:34  roddey
  161.  * Got rid of the use of -1 to represent an invalid transition state,
  162.  * and just created a const value that is unsigned. This should make
  163.  * some compilers happier.
  164.  *
  165.  * Revision 1.3  2000/03/02 19:55:38  roddey
  166.  * This checkin includes many changes done while waiting for the
  167.  * 1.1.0 code to be finished. I can't list them all here, but a list is
  168.  * available elsewhere.
  169.  *
  170.  * Revision 1.2  2000/02/09 21:42:37  abagchi
  171.  * Copyright swatswat
  172.  *
  173.  * Revision 1.1.1.1  1999/11/09 01:03:17  twl
  174.  * Initial checkin
  175.  *
  176.  * Revision 1.2  1999/11/08 20:45:38  rahul
  177.  * Swat for adding in Product name and CVS comment log variable.
  178.  *
  179.  */
  180. // ---------------------------------------------------------------------------
  181. //  Includes
  182. // ---------------------------------------------------------------------------
  183. #include <util/RuntimeException.hpp>
  184. #include <framework/XMLBuffer.hpp>
  185. #include <framework/XMLElementDecl.hpp>
  186. #include <framework/XMLValidator.hpp>
  187. #include <validators/common/CMAny.hpp>
  188. #include <validators/common/CMBinaryOp.hpp>
  189. #include <validators/common/CMLeaf.hpp>
  190. #include <validators/common/CMUnaryOp.hpp>
  191. #include <validators/common/DFAContentModel.hpp>
  192. #include <validators/common/ContentSpecNode.hpp>
  193. #include <validators/common/Grammar.hpp>
  194. #include <validators/schema/SchemaSymbols.hpp>
  195. #include <validators/schema/SubstitutionGroupComparator.hpp>
  196. #include <validators/schema/XercesElementWildcard.hpp>
  197. #include <util/RefHashTableOf.hpp>
  198. #include <util/HashCMStateSet.hpp>
  199. #include <util/XMLInteger.hpp>
  200. // ---------------------------------------------------------------------------
  201. //  DFAContentModel: Constructors and Destructor
  202. // ---------------------------------------------------------------------------
  203. DFAContentModel::DFAContentModel(const bool             dtd
  204.                                , ContentSpecNode* const elemContentSpec) :
  205.     fElemMap(0)
  206.     , fElemMapType(0)
  207.     , fElemMapSize(0)
  208.     , fEmptyOk(false)
  209.     , fEOCPos(0)
  210.     , fFinalStateFlags(0)
  211.     , fFollowList(0)
  212.     , fHeadNode(0)
  213.     , fLeafCount(0)
  214.     , fLeafList(0)
  215.     , fTransTable(0)
  216.     , fTransTableSize(0)
  217.     , fDTD(dtd)
  218.     , fIsMixed(false)
  219.     , fLeafNameTypeVector(0)
  220. {
  221.     // And build the DFA data structures
  222.     buildDFA(elemContentSpec);
  223. }
  224. DFAContentModel::DFAContentModel(const bool             dtd
  225.                                , ContentSpecNode* const elemContentSpec
  226.                                , const bool             isMixed ):
  227.     fElemMap(0)
  228.     , fElemMapType(0)
  229.     , fElemMapSize(0)
  230.     , fEmptyOk(false)
  231.     , fEOCPos(0)
  232.     , fFinalStateFlags(0)
  233.     , fFollowList(0)
  234.     , fHeadNode(0)
  235.     , fLeafCount(0)
  236.     , fLeafList(0)
  237.     , fTransTable(0)
  238.     , fTransTableSize(0)
  239.     , fDTD(dtd)
  240.     , fIsMixed(isMixed)
  241.     , fLeafNameTypeVector(0)
  242. {
  243.     // And build the DFA data structures
  244.     buildDFA(elemContentSpec);
  245. }
  246. DFAContentModel::~DFAContentModel()
  247. {
  248.     //
  249.     //  Clean up all the stuff that is not just temporary representation
  250.     //  data that was cleaned up after building the DFA.
  251.     //
  252.     delete [] fFinalStateFlags;
  253.     unsigned index;
  254.     for (index = 0; index < fTransTableSize; index++)
  255.         delete [] fTransTable[index];
  256.     delete [] fTransTable;
  257.     for (index = 0; index < fLeafCount; index++)
  258.         delete fElemMap[index];
  259.     delete [] fElemMap;
  260.     delete [] fElemMapType;
  261.     delete [] fLeafListType;
  262. }
  263. // ---------------------------------------------------------------------------
  264. //  DFAContentModel: Implementation of the ContentModel virtual interface
  265. // ---------------------------------------------------------------------------
  266. int
  267. DFAContentModel::validateContent( QName** const        children
  268.                                 , const unsigned int   childCount
  269.                                 , const unsigned int   emptyNamespaceId) const
  270. {
  271.     //
  272.     //  If there are no children, then either we fail on the 0th element
  273.     //  or we return success. It depends upon whether this content model
  274.     //  accepts empty content, which we determined earlier.
  275.     //
  276.     if (!childCount)
  277.     {
  278.         // success -1
  279.         return fEmptyOk ? -1 : 0;
  280.     }
  281.     //
  282.     //  Lets loop through the children in the array and move our way
  283.     //  through the states. Note that we use the fElemMap array to map
  284.     //  an element index to a state index.
  285.     //
  286.     unsigned int curState = 0;
  287.     unsigned int nextState = 0;
  288.     unsigned int childIndex = 0;
  289.     for (; childIndex < childCount; childIndex++)
  290.     {
  291.         // Get the current element index out
  292.         const QName* curElem = children[childIndex];
  293.         const XMLCh* curElemRawName = 0;
  294.         if (fDTD)
  295.             curElemRawName = curElem->getRawName();
  296.         // If this is text in a Schema mixed content model, skip it.
  297.         if ( fIsMixed &&
  298.             ( curElem->getURI() == XMLElementDecl::fgPCDataElemId))
  299.             continue;
  300.         // Look up this child in our element map
  301.         unsigned int elemIndex = 0;
  302.         for (; elemIndex < fElemMapSize; elemIndex++)
  303.         {
  304.             const QName* inElem  = fElemMap[elemIndex];
  305.             if (fDTD) {
  306.                 if (!XMLString::compareString(inElem->getRawName(), curElemRawName)) {
  307.                     nextState = fTransTable[curState][elemIndex];
  308.                     if (nextState != XMLContentModel::gInvalidTrans)
  309.                         break;
  310.                 }
  311.             }
  312.             else {
  313.                 ContentSpecNode::NodeTypes type = fElemMapType[elemIndex];
  314.                 if (type == ContentSpecNode::Leaf)
  315.                 {
  316.                     if ((inElem->getURI() == curElem->getURI()) &&
  317.                     (!XMLString::compareString(inElem->getLocalPart(), curElem->getLocalPart()))) {
  318.                         nextState = fTransTable[curState][elemIndex];
  319.                         if (nextState != XMLContentModel::gInvalidTrans)
  320.                             break;
  321.                     }
  322.                 }
  323.                 else if ((type & 0x0f)== ContentSpecNode::Any)
  324.                 {
  325.                     nextState = fTransTable[curState][elemIndex];
  326.                     if (nextState != XMLContentModel::gInvalidTrans)
  327.                             break;
  328.                 }
  329.                 else if ((type & 0x0f) == ContentSpecNode::Any_NS)
  330.                 {
  331.                     if (inElem->getURI() == curElem->getURI())
  332.                     {
  333.                         nextState = fTransTable[curState][elemIndex];
  334.                         if (nextState != XMLContentModel::gInvalidTrans)
  335.                             break;
  336.                     }
  337.                 }
  338.                 else if ((type & 0x0f) == ContentSpecNode::Any_Other)
  339.                 {
  340.                     if (inElem->getURI() != curElem->getURI()) {
  341.                         nextState = fTransTable[curState][elemIndex];
  342.                         if (nextState != XMLContentModel::gInvalidTrans)
  343.                             break;
  344.                     }
  345.                 }
  346.             }
  347.         }//for elemIndex
  348.         // If "nextState" is -1, we found a match, but the transition is invalid
  349.         if (nextState == XMLContentModel::gInvalidTrans)
  350.             return childIndex;
  351.         // If we didn't find it, then obviously not valid
  352.         if (elemIndex == fElemMapSize)
  353.             return childIndex;
  354.         curState = nextState;
  355.         nextState = 0;
  356.     }//for childIndex
  357.     //
  358.     //  We transitioned all the way through the input list. However, that
  359.     //  does not mean that we ended in a final state. So check whether
  360.     //  our ending state is a final state.
  361.     //
  362.     if (!fFinalStateFlags[curState])
  363.         return childIndex;
  364.     //success
  365.     return -1;
  366. }
  367. int DFAContentModel::validateContentSpecial(QName** const          children
  368.                                             , const unsigned int      childCount
  369.                                             , const unsigned int      emptyNamespaceId
  370.                                             , GrammarResolver*  const pGrammarResolver
  371.                                             , XMLStringPool*    const pStringPool) const
  372. {
  373.     SubstitutionGroupComparator comparator(pGrammarResolver, pStringPool);
  374.     if (childCount == 0)
  375.         return fEmptyOk ? -1 : 0;
  376.     //
  377.     //  Lets loop through the children in the array and move our way
  378.     //  through the states. Note that we use the fElemMap array to map
  379.     //  an element index to a state index.
  380.     //
  381.     unsigned int curState = 0;
  382.     unsigned int nextState = 0;
  383.     unsigned int childIndex = 0;
  384.     for (; childIndex < childCount; childIndex++)
  385.     {
  386.         // Get the current element index out
  387.         QName* curElem = children[childIndex];
  388.         // If this is text in a Schema mixed content model, skip it.
  389.         if ( fIsMixed &&
  390.             ( curElem->getURI() == XMLElementDecl::fgPCDataElemId))
  391.             continue;
  392.         // Look up this child in our element map
  393.         unsigned int elemIndex = 0;
  394.         for (; elemIndex < fElemMapSize; elemIndex++)
  395.         {
  396.             QName* inElem  = fElemMap[elemIndex];
  397.             ContentSpecNode::NodeTypes type = fElemMapType[elemIndex];
  398.             if (type == ContentSpecNode::Leaf)
  399.             {
  400.                 if (comparator.isEquivalentTo(curElem, inElem) )
  401.                 {
  402.                     nextState = fTransTable[curState][elemIndex];
  403.                     if (nextState != XMLContentModel::gInvalidTrans)
  404.                         break;
  405.                 }
  406.             }
  407.             else if ((type & 0x0f)== ContentSpecNode::Any)
  408.             {
  409.                 nextState = fTransTable[curState][elemIndex];
  410.                 if (nextState != XMLContentModel::gInvalidTrans)
  411.                         break;
  412.             }
  413.             else if ((type & 0x0f) == ContentSpecNode::Any_NS)
  414.             {
  415.                 if (inElem->getURI() == curElem->getURI())
  416.                 {
  417.                     nextState = fTransTable[curState][elemIndex];
  418.                     if (nextState != XMLContentModel::gInvalidTrans)
  419.                         break;
  420.                 }
  421.             }
  422.             else if ((type & 0x0f) == ContentSpecNode::Any_Other)
  423.             {
  424.                 if (inElem->getURI() != curElem->getURI())
  425.                 {
  426.                     nextState = fTransTable[curState][elemIndex];
  427.                     if (nextState != XMLContentModel::gInvalidTrans)
  428.                         break;
  429.                 }
  430.             }
  431.         }//for elemIndex
  432.         // If "nextState" is -1, we found a match, but the transition is invalid
  433.         if (nextState == XMLContentModel::gInvalidTrans)
  434.             return childIndex;
  435.         // If we didn't find it, then obviously not valid
  436.         if (elemIndex == fElemMapSize)
  437.             return childIndex;
  438.         curState = nextState;
  439.         nextState = 0;
  440.     }//for childIndex
  441.     //
  442.     //  We transitioned all the way through the input list. However, that
  443.     //  does not mean that we ended in a final state. So check whether
  444.     //  our ending state is a final state.
  445.     //
  446.     if (!fFinalStateFlags[curState])
  447.         return childIndex;
  448.     //success
  449.     return -1;
  450. }
  451. // ---------------------------------------------------------------------------
  452. //  DFAContentModel: Private helper methods
  453. // ---------------------------------------------------------------------------
  454. void DFAContentModel::buildDFA(ContentSpecNode* const curNode)
  455. {
  456.     unsigned int index;
  457.     //
  458.     //  The first step we need to take is to rewrite the content model using
  459.     //  our CMNode objects, and in the process get rid of any repetition short
  460.     //  cuts, converting them into '*' style repetitions or getting rid of
  461.     //  repetitions altogether.
  462.     //
  463.     //  The conversions done are:
  464.     //
  465.     //  x+ -> (x|x*)
  466.     //  x? -> (x|epsilon)
  467.     //
  468.     //  This is a relatively complex scenario. What is happening is that we
  469.     //  create a top level binary node of which the special EOC value is set
  470.     //  as the right side node. The the left side is set to the rewritten
  471.     //  syntax tree. The source is the original content model info from the
  472.     //  decl pool. The rewrite is done by buildSyntaxTree() which recurses the
  473.     //  decl pool's content of the element and builds a new tree in the
  474.     //  process.
  475.     //
  476.     //  Note that, during this operation, we set each non-epsilon leaf node's
  477.     //  DFA state position and count the number of such leafs, which is left
  478.     //  in the fLeafCount member.
  479.     //
  480.     CMLeaf* nodeEOC = new CMLeaf(new QName(XMLUni::fgZeroLenString,
  481.                                            XMLUni::fgZeroLenString,
  482.                                            XMLContentModel::gEOCFakeId)
  483.                                  , ~0
  484.                                  , true);
  485.     CMNode* nodeOrgContent = buildSyntaxTree(curNode);
  486.     fHeadNode = new CMBinaryOp
  487.     (
  488.         ContentSpecNode::Sequence
  489.         , nodeOrgContent
  490.         , nodeEOC
  491.     );
  492.     //
  493.     //  And handle specially the EOC node, which also must be numbered and
  494.     //  counted as a non-epsilon leaf node. It could not be handled in the
  495.     //  above tree build because it was created before all that started. We
  496.     //  save the EOC position since its used during the DFA building loop.
  497.     //
  498.     fEOCPos = fLeafCount;
  499.     nodeEOC->setPosition(fLeafCount++);
  500.     //
  501.     //  Ok, so now we have to iterate the new tree and do a little more work
  502.     //  now that we know the leaf count. One thing we need to do is to
  503.     //  calculate the first and last position sets of each node. This is
  504.     //  cached away in each of the nodes.
  505.     //
  506.     //  Along the way we also set the leaf count in each node as the maximum
  507.     //  state count. They must know this in order to create their first/last
  508.     //  position sets.
  509.     //
  510.     //  We also need to build an array of references to the non-epsilon
  511.     //  leaf nodes. Since we iterate here the same way as we did during the
  512.     //  initial tree build (which built their position numbers, we will put
  513.     //  them in the array according to their position values.
  514.     //
  515.     fLeafList = new CMLeaf*[fLeafCount];
  516.     fLeafListType = new ContentSpecNode::NodeTypes[fLeafCount];
  517.     postTreeBuildInit(fHeadNode, 0);
  518.     //
  519.     //  And, moving onward... We now need to build the follow position sets
  520.     //  for all the nodes. So we allocate an array of pointers to state sets,
  521.     //  one for each leaf node (i.e. each significant DFA position.)
  522.     //
  523.     fFollowList = new CMStateSet*[fLeafCount];
  524.     for (index = 0; index < fLeafCount; index++)
  525.         fFollowList[index] = new CMStateSet(fLeafCount);
  526.     calcFollowList(fHeadNode);
  527.     //
  528.     //  Check to see whether this content model can handle an empty content,
  529.     //  which is something we need to optimize by looking now before we
  530.     //  throw away the info that would tell us that.
  531.     //
  532.     //  If the left node of the head (the top level of the original content)
  533.     //  is nullable, then its true.
  534.     //
  535.     fEmptyOk = nodeOrgContent->isNullable();
  536.     //
  537.     //  And finally the big push... Now we build the DFA using all the states
  538.     //  and the tree we've built up. First we set up the various data
  539.     //  structures we are going to use while we do this.
  540.     //
  541.     //  First of all we need an array of unique element ids in our content
  542.     //  model. For each transition table entry, we need a set of contiguous
  543.     //  indices to represent the transitions for a particular input element.
  544.     //  So we need to a zero based range of indexes that map to element types.
  545.     //  This element map provides that mapping.
  546.     //
  547.     fElemMap = new QName*[fLeafCount];
  548.     fElemMapType = new ContentSpecNode::NodeTypes[fLeafCount];
  549.     fElemMapSize = 0;
  550.     for (unsigned int outIndex = 0; outIndex < fLeafCount; outIndex++)
  551.     {
  552.         fElemMap[outIndex] = new QName();
  553.         if ( (fLeafListType[outIndex] & 0x0f) != ContentSpecNode::Leaf )
  554.             if (!fLeafNameTypeVector)
  555.                 fLeafNameTypeVector = new ContentLeafNameTypeVector();
  556.         // Get the current leaf's element index
  557.         const QName* element = fLeafList[outIndex]->getElement();
  558.         const XMLCh* elementRawName = 0;
  559.         if (fDTD && element)
  560.             elementRawName = element->getRawName();
  561.         // See if the current leaf node's element index is in the list
  562.         unsigned int inIndex = 0;
  563.         for (; inIndex < fElemMapSize; inIndex++)
  564.         {
  565.             const QName* inElem = fElemMap[inIndex];
  566.             if (fDTD) {
  567.                 if (!XMLString::compareString(inElem->getRawName(), elementRawName)) {
  568.                     break;
  569.                 }
  570.             }
  571.             else {
  572.                 if ((fElemMapType[inIndex] == fLeafListType[outIndex]) &&
  573.                     (inElem->getURI() == element->getURI()) &&
  574.                     (!XMLString::compareString(inElem->getLocalPart(), element->getLocalPart()))) {
  575.                     break;
  576.                 }
  577.             }
  578.         }
  579.         // If it was not in the list, then add it and bump the map size
  580.         if (inIndex == fElemMapSize)
  581.         {
  582.             fElemMap[fElemMapSize]->setValues(*element);
  583.             fElemMapType[fElemMapSize] = fLeafListType[outIndex];
  584.             ++fElemMapSize;
  585.         }
  586.     }
  587.     // set up the fLeafNameTypeVector object if there is one.
  588.     if (fLeafNameTypeVector) {
  589.         fLeafNameTypeVector->setValues(fElemMap, fElemMapType, fElemMapSize);
  590.     }
  591.     /***
  592.      * Optimization(Jan, 2001); We sort fLeafList according to
  593.      * elemIndex which is *uniquely* associated to each leaf.
  594.      * We are *assuming* that each element appears in at least one leaf.
  595.      **/
  596.     // don't forget to delete it
  597.     int *fLeafSorter = new int[fLeafCount + fElemMapSize];
  598.     unsigned int fSortCount = 0;
  599.     for (unsigned int elemIndex = 0; elemIndex < fElemMapSize; elemIndex++)
  600.     {
  601.         const QName* element = fElemMap[elemIndex];
  602.         const XMLCh* elementRawName = 0;
  603.         if (fDTD && element)
  604.             elementRawName = element->getRawName();
  605.         for (unsigned int leafIndex = 0; leafIndex < fLeafCount; leafIndex++)
  606.         {
  607.             const QName* leaf = fLeafList[leafIndex]->getElement();
  608.             const int leafType = fLeafListType[leafIndex];
  609.             if (fDTD) {
  610.                 if (!XMLString::compareString(leaf->getRawName(), elementRawName)) {
  611.                     fLeafSorter[fSortCount++] = leafIndex;
  612.                 }
  613.             }
  614.             else {
  615.                 if ((fElemMapType[elemIndex] == fLeafListType[leafIndex]) &&
  616.                     (leaf->getURI() == element->getURI()) &&
  617.                     (!XMLString::compareString(leaf->getLocalPart(), element->getLocalPart()))) {
  618.                       fLeafSorter[fSortCount++] = leafIndex;
  619.                 }
  620.             }
  621.         }
  622.         fLeafSorter[fSortCount++] = -1;
  623.     }
  624.     //
  625.     //  Next lets create some arrays, some that that hold transient info
  626.     //  during the DFA build and some that are permament. These are kind of
  627.     //  sticky since we cannot know how big they will get, but we don't want
  628.     //  to use any collection type classes because of performance.
  629.     //
  630.     //  Basically they will probably be about fLeafCount*2 on average, but can
  631.     //  be as large as 2^(fLeafCount*2), worst case. So we start with
  632.     //  fLeafCount*4 as a middle ground. This will be very unlikely to ever
  633.     //  have to expand though, it if does, the overhead will be somewhat ugly.
  634.     //
  635.     unsigned int curArraySize = fLeafCount * 4;
  636.     const CMStateSet** statesToDo = new const CMStateSet*[curArraySize];
  637.     fFinalStateFlags = new bool[curArraySize];
  638.     fTransTable = new unsigned int*[curArraySize];
  639.     //
  640.     //  Ok we start with the initial set as the first pos set of the head node
  641.     //  (which is the seq node that holds the content model and the EOC node.)
  642.     //
  643.     const CMStateSet* setT = new CMStateSet(fHeadNode->getFirstPos());
  644.     //
  645.     //  Init our two state flags. Basically the unmarked state counter is
  646.     //  always chasing the current state counter. When it catches up, that
  647.     //  means we made a pass through that did not add any new states to the
  648.     //  lists, at which time we are done. We could have used a expanding array
  649.     //  of flags which we used to mark off states as we complete them, but
  650.     //  this is easier though less readable maybe.
  651.     //
  652.     unsigned int unmarkedState = 0;
  653.     unsigned int curState = 0;
  654.     //
  655.     //  Init the first transition table entry, and put the initial state
  656.     //  into the states to do list, then bump the current state.
  657.     //
  658.     fTransTable[curState] = makeDefStateList();
  659.     statesToDo[curState] = setT;
  660.     curState++;
  661.     //
  662.     // the stateTable is an auxiliary means to fast
  663.     // identification of new state created (instead
  664.     // of squential loop statesToDo to find out),
  665.     // while the role that statesToDo plays remain unchanged.
  666.     //
  667.     // TODO: in the future, we may change the 29 to something
  668.     //       derived from curArraySize.
  669.     RefHashTableOf<XMLInteger> *stateTable = new RefHashTableOf<XMLInteger>(curArraySize, true, new HashCMStateSet());
  670.     //stateTable->put((CMStateSet*)setT, new XMLInteger(0));
  671.     //
  672.     //  Ok, almost done with the algorithm from hell... We now enter the
  673.     //  loop where we go until the states done counter catches up with
  674.     //  the states to do counter.
  675.     //
  676.     CMStateSet* newSet = 0;
  677.     while (unmarkedState < curState)
  678.     {
  679.         //
  680.         //  Get the next unmarked state out of the list of states to do.
  681.         //  And get the associated transition table entry.
  682.         //
  683.         setT = statesToDo[unmarkedState];
  684.         unsigned int* transEntry = fTransTable[unmarkedState];
  685.         // Mark this one final if it contains the EOC state
  686.         fFinalStateFlags[unmarkedState] = setT->getBit(fEOCPos);
  687.         // Bump up the unmarked state count, marking this state done
  688.         unmarkedState++;
  689.         // Optimization(Jan, 2001)
  690.         unsigned int sorterIndex = 0;
  691.         // Optimization(Jan, 2001)
  692.         // Loop through each possible input symbol in the element map
  693.         for (unsigned int elemIndex = 0; elemIndex < fElemMapSize; elemIndex++)
  694.         {
  695.             //
  696.             //  Build up a set of states which is the union of all of the
  697.             //  follow sets of DFA positions that are in the current state. If
  698.             //  we gave away the new set last time through then create a new
  699.             //  one. Otherwise, zero out the existing one.
  700.             //
  701.             if (!newSet)
  702.                 newSet = new CMStateSet(fLeafCount);
  703.             else
  704.                 newSet->zeroBits();
  705. #ifdef OBSOLETED
  706. // unoptimized code
  707.             for (unsigned int leafIndex = 0; leafIndex < fLeafCount; leafIndex++)
  708.             {
  709.                 // If this leaf index (DFA position) is in the current set...
  710.                 if (setT->getBit(leafIndex))
  711.                 {
  712.                     //
  713.                     //  If this leaf is the current input symbol, then we want
  714.                     //  to add its follow list to the set of states to transition
  715.                     //  to from the current state.
  716.                     //
  717.                     const QName* leaf = fLeafList[leafIndex]->getElement();
  718.                     const QName* element = fElemMap[elemIndex];
  719.                     if (fDTD) {
  720.                         if (!XMLString::compareString(leaf->getRawName(), element->getRawName())) {
  721.                             *newSet |= *fFollowList[leafIndex];
  722.                         }
  723.                     }
  724.                     else {
  725.                         if ((leaf->getURI() == element->getURI()) &&
  726.                             (!XMLString::compareString(leaf->getLocalPart(), element->getLocalPart()))) {
  727.                             *newSet |= *fFollowList[leafIndex];
  728.                         }
  729.                     }
  730.                 }
  731.             } // for leafIndex
  732. #endif
  733.             // Optimization(Jan, 2001)
  734.             int leafIndex = fLeafSorter[sorterIndex++];
  735.             while (leafIndex != -1)
  736.             {
  737.                 // If this leaf index (DFA position) is in the current set...
  738.                 if (setT->getBit(leafIndex))
  739.                 {
  740.                     //
  741.                     //  If this leaf is the current input symbol, then we
  742.                     //  want to add its follow list to the set of states to
  743.                     //  transition to from the current state.
  744.                     //
  745.                     *newSet |= *fFollowList[leafIndex];
  746.                 }
  747.                 leafIndex = fLeafSorter[sorterIndex++];
  748.             } // while (leafIndex != -1)
  749.             //
  750.             //  If this new set is not empty, then see if its in the list
  751.             //  of states to do. If not, then add it.
  752.             //
  753.             if (!newSet->isEmpty())
  754.             {
  755.                 //
  756.                 //  Search the 'states to do' list to see if this new
  757.                 //  state set is already in there.
  758.                 //
  759.                 /***
  760.                 unsigned int stateIndex = 0;
  761.                 for (; stateIndex < curState; stateIndex++)
  762.                 {
  763.                     if (*statesToDo[stateIndex] == *newSet)
  764.                         break;
  765.                 }
  766.                 ***/
  767.                 XMLInteger *stateObj = (XMLInteger*) (stateTable->get(newSet));
  768.                 unsigned int stateIndex = (stateObj == 0 ? curState : stateObj->intValue());
  769.                 // If we did not find it, then add it
  770.                 if (stateIndex == curState)
  771.                 {
  772.                     //
  773.                     //  Put this new state into the states to do and init
  774.                     //  a new entry at the same index in the transition
  775.                     //  table.
  776.                     //
  777.                     statesToDo[curState] = newSet;
  778.                     fTransTable[curState] = makeDefStateList();
  779.                     stateTable->put(newSet, new XMLInteger(curState));
  780.                     // We now have a new state to do so bump the count
  781.                     curState++;
  782.                     //
  783.                     //  Null out the new set to indicate we adopted it. This
  784.                     //  will cause the creation of a new set on the next time
  785.                     //  around the loop.
  786.                     //
  787.                     newSet = 0;
  788.                 }
  789.                 //
  790.                 //  Now set this state in the transition table's entry for this
  791.                 //  element (using its index), with the DFA state we will move
  792.                 //  to from the current state when we see this input element.
  793.                 //
  794.                 transEntry[elemIndex] = stateIndex;
  795.                 // Expand the arrays if we're full
  796.                 if (curState == curArraySize)
  797.                 {
  798.                     //
  799.                     //  Yikes, we overflowed the initial array size, so we've
  800.                     //  got to expand all of these arrays. So adjust up the
  801.                     //  size by 50% and allocate new arrays.
  802.                     //
  803.                     const unsigned int newSize = (unsigned int)(curArraySize * 1.5);
  804.                     const CMStateSet** newToDo = new const CMStateSet*[newSize];
  805.                     bool* newFinalFlags = new bool[newSize];
  806.                     unsigned int** newTransTable = new unsigned int*[newSize];
  807.                     // Copy over all of the existing content
  808.                     for (unsigned int expIndex = 0; expIndex < curArraySize; expIndex++)
  809.                     {
  810.                         newToDo[expIndex] = statesToDo[expIndex];
  811.                         newFinalFlags[expIndex] = fFinalStateFlags[expIndex];
  812.                         newTransTable[expIndex] = fTransTable[expIndex];
  813.                     }
  814.                     // Clean up the old stuff
  815.                     delete [] statesToDo;
  816.                     delete [] fFinalStateFlags;
  817.                     delete [] fTransTable;
  818.                     // Store the new array size and pointers
  819.                     curArraySize = newSize;
  820.                     statesToDo = newToDo;
  821.                     fFinalStateFlags = newFinalFlags;
  822.                     fTransTable = newTransTable;
  823.                 } //if (curState == curArraySize)
  824.             } //if (!newSet->isEmpty())
  825.         } // for elemIndex
  826.     } //while
  827.     // Store the current state count in the trans table size
  828.     fTransTableSize = curState;
  829.     // If the last temp set was not stored, then clean it up
  830.     if (newSet)
  831.         delete newSet;
  832.     //
  833.     //  Now we can clean up all of the temporary data that was needed during
  834.     //  DFA build.
  835.     //
  836.     //
  837.     // Note on memory leak: Bugzilla#2707:
  838.     // ===================================
  839.     // The CMBinary, pointed to by fHeadNode, shall be released by
  840.     // deleted by itself.
  841.     //
  842.     // Change has been made to postTreeBuildInit() such that fLeafList[]
  843.     // would maintain its **OWN** copy of CMLeaf to avoid double deletion
  844.     // of CMLeaf.
  845.     //
  846.     delete fHeadNode;
  847.     for (index = 0; index < fLeafCount; index++)
  848.         delete fFollowList[index];
  849.     delete [] fFollowList;
  850.     //
  851.     // removeAll() will delete all data, XMLInteger,
  852.     // while the keys are to be deleted by the
  853.     // deletion of statesToDo.
  854.     //
  855.     delete stateTable;
  856.     for (index = 0; index < curState; index++)
  857.         delete (CMStateSet*)statesToDo[index];
  858.     delete [] statesToDo;
  859.     for (index = 0; index < fLeafCount; index++)
  860.         delete fLeafList[index];
  861.     delete [] fLeafList;
  862.     delete [] fLeafSorter;
  863. }
  864. CMNode* DFAContentModel::buildSyntaxTree(ContentSpecNode* const curNode)
  865. {
  866.     // Initialize a return node pointer
  867.     CMNode* retNode = 0;
  868.     // Get the spec type of the passed node
  869.     const ContentSpecNode::NodeTypes curType = curNode->getType();
  870.     if ((curType & 0x0f) == ContentSpecNode::Any
  871.         || (curType & 0x0f) == ContentSpecNode::Any_Other
  872.         || (curType & 0x0f) == ContentSpecNode::Any_NS)
  873.     {
  874.         retNode = new CMAny(curType, curNode->getElement()->getURI(), fLeafCount++);
  875.     }
  876.     else if (curType == ContentSpecNode::Leaf)
  877.     {
  878.         //
  879.         //  Create a new leaf node, and pass it the current leaf count, which
  880.         //  is its DFA state position. Bump the leaf count after storing it.
  881.         //  This makes the positions zero based since we store first and then
  882.         //  increment.
  883.         //
  884.         retNode = new CMLeaf(curNode->getElement(), fLeafCount++);
  885.     }
  886.      else
  887.     {
  888.         //
  889.         //  Its not a leaf, so we have to recurse its left and maybe right
  890.         //  nodes. Save both values before we recurse and trash the node.
  891.         //
  892.         ContentSpecNode* leftNode = curNode->getFirst();
  893.         ContentSpecNode* rightNode = curNode->getSecond();
  894.         if ((curType == ContentSpecNode::Choice)
  895.         ||   (curType == ContentSpecNode::Sequence))
  896.         {
  897.             //
  898.             //  Recurse on both children, and return a binary op node with the
  899.             //  two created sub nodes as its children. The node type is the
  900.             //  same type as the source.
  901.             //
  902.             CMNode* newLeft = buildSyntaxTree(leftNode);
  903.             CMNode* newRight = buildSyntaxTree(rightNode);
  904.             retNode = new CMBinaryOp(curType, newLeft, newRight);
  905.         }
  906.          else if (curType == ContentSpecNode::ZeroOrMore
  907.                || curType == ContentSpecNode::ZeroOrOne
  908.                || curType == ContentSpecNode::OneOrMore)
  909.         {
  910.             // This one is fine as is, just change to our form
  911.             retNode = new CMUnaryOp(curType, buildSyntaxTree(leftNode));
  912.         }
  913.          else
  914.         {
  915.             ThrowXML(RuntimeException, XMLExcepts::CM_UnknownCMSpecType);
  916.         }
  917.     }
  918.     return retNode;
  919. }
  920. void DFAContentModel::calcFollowList(CMNode* const curNode)
  921. {
  922.     // Get the spec type of the passed node
  923.     const ContentSpecNode::NodeTypes curType = curNode->getType();
  924.     if (curType == ContentSpecNode::Choice)
  925.     {
  926.         // Just recurse
  927.         calcFollowList(((CMBinaryOp*)curNode)->getLeft());
  928.         calcFollowList(((CMBinaryOp*)curNode)->getRight());
  929.     }
  930.      else if (curType == ContentSpecNode::Sequence)
  931.     {
  932.         // Recurse before we process this node
  933.         calcFollowList(((CMBinaryOp*)curNode)->getLeft());
  934.         calcFollowList(((CMBinaryOp*)curNode)->getRight());
  935.         //
  936.         //  Now handle our level. We use our left child's last pos set and our
  937.         //  right child's first pos set, so get them now for convenience.
  938.         //
  939.         const CMStateSet& last  = ((CMBinaryOp*)curNode)->getLeft()->getLastPos();
  940.         const CMStateSet& first = ((CMBinaryOp*)curNode)->getRight()->getFirstPos();
  941.         //
  942.         //  Now, for every position which is in our left child's last set
  943.         //  add all of the states in our right child's first set to the
  944.         //  follow set for that position.
  945.         //
  946.         for (unsigned int index = 0; index < fLeafCount; index++)
  947.         {
  948.             if (last.getBit(index))
  949.                 *fFollowList[index] |= first;
  950.         }
  951.     }
  952.      else if (curType == ContentSpecNode::ZeroOrMore ||
  953.       curType == ContentSpecNode::OneOrMore   )
  954.     {
  955.         // Recurse first
  956.         calcFollowList(((CMUnaryOp*)curNode)->getChild());
  957.         //
  958.         //  Now handle our level. We use our own first and last position
  959.         //  sets, so get them up front.
  960.         //
  961.         const CMStateSet& first = curNode->getFirstPos();
  962.         const CMStateSet& last  = curNode->getLastPos();
  963.         //
  964.         //  For every position which is in our last position set, add all
  965.         //  of our first position states to the follow set for that
  966.         //  position.
  967.         //
  968.         for (unsigned int index = 0; index < fLeafCount; index++)
  969.         {
  970.             if (last.getBit(index))
  971.                 *fFollowList[index] |= first;
  972.         }
  973.     }
  974.      else if (curType == ContentSpecNode::ZeroOrOne)
  975.     {
  976.         // Recurse only
  977.         calcFollowList(((CMUnaryOp*)curNode)->getChild());
  978.     }
  979. }
  980. //
  981. //  gInvalidTrans is used to represent bad transitions in the transition table
  982. //  entry for each state. So each entry is initialized to that value. This
  983. //  method creates a new entry and initializes it.
  984. //
  985. unsigned int* DFAContentModel::makeDefStateList() const
  986. {
  987.     unsigned int* retArray = new unsigned int[fElemMapSize];
  988.     for (unsigned int index = 0; index < fElemMapSize; index++)
  989.         retArray[index] = XMLContentModel::gInvalidTrans;
  990.     return retArray;
  991. }
  992. int DFAContentModel::postTreeBuildInit(         CMNode* const   nodeCur
  993.                                         , const unsigned int    curIndex)
  994. {
  995.     // Set the maximum states on this node
  996.     nodeCur->setMaxStates(fLeafCount);
  997.     // Get the spec type of the passed node
  998.     const ContentSpecNode::NodeTypes curType = nodeCur->getType();
  999.     // Get a copy of the index we can modify
  1000.     unsigned int newIndex = curIndex;
  1001.     // Recurse as required
  1002.     if ( ((curType & 0x0f) == ContentSpecNode::Any)       ||
  1003.          ((curType & 0x0f) == ContentSpecNode::Any_NS) ||
  1004.          ((curType & 0x0f) == ContentSpecNode::Any_Other)  )
  1005.     {
  1006.         fLeafList[newIndex] = new CMLeaf(new QName(XMLUni::fgZeroLenString
  1007.                                                  , XMLUni::fgZeroLenString
  1008.                                                  , ((CMAny*) nodeCur)->getURI())
  1009.                                        , ((CMAny*)nodeCur)->getPosition()
  1010.                                        , true);
  1011.         fLeafListType[newIndex] = curType;
  1012.         ++newIndex;
  1013.     }
  1014.     else if ((curType == ContentSpecNode::Choice)
  1015.          ||  (curType == ContentSpecNode::Sequence))
  1016.     {
  1017.         newIndex = postTreeBuildInit(((CMBinaryOp*)nodeCur)->getLeft(), newIndex);
  1018.         newIndex = postTreeBuildInit(((CMBinaryOp*)nodeCur)->getRight(), newIndex);
  1019.     }
  1020.     else if (curType == ContentSpecNode::ZeroOrMore ||
  1021.              curType == ContentSpecNode::ZeroOrOne  ||
  1022.              curType == ContentSpecNode::OneOrMore)
  1023.     {
  1024.         newIndex = postTreeBuildInit(((CMUnaryOp*)nodeCur)->getChild(), newIndex);
  1025.     }
  1026.     else if (curType == ContentSpecNode::Leaf)
  1027.     {
  1028.         //
  1029.         //  Put this node in the leaf list at the current index if its
  1030.         //  a non-epsilon leaf.
  1031.         //
  1032.         if (((CMLeaf*)nodeCur)->getElement()->getURI() != XMLContentModel::gEpsilonFakeId)
  1033.         {
  1034.             //
  1035.             // fLeafList make its own copy of the CMLeaf, so that
  1036.             // delete[] fLeafList and delete the owner of the nodeCur
  1037.             // will NOT delete the nodeCur --twice--,
  1038.             // thuse to make delete the owner of the nodeCur possible.
  1039.             //
  1040.             fLeafList[newIndex] = new CMLeaf(((CMLeaf*)nodeCur)->getElement(),
  1041.                                            ((CMLeaf*)nodeCur)->getPosition());
  1042.             fLeafListType[newIndex] = ContentSpecNode::Leaf;
  1043.             ++newIndex;
  1044.         }
  1045.     }
  1046.     else
  1047.     {
  1048.         ThrowXML(RuntimeException, XMLExcepts::CM_UnknownCMSpecType);
  1049.     }
  1050.     return newIndex;
  1051. }
  1052. ContentLeafNameTypeVector* DFAContentModel::getContentLeafNameTypeVector() const
  1053. {
  1054.    //later change it to return the data member
  1055. return fLeafNameTypeVector;
  1056. };
  1057. void DFAContentModel::checkUniqueParticleAttribution (SchemaGrammar*    const pGrammar,
  1058.                                                       GrammarResolver*  const pGrammarResolver,
  1059.                                                       XMLStringPool*    const pStringPool,
  1060.                                                       XMLValidator*     const pValidator,
  1061.                                                       unsigned int*     const pContentSpecOrgURI)
  1062. {
  1063.     SubstitutionGroupComparator comparator(pGrammarResolver, pStringPool);
  1064.     unsigned int i, j, k;
  1065.     // Rename the URI back
  1066.     for (i = 0; i < fElemMapSize; i++) {
  1067.         unsigned int orgURIIndex = fElemMap[i]->getURI();
  1068.         if (orgURIIndex != XMLContentModel::gEOCFakeId) {
  1069.             fElemMap[i]->setURI(pContentSpecOrgURI[orgURIIndex]);
  1070.         }
  1071.     }
  1072.     // Unique Particle Attribution
  1073.     // store the conflict results between any two elements in fElemMap
  1074.     // XMLContentModel::gInvalidTrans: not compared; 0: no conflict; 1: conflict
  1075.     unsigned int** fConflictTable = new unsigned int*[fElemMapSize];
  1076.     // initialize the conflict table
  1077.     for (j = 0; j < fElemMapSize; j++) {
  1078.         fConflictTable[j] = new unsigned int[fElemMapSize];
  1079.         for (k = j+1; k < fElemMapSize; k++)
  1080.             fConflictTable[j][k] = XMLContentModel::gInvalidTrans;
  1081.     }
  1082.     // for each state, check whether it has overlap transitions
  1083.     for (i = 0; i < fTransTableSize; i++) {
  1084.         for (j = 0; j < fElemMapSize; j++) {
  1085.             for (k = j+1; k < fElemMapSize; k++) {
  1086.                 if (fTransTable[i][j] != XMLContentModel::gInvalidTrans &&
  1087.                     fTransTable[i][k] != XMLContentModel::gInvalidTrans &&
  1088.                     fConflictTable[j][k] == XMLContentModel::gInvalidTrans) {
  1089.                     // If this is text in a Schema mixed content model, skip it.
  1090.                     if ( fIsMixed &&
  1091.                          (( fElemMap[j]->getURI() == XMLElementDecl::fgPCDataElemId) ||
  1092.                           ( fElemMap[k]->getURI() == XMLElementDecl::fgPCDataElemId)))
  1093.                         continue;
  1094.                     if (XercesElementWildcard::conflict(pGrammar,
  1095.                                                         fElemMapType[j],
  1096.                                                         fElemMap[j],
  1097.                                                         fElemMapType[k],
  1098.                                                         fElemMap[k],
  1099.                                                         &comparator)) {
  1100.                        fConflictTable[j][k] = 1;
  1101.                        XMLBuffer buf1;
  1102.                        if (((fElemMapType[j] & 0x0f) == ContentSpecNode::Any) ||
  1103.                            ((fElemMapType[j] & 0x0f) == ContentSpecNode::Any_NS))
  1104.                            buf1.set(SchemaSymbols::fgATTVAL_TWOPOUNDANY);
  1105.                        else if ((fElemMapType[j] & 0x0f) == ContentSpecNode::Any_Other)
  1106.                            buf1.set(SchemaSymbols::fgATTVAL_TWOPOUNDOTHER);
  1107.                        else
  1108.                            buf1.set(fElemMap[j]->getRawName());
  1109.                        XMLBuffer buf2;
  1110.                        if (((fElemMapType[k] & 0x0f) == ContentSpecNode::Any) ||
  1111.                            ((fElemMapType[k] & 0x0f) == ContentSpecNode::Any_NS))
  1112.                            buf2.set(SchemaSymbols::fgATTVAL_TWOPOUNDANY);
  1113.                        else if ((fElemMapType[k] & 0x0f) == ContentSpecNode::Any_Other)
  1114.                            buf2.set(SchemaSymbols::fgATTVAL_TWOPOUNDOTHER);
  1115.                        else
  1116.                            buf2.set(fElemMap[k]->getRawName());
  1117.                        pValidator->emitError(XMLValid::UniqueParticleAttributionFail,
  1118.                                              buf1.getRawBuffer(),
  1119.                                              buf2.getRawBuffer());
  1120.                     }
  1121.                     else
  1122.                        fConflictTable[j][k] = 0;
  1123.                 }
  1124.             }
  1125.         }
  1126.     }
  1127.     for (i = 0; i < fElemMapSize; i++)
  1128.         delete [] fConflictTable[i];
  1129.     delete [] fConflictTable;
  1130. }