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

词法分析

开发平台:

Visual C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 2002,2003 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.   * $Id: WFXMLScanner.cpp,v 1.12 2003/05/18 14:02:04 knoaman Exp $
  58.  */
  59. // ---------------------------------------------------------------------------
  60. //  Includes
  61. // ---------------------------------------------------------------------------
  62. #include <xercesc/internal/WFXMLScanner.hpp>
  63. #include <xercesc/util/Janitor.hpp>
  64. #include <xercesc/util/RuntimeException.hpp>
  65. #include <xercesc/util/UnexpectedEOFException.hpp>
  66. #include <xercesc/sax/InputSource.hpp>
  67. #include <xercesc/framework/XMLDocumentHandler.hpp>
  68. #include <xercesc/framework/XMLEntityHandler.hpp>
  69. #include <xercesc/framework/XMLPScanToken.hpp>
  70. #include <xercesc/framework/XMLValidityCodes.hpp>
  71. #include <xercesc/internal/EndOfEntityException.hpp>
  72. XERCES_CPP_NAMESPACE_BEGIN
  73. // ---------------------------------------------------------------------------
  74. //  WFXMLScanner: Constructors and Destructor
  75. // ---------------------------------------------------------------------------
  76. WFXMLScanner::WFXMLScanner( XMLValidator* const  valToAdopt
  77.                           , MemoryManager* const manager) :
  78.     XMLScanner(valToAdopt, manager)
  79.     , fElementIndex(0)
  80.     , fElements(0)
  81.     , fEntityTable(0)
  82.     , fAttrNameHashList(0)
  83.     , fAttrNSList(0)
  84.     , fElementLookup(0)
  85.     , fElemStack(manager)
  86. {
  87.     try
  88.     {
  89.         commonInit();
  90.     }
  91.     catch(...)
  92.     {
  93.         cleanUp();
  94.         throw;
  95.     }
  96. }
  97. WFXMLScanner::WFXMLScanner( XMLDocumentHandler* const docHandler
  98.                           , DocTypeHandler* const     docTypeHandler
  99.                           , XMLEntityHandler* const   entityHandler
  100.                           , XMLErrorReporter* const   errHandler
  101.                           , XMLValidator* const       valToAdopt
  102.                           , MemoryManager* const      manager) :
  103.     XMLScanner(docHandler, docTypeHandler, entityHandler, errHandler, valToAdopt, manager)
  104.     , fElementIndex(0)
  105.     , fElements(0)
  106.     , fEntityTable(0)
  107.     , fAttrNameHashList(0)
  108.     , fAttrNSList(0)
  109.     , fElementLookup(0)
  110.     , fElemStack(manager)
  111. {
  112.     try
  113.     {
  114.         commonInit();
  115.     }
  116.     catch(...)
  117.     {
  118.         cleanUp();
  119.         throw;
  120.     }
  121. }
  122. WFXMLScanner::~WFXMLScanner()
  123. {
  124.     cleanUp();
  125. }
  126. // ---------------------------------------------------------------------------
  127. //  XMLScanner: Getter methods
  128. // ---------------------------------------------------------------------------
  129. NameIdPool<DTDEntityDecl>* WFXMLScanner::getEntityDeclPool()
  130. {
  131.     return 0;
  132. }
  133. const NameIdPool<DTDEntityDecl>* WFXMLScanner::getEntityDeclPool() const
  134. {
  135.     return 0;
  136. }
  137. // ---------------------------------------------------------------------------
  138. //  WFXMLScanner: Main entry point to scan a document
  139. // ---------------------------------------------------------------------------
  140. void WFXMLScanner::scanDocument(const InputSource& src)
  141. {
  142.     //  Bump up the sequence id for this parser instance. This will invalidate
  143.     //  any previous progressive scan tokens.
  144.     fSequenceId++;
  145.     try
  146.     {
  147.         //  Reset the scanner and its plugged in stuff for a new run. This
  148.         //  resets all the data structures, creates the initial reader and
  149.         //  pushes it on the stack, and sets up the base document path.
  150.         scanReset(src);
  151.         // If we have a document handler, then call the start document
  152.         if (fDocHandler)
  153.             fDocHandler->startDocument();
  154.         //  Scan the prolog part, which is everything before the root element
  155.         //  including the DTD subsets.
  156.         scanProlog();
  157.         //  If we got to the end of input, then its not a valid XML file.
  158.         //  Else, go on to scan the content.
  159.         if (fReaderMgr.atEOF())
  160.         {
  161.             emitError(XMLErrs::EmptyMainEntity);
  162.         }
  163.         else
  164.         {
  165.             // Scan content, and tell it its not an external entity
  166.             if (scanContent(false))
  167.             {
  168.                 // That went ok, so scan for any miscellaneous stuff
  169.                 if (!fReaderMgr.atEOF())
  170.                     scanMiscellaneous();
  171.             }
  172.         }
  173.         // If we have a document handler, then call the end document
  174.         if (fDocHandler)
  175.             fDocHandler->endDocument();
  176.         // Reset the reader manager to close all files, sockets, etc...
  177.         fReaderMgr.reset();
  178.     }
  179.     //  NOTE:
  180.     //
  181.     //  In all of the error processing below, the emitError() call MUST come
  182.     //  before the flush of the reader mgr, or it will fail because it tries
  183.     //  to find out the position in the XML source of the error.
  184.     catch(const XMLErrs::Codes)
  185.     {
  186.         // This is a 'first fatal error' type exit, so reset and fall through
  187.         fReaderMgr.reset();
  188.     }
  189.     catch(const XMLValid::Codes)
  190.     {
  191.         // This is a 'first fatal error' type exit, so reset and fall through
  192.         fReaderMgr.reset();
  193.     }
  194.     catch(const XMLException& excToCatch)
  195.     {
  196.         //  Emit the error and catch any user exception thrown from here. Make
  197.         //  sure in all cases we flush the reader manager.
  198.         fInException = true;
  199.         try
  200.         {
  201.             if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
  202.                 emitError
  203.                 (
  204.                     XMLErrs::XMLException_Warning
  205.                     , excToCatch.getType()
  206.                     , excToCatch.getMessage()
  207.                 );
  208.             else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
  209.                 emitError
  210.                 (
  211.                     XMLErrs::XMLException_Fatal
  212.                     , excToCatch.getType()
  213.                     , excToCatch.getMessage()
  214.                 );
  215.             else
  216.                 emitError
  217.                 (
  218.                     XMLErrs::XMLException_Error
  219.                     , excToCatch.getType()
  220.                     , excToCatch.getMessage()
  221.                 );
  222.         }
  223.         catch(...)
  224.         {
  225.             // Flush the reader manager and rethrow user's error
  226.             fReaderMgr.reset();
  227.             throw;
  228.         }
  229.         // If it returned, then reset the reader manager and fall through
  230.         fReaderMgr.reset();
  231.     }
  232.     catch(...)
  233.     {
  234.         // Reset and rethrow
  235.         fReaderMgr.reset();
  236.         throw;
  237.     }
  238. }
  239. bool WFXMLScanner::scanNext(XMLPScanToken& token)
  240. {
  241.     // Make sure this token is still legal
  242.     if (!isLegalToken(token))
  243.         ThrowXML(RuntimeException, XMLExcepts::Scan_BadPScanToken);
  244.     // Find the next token and remember the reader id
  245.     unsigned int orgReader;
  246.     XMLTokens curToken;
  247.     bool retVal = true;
  248.     try
  249.     {
  250.         while (true)
  251.         {
  252.             //  We have to handle any end of entity exceptions that happen here.
  253.             //  We could be at the end of X nested entities, each of which will
  254.             //  generate an end of entity exception as we try to move forward.
  255.             try
  256.             {
  257.                 curToken = senseNextToken(orgReader);
  258.                 break;
  259.             }
  260.             catch(const EndOfEntityException& toCatch)
  261.             {
  262.                 // Send an end of entity reference event
  263.                 if (fDocHandler)
  264.                     fDocHandler->endEntityReference(toCatch.getEntity());
  265.             }
  266.         }
  267.         if (curToken == Token_CharData)
  268.         {
  269.             scanCharData(fCDataBuf);
  270.         }
  271.         else if (curToken == Token_EOF)
  272.         {
  273.             if (!fElemStack.isEmpty())
  274.             {
  275.                 const ElemStack::StackElem* topElem = fElemStack.popTop();
  276.                 emitError
  277.                 (
  278.                     XMLErrs::EndedWithTagsOnStack
  279.                     , topElem->fThisElement->getFullName()
  280.                 );
  281.             }
  282.             retVal = false;
  283.         }
  284.         else
  285.         {
  286.             // Its some sort of markup
  287.             bool gotData = true;
  288.             switch(curToken)
  289.             {
  290.                 case Token_CData :
  291.                     // Make sure we are within content
  292.                     if (fElemStack.isEmpty())
  293.                         emitError(XMLErrs::CDATAOutsideOfContent);
  294.                     scanCDSection();
  295.                     break;
  296.                 case Token_Comment :
  297.                     scanComment();
  298.                     break;
  299.                 case Token_EndTag :
  300.                     scanEndTag(gotData);
  301.                     break;
  302.                 case Token_PI :
  303.                     scanPI();
  304.                     break;
  305.                 case Token_StartTag :
  306.                     if (fDoNamespaces)
  307.                         scanStartTagNS(gotData);
  308.                     else
  309.                         scanStartTag(gotData);
  310.                     break;
  311.                 default :
  312.                     fReaderMgr.skipToChar(chOpenAngle);
  313.                     break;
  314.             }
  315.             if (orgReader != fReaderMgr.getCurrentReaderNum())
  316.                 emitError(XMLErrs::PartialMarkupInEntity);
  317.             // If we hit the end, then do the miscellaneous part
  318.             if (!gotData)
  319.             {
  320.                 // That went ok, so scan for any miscellaneous stuff
  321.                 scanMiscellaneous();
  322.                 if (fDocHandler)
  323.                     fDocHandler->endDocument();
  324.             }
  325.         }
  326.     }
  327.     //  NOTE:
  328.     //
  329.     //  In all of the error processing below, the emitError() call MUST come
  330.     //  before the flush of the reader mgr, or it will fail because it tries
  331.     //  to find out the position in the XML source of the error.
  332.     catch(const XMLErrs::Codes)
  333.     {
  334.         // This is a 'first failure' exception, so reset and return failure
  335.         fReaderMgr.reset();
  336.         return false;
  337.     }
  338.     catch(const XMLValid::Codes)
  339.     {
  340.         // This is a 'first fatal error' type exit, so reset and reuturn failure
  341.         fReaderMgr.reset();
  342.         return false;
  343.     }
  344.     catch(const XMLException& excToCatch)
  345.     {
  346.         //  Emit the error and catch any user exception thrown from here. Make
  347.         //  sure in all cases we flush the reader manager.
  348.         fInException = true;
  349.         try
  350.         {
  351.             if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
  352.                 emitError
  353.                 (
  354.                     XMLErrs::XMLException_Warning
  355.                     , excToCatch.getType()
  356.                     , excToCatch.getMessage()
  357.                 );
  358.             else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
  359.                 emitError
  360.                 (
  361.                     XMLErrs::XMLException_Fatal
  362.                     , excToCatch.getType()
  363.                     , excToCatch.getMessage()
  364.                 );
  365.             else
  366.                 emitError
  367.                 (
  368.                     XMLErrs::XMLException_Error
  369.                     , excToCatch.getType()
  370.                     , excToCatch.getMessage()
  371.                 );
  372.         }
  373.         catch(...)
  374.         {
  375.             // Reset and rethrow user error
  376.             fReaderMgr.reset();
  377.             throw;
  378.         }
  379.         // Reset and return failure
  380.         fReaderMgr.reset();
  381.         return false;
  382.     }
  383.     catch(...)
  384.     {
  385.         // Reset and rethrow original error
  386.         fReaderMgr.reset();
  387.         throw;
  388.     }
  389.     // If we hit the end, then flush the reader manager
  390.     if (!retVal)
  391.         fReaderMgr.reset();
  392.     return retVal;
  393. }
  394. // ---------------------------------------------------------------------------
  395. //  WFXMLScanner: Private helper methods.
  396. // ---------------------------------------------------------------------------
  397. //  This method handles the common initialization, to avoid having to do
  398. //  it redundantly in multiple constructors.
  399. void WFXMLScanner::commonInit()
  400. {
  401.     fEntityTable = new (fMemoryManager) ValueHashTableOf<XMLCh>(11, fMemoryManager);
  402.     fAttrNameHashList = new (fMemoryManager)ValueVectorOf<unsigned int>(16, fMemoryManager);
  403.     fAttrNSList = new (fMemoryManager) ValueVectorOf<XMLAttr*>(8, fMemoryManager);
  404.     fElements = new (fMemoryManager) RefVectorOf<XMLElementDecl>(32, true, fMemoryManager);
  405.     fElementLookup = new (fMemoryManager) RefHashTableOf<XMLElementDecl>(109, false, fMemoryManager);
  406.     //  Add the default entity entries for the character refs that must always
  407.     //  be present.
  408.     fEntityTable->put((void*) XMLUni::fgAmp, chAmpersand);
  409.     fEntityTable->put((void*) XMLUni::fgLT, chOpenAngle);
  410.     fEntityTable->put((void*) XMLUni::fgGT, chCloseAngle);
  411.     fEntityTable->put((void*) XMLUni::fgQuot, chDoubleQuote);
  412.     fEntityTable->put((void*) XMLUni::fgApos, chSingleQuote);
  413. }
  414. void WFXMLScanner::cleanUp()
  415. {
  416.     delete fEntityTable;
  417.     delete fAttrNameHashList;
  418.     delete fAttrNSList;
  419.     delete fElementLookup;
  420.     delete fElements;
  421. }
  422. unsigned int
  423. WFXMLScanner::resolvePrefix(const   XMLCh* const          prefix
  424.                             , const ElemStack::MapModes mode)
  425. {
  426.     //  Watch for the special namespace prefixes. We always map these to
  427.     //  special URIs. 'xml' gets mapped to the official URI that its defined
  428.     //  to map to by the NS spec. xmlns gets mapped to a special place holder
  429.     //  URI that we define (so that it maps to something checkable.)
  430.     if (XMLString::equals(prefix, XMLUni::fgXMLNSString))
  431.         return fXMLNSNamespaceId;
  432.     else if (XMLString::equals(prefix, XMLUni::fgXMLString))
  433.         return fXMLNamespaceId;
  434.     //  Ask the element stack to search up itself for a mapping for the
  435.     //  passed prefix.
  436.     bool unknown;
  437.     unsigned int uriId = fElemStack.mapPrefixToURI(prefix, mode, unknown);
  438.     // If it was unknown, then the URI was faked in but we have to issue an error
  439.     if (unknown)
  440.         emitError(XMLErrs::UnknownPrefix, prefix);
  441.     return uriId;
  442. }
  443. //  This method will reset the scanner data structures, and related plugged
  444. //  in stuff, for a new scan session. We get the input source for the primary
  445. //  XML entity, create the reader for it, and push it on the stack so that
  446. //  upon successful return from here we are ready to go.
  447. void WFXMLScanner::scanReset(const InputSource& src)
  448. {
  449.     //  For all installed handlers, send reset events. This gives them
  450.     //  a chance to flush any cached data.
  451.     if (fDocHandler)
  452.         fDocHandler->resetDocument();
  453.     if (fEntityHandler)
  454.         fEntityHandler->resetEntities();
  455.     if (fErrorReporter)
  456.         fErrorReporter->resetErrors();
  457.     //  Reset the element stack, and give it the latest ids for the special
  458.     //  URIs it has to know about.
  459.     fElemStack.reset
  460.     (
  461.         fEmptyNamespaceId
  462.         , fUnknownNamespaceId
  463.         , fXMLNamespaceId
  464.         , fXMLNSNamespaceId
  465.     );
  466.     // Reset some status flags
  467.     fInException = false;
  468.     fStandalone = false;
  469.     fErrorCount = 0;
  470.     fHasNoDTD = true;
  471.     fElementIndex = 0;
  472.     // Reset elements lookup table
  473.     fElementLookup->removeAll();
  474.     //  Handle the creation of the XML reader object for this input source.
  475.     //  This will provide us with transcoding and basic lexing services.
  476.     XMLReader* newReader = fReaderMgr.createReader
  477.     (
  478.         src
  479.         , true
  480.         , XMLReader::RefFrom_NonLiteral
  481.         , XMLReader::Type_General
  482.         , XMLReader::Source_External
  483.         , fCalculateSrcOfs
  484.     );
  485.     if (!newReader) {
  486.         if (src.getIssueFatalErrorIfNotFound())
  487.             ThrowXML1(RuntimeException, XMLExcepts::Scan_CouldNotOpenSource, src.getSystemId());
  488.         else
  489.             ThrowXML1(RuntimeException, XMLExcepts::Scan_CouldNotOpenSource_Warning, src.getSystemId());
  490.     }
  491.     // Push this read onto the reader manager
  492.     fReaderMgr.pushReader(newReader, 0);
  493.     // and reset security-related things if necessary:
  494.     if(fSecurityManager != 0) 
  495.     {
  496.         fEntityExpansionLimit = fSecurityManager->getEntityExpansionLimit();
  497.         fEntityExpansionCount = 0;
  498.     }
  499. }
  500. //  This method is called between markup in content. It scans for character
  501. //  data that is sent to the document handler. It watches for any markup
  502. //  characters that would indicate that the character data has ended. It also
  503. //  handles expansion of general and character entities.
  504. //
  505. //  sendData() is a local static helper for this method which handles some
  506. //  code that must be done in three different places here.
  507. void WFXMLScanner::sendCharData(XMLBuffer& toSend)
  508. {
  509.     // If no data in the buffer, then nothing to do
  510.     if (toSend.isEmpty())
  511.         return;
  512.     // Always assume its just char data if not validating
  513.     if (fDocHandler)
  514.         fDocHandler->docCharacters(toSend.getRawBuffer(), toSend.getLen(), false);
  515.     // Reset buffer
  516.     toSend.reset();
  517. }
  518. // ---------------------------------------------------------------------------
  519. //  WFXMLScanner: Private scanning methods
  520. // ---------------------------------------------------------------------------
  521. //  This method will kick off the scanning of the primary content of the
  522. //  document, i.e. the elements.
  523. bool WFXMLScanner::scanContent(const bool extEntity)
  524. {
  525.     //  Go into a loop until we hit the end of the root element, or we fall
  526.     //  out because there is no root element.
  527.     //
  528.     //  We have to do kind of a deeply nested double loop here in order to
  529.     //  avoid doing the setup/teardown of the exception handler on each
  530.     //  round. Doing it this way we only do it when an exception actually
  531.     //  occurs.
  532.     bool gotData = true;
  533.     bool inMarkup = false;
  534.     while (gotData)
  535.     {
  536.         try
  537.         {
  538.             while (gotData)
  539.             {
  540.                 //  Sense what the next top level token is. According to what
  541.                 //  this tells us, we will call something to handle that kind
  542.                 //  of thing.
  543.                 unsigned int orgReader;
  544.                 const XMLTokens curToken = senseNextToken(orgReader);
  545.                 //  Handle character data and end of file specially. Char data
  546.                 //  is not markup so we don't want to handle it in the loop
  547.                 //  below.
  548.                 if (curToken == Token_CharData)
  549.                 {
  550.                     //  Scan the character data and call appropriate events. Let
  551.                     //  him use our local character data buffer for efficiency.
  552.                     scanCharData(fCDataBuf);
  553.                     continue;
  554.                 }
  555.                 else if (curToken == Token_EOF)
  556.                 {
  557.                     //  The element stack better be empty at this point or we
  558.                     //  ended prematurely before all elements were closed.
  559.                     if (!fElemStack.isEmpty())
  560.                     {
  561.                         const ElemStack::StackElem* topElem = fElemStack.popTop();
  562.                         emitError
  563.                         (
  564.                             XMLErrs::EndedWithTagsOnStack
  565.                             , topElem->fThisElement->getFullName()
  566.                         );
  567.                     }
  568.                     // Its the end of file, so clear the got data flag
  569.                     gotData = false;
  570.                     continue;
  571.                 }
  572.                 // We are in some sort of markup now
  573.                 inMarkup = true;
  574.                 //  According to the token we got, call the appropriate
  575.                 //  scanning method.
  576.                 switch(curToken)
  577.                 {
  578.                     case Token_CData :
  579.                         // Make sure we are within content
  580.                         if (fElemStack.isEmpty())
  581.                             emitError(XMLErrs::CDATAOutsideOfContent);
  582.                         scanCDSection();
  583.                         break;
  584.                     case Token_Comment :
  585.                         scanComment();
  586.                         break;
  587.                     case Token_EndTag :
  588.                         scanEndTag(gotData);
  589.                         break;
  590.                     case Token_PI :
  591.                         scanPI();
  592.                         break;
  593.                     case Token_StartTag :
  594.                         if (fDoNamespaces)
  595.                             scanStartTagNS(gotData);
  596.                         else
  597.                             scanStartTag(gotData);
  598.                         break;
  599.                     default :
  600.                         fReaderMgr.skipToChar(chOpenAngle);
  601.                         break;
  602.                 }
  603.                 if (orgReader != fReaderMgr.getCurrentReaderNum())
  604.                     emitError(XMLErrs::PartialMarkupInEntity);
  605.                 // And we are back out of markup again
  606.                 inMarkup = false;
  607.             }
  608.         }
  609.         catch(const EndOfEntityException& toCatch)
  610.         {
  611.             //  If we were in some markup when this happened, then its a
  612.             //  partial markup error.
  613.             if (inMarkup)
  614.                 emitError(XMLErrs::PartialMarkupInEntity);
  615.             // Send an end of entity reference event
  616.             if (fDocHandler)
  617.                 fDocHandler->endEntityReference(toCatch.getEntity());
  618.             inMarkup = false;
  619.         }
  620.     }
  621.     // It went ok, so return success
  622.     return true;
  623. }
  624. void WFXMLScanner::scanEndTag(bool& gotData)
  625. {
  626.     //  Assume we will still have data until proven otherwise. It will only
  627.     //  ever be false if this is the end of the root element.
  628.     gotData = true;
  629.     //  Check if the element stack is empty. If so, then this is an unbalanced
  630.     //  element (i.e. more ends than starts, perhaps because of bad text
  631.     //  causing one to be skipped.)
  632.     if (fElemStack.isEmpty())
  633.     {
  634.         emitError(XMLErrs::MoreEndThanStartTags);
  635.         fReaderMgr.skipPastChar(chCloseAngle);
  636.         ThrowXML(RuntimeException, XMLExcepts::Scan_UnbalancedStartEnd);
  637.     }
  638.     //  Pop the stack of the element we are supposed to be ending. Remember
  639.     //  that we don't own this. The stack just keeps them and reuses them.
  640.     unsigned int uriId = (fDoNamespaces)
  641.         ? fElemStack.getCurrentURI() : fEmptyNamespaceId;
  642.     const ElemStack::StackElem* topElem = fElemStack.popTop();
  643.     // See if it was the root element, to avoid multiple calls below
  644.     const bool isRoot = fElemStack.isEmpty();
  645.     // Make sure that its the end of the element that we expect
  646.     if (!fReaderMgr.skippedString(topElem->fThisElement->getFullName()))
  647.     {
  648.         emitError
  649.         (
  650.             XMLErrs::ExpectedEndOfTagX
  651.             , topElem->fThisElement->getFullName()
  652.         );
  653.         fReaderMgr.skipPastChar(chCloseAngle);
  654.         return;
  655.     }
  656.     // Make sure we are back on the same reader as where we started
  657.     if (topElem->fReaderNum != fReaderMgr.getCurrentReaderNum())
  658.         emitError(XMLErrs::PartialTagMarkupError);
  659.     // Skip optional whitespace
  660.     fReaderMgr.skipPastSpaces();
  661.     // Make sure we find the closing bracket
  662.     if (!fReaderMgr.skippedChar(chCloseAngle))
  663.     {
  664.         emitError
  665.         (
  666.             XMLErrs::UnterminatedEndTag
  667.             , topElem->fThisElement->getFullName()
  668.         );
  669.     }
  670.     // If we have a doc handler, tell it about the end tag
  671.     if (fDocHandler)
  672.     {
  673.         fDocHandler->endElement
  674.         (
  675.             *topElem->fThisElement
  676.             , uriId
  677.             , isRoot
  678.             , topElem->fThisElement->getElementName()->getPrefix()
  679.         );
  680.     }
  681.     // If this was the root, then done with content
  682.     gotData = !isRoot;
  683. }
  684. void WFXMLScanner::scanDocTypeDecl()
  685. {
  686.     // Just skips over it
  687.     // REVISIT: Should we issue a warning
  688.     static const XMLCh doctypeIE[] =
  689.     {
  690.         chOpenSquare, chCloseAngle, chNull
  691.     };
  692.     XMLCh nextCh = fReaderMgr.skipUntilIn(doctypeIE);
  693.     if (nextCh == chOpenSquare)
  694.         fReaderMgr.skipPastChar(chCloseSquare);
  695.     fReaderMgr.skipPastChar(chCloseAngle);
  696. }
  697. bool WFXMLScanner::scanStartTag(bool& gotData)
  698. {
  699.     //  Assume we will still have data until proven otherwise. It will only
  700.     //  ever be false if this is the root and its empty.
  701.     gotData = true;
  702.     //  Get the QName. In this case, we are not doing namespaces, so we just
  703.     //  use it as is and don't have to break it into parts.
  704.     if (!fReaderMgr.getName(fQNameBuf))
  705.     {
  706.         emitError(XMLErrs::ExpectedElementName);
  707.         fReaderMgr.skipToChar(chOpenAngle);
  708.         return false;
  709.     }
  710.     // Assume it won't be an empty tag
  711.     bool isEmpty = false;
  712.     // See if its the root element
  713.     const bool isRoot = fElemStack.isEmpty();
  714.     //  Lets try to look up the element
  715.     const XMLCh* qnameRawBuf = fQNameBuf.getRawBuffer();
  716.     XMLElementDecl* elemDecl = fElementLookup->get(qnameRawBuf);
  717.     if (!elemDecl) {
  718.         if (fElementIndex < fElements->size()) {
  719.             elemDecl = fElements->elementAt(fElementIndex);
  720.         }
  721.         else {
  722.             elemDecl = new (fMemoryManager) DTDElementDecl
  723.             (
  724.                 fMemoryManager
  725.             );
  726.             fElements->addElement(elemDecl);
  727.         }
  728.         elemDecl->setElementName(XMLUni::fgZeroLenString, qnameRawBuf, fEmptyNamespaceId);
  729.         fElementLookup->put((void*)elemDecl->getFullName(), elemDecl);
  730.         fElementIndex++;
  731.     }
  732.     // Expand the element stack and add the new element
  733.     fElemStack.addLevel(elemDecl, fReaderMgr.getCurrentReaderNum());
  734.     // Skip any whitespace after the name
  735.     fReaderMgr.skipPastSpaces();
  736.     //  We loop until we either see a /> or >, handling attribute/value
  737.     //  pairs until we get there.
  738.     unsigned int    attCount = 0;
  739.     unsigned int    curAttListSize = fAttrList->size();
  740.     while (true)
  741.     {
  742.         // And get the next non-space character
  743.         XMLCh nextCh = fReaderMgr.peekNextChar();
  744.         //  If the next character is not a slash or closed angle bracket,
  745.         //  then it must be whitespace, since whitespace is required
  746.         //  between the end of the last attribute and the name of the next
  747.         //  one.
  748.         if (attCount)
  749.         {
  750.             if ((nextCh != chForwardSlash) && (nextCh != chCloseAngle))
  751.             {
  752.                 if (fReaderMgr.getCurrentReader()->isWhitespace(nextCh))
  753.                 {
  754.                     // Ok, skip by them and peek another char
  755.                     fReaderMgr.skipPastSpaces();
  756.                     nextCh = fReaderMgr.peekNextChar();
  757.                 }
  758.                  else
  759.                 {
  760.                     // Emit the error but keep on going
  761.                     emitError(XMLErrs::ExpectedWhitespace);
  762.                 }
  763.             }
  764.         }
  765.         //  Ok, here we first check for any of the special case characters.
  766.         //  If its not one, then we do the normal case processing, which
  767.         //  assumes that we've hit an attribute value, Otherwise, we do all
  768.         //  the special case checks.
  769.         if (!fReaderMgr.getCurrentReader()->isSpecialStartTagChar(nextCh))
  770.         {
  771.             //  Assume its going to be an attribute, so get a name from
  772.             //  the input.
  773.             if (!fReaderMgr.getName(fAttNameBuf))
  774.             {
  775.                 emitError(XMLErrs::ExpectedAttrName);
  776.                 fReaderMgr.skipPastChar(chCloseAngle);
  777.                 return false;
  778.             }
  779.             // And next must be an equal sign
  780.             if (!scanEq())
  781.             {
  782.                 static const XMLCh tmpList[] =
  783.                 {
  784.                     chSingleQuote, chDoubleQuote, chCloseAngle
  785.                     , chOpenAngle, chForwardSlash, chNull
  786.                 };
  787.                 emitError(XMLErrs::ExpectedEqSign);
  788.                 //  Try to sync back up by skipping forward until we either
  789.                 //  hit something meaningful.
  790.                 const XMLCh chFound = fReaderMgr.skipUntilInOrWS(tmpList);
  791.                 if ((chFound == chCloseAngle) || (chFound == chForwardSlash))
  792.                 {
  793.                     // Jump back to top for normal processing of these
  794.                     continue;
  795.                 }
  796.                 else if ((chFound == chSingleQuote)
  797.                       ||  (chFound == chDoubleQuote)
  798.                       ||  fReaderMgr.getCurrentReader()->isWhitespace(chFound))
  799.                 {
  800.                     // Just fall through assuming that the value is to follow
  801.                 }
  802.                 else if (chFound == chOpenAngle)
  803.                 {
  804.                     // Assume a malformed tag and that new one is starting
  805.                     emitError(XMLErrs::UnterminatedStartTag, qnameRawBuf);
  806.                     return false;
  807.                 }
  808.                 else
  809.                 {
  810.                     // Something went really wrong
  811.                     return false;
  812.                 }
  813.             }
  814.             //  See if this attribute is declared more than one for this element.
  815.             const XMLCh* attNameRawBuf = fAttNameBuf.getRawBuffer();
  816.             unsigned int attNameHash = XMLString::hash(attNameRawBuf, 109);
  817.             if (attCount) {
  818.                 for (unsigned int k=0; k < attCount; k++) {
  819.                     if (fAttrNameHashList->elementAt(k) == attNameHash) {
  820.                         if (
  821.                                XMLString::equals
  822.                                (
  823.                                    fAttrList->elementAt(k)->getName()
  824.                                    , attNameRawBuf
  825.                                )
  826.                            )
  827.                         {
  828.                             emitError
  829.                             (
  830.                                 XMLErrs::AttrAlreadyUsedInSTag
  831.                                 , attNameRawBuf
  832.                                 , qnameRawBuf
  833.                             );
  834.                             break;
  835.                         }
  836.                     }
  837.                 }
  838.             }
  839.             //  Skip any whitespace before the value and then scan the att
  840.             //  value. This will come back normalized with entity refs and
  841.             //  char refs expanded.
  842.             fReaderMgr.skipPastSpaces();
  843.             if (!scanAttValue(attNameRawBuf, fAttValueBuf))
  844.             {
  845.                 static const XMLCh tmpList[] =
  846.                 {
  847.                     chCloseAngle, chOpenAngle, chForwardSlash, chNull
  848.                 };
  849.                 emitError(XMLErrs::ExpectedAttrValue);
  850.                 //  It failed, so lets try to get synced back up. We skip
  851.                 //  forward until we find some whitespace or one of the
  852.                 //  chars in our list.
  853.                 const XMLCh chFound = fReaderMgr.skipUntilInOrWS(tmpList);
  854.                 if ((chFound == chCloseAngle)
  855.                 ||  (chFound == chForwardSlash)
  856.                 ||  fReaderMgr.getCurrentReader()->isWhitespace(chFound))
  857.                 {
  858.                     //  Just fall through and process this attribute, though
  859.                     //  the value will be "".
  860.                 }
  861.                 else if (chFound == chOpenAngle)
  862.                 {
  863.                     // Assume a malformed tag and that new one is starting
  864.                     emitError(XMLErrs::UnterminatedStartTag, qnameRawBuf);
  865.                     return false;
  866.                 }
  867.                 else
  868.                 {
  869.                     // Something went really wrong
  870.                     return false;
  871.                 }
  872.             }
  873.             //  Add this attribute to the attribute list that we use to
  874.             //  pass them to the handler. We reuse its existing elements
  875.             //  but expand it as required.
  876.             XMLAttr* curAtt;
  877.             if (attCount >= curAttListSize)
  878.             {
  879.                 curAtt = new (fMemoryManager) XMLAttr
  880.                 (
  881.                     -1
  882.                     , attNameRawBuf
  883.                     , XMLUni::fgZeroLenString
  884.                     , fAttValueBuf.getRawBuffer()
  885.                     , XMLAttDef::CData
  886.                     , true
  887.                     , fMemoryManager
  888.                 );
  889.                 fAttrList->addElement(curAtt);
  890.                 fAttrNameHashList->addElement(attNameHash);
  891.             }
  892.             else
  893.             {
  894.                 curAtt = fAttrList->elementAt(attCount);
  895.                 curAtt->set
  896.                 (
  897.                     -1
  898.                     , attNameRawBuf
  899.                     , XMLUni::fgZeroLenString
  900.                     , fAttValueBuf.getRawBuffer()
  901.                 );
  902.                 curAtt->setSpecified(true);
  903.                 fAttrNameHashList->setElementAt(attNameHash, attCount);
  904.             }
  905.             attCount++;
  906.             // And jump back to the top of the loop
  907.             continue;
  908.         }
  909.         //  It was some special case character so do all of the checks and
  910.         //  deal with it.
  911.         if (!nextCh)
  912.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  913.         if (nextCh == chForwardSlash)
  914.         {
  915.             fReaderMgr.getNextChar();
  916.             isEmpty = true;
  917.             if (!fReaderMgr.skippedChar(chCloseAngle))
  918.                 emitError(XMLErrs::UnterminatedStartTag, qnameRawBuf);
  919.             break;
  920.         }
  921.         else if (nextCh == chCloseAngle)
  922.         {
  923.             fReaderMgr.getNextChar();
  924.             break;
  925.         }
  926.         else if (nextCh == chOpenAngle)
  927.         {
  928.             //  Check for this one specially, since its going to be common
  929.             //  and it is kind of auto-recovering since we've already hit the
  930.             //  next open bracket, which is what we would have seeked to (and
  931.             //  skipped this whole tag.)
  932.             emitError(XMLErrs::UnterminatedStartTag, elemDecl->getFullName());
  933.             break;
  934.         }
  935.         else if ((nextCh == chSingleQuote) || (nextCh == chDoubleQuote))
  936.         {
  937.             //  Check for this one specially, which is probably a missing
  938.             //  attribute name, e.g. ="value". Just issue expected name
  939.             //  error and eat the quoted string, then jump back to the
  940.             //  top again.
  941.             emitError(XMLErrs::ExpectedAttrName);
  942.             fReaderMgr.getNextChar();
  943.             fReaderMgr.skipQuotedString(nextCh);
  944.             fReaderMgr.skipPastSpaces();
  945.             continue;
  946.         }
  947.     }
  948.     //  If empty, validate content right now if we are validating and then
  949.     //  pop the element stack top. Else, we have to update the current stack
  950.     //  top's namespace mapping elements.
  951.     if (isEmpty)
  952.     {
  953.         // Pop the element stack back off since it'll never be used now
  954.         fElemStack.popTop();
  955.         // If the elem stack is empty, then it was an empty root
  956.         if (isRoot)
  957.             gotData = false;
  958.     }
  959.     //  If we have a document handler, then tell it about this start tag. We
  960.     //  don't have any URI id to send along, so send fEmptyNamespaceId. We also do not send
  961.     //  any prefix since its just one big name if we are not doing namespaces.
  962.     if (fDocHandler)
  963.     {
  964.         fDocHandler->startElement
  965.         (
  966.             *elemDecl
  967.             , fEmptyNamespaceId
  968.             , 0
  969.             , *fAttrList
  970.             , attCount
  971.             , isEmpty
  972.             , isRoot
  973.         );
  974.     }
  975.     return true;
  976. }
  977. //  This method is called to scan a start tag when we are processing
  978. //  namespaces. There are two different versions of this method, one for
  979. //  namespace aware processing an done for non-namespace aware processing.
  980. //
  981. //  This method is called after we've scanned the < of a start tag. So we
  982. //  have to get the element name, then scan the attributes, after which
  983. //  we are either going to see >, />, or attributes followed by one of those
  984. //  sequences.
  985. bool WFXMLScanner::scanStartTagNS(bool& gotData)
  986. {
  987.     //  Assume we will still have data until proven otherwise. It will only
  988.     //  ever be false if this is the root and its empty.
  989.     gotData = true;
  990.     //  The current position is after the open bracket, so we need to read in
  991.     //  in the element name.
  992.     if (!fReaderMgr.getName(fQNameBuf))
  993.     {
  994.         emitError(XMLErrs::ExpectedElementName);
  995.         fReaderMgr.skipToChar(chOpenAngle);
  996.         return false;
  997.     }
  998.     // See if its the root element
  999.     const bool isRoot = fElemStack.isEmpty();
  1000. // Assume it won't be an empty tag
  1001.     bool isEmpty = false;
  1002.     // Skip any whitespace after the name
  1003.     fReaderMgr.skipPastSpaces();
  1004.     //  Lets try to look up the element
  1005.     const XMLCh* qnameRawBuf = fQNameBuf.getRawBuffer();
  1006.     XMLElementDecl* elemDecl = fElementLookup->get(qnameRawBuf);
  1007.     if (!elemDecl) {
  1008.         if (!XMLString::compareNString(qnameRawBuf, XMLUni::fgXMLNSColonString, 6))
  1009.             emitError(XMLErrs::NoXMLNSAsElementPrefix, qnameRawBuf);
  1010.         if (fElementIndex < fElements->size()) {
  1011.             elemDecl = fElements->elementAt(fElementIndex);
  1012.         }
  1013.         else {
  1014.             elemDecl = new (fMemoryManager) DTDElementDecl
  1015.             (
  1016.                 fMemoryManager
  1017.             );
  1018.             fElements->addElement(elemDecl);
  1019.         }
  1020.         elemDecl->setElementName(qnameRawBuf, fEmptyNamespaceId);
  1021.         fElementLookup->put((void*)elemDecl->getFullName(), elemDecl);
  1022.         fElementIndex++;
  1023.     }
  1024.     // Expand the element stack and add the new element
  1025.     fElemStack.addLevel(elemDecl, fReaderMgr.getCurrentReaderNum());
  1026.     // reset NS attribute list
  1027.     fAttrNSList->removeAllElements();
  1028.     // We loop until we either see a /> or >, handling attribute/value
  1029.     // pairs until we get there.
  1030.     unsigned int attCount = 0;
  1031.     unsigned int curAttListSize = fAttrList->size();
  1032.     while (true)
  1033.     {
  1034.         // And get the next non-space character
  1035.         XMLCh nextCh = fReaderMgr.peekNextChar();
  1036.         //  If the next character is not a slash or closed angle bracket,
  1037.         //  then it must be whitespace, since whitespace is required
  1038.         //  between the end of the last attribute and the name of the next
  1039.         //  one.
  1040.         if (attCount)
  1041.         {
  1042.             if ((nextCh != chForwardSlash) && (nextCh != chCloseAngle))
  1043.             {
  1044.                 if (fReaderMgr.getCurrentReader()->isWhitespace(nextCh))
  1045.                 {
  1046.                     // Ok, skip by them and peek another char
  1047.                     fReaderMgr.skipPastSpaces();
  1048.                     nextCh = fReaderMgr.peekNextChar();
  1049.                 }
  1050.                 else
  1051.                 {
  1052.                     // Emit the error but keep on going
  1053.                     emitError(XMLErrs::ExpectedWhitespace);
  1054.                 }
  1055.             }
  1056.         }
  1057.         //  Ok, here we first check for any of the special case characters.
  1058.         //  If its not one, then we do the normal case processing, which
  1059.         //  assumes that we've hit an attribute value, Otherwise, we do all
  1060.         //  the special case checks.
  1061.         if (!fReaderMgr.getCurrentReader()->isSpecialStartTagChar(nextCh))
  1062.         {
  1063.             //  Assume its going to be an attribute, so get a name from
  1064.             //  the input.
  1065.             if (!fReaderMgr.getName(fAttNameBuf))
  1066.             {
  1067.                 emitError(XMLErrs::ExpectedAttrName);
  1068.                 fReaderMgr.skipPastChar(chCloseAngle);
  1069.                 return false;
  1070.             }
  1071.             // And next must be an equal sign
  1072.             if (!scanEq())
  1073.             {
  1074.                 static const XMLCh tmpList[] =
  1075.                 {
  1076.                     chSingleQuote, chDoubleQuote, chCloseAngle
  1077.                     , chOpenAngle, chForwardSlash, chNull
  1078.                 };
  1079.                 emitError(XMLErrs::ExpectedEqSign);
  1080.                 //  Try to sync back up by skipping forward until we either
  1081.                 //  hit something meaningful.
  1082.                 const XMLCh chFound = fReaderMgr.skipUntilInOrWS(tmpList);
  1083.                 if ((chFound == chCloseAngle) || (chFound == chForwardSlash))
  1084.                 {
  1085.                     // Jump back to top for normal processing of these
  1086.                     continue;
  1087.                 }
  1088.                 else if ((chFound == chSingleQuote)
  1089.                       ||  (chFound == chDoubleQuote)
  1090.                       ||  fReaderMgr.getCurrentReader()->isWhitespace(chFound))
  1091.                 {
  1092.                     // Just fall through assuming that the value is to follow
  1093.                 }
  1094.                 else if (chFound == chOpenAngle)
  1095.                 {
  1096.                     // Assume a malformed tag and that new one is starting
  1097.                     emitError(XMLErrs::UnterminatedStartTag, qnameRawBuf);
  1098.                     return false;
  1099.                 }
  1100.                 else
  1101.                 {
  1102.                     // Something went really wrong
  1103.                     return false;
  1104.                 }
  1105.             }
  1106.             //  See if this attribute is declared more than one for this element.
  1107.             const XMLCh* attNameRawBuf = fAttNameBuf.getRawBuffer();
  1108.             unsigned int attNameHash = XMLString::hash(attNameRawBuf, 109);
  1109.             if (attCount) {
  1110.                 for (unsigned int k=0; k < attCount; k++) {
  1111.                     if (fAttrNameHashList->elementAt(k) == attNameHash) {
  1112.                         if (XMLString::equals(
  1113.                                 fAttrList->elementAt(k)->getQName()
  1114.                                 , attNameRawBuf))
  1115.                         {
  1116.                             emitError
  1117.                             (
  1118.                                 XMLErrs::AttrAlreadyUsedInSTag
  1119.                                 , attNameRawBuf
  1120.                                 , qnameRawBuf
  1121.                             );
  1122.                             break;
  1123.                         }
  1124.                     }
  1125.                 }
  1126.             }
  1127.             //  Skip any whitespace before the value and then scan the att
  1128.             //  value. This will come back normalized with entity refs and
  1129.             //  char refs expanded.
  1130.             fReaderMgr.skipPastSpaces();
  1131.             if (!scanAttValue(attNameRawBuf, fAttValueBuf))
  1132.             {
  1133.                 static const XMLCh tmpList[] =
  1134.                 {
  1135.                     chCloseAngle, chOpenAngle, chForwardSlash, chNull
  1136.                 };
  1137.                 emitError(XMLErrs::ExpectedAttrValue);
  1138.                 //  It failed, so lets try to get synced back up. We skip
  1139.                 //  forward until we find some whitespace or one of the
  1140.                 //  chars in our list.
  1141.                 const XMLCh chFound = fReaderMgr.skipUntilInOrWS(tmpList);
  1142.                 if ((chFound == chCloseAngle)
  1143.                 ||  (chFound == chForwardSlash)
  1144.                 ||  fReaderMgr.getCurrentReader()->isWhitespace(chFound))
  1145.                 {
  1146.                     //  Just fall through and process this attribute, though
  1147.                     //  the value will be "".
  1148.                 }
  1149.                 else if (chFound == chOpenAngle)
  1150.                 {
  1151.                     // Assume a malformed tag and that new one is starting
  1152.                     emitError(XMLErrs::UnterminatedStartTag, qnameRawBuf);
  1153.                     return false;
  1154.                 }
  1155.                 else
  1156.                 {
  1157.                     // Something went really wrong
  1158.                     return false;
  1159.                 }
  1160.             }
  1161.             //  Add this attribute to the attribute list that we use to
  1162.             //  pass them to the handler. We reuse its existing elements
  1163.             //  but expand it as required.
  1164.             const XMLCh* attValueRawBuf = fAttValueBuf.getRawBuffer();
  1165.             XMLAttr* curAtt = 0;
  1166.             if (attCount >= curAttListSize)
  1167.             {
  1168.                 curAtt = new (fMemoryManager) XMLAttr
  1169.                 (
  1170.                     fEmptyNamespaceId
  1171.                     , attNameRawBuf
  1172.                     , attValueRawBuf
  1173.                     , XMLAttDef::CData
  1174.                     , true
  1175.                     , fMemoryManager
  1176.                 );
  1177.                 fAttrList->addElement(curAtt);
  1178.                 fAttrNameHashList->addElement(attNameHash);
  1179.             }
  1180.             else
  1181.             {
  1182.                 curAtt = fAttrList->elementAt(attCount);
  1183.                 curAtt->set
  1184.                 (
  1185.                     fEmptyNamespaceId
  1186.                     , attNameRawBuf
  1187.                     , attValueRawBuf
  1188.                 );
  1189.                 curAtt->setSpecified(true);
  1190.                 fAttrNameHashList->setElementAt(attNameHash, attCount);
  1191.             }
  1192.             // Make sure that the name is basically well formed for namespace
  1193.             //  enabled rules. It either has no colons, or it has one which
  1194.             //  is neither the first or last char.
  1195.             const int colonFirst = XMLString::indexOf(attNameRawBuf, chColon);
  1196.             if (colonFirst != -1)
  1197.             {
  1198.                 const int colonLast = XMLString::lastIndexOf(attNameRawBuf, chColon);
  1199.                 if (colonFirst != colonLast)
  1200.                 {
  1201.                     emitError(XMLErrs::TooManyColonsInName);
  1202.                     continue;
  1203.                 }
  1204.                 else if ((colonFirst == 0)
  1205.                       ||  (colonLast == (int)fAttNameBuf.getLen() - 1))
  1206.                 {
  1207.                     emitError(XMLErrs::InvalidColonPos);
  1208.                     continue;
  1209.                 }
  1210.             }
  1211.             // Map prefix to namespace
  1212.             const XMLCh* attPrefix = curAtt->getPrefix();
  1213.             const XMLCh* attLocalName = curAtt->getName();
  1214.             const XMLCh* namespaceURI = fAttValueBuf.getRawBuffer();
  1215.             if (attPrefix && *attPrefix) {
  1216.                 if (XMLString::equals(attPrefix, XMLUni::fgXMLString)) {
  1217.                     curAtt->setURIId(fXMLNamespaceId);
  1218.                 }
  1219.                 else if (XMLString::equals(attPrefix, XMLUni::fgXMLNSString)) {
  1220.                     if (XMLString::equals(attLocalName, XMLUni::fgXMLNSString))
  1221.                         emitError(XMLErrs::NoUseOfxmlnsAsPrefix);
  1222.                     else if (XMLString::equals(attLocalName, XMLUni::fgXMLString)) {
  1223.                         if (!XMLString::equals(namespaceURI, XMLUni::fgXMLURIName))
  1224.                             emitError(XMLErrs::PrefixXMLNotMatchXMLURI);
  1225.                     }
  1226.                     if (!namespaceURI)
  1227.                         emitError(XMLErrs::NoEmptyStrNamespace, attNameRawBuf);
  1228.                     else if(!*namespaceURI && fXMLVersion == XMLReader::XMLV1_0)
  1229.                         emitError(XMLErrs::NoEmptyStrNamespace, attNameRawBuf);
  1230.                     fElemStack.addPrefix
  1231.                     (
  1232.                         attLocalName
  1233.                         , fURIStringPool->addOrFind(namespaceURI)
  1234.                     );
  1235.                     curAtt->setURIId(fXMLNSNamespaceId);
  1236.                 }
  1237.                 else {
  1238.                     fAttrNSList->addElement(curAtt);
  1239.                 }
  1240.             }
  1241.             else {
  1242.                 if (XMLString::equals(XMLUni::fgXMLNSString, attLocalName)) {
  1243.                     if (XMLString::equals(namespaceURI, XMLUni::fgXMLNSURIName))
  1244.                         emitError(XMLErrs::NoUseOfxmlnsURI);
  1245.                     else if (XMLString::equals(namespaceURI, XMLUni::fgXMLURIName))
  1246.                         emitError(XMLErrs::XMLURINotMatchXMLPrefix);
  1247.                     fElemStack.addPrefix
  1248.                     (
  1249.                         XMLUni::fgZeroLenString
  1250.                         , fURIStringPool->addOrFind(namespaceURI)
  1251.                     );
  1252.                 }
  1253.             }
  1254.             // increment attribute count
  1255.             attCount++;
  1256.             // And jump back to the top of the loop
  1257.             continue;
  1258.         }
  1259.         //  It was some special case character so do all of the checks and
  1260.         //  deal with it.
  1261.         if (!nextCh)
  1262.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  1263.         if (nextCh == chForwardSlash)
  1264.         {
  1265.             fReaderMgr.getNextChar();
  1266.             isEmpty = true;
  1267.             if (!fReaderMgr.skippedChar(chCloseAngle))
  1268.                 emitError(XMLErrs::UnterminatedStartTag, qnameRawBuf);
  1269.             break;
  1270.         }
  1271.         else if (nextCh == chCloseAngle)
  1272.         {
  1273.             fReaderMgr.getNextChar();
  1274.             break;
  1275.         }
  1276.         else if (nextCh == chOpenAngle)
  1277.         {
  1278.             //  Check for this one specially, since its going to be common
  1279.             //  and it is kind of auto-recovering since we've already hit the
  1280.             //  next open bracket, which is what we would have seeked to (and
  1281.             //  skipped this whole tag.)
  1282.             emitError(XMLErrs::UnterminatedStartTag, qnameRawBuf);
  1283.             break;
  1284.         }
  1285.         else if ((nextCh == chSingleQuote) || (nextCh == chDoubleQuote))
  1286.         {
  1287.             //  Check for this one specially, which is probably a missing
  1288.             //  attribute name, e.g. ="value". Just issue expected name
  1289.             //  error and eat the quoted string, then jump back to the
  1290.             //  top again.
  1291.             emitError(XMLErrs::ExpectedAttrName);
  1292.             fReaderMgr.getNextChar();
  1293.             fReaderMgr.skipQuotedString(nextCh);
  1294.             fReaderMgr.skipPastSpaces();
  1295.             continue;
  1296.         }
  1297.     }
  1298.     // Handle provided attributes that we did not map their prefixes
  1299.     for (unsigned int i=0; i < fAttrNSList->size(); i++) {
  1300.         XMLAttr* providedAttr = fAttrNSList->elementAt(i);
  1301.         providedAttr->setURIId
  1302.         (
  1303.         resolvePrefix
  1304.             (
  1305.                 providedAttr->getPrefix(),
  1306.                 ElemStack::Mode_Attribute
  1307.             )
  1308.         );
  1309.     }
  1310.     // Resolve the qualified name to a URI.
  1311.     unsigned int uriId = resolvePrefix
  1312.     (
  1313.         elemDecl->getElementName()->getPrefix()
  1314.         , ElemStack::Mode_Element
  1315.     );
  1316.     // Now we can update the element stack
  1317.     fElemStack.setCurrentURI(uriId);
  1318.     // Tell the document handler about this start tag
  1319.     if (fDocHandler)
  1320.     {
  1321.         fDocHandler->startElement
  1322.         (
  1323.             *elemDecl
  1324.             , uriId
  1325.             , elemDecl->getElementName()->getPrefix()
  1326.             , *fAttrList
  1327.             , attCount
  1328.             , false
  1329.             , isRoot
  1330.         );
  1331.     }
  1332.     //  If empty, validate content right now if we are validating and then
  1333.     //  pop the element stack top. Else, we have to update the current stack
  1334.     //  top's namespace mapping elements.
  1335.     if (isEmpty)
  1336.     {
  1337.         // Pop the element stack back off since it'll never be used now
  1338.         fElemStack.popTop();
  1339.         // If we have a doc handler, tell it about the end tag
  1340.         if (fDocHandler)
  1341.         {
  1342.             fDocHandler->endElement
  1343.             (
  1344.                 *elemDecl
  1345.                 , uriId
  1346.                 , isRoot
  1347.                 , elemDecl->getElementName()->getPrefix()
  1348.             );
  1349.         }
  1350.         // If the elem stack is empty, then it was an empty root
  1351.         if (isRoot)
  1352.             gotData = false;
  1353.     }
  1354.     return true;
  1355. }
  1356. unsigned int
  1357. WFXMLScanner::resolveQName(const   XMLCh* const qName
  1358.                            ,       XMLBuffer&   prefixBuf
  1359.                            , const short        mode
  1360.                            ,       int&         prefixColonPos)
  1361. {
  1362.     //  Lets split out the qName into a URI and name buffer first. The URI
  1363.     //  can be empty.
  1364.     prefixColonPos = XMLString::indexOf(qName, chColon);
  1365.     if (prefixColonPos == -1)
  1366.     {
  1367.         //  Its all name with no prefix, so put the whole thing into the name
  1368.         //  buffer. Then map the empty string to a URI, since the empty string
  1369.         //  represents the default namespace. This will either return some
  1370.         //  explicit URI which the default namespace is mapped to, or the
  1371.         //  the default global namespace.
  1372.         bool unknown = false;
  1373.         prefixBuf.reset();
  1374.         return fElemStack.mapPrefixToURI(XMLUni::fgZeroLenString, (ElemStack::MapModes) mode, unknown);
  1375.     }
  1376.     else
  1377.     {
  1378.         //  Copy the chars up to but not including the colon into the prefix
  1379.         //  buffer.
  1380.         prefixBuf.set(qName, prefixColonPos);
  1381.         //  Watch for the special namespace prefixes. We always map these to
  1382.         //  special URIs. 'xml' gets mapped to the official URI that its defined
  1383.         //  to map to by the NS spec. xmlns gets mapped to a special place holder
  1384.         //  URI that we define (so that it maps to something checkable.)
  1385.         const XMLCh* prefixRawBuf = prefixBuf.getRawBuffer();
  1386.         if (XMLString::equals(prefixRawBuf, XMLUni::fgXMLNSString)) {
  1387.             // if this is an element, it is an error to have xmlns as prefix
  1388.             if (mode == ElemStack::Mode_Element)
  1389.                 emitError(XMLErrs::NoXMLNSAsElementPrefix, qName);
  1390.             return fXMLNSNamespaceId;
  1391.         }
  1392.         else if (XMLString::equals(prefixRawBuf, XMLUni::fgXMLString)) {
  1393.             return  fXMLNamespaceId;
  1394.         }
  1395.         else
  1396.         {
  1397.             bool unknown = false;
  1398.             unsigned int uriId = fElemStack.mapPrefixToURI(prefixRawBuf, (ElemStack::MapModes) mode, unknown);
  1399.             if (unknown)
  1400.                 emitError(XMLErrs::UnknownPrefix, prefixRawBuf);
  1401.             return uriId;
  1402.         }
  1403.     }
  1404. }
  1405. // ---------------------------------------------------------------------------
  1406. //  XMLScanner: Private parsing methods
  1407. // ---------------------------------------------------------------------------
  1408. bool WFXMLScanner::scanAttValue(const XMLCh* const attrName
  1409.                               ,     XMLBuffer&   toFill)
  1410. {
  1411.     // Reset the target buffer
  1412.     toFill.reset();
  1413.     // Get the next char which must be a single or double quote
  1414.     XMLCh quoteCh;
  1415.     if (!fReaderMgr.skipIfQuote(quoteCh))
  1416.         return false;
  1417.     //  We have to get the current reader because we have to ignore closing
  1418.     //  quotes until we hit the same reader again.
  1419.     const unsigned int curReader = fReaderMgr.getCurrentReaderNum();
  1420.     //  Loop until we get the attribute value. Note that we use a double
  1421.     //  loop here to avoid the setup/teardown overhead of the exception
  1422.     //  handler on every round.
  1423.     XMLCh   nextCh;
  1424.     XMLCh   secondCh = 0;
  1425.     bool    firstNonWS = false;
  1426.     bool    gotLeadingSurrogate = false;
  1427.     bool    escaped;
  1428.     while (true)
  1429.     {
  1430.     try
  1431.     {
  1432.         while(true)
  1433.         {
  1434.             nextCh = fReaderMgr.getNextChar();
  1435.             if (!nextCh)
  1436.                 ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  1437.             // Check for our ending quote in the same entity
  1438.             if (nextCh == quoteCh)
  1439.             {
  1440.                 if (curReader == fReaderMgr.getCurrentReaderNum())
  1441.                     return true;
  1442.                 // Watch for spillover into a previous entity
  1443.                 if (curReader > fReaderMgr.getCurrentReaderNum())
  1444.                 {
  1445.                     emitError(XMLErrs::PartialMarkupInEntity);
  1446.                     return false;
  1447.                 }
  1448.             }
  1449.             //  Check for an entity ref now, before we let it affect our
  1450.             //  whitespace normalization logic below. We ignore the empty flag
  1451.             //  in this one.
  1452.             escaped = false;
  1453.             if (nextCh == chAmpersand)
  1454.             {
  1455.                 if (scanEntityRef(true, nextCh, secondCh, escaped) != EntityExp_Returned)
  1456.                 {
  1457.                     gotLeadingSurrogate = false;
  1458.                     continue;
  1459.                 }
  1460.             }
  1461.             else if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
  1462.             {
  1463.                 // Deal with surrogate pairs
  1464.                 //  Its a leading surrogate. If we already got one, then
  1465.                 //  issue an error, else set leading flag to make sure that
  1466.                 //  we look for a trailing next time.
  1467.                 if (gotLeadingSurrogate)
  1468.                 {
  1469.                     emitError(XMLErrs::Expected2ndSurrogateChar);
  1470.                 }
  1471.                 else
  1472.                     gotLeadingSurrogate = true;
  1473.             }
  1474.             else
  1475.             {
  1476.                 //  If its a trailing surrogate, make sure that we are
  1477.                 //  prepared for that. Else, its just a regular char so make
  1478.                 //  sure that we were not expected a trailing surrogate.
  1479.                 if ((nextCh >= 0xDC00) && (nextCh <= 0xDFFF))
  1480.                 {
  1481.                     // Its trailing, so make sure we were expecting it
  1482.                     if (!gotLeadingSurrogate)
  1483.                         emitError(XMLErrs::Unexpected2ndSurrogateChar);
  1484.                 }
  1485.                 else
  1486.                 {
  1487.                     //  Its just a char, so make sure we were not expecting a
  1488.                     //  trailing surrogate.
  1489.                     if (gotLeadingSurrogate) {
  1490.                         emitError(XMLErrs::Expected2ndSurrogateChar);
  1491.                     }
  1492.                     // Its got to at least be a valid XML character
  1493.                     else if (!fReaderMgr.getCurrentReader()->isXMLChar(nextCh))
  1494.                     {
  1495.                         XMLCh tmpBuf[9];
  1496.                         XMLString::binToText
  1497.                         (
  1498.                             nextCh
  1499.                             , tmpBuf
  1500.                             , 8
  1501.                             , 16
  1502.                         );
  1503.                         emitError(XMLErrs::InvalidCharacterInAttrValue, attrName, tmpBuf);
  1504.                     }
  1505.                 }
  1506.                 gotLeadingSurrogate = false;
  1507.             }
  1508.             //  If its not escaped, then make sure its not a < character, which
  1509.             //  is not allowed in attribute values.
  1510.             if (!escaped) {
  1511.                 if (nextCh == chOpenAngle)
  1512.                     emitError(XMLErrs::BracketInAttrValue, attrName);
  1513.                 else if (fReaderMgr.getCurrentReader()->isWhitespace(nextCh))
  1514.                     nextCh = chSpace;
  1515.             }
  1516.             // Else add it to the buffer
  1517.             toFill.append(nextCh);
  1518.             if (secondCh)
  1519.                toFill.append(secondCh);
  1520.         }
  1521.     }
  1522.     catch(const EndOfEntityException&)
  1523.     {
  1524.         // Just eat it and continue.
  1525.         gotLeadingSurrogate = false;
  1526.         escaped = false;
  1527.     }
  1528.     }
  1529.     return true;
  1530. }
  1531. //  This method scans a CDATA section. It collects the character into one
  1532. //  of the temp buffers and calls the document handler, if any, with the
  1533. //  characters. It assumes that the <![CDATA string has been scanned before
  1534. //  this call.
  1535. void WFXMLScanner::scanCDSection()
  1536. {
  1537.     //  This is the CDATA section opening sequence, minus the '<' character.
  1538.     //  We use this to watch for nested CDATA sections, which are illegal.
  1539.     static const XMLCh CDataPrefix[] =
  1540.     {
  1541.             chBang, chOpenSquare, chLatin_C, chLatin_D, chLatin_A
  1542.         ,   chLatin_T, chLatin_A, chOpenSquare, chNull
  1543.     };
  1544.     static const XMLCh CDataClose[] =
  1545.     {
  1546.             chCloseSquare, chCloseAngle, chNull
  1547.     };
  1548.     //  The next character should be the opening square bracket. If not
  1549.     //  issue an error, but then try to recover by skipping any whitespace
  1550.     //  and checking again.
  1551.     if (!fReaderMgr.skippedChar(chOpenSquare))
  1552.     {
  1553.         emitError(XMLErrs::ExpectedOpenSquareBracket);
  1554.         fReaderMgr.skipPastSpaces();
  1555.         // If we still don't find it, then give up, else keep going
  1556.         if (!fReaderMgr.skippedChar(chOpenSquare))
  1557.             return;
  1558.     }
  1559.     // Get a buffer for this
  1560.     XMLBufBid bbCData(&fBufMgr);
  1561.     //  We just scan forward until we hit the end of CDATA section sequence.
  1562.     //  CDATA is effectively a big escape mechanism so we don't treat markup
  1563.     //  characters specially here.
  1564.     bool            emittedError = false;
  1565.     bool    gotLeadingSurrogate = false;
  1566.     while (true)
  1567.     {
  1568.         const XMLCh nextCh = fReaderMgr.getNextChar();
  1569.         // Watch for unexpected end of file
  1570.         if (!nextCh)
  1571.         {
  1572.             emitError(XMLErrs::UnterminatedCDATASection);
  1573.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  1574.         }
  1575.         //  If this is a close square bracket it could be our closing
  1576.         //  sequence.
  1577.         if (nextCh == chCloseSquare && fReaderMgr.skippedString(CDataClose))
  1578.         {
  1579.             //  make sure we were not expecting a trailing surrogate.
  1580.             if (gotLeadingSurrogate)
  1581.                 emitError(XMLErrs::Expected2ndSurrogateChar);
  1582.             // If we have a doc handler, call it
  1583.             if (fDocHandler)
  1584.             {
  1585.                 fDocHandler->docCharacters
  1586.                 (
  1587.                     bbCData.getRawBuffer()
  1588.                     , bbCData.getLen()
  1589.                     , true
  1590.                 );
  1591.             }
  1592.             // And we are done
  1593.             break;
  1594.         }
  1595.         //  Make sure its a valid character. But if we've emitted an error
  1596.         //  already, don't bother with the overhead since we've already told
  1597.         //  them about it.
  1598.         if (!emittedError)
  1599.         {
  1600.             // Deal with surrogate pairs
  1601.             if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
  1602.             {
  1603.                 //  Its a leading surrogate. If we already got one, then
  1604.                 //  issue an error, else set leading flag to make sure that
  1605.                 //  we look for a trailing next time.
  1606.                 if (gotLeadingSurrogate)
  1607.                     emitError(XMLErrs::Expected2ndSurrogateChar);
  1608.                 else
  1609.                     gotLeadingSurrogate = true;
  1610.             }
  1611.             else
  1612.             {
  1613.                 //  If its a trailing surrogate, make sure that we are
  1614.                 //  prepared for that. Else, its just a regular char so make
  1615.                 //  sure that we were not expected a trailing surrogate.
  1616.                 if ((nextCh >= 0xDC00) && (nextCh <= 0xDFFF))
  1617.                 {
  1618.                     // Its trailing, so make sure we were expecting it
  1619.                     if (!gotLeadingSurrogate)
  1620.                         emitError(XMLErrs::Unexpected2ndSurrogateChar);
  1621.                 }
  1622.                 else
  1623.                 {
  1624.                     //  Its just a char, so make sure we were not expecting a
  1625.                     //  trailing surrogate.
  1626.                     if (gotLeadingSurrogate)
  1627.                         emitError(XMLErrs::Expected2ndSurrogateChar);
  1628.                     // Its got to at least be a valid XML character
  1629.                     else if (!fReaderMgr.getCurrentReader()->isXMLChar(nextCh))
  1630.                     {
  1631.                         XMLCh tmpBuf[9];
  1632.                         XMLString::binToText
  1633.                         (
  1634.                             nextCh
  1635.                             , tmpBuf
  1636.                             , 8
  1637.                             , 16
  1638.                         );
  1639.                         emitError(XMLErrs::InvalidCharacter, tmpBuf);
  1640.                         emittedError = true;
  1641.                     }
  1642.                 }
  1643.                 gotLeadingSurrogate = false;
  1644.             }
  1645.         }
  1646.         // Add it to the buffer
  1647.         bbCData.append(nextCh);
  1648.     }
  1649. }
  1650. void WFXMLScanner::scanCharData(XMLBuffer& toUse)
  1651. {
  1652.     //  We have to watch for the stupid ]]> sequence, which is illegal in
  1653.     //  character data. So this is a little state machine that handles that.
  1654.     enum States
  1655.     {
  1656.         State_Waiting
  1657.         , State_GotOne
  1658.         , State_GotTwo
  1659.     };
  1660.     // Reset the buffer before we start
  1661.     toUse.reset();
  1662.     // Turn on the 'throw at end' flag of the reader manager
  1663.     ThrowEOEJanitor jan(&fReaderMgr, true);
  1664.     //  In order to be more efficient we have to use kind of a deeply nested
  1665.     //  set of blocks here. The outer block puts on a try and catches end of
  1666.     //  entity exceptions. The inner loop is the per-character loop. If we
  1667.     //  put the try inside the inner loop, it would work but would require
  1668.     //  the exception handling code setup/teardown code to be invoked for
  1669.     //  each character.
  1670.     XMLCh   nextCh;
  1671.     XMLCh   secondCh = 0;
  1672.     States  curState = State_Waiting;
  1673.     bool    escaped = false;
  1674.     bool    gotLeadingSurrogate = false;
  1675.     bool    notDone = true;
  1676.     while (notDone)
  1677.     {
  1678.         try
  1679.         {
  1680.             while (true)
  1681.             {
  1682.                 //  Eat through as many plain content characters as possible without
  1683.                 //  needing special handling.  Moving most content characters here,
  1684.                 //  in this one call, rather than running the overall loop once
  1685.                 //  per content character, is a speed optimization.
  1686.                 if (curState == State_Waiting  &&  !gotLeadingSurrogate)
  1687.                 {
  1688.                      fReaderMgr.movePlainContentChars(toUse);
  1689.                 }
  1690.                 // Try to get another char from the source
  1691.                 //   The code from here on down covers all contengencies,
  1692.                 if (!fReaderMgr.getNextCharIfNot(chOpenAngle, nextCh))
  1693.                 {
  1694.                     // If we were waiting for a trailing surrogate, its an error
  1695.                     if (gotLeadingSurrogate)
  1696.                         emitError(XMLErrs::Expected2ndSurrogateChar);
  1697.                     notDone = false;
  1698.                     break;
  1699.                 }
  1700.                 //  Watch for a reference. Note that the escapement mechanism
  1701.                 //  is ignored in this content.
  1702.                 escaped = false;
  1703.                 if (nextCh == chAmpersand)
  1704.                 {
  1705.                     sendCharData(toUse);
  1706.                     // Turn off the throwing at the end of entity during this
  1707.                     ThrowEOEJanitor jan(&fReaderMgr, false);
  1708.                     if (scanEntityRef(false, nextCh, secondCh, escaped) != EntityExp_Returned)
  1709.                     {
  1710.                         gotLeadingSurrogate = false;
  1711.                         continue;
  1712.                     }
  1713.                 }
  1714.                 else if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
  1715.                 {
  1716.                     // Deal with surrogate pairs
  1717.                     //  Its a leading surrogate. If we already got one, then
  1718.                     //  issue an error, else set leading flag to make sure that
  1719.                     //  we look for a trailing next time.
  1720.                     if (gotLeadingSurrogate)
  1721.                     {
  1722.                         emitError(XMLErrs::Expected2ndSurrogateChar);
  1723.                     }
  1724.                     else
  1725.                         gotLeadingSurrogate = true;
  1726.                 }
  1727.                 else
  1728.                 {
  1729.                     //  If its a trailing surrogate, make sure that we are
  1730.                     //  prepared for that. Else, its just a regular char so make
  1731.                     //  sure that we were not expected a trailing surrogate.
  1732.                     if ((nextCh >= 0xDC00) && (nextCh <= 0xDFFF))
  1733.                     {
  1734.                         // Its trailing, so make sure we were expecting it
  1735.                         if (!gotLeadingSurrogate)
  1736.                             emitError(XMLErrs::Unexpected2ndSurrogateChar);
  1737.                     }
  1738.                     else
  1739.                     {
  1740.                         //  Its just a char, so make sure we were not expecting a
  1741.                         //  trailing surrogate.
  1742.                         if (gotLeadingSurrogate) {
  1743.                             emitError(XMLErrs::Expected2ndSurrogateChar);
  1744.                         }
  1745.                         // Its got to at least be a valid XML character
  1746.                         else if (!fReaderMgr.getCurrentReader()->isXMLChar(nextCh))
  1747.                         {
  1748.                             XMLCh tmpBuf[9];
  1749.                             XMLString::binToText
  1750.                             (
  1751.                                 nextCh
  1752.                                 , tmpBuf
  1753.                                 , 8
  1754.                                 , 16
  1755.                             );
  1756.                             emitError(XMLErrs::InvalidCharacter, tmpBuf);
  1757.                         }
  1758.                     }
  1759.                     gotLeadingSurrogate = false;
  1760.                 }
  1761.                 // Keep the state machine up to date
  1762.                 if (!escaped)
  1763.                 {
  1764.                     if (nextCh == chCloseSquare)
  1765.                     {
  1766.                         if (curState == State_Waiting)
  1767.                             curState = State_GotOne;
  1768.                         else if (curState == State_GotOne)
  1769.                             curState = State_GotTwo;
  1770.                     }
  1771.                     else if (nextCh == chCloseAngle)
  1772.                     {
  1773.                         if (curState == State_GotTwo)
  1774.                             emitError(XMLErrs::BadSequenceInCharData);
  1775.                         curState = State_Waiting;
  1776.                     }
  1777.                     else
  1778.                     {
  1779.                         curState = State_Waiting;
  1780.                     }
  1781.                 }
  1782.                 else
  1783.                 {
  1784.                     curState = State_Waiting;
  1785.                 }
  1786.                 // Add this char to the buffer
  1787.                 toUse.append(nextCh);
  1788.                 if (secondCh)
  1789.                     toUse.append(secondCh);
  1790.             }
  1791.         }
  1792.         catch(const EndOfEntityException& toCatch)
  1793.         {
  1794.             //  Some entity ended, so we have to send any accumulated
  1795.             //  chars and send an end of entity event.
  1796.             sendCharData(toUse);
  1797.             gotLeadingSurrogate = false;
  1798.             if (fDocHandler)
  1799.                 fDocHandler->endEntityReference(toCatch.getEntity());
  1800.         }
  1801.     }
  1802.     // Send any char data that we accumulated into the buffer
  1803.     sendCharData(toUse);
  1804. }
  1805. //  This method will scan a general/character entity ref. It will either
  1806. //  expand a char ref and return it directly, or push a reader for a general
  1807. //  entity.
  1808. //
  1809. //  The return value indicates whether the char parameters hold the value
  1810. //  or whether the value was pushed as a reader, or that it failed.
  1811. //
  1812. //  The escaped flag tells the caller whether the returned parameter resulted
  1813. //  from a character reference, which escapes the character in some cases. It
  1814. //  only makes any difference if the return value indicates the value was
  1815. //  returned directly.
  1816. XMLScanner::EntityExpRes
  1817. WFXMLScanner::scanEntityRef(const bool    inAttVal
  1818.                             ,     XMLCh&  firstCh
  1819.                             ,     XMLCh&  secondCh
  1820.                             ,     bool&   escaped)
  1821. {
  1822.     // Assume no escape
  1823.     secondCh = 0;
  1824.     escaped = false;
  1825.     // We have to insure that its all in one entity
  1826.     const unsigned int curReader = fReaderMgr.getCurrentReaderNum();
  1827.     //  If the next char is a pound, then its a character reference and we
  1828.     //  need to expand it always.
  1829.     if (fReaderMgr.skippedChar(chPound))
  1830.     {
  1831.         //  Its a character reference, so scan it and get back the numeric
  1832.         //  value it represents.
  1833.         if (!scanCharRef(firstCh, secondCh))
  1834.             return EntityExp_Failed;
  1835.         escaped = true;
  1836.         if (curReader != fReaderMgr.getCurrentReaderNum())
  1837.             emitError(XMLErrs::PartialMarkupInEntity);
  1838.         return EntityExp_Returned;
  1839.     }
  1840.     // Expand it since its a normal entity ref
  1841.     XMLBufBid bbName(&fBufMgr);
  1842.     if (!fReaderMgr.getName(bbName.getBuffer()))
  1843.     {
  1844.         emitError(XMLErrs::ExpectedEntityRefName);
  1845.         return EntityExp_Failed;
  1846.     }
  1847.     //  Next char must be a semi-colon. But if its not, just emit
  1848.     //  an error and try to continue.
  1849.     if (!fReaderMgr.skippedChar(chSemiColon))
  1850.         emitError(XMLErrs::UnterminatedEntityRef, bbName.getRawBuffer());
  1851.     // Make sure we ended up on the same entity reader as the & char
  1852.     if (curReader != fReaderMgr.getCurrentReaderNum())
  1853.         emitError(XMLErrs::PartialMarkupInEntity);
  1854.     // Look up the name in the general entity pool
  1855.     // If it does not exist, then obviously an error
  1856.     if (!fEntityTable->containsKey(bbName.getRawBuffer()))
  1857.     {
  1858.         // XML 1.0 Section 4.1
  1859.         // Well-formedness Constraint for entity not found:
  1860.         //   In a document without any DTD, a document with only an internal DTD subset which contains no parameter entity references,
  1861.         //      or a document with "standalone='yes'", for an entity reference that does not occur within the external subset
  1862.         //      or a parameter entity
  1863.         if (fStandalone || fHasNoDTD)
  1864.             emitError(XMLErrs::EntityNotFound, bbName.getRawBuffer());
  1865.         return EntityExp_Failed;
  1866.     }
  1867.     // here's where we need to check if there's a SecurityManager,
  1868.     // how many entity references we've had
  1869.     if(fSecurityManager != 0 && ++fEntityExpansionCount > fEntityExpansionLimit) {
  1870.         XMLCh expLimStr[16];
  1871.         XMLString::binToText(fEntityExpansionLimit, expLimStr, 15, 10);
  1872.         emitError
  1873.         ( 
  1874.             XMLErrs::EntityExpansionLimitExceeded
  1875.             , expLimStr
  1876.         );
  1877.         // there seems nothing better to be done than to reset the entity expansion counter
  1878.         fEntityExpansionCount = 0;
  1879.     }
  1880.     firstCh = fEntityTable->get(bbName.getRawBuffer());
  1881.     escaped = true;
  1882.     return EntityExp_Returned;
  1883. }
  1884. // ---------------------------------------------------------------------------
  1885. //  WFXMLScanner: Grammar preparsing
  1886. // ---------------------------------------------------------------------------
  1887. Grammar* WFXMLScanner::loadGrammar(const   InputSource&
  1888.                                    , const short
  1889.                                    , const bool)
  1890. {
  1891.     // REVISIT: emit a warning or throw an exception
  1892.     return 0;
  1893. }
  1894. XERCES_CPP_NAMESPACE_END