DTDScanner.cpp
上传用户:zhuqijet
上传日期:2013-06-25
资源大小:10074k
文件大小:134k
源码类别:

词法分析

开发平台:

Visual 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: DTDScanner.cpp,v $
  58.  * Revision 1.27  2003/05/18 14:02:06  knoaman
  59.  * Memory manager implementation: pass per instance manager.
  60.  *
  61.  * Revision 1.26  2003/05/16 21:43:19  knoaman
  62.  * Memory manager implementation: Modify constructors to pass in the memory manager.
  63.  *
  64.  * Revision 1.25  2003/05/15 18:54:50  knoaman
  65.  * Partial implementation of the configurable memory manager.
  66.  *
  67.  * Revision 1.24  2003/03/10 15:28:07  tng
  68.  * XML1.0 Errata E38
  69.  *
  70.  * Revision 1.23  2003/02/05 22:07:09  tng
  71.  * [Bug 3111] Problem with LexicalHandler::startDTD() and LexicalHandler::endDTD().
  72.  *
  73.  * Revision 1.22  2003/01/20 22:01:38  tng
  74.  * Need to check text decl when expanding PE
  75.  *
  76.  * Revision 1.21  2003/01/16 21:30:14  tng
  77.  * [Bug 16151] Memory leak in DTDScanner with ill-formed DTD declaration.  Fix by David Bertoni.
  78.  *
  79.  * Revision 1.20  2002/12/24 16:12:19  tng
  80.  * For performance reason, move the character check to scancharref.
  81.  *
  82.  * Revision 1.19  2002/12/20 22:10:47  tng
  83.  * XML 1.1
  84.  *
  85.  * Revision 1.18  2002/12/18 14:17:55  gareth
  86.  * Fix to bug #13438. When you eant a vector that calls delete[] on its members you should use RefArrayVectorOf.
  87.  *
  88.  * Revision 1.17  2002/12/04 02:47:25  knoaman
  89.  * scanner re-organization.
  90.  *
  91.  * Revision 1.16  2002/11/14 22:34:11  tng
  92.  * [Bug 14265] Access violation with Null systemId/publicId in DTDScanner
  93.  *
  94.  * Revision 1.15  2002/11/05 21:40:36  tng
  95.  * Oasis test fix:
  96.  * 1.  Should check if content model allow character for CDataSection case
  97.  * 2. Should check partial markup in entity for INCLUDE and IGNORE scenario
  98.  * 3. If standalone is yes, reference to entity where its declaration is external is a well-formness fatal error (XML 1.0 Section 4.1)
  99.  * If standalone is yes, reference to parameter entity where is declaration is external is a validity constraint (XML 1.0 Section 2.9)
  100.  * 4.  XML 1.0 Section 2.8 Partial markup in parameter entity reference.
  101.  * If it is a complete declaration, partial markup is a fatal error.
  102.  *
  103.  * Revision 1.14  2002/11/04 14:50:40  tng
  104.  * C++ Namespace Support.
  105.  *
  106.  * Revision 1.13  2002/09/24 20:10:30  tng
  107.  * Performance: use XMLString::equals instead of XMLString::compareString
  108.  *
  109.  * Revision 1.12  2002/08/22 21:05:29  tng
  110.  * [Bug 7475] Xerces-C++ reports validation error with Docbook.
  111.  *
  112.  * Revision 1.11  2002/08/22 20:26:01  tng
  113.  * [Bug 7512] Wrong error message created .
  114.  *
  115.  * Revision 1.10  2002/08/22 19:29:13  tng
  116.  * [Bug 11448] DomCount has problems with XHTML1.1 DTD.
  117.  *
  118.  * Revision 1.9  2002/08/19 14:40:31  tng
  119.  * Fix: public id / system id in entity decl should be null if empty
  120.  *
  121.  * Revision 1.8  2002/07/26 13:33:44  knoaman
  122.  * Public/System id for notations should be stored as NULL if missing.
  123.  *
  124.  * Revision 1.7  2002/07/11 18:39:48  knoaman
  125.  * Access entities through the DTDGrammar instead of the scanner.
  126.  *
  127.  * Revision 1.6  2002/06/06 20:36:33  tng
  128.  * Fix: Valid encoding name is not checked in scanning Text Decl
  129.  *
  130.  * Revision 1.5  2002/05/30 16:17:19  tng
  131.  * Add feature to optionally ignore external DTD.
  132.  *
  133.  * Revision 1.4  2002/05/03 14:51:16  peiyongz
  134.  * Bug#8769: UMR detected by memory tool - patch from Kenneth Palsson
  135.  *
  136.  * Revision 1.3  2002/02/28 22:34:36  peiyongz
  137.  * Bug#2717: patch to Unterminated INCLUDE section causes infinite loop with setExitOnFirstFatalError(false)
  138.  *
  139.  * Revision 1.2  2002/02/26 21:06:53  knoaman
  140.  * Create ZeroOrOne node only if needed.
  141.  *
  142.  * Revision 1.1.1.1  2002/02/01 22:22:44  peiyongz
  143.  * sane_include
  144.  *
  145.  * Revision 1.25  2002/01/24 16:30:50  tng
  146.  * [Bug 3111] Problem with LexicalHandler::startDTD() and LexicalHandler::endDTD() .
  147.  *
  148.  * Revision 1.24  2001/12/17 15:39:14  knoaman
  149.  * Fix for surrogate pair support.
  150.  *
  151.  * Revision 1.23  2001/12/14 20:21:37  knoaman
  152.  * Add surrogate support to comments and processing instrunctions.
  153.  *
  154.  * Revision 1.22  2001/12/06 17:51:18  tng
  155.  * Performance Enhancement. The ContentSpecNode constructor always copied the QName
  156.  * that was passed to it.  Added a second constructor that allows the QName to be just assigned, not copied.
  157.  * That was because there are some cases in which a temporary QName was constructed, passed to ContentSpecNode, and then deleted.
  158.  * There were examples of that in TraverseSchema and DTDScanner.
  159.  * By Henry Zongaro.
  160.  *
  161.  * Revision 1.21  2001/11/13 13:27:28  tng
  162.  * Move root element check to XMLScanner.
  163.  *
  164.  * Revision 1.20  2001/09/05 20:49:10  knoaman
  165.  * Fix for complexTypes with mixed content model.
  166.  *
  167.  * Revision 1.19  2001/08/02 16:54:39  tng
  168.  * Reset some Scanner flags in scanReset().
  169.  *
  170.  * Revision 1.18  2001/07/13 16:57:11  tng
  171.  * ScanId fix.
  172.  *
  173.  * Revision 1.17  2001/07/12 20:10:18  tng
  174.  * Partial Markup in Parameter Entity is validity constraint and thus should be just error, not fatal error.
  175.  *
  176.  * Revision 1.16  2001/07/10 21:09:39  tng
  177.  * Give proper error messsage when scanning external id.
  178.  *
  179.  * Revision 1.15  2001/07/10 20:56:17  tng
  180.  * Should check the first char of PI Target Name.
  181.  *
  182.  * Revision 1.14  2001/07/09 13:42:20  tng
  183.  * Partial Markup in Parameter Entity is validity constraint and thus should be just error, not fatal error.
  184.  *
  185.  * Revision 1.13  2001/07/05 14:05:29  tng
  186.  * Encoding String must present for external entity text decl.
  187.  *
  188.  * Revision 1.12  2001/07/05 13:12:19  tng
  189.  * Standalone checking is validity constraint and thus should be just error, not fatal error:
  190.  *
  191.  * Revision 1.11  2001/06/25 14:39:54  knoaman
  192.  * Fix bug #965 - submitted by Matt Lovett
  193.  *
  194.  * Revision 1.10  2001/06/22 12:42:33  tng
  195.  * [Bug 2257] 1.5 thinks a <?xml-stylesheet ...> tag is a <?xml ...> tag
  196.  *
  197.  * Revision 1.9  2001/06/21 14:25:53  knoaman
  198.  * Fix for bug 1946
  199.  *
  200.  * Revision 1.8  2001/06/04 13:25:50  tng
  201.  * the start tag "<?xml" could be followed by (#x20 | #x9 | #xD | #xA)+.  Fixed by Pei Yong Zhang.
  202.  *
  203.  * Revision 1.7  2001/05/28 20:54:06  tng
  204.  * Schema: allocate a fDTDValidator, fSchemaValidator explicitly to avoid wrong cast
  205.  *
  206.  * Revision 1.6  2001/05/11 13:27:09  tng
  207.  * Copyright update.
  208.  *
  209.  * Revision 1.5  2001/05/03 20:34:36  tng
  210.  * Schema: SchemaValidator update
  211.  *
  212.  * Revision 1.4  2001/04/23 18:54:35  tng
  213.  * Reuse grammar should allow users to use any stored element decl as root.  Fixed by Erik Rydgren.
  214.  *
  215.  * Revision 1.3  2001/04/19 18:17:21  tng
  216.  * Schema: SchemaValidator update, and use QName in Content Model
  217.  *
  218.  * Revision 1.2  2001/03/30 16:35:17  tng
  219.  * Schema: Whitespace normalization.
  220.  *
  221.  * Revision 1.1  2001/03/21 21:56:20  tng
  222.  * Schema: Add Schema Grammar, Schema Validator, and split the DTDValidator into DTDValidator, DTDScanner, and DTDGrammar.
  223.  *
  224.  */
  225. // ---------------------------------------------------------------------------
  226. //  Includes
  227. // ---------------------------------------------------------------------------
  228. #include <xercesc/util/BinMemInputStream.hpp>
  229. #include <xercesc/util/FlagJanitor.hpp>
  230. #include <xercesc/util/Janitor.hpp>
  231. #include <xercesc/util/XMLUniDefs.hpp>
  232. #include <xercesc/util/UnexpectedEOFException.hpp>
  233. #include <xercesc/sax/InputSource.hpp>
  234. #include <xercesc/framework/XMLDocumentHandler.hpp>
  235. #include <xercesc/framework/XMLEntityHandler.hpp>
  236. #include <xercesc/framework/XMLValidator.hpp>
  237. #include <xercesc/internal/EndOfEntityException.hpp>
  238. #include <xercesc/internal/XMLScanner.hpp>
  239. #include <xercesc/validators/common/ContentSpecNode.hpp>
  240. #include <xercesc/validators/common/MixedContentModel.hpp>
  241. #include <xercesc/validators/DTD/DTDEntityDecl.hpp>
  242. #include <xercesc/validators/DTD/DocTypeHandler.hpp>
  243. #include <xercesc/validators/DTD/DTDScanner.hpp>
  244. XERCES_CPP_NAMESPACE_BEGIN
  245. // ---------------------------------------------------------------------------
  246. //  Local methods
  247. // ---------------------------------------------------------------------------
  248. //
  249. //  This method automates the grunt work of looking at a char and see if its
  250. //  a repetition suffix. If so, it creates a new correct rep node and wraps
  251. //  the pass node in it. Otherwise, it returns the previous node.
  252. //
  253. static ContentSpecNode* makeRepNode(const XMLCh testCh,
  254.                                     ContentSpecNode* const prevNode,
  255.                                     MemoryManager* const manager)
  256. {
  257.     if (testCh == chQuestion)
  258.     {
  259.         return new (manager) ContentSpecNode
  260.         (
  261.             ContentSpecNode::ZeroOrOne
  262.             , prevNode
  263.             , 0
  264.             , true
  265.             , true
  266.             , manager
  267.         );
  268.     }
  269.      else if (testCh == chPlus)
  270.     {
  271.         return new (manager) ContentSpecNode
  272.         (
  273.             ContentSpecNode::OneOrMore
  274.             , prevNode
  275.             , 0
  276.             , true
  277.             , true
  278.             , manager
  279.         );
  280.     }
  281.      else if (testCh == chAsterisk)
  282.     {
  283.         return new (manager) ContentSpecNode
  284.         (
  285.             ContentSpecNode::ZeroOrMore
  286.             , prevNode
  287.             , 0
  288.             , true
  289.             , true
  290.             , manager
  291.         );
  292.     }
  293.     // Just return the incoming node
  294.     return prevNode;
  295. }
  296. // ---------------------------------------------------------------------------
  297. //  DTDValidator: Constructors and Destructor
  298. // ---------------------------------------------------------------------------
  299. DTDScanner::DTDScanner( DTDGrammar*           dtdGrammar
  300.                       , DocTypeHandler* const docTypeHandler
  301.                       , MemoryManager* const  manager) :
  302.     fMemoryManager(manager)
  303.     , fDocTypeHandler(docTypeHandler)
  304.     , fDumAttDef(0)
  305.     , fDumElemDecl(0)
  306.     , fDumEntityDecl(0)
  307.     , fInternalSubset(false)
  308.     , fNextAttrId(1)
  309.     , fDTDGrammar(dtdGrammar)
  310.     , fPEntityDeclPool(0)
  311.     , fDocTypeReaderId(0)
  312. {
  313.     fPEntityDeclPool = new (fMemoryManager) NameIdPool<DTDEntityDecl>(109, 128, fMemoryManager);
  314. }
  315. DTDScanner::~DTDScanner()
  316. {
  317.     delete fDumAttDef;
  318.     delete fDumElemDecl;
  319.     delete fDumEntityDecl;
  320.     delete fPEntityDeclPool;
  321. }
  322. // -----------------------------------------------------------------------
  323. //  Setter methods
  324. // -----------------------------------------------------------------------
  325. void DTDScanner::setScannerInfo(XMLScanner* const      owningScanner
  326.                             , ReaderMgr* const      readerMgr
  327.                             , XMLBufferMgr* const   bufMgr)
  328. {
  329.     // We don't own any of these, we just reference them
  330.     fScanner = owningScanner;
  331.     fReaderMgr = readerMgr;
  332.     fBufMgr = bufMgr;
  333.     if (fScanner->getDoNamespaces())
  334.         fEmptyNamespaceId = fScanner->getEmptyNamespaceId();
  335.     else
  336.         fEmptyNamespaceId = 0;
  337.     fDocTypeReaderId = fReaderMgr->getCurrentReaderNum();
  338. }
  339. // ---------------------------------------------------------------------------
  340. //  DTDScanner: Private scanning methods
  341. // ---------------------------------------------------------------------------
  342. bool DTDScanner::checkForPERef(const  bool    spaceRequired
  343.                                 , const bool    inLiteral
  344.                                 , const bool    inMarkup
  345.                                 , const bool    throwAtEndExt)
  346. {
  347.     bool gotSpace = false;
  348.     //
  349.     //  See if we have any spaces up front. If so, then skip them and set
  350.     //  the gotSpaces flag.
  351.     //
  352.     if (fReaderMgr->skippedSpace())
  353.     {
  354.         fReaderMgr->skipPastSpaces();
  355.         gotSpace = true;
  356.     }
  357.     // If the next char is a percent, then expand the PERef
  358.     if (!fReaderMgr->skippedChar(chPercent))
  359.        return gotSpace;
  360.     while (true)
  361.     {
  362.        if (!expandPERef(false, inLiteral, inMarkup, throwAtEndExt))
  363.           fScanner->emitError(XMLErrs::ExpectedEntityRefName);
  364.        // And skip any more spaces in the expanded value
  365.        if (fReaderMgr->skippedSpace())
  366.        {
  367.           fReaderMgr->skipPastSpaces();
  368.           gotSpace = true;
  369.        }
  370.        if (!fReaderMgr->skippedChar(chPercent))
  371.           break;
  372.     }
  373.     return gotSpace;
  374. }
  375. bool DTDScanner::expandPERef( const   bool    scanExternal
  376.                                 , const bool    inLiteral
  377.                                 , const bool    inMarkup
  378.                                 , const bool    throwEndOfExt)
  379. {
  380.     fScanner->setHasNoDTD(false);
  381.     XMLBufBid bbName(fBufMgr);
  382.     //
  383.     //  If we are in the internal subset and in markup, then this is
  384.     //  an error but we go ahead and do it anyway.
  385.     //
  386.     if (fInternalSubset && inMarkup)
  387.         fScanner->emitError(XMLErrs::PERefInMarkupInIntSubset);
  388.     if (!fReaderMgr->getName(bbName.getBuffer()))
  389.     {
  390.         fScanner->emitError(XMLErrs::ExpectedPEName);
  391.         // Skip the semicolon if that's what we ended up on
  392.         fReaderMgr->skippedChar(chSemiColon);
  393.         return false;
  394.     }
  395.     // If no terminating semicolon, emit an error but try to keep going
  396.     if (!fReaderMgr->skippedChar(chSemiColon))
  397.         fScanner->emitError(XMLErrs::UnterminatedEntityRef, bbName.getRawBuffer());
  398.     //
  399.     //  Look it up in the PE decl pool and see if it exists. If not, just
  400.     //  emit an error and continue.
  401.     //
  402.     XMLEntityDecl* decl = fPEntityDeclPool->getByKey(bbName.getRawBuffer());
  403.     if (!decl)
  404.     {
  405.         // XML 1.0 Section 4.1
  406.         if (fScanner->getStandalone()) {
  407.             // no need to check fScanner->fHasNoDTD which is for sure false
  408.             // since we are in expandPERef already
  409.             fScanner->emitError(XMLErrs::EntityNotFound, bbName.getRawBuffer());
  410.         }
  411.         else {
  412.             if (fScanner->getDoValidation())
  413.                 fScanner->getValidator()->emitError(XMLValid::VC_EntityNotFound, bbName.getRawBuffer());
  414.         }
  415.         return false;
  416.     }
  417.     //
  418.     // XML 1.0 Section 2.9
  419.     //  If we are a standalone document, then it has to have been declared
  420.     //  in the internal subset. Keep going though.
  421.     //
  422.     if (fScanner->getDoValidation() && fScanner->getStandalone() && !decl->getDeclaredInIntSubset())
  423.         fScanner->getValidator()->emitError(XMLValid::VC_IllegalRefInStandalone, bbName.getRawBuffer());
  424.     //
  425.     //  Okee dokee, we found it. So create either a memory stream with
  426.     //  the entity value contents, or a file stream if its an external
  427.     //  entity.
  428.     //
  429.     if (decl->isExternal())
  430.     {
  431.         // And now create a reader to read this entity
  432.         InputSource* srcUsed;
  433.         XMLReader* reader = fReaderMgr->createReader
  434.         (
  435.             decl->getBaseURI()
  436.             , decl->getSystemId()
  437.             , decl->getPublicId()
  438.             , false
  439.             , inLiteral ? XMLReader::RefFrom_Literal : XMLReader::RefFrom_NonLiteral
  440.             , XMLReader::Type_PE
  441.             , XMLReader::Source_External
  442.             , srcUsed
  443.         );
  444.         // Put a janitor on the source so its cleaned up on exit
  445.         Janitor<InputSource> janSrc(srcUsed);
  446.         // If the creation failed then throw an exception
  447.         if (!reader)
  448.             ThrowXML1(RuntimeException, XMLExcepts::Gen_CouldNotOpenExtEntity, srcUsed->getSystemId());
  449.         // Set the 'throw at end' flag, to the one we were given
  450.         reader->setThrowAtEnd(throwEndOfExt);
  451.         //
  452.         //  Push the reader. If its a recursive expansion, then emit an error
  453.         //  and return an failure.
  454.         //
  455.         if (!fReaderMgr->pushReader(reader, decl))
  456.         {
  457.             fScanner->emitError(XMLErrs::RecursiveEntity, decl->getName());
  458.             return false;
  459.         }
  460.         //
  461.         //  If the caller wants us to scan the external entity, then lets
  462.         //  do that now.
  463.         //
  464.         if (scanExternal)
  465.         {
  466.             XMLEntityHandler* entHandler = fScanner->getEntityHandler();
  467.             // If we have an entity handler, tell it we are starting this entity
  468.             if (entHandler)
  469.                 entHandler->startInputSource(*srcUsed);
  470.             //
  471.             //  Scan the external entity now. The parameter tells it that
  472.             //  it is not in an include section. Get the current reader
  473.             //  level so we can catch partial markup errors and be sure
  474.             //  to get back to here if we get an exception out of the
  475.             //  ext subset scan.
  476.             //
  477.             const unsigned int readerNum = fReaderMgr->getCurrentReaderNum();
  478.             try
  479.             {
  480.                 scanExtSubsetDecl(false, false);
  481.             }
  482.             catch(...)
  483.             {
  484.                 // Pop the reader back to the original level
  485.                 fReaderMgr->cleanStackBackTo(readerNum);
  486.                 // End the input source, even though its not happy
  487.                 if (entHandler)
  488.                     entHandler->endInputSource(*srcUsed);
  489.                 throw;
  490.             }
  491.             // If we have an entity handler, tell it we are ending this entity
  492.             if (entHandler)
  493.                 entHandler->endInputSource(*srcUsed);
  494.         }
  495.         else {
  496.             // If it starts with the XML string, then parse a text decl
  497.             if (fScanner->checkXMLDecl(true))
  498.                 scanTextDecl();
  499.         }
  500.     }
  501.      else
  502.     {
  503.         // Create a reader over a memory stream over the entity value
  504.         XMLReader* valueReader = fReaderMgr->createIntEntReader
  505.         (
  506.             decl->getName()
  507.             , inLiteral ? XMLReader::RefFrom_Literal : XMLReader::RefFrom_NonLiteral
  508.             , XMLReader::Type_PE
  509.             , decl->getValue()
  510.             , decl->getValueLen()
  511.             , false
  512.         );
  513.         //
  514.         //  Trt to push the entity reader onto the reader manager stack,
  515.         //  where it will become the subsequent input. If it fails, that
  516.         //  means the entity is recursive, so issue an error. The reader
  517.         //  will have just been discarded, but we just keep going.
  518.         //
  519.         if (!fReaderMgr->pushReader(valueReader, decl))
  520.             fScanner->emitError(XMLErrs::RecursiveEntity, decl->getName());
  521.     }
  522.     return true;
  523. }
  524. bool DTDScanner::getQuotedString(XMLBuffer& toFill)
  525. {
  526.     // Reset the target buffer
  527.     toFill.reset();
  528.     // Get the next char which must be a single or double quote
  529.     XMLCh quoteCh;
  530.     if (!fReaderMgr->skipIfQuote(quoteCh))
  531.         return false;
  532.     while (true)
  533.     {
  534.         // Get another char
  535.         const XMLCh nextCh = fReaderMgr->getNextChar();
  536.         // See if it matches the starting quote char
  537.         if (nextCh == quoteCh)
  538.             break;
  539.         //
  540.         //  We should never get either an end of file null char here. If we
  541.         //  do, just fail. It will be handled more gracefully in the higher
  542.         //  level code that called us.
  543.         //
  544.         if (!nextCh)
  545.             return false;
  546.         // Else add it to the buffer
  547.         toFill.append(nextCh);
  548.     }
  549.     return true;
  550. }
  551. XMLAttDef*
  552. DTDScanner::scanAttDef(DTDElementDecl& parentElem, XMLBuffer& bufToUse)
  553. {
  554.     // Check for PE ref or optional whitespace
  555.     checkForPERef(false, false, true);
  556.     // Get the name of the attribute
  557.     if (!fReaderMgr->getName(bufToUse))
  558.     {
  559.         fScanner->emitError(XMLErrs::ExpectedAttrName);
  560.         return 0;
  561.     }
  562.     //
  563.     //  Look up this attribute in the parent element's attribute list. If
  564.     //  it already exists, then use the dummy.
  565.     //
  566.     DTDAttDef* decl = parentElem.getAttDef(bufToUse.getRawBuffer());
  567.     if (decl)
  568.     {
  569.         // It already exists, so put out a warning
  570.         fScanner->emitError
  571.         (
  572.             XMLErrs::AttListAlreadyExists
  573.             , bufToUse.getRawBuffer()
  574.             , parentElem.getFullName()
  575.         );
  576.         // Use the dummy decl to parse into and set its name to the name we got
  577.         if (!fDumAttDef)
  578.         {
  579.             fDumAttDef = new (fMemoryManager) DTDAttDef(fMemoryManager);
  580.             fDumAttDef->setId(fNextAttrId++);
  581.         }
  582.         fDumAttDef->setName(bufToUse.getRawBuffer());
  583.         decl = fDumAttDef;
  584.     }
  585.      else
  586.     {
  587.         //
  588.         //  It does not already exist so create a new one, give it the next
  589.         //  available unique id, and add it
  590.         //
  591.         decl = new (fMemoryManager) DTDAttDef
  592.         (
  593.             bufToUse.getRawBuffer()
  594.             , XMLAttDef::CData
  595.             , XMLAttDef::Implied
  596.             , fMemoryManager
  597.         );
  598.         decl->setId(fNextAttrId++);
  599.         decl->setExternalAttDeclaration(isReadingExternalEntity());
  600.         parentElem.addAttDef(decl);
  601.     }
  602.     // Set a flag to indicate whether we are doing a dummy parse
  603.     const bool isIgnored = (decl == fDumAttDef);
  604.     // Space is required here, so check for PE ref, and require space
  605.     if (!checkForPERef(true, false, true))
  606.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  607.     //
  608.     //  Next has to be one of the attribute type strings. This tells us what
  609.     //  is to follow.
  610.     //
  611.     if (fReaderMgr->skippedString(XMLUni::fgCDATAString))
  612.     {
  613.         decl->setType(XMLAttDef::CData);
  614.     }
  615.      else if (fReaderMgr->skippedString(XMLUni::fgIDString))
  616.     {
  617.         if (!fReaderMgr->skippedString(XMLUni::fgRefString))
  618.             decl->setType(XMLAttDef::ID);
  619.         else if (!fReaderMgr->skippedChar(chLatin_S))
  620.             decl->setType(XMLAttDef::IDRef);
  621.         else
  622.             decl->setType(XMLAttDef::IDRefs);
  623.     }
  624.      else if (fReaderMgr->skippedString(XMLUni::fgEntitString))
  625.     {
  626.         if (fReaderMgr->skippedChar(chLatin_Y))
  627.         {
  628.             decl->setType(XMLAttDef::Entity);
  629.         }
  630.          else if (fReaderMgr->skippedString(XMLUni::fgIESString))
  631.         {
  632.             decl->setType(XMLAttDef::Entities);
  633.         }
  634.          else
  635.         {
  636.             fScanner->emitError
  637.             (
  638.                 XMLErrs::ExpectedAttributeType
  639.                 , decl->getFullName()
  640.                 , parentElem.getFullName()
  641.             );
  642.             return 0;
  643.         }
  644.     }
  645.      else if (fReaderMgr->skippedString(XMLUni::fgNmTokenString))
  646.     {
  647.         if (fReaderMgr->skippedChar(chLatin_S))
  648.             decl->setType(XMLAttDef::NmTokens);
  649.         else
  650.             decl->setType(XMLAttDef::NmToken);
  651.     }
  652.      else if (fReaderMgr->skippedString(XMLUni::fgNotationString))
  653.     {
  654.         // Check for PE ref and require space
  655.         if (!checkForPERef(true, false, true))
  656.             fScanner->emitError(XMLErrs::ExpectedWhitespace);
  657.         decl->setType(XMLAttDef::Notation);
  658.         if (!scanEnumeration(*decl, bufToUse, true))
  659.             return 0;
  660.         // Set the value as the enumeration for this decl
  661.         decl->setEnumeration(bufToUse.getRawBuffer());
  662.     }
  663.      else if (fReaderMgr->skippedChar(chOpenParen))
  664.     {
  665.         decl->setType(XMLAttDef::Enumeration);
  666.         if (!scanEnumeration(*decl, bufToUse, false))
  667.             return 0;
  668.         // Set the value as the enumeration for this decl
  669.         decl->setEnumeration(bufToUse.getRawBuffer());
  670.     }
  671.      else
  672.     {
  673.         fScanner->emitError
  674.         (
  675.             XMLErrs::ExpectedAttributeType
  676.             , decl->getFullName()
  677.             , parentElem.getFullName()
  678.         );
  679.         return 0;
  680.     }
  681.     // Space is required here, so check for PE ref, and require space
  682.     if (!checkForPERef(true, false, true))
  683.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  684.     // And then scan for the optional default value declaration
  685.     scanDefaultDecl(*decl);
  686.     // If validating, then do a couple of validation constraints
  687.     if (fScanner->getDoValidation())
  688.     {
  689.         if (decl->getType() == XMLAttDef::ID)
  690.         {
  691.             if ((decl->getDefaultType() != XMLAttDef::Implied)
  692.             &&  (decl->getDefaultType() != XMLAttDef::Required))
  693.             {
  694.                 fScanner->getValidator()->emitError(XMLValid::BadIDAttrDefType, decl->getFullName());
  695.             }
  696.         }
  697.         // if attdef is xml:space, check correct enumeration (default|preserve)
  698.         const XMLCh fgXMLSpace[] = { chLatin_x, chLatin_m, chLatin_l, chColon, chLatin_s, chLatin_p, chLatin_a, chLatin_c, chLatin_e, chNull };
  699.         if (XMLString::equals(decl->getFullName(),fgXMLSpace)) {
  700.             const XMLCh fgPreserve[] = { chLatin_p, chLatin_r, chLatin_e, chLatin_s, chLatin_e, chLatin_r, chLatin_v, chLatin_e, chNull };
  701.             const XMLCh fgDefault[] = { chLatin_d, chLatin_e, chLatin_f, chLatin_a, chLatin_u, chLatin_l, chLatin_t, chNull };
  702.             bool ok = false;
  703.             if (decl->getType() == XMLAttDef::Enumeration) {
  704.                 BaseRefVectorOf<XMLCh>* enumVector = XMLString::tokenizeString(decl->getEnumeration());
  705.                 int size = enumVector->size();
  706.                 ok = (size == 1 &&
  707.                      (XMLString::equals(enumVector->elementAt(0), fgDefault) ||
  708.                       XMLString::equals(enumVector->elementAt(0), fgPreserve))) ||
  709.                      (size == 2 &&
  710.                      (XMLString::equals(enumVector->elementAt(0), fgDefault) &&
  711.                       XMLString::equals(enumVector->elementAt(1), fgPreserve))) ||
  712.                      (size == 2 &&
  713.                      (XMLString::equals(enumVector->elementAt(1), fgDefault) &&
  714.                       XMLString::equals(enumVector->elementAt(0), fgPreserve)));
  715.                 delete enumVector;
  716.             }
  717.             if (!ok)
  718.                 fScanner->getValidator()->emitError(XMLValid::IllegalXMLSpace);
  719.         }
  720.     }
  721.     // If we have a doc type handler, tell it about this attdef.
  722.     if (fDocTypeHandler)
  723.         fDocTypeHandler->attDef(parentElem, *decl, isIgnored);
  724.     return decl;
  725. }
  726. void DTDScanner::scanAttListDecl()
  727. {
  728.     // Space is required here, so check for a PE ref
  729.     if (!checkForPERef(true, false, true))
  730.     {
  731.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  732.         fReaderMgr->skipPastChar(chCloseAngle);
  733.         return;
  734.     }
  735.     //
  736.     //  Next should be the name of the element it belongs to, so get a buffer
  737.     //  and get the name into it.
  738.     //
  739.     XMLBufBid bbName(fBufMgr);
  740.     if (!fReaderMgr->getName(bbName.getBuffer()))
  741.     {
  742.         fScanner->emitError(XMLErrs::ExpectedElementName);
  743.         fReaderMgr->skipPastChar(chCloseAngle);
  744.         return;
  745.     }
  746.     //
  747.     //  Find this element's declaration. If it has not been declared yet,
  748.     //  we will force one into the list, but not mark it as declared.
  749.     //
  750.     DTDElementDecl* elemDecl = (DTDElementDecl*) fDTDGrammar->getElemDecl(fEmptyNamespaceId, 0, bbName.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE);
  751.     if (!elemDecl)
  752.     {
  753.         //
  754.         //  Lets fault in a declaration and add it to the pool. We mark
  755.         //  it having been created because of an attlist. Later, if its
  756.         //  declared, this will be updated.
  757.         //
  758.         elemDecl = new (fMemoryManager) DTDElementDecl
  759.         (
  760.             bbName.getRawBuffer()
  761.             , fEmptyNamespaceId
  762.             , DTDElementDecl::Any
  763.             , fMemoryManager
  764.         );
  765.         elemDecl->setCreateReason(XMLElementDecl::AttList);
  766.         elemDecl->setExternalElemDeclaration(isReadingExternalEntity());
  767.         fDTDGrammar->putElemDecl((XMLElementDecl*) elemDecl);
  768.     }
  769.     // If we have a doc type handler, tell it the att list is starting
  770.     if (fDocTypeHandler)
  771.         fDocTypeHandler->startAttList(*elemDecl);
  772.     //
  773.     //  Now we loop until we are done with all of the attributes in this
  774.     //  list. We need a buffer to use for local processing.
  775.     //
  776.     XMLBufBid   bbTmp(fBufMgr);
  777.     XMLBuffer&  tmpBuf = bbTmp.getBuffer();
  778.     bool        seenAnId = false;
  779.     while (true)
  780.     {
  781.         // Get the next char out and see what it tells us to do
  782.         const XMLCh nextCh = fReaderMgr->peekNextChar();
  783.         // Watch for EOF
  784.         if (!nextCh)
  785.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  786.         if (nextCh == chCloseAngle)
  787.         {
  788.             // We are done with this attribute list
  789.             fReaderMgr->getNextChar();
  790.             break;
  791.         }
  792.          else if (fReaderMgr->getCurrentReader()->isWhitespace(nextCh))
  793.         {
  794.             //
  795.             //  If advanced callbacks are enabled and we have a doc
  796.             //  type handler, then gather up the white space and call
  797.             //  back on the doctype handler. Otherwise, just skip
  798.             //  whitespace.
  799.             //
  800.             if (fDocTypeHandler)
  801.             {
  802.                 fReaderMgr->getSpaces(tmpBuf);
  803.                 fDocTypeHandler->doctypeWhitespace
  804.                 (
  805.                     tmpBuf.getRawBuffer()
  806.                     , tmpBuf.getLen()
  807.                 );
  808.             }
  809.              else
  810.             {
  811.                 fReaderMgr->skipPastSpaces();
  812.             }
  813.         }
  814.          else if (nextCh == chPercent)
  815.         {
  816.             // Eat the percent and expand the ref
  817.             fReaderMgr->getNextChar();
  818.             expandPERef(false, false, true);
  819.         }
  820.          else
  821.         {
  822.             //
  823.             //  It must be an attribute name, so scan it. We let
  824.             //  it use our local buffer for its name scanning.
  825.             //
  826.             XMLAttDef* attDef = scanAttDef(*elemDecl, tmpBuf);
  827.             if (!attDef)
  828.             {
  829.                 fReaderMgr->skipPastChar(chCloseAngle);
  830.                 break;
  831.             }
  832.             //
  833.             //  If we are validating and its an ID type, then we have to
  834.             //  make sure that we have not seen an id attribute yet. Set
  835.             //  the flag to say that we've seen one now also.
  836.             //
  837.             if (fScanner->getDoValidation())
  838.             {
  839.                 if (attDef->getType() == XMLAttDef::ID)
  840.                 {
  841.                     if (seenAnId)
  842.                         fScanner->getValidator()->emitError(XMLValid::MultipleIdAttrs, elemDecl->getFullName());
  843.                     seenAnId = true;
  844.                 }
  845.             }
  846.         }
  847.     }
  848.     // If we have a doc type handler, tell it the att list is ending
  849.     if (fDocTypeHandler)
  850.         fDocTypeHandler->endAttList(*elemDecl);
  851. }
  852. //
  853. //  This method is called to scan the value of an attribute in content. This
  854. //  involves some normalization and replacement of general entity and
  855. //  character references.
  856. //
  857. //  End of entity's must be dealt with here. During DTD scan, they can come
  858. //  from external entities. During content, they can come from any entity.
  859. //  We just eat the end of entity and continue with our scan until we come
  860. //  to the closing quote. If an unterminated value causes us to go through
  861. //  subsequent entities, that will cause errors back in the calling code,
  862. //  but there's little we can do about it here.
  863. //
  864. bool DTDScanner::scanAttValue(const   XMLCh* const        attrName
  865.                                 ,       XMLBuffer&          toFill
  866.                                 , const XMLAttDef::AttTypes type)
  867. {
  868.     enum States
  869.     {
  870.         InWhitespace
  871.         , InContent
  872.     };
  873.     // Reset the target buffer
  874.     toFill.reset();
  875.     // Get the next char which must be a single or double quote
  876.     XMLCh quoteCh;
  877.     if (!fReaderMgr->skipIfQuote(quoteCh))
  878.         return false;
  879.     //
  880.     //  We have to get the current reader because we have to ignore closing
  881.     //  quotes until we hit the same reader again.
  882.     //
  883.     const unsigned int curReader = fReaderMgr->getCurrentReaderNum();
  884.     //
  885.     //  Loop until we get the attribute value. Note that we use a double
  886.     //  loop here to avoid the setup/teardown overhead of the exception
  887.     //  handler on every round.
  888.     //
  889.     XMLCh   nextCh;
  890.     XMLCh   secondCh = 0;
  891.     States  curState = InContent;
  892.     bool    firstNonWS = false;
  893.     bool    gotLeadingSurrogate = false;
  894.     bool    escaped;
  895.     while (true)
  896.     {
  897.     try
  898.     {
  899.         while(true)
  900.         {
  901.             nextCh = fReaderMgr->getNextChar();
  902.             if (!nextCh)
  903.                 ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  904.             // Check for our ending quote in the same entity
  905.             if (nextCh == quoteCh)
  906.             {
  907.                 if (curReader == fReaderMgr->getCurrentReaderNum())
  908.                     return true;
  909.                 // Watch for spillover into a previous entity
  910.                 if (curReader > fReaderMgr->getCurrentReaderNum())
  911.                 {
  912.                     fScanner->emitError(XMLErrs::PartialMarkupInEntity);
  913.                     return false;
  914.                 }
  915.             }
  916.             //
  917.             //  Check for an entity ref now, before we let it affect our
  918.             //  whitespace normalization logic below. We ignore the empty flag
  919.             //  in this one.
  920.             //
  921.             escaped = false;
  922.             if (nextCh == chAmpersand)
  923.             {
  924.                 if (scanEntityRef(nextCh, secondCh, escaped) != EntityExp_Returned)
  925.                 {
  926.                     gotLeadingSurrogate = false;
  927.                     continue;
  928.                 }
  929.             }
  930.             else if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
  931.             {
  932.                 // Check for correct surrogate pairs
  933.                 if (gotLeadingSurrogate)
  934.                     fScanner->emitError(XMLErrs::Expected2ndSurrogateChar);
  935.                 else
  936.                     gotLeadingSurrogate = true;
  937.             }
  938.              else
  939.             {
  940.                 if (gotLeadingSurrogate)
  941.                 {
  942.                     if ((nextCh < 0xDC00) || (nextCh > 0xDFFF))
  943.                         fScanner->emitError(XMLErrs::Expected2ndSurrogateChar);
  944.                 }
  945.                 // Its got to at least be a valid XML character
  946.                 else if (!fReaderMgr->getCurrentReader()->isXMLChar(nextCh))
  947.                 {
  948.                     XMLCh tmpBuf[9];
  949.                     XMLString::binToText
  950.                     (
  951.                         nextCh
  952.                         , tmpBuf
  953.                         , 8
  954.                         , 16
  955.                     );
  956.                     fScanner->emitError
  957.                     (
  958.                         XMLErrs::InvalidCharacterInAttrValue
  959.                         , attrName
  960.                         , tmpBuf
  961.                     );
  962.                 }
  963.                 gotLeadingSurrogate = false;
  964.             }
  965.             //
  966.             //  If its not escaped, then make sure its not a < character, which
  967.             //  is not allowed in attribute values.
  968.             //
  969.             if (!escaped && (nextCh == chOpenAngle))
  970.                 fScanner->emitError(XMLErrs::BracketInAttrValue, attrName);
  971.             //
  972.             //  If the attribute is a CDATA type we do simple replacement of
  973.             //  tabs and new lines with spaces, if the character is not escaped
  974.             //  by way of a char ref.
  975.             //
  976.             //  Otherwise, we do the standard non-CDATA normalization of
  977.             //  compressing whitespace to single spaces and getting rid of
  978.             //  leading and trailing whitespace.
  979.             //
  980.             if (type == XMLAttDef::CData)
  981.             {
  982.                 if (!escaped)
  983.                 {
  984.                     if ((nextCh == 0x09) || (nextCh == 0x0A) || (nextCh == 0x0D))
  985.                         nextCh = chSpace;
  986.                 }
  987.             }
  988.              else
  989.             {
  990.                 if (curState == InWhitespace)
  991.                 {
  992.                     if (!fReaderMgr->getCurrentReader()->isWhitespace(nextCh))
  993.                     {
  994.                         if (firstNonWS)
  995.                             toFill.append(chSpace);
  996.                         curState = InContent;
  997.                         firstNonWS = true;
  998.                     }
  999.                      else
  1000.                     {
  1001.                         continue;
  1002.                     }
  1003.                 }
  1004.                  else if (curState == InContent)
  1005.                 {
  1006.                     if (fReaderMgr->getCurrentReader()->isWhitespace(nextCh))
  1007.                     {
  1008.                         curState = InWhitespace;
  1009.                         continue;
  1010.                     }
  1011.                     firstNonWS = true;
  1012.                 }
  1013.             }
  1014.             // Else add it to the buffer
  1015.             toFill.append(nextCh);
  1016.             if (secondCh)
  1017.                toFill.append(secondCh);
  1018.         }
  1019.     }
  1020.     catch(const EndOfEntityException&)
  1021.     {
  1022.         // Just eat it and continue.
  1023.         gotLeadingSurrogate = false;
  1024.         escaped = false;
  1025.     }
  1026.     }
  1027.     return true;
  1028. }
  1029. bool DTDScanner::scanCharRef(XMLCh& first, XMLCh& second)
  1030. {
  1031.     bool gotOne = false;
  1032.     unsigned int value = 0;
  1033.     //
  1034.     //  Set the radix. Its supposed to be a lower case x if hex. But, in
  1035.     //  order to recover well, we check for an upper and put out an error
  1036.     //  for that.
  1037.     //
  1038.     unsigned int radix = 10;
  1039.     if (fReaderMgr->skippedChar(chLatin_x))
  1040.     {
  1041.         radix = 16;
  1042.     }
  1043.      else if (fReaderMgr->skippedChar(chLatin_X))
  1044.     {
  1045.         fScanner->emitError(XMLErrs::HexRadixMustBeLowerCase);
  1046.         radix = 16;
  1047.     }
  1048.     while (true)
  1049.     {
  1050.         const XMLCh nextCh = fReaderMgr->peekNextChar();
  1051.         // Watch for EOF
  1052.         if (!nextCh)
  1053.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  1054.         // Break out on the terminating semicolon
  1055.         if (nextCh == chSemiColon)
  1056.         {
  1057.             fReaderMgr->getNextChar();
  1058.             break;
  1059.         }
  1060.         //
  1061.         //  Convert this char to a binary value, or bail out if its not
  1062.         //  one.
  1063.         //
  1064.         unsigned int nextVal;
  1065.         if ((nextCh >= chDigit_0) && (nextCh <= chDigit_9))
  1066.             nextVal = (unsigned int)(nextCh - chDigit_0);
  1067.         else if ((nextCh >= chLatin_A) && (nextCh <= chLatin_F))
  1068.             nextVal= (unsigned int)(10 + (nextCh - chLatin_A));
  1069.         else if ((nextCh >= chLatin_a) && (nextCh <= chLatin_f))
  1070.             nextVal = (unsigned int)(10 + (nextCh - chLatin_a));
  1071.         else
  1072.         {
  1073.             //
  1074.             //  If we got at least a sigit, then do an unterminated ref
  1075.             //  error. Else, do an expected a numerical ref thing.
  1076.             //
  1077.             if (gotOne)
  1078.                 fScanner->emitError(XMLErrs::UnterminatedCharRef);
  1079.             else
  1080.                 fScanner->emitError(XMLErrs::ExpectedNumericalCharRef);
  1081.             return false;
  1082.         }
  1083.         //
  1084.         //  Make sure its valid for the radix. If not, then just eat the
  1085.         //  digit and go on after issueing an error. Else, update the
  1086.         //  running value with this new digit.
  1087.         //
  1088.         if (nextVal >= radix)
  1089.         {
  1090.             XMLCh tmpStr[2];
  1091.             tmpStr[0] = nextCh;
  1092.             tmpStr[1] = chNull;
  1093.             fScanner->emitError(XMLErrs::BadDigitForRadix, tmpStr);
  1094.         }
  1095.          else
  1096.         {
  1097.             value = (value * radix) + nextVal;
  1098.         }
  1099.         // Indicate that we got at least one good digit
  1100.         gotOne = true;
  1101.         // Eat the char we just processed
  1102.         fReaderMgr->getNextChar();
  1103.     }
  1104.     // Return the char (or chars)
  1105.     // And check if the character expanded is valid or not
  1106.     if (value >= 0x10000 && value <= 0x10FFFF)
  1107.     {
  1108.         value -= 0x10000;
  1109.         first  = XMLCh((value >> 10) + 0xD800);
  1110.         second = XMLCh((value & 0x3FF) + 0xDC00);
  1111.     }
  1112.     else if (value <= 0xFFFD)
  1113.     {
  1114.         first  = XMLCh(value);
  1115.         second = 0;
  1116.         if (!fReaderMgr->getCurrentReader()->isXMLChar(first) && !fReaderMgr->getCurrentReader()->isControlChar(first)) {
  1117.             // Character reference was not in the valid range
  1118.             fScanner->emitError(XMLErrs::InvalidCharacterRef);
  1119.             return false;
  1120.         }
  1121.     }
  1122.     else {
  1123.         // Character reference was not in the valid range
  1124.         fScanner->emitError(XMLErrs::InvalidCharacterRef);
  1125.         return false;
  1126.     }
  1127.     return true;
  1128. }
  1129. ContentSpecNode*
  1130. DTDScanner::scanChildren(const DTDElementDecl& elemDecl, XMLBuffer& bufToUse)
  1131. {
  1132.     // Check for a PE ref here, but don't require spaces
  1133.     checkForPERef(false, false, true);
  1134.     // We have to check entity nesting here
  1135.     unsigned int curReader;
  1136.     //
  1137.     //  We know that the caller just saw an opening parenthesis, so we need
  1138.     //  to parse until we hit the end of it, recursing for other nested
  1139.     //  parentheses we see.
  1140.     //
  1141.     //  We have to check for one up front, since it could be something like
  1142.     //  (((a)*)) etc...
  1143.     //
  1144.     ContentSpecNode* curNode = 0;
  1145.     if (fReaderMgr->skippedChar(chOpenParen))
  1146.     {
  1147.         curReader = fReaderMgr->getCurrentReaderNum();
  1148.         // Lets call ourself and get back the resulting node
  1149.         curNode = scanChildren(elemDecl, bufToUse);
  1150.         // If that failed, no need to go further, return failure
  1151.         if (!curNode)
  1152.             return 0;
  1153.         if (curReader != fReaderMgr->getCurrentReaderNum() && fScanner->getDoValidation())
  1154.             fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE);
  1155.     }
  1156.      else
  1157.     {
  1158.         // Not a nested paren, so it must be a leaf node
  1159.         if (!fReaderMgr->getName(bufToUse))
  1160.         {
  1161.             fScanner->emitError(XMLErrs::ExpectedElementName);
  1162.             return 0;
  1163.         }
  1164.         //
  1165.         //  Create a leaf node for it. If we can find the element id for
  1166.         //  this element, then use it. Else, we have to fault in an element
  1167.         //  decl, marked as created because of being in a content model.
  1168.         //
  1169.         XMLElementDecl* decl = fDTDGrammar->getElemDecl(fEmptyNamespaceId, 0, bufToUse.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE);
  1170.         if (!decl)
  1171.         {
  1172.             decl = new (fMemoryManager) DTDElementDecl
  1173.             (
  1174.                 bufToUse.getRawBuffer()
  1175.                 , fEmptyNamespaceId
  1176.                 , DTDElementDecl::Any
  1177.                 , fMemoryManager
  1178.             );
  1179.             decl->setCreateReason(XMLElementDecl::InContentModel);
  1180.             decl->setExternalElemDeclaration(isReadingExternalEntity());
  1181.             fDTDGrammar->putElemDecl(decl);
  1182.         }
  1183.         curNode = new (fMemoryManager) ContentSpecNode
  1184.         (
  1185.             decl->getElementName()
  1186.             , fMemoryManager
  1187.         );
  1188.         // Check for a PE ref here, but don't require spaces
  1189.         const bool gotSpaces = checkForPERef(false, false, true);
  1190.         // Check for a repetition character after the leaf
  1191.         const XMLCh repCh = fReaderMgr->peekNextChar();
  1192.         ContentSpecNode* tmpNode = makeRepNode(repCh, curNode, fMemoryManager);
  1193.         if (tmpNode != curNode)
  1194.         {
  1195.             if (gotSpaces)
  1196.                 fScanner->emitError(XMLErrs::UnexpectedWhitespace);
  1197.             fReaderMgr->getNextChar();
  1198.             curNode = tmpNode;
  1199.         }
  1200.     }
  1201.     // Check for a PE ref here, but don't require spaces
  1202.     checkForPERef(false, false, true);
  1203.     //
  1204.     //  Ok, the next character tells us what kind of content this particular
  1205.     //  model this particular parentesized section is. Its either a choice if
  1206.     //  we see ',', a sequence if we see '|', or a single leaf node if we see
  1207.     //  a closing paren.
  1208.     //
  1209.     const XMLCh opCh = fReaderMgr->peekNextChar();
  1210.     if ((opCh != chComma)
  1211.     &&  (opCh != chPipe)
  1212.     &&  (opCh != chCloseParen))
  1213.     {
  1214.         // Not a legal char, so delete our node and return failure
  1215.         delete curNode;
  1216.         fScanner->emitError(XMLErrs::ExpectedSeqChoiceLeaf);
  1217.         return 0;
  1218.     }
  1219.     //
  1220.     //  Create the head node of the correct type. We need this to remember
  1221.     //  the top of the local tree. If it was a single subexpr, then just
  1222.     //  set the head node to the current node. For the others, we'll build
  1223.     //  the tree off the second child as we move across.
  1224.     //
  1225.     ContentSpecNode* headNode = 0;
  1226.     ContentSpecNode::NodeTypes curType = ContentSpecNode::UnknownType;
  1227.     if (opCh == chComma)
  1228.     {
  1229.         curType = ContentSpecNode::Sequence;
  1230.         headNode = new (fMemoryManager) ContentSpecNode
  1231.         (
  1232.             curType
  1233.             , curNode
  1234.             , 0
  1235.             , true
  1236.             , true
  1237.             , fMemoryManager
  1238.         );
  1239.         curNode = headNode;
  1240.     }
  1241.      else if (opCh == chPipe)
  1242.     {
  1243.         curType = ContentSpecNode::Choice;
  1244.         headNode = new (fMemoryManager) ContentSpecNode
  1245.         (
  1246.             curType
  1247.             , curNode
  1248.             , 0
  1249.             , true
  1250.             , true
  1251.             , fMemoryManager
  1252.         );
  1253.         curNode = headNode;
  1254.     }
  1255.      else
  1256.     {
  1257.         headNode = curNode;
  1258.         fReaderMgr->getNextChar();
  1259.     }
  1260.     //
  1261.     //  If it was a sequence or choice, we just loop until we get to the
  1262.     //  end of our section, adding each new leaf or sub expression to the
  1263.     //  right child of the current node, and making that new node the current
  1264.     //  node.
  1265.     //
  1266.     if ((opCh == chComma) || (opCh == chPipe))
  1267.     {
  1268.         ContentSpecNode* lastNode = 0;
  1269.         while (true)
  1270.         {
  1271.             //
  1272.             //  The next thing must either be another | or , character followed
  1273.             //  by another leaf or subexpression, or a closing parenthesis, or a
  1274.             //  PE ref.
  1275.             //
  1276.             if (fReaderMgr->lookingAtChar(chPercent))
  1277.             {
  1278.                 checkForPERef(false, false, true);
  1279.             }
  1280.              else if (fReaderMgr->skippedSpace())
  1281.             {
  1282.                 // Just skip whitespace
  1283.                 fReaderMgr->skipPastSpaces();
  1284.             }
  1285.              else if (fReaderMgr->skippedChar(chCloseParen))
  1286.             {
  1287.                 //
  1288.                 //  We've hit the end of this section, so break out. But, we
  1289.                 //  need to see if we left a partial sequence of choice node
  1290.                 //  without a second node. If so, we have to undo that and
  1291.                 //  put its left child into the right node of the previous
  1292.                 //  node.
  1293.                 //
  1294.                 if ((curNode->getType() == ContentSpecNode::Choice)
  1295.                 ||  (curNode->getType() == ContentSpecNode::Sequence))
  1296.                 {
  1297.                     if (!curNode->getSecond())
  1298.                     {
  1299.                         ContentSpecNode* saveFirst = curNode->orphanFirst();
  1300.                         lastNode->setSecond(saveFirst);
  1301.                         curNode = lastNode;
  1302.                     }
  1303.                 }
  1304.                 break;
  1305.             }
  1306.              else if (fReaderMgr->skippedChar(opCh))
  1307.             {
  1308.                 // Check for a PE ref here, but don't require spaces
  1309.                 checkForPERef(false, false, true);
  1310.                 if (fReaderMgr->skippedChar(chOpenParen))
  1311.                 {
  1312.                     curReader = fReaderMgr->getCurrentReaderNum();
  1313.                     // Recurse to handle this new guy
  1314.                     ContentSpecNode* subNode = scanChildren(elemDecl, bufToUse);
  1315.                     // If it failed, we are done, clean up here and return failure
  1316.                     if (!subNode)
  1317.                     {
  1318.                         delete headNode;
  1319.                         return 0;
  1320.                     }
  1321.                     if (curReader != fReaderMgr->getCurrentReaderNum() && fScanner->getDoValidation())
  1322.                         fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE);
  1323.                     // Else patch it in and make it the new current
  1324.                     ContentSpecNode* newCur = new (fMemoryManager) ContentSpecNode
  1325.                     (
  1326.                         curType
  1327.                         , subNode
  1328.                         , 0
  1329.                         , true
  1330.                         , true
  1331.                         , fMemoryManager
  1332.                     );
  1333.                     curNode->setSecond(newCur);
  1334.                     lastNode = curNode;
  1335.                     curNode = newCur;
  1336.                 }
  1337.                  else
  1338.                 {
  1339.                     //
  1340.                     //  Got to be a leaf node, so get a name. If we cannot get
  1341.                     //  one, then clean up and get outa here.
  1342.                     //
  1343.                     if (!fReaderMgr->getName(bufToUse))
  1344.                     {
  1345.                         delete headNode;
  1346.                         fScanner->emitError(XMLErrs::ExpectedElementName);
  1347.                         return 0;
  1348.                     }
  1349.                     //
  1350.                     //  Create a leaf node for it. If we can find the element
  1351.                     //  id for this element, then use it. Else, we have to
  1352.                     //  fault in an element decl, marked as created because
  1353.                     //  of being in a content model.
  1354.                     //
  1355.                     XMLElementDecl* decl = fDTDGrammar->getElemDecl(fEmptyNamespaceId, 0, bufToUse.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE);
  1356.                     if (!decl)
  1357.                     {
  1358.                         decl = new (fMemoryManager) DTDElementDecl
  1359.                         (
  1360.                             bufToUse.getRawBuffer()
  1361.                             , fEmptyNamespaceId
  1362.                             , DTDElementDecl::Any
  1363.                             , fMemoryManager
  1364.                         );
  1365.                         decl->setCreateReason(XMLElementDecl::InContentModel);
  1366.                         decl->setExternalElemDeclaration(isReadingExternalEntity());
  1367.                         fDTDGrammar->putElemDecl(decl);
  1368.                     }
  1369.                     ContentSpecNode* tmpLeaf = new (fMemoryManager) ContentSpecNode
  1370.                     (
  1371.                         decl->getElementName()
  1372.                         , fMemoryManager
  1373.                     );
  1374.                     // Check for a repetition character after the leaf
  1375.                     const XMLCh repCh = fReaderMgr->peekNextChar();
  1376.                     ContentSpecNode* tmpLeaf2 = makeRepNode(repCh, tmpLeaf, fMemoryManager);
  1377.                     if (tmpLeaf != tmpLeaf2)
  1378.                         fReaderMgr->getNextChar();
  1379.                     //
  1380.                     //  Create a new sequence or choice node, with the leaf
  1381.                     //  (or rep surrounding it) we just got as its first node.
  1382.                     //  Make the new node the second node of the current node,
  1383.                     //  and then make it the current node.
  1384.                     //
  1385.                     ContentSpecNode* newCur = new (fMemoryManager) ContentSpecNode
  1386.                     (
  1387.                         curType
  1388.                         , tmpLeaf2
  1389.                         , 0
  1390.                         , true
  1391.                         , true
  1392.                         , fMemoryManager
  1393.                     );
  1394.                     curNode->setSecond(newCur);
  1395.                     lastNode = curNode;
  1396.                     curNode = newCur;
  1397.                 }
  1398.             }
  1399.              else
  1400.             {
  1401.                 // Cannot be valid
  1402.                 if (opCh == chComma)
  1403.                 {
  1404.                     fScanner->emitError(XMLErrs::ExpectedChoiceOrCloseParen);
  1405.                 }
  1406.                  else
  1407.                 {
  1408.                     fScanner->emitError
  1409.                     (
  1410.                         XMLErrs::ExpectedSeqOrCloseParen
  1411.                         , elemDecl.getFullName()
  1412.                     );
  1413.                 }
  1414.                 delete headNode;
  1415.                 return 0;
  1416.             }
  1417.         }
  1418.     }
  1419.     //
  1420.     //  We saw the terminating parenthesis so lets check for any repetition
  1421.     //  character, and create a node for that, making the head node the child
  1422.     //  of it.
  1423.     //
  1424.     XMLCh repCh = fReaderMgr->peekNextChar();
  1425.     ContentSpecNode* retNode = makeRepNode(repCh, headNode, fMemoryManager);
  1426.     if (retNode != headNode)
  1427.         fReaderMgr->getNextChar();
  1428.     return retNode;
  1429. }
  1430. //
  1431. //  We get here after the '<!--' part of the comment. We scan past the
  1432. //  terminating '-->' It will calls the appropriate handler with the comment
  1433. //  text, if one is provided. A comment can be in either the document or
  1434. //  the DTD, so the fInDocument flag is used to know which handler to send
  1435. //  it to.
  1436. //
  1437. void DTDScanner::scanComment()
  1438. {
  1439.     enum States
  1440.     {
  1441.         InText
  1442.         , OneDash
  1443.         , TwoDashes
  1444.     };
  1445.     // Get a buffer for this
  1446.     XMLBufBid bbComment(fBufMgr);
  1447.     //
  1448.     //  Get the comment text into a temp buffer. Be sure to use temp buffer
  1449.     //  two here, since its to be used for stuff that is potentially longer
  1450.     //  than just a name.
  1451.     //
  1452.     bool   gotLeadingSurrogate = false;
  1453.     States curState = InText;
  1454.     while (true)
  1455.     {
  1456.         // Get the next character
  1457.         const XMLCh nextCh = fReaderMgr->getNextChar();
  1458.         //  Watch for an end of file
  1459.         if (!nextCh)
  1460.         {
  1461.             fScanner->emitError(XMLErrs::UnterminatedComment);
  1462.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  1463.         }
  1464.         // Check for correct surrogate pairs
  1465.         if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
  1466.         {
  1467.             if (gotLeadingSurrogate)
  1468.                 fScanner->emitError(XMLErrs::Expected2ndSurrogateChar);
  1469.             else
  1470.                 gotLeadingSurrogate = true;
  1471.         }
  1472.         else
  1473.         {
  1474.             if (gotLeadingSurrogate)
  1475.             {
  1476.                 if ((nextCh < 0xDC00) || (nextCh > 0xDFFF))
  1477.                     fScanner->emitError(XMLErrs::Expected2ndSurrogateChar);
  1478.             }
  1479.             // Its got to at least be a valid XML character
  1480.             else if (!fReaderMgr->getCurrentReader()->isXMLChar(nextCh)) {
  1481.                 XMLCh tmpBuf[9];
  1482.                 XMLString::binToText
  1483.                 (
  1484.                     nextCh
  1485.                     , tmpBuf
  1486.                     , 8
  1487.                     , 16
  1488.                 );
  1489.                 fScanner->emitError(XMLErrs::InvalidCharacter, tmpBuf);
  1490.             }
  1491.             gotLeadingSurrogate = false;
  1492.         }
  1493.         if (curState == InText)
  1494.         {
  1495.             // If its a dash, go to OneDash state. Otherwise take as text
  1496.             if (nextCh == chDash)
  1497.                 curState = OneDash;
  1498.             else
  1499.                 bbComment.append(nextCh);
  1500.         }
  1501.          else if (curState == OneDash)
  1502.         {
  1503.             //
  1504.             //  If its another dash, then we change to the two dashes states.
  1505.             //  Otherwise, we have to put in the deficit dash and the new
  1506.             //  character and go back to InText.
  1507.             //
  1508.             if (nextCh == chDash)
  1509.             {
  1510.                 curState = TwoDashes;
  1511.             }
  1512.              else
  1513.             {
  1514.                 bbComment.append(chDash);
  1515.                 bbComment.append(nextCh);
  1516.                 curState = InText;
  1517.             }
  1518.         }
  1519.          else if (curState == TwoDashes)
  1520.         {
  1521.             // The next character must be the closing bracket
  1522.             if (nextCh != chCloseAngle)
  1523.             {
  1524.                 fScanner->emitError(XMLErrs::IllegalSequenceInComment);
  1525.                 fReaderMgr->skipPastChar(chCloseAngle);
  1526.                 return;
  1527.             }
  1528.             break;
  1529.         }
  1530.     }
  1531.     // If there is a doc type handler, then pass on the comment stuff
  1532.     if (fDocTypeHandler)
  1533.         fDocTypeHandler->doctypeComment(bbComment.getRawBuffer());
  1534. }
  1535. bool DTDScanner::scanContentSpec(DTDElementDecl& toFill)
  1536. {
  1537.     //
  1538.     //  Check for for a couple of the predefined content type strings. If
  1539.     //  its not one of these, its got to be a parenthesized reg ex type
  1540.     //  expression.
  1541.     //
  1542.     if (fReaderMgr->skippedString(XMLUni::fgEmptyString))
  1543.     {
  1544.         toFill.setModelType(DTDElementDecl::Empty);
  1545.         return true;
  1546.     }
  1547.     if (fReaderMgr->skippedString(XMLUni::fgAnyString))
  1548.     {
  1549.         toFill.setModelType(DTDElementDecl::Any);
  1550.         return true;
  1551.     }
  1552.     // Its got to be a parenthesized regular expression
  1553.     if (!fReaderMgr->skippedChar(chOpenParen))
  1554.     {
  1555.         fScanner->emitError
  1556.         (
  1557.             XMLErrs::ExpectedContentSpecExpr
  1558.             , toFill.getFullName()
  1559.         );
  1560.         return false;
  1561.     }
  1562.     // Get the current reader id, so we can test for partial markup
  1563.     const unsigned int curReader = fReaderMgr->getCurrentReaderNum();
  1564.     // We could have a PE ref here, but don't require space
  1565.     checkForPERef(false, false, true);
  1566.     //
  1567.     //  Now we look for a PCDATA string. If its PCDATA, then it must be a
  1568.     //  MIXED model. Otherwise, it must be a regular list of children in
  1569.     //  a regular expression perhaps.
  1570.     //
  1571.     bool status;
  1572.     if (fReaderMgr->skippedString(XMLUni::fgPCDATAString))
  1573.     {
  1574.         // Set the model to mixed
  1575.         toFill.setModelType(DTDElementDecl::Mixed_Simple);
  1576.         status = scanMixed(toFill);
  1577.         //
  1578.         //  If we are validating we have to check that there are no multiple
  1579.         //  uses of any child elements.
  1580.         //
  1581.         if (fScanner->getDoValidation())
  1582.         {
  1583.             if (((const MixedContentModel*)toFill.getContentModel())->hasDups())
  1584.                 fScanner->getValidator()->emitError(XMLValid::RepElemInMixed);
  1585.         }
  1586.     }
  1587.      else
  1588.     {
  1589.         //
  1590.         //  We have to do a recursive scan of the content model. Create a
  1591.         //  buffer for it to use, for efficiency. It returns the top ofthe
  1592.         //  content spec node tree, which we set if successful.
  1593.         //
  1594.         toFill.setModelType(DTDElementDecl::Children);
  1595.         XMLBufBid bbTmp(fBufMgr);
  1596.         ContentSpecNode* resNode = scanChildren(toFill, bbTmp.getBuffer());
  1597.         status = (resNode != 0);
  1598.         if (status)
  1599.             toFill.setContentSpec(resNode);
  1600.     }
  1601.     // Make sure we are on the same reader as where we started
  1602.     if (curReader != fReaderMgr->getCurrentReaderNum() && fScanner->getDoValidation())
  1603.         fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE);
  1604.     return status;
  1605. }
  1606. void DTDScanner::scanDefaultDecl(DTDAttDef& toFill)
  1607. {
  1608.     if (fReaderMgr->skippedString(XMLUni::fgRequiredString))
  1609.     {
  1610.         toFill.setDefaultType(XMLAttDef::Required);
  1611.         return;
  1612.     }
  1613.     if (fReaderMgr->skippedString(XMLUni::fgImpliedString))
  1614.     {
  1615.         toFill.setDefaultType(XMLAttDef::Implied);
  1616.         return;
  1617.     }
  1618.     if (fReaderMgr->skippedString(XMLUni::fgFixedString))
  1619.     {
  1620.         //
  1621.         //  There must be space before the fixed value. If there is not, then
  1622.         //  emit an error but keep going.
  1623.         //
  1624.         if (!fReaderMgr->skippedSpace())
  1625.             fScanner->emitError(XMLErrs::ExpectedWhitespace);
  1626.         else
  1627.             fReaderMgr->skipPastSpaces();
  1628.         toFill.setDefaultType(XMLAttDef::Fixed);
  1629.     }
  1630.      else
  1631.     {
  1632.         toFill.setDefaultType(XMLAttDef::Default);
  1633.     }
  1634.     //
  1635.     //  If we got here, its fixed or default, so we need to get a value.
  1636.     //  If we don't, then emit an error but just set the default value to
  1637.     //  an empty string and try to keep going.
  1638.     //
  1639.     // Check for PE ref or optional whitespace
  1640.     checkForPERef(false, false, true);
  1641.     XMLBufBid bbValue(fBufMgr);
  1642.     if (!scanAttValue(toFill.getFullName(), bbValue.getBuffer(), toFill.getType()))
  1643.         fScanner->emitError(XMLErrs::ExpectedDefAttrDecl);
  1644.     toFill.setValue(bbValue.getRawBuffer());
  1645. }
  1646. //
  1647. //  This is called after seeing '<!ELEMENT' which indicates that an element
  1648. //  markup is starting. This guy scans the rest of it and adds it to the
  1649. //  element decl pool if it has not already been declared.
  1650. //
  1651. void DTDScanner::scanElementDecl()
  1652. {
  1653.     //
  1654.     //  Space is legal (required actually) here so check for a PE ref. If
  1655.     //  we don't get our whitespace, then issue and error, but try to keep
  1656.     //  going.
  1657.     //
  1658.     if (!checkForPERef(true, false, true))
  1659.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  1660.     // Get a buffer for the element name and scan in the name
  1661.     XMLBufBid bbName(fBufMgr);
  1662.     if (!fReaderMgr->getName(bbName.getBuffer()))
  1663.     {
  1664.         fScanner->emitError(XMLErrs::ExpectedElementName);
  1665.         fReaderMgr->skipPastChar(chCloseAngle);
  1666.         return;
  1667.     }
  1668.     // Look this guy up in the element decl pool
  1669.     DTDElementDecl* decl = (DTDElementDecl*) fDTDGrammar->getElemDecl(fEmptyNamespaceId, 0, bbName.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE);
  1670.     //
  1671.     //  If it does not exist, then we need to create it. If it does and
  1672.     //  its marked as declared, then that's an error, but we still need to
  1673.     //  scan over the content model so use the dummy declaration that the
  1674.     //  parsing code can fill in.
  1675.     //
  1676.     if (decl)
  1677.     {
  1678.         if (decl->isDeclared())
  1679.         {
  1680.             if (fScanner->getDoValidation())
  1681.                 fScanner->getValidator()->emitError(XMLValid::ElementAlreadyExists, bbName.getRawBuffer());
  1682.             if (!fDumElemDecl)
  1683.                 fDumElemDecl = new (fMemoryManager) DTDElementDecl
  1684.                 (
  1685.                     bbName.getRawBuffer()
  1686.                     , fEmptyNamespaceId
  1687.                     , DTDElementDecl::Any
  1688.                     , fMemoryManager
  1689.                 );
  1690.             else
  1691.                 fDumElemDecl->setElementName(bbName.getRawBuffer(),fEmptyNamespaceId);
  1692.         }
  1693.     }
  1694.      else
  1695.     {
  1696.         //
  1697.         //  Create the new empty declaration to fill in and put it into
  1698.         //  the decl pool.
  1699.         //
  1700.         decl = new (fMemoryManager) DTDElementDecl
  1701.         (
  1702.             bbName.getRawBuffer()
  1703.             , fEmptyNamespaceId
  1704.             , DTDElementDecl::Any
  1705.             , fMemoryManager
  1706.         );
  1707.         fDTDGrammar->putElemDecl(decl);
  1708.     }
  1709.     // Set a flag for whether we will ignore this one
  1710.     const bool isIgnored = (decl == fDumElemDecl);
  1711.     // Mark this one if being externally declared
  1712.     decl->setExternalElemDeclaration(isReadingExternalEntity());
  1713.     // Mark this one as being declared
  1714.     decl->setCreateReason(XMLElementDecl::Declared);
  1715.     // Another check for a PE ref, with at least required whitespace
  1716.     if (!checkForPERef(true, false, true))
  1717.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  1718.     // And now scan the content model for this guy.
  1719.     if (!scanContentSpec(*decl))
  1720.     {
  1721.         fReaderMgr->skipPastChar(chCloseAngle);
  1722.         return;
  1723.     }
  1724.     // Another check for a PE ref, but we don't require whitespace here
  1725.     checkForPERef(false, false, true);
  1726.     // And we should have the ending angle bracket
  1727.     if (!fReaderMgr->skippedChar(chCloseAngle))
  1728.     {
  1729.         fScanner->emitError(XMLErrs::UnterminatedElementDecl, bbName.getRawBuffer());
  1730.         fReaderMgr->skipPastChar(chCloseAngle);
  1731.     }
  1732.     //
  1733.     //  If we have a DTD handler tell it about the new element decl. We
  1734.     //  tell it if its one that can be ignored, cause its an override of a
  1735.     //  previously existing decl. If it is being ignored, only call back
  1736.     //  if advanced callbacks are enabled.
  1737.     //
  1738.     if (fDocTypeHandler)
  1739.         fDocTypeHandler->elementDecl(*decl, isIgnored);
  1740. }
  1741. //
  1742. //  This method will process a general or parameter entity reference. The
  1743. //  entity name and entity text will be stored in the entity pool. The value
  1744. //  of the entity will be scanned for any other parameter entity or char
  1745. //  references which will be expanded. So the stored value can only have
  1746. //  general entity references when done.
  1747. //
  1748. void DTDScanner::scanEntityDecl()
  1749. {
  1750.     //
  1751.     //  Space is required here, but we cannot check for a PE Ref since
  1752.     //  there could be a legal (no-ref) percent sign here. Since any
  1753.     //  entity that ended here would be illegal, we just skip spaces
  1754.     //  and then check for a percent.
  1755.     //
  1756.     if (!fReaderMgr->lookingAtSpace())
  1757.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  1758.     else
  1759.         fReaderMgr->skipPastSpaces();
  1760.     const bool isPEDecl = fReaderMgr->skippedChar(chPercent);
  1761.     //
  1762.     //  If a PE decl, then eat the percent and check for spaces or a
  1763.     //  PE ref on the other side of it. At least spaces are required.
  1764.     //
  1765.     if (isPEDecl)
  1766.     {
  1767.         if (!checkForPERef(true, false, true))
  1768.             fScanner->emitError(XMLErrs::ExpectedWhitespace);
  1769.     }
  1770.     //
  1771.     //  Now lets get a name, which should be the name of the entity. We
  1772.     //  have to get a buffer for this.
  1773.     //
  1774.     XMLBufBid bbName(fBufMgr);
  1775.     if (!fReaderMgr->getName(bbName.getBuffer()))
  1776.     {
  1777.         fScanner->emitError(XMLErrs::ExpectedPEName);
  1778.         fReaderMgr->skipPastChar(chCloseAngle);
  1779.         return;
  1780.     }
  1781.     // If namespaces are enabled, then no colons allowed
  1782.     if (fScanner->getDoNamespaces())
  1783.     {
  1784.         if (XMLString::indexOf(bbName.getRawBuffer(), chColon) != -1)
  1785.             fScanner->emitError(XMLErrs::ColonNotLegalWithNS);
  1786.     }
  1787.     //
  1788.     //  See if this entity already exists. If so, then the existing one
  1789.     //  takes precendence. So we use the local dummy decl to parse into
  1790.     //  and just ignore the results.
  1791.     //
  1792.     DTDEntityDecl* entityDecl;
  1793.     if (isPEDecl)
  1794.         entityDecl = fPEntityDeclPool->getByKey(bbName.getRawBuffer());
  1795.     else
  1796.         entityDecl = fDTDGrammar->getEntityDecl(bbName.getRawBuffer());
  1797.     if (entityDecl)
  1798.     {
  1799.         if (!fDumEntityDecl)
  1800.             fDumEntityDecl = new (fMemoryManager) DTDEntityDecl(fMemoryManager);
  1801.         fDumEntityDecl->setName(bbName.getRawBuffer());
  1802.         entityDecl = fDumEntityDecl;
  1803.     }
  1804.      else
  1805.     {
  1806.         // Its not in existence already, then create an entity decl for it
  1807.         entityDecl = new (fMemoryManager) DTDEntityDecl(bbName.getRawBuffer(), false, fMemoryManager);
  1808.         //
  1809.         //  Set the declaration location. The parameter indicates whether its
  1810.         //  declared in the content/internal subset, so we know whether or not
  1811.         //  its in the external subset.
  1812.         //
  1813.         entityDecl->setDeclaredInIntSubset(fInternalSubset);
  1814.         // Add it to the appropriate entity decl pool
  1815.         if (isPEDecl)
  1816.             fPEntityDeclPool->put(entityDecl);
  1817.          else
  1818.             fDTDGrammar->putEntityDecl(entityDecl);
  1819.     }
  1820.     // Set a flag that indicates whether we are ignoring this one
  1821.     const bool isIgnored = (entityDecl == fDumEntityDecl);
  1822.     // Set the PE flag on it