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

词法分析

开发平台:

Visual C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 1999-2002 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: XMLScanner.cpp,v 1.45 2003/05/18 14:02:04 knoaman Exp $
  58.  */
  59. // ---------------------------------------------------------------------------
  60. //  Includes
  61. // ---------------------------------------------------------------------------
  62. #include <xercesc/internal/XMLScanner.hpp>
  63. #include <xercesc/util/Janitor.hpp>
  64. #include <xercesc/util/Mutexes.hpp>
  65. #include <xercesc/util/RuntimeException.hpp>
  66. #include <xercesc/util/UnexpectedEOFException.hpp>
  67. #include <xercesc/util/XMLMsgLoader.hpp>
  68. #include <xercesc/util/XMLRegisterCleanup.hpp>
  69. #include <xercesc/framework/LocalFileInputSource.hpp>
  70. #include <xercesc/framework/URLInputSource.hpp>
  71. #include <xercesc/framework/XMLDocumentHandler.hpp>
  72. #include <xercesc/framework/XMLEntityHandler.hpp>
  73. #include <xercesc/framework/XMLPScanToken.hpp>
  74. #include <xercesc/framework/XMLValidator.hpp>
  75. #include <xercesc/internal/EndOfEntityException.hpp>
  76. #include <xercesc/validators/DTD/DocTypeHandler.hpp>
  77. #include <xercesc/validators/common/GrammarResolver.hpp>
  78. XERCES_CPP_NAMESPACE_BEGIN
  79. // ---------------------------------------------------------------------------
  80. //  Local static data
  81. // ---------------------------------------------------------------------------
  82. static XMLUInt32       gScannerId;
  83. static bool            sRegistered = false;
  84. static XMLMutex*       sScannerMutex = 0;
  85. static XMLRegisterCleanup scannerMutexCleanup;
  86. static XMLMsgLoader*   gMsgLoader = 0;
  87. static XMLRegisterCleanup cleanupMsgLoader;
  88. // ---------------------------------------------------------------------------
  89. //  Local, static functions
  90. // ---------------------------------------------------------------------------
  91. //  Cleanup for the message loader
  92. void XMLScanner::reinitMsgLoader()
  93. {
  94. delete gMsgLoader;
  95. gMsgLoader = 0;
  96. }
  97. //  Cleanup for the scanner mutex
  98. void XMLScanner::reinitScannerMutex()
  99. {
  100.     delete sScannerMutex;
  101.     sScannerMutex = 0;
  102.     sRegistered = false;
  103. }
  104. //
  105. //  We need to fault in this mutex. But, since its used for synchronization
  106. //  itself, we have to do this the low level way using a compare and swap.
  107. //
  108. static XMLMutex& gScannerMutex()
  109. {
  110.     if (!sScannerMutex)
  111.     {
  112.         XMLMutex* tmpMutex = new XMLMutex;
  113.         if (XMLPlatformUtils::compareAndSwap((void**)&sScannerMutex, tmpMutex, 0))
  114.         {
  115.             // Someone beat us to it, so let's clean up ours
  116.             delete tmpMutex;
  117.         }
  118.         // Now lock it and try to register it
  119.         XMLMutexLock lock(sScannerMutex);
  120.         // If we got here first, then register it and set the registered flag
  121.         if (!sRegistered)
  122.         {
  123. scannerMutexCleanup.registerCleanup(XMLScanner::reinitScannerMutex);
  124.             sRegistered = true;
  125.         }
  126.     }
  127.     return *sScannerMutex;
  128. }
  129. static XMLMsgLoader& gScannerMsgLoader()
  130. {
  131.     XMLMutexLock lockInit(&gScannerMutex());
  132.     // If we haven't loaded our message yet, then do that
  133.     if (!gMsgLoader)
  134.     {
  135.         gMsgLoader = XMLPlatformUtils::loadMsgSet(XMLUni::fgXMLErrDomain);
  136.         if (!gMsgLoader)
  137.             XMLPlatformUtils::panic(PanicHandler::Panic_CantLoadMsgDomain);
  138.         // Register this object to be cleaned up at termination
  139.         cleanupMsgLoader.registerCleanup(XMLScanner::reinitMsgLoader);
  140.     }
  141.     return *gMsgLoader;
  142. }
  143. // ---------------------------------------------------------------------------
  144. //  XMLScanner: Constructors and Destructor
  145. // ---------------------------------------------------------------------------
  146. XMLScanner::XMLScanner(XMLValidator* const valToAdopt,
  147.                        MemoryManager* const manager) :
  148.     fCalculateSrcOfs(false)
  149.     , fDoNamespaces(false)
  150.     , fExitOnFirstFatal(true)
  151.     , fValidationConstraintFatal(false)
  152.     , fInException(false)
  153.     , fStandalone(false)
  154.     , fHasNoDTD(true)
  155.     , fValidate(false)
  156.     , fValidatorFromUser(false)
  157.     , fDoSchema(false)
  158.     , fSchemaFullChecking(false)
  159.     , fToCacheGrammar(false)
  160.     , fUseCachedGrammar(false)
  161.     , fLoadExternalDTD(true)
  162.     , fNormalizeData(true)
  163.     , fErrorCount(0)
  164.     , fEmptyNamespaceId(0)
  165.     , fUnknownNamespaceId(0)
  166.     , fXMLNamespaceId(0)
  167.     , fXMLNSNamespaceId(0)
  168.     , fSchemaNamespaceId(0)
  169.     , fScannerId(0)
  170.     , fSequenceId(0)
  171.     , fAttrList(0)
  172.     , fDocHandler(0)
  173.     , fDocTypeHandler(0)
  174.     , fEntityHandler(0)
  175.     , fErrorReporter(0)
  176.     , fErrorHandler(0)
  177.     , fIDRefList(0)
  178.     , fReaderMgr(manager)
  179.     , fValidator(valToAdopt)
  180.     , fValScheme(Val_Never)
  181.     , fGrammarResolver(0)
  182.     , fGrammar(0)
  183.     , fRootGrammar(0)
  184.     , fURIStringPool(0)
  185.     , fRootElemName(0)
  186.     , fExternalSchemaLocation(0)
  187.     , fExternalNoNamespaceSchemaLocation(0)
  188.     , fStandardUriConformant(false)
  189.     , fSecurityManager(0)
  190.     , fXMLVersion(XMLReader::XMLV1_0)
  191.     , fMemoryManager(manager)
  192.     , fBufMgr(manager)
  193.     , fAttNameBuf(1023, manager)
  194.     , fAttValueBuf(1023, manager)
  195.     , fCDataBuf(1023, manager)
  196.     , fQNameBuf(1023, manager)
  197.     , fPrefixBuf(1023, manager)
  198.     , fURIBuf(1023, manager)
  199. {
  200.    commonInit();
  201.    if (fValidator) {
  202.        fValidatorFromUser = true;
  203.        initValidator(fValidator);
  204.    }
  205. }
  206. XMLScanner::XMLScanner( XMLDocumentHandler* const  docHandler
  207.                           , DocTypeHandler* const    docTypeHandler
  208.                           , XMLEntityHandler* const  entityHandler
  209.                           , XMLErrorReporter* const  errHandler
  210.                           , XMLValidator* const      valToAdopt
  211.                           , MemoryManager* const     manager) :
  212.     fCalculateSrcOfs(false)
  213.     , fDoNamespaces(false)
  214.     , fExitOnFirstFatal(true)
  215.     , fValidationConstraintFatal(false)
  216.     , fInException(false)
  217.     , fStandalone(false)
  218.     , fHasNoDTD(true)
  219.     , fValidate(false)
  220.     , fValidatorFromUser(false)
  221.     , fDoSchema(false)
  222.     , fSchemaFullChecking(false)
  223.     , fToCacheGrammar(false)
  224.     , fUseCachedGrammar(false)
  225. , fLoadExternalDTD(true)
  226.     , fNormalizeData(true)
  227.     , fErrorCount(0)
  228.     , fEmptyNamespaceId(0)
  229.     , fUnknownNamespaceId(0)
  230.     , fXMLNamespaceId(0)
  231.     , fXMLNSNamespaceId(0)
  232.     , fSchemaNamespaceId(0)
  233.     , fScannerId(0)
  234.     , fSequenceId(0)
  235.     , fAttrList(0)
  236.     , fDocHandler(docHandler)
  237.     , fDocTypeHandler(docTypeHandler)
  238.     , fEntityHandler(entityHandler)
  239.     , fErrorReporter(errHandler)
  240.     , fErrorHandler(0)
  241.     , fIDRefList(0)
  242.     , fReaderMgr(manager)
  243.     , fValidator(valToAdopt)
  244.     , fValScheme(Val_Never)
  245.     , fGrammarResolver(0)
  246.     , fGrammar(0)
  247.     , fRootGrammar(0)
  248.     , fURIStringPool(0)
  249.     , fRootElemName(0)
  250.     , fExternalSchemaLocation(0)
  251.     , fExternalNoNamespaceSchemaLocation(0)
  252.     , fStandardUriConformant(false)
  253.     , fSecurityManager(0)
  254.     , fXMLVersion(XMLReader::XMLV1_0)
  255.     , fMemoryManager(manager)
  256.     , fBufMgr(manager)
  257.     , fAttNameBuf(1023, manager)
  258.     , fAttValueBuf(1023, manager)
  259.     , fCDataBuf(1023, manager)
  260.     , fQNameBuf(1023, manager)
  261.     , fPrefixBuf(1023, manager)
  262.     , fURIBuf(1023, manager)
  263. {
  264.    commonInit();
  265.    if (valToAdopt){
  266.        fValidatorFromUser = true;
  267.        initValidator(fValidator);
  268.    }
  269. }
  270. XMLScanner::~XMLScanner()
  271. {
  272.     delete fAttrList;
  273.     delete fIDRefList;
  274.     fMemoryManager->deallocate(fRootElemName);//delete [] fRootElemName;
  275.     fMemoryManager->deallocate(fExternalSchemaLocation);//delete [] fExternalSchemaLocation;
  276.     fMemoryManager->deallocate(fExternalNoNamespaceSchemaLocation);//delete [] fExternalNoNamespaceSchemaLocation;
  277. }
  278. void XMLScanner::setValidator(XMLValidator* const valToAdopt)
  279. {
  280.     if (fValidatorFromUser)
  281.         delete fValidator;
  282.     fValidator = valToAdopt;
  283.     fValidatorFromUser = true;
  284.     initValidator(fValidator);
  285. }
  286. // ---------------------------------------------------------------------------
  287. //  XMLScanner: Main entry point to scan a document
  288. // ---------------------------------------------------------------------------
  289. void XMLScanner::scanDocument(  const   XMLCh* const    systemId)
  290. {
  291.     //  First we try to parse it as a URL. If that fails, we assume its
  292.     //  a file and try it that way.
  293.     InputSource* srcToUse = 0;
  294.     try
  295.     {
  296.         //  Create a temporary URL. Since this is the primary document,
  297.         //  it has to be fully qualified. If not, then assume we are just
  298.         //  mistaking a file for a URL.
  299.         XMLURL tmpURL(systemId, fMemoryManager);
  300.         if (tmpURL.isRelative()) {
  301.             if (!fStandardUriConformant)
  302.                 srcToUse = new (fMemoryManager) LocalFileInputSource(systemId, fMemoryManager);
  303.             else {
  304.                 // since this is the top of the try/catch, cannot call ThrowXML
  305.                 // emit the error directly
  306.                 MalformedURLException e(__FILE__, __LINE__, XMLExcepts::URL_NoProtocolPresent);
  307.                 fInException = true;
  308.                 emitError
  309.                 (
  310.                     XMLErrs::XMLException_Fatal
  311.                     , e.getType()
  312.                     , e.getMessage()
  313.                 );
  314.                 return;
  315.             }
  316.         }
  317.         else
  318.         {
  319.             if (fStandardUriConformant && tmpURL.hasInvalidChar()) {
  320.                 MalformedURLException e(__FILE__, __LINE__, XMLExcepts::URL_MalformedURL);
  321.                 fInException = true;
  322.                 emitError
  323.                 (
  324.                     XMLErrs::XMLException_Fatal
  325.                     , e.getType()
  326.                     , e.getMessage()
  327.                 );
  328.                 return;
  329.             }
  330.             srcToUse = new (fMemoryManager) URLInputSource(tmpURL, fMemoryManager);
  331.         }
  332.     }
  333.     catch(const MalformedURLException& e)
  334.     {
  335.         if (!fStandardUriConformant)
  336.             srcToUse = new (fMemoryManager) LocalFileInputSource(systemId, fMemoryManager);
  337.         else {
  338.             // since this is the top of the try/catch, cannot call ThrowXML
  339.             // emit the error directly
  340.             // lazy bypass ... since all MalformedURLException are fatal, no need to check the type
  341.             fInException = true;
  342.             emitError
  343.             (
  344.                 XMLErrs::XMLException_Fatal
  345.                 , e.getType()
  346.                 , e.getMessage()
  347.             );
  348.             return;
  349.         }
  350.     }
  351.     catch(const XMLException& excToCatch)
  352.     {
  353.         //  For any other XMLException,
  354.         //  emit the error and catch any user exception thrown from here.
  355.         fInException = true;
  356.         if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
  357.             emitError
  358.             (
  359.                 XMLErrs::XMLException_Warning
  360.                 , excToCatch.getType()
  361.                 , excToCatch.getMessage()
  362.             );
  363.         else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
  364.             emitError
  365.             (
  366.                 XMLErrs::XMLException_Fatal
  367.                 , excToCatch.getType()
  368.                 , excToCatch.getMessage()
  369.             );
  370.         else
  371.             emitError
  372.             (
  373.                 XMLErrs::XMLException_Error
  374.                 , excToCatch.getType()
  375.                 , excToCatch.getMessage()
  376.             );
  377.         return;
  378.     }
  379.     catch(...)
  380.     {
  381.         // Just rethrow this, since its not our problem
  382.         throw;
  383.     }
  384.     Janitor<InputSource> janSrc(srcToUse);
  385.     scanDocument(*srcToUse);
  386. }
  387. void XMLScanner::scanDocument(  const   char* const systemId)
  388. {
  389.     // We just delegate this to the XMLCh version after transcoding
  390.     XMLCh* tmpBuf = XMLString::transcode(systemId, fMemoryManager);
  391.     ArrayJanitor<XMLCh> janBuf(tmpBuf, fMemoryManager);
  392.     scanDocument(tmpBuf);
  393. }
  394. //  This method begins a progressive parse. It scans through the prolog and
  395. //  returns a token to be used on subsequent scanNext() calls. If the return
  396. //  value is true, then the token is legal and ready for further use. If it
  397. //  returns false, then the scan of the prolog failed and the token is not
  398. //  going to work on subsequent scanNext() calls.
  399. bool XMLScanner::scanFirst( const   XMLCh* const    systemId
  400.                             ,       XMLPScanToken&  toFill)
  401. {
  402.     //  First we try to parse it as a URL. If that fails, we assume its
  403.     //  a file and try it that way.
  404.     InputSource* srcToUse = 0;
  405.     try
  406.     {
  407.         //  Create a temporary URL. Since this is the primary document,
  408.         //  it has to be fully qualified. If not, then assume we are just
  409.         //  mistaking a file for a URL.
  410.         XMLURL tmpURL(systemId, fMemoryManager);
  411.         if (tmpURL.isRelative()) {
  412.             if (!fStandardUriConformant)
  413.                 srcToUse = new (fMemoryManager) LocalFileInputSource(systemId, fMemoryManager);
  414.             else {
  415.                 // since this is the top of the try/catch, cannot call ThrowXML
  416.                 // emit the error directly
  417.                 MalformedURLException e(__FILE__, __LINE__, XMLExcepts::URL_NoProtocolPresent);
  418.                 fInException = true;
  419.                 emitError
  420.                 (
  421.                     XMLErrs::XMLException_Fatal
  422.                     , e.getType()
  423.                     , e.getMessage()
  424.                 );
  425.                 return false;
  426.             }
  427.         }
  428.         else
  429.         {
  430.             if (fStandardUriConformant && tmpURL.hasInvalidChar()) {
  431.                 MalformedURLException e(__FILE__, __LINE__, XMLExcepts::URL_MalformedURL);
  432.                 fInException = true;
  433.                 emitError
  434.                 (
  435.                     XMLErrs::XMLException_Fatal
  436.                     , e.getType()
  437.                     , e.getMessage()
  438.                 );
  439.                 return false;
  440.             }
  441.             srcToUse = new (fMemoryManager) URLInputSource(tmpURL, fMemoryManager);
  442.         }
  443.     }
  444.     catch(const MalformedURLException& e)
  445.     {
  446.         if (!fStandardUriConformant)
  447.             srcToUse = new (fMemoryManager) LocalFileInputSource(systemId,  fMemoryManager);
  448.         else {
  449.             // since this is the top of the try/catch, cannot call ThrowXML
  450.             // emit the error directly
  451.             // lazy bypass ... since all MalformedURLException are fatal, no need to check the type
  452.             fInException = true;
  453.             emitError
  454.             (
  455.                 XMLErrs::XMLException_Fatal
  456.                 , e.getType()
  457.                 , e.getMessage()
  458.             );
  459.             return false;
  460.         }
  461.     }
  462.     catch(const XMLException& excToCatch)
  463.     {
  464.         //  For any other XMLException,
  465.         //  emit the error and catch any user exception thrown from here.
  466.         fInException = true;
  467.         if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
  468.             emitError
  469.             (
  470.                 XMLErrs::XMLException_Warning
  471.                 , excToCatch.getType()
  472.                 , excToCatch.getMessage()
  473.             );
  474.         else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
  475.             emitError
  476.             (
  477.                 XMLErrs::XMLException_Fatal
  478.                 , excToCatch.getType()
  479.                 , excToCatch.getMessage()
  480.             );
  481.         else
  482.             emitError
  483.             (
  484.                 XMLErrs::XMLException_Error
  485.                 , excToCatch.getType()
  486.                 , excToCatch.getMessage()
  487.             );
  488.         return false;
  489.     }
  490.     catch(...)
  491.     {
  492.         // Just rethrow this, since its not our problem
  493.         throw;
  494.     }
  495.     Janitor<InputSource> janSrc(srcToUse);
  496.     return scanFirst(*srcToUse, toFill);
  497. }
  498. bool XMLScanner::scanFirst( const   char* const     systemId
  499.                             ,       XMLPScanToken&  toFill)
  500. {
  501.     // We just delegate this to the XMLCh version after transcoding
  502.     XMLCh* tmpBuf = XMLString::transcode(systemId, fMemoryManager);
  503.     ArrayJanitor<XMLCh> janBuf(tmpBuf, fMemoryManager);
  504.     return scanFirst(tmpBuf, toFill);
  505. }
  506. bool XMLScanner::scanFirst( const   InputSource&    src
  507.                            ,       XMLPScanToken&  toFill)
  508. {
  509.     //  Bump up the sequence id for this new scan cycle. This will invalidate
  510.     //  any previous tokens we've returned.
  511.     fSequenceId++;
  512.     // Reset the scanner and its plugged in stuff for a new run.  This
  513.     // resets all the data structures, creates the initial reader and
  514.     // pushes it on the stack, and sets up the base document path
  515.     scanReset(src);
  516.     // If we have a document handler, then call the start document
  517.     if (fDocHandler)
  518.         fDocHandler->startDocument();
  519.     try
  520.     {
  521.         //  Scan the prolog part, which is everything before the root element
  522.         //  including the DTD subsets. This is all that is done on the scan
  523.         //  first.
  524.         scanProlog();
  525.         //  If we got to the end of input, then its not a valid XML file.
  526.         //  Else, go on to scan the content.
  527.         if (fReaderMgr.atEOF())
  528.         {
  529.             emitError(XMLErrs::EmptyMainEntity);
  530.         }
  531.     }
  532.     //  NOTE:
  533.     //
  534.     //  In all of the error processing below, the emitError() call MUST come
  535.     //  before the flush of the reader mgr, or it will fail because it tries
  536.     //  to find out the position in the XML source of the error.
  537.     catch(const XMLErrs::Codes)
  538.     {
  539.         // This is a 'first failure' exception so reset and return a failure
  540.         fReaderMgr.reset();
  541.         return false;
  542.     }
  543.     catch(const XMLValid::Codes)
  544.     {
  545.         // This is a 'first fatal error' type exit, so reset and reuturn failure
  546.         fReaderMgr.reset();
  547.         return false;
  548.     }
  549.     catch(const XMLException& excToCatch)
  550.     {
  551.         //  Emit the error and catch any user exception thrown from here. Make
  552.         //  sure in all cases we flush the reader manager.
  553.         fInException = true;
  554.         try
  555.         {
  556.             if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
  557.                 emitError
  558.                 (
  559.                     XMLErrs::XMLException_Warning
  560.                     , excToCatch.getType()
  561.                     , excToCatch.getMessage()
  562.                 );
  563.             else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
  564.                 emitError
  565.                 (
  566.                     XMLErrs::XMLException_Fatal
  567.                     , excToCatch.getType()
  568.                     , excToCatch.getMessage()
  569.                 );
  570.             else
  571.                 emitError
  572.                 (
  573.                     XMLErrs::XMLException_Error
  574.                     , excToCatch.getType()
  575.                     , excToCatch.getMessage()
  576.                 );
  577.         }
  578.         catch(...)
  579.         {
  580.             // Reset and rethrow the user error
  581.             fReaderMgr.reset();
  582.             throw;
  583.         }
  584.         // Reset and return a failure
  585.         fReaderMgr.reset();
  586.         return false;
  587.     }
  588.     catch(...)
  589.     {
  590.         // Reset and rethrow original error
  591.         fReaderMgr.reset();
  592.         throw;
  593.     }
  594.     // Fill in the caller's token to make it legal and return success
  595.     toFill.set(fScannerId, fSequenceId);
  596.     return true;
  597. }
  598. void XMLScanner::scanReset(XMLPScanToken& token)
  599. {
  600.     // Make sure this token is still legal
  601.     if (!isLegalToken(token))
  602.         ThrowXML(RuntimeException, XMLExcepts::Scan_BadPScanToken);
  603.     // Reset the reader manager
  604.     fReaderMgr.reset();
  605.     // And invalidate any tokens by bumping our sequence number
  606.     fSequenceId++;
  607.     // Reset our error count
  608.     fErrorCount = 0;
  609. }
  610. void XMLScanner::setParseSettings(XMLScanner* const refScanner)
  611. {
  612.     setDocHandler(refScanner->getDocHandler());
  613.     setDocTypeHandler(refScanner->getDocTypeHandler());
  614.     setErrorHandler(refScanner->getErrorHandler());
  615.     setErrorReporter(refScanner->getErrorReporter());
  616.     setEntityHandler(refScanner->getEntityHandler());
  617.     setDoNamespaces(refScanner->getDoNamespaces());
  618.     setDoSchema(refScanner->getDoSchema());
  619.     setCalculateSrcOfs(refScanner->getCalculateSrcOfs());
  620.     setStandardUriConformant(refScanner->getStandardUriConformant());
  621.     setExitOnFirstFatal(refScanner->getExitOnFirstFatal());
  622.     setValidationConstraintFatal(refScanner->getValidationConstraintFatal());
  623.     setValidationSchemaFullChecking(refScanner->getValidationSchemaFullChecking());
  624.     cacheGrammarFromParse(refScanner->isCachingGrammarFromParse());
  625.     useCachedGrammarInParse(refScanner->isUsingCachedGrammarInParse());
  626.     setLoadExternalDTD(refScanner->getLoadExternalDTD());
  627.     setNormalizeData(refScanner->getNormalizeData());
  628.     setExternalSchemaLocation(refScanner->getExternalSchemaLocation());
  629.     setExternalNoNamespaceSchemaLocation(refScanner->getExternalNoNamespaceSchemaLocation());
  630.     setValidationScheme(refScanner->getValidationScheme());
  631. }
  632. // ---------------------------------------------------------------------------
  633. //  XMLScanner: Private helper methods.
  634. // ---------------------------------------------------------------------------
  635. //  This method handles the common initialization, to avoid having to do
  636. //  it redundantly in multiple constructors.
  637. void XMLScanner::commonInit()
  638. {
  639.     //  We have to do a little init that involves statics, so we have to
  640.     //  use the mutex to protect it.
  641.     {
  642.         XMLMutexLock lockInit(&gScannerMutex());
  643.         // And assign ourselves the next available scanner id
  644.         fScannerId = ++gScannerId;
  645.     }
  646.     //  Create the attribute list, which is used to store attribute values
  647.     //  during start tag processing. Give it a reasonable initial size that
  648.     //  will serve for most folks, though it will grow as required.
  649.     fAttrList = new (fMemoryManager) RefVectorOf<XMLAttr>(32, true, fMemoryManager);
  650.     //  Create the id ref list. This is used to enforce XML 1.0 ID ref
  651.     //  semantics, i.e. all id refs must refer to elements that exist
  652.     fIDRefList = new (fMemoryManager) RefHashTableOf<XMLRefInfo>(109, fMemoryManager);
  653.     //  Create the GrammarResolver
  654.     //fGrammarResolver = new GrammarResolver();
  655. }
  656. void XMLScanner::initValidator(XMLValidator* theValidator) {
  657.     //  Tell the validator about the stuff it needs to know in order to
  658.     //  do its work.
  659.     theValidator->setScannerInfo(this, &fReaderMgr, &fBufMgr);
  660.     theValidator->setErrorReporter(fErrorReporter);
  661. }
  662. // ---------------------------------------------------------------------------
  663. //  XMLScanner: Error emitting methods
  664. // ---------------------------------------------------------------------------
  665. //  These methods are called whenever the scanner wants to emit an error.
  666. //  It handles getting the message loaded, doing token replacement, etc...
  667. //  and then calling the error handler, if its installed.
  668. void XMLScanner::emitError(const XMLErrs::Codes toEmit)
  669. {
  670.     // Bump the error count if it is not a warning
  671.     if (XMLErrs::errorType(toEmit) != XMLErrorReporter::ErrType_Warning)
  672.         incrementErrorCount();
  673.     if (fErrorReporter)
  674.     {
  675.         // Load the message into a local for display
  676.         const unsigned int msgSize = 1023;
  677.         XMLCh errText[msgSize + 1];
  678.         if (!gScannerMsgLoader().loadMsg(toEmit, errText, msgSize))
  679.         {
  680.                 // <TBD> Probably should load a default msg here
  681.         }
  682.         //  Create a LastExtEntityInfo structure and get the reader manager
  683.         //  to fill it in for us. This will give us the information about
  684.         //  the last reader on the stack that was an external entity of some
  685.         //  sort (i.e. it will ignore internal entities.
  686.         ReaderMgr::LastExtEntityInfo lastInfo;
  687.         fReaderMgr.getLastExtEntityInfo(lastInfo);
  688.         fErrorReporter->error
  689.         (
  690.             toEmit
  691.             , XMLUni::fgXMLErrDomain
  692.             , XMLErrs::errorType(toEmit)
  693.             , errText
  694.             , lastInfo.systemId
  695.             , lastInfo.publicId
  696.             , lastInfo.lineNumber
  697.             , lastInfo.colNumber
  698.         );
  699.     }
  700.     // Bail out if its fatal an we are to give up on the first fatal error
  701.     if (XMLErrs::isFatal(toEmit) && fExitOnFirstFatal && !fInException)
  702.         throw toEmit;
  703. }
  704. void XMLScanner::emitError( const   XMLErrs::Codes    toEmit
  705.                             , const XMLCh* const        text1
  706.                             , const XMLCh* const        text2
  707.                             , const XMLCh* const        text3
  708.                             , const XMLCh* const        text4)
  709. {
  710.     // Bump the error count if it is not a warning
  711.     if (XMLErrs::errorType(toEmit) != XMLErrorReporter::ErrType_Warning)
  712.         incrementErrorCount();
  713.     if (fErrorReporter)
  714.     {
  715.         //  Load the message into alocal and replace any tokens found in
  716.         //  the text.
  717.         const unsigned int maxChars = 2047;
  718.         XMLCh errText[maxChars + 1];
  719.         if (!gScannerMsgLoader().loadMsg(toEmit, errText, maxChars, text1, text2, text3, text4))
  720.         {
  721.                 // <TBD> Should probably load a default message here
  722.         }
  723.         //  Create a LastExtEntityInfo structure and get the reader manager
  724.         //  to fill it in for us. This will give us the information about
  725.         //  the last reader on the stack that was an external entity of some
  726.         //  sort (i.e. it will ignore internal entities.
  727.         ReaderMgr::LastExtEntityInfo lastInfo;
  728.         fReaderMgr.getLastExtEntityInfo(lastInfo);
  729.         fErrorReporter->error
  730.         (
  731.             toEmit
  732.             , XMLUni::fgXMLErrDomain
  733.             , XMLErrs::errorType(toEmit)
  734.             , errText
  735.             , lastInfo.systemId
  736.             , lastInfo.publicId
  737.             , lastInfo.lineNumber
  738.             , lastInfo.colNumber
  739.         );
  740.     }
  741.     // Bail out if its fatal an we are to give up on the first fatal error
  742.     if (XMLErrs::isFatal(toEmit) && fExitOnFirstFatal && !fInException)
  743.         throw toEmit;
  744. }
  745. void XMLScanner::emitError( const   XMLErrs::Codes    toEmit
  746.                             , const char* const         text1
  747.                             , const char* const         text2
  748.                             , const char* const         text3
  749.                             , const char* const         text4)
  750. {
  751.     // Bump the error count if it is not a warning
  752.     if (XMLErrs::errorType(toEmit) != XMLErrorReporter::ErrType_Warning)
  753.         incrementErrorCount();
  754.     if (fErrorReporter)
  755.     {
  756.         //  Load the message into alocal and replace any tokens found in
  757.         //  the text.
  758.         const unsigned int maxChars = 2047;
  759.         XMLCh errText[maxChars + 1];
  760.         if (!gScannerMsgLoader().loadMsg(toEmit, errText, maxChars, text1, text2, text3, text4))
  761.         {
  762.                 // <TBD> Should probably load a default message here
  763.         }
  764.         //  Create a LastExtEntityInfo structure and get the reader manager
  765.         //  to fill it in for us. This will give us the information about
  766.         //  the last reader on the stack that was an external entity of some
  767.         //  sort (i.e. it will ignore internal entities.
  768.         ReaderMgr::LastExtEntityInfo lastInfo;
  769.         fReaderMgr.getLastExtEntityInfo(lastInfo);
  770.         fErrorReporter->error
  771.         (
  772.             toEmit
  773.             , XMLUni::fgXMLErrDomain
  774.             , XMLErrs::errorType(toEmit)
  775.             , errText
  776.             , lastInfo.systemId
  777.             , lastInfo.publicId
  778.             , lastInfo.lineNumber
  779.             , lastInfo.colNumber
  780.         );
  781.     }
  782.     // Bail out if its fatal an we are to give up on the first fatal error
  783.     if (XMLErrs::isFatal(toEmit) && fExitOnFirstFatal && !fInException)
  784.         throw toEmit;
  785. }
  786. // ---------------------------------------------------------------------------
  787. //  XMLScanner: Getter methods
  788. // ---------------------------------------------------------------------------
  789. //  This method allows the caller to query the current location of the scanner.
  790. //  It will return the sys/public ids of the current entity, and the line/col
  791. //  position within it.
  792. //
  793. //  NOTE: This API returns the location with the last external file. So if its
  794. //  currently scanning an entity, the position returned will be the end of
  795. //  the entity reference in the file that had the reference.
  796. //
  797. /*bool
  798. XMLScanner::getLastExtLocation(         XMLCh* const    sysIdToFill
  799.                                 , const unsigned int    maxSysIdChars
  800.                                 ,       XMLCh* const    pubIdToFill
  801.                                 , const unsigned int    maxPubIdChars
  802.                                 ,       XMLSSize_t&     lineToFill
  803.                                 ,       XMLSSize_t&     colToFill) const
  804. {
  805.     // Create a local info object and get it filled in by the reader manager
  806.     ReaderMgr::LastExtEntityInfo lastInfo;
  807.     fReaderMgr.getLastExtEntityInfo(lastInfo);
  808.     // Fill in the line and column number
  809.     lineToFill = lastInfo.lineNumber;
  810.     colToFill = lastInfo.colNumber;
  811.     // And copy over as much of the ids as will fit
  812.     sysIdToFill[0] = 0;
  813.     if (lastInfo.systemId)
  814.     {
  815.         if (XMLString::stringLen(lastInfo.systemId) > maxSysIdChars)
  816.             return false;
  817.         XMLString::copyString(sysIdToFill, lastInfo.systemId);
  818.     }
  819.     pubIdToFill[0] = 0;
  820.     if (lastInfo.publicId)
  821.     {
  822.         if (XMLString::stringLen(lastInfo.publicId) > maxPubIdChars)
  823.             return false;
  824.         XMLString::copyString(pubIdToFill, lastInfo.publicId);
  825.     }
  826.     return true;
  827. }*/
  828. // ---------------------------------------------------------------------------
  829. //  XMLScanner: Private scanning methods
  830. // ---------------------------------------------------------------------------
  831. //  This method is called after the end of the root element, to handle
  832. //  any miscellaneous stuff hanging around.
  833. void XMLScanner::scanMiscellaneous()
  834. {
  835.     // Get a buffer for this work
  836.     XMLBufBid bbCData(&fBufMgr);
  837.     while (true)
  838.     {
  839.         try
  840.         {
  841.             const XMLCh nextCh = fReaderMgr.peekNextChar();
  842.             // Watch for end of file and break out
  843.             if (!nextCh)
  844.                 break;
  845.             if (nextCh == chOpenAngle)
  846.             {
  847.                 if (checkXMLDecl(true))
  848.                 {
  849.                     // Can't have an XML decl here
  850.                     emitError(XMLErrs::NotValidAfterContent);
  851.                     fReaderMgr.skipPastChar(chCloseAngle);
  852.                 }
  853.                 else if (fReaderMgr.skippedString(XMLUni::fgPIString))
  854.                 {
  855.                     scanPI();
  856.                 }
  857.                  else if (fReaderMgr.skippedString(XMLUni::fgCommentString))
  858.                 {
  859.                     scanComment();
  860.                 }
  861.                 else
  862.                 {
  863.                     // This can't be possible, so just give up
  864.                     emitError(XMLErrs::ExpectedCommentOrPI);
  865.                     fReaderMgr.skipPastChar(chCloseAngle);
  866.                 }
  867.             }
  868.             else if (fReaderMgr.getCurrentReader()->isWhitespace(nextCh))
  869.             {
  870.                 //  If we have a doc handler, then gather up the spaces and
  871.                 //  call back. Otherwise, just skip over whitespace.
  872.                 if (fDocHandler)
  873.                 {
  874.                     fReaderMgr.getSpaces(bbCData.getBuffer());
  875.                     fDocHandler->ignorableWhitespace
  876.                     (
  877.                         bbCData.getRawBuffer()
  878.                         , bbCData.getLen()
  879.                         , false
  880.                     );
  881.                 }
  882.                 else
  883.                 {
  884.                     fReaderMgr.skipPastSpaces();
  885.                 }
  886.             }
  887.             else
  888.             {
  889.                 emitError(XMLErrs::ExpectedCommentOrPI);
  890.                 fReaderMgr.skipPastChar(chCloseAngle);
  891.             }
  892.         }
  893.         catch(const EndOfEntityException&)
  894.         {
  895.             //  Some entity leaked out of the content part of the document. Issue
  896.             //  a warning and keep going.
  897.             emitError(XMLErrs::EntityPropogated);
  898.         }
  899.     }
  900. }
  901. //  Scans a PI and calls the appropriate callbacks. At entry we have just
  902. //  scanned the <? part, and need to now start on the PI target name.
  903. void XMLScanner::scanPI()
  904. {
  905.     const XMLCh* namePtr = 0;
  906.     const XMLCh* targetPtr = 0;
  907.     //  If there are any spaces here, then warn about it. If we aren't in
  908.     //  'first error' mode, then we'll come back and can easily pick up
  909.     //  again by just skipping them.
  910.     if (fReaderMgr.lookingAtSpace())
  911.     {
  912.         emitError(XMLErrs::PINameExpected);
  913.         fReaderMgr.skipPastSpaces();
  914.     }
  915.     // Get a buffer for the PI name and scan it in
  916.     XMLBufBid bbName(&fBufMgr);
  917.     if (!fReaderMgr.getName(bbName.getBuffer()))
  918.     {
  919.         emitError(XMLErrs::PINameExpected);
  920.         fReaderMgr.skipPastChar(chCloseAngle);
  921.         return;
  922.     }
  923.     // Point the name pointer at the raw data
  924.     namePtr = bbName.getRawBuffer();
  925.     // See if it is some form of 'xml' and emit a warning
  926.     if (!XMLString::compareIString(namePtr, XMLUni::fgXMLString))
  927.         emitError(XMLErrs::NoPIStartsWithXML);
  928.     // If namespaces are enabled, then no colons allowed
  929.     if (fDoNamespaces)
  930.     {
  931.         if (XMLString::indexOf(namePtr, chColon) != -1)
  932.             emitError(XMLErrs::ColonNotLegalWithNS);
  933.     }
  934.     //  If we don't hit a space next, then the PI has no target. If we do
  935.     //  then get out the target. Get a buffer for it as well
  936.     XMLBufBid bbTarget(&fBufMgr);
  937.     if (fReaderMgr.skippedSpace())
  938.     {
  939.         // Skip any leading spaces
  940.         fReaderMgr.skipPastSpaces();
  941.         bool gotLeadingSurrogate = false;
  942.         // It does have a target, so lets move on to deal with that.
  943.         while (1)
  944.         {
  945.             const XMLCh nextCh = fReaderMgr.getNextChar();
  946.             // Watch for an end of file, which is always bad here
  947.             if (!nextCh)
  948.             {
  949.                 emitError(XMLErrs::UnterminatedPI);
  950.                 ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  951.             }
  952.             // Watch for potential terminating character
  953.             if (nextCh == chQuestion)
  954.             {
  955.                 // It must be followed by '>' to be a termination of the target
  956.                 if (fReaderMgr.skippedChar(chCloseAngle))
  957.                     break;
  958.             }
  959.             // Check for correct surrogate pairs
  960.             if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
  961.             {
  962.                 if (gotLeadingSurrogate)
  963.                     emitError(XMLErrs::Expected2ndSurrogateChar);
  964.                 else
  965.                     gotLeadingSurrogate = true;
  966.             }
  967.              else
  968.             {
  969.                 if (gotLeadingSurrogate)
  970.                 {
  971.                     if ((nextCh < 0xDC00) || (nextCh > 0xDFFF))
  972.                         emitError(XMLErrs::Expected2ndSurrogateChar);
  973.                 }
  974.                 // Its got to at least be a valid XML character
  975.                 else if (!fReaderMgr.getCurrentReader()->isXMLChar(nextCh)) {
  976.                     XMLCh tmpBuf[9];
  977.                     XMLString::binToText
  978.                     (
  979.                         nextCh
  980.                         , tmpBuf
  981.                         , 8
  982.                         , 16
  983.                     );
  984.                     emitError(XMLErrs::InvalidCharacter, tmpBuf);
  985.                 }
  986.                 gotLeadingSurrogate = false;
  987.             }
  988.             bbTarget.append(nextCh);
  989.         }
  990.     }
  991.     else
  992.     {
  993.         // No target, but make sure its terminated ok
  994.         if (!fReaderMgr.skippedChar(chQuestion))
  995.         {
  996.             emitError(XMLErrs::UnterminatedPI);
  997.             fReaderMgr.skipPastChar(chCloseAngle);
  998.             return;
  999.         }
  1000.         if (!fReaderMgr.skippedChar(chCloseAngle))
  1001.         {
  1002.             emitError(XMLErrs::UnterminatedPI);
  1003.             fReaderMgr.skipPastChar(chCloseAngle);
  1004.             return;
  1005.         }
  1006.     }
  1007.     // Point the target pointer at the raw data
  1008.     targetPtr = bbTarget.getRawBuffer();
  1009.     // If we have a handler, then call it
  1010.     if (fDocHandler)
  1011.     {
  1012.         fDocHandler->docPI
  1013.         (
  1014.             namePtr
  1015.             , targetPtr
  1016.        );
  1017.     }
  1018. }
  1019. //  Scans all the input from the start of the file to the root element.
  1020. //  There does not have to be anything in the prolog necessarily, but usually
  1021. //  there is at least an XMLDecl.
  1022. //
  1023. //  On exit from here we are either at the end of the file or about to read
  1024. //  the opening < of the root element.
  1025. void XMLScanner::scanProlog()
  1026. {
  1027.     // Get a buffer for whitespace processing
  1028.     XMLBufBid bbCData(&fBufMgr);
  1029.     //  Loop through the prolog. If there is no content, this could go all
  1030.     //  the way to the end of the file.
  1031.     try
  1032.     {
  1033.         while (true)
  1034.         {
  1035.             const XMLCh nextCh = fReaderMgr.peekNextChar();
  1036.             if (nextCh == chOpenAngle)
  1037.             {
  1038.                 //  Ok, it could be the xml decl, a comment, the doc type line,
  1039.                 //  or the start of the root element.
  1040.                 if (checkXMLDecl(true))
  1041.                 {
  1042.                     // There shall be at lease --ONE-- space in between
  1043.                     // the tag '<?xml' and the VersionInfo.
  1044.                     //
  1045.                     //  If we are not at line 1, col 6, then the decl was not
  1046.                     //  the first text, so its invalid.
  1047.                     const XMLReader* curReader = fReaderMgr.getCurrentReader();
  1048.                     if ((curReader->getLineNumber() != 1)
  1049.                     ||  (curReader->getColumnNumber() != 7))
  1050.                     {
  1051.                         emitError(XMLErrs::XMLDeclMustBeFirst);
  1052.                     }
  1053.                     scanXMLDecl(Decl_XML);
  1054.                 }
  1055.                 else if (fReaderMgr.skippedString(XMLUni::fgPIString))
  1056.                 {
  1057.                     scanPI();
  1058.                 }
  1059.                  else if (fReaderMgr.skippedString(XMLUni::fgCommentString))
  1060.                 {
  1061.                     scanComment();
  1062.                 }
  1063.                  else if (fReaderMgr.skippedString(XMLUni::fgDocTypeString))
  1064.                 {
  1065.                     scanDocTypeDecl();
  1066.                     // if reusing grammar, this has been validated already in first scan
  1067.                     // skip for performance
  1068.                     if (fValidate && !fGrammar->getValidated()) {
  1069.                         //  validate the DTD scan so far
  1070.                         fValidator->preContentValidation(fUseCachedGrammar, true);
  1071.                     }
  1072.                 }
  1073.                 else
  1074.                 {
  1075.                     // Assume its the start of the root element
  1076.                     return;
  1077.                 }
  1078.             }
  1079.             else if (fReaderMgr.getCurrentReader()->isWhitespace(nextCh))
  1080.             {
  1081.                 //  If we have a document handler then gather up the
  1082.                 //  whitespace and call back. Otherwise just skip over spaces.
  1083.                 if (fDocHandler)
  1084.                 {
  1085.                     fReaderMgr.getSpaces(bbCData.getBuffer());
  1086.                     fDocHandler->ignorableWhitespace
  1087.                     (
  1088.                         bbCData.getRawBuffer()
  1089.                         , bbCData.getLen()
  1090.                         , false
  1091.                     );
  1092.                 }
  1093.                  else
  1094.                 {
  1095.                     fReaderMgr.skipPastSpaces();
  1096.                 }
  1097.             }
  1098.              else
  1099.             {
  1100.                 emitError(XMLErrs::InvalidDocumentStructure);
  1101.                 // Watch for end of file and break out
  1102.                 if (!nextCh)
  1103.                     break;
  1104.                 else
  1105.                     fReaderMgr.skipPastChar(chCloseAngle);
  1106.             }
  1107.         }
  1108.     }
  1109.     catch(const EndOfEntityException&)
  1110.     {
  1111.         //  We should never get an end of entity here. They should only
  1112.         //  occur within the doc type scanning method, and not leak out to
  1113.         //  here.
  1114.         emitError
  1115.         (
  1116.             XMLErrs::UnexpectedEOE
  1117.             , "in prolog"
  1118.         );
  1119.     }
  1120. }
  1121. //  Scans the <?xml .... ?> line. This stuff is all sequential so we don't
  1122. //  do any state machine loop here. We just bull straight through it. It ends
  1123. //  past the closing bracket. If there is a document handler, then its called
  1124. //  on the XMLDecl callback.
  1125. //
  1126. //  On entry, the <?xml has been scanned, and we pick it up from there.
  1127. //
  1128. //  NOTE: In order to provide good recovery from bad XML here, we try to be
  1129. //  very flexible. No matter what order the stuff is in, we'll keep going
  1130. //  though we'll issue errors.
  1131. //
  1132. //  The parameter tells us which type of decl we should expect, Text or XML.
  1133. //    [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
  1134. //    [77] TextDecl::= '<?xml' VersionInfo? EncodingDecl S? '?>'
  1135. void XMLScanner::scanXMLDecl(const DeclTypes type)
  1136. {
  1137.     // Get us some buffers to use
  1138.     XMLBufBid bbVersion(&fBufMgr);
  1139.     XMLBufBid bbEncoding(&fBufMgr);
  1140.     XMLBufBid bbStand(&fBufMgr);
  1141.     XMLBufBid bbDummy(&fBufMgr);
  1142.     XMLBufBid bbName(&fBufMgr);
  1143.     //  We use this little enum and array to keep up with what we found
  1144.     //  and what order we found them in. This lets us get them free form
  1145.     //  without too much overhead, but still know that they were in the
  1146.     //  wrong order.
  1147.     enum Strings
  1148.     {
  1149.         VersionString
  1150.         , EncodingString
  1151.         , StandaloneString
  1152.         , UnknownString
  1153.         , StringCount
  1154.     };
  1155.     int flags[StringCount] = { -1, -1, -1, -1 };
  1156.     //  Also set up a list of buffers in the right order so that we know
  1157.     //  where to put stuff.
  1158.     XMLBuffer* buffers[StringCount] ;
  1159.     buffers[0] = &bbVersion.getBuffer();
  1160.     buffers[1] = &bbEncoding.getBuffer();
  1161.     buffers[2] = &bbStand.getBuffer();
  1162.     buffers[3] = &bbDummy.getBuffer();
  1163.     int curCount = 0;
  1164.     Strings curString;
  1165.     XMLBuffer& nameBuf = bbName.getBuffer();
  1166.     while (true)
  1167.     {
  1168.         // Skip any spaces
  1169.         const unsigned int spaceCount = fReaderMgr.skipPastSpaces();
  1170.         // If we are looking at a question mark, then break out
  1171.         if (fReaderMgr.lookingAtChar(chQuestion))
  1172.             break;
  1173.         // If this is not the first string, then we require the spaces
  1174.         if (!spaceCount && curCount)
  1175.             emitError(XMLErrs::ExpectedWhitespace);
  1176.         //  Get characters up to the next whitespace or equal's sign.
  1177.         if (!scanUpToWSOr(nameBuf, chEqual))
  1178.             emitError(XMLErrs::ExpectedDeclString);
  1179.         // See if it matches any of our expected strings
  1180.         if (XMLString::equals(nameBuf.getRawBuffer(), XMLUni::fgVersionString))
  1181.             curString = VersionString;
  1182.         else if (XMLString::equals(nameBuf.getRawBuffer(), XMLUni::fgEncodingString))
  1183.             curString = EncodingString;
  1184.         else if (XMLString::equals(nameBuf.getRawBuffer(), XMLUni::fgStandaloneString))
  1185.             curString = StandaloneString;
  1186.         else
  1187.             curString = UnknownString;
  1188.         //  If its an unknown string, then give that error. Else check to
  1189.         //  see if this one has been done already and give that error.
  1190.         if (curString == UnknownString)
  1191.             emitError(XMLErrs::ExpectedDeclString, nameBuf.getRawBuffer());
  1192.         else if (flags[curString] != -1)
  1193.             emitError(XMLErrs::DeclStringRep, nameBuf.getRawBuffer());
  1194.         else if (flags[curString] == -1)
  1195.             flags[curString] = ++curCount;
  1196.         //  Scan for an equal's sign. If we don't find it, issue an error
  1197.         //  but keep trying to go on.
  1198.         if (!scanEq())
  1199.             emitError(XMLErrs::ExpectedEqSign);
  1200.         //  Get a quote string into the buffer for the string that we are
  1201.         //  currently working on.
  1202.         if (!getQuotedString(*buffers[curString]))
  1203.         {
  1204.             emitError(XMLErrs::ExpectedQuotedString);
  1205.             fReaderMgr.skipPastChar(chCloseAngle);
  1206.             return;
  1207.         }
  1208.         // And validate the value according which one it was
  1209.         const XMLCh* rawValue = buffers[curString]->getRawBuffer();
  1210.         if (curString == VersionString)
  1211.         {
  1212.             if (XMLString::equals(rawValue, XMLUni::fgVersion1_1)) {
  1213.                 if (type == Decl_XML) {
  1214.                  fXMLVersion = XMLReader::XMLV1_1;
  1215.                     fReaderMgr.setXMLVersion(XMLReader::XMLV1_1);
  1216.                 }
  1217.                 else {
  1218.                  if (fXMLVersion != XMLReader::XMLV1_1)
  1219.                      emitError(XMLErrs::UnsupportedXMLVersion, rawValue);                
  1220.              }
  1221.             }
  1222.             else if (XMLString::equals(rawValue, XMLUni::fgVersion1_0)) {
  1223.                 if (type == Decl_XML) {
  1224.                  fXMLVersion = XMLReader::XMLV1_0;
  1225.                     fReaderMgr.setXMLVersion(XMLReader::XMLV1_0);                    
  1226.                 }
  1227.             }
  1228.             else
  1229.                 emitError(XMLErrs::UnsupportedXMLVersion, rawValue);
  1230.         }
  1231.          else if (curString == EncodingString)
  1232.         {
  1233.             if (!XMLString::isValidEncName(rawValue))
  1234.                 emitError(XMLErrs::BadXMLEncoding, rawValue);
  1235.         }
  1236.          else if (curString == StandaloneString)
  1237.         {
  1238.             if (XMLString::equals(rawValue, XMLUni::fgYesString))
  1239.                 fStandalone = true;
  1240.             else if (XMLString::equals(rawValue, XMLUni::fgNoString))
  1241.                 fStandalone = false;
  1242.             else
  1243.             {
  1244.                 emitError(XMLErrs::BadStandalone);
  1245.                 if (!XMLString::compareIString(rawValue, XMLUni::fgYesString))
  1246.                     fStandalone = true;
  1247.                 else if (!XMLString::compareIString(rawValue, XMLUni::fgNoString))
  1248.                     fStandalone = false;
  1249.             }
  1250.         }
  1251.     }
  1252.     //  Make sure that the strings present are in order. We don't care about
  1253.     //  which ones are present at this point, just that any there are in the
  1254.     //  right order.
  1255.     int curTop = 0;
  1256.     for (int index = VersionString; index < StandaloneString; index++)
  1257.     {
  1258.         if (flags[index] != -1)
  1259.         {
  1260.             if (flags[index] !=  curTop + 1)
  1261.             {
  1262.                 emitError(XMLErrs::DeclStringsInWrongOrder);
  1263.                 break;
  1264.             }
  1265.             curTop = flags[index];
  1266.         }
  1267.     }
  1268.     //  If its an XML decl, the version must be present.
  1269.     //  If its a Text decl, then encoding must be present AND standalone must not be present.
  1270.     if ((type == Decl_XML) && (flags[VersionString] == -1))
  1271.         emitError(XMLErrs::XMLVersionRequired);
  1272.     else if (type == Decl_Text) {
  1273.         if (flags[StandaloneString] != -1)
  1274.             emitError(XMLErrs::StandaloneNotLegal);
  1275.         if (flags[EncodingString] == -1)
  1276.             emitError(XMLErrs::EncodingRequired);
  1277.     }
  1278.     if (!fReaderMgr.skippedChar(chQuestion))
  1279.     {
  1280.         emitError(XMLErrs::UnterminatedXMLDecl);
  1281.         fReaderMgr.skipPastChar(chCloseAngle);
  1282.     }
  1283.      else if (!fReaderMgr.skippedChar(chCloseAngle))
  1284.     {
  1285.         emitError(XMLErrs::UnterminatedXMLDecl);
  1286.         fReaderMgr.skipPastChar(chCloseAngle);
  1287.     }
  1288.     //  Do this before we possibly update the reader with the
  1289.     //  actual encoding string. Otherwise, we will pass the wrong thing
  1290.     //  for the last parameter!
  1291.     const XMLCh* actualEnc = fReaderMgr.getCurrentEncodingStr();
  1292.     //  Ok, we've now seen the real encoding string, if there was one, so
  1293.     //  lets call back on the current reader and tell it what the real
  1294.     //  encoding string was. If it fails, that's because it represents some
  1295.     //  sort of contradiction with the autosensed format, and it keeps the
  1296.     //  original encoding.
  1297.     //
  1298.     //  NOTE: This can fail for a number of reasons, such as a bogus encoding
  1299.     //  name or because its in flagrant contradiction of the auto-sensed
  1300.     //  format.
  1301.     if (flags[EncodingString] != -1)
  1302.     {
  1303.         if (!fReaderMgr.getCurrentReader()->setEncoding(bbEncoding.getRawBuffer()))
  1304.             emitError(XMLErrs::ContradictoryEncoding, bbEncoding.getRawBuffer());
  1305.         else
  1306.             actualEnc = bbEncoding.getRawBuffer();
  1307.     }
  1308.     //  If we have a document handler then call the XML Decl callback.
  1309.     if (type == Decl_XML)
  1310.     {
  1311.         if (fDocHandler)
  1312.             fDocHandler->XMLDecl
  1313.             (
  1314.                 bbVersion.getRawBuffer()
  1315.                 , bbEncoding.getRawBuffer()
  1316.                 , bbStand.getRawBuffer()
  1317.                 , actualEnc
  1318.             );
  1319.     }
  1320.     else if (type == Decl_Text)
  1321.     {
  1322.         if (fDocTypeHandler)
  1323.             fDocTypeHandler->TextDecl
  1324.             (
  1325.                 bbVersion.getRawBuffer()
  1326.                 , bbEncoding.getRawBuffer()
  1327.             );
  1328.     }
  1329. }
  1330. const XMLCh* XMLScanner::getURIText(const   unsigned int    uriId) const
  1331. {
  1332.     if (fURIStringPool->exists(uriId)) {
  1333.         // Look up the URI in the string pool and return its id
  1334.         const XMLCh* value = fURIStringPool->getValueForId(uriId);
  1335.         if (!value)
  1336.             return XMLUni::fgZeroLenString;
  1337.         return value;
  1338.     }
  1339.     else
  1340.         return XMLUni::fgZeroLenString;
  1341. }
  1342. bool XMLScanner::getURIText(  const   unsigned int    uriId
  1343.                       ,       XMLBuffer&      uriBufToFill) const
  1344. {
  1345.     if (fURIStringPool->exists(uriId)) {
  1346.         // Look up the URI in the string pool and return its id
  1347.         const XMLCh* value = fURIStringPool->getValueForId(uriId);
  1348.         if (!value)
  1349.             return false;
  1350.         uriBufToFill.set(value);
  1351.         return true;
  1352.     }
  1353.     else
  1354.         return false;
  1355. }
  1356. bool XMLScanner::checkXMLDecl(bool startWithAngle) {
  1357.     // [23] XMLDecl     ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
  1358.     // [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"')
  1359.     //
  1360.     // [3]  S           ::= (#x20 | #x9 | #xD | #xA)+
  1361.     if (startWithAngle) {
  1362.         if (fReaderMgr.peekString(XMLUni::fgXMLDeclString)) {
  1363.             if (fReaderMgr.skippedString(XMLUni::fgXMLDeclStringSpace)
  1364.                || fReaderMgr.skippedString(XMLUni::fgXMLDeclStringHTab)
  1365.                || fReaderMgr.skippedString(XMLUni::fgXMLDeclStringLF)
  1366.                || fReaderMgr.skippedString(XMLUni::fgXMLDeclStringCR))
  1367.             {
  1368.                 return true;
  1369.             }
  1370.             else if (fReaderMgr.skippedString(XMLUni::fgXMLDeclStringSpaceU)
  1371.                || fReaderMgr.skippedString(XMLUni::fgXMLDeclStringHTabU)
  1372.                || fReaderMgr.skippedString(XMLUni::fgXMLDeclStringLFU)
  1373.                || fReaderMgr.skippedString(XMLUni::fgXMLDeclStringCRU))
  1374.             {
  1375.                 //  Just in case, check for upper case. If found, issue
  1376.                 //  an error, but keep going.
  1377.                 emitError(XMLErrs::XMLDeclMustBeLowerCase);
  1378.                 return true;
  1379.             }
  1380.         }
  1381.     }
  1382.     else {
  1383.         if (fReaderMgr.peekString(XMLUni::fgXMLString)) {
  1384.             if (fReaderMgr.skippedString(XMLUni::fgXMLStringSpace)
  1385.                || fReaderMgr.skippedString(XMLUni::fgXMLStringHTab)
  1386.                || fReaderMgr.skippedString(XMLUni::fgXMLStringLF)
  1387.                || fReaderMgr.skippedString(XMLUni::fgXMLStringCR))
  1388.             {
  1389.                 return true;
  1390.             }
  1391.             else if (fReaderMgr.skippedString(XMLUni::fgXMLStringSpaceU)
  1392.                || fReaderMgr.skippedString(XMLUni::fgXMLStringHTabU)
  1393.                || fReaderMgr.skippedString(XMLUni::fgXMLStringLFU)
  1394.                || fReaderMgr.skippedString(XMLUni::fgXMLStringCRU))
  1395.             {
  1396.                 //  Just in case, check for upper case. If found, issue
  1397.                 //  an error, but keep going.
  1398.                 emitError(XMLErrs::XMLDeclMustBeLowerCase);
  1399.                 return true;
  1400.             }
  1401.         }
  1402.     }
  1403.     return false;
  1404. }
  1405. // ---------------------------------------------------------------------------
  1406. //  XMLScanner: Grammar preparsing
  1407. // ---------------------------------------------------------------------------
  1408. Grammar* XMLScanner::loadGrammar(const   XMLCh* const systemId
  1409.                                  , const short        grammarType
  1410.                                  , const bool         toCache)
  1411. {
  1412.     InputSource* srcToUse = 0;
  1413.     if (fEntityHandler){
  1414.         srcToUse = fEntityHandler->resolveEntity(XMLUni::fgZeroLenString, systemId);
  1415.     }
  1416.     //  First we try to parse it as a URL. If that fails, we assume its
  1417.     //  a file and try it that way.
  1418.     if (!srcToUse) {
  1419.         try
  1420.         {
  1421.             //  Create a temporary URL. Since this is the primary document,
  1422.             //  it has to be fully qualified. If not, then assume we are just
  1423.             //  mistaking a file for a URL.
  1424.             XMLURL tmpURL(systemId, fMemoryManager);
  1425.             if (tmpURL.isRelative())
  1426.             {
  1427.                 if (!fStandardUriConformant)
  1428.                     srcToUse = new (fMemoryManager) LocalFileInputSource(systemId, fMemoryManager);
  1429.                 else {
  1430.                     // since this is the top of the try/catch, cannot call ThrowXML
  1431.                     // emit the error directly
  1432.                     MalformedURLException e(__FILE__, __LINE__, XMLExcepts::URL_NoProtocolPresent);
  1433.                     fInException = true;
  1434.                     emitError
  1435.                     (
  1436.                         XMLErrs::XMLException_Fatal
  1437.                         , e.getType()
  1438.                         , e.getMessage()
  1439.                     );
  1440.                     return 0;
  1441.                 }
  1442.             }
  1443.             else
  1444.             {
  1445.                 if (fStandardUriConformant && tmpURL.hasInvalidChar()) {
  1446.                     MalformedURLException e(__FILE__, __LINE__, XMLExcepts::URL_MalformedURL);
  1447.                     fInException = true;
  1448.                     emitError
  1449.                     (
  1450.                         XMLErrs::XMLException_Fatal
  1451.                         , e.getType()
  1452.                         , e.getMessage()
  1453.                     );
  1454.                     return 0;
  1455.                 }
  1456.                 srcToUse = new (fMemoryManager) URLInputSource(tmpURL, fMemoryManager);
  1457.             }
  1458.         }
  1459.         catch(const MalformedURLException& e)
  1460.         {
  1461.             if (!fStandardUriConformant)
  1462.                 srcToUse = new (fMemoryManager) LocalFileInputSource(systemId, fMemoryManager);
  1463.             else {
  1464.                 // since this is the top of the try/catch, cannot call ThrowXML
  1465.                 // emit the error directly
  1466.                 // lazy bypass ... since all MalformedURLException are fatal, no need to check the type
  1467.                 fInException = true;
  1468.                 emitError
  1469.                 (
  1470.                     XMLErrs::XMLException_Fatal
  1471.                     , e.getType()
  1472.                     , e.getMessage()
  1473.                 );
  1474.                 return 0;
  1475.             }
  1476.         }
  1477.         catch(const XMLException& excToCatch)
  1478.         {
  1479.             //  For any other XMLException,
  1480.             //  emit the error and catch any user exception thrown from here.
  1481.             fInException = true;
  1482.             if (excToCatch.getErrorType() == XMLErrorReporter::ErrType_Warning)
  1483.                 emitError
  1484.                 (
  1485.                     XMLErrs::XMLException_Warning
  1486.                     , excToCatch.getType()
  1487.                     , excToCatch.getMessage()
  1488.                 );
  1489.             else if (excToCatch.getErrorType() >= XMLErrorReporter::ErrType_Fatal)
  1490.                 emitError
  1491.                 (
  1492.                     XMLErrs::XMLException_Fatal
  1493.                     , excToCatch.getType()
  1494.                     , excToCatch.getMessage()
  1495.                 );
  1496.             else
  1497.                 emitError
  1498.                 (
  1499.                     XMLErrs::XMLException_Error
  1500.                     , excToCatch.getType()
  1501.                     , excToCatch.getMessage()
  1502.                 );
  1503.                 return 0;
  1504.         }
  1505.         catch(...)
  1506.         {
  1507.             // Just rethrow this, since its not our problem
  1508.             throw;
  1509.         }
  1510.     }
  1511.     Janitor<InputSource> janSrc(srcToUse);
  1512.     return loadGrammar(*srcToUse, grammarType, toCache);
  1513. }
  1514. Grammar* XMLScanner::loadGrammar(const   char* const systemId
  1515.                                  , const short       grammarType
  1516.                                  , const bool        toCache)
  1517. {
  1518.     // We just delegate this to the XMLCh version after transcoding
  1519.     XMLCh* tmpBuf = XMLString::transcode(systemId, fMemoryManager);
  1520.     ArrayJanitor<XMLCh> janBuf(tmpBuf, fMemoryManager);
  1521.     return loadGrammar(tmpBuf, grammarType, toCache);
  1522. }
  1523. // ---------------------------------------------------------------------------
  1524. //  XMLScanner: Setter methods
  1525. // ---------------------------------------------------------------------------
  1526. void XMLScanner::setURIStringPool(XMLStringPool* const stringPool)
  1527. {
  1528.     fURIStringPool = stringPool;
  1529.     fEmptyNamespaceId   = fURIStringPool->addOrFind(XMLUni::fgZeroLenString);
  1530.     fUnknownNamespaceId = fURIStringPool->addOrFind(XMLUni::fgUnknownURIName);
  1531.     fXMLNamespaceId     = fURIStringPool->addOrFind(XMLUni::fgXMLURIName);
  1532.     fXMLNSNamespaceId   = fURIStringPool->addOrFind(XMLUni::fgXMLNSURIName);
  1533. }
  1534. // ---------------------------------------------------------------------------
  1535. //  XMLScanner: Private helper methods
  1536. // ---------------------------------------------------------------------------
  1537. //  This method is called after the content scan to insure that all the
  1538. //  ID/IDREF attributes match up (i.e. that all IDREFs refer to IDs.) This is
  1539. //  an XML 1.0 rule, so we can do here in the core.
  1540. void XMLScanner::checkIDRefs()
  1541. {
  1542.     //  Iterate the id ref list. If we find any entries here which are used
  1543.     //  but not declared, then that's an error.
  1544.     RefHashTableOfEnumerator<XMLRefInfo> refEnum(fIDRefList);
  1545.     while (refEnum.hasMoreElements())
  1546.     {
  1547.         // Get a ref to the current element
  1548.         const XMLRefInfo& curRef = refEnum.nextElement();
  1549.         // If its used but not declared, then its an error
  1550.         if (!curRef.getDeclared() && curRef.getUsed() && fValidate)
  1551.             fValidator->emitError(XMLValid::IDNotDeclared, curRef.getRefName());
  1552.     }
  1553. }
  1554. //  This just does a simple check that the passed progressive scan token is
  1555. //  legal for this scanner.
  1556. bool XMLScanner::isLegalToken(const XMLPScanToken& toCheck)
  1557. {
  1558.     return ((fScannerId == toCheck.fScannerId)
  1559.     &&      (fSequenceId == toCheck.fSequenceId));
  1560. }
  1561. //  This method will handle figuring out what the next top level token is
  1562. //  in the input stream. It will return an enumerated value that indicates
  1563. //  what it believes the next XML level token must be. It will eat as many
  1564. //  chars are required to figure out what is next.
  1565. XMLScanner::XMLTokens XMLScanner::senseNextToken(unsigned int& orgReader)
  1566. {
  1567.     //  Get the next character and use it to guesstimate what the next token
  1568.     //  is going to be. We turn on end of entity exceptions when we do this
  1569.     //  in order to catch the scenario where the current entity ended at
  1570.     //  the > of some markup.
  1571.     XMLCh nextCh;
  1572.     {
  1573.         ThrowEOEJanitor janMgr(&fReaderMgr, true);
  1574.         nextCh = fReaderMgr.peekNextChar();
  1575.     }
  1576.     //  Check for special chars. Start with the most
  1577.     //  obvious end of file, which should be legal here at top level.
  1578.     if (!nextCh)
  1579.         return Token_EOF;
  1580.     //  If it's not a '<' we must be in content.
  1581.     //
  1582.     //  This includes entity references '&' of some sort. These must
  1583.     //  be character data because that's the only place a reference can
  1584.     //  occur in content.
  1585.     if (nextCh != chOpenAngle)
  1586.         return Token_CharData;
  1587.     //  Ok it had to have been a '<' character. So get it out of the reader
  1588.     //  and store the reader number where we saw it, passing it back to the
  1589.     //  caller.
  1590.     fReaderMgr.getNextChar();
  1591.     orgReader = fReaderMgr.getCurrentReaderNum();
  1592.     //  Ok, so lets go through the things that it could be at this point which
  1593.     //  are all some form of markup.
  1594.     nextCh = fReaderMgr.peekNextChar();
  1595.     if (nextCh == chForwardSlash)
  1596.     {
  1597.         fReaderMgr.getNextChar();
  1598.         return Token_EndTag;
  1599.     }
  1600.     else if (nextCh == chBang)
  1601.     {
  1602.         static const XMLCh gCDATAStr[] =
  1603.         {
  1604.                 chBang, chOpenSquare, chLatin_C, chLatin_D, chLatin_A
  1605.             ,   chLatin_T, chLatin_A, chNull
  1606.         };
  1607.         static const XMLCh gCommentString[] =
  1608.         {
  1609.             chBang, chDash, chDash, chNull
  1610.         };
  1611.         if (fReaderMgr.skippedString(gCDATAStr))
  1612.             return Token_CData;
  1613.         if (fReaderMgr.skippedString(gCommentString))
  1614.             return Token_Comment;
  1615.         emitError(XMLErrs::ExpectedCommentOrCDATA);
  1616.         return Token_Unknown;
  1617.     }
  1618.     else if (nextCh == chQuestion)
  1619.     {
  1620.         // It must be a PI
  1621.         fReaderMgr.getNextChar();
  1622.         return Token_PI;
  1623.     }
  1624.     //  Assume its an element name, so return with a start tag token. If it
  1625.     //  turns out not to be, then it will fail when it cannot get a valid tag.
  1626.     return Token_StartTag;
  1627. }
  1628. // ---------------------------------------------------------------------------
  1629. //  XMLScanner: Private parsing methods
  1630. // ---------------------------------------------------------------------------
  1631. //  This guy just scans out a single or double quoted string of characters.
  1632. //  It does not pass any judgement on the contents and assumes that it is
  1633. //  illegal to have another quote of the same kind inside the string's
  1634. //  contents.
  1635. //
  1636. //  NOTE: This is for simple stuff like the strings in the XMLDecl which
  1637. //  cannot have any entities inside them. So this guy does not handle any
  1638. //  end of entity stuff.
  1639. bool XMLScanner::getQuotedString(XMLBuffer& toFill)
  1640. {
  1641.     // Reset the target buffer
  1642.     toFill.reset();
  1643.     // Get the next char which must be a single or double quote
  1644.     XMLCh quoteCh;
  1645.     if (!fReaderMgr.skipIfQuote(quoteCh))
  1646.         return false;
  1647.     while (true)
  1648.     {
  1649.         // Get another char
  1650.         const XMLCh nextCh = fReaderMgr.getNextChar();
  1651.         // See if it matches the starting quote char
  1652.         if (nextCh == quoteCh)
  1653.             break;
  1654.         //  We should never get either an end of file null char here. If we
  1655.         //  do, just fail. It will be handled more gracefully in the higher
  1656.         //  level code that called us.
  1657.         if (!nextCh)
  1658.             return false;
  1659.         // Else add it to the buffer
  1660.         toFill.append(nextCh);
  1661.     }
  1662.     return true;
  1663. }
  1664. //  This method scans a character reference and returns the character that
  1665. //  was refered to. It assumes that we've already scanned the &# characters
  1666. //  that prefix the numeric code.
  1667. bool XMLScanner::scanCharRef(XMLCh& toFill, XMLCh& second)
  1668. {
  1669.     bool gotOne = false;
  1670.     unsigned int value = 0;
  1671.     //  Set the radix. Its supposed to be a lower case x if hex. But, in
  1672.     //  order to recover well, we check for an upper and put out an error
  1673.     //  for that.
  1674.     unsigned int radix = 10;
  1675.     if (fReaderMgr.skippedChar(chLatin_x))
  1676.     {
  1677.         radix = 16;
  1678.     }
  1679.     else if (fReaderMgr.skippedChar(chLatin_X))
  1680.     {
  1681.         emitError(XMLErrs::HexRadixMustBeLowerCase);
  1682.         radix = 16;
  1683.     }
  1684.     while (true)
  1685.     {
  1686.         const XMLCh nextCh = fReaderMgr.peekNextChar();
  1687.         // Watch for EOF
  1688.         if (!nextCh)
  1689.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  1690.         // Break out on the terminating semicolon
  1691.         if (nextCh == chSemiColon)
  1692.         {
  1693.             fReaderMgr.getNextChar();
  1694.             break;
  1695.         }
  1696.         //  Convert this char to a binary value, or bail out if its not
  1697.         //  one.
  1698.         unsigned int nextVal;
  1699.         if ((nextCh >= chDigit_0) && (nextCh <= chDigit_9))
  1700.             nextVal = (unsigned int)(nextCh - chDigit_0);
  1701.         else if ((nextCh >= chLatin_A) && (nextCh <= chLatin_F))
  1702.             nextVal= (unsigned int)(10 + (nextCh - chLatin_A));
  1703.         else if ((nextCh >= chLatin_a) && (nextCh <= chLatin_f))
  1704.             nextVal = (unsigned int)(10 + (nextCh - chLatin_a));
  1705.         else
  1706.         {
  1707.             // Return a zero
  1708.             toFill = 0;
  1709.             //  If we got at least a sigit, then do an unterminated ref error.
  1710.             //  Else, do an expected a numerical ref thing.
  1711.             if (gotOne)
  1712.                 emitError(XMLErrs::UnterminatedCharRef);
  1713.             else
  1714.                 emitError(XMLErrs::ExpectedNumericalCharRef);
  1715.             // Return failure
  1716.             return false;
  1717.         }
  1718.         //  Make sure its valid for the radix. If not, then just eat the
  1719.         //  digit and go on after issueing an error. Else, update the
  1720.         //  running value with this new digit.
  1721.         if (nextVal >= radix)
  1722.         {
  1723.             XMLCh tmpStr[2];
  1724.             tmpStr[0] = nextCh;
  1725.             tmpStr[1] = chNull;
  1726.             emitError(XMLErrs::BadDigitForRadix, tmpStr);
  1727.         }
  1728.         else
  1729.         {
  1730.             value = (value * radix) + nextVal;
  1731.         }
  1732.         // Indicate that we got at least one good digit
  1733.         gotOne = true;
  1734.         // And eat the last char
  1735.         fReaderMgr.getNextChar();
  1736.     }
  1737.     // Return the char (or chars)
  1738.     // And check if the character expanded is valid or not
  1739.     if (value >= 0x10000 && value <= 0x10FFFF)
  1740.     {
  1741.         value -= 0x10000;
  1742.         toFill = XMLCh((value >> 10) + 0xD800);
  1743.         second = XMLCh((value & 0x3FF) + 0xDC00);
  1744.     }
  1745.     else if (value <= 0xFFFD)
  1746.     {
  1747.         toFill = XMLCh(value);
  1748.         second = 0;
  1749.         if (!fReaderMgr.getCurrentReader()->isXMLChar(toFill) && !fReaderMgr.getCurrentReader()->isControlChar(toFill)) {
  1750.             // Character reference was not in the valid range
  1751.             emitError(XMLErrs::InvalidCharacterRef);
  1752.             return false;
  1753.         }
  1754.     }
  1755.     else {
  1756.         // Character reference was not in the valid range
  1757.         emitError(XMLErrs::InvalidCharacterRef);
  1758.         return false;
  1759.     }
  1760.     return true;
  1761. }
  1762. //  We get here after the '<!--' part of the comment. We scan past the
  1763. //  terminating '-->' It will calls the appropriate handler with the comment
  1764. //  text, if one is provided. A comment can be in either the document or
  1765. //  the DTD, so the fInDocument flag is used to know which handler to send
  1766. //  it to.
  1767. void XMLScanner::scanComment()
  1768. {
  1769.     enum States
  1770.     {
  1771.         InText
  1772.         , OneDash
  1773.         , TwoDashes
  1774.     };
  1775.     // Get a buffer for this
  1776.     XMLBufBid bbComment(&fBufMgr);
  1777.     //  Get the comment text into a temp buffer. Be sure to use temp buffer
  1778.     //  two here, since its to be used for stuff that is potentially longer
  1779.     //  than just a name.
  1780.     States curState = InText;
  1781.     bool gotLeadingSurrogate = false;
  1782.     while (true)
  1783.     {
  1784.         // Get the next character
  1785.         const XMLCh nextCh = fReaderMgr.getNextChar();
  1786.         //  Watch for an end of file
  1787.         if (!nextCh)
  1788.         {
  1789.             emitError(XMLErrs::UnterminatedComment);
  1790.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  1791.         }
  1792.         // Check for correct surrogate pairs
  1793.         if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
  1794.         {
  1795.             if (gotLeadingSurrogate)
  1796.                 emitError(XMLErrs::Expected2ndSurrogateChar);
  1797.             else
  1798.                 gotLeadingSurrogate = true;
  1799.         }
  1800.         else
  1801.         {
  1802.             if (gotLeadingSurrogate)
  1803.             {
  1804.                 if ((nextCh < 0xDC00) || (nextCh > 0xDFFF))
  1805.                     emitError(XMLErrs::Expected2ndSurrogateChar);
  1806.             }
  1807.             // Its got to at least be a valid XML character
  1808.             else if (!fReaderMgr.getCurrentReader()->isXMLChar(nextCh)) {
  1809.                 XMLCh tmpBuf[9];
  1810.                 XMLString::binToText
  1811.                 (
  1812.                     nextCh
  1813.                     , tmpBuf
  1814.                     , 8
  1815.                     , 16
  1816.                 );
  1817.                 emitError(XMLErrs::InvalidCharacter, tmpBuf);
  1818.             }
  1819.             gotLeadingSurrogate = false;
  1820.         }
  1821.         if (curState == InText)
  1822.         {
  1823.             // If its a dash, go to OneDash state. Otherwise take as text
  1824.             if (nextCh == chDash)
  1825.                 curState = OneDash;
  1826.             else
  1827.                 bbComment.append(nextCh);
  1828.         }
  1829.         else if (curState == OneDash)
  1830.         {
  1831.             //  If its another dash, then we change to the two dashes states.
  1832.             //  Otherwise, we have to put in the deficit dash and the new
  1833.             //  character and go back to InText.
  1834.             if (nextCh == chDash)
  1835.             {
  1836.                 curState = TwoDashes;
  1837.             }
  1838.             else
  1839.             {
  1840.                 bbComment.append(chDash);
  1841.                 bbComment.append(nextCh);
  1842.                 curState = InText;
  1843.             }
  1844.         }
  1845.         else if (curState == TwoDashes)
  1846.         {
  1847.             // The next character must be the closing bracket
  1848.             if (nextCh != chCloseAngle)
  1849.             {
  1850.                 emitError(XMLErrs::IllegalSequenceInComment);
  1851.                 fReaderMgr.skipPastChar(chCloseAngle);
  1852.                 return;
  1853.             }
  1854.             break;
  1855.         }
  1856.     }
  1857.     // If we have an available handler, call back with the comment.
  1858.     if (fDocHandler)
  1859.     {
  1860.         fDocHandler->docComment
  1861.         (
  1862.             bbComment.getRawBuffer()
  1863.         );
  1864.     }
  1865. }
  1866. //  Most equal signs can have white space around them, so this little guy
  1867. //  just makes the calling code cleaner by eating whitespace.
  1868. bool XMLScanner::scanEq()
  1869. {
  1870.     fReaderMgr.skipPastSpaces();
  1871.     if (fReaderMgr.skippedChar(chEqual))
  1872.     {
  1873.         fReaderMgr.skipPastSpaces();
  1874.         return true;
  1875.     }
  1876.     return false;
  1877. }
  1878. unsigned int
  1879. XMLScanner::scanUpToWSOr(XMLBuffer& toFill, const XMLCh chEndChar)
  1880. {
  1881.     fReaderMgr.getUpToCharOrWS(toFill, chEndChar);
  1882.     return toFill.getLen();
  1883. }
  1884. XERCES_CPP_NAMESPACE_END