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

xml/soap/webservice

开发平台:

C/C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  *
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  *
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  *
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written
  29.  *    permission, please contact apache@apache.org.
  30.  *
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their name, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 1999, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Log: DTDScanner.cpp,v $
  58.  * Revision 1.22  2001/12/06 17:51:18  tng
  59.  * Performance Enhancement. The ContentSpecNode constructor always copied the QName
  60.  * that was passed to it.  Added a second constructor that allows the QName to be just assigned, not copied.
  61.  * That was because there are some cases in which a temporary QName was constructed, passed to ContentSpecNode, and then deleted.
  62.  * There were examples of that in TraverseSchema and DTDScanner.
  63.  * By Henry Zongaro.
  64.  *
  65.  * Revision 1.21  2001/11/13 13:27:28  tng
  66.  * Move root element check to XMLScanner.
  67.  *
  68.  * Revision 1.20  2001/09/05 20:49:10  knoaman
  69.  * Fix for complexTypes with mixed content model.
  70.  *
  71.  * Revision 1.19  2001/08/02 16:54:39  tng
  72.  * Reset some Scanner flags in scanReset().
  73.  *
  74.  * Revision 1.18  2001/07/13 16:57:11  tng
  75.  * ScanId fix.
  76.  *
  77.  * Revision 1.17  2001/07/12 20:10:18  tng
  78.  * Partial Markup in Parameter Entity is validity constraint and thus should be just error, not fatal error.
  79.  *
  80.  * Revision 1.16  2001/07/10 21:09:39  tng
  81.  * Give proper error messsage when scanning external id.
  82.  *
  83.  * Revision 1.15  2001/07/10 20:56:17  tng
  84.  * Should check the first char of PI Target Name.
  85.  *
  86.  * Revision 1.14  2001/07/09 13:42:20  tng
  87.  * Partial Markup in Parameter Entity is validity constraint and thus should be just error, not fatal error.
  88.  *
  89.  * Revision 1.13  2001/07/05 14:05:29  tng
  90.  * Encoding String must present for external entity text decl.
  91.  *
  92.  * Revision 1.12  2001/07/05 13:12:19  tng
  93.  * Standalone checking is validity constraint and thus should be just error, not fatal error:
  94.  *
  95.  * Revision 1.11  2001/06/25 14:39:54  knoaman
  96.  * Fix bug #965 - submitted by Matt Lovett
  97.  *
  98.  * Revision 1.10  2001/06/22 12:42:33  tng
  99.  * [Bug 2257] 1.5 thinks a <?xml-stylesheet ...> tag is a <?xml ...> tag
  100.  *
  101.  * Revision 1.9  2001/06/21 14:25:53  knoaman
  102.  * Fix for bug 1946
  103.  *
  104.  * Revision 1.8  2001/06/04 13:25:50  tng
  105.  * the start tag "<?xml" could be followed by (#x20 | #x9 | #xD | #xA)+.  Fixed by Pei Yong Zhang.
  106.  *
  107.  * Revision 1.7  2001/05/28 20:54:06  tng
  108.  * Schema: allocate a fDTDValidator, fSchemaValidator explicitly to avoid wrong cast
  109.  *
  110.  * Revision 1.6  2001/05/11 13:27:09  tng
  111.  * Copyright update.
  112.  *
  113.  * Revision 1.5  2001/05/03 20:34:36  tng
  114.  * Schema: SchemaValidator update
  115.  *
  116.  * Revision 1.4  2001/04/23 18:54:35  tng
  117.  * Reuse grammar should allow users to use any stored element decl as root.  Fixed by Erik Rydgren.
  118.  *
  119.  * Revision 1.3  2001/04/19 18:17:21  tng
  120.  * Schema: SchemaValidator update, and use QName in Content Model
  121.  *
  122.  * Revision 1.2  2001/03/30 16:35:17  tng
  123.  * Schema: Whitespace normalization.
  124.  *
  125.  * Revision 1.1  2001/03/21 21:56:20  tng
  126.  * Schema: Add Schema Grammar, Schema Validator, and split the DTDValidator into DTDValidator, DTDScanner, and DTDGrammar.
  127.  *
  128.  */
  129. // ---------------------------------------------------------------------------
  130. //  Includes
  131. // ---------------------------------------------------------------------------
  132. #include <util/BinMemInputStream.hpp>
  133. #include <util/FlagJanitor.hpp>
  134. #include <util/Janitor.hpp>
  135. #include <util/XMLUniDefs.hpp>
  136. #include <util/UnexpectedEOFException.hpp>
  137. #include <sax/InputSource.hpp>
  138. #include <framework/XMLDocumentHandler.hpp>
  139. #include <framework/XMLEntityHandler.hpp>
  140. #include <internal/EndOfEntityException.hpp>
  141. #include <internal/XMLScanner.hpp>
  142. #include <validators/common/ContentSpecNode.hpp>
  143. #include <validators/common/MixedContentModel.hpp>
  144. #include <validators/DTD/DTDEntityDecl.hpp>
  145. #include <validators/DTD/DocTypeHandler.hpp>
  146. #include <validators/DTD/DTDScanner.hpp>
  147. // ---------------------------------------------------------------------------
  148. //  Local methods
  149. // ---------------------------------------------------------------------------
  150. //
  151. //  This method automates the grunt work of looking at a char and see if its
  152. //  a repetition suffix. If so, it creates a new correct rep node and wraps
  153. //  the pass node in it. Otherwise, it returns the previous node.
  154. //
  155. static ContentSpecNode*
  156. makeRepNode(const XMLCh testCh, ContentSpecNode* const prevNode)
  157. {
  158.     if (testCh == chQuestion)
  159.     {
  160.         return new ContentSpecNode
  161.         (
  162.             ContentSpecNode::ZeroOrOne
  163.             , prevNode
  164.             , 0
  165.         );
  166.     }
  167.      else if (testCh == chPlus)
  168.     {
  169.         return new ContentSpecNode
  170.         (
  171.             ContentSpecNode::OneOrMore
  172.             , prevNode
  173.             , 0
  174.         );
  175.     }
  176.      else if (testCh == chAsterisk)
  177.     {
  178.         return new ContentSpecNode
  179.         (
  180.             ContentSpecNode::ZeroOrMore
  181.             , prevNode
  182.             , 0
  183.         );
  184.     }
  185.     // Just return the incoming node
  186.     return prevNode;
  187. }
  188. // ---------------------------------------------------------------------------
  189. //  DTDValidator: Constructors and Destructor
  190. // ---------------------------------------------------------------------------
  191. DTDScanner::DTDScanner(DTDGrammar* dtdGrammar, NameIdPool<DTDEntityDecl>* entityDeclPool, DocTypeHandler* const    docTypeHandler) :
  192.     fDocTypeHandler(docTypeHandler)
  193.     , fDumAttDef(0)
  194.     , fDumElemDecl(0)
  195.     , fDumEntityDecl(0)
  196.     , fInternalSubset(false)
  197.     , fNextAttrId(1)
  198.     , fDTDGrammar(dtdGrammar)
  199.     , fPEntityDeclPool(0)
  200.     , fEntityDeclPool(entityDeclPool)
  201.     , fDocTypeReaderId(0)
  202. {
  203.     fPEntityDeclPool = new NameIdPool<DTDEntityDecl>(109);
  204. }
  205. DTDScanner::~DTDScanner()
  206. {
  207.     delete fDumAttDef;
  208.     delete fDumElemDecl;
  209.     delete fDumEntityDecl;
  210.     delete fPEntityDeclPool;
  211. }
  212. // ---------------------------------------------------------------------------
  213. //  DTDScanner: Private scanning methods
  214. // ---------------------------------------------------------------------------
  215. bool DTDScanner::checkForPERef(const  bool    spaceRequired
  216.                                 , const bool    inLiteral
  217.                                 , const bool    inMarkup
  218.                                 , const bool    throwAtEndExt)
  219. {
  220.     bool gotSpace = false;
  221.     //
  222.     //  See if we have any spaces up front. If so, then skip them and set
  223.     //  the gotSpaces flag.
  224.     //
  225.     if (fReaderMgr->skippedSpace())
  226.     {
  227.         fReaderMgr->skipPastSpaces();
  228.         gotSpace = true;
  229.     }
  230.     // If the next char is a percent, then expand the PERef
  231.     if (!fReaderMgr->skippedChar(chPercent))
  232.        return gotSpace;
  233.     while (true)
  234.     {
  235.        if (!expandPERef(false, inLiteral, inMarkup, throwAtEndExt))
  236.           fScanner->emitError(XMLErrs::ExpectedEntityRefName);
  237.        // And skip any more spaces in the expanded value
  238.        if (fReaderMgr->skippedSpace())
  239.        {
  240.           fReaderMgr->skipPastSpaces();
  241.           gotSpace = true;
  242.        }
  243.        if (!fReaderMgr->skippedChar(chPercent))
  244.           break;
  245.     }
  246.     return gotSpace;
  247. }
  248. bool DTDScanner::expandPERef( const   bool    scanExternal
  249.                                 , const bool    inLiteral
  250.                                 , const bool    inMarkup
  251.                                 , const bool    throwEndOfExt)
  252. {
  253.     fScanner->setHasNoDTD(false);
  254.     XMLBufBid bbName(fBufMgr);
  255.     //
  256.     //  If we are in the internal subset and in markup, then this is
  257.     //  an error but we go ahead and do it anyway.
  258.     //
  259.     if (fInternalSubset && inMarkup)
  260.         fScanner->emitError(XMLErrs::PERefInMarkupInIntSubset);
  261.     if (!fReaderMgr->getName(bbName.getBuffer()))
  262.     {
  263.         fScanner->emitError(XMLErrs::ExpectedPEName);
  264.         // Skip the semicolon if that's what we ended up on
  265.         fReaderMgr->skippedChar(chSemiColon);
  266.         return false;
  267.     }
  268.     // If no terminating semicolon, emit an error but try to keep going
  269.     if (!fReaderMgr->skippedChar(chSemiColon))
  270.         fScanner->emitError(XMLErrs::UnterminatedEntityRef, bbName.getRawBuffer());
  271.     //
  272.     //  Look it up in the PE decl pool and see if it exists. If not, just
  273.     //  emit an error and continue.
  274.     //
  275.     XMLEntityDecl* decl = fPEntityDeclPool->getByKey(bbName.getRawBuffer());
  276.     if (!decl)
  277.     {
  278.         // XML 1.0 Section 4.1
  279.         if (fScanner->getStandalone()) {
  280.             // no need to check fScanner->fHasNoDTD which is for sure false
  281.             // since we are in expandPERef already
  282.             fScanner->emitError(XMLErrs::EntityNotFound, bbName.getRawBuffer());
  283.         }
  284.         else {
  285.             if (fScanner->getDoValidation())
  286.                 fScanner->getValidator()->emitError(XMLValid::VC_EntityNotFound, bbName.getRawBuffer());
  287.         }
  288.         return false;
  289.     }
  290.     //
  291.     //  If we are a standalone document, then it has to have been declared
  292.     //  in the internal subset. Keep going though.
  293.     //
  294.     if (fScanner->getDoValidation() && fScanner->getStandalone() && !decl->getDeclaredInIntSubset())
  295.         fScanner->getValidator()->emitError(XMLValid::IllegalRefInStandalone, bbName.getRawBuffer());
  296.     //
  297.     //  Okee dokee, we found it. So create either a memory stream with
  298.     //  the entity value contents, or a file stream if its an external
  299.     //  entity.
  300.     //
  301.     if (decl->isExternal())
  302.     {
  303.         // And now create a reader to read this entity
  304.         InputSource* srcUsed;
  305.         XMLReader* reader = fReaderMgr->createReader
  306.         (
  307.             decl->getSystemId()
  308.             , decl->getPublicId()
  309.             , false
  310.             , inLiteral ? XMLReader::RefFrom_Literal : XMLReader::RefFrom_NonLiteral
  311.             , XMLReader::Type_PE
  312.             , XMLReader::Source_External
  313.             , srcUsed
  314.         );
  315.         // Put a janitor on the source so its cleaned up on exit
  316.         Janitor<InputSource> janSrc(srcUsed);
  317.         // If the creation failed then throw an exception
  318.         if (!reader)
  319.             ThrowXML1(RuntimeException, XMLExcepts::Gen_CouldNotOpenExtEntity, srcUsed->getSystemId());
  320.         // Set the 'throw at end' flag, to the one we were given
  321.         reader->setThrowAtEnd(throwEndOfExt);
  322.         //
  323.         //  Push the reader. If its a recursive expansion, then emit an error
  324.         //  and return an failure.
  325.         //
  326.         if (!fReaderMgr->pushReader(reader, decl))
  327.         {
  328.             fScanner->emitError(XMLErrs::RecursiveEntity, decl->getName());
  329.             return false;
  330.         }
  331.         //
  332.         //  If the caller wants us to scan the external entity, then lets
  333.         //  do that now.
  334.         //
  335.         if (scanExternal)
  336.         {
  337.             XMLEntityHandler* entHandler = fScanner->getEntityHandler();
  338.             // If we have an entity handler, tell it we are starting this entity
  339.             if (entHandler)
  340.                 entHandler->startInputSource(*srcUsed);
  341.             //
  342.             //  Scan the external entity now. The parameter tells it that
  343.             //  it is not in an include section. Get the current reader
  344.             //  level so we can catch partial markup errors and be sure
  345.             //  to get back to here if we get an exception out of the
  346.             //  ext subset scan.
  347.             //
  348.             const unsigned int readerNum = fReaderMgr->getCurrentReaderNum();
  349.             try
  350.             {
  351.                 scanExtSubsetDecl(false);
  352.             }
  353.             catch(...)
  354.             {
  355.                 // Pop the reader back to the original level
  356.                 fReaderMgr->cleanStackBackTo(readerNum);
  357.                 // End the input source, even though its not happy
  358.                 if (entHandler)
  359.                     entHandler->endInputSource(*srcUsed);
  360.                 throw;
  361.             }
  362.             // If we have an entity handler, tell it we are ending this entity
  363.             if (entHandler)
  364.                 entHandler->endInputSource(*srcUsed);
  365.         }
  366.     }
  367.      else
  368.     {
  369.         // Create a reader over a memory stream over the entity value
  370.         XMLReader* valueReader = fReaderMgr->createIntEntReader
  371.         (
  372.             decl->getName()
  373.             , inLiteral ? XMLReader::RefFrom_Literal : XMLReader::RefFrom_NonLiteral
  374.             , XMLReader::Type_PE
  375.             , decl->getValue()
  376.             , decl->getValueLen()
  377.             , false
  378.         );
  379.         //
  380.         //  Trt to push the entity reader onto the reader manager stack,
  381.         //  where it will become the subsequent input. If it fails, that
  382.         //  means the entity is recursive, so issue an error. The reader
  383.         //  will have just been discarded, but we just keep going.
  384.         //
  385.         if (!fReaderMgr->pushReader(valueReader, decl))
  386.             fScanner->emitError(XMLErrs::RecursiveEntity, decl->getName());
  387.     }
  388.     return true;
  389. }
  390. bool DTDScanner::getQuotedString(XMLBuffer& toFill)
  391. {
  392.     // Reset the target buffer
  393.     toFill.reset();
  394.     // Get the next char which must be a single or double quote
  395.     XMLCh quoteCh;
  396.     if (!fReaderMgr->skipIfQuote(quoteCh))
  397.         return false;
  398.     while (true)
  399.     {
  400.         // Get another char
  401.         const XMLCh nextCh = fReaderMgr->getNextChar();
  402.         // See if it matches the starting quote char
  403.         if (nextCh == quoteCh)
  404.             break;
  405.         //
  406.         //  We should never get either an end of file null char here. If we
  407.         //  do, just fail. It will be handled more gracefully in the higher
  408.         //  level code that called us.
  409.         //
  410.         if (!nextCh)
  411.             return false;
  412.         // Else add it to the buffer
  413.         toFill.append(nextCh);
  414.     }
  415.     return true;
  416. }
  417. XMLAttDef*
  418. DTDScanner::scanAttDef(DTDElementDecl& parentElem, XMLBuffer& bufToUse)
  419. {
  420.     // Check for PE ref or optional whitespace
  421.     checkForPERef(false, false, true);
  422.     // Get the name of the attribute
  423.     if (!fReaderMgr->getName(bufToUse))
  424.     {
  425.         fScanner->emitError(XMLErrs::ExpectedAttrName);
  426.         return 0;
  427.     }
  428.     //
  429.     //  Look up this attribute in the parent element's attribute list. If
  430.     //  it already exists, then use the dummy.
  431.     //
  432.     DTDAttDef* decl = parentElem.getAttDef(bufToUse.getRawBuffer());
  433.     if (decl)
  434.     {
  435.         // It already exists, so put out a warning
  436.         fScanner->emitError
  437.         (
  438.             XMLErrs::AttListAlreadyExists
  439.             , bufToUse.getRawBuffer()
  440.             , parentElem.getFullName()
  441.         );
  442.         // Use the dummy decl to parse into and set its name to the name we got
  443.         if (!fDumAttDef)
  444.         {
  445.             fDumAttDef = new DTDAttDef;
  446.             fDumAttDef->setId(fNextAttrId++);
  447.         }
  448.         fDumAttDef->setName(bufToUse.getRawBuffer());
  449.         decl = fDumAttDef;
  450.     }
  451.      else
  452.     {
  453.         //
  454.         //  It does not already exist so create a new one, give it the next
  455.         //  available unique id, and add it
  456.         //
  457.         decl = new DTDAttDef(bufToUse.getRawBuffer());
  458.         decl->setId(fNextAttrId++);
  459.         decl->setExternalAttDeclaration(isReadingExternalEntity());
  460.         parentElem.addAttDef(decl);
  461.     }
  462.     // Set a flag to indicate whether we are doing a dummy parse
  463.     const bool isIgnored = (decl == fDumAttDef);
  464.     // Space is required here, so check for PE ref, and require space
  465.     if (!checkForPERef(true, false, true))
  466.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  467.     //
  468.     //  Next has to be one of the attribute type strings. This tells us what
  469.     //  is to follow.
  470.     //
  471.     if (fReaderMgr->skippedString(XMLUni::fgCDATAString))
  472.     {
  473.         decl->setType(XMLAttDef::CData);
  474.     }
  475.      else if (fReaderMgr->skippedString(XMLUni::fgIDString))
  476.     {
  477.         if (!fReaderMgr->skippedString(XMLUni::fgRefString))
  478.             decl->setType(XMLAttDef::ID);
  479.         else if (!fReaderMgr->skippedChar(chLatin_S))
  480.             decl->setType(XMLAttDef::IDRef);
  481.         else
  482.             decl->setType(XMLAttDef::IDRefs);
  483.     }
  484.      else if (fReaderMgr->skippedString(XMLUni::fgEntitString))
  485.     {
  486.         if (fReaderMgr->skippedChar(chLatin_Y))
  487.         {
  488.             decl->setType(XMLAttDef::Entity);
  489.         }
  490.          else if (fReaderMgr->skippedString(XMLUni::fgIESString))
  491.         {
  492.             decl->setType(XMLAttDef::Entities);
  493.         }
  494.          else
  495.         {
  496.             fScanner->emitError
  497.             (
  498.                 XMLErrs::ExpectedAttributeType
  499.                 , decl->getFullName()
  500.                 , parentElem.getFullName()
  501.             );
  502.             return 0;
  503.         }
  504.     }
  505.      else if (fReaderMgr->skippedString(XMLUni::fgNmTokenString))
  506.     {
  507.         if (fReaderMgr->skippedChar(chLatin_S))
  508.             decl->setType(XMLAttDef::NmTokens);
  509.         else
  510.             decl->setType(XMLAttDef::NmToken);
  511.     }
  512.      else if (fReaderMgr->skippedString(XMLUni::fgNotationString))
  513.     {
  514.         // Check for PE ref and require space
  515.         if (!checkForPERef(true, false, true))
  516.             fScanner->emitError(XMLErrs::ExpectedWhitespace);
  517.         decl->setType(XMLAttDef::Notation);
  518.         if (!scanEnumeration(*decl, bufToUse, true))
  519.             return 0;
  520.         // Set the value as the enumeration for this decl
  521.         decl->setEnumeration(bufToUse.getRawBuffer());
  522.     }
  523.      else if (fReaderMgr->skippedChar(chOpenParen))
  524.     {
  525.         decl->setType(XMLAttDef::Enumeration);
  526.         if (!scanEnumeration(*decl, bufToUse, false))
  527.             return 0;
  528.         // Set the value as the enumeration for this decl
  529.         decl->setEnumeration(bufToUse.getRawBuffer());
  530.     }
  531.      else
  532.     {
  533.         fScanner->emitError
  534.         (
  535.             XMLErrs::ExpectedAttributeType
  536.             , decl->getFullName()
  537.             , parentElem.getFullName()
  538.         );
  539.         return 0;
  540.     }
  541.     // Space is required here, so check for PE ref, and require space
  542.     if (!checkForPERef(true, false, true))
  543.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  544.     // And then scan for the optional default value declaration
  545.     scanDefaultDecl(*decl);
  546.     // If validating, then do a couple of validation constraints
  547.     if (fScanner->getDoValidation())
  548.     {
  549.         if (decl->getType() == XMLAttDef::ID)
  550.         {
  551.             if ((decl->getDefaultType() != XMLAttDef::Implied)
  552.             &&  (decl->getDefaultType() != XMLAttDef::Required))
  553.             {
  554.                 fScanner->getValidator()->emitError(XMLValid::BadIDAttrDefType, decl->getFullName());
  555.             }
  556.         }
  557.         // if attdef is xml:space, check correct enumeration (default|preserve)
  558.         const XMLCh fgXMLSpace[] = { chLatin_x, chLatin_m, chLatin_l, chColon, chLatin_s, chLatin_p, chLatin_a, chLatin_c, chLatin_e, chNull };
  559.         if (!XMLString::compareString(decl->getFullName(),fgXMLSpace)) {
  560.             const XMLCh fgPreserve[] = { chLatin_p, chLatin_r, chLatin_e, chLatin_s, chLatin_e, chLatin_r, chLatin_v, chLatin_e, chNull };
  561.             const XMLCh fgDefault[] = { chLatin_d, chLatin_e, chLatin_f, chLatin_a, chLatin_u, chLatin_l, chLatin_t, chNull };
  562.             bool ok = false;
  563.             if (decl->getType() == XMLAttDef::Enumeration) {
  564.                 RefVectorOf<XMLCh>* enumVector = XMLString::tokenizeString(decl->getEnumeration());
  565.                 int size = enumVector->size();
  566.                 ok = (size == 1 &&
  567.                      (!XMLString::compareString(enumVector->elementAt(0), fgDefault) ||
  568.                       !XMLString::compareString(enumVector->elementAt(0), fgPreserve))) ||
  569.                      (size == 2 &&
  570.                      (!XMLString::compareString(enumVector->elementAt(0), fgDefault) &&
  571.                       !XMLString::compareString(enumVector->elementAt(1), fgPreserve))) ||
  572.                      (size == 2 &&
  573.                      (!XMLString::compareString(enumVector->elementAt(1), fgDefault) &&
  574.                       !XMLString::compareString(enumVector->elementAt(0), fgPreserve)));
  575.                 delete enumVector;
  576.             }
  577.             if (!ok)
  578.                 fScanner->getValidator()->emitError(XMLValid::IllegalXMLSpace);
  579.         }
  580.     }
  581.     // If we have a doc type handler, tell it about this attdef.
  582.     if (fDocTypeHandler)
  583.         fDocTypeHandler->attDef(parentElem, *decl, isIgnored);
  584.     return decl;
  585. }
  586. void DTDScanner::scanAttListDecl()
  587. {
  588.     // Space is required here, so check for a PE ref
  589.     if (!checkForPERef(true, false, true))
  590.     {
  591.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  592.         fReaderMgr->skipPastChar(chCloseAngle);
  593.         return;
  594.     }
  595.     //
  596.     //  Next should be the name of the element it belongs to, so get a buffer
  597.     //  and get the name into it.
  598.     //
  599.     XMLBufBid bbName(fBufMgr);
  600.     if (!fReaderMgr->getName(bbName.getBuffer()))
  601.     {
  602.         fScanner->emitError(XMLErrs::ExpectedElementName);
  603.         fReaderMgr->skipPastChar(chCloseAngle);
  604.         return;
  605.     }
  606.     //
  607.     //  Find this element's declaration. If it has not been declared yet,
  608.     //  we will force one into the list, but not mark it as declared.
  609.     //
  610.     DTDElementDecl* elemDecl = (DTDElementDecl*) fDTDGrammar->getElemDecl(fEmptyNamespaceId, 0, bbName.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE);
  611.     if (!elemDecl)
  612.     {
  613.         //
  614.         //  Lets fault in a declaration and add it to the pool. We mark
  615.         //  it having been created because of an attlist. Later, if its
  616.         //  declared, this will be updated.
  617.         //
  618.         elemDecl = new DTDElementDecl(bbName.getRawBuffer(), fEmptyNamespaceId);
  619.         elemDecl->setCreateReason(XMLElementDecl::AttList);
  620.         elemDecl->setExternalElemDeclaration(isReadingExternalEntity());
  621.         fDTDGrammar->putElemDecl((XMLElementDecl*) elemDecl);
  622.     }
  623.     // If we have a doc type handler, tell it the att list is starting
  624.     if (fDocTypeHandler)
  625.         fDocTypeHandler->startAttList(*elemDecl);
  626.     //
  627.     //  Now we loop until we are done with all of the attributes in this
  628.     //  list. We need a buffer to use for local processing.
  629.     //
  630.     XMLBufBid   bbTmp(fBufMgr);
  631.     XMLBuffer&  tmpBuf = bbTmp.getBuffer();
  632.     bool        seenAnId = false;
  633.     while (true)
  634.     {
  635.         // Get the next char out and see what it tells us to do
  636.         const XMLCh nextCh = fReaderMgr->peekNextChar();
  637.         // Watch for EOF
  638.         if (!nextCh)
  639.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  640.         if (nextCh == chCloseAngle)
  641.         {
  642.             // We are done with this attribute list
  643.             fReaderMgr->getNextChar();
  644.             break;
  645.         }
  646.          else if (XMLReader::isWhitespace(nextCh))
  647.         {
  648.             //
  649.             //  If advanced callbacks are enabled and we have a doc
  650.             //  type handler, then gather up the white space and call
  651.             //  back on the doctype handler. Otherwise, just skip
  652.             //  whitespace.
  653.             //
  654.             if (fDocTypeHandler)
  655.             {
  656.                 fReaderMgr->getSpaces(tmpBuf);
  657.                 fDocTypeHandler->doctypeWhitespace
  658.                 (
  659.                     tmpBuf.getRawBuffer()
  660.                     , tmpBuf.getLen()
  661.                 );
  662.             }
  663.              else
  664.             {
  665.                 fReaderMgr->skipPastSpaces();
  666.             }
  667.         }
  668.          else if (nextCh == chPercent)
  669.         {
  670.             // Eat the percent and expand the ref
  671.             fReaderMgr->getNextChar();
  672.             expandPERef(false, false, true);
  673.         }
  674.          else
  675.         {
  676.             //
  677.             //  It must be an attribute name, so scan it. We let
  678.             //  it use our local buffer for its name scanning.
  679.             //
  680.             XMLAttDef* attDef = scanAttDef(*elemDecl, tmpBuf);
  681.             if (!attDef)
  682.             {
  683.                 fReaderMgr->skipPastChar(chCloseAngle);
  684.                 break;
  685.             }
  686.             //
  687.             //  If we are validating and its an ID type, then we have to
  688.             //  make sure that we have not seen an id attribute yet. Set
  689.             //  the flag to say that we've seen one now also.
  690.             //
  691.             if (fScanner->getDoValidation())
  692.             {
  693.                 if (attDef->getType() == XMLAttDef::ID)
  694.                 {
  695.                     if (seenAnId)
  696.                         fScanner->getValidator()->emitError(XMLValid::MultipleIdAttrs, elemDecl->getFullName());
  697.                     seenAnId = true;
  698.                 }
  699.             }
  700.         }
  701.     }
  702.     // If we have a doc type handler, tell it the att list is ending
  703.     if (fDocTypeHandler)
  704.         fDocTypeHandler->endAttList(*elemDecl);
  705. }
  706. //
  707. //  This method is called to scan the value of an attribute in content. This
  708. //  involves some normalization and replacement of general entity and
  709. //  character references.
  710. //
  711. //  End of entity's must be dealt with here. During DTD scan, they can come
  712. //  from external entities. During content, they can come from any entity.
  713. //  We just eat the end of entity and continue with our scan until we come
  714. //  to the closing quote. If an unterminated value causes us to go through
  715. //  subsequent entities, that will cause errors back in the calling code,
  716. //  but there's little we can do about it here.
  717. //
  718. bool DTDScanner::scanAttValue(const   XMLCh* const        attrName
  719.                                 ,       XMLBuffer&          toFill
  720.                                 , const XMLAttDef::AttTypes type)
  721. {
  722.     enum States
  723.     {
  724.         InWhitespace
  725.         , InContent
  726.     };
  727.     // Reset the target buffer
  728.     toFill.reset();
  729.     // Get the next char which must be a single or double quote
  730.     XMLCh quoteCh;
  731.     if (!fReaderMgr->skipIfQuote(quoteCh))
  732.         return false;
  733.     //
  734.     //  We have to get the current reader because we have to ignore closing
  735.     //  quotes until we hit the same reader again.
  736.     //
  737.     const unsigned int curReader = fReaderMgr->getCurrentReaderNum();
  738.     //
  739.     //  Loop until we get the attribute value. Note that we use a double
  740.     //  loop here to avoid the setup/teardown overhead of the exception
  741.     //  handler on every round.
  742.     //
  743.     XMLCh   nextCh;
  744.     XMLCh   secondCh = 0;
  745.     States  curState = InContent;
  746.     bool    firstNonWS = false;
  747.     bool    gotLeadingSurrogate = false;
  748.     bool    escaped;
  749.     while (true)
  750.     {
  751.     try
  752.     {
  753.         while(true)
  754.         {
  755.             // Get another char. Use second char from prevous is its there
  756.             if (secondCh)
  757.             {
  758.                 nextCh = secondCh;
  759.                 secondCh = 0;
  760.             }
  761.              else
  762.             {
  763.                 nextCh = fReaderMgr->getNextChar();
  764.             }
  765.             if (!nextCh)
  766.                 ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  767.             // Check for our ending quote in the same entity
  768.             if (nextCh == quoteCh)
  769.             {
  770.                 if (curReader == fReaderMgr->getCurrentReaderNum())
  771.                     return true;
  772.                 // Watch for spillover into a previous entity
  773.                 if (curReader > fReaderMgr->getCurrentReaderNum())
  774.                 {
  775.                     fScanner->emitError(XMLErrs::PartialMarkupInEntity);
  776.                     return false;
  777.                 }
  778.             }
  779.             //
  780.             //  Check for an entity ref now, before we let it affect our
  781.             //  whitespace normalization logic below. We ignore the empty flag
  782.             //  in this one.
  783.             //
  784.             escaped = false;
  785.             if (nextCh == chAmpersand)
  786.             {
  787.                 if (scanEntityRef(nextCh, secondCh, escaped) != EntityExp_Returned)
  788.                 {
  789.                     gotLeadingSurrogate = false;
  790.                     continue;
  791.                 }
  792.             }
  793.             // Check for correct surrogate pairs
  794.             if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
  795.             {
  796.                 if (gotLeadingSurrogate)
  797.                     fScanner->emitError(XMLErrs::Expected2ndSurrogateChar);
  798.                 else
  799.                     gotLeadingSurrogate = true;
  800.             }
  801.              else
  802.             {
  803.                 if (gotLeadingSurrogate)
  804.                 {
  805.                     if ((nextCh < 0xDC00) && (nextCh > 0xDFFF))
  806.                         fScanner->emitError(XMLErrs::Expected2ndSurrogateChar);
  807.                 }
  808.                 gotLeadingSurrogate = false;
  809.                 // Its got to at least be a valid XML character
  810.                 if (!XMLReader::isXMLChar(nextCh))
  811.                 {
  812.                     XMLCh tmpBuf[9];
  813.                     XMLString::binToText
  814.                     (
  815.                         nextCh
  816.                         , tmpBuf
  817.                         , 8
  818.                         , 16
  819.                     );
  820.                     fScanner->emitError
  821.                     (
  822.                         XMLErrs::InvalidCharacter
  823.                         , attrName
  824.                         , tmpBuf
  825.                     );
  826.                 }
  827.             }
  828.             //
  829.             //  If its not escaped, then make sure its not a < character, which
  830.             //  is not allowed in attribute values.
  831.             //
  832.             if (!escaped && (nextCh == chOpenAngle))
  833.                 fScanner->emitError(XMLErrs::BracketInAttrValue, attrName);
  834.             //
  835.             //  If the attribute is a CDATA type we do simple replacement of
  836.             //  tabs and new lines with spaces, if the character is not escaped
  837.             //  by way of a char ref.
  838.             //
  839.             //  Otherwise, we do the standard non-CDATA normalization of
  840.             //  compressing whitespace to single spaces and getting rid of
  841.             //  leading and trailing whitespace.
  842.             //
  843.             if (type == XMLAttDef::CData)
  844.             {
  845.                 if (!escaped)
  846.                 {
  847.                     if ((nextCh == 0x09) || (nextCh == 0x0A) || (nextCh == 0x0D))
  848.                         nextCh = chSpace;
  849.                 }
  850.             }
  851.              else
  852.             {
  853.                 if (curState == InWhitespace)
  854.                 {
  855.                     if (!XMLReader::isWhitespace(nextCh))
  856.                     {
  857.                         if (firstNonWS)
  858.                             toFill.append(chSpace);
  859.                         curState = InContent;
  860.                         firstNonWS = true;
  861.                     }
  862.                      else
  863.                     {
  864.                         continue;
  865.                     }
  866.                 }
  867.                  else if (curState == InContent)
  868.                 {
  869.                     if (XMLReader::isWhitespace(nextCh))
  870.                     {
  871.                         curState = InWhitespace;
  872.                         continue;
  873.                     }
  874.                     firstNonWS = true;
  875.                 }
  876.             }
  877.             // Else add it to the buffer
  878.             toFill.append(nextCh);
  879.         }
  880.     }
  881.     catch(const EndOfEntityException&)
  882.     {
  883.         // Just eat it and continue.
  884.         gotLeadingSurrogate = false;
  885.         escaped = false;
  886.     }
  887.     }
  888.     return true;
  889. }
  890. bool DTDScanner::scanCharRef(XMLCh& first, XMLCh& second)
  891. {
  892.     bool gotOne = false;
  893.     unsigned int value = 0;
  894.     //
  895.     //  Set the radix. Its supposed to be a lower case x if hex. But, in
  896.     //  order to recover well, we check for an upper and put out an error
  897.     //  for that.
  898.     //
  899.     unsigned int radix = 10;
  900.     if (fReaderMgr->skippedChar(chLatin_x))
  901.     {
  902.         radix = 16;
  903.     }
  904.      else if (fReaderMgr->skippedChar(chLatin_X))
  905.     {
  906.         fScanner->emitError(XMLErrs::HexRadixMustBeLowerCase);
  907.         radix = 16;
  908.     }
  909.     while (true)
  910.     {
  911.         const XMLCh nextCh = fReaderMgr->peekNextChar();
  912.         // Watch for EOF
  913.         if (!nextCh)
  914.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  915.         // Break out on the terminating semicolon
  916.         if (nextCh == chSemiColon)
  917.         {
  918.             fReaderMgr->getNextChar();
  919.             break;
  920.         }
  921.         //
  922.         //  Convert this char to a binary value, or bail out if its not
  923.         //  one.
  924.         //
  925.         unsigned int nextVal;
  926.         if ((nextCh >= chDigit_0) && (nextCh <= chDigit_9))
  927.             nextVal = (unsigned int)(nextCh - chDigit_0);
  928.         else if ((nextCh >= chLatin_A) && (nextCh <= chLatin_F))
  929.             nextVal= (unsigned int)(10 + (nextCh - chLatin_A));
  930.         else if ((nextCh >= chLatin_a) && (nextCh <= chLatin_f))
  931.             nextVal = (unsigned int)(10 + (nextCh - chLatin_a));
  932.         else
  933.         {
  934.             //
  935.             //  If we got at least a sigit, then do an unterminated ref
  936.             //  error. Else, do an expected a numerical ref thing.
  937.             //
  938.             if (gotOne)
  939.                 fScanner->emitError(XMLErrs::UnterminatedCharRef);
  940.             else
  941.                 fScanner->emitError(XMLErrs::ExpectedNumericalCharRef);
  942.             return false;
  943.         }
  944.         //
  945.         //  Make sure its valid for the radix. If not, then just eat the
  946.         //  digit and go on after issueing an error. Else, update the
  947.         //  running value with this new digit.
  948.         //
  949.         if (nextVal >= radix)
  950.         {
  951.             XMLCh tmpStr[2];
  952.             tmpStr[0] = nextCh;
  953.             tmpStr[1] = chNull;
  954.             fScanner->emitError(XMLErrs::BadDigitForRadix, tmpStr);
  955.         }
  956.          else
  957.         {
  958.             value = (value * radix) + nextVal;
  959.         }
  960.         // Indicate that we got at least one good digit
  961.         gotOne = true;
  962.         // Eat the char we just processed
  963.         fReaderMgr->getNextChar();
  964.     }
  965.     // Return the char (or chars)
  966.     if (value >= 0x10000)
  967.     {
  968.         value -= 0x10000;
  969.         first = XMLCh((value >> 10) + 0xD800);
  970.         second = XMLCh((value & 0x3FF) + 0xDC00);
  971.     }
  972.      else
  973.     {
  974.         first = XMLCh(value);
  975.         second = 0;
  976.     }
  977.     return true;
  978. }
  979. ContentSpecNode*
  980. DTDScanner::scanChildren(const DTDElementDecl& elemDecl, XMLBuffer& bufToUse)
  981. {
  982.     // Check for a PE ref here, but don't require spaces
  983.     checkForPERef(false, false, true);
  984.     // We have to check entity nesting here
  985.     unsigned int curReader;
  986.     //
  987.     //  We know that the caller just saw an opening parenthesis, so we need
  988.     //  to parse until we hit the end of it, recursing for other nested
  989.     //  parentheses we see.
  990.     //
  991.     //  We have to check for one up front, since it could be something like
  992.     //  (((a)*)) etc...
  993.     //
  994.     ContentSpecNode* curNode = 0;
  995.     if (fReaderMgr->skippedChar(chOpenParen))
  996.     {
  997.         curReader = fReaderMgr->getCurrentReaderNum();
  998.         // Lets call ourself and get back the resulting node
  999.         curNode = scanChildren(elemDecl, bufToUse);
  1000.         // If that failed, no need to go further, return failure
  1001.         if (!curNode)
  1002.             return 0;
  1003.         if (curReader != fReaderMgr->getCurrentReaderNum() && fScanner->getDoValidation())
  1004.             fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE);
  1005.     }
  1006.      else
  1007.     {
  1008.         // Not a nested paren, so it must be a leaf node
  1009.         if (!fReaderMgr->getName(bufToUse))
  1010.         {
  1011.             fScanner->emitError(XMLErrs::ExpectedElementName);
  1012.             return 0;
  1013.         }
  1014.         //
  1015.         //  Create a leaf node for it. If we can find the element id for
  1016.         //  this element, then use it. Else, we have to fault in an element
  1017.         //  decl, marked as created because of being in a content model.
  1018.         //
  1019.         XMLElementDecl* decl = fDTDGrammar->getElemDecl(fEmptyNamespaceId, 0, bufToUse.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE);
  1020.         if (!decl)
  1021.         {
  1022.             decl = new DTDElementDecl(bufToUse.getRawBuffer(), fEmptyNamespaceId);
  1023.             decl->setCreateReason(XMLElementDecl::InContentModel);
  1024.             decl->setExternalElemDeclaration(isReadingExternalEntity());
  1025.             fDTDGrammar->putElemDecl(decl);
  1026.         }
  1027.         curNode = new ContentSpecNode(decl->getElementName());
  1028.         // Check for a PE ref here, but don't require spaces
  1029.         const bool gotSpaces = checkForPERef(false, false, true);
  1030.         // Check for a repetition character after the leaf
  1031.         const XMLCh repCh = fReaderMgr->peekNextChar();
  1032.         ContentSpecNode* tmpNode = makeRepNode(repCh, curNode);
  1033.         if (tmpNode != curNode)
  1034.         {
  1035.             if (gotSpaces)
  1036.                 fScanner->emitError(XMLErrs::UnexpectedWhitespace);
  1037.             fReaderMgr->getNextChar();
  1038.             curNode = tmpNode;
  1039.         }
  1040.     }
  1041.     // Check for a PE ref here, but don't require spaces
  1042.     checkForPERef(false, false, true);
  1043.     //
  1044.     //  Ok, the next character tells us what kind of content this particular
  1045.     //  model this particular parentesized section is. Its either a choice if
  1046.     //  we see ',', a sequence if we see '|', or a single leaf node if we see
  1047.     //  a closing paren.
  1048.     //
  1049.     const XMLCh opCh = fReaderMgr->peekNextChar();
  1050.     if ((opCh != chComma)
  1051.     &&  (opCh != chPipe)
  1052.     &&  (opCh != chCloseParen))
  1053.     {
  1054.         // Not a legal char, so delete our node and return failure
  1055.         fScanner->emitError(XMLErrs::ExpectedSeqChoiceLeaf);
  1056.         delete curNode;
  1057.         return 0;
  1058.     }
  1059.     //
  1060.     //  Create the head node of the correct type. We need this to remember
  1061.     //  the top of the local tree. If it was a single subexpr, then just
  1062.     //  set the head node to the current node. For the others, we'll build
  1063.     //  the tree off the second child as we move across.
  1064.     //
  1065.     ContentSpecNode* headNode = 0;
  1066.     ContentSpecNode::NodeTypes curType;
  1067.     if (opCh == chComma)
  1068.     {
  1069.         curType = ContentSpecNode::Sequence;
  1070.         headNode = new ContentSpecNode(curType, curNode, 0);
  1071.         curNode = headNode;
  1072.     }
  1073.      else if (opCh == chPipe)
  1074.     {
  1075.         curType = ContentSpecNode::Choice;
  1076.         headNode = new ContentSpecNode(curType, curNode, 0);
  1077.         curNode = headNode;
  1078.     }
  1079.      else
  1080.     {
  1081.         headNode = curNode;
  1082.         fReaderMgr->getNextChar();
  1083.     }
  1084.     //
  1085.     //  If it was a sequence or choice, we just loop until we get to the
  1086.     //  end of our section, adding each new leaf or sub expression to the
  1087.     //  right child of the current node, and making that new node the current
  1088.     //  node.
  1089.     //
  1090.     if ((opCh == chComma) || (opCh == chPipe))
  1091.     {
  1092.         ContentSpecNode* lastNode = 0;
  1093.         while (true)
  1094.         {
  1095.             //
  1096.             //  The next thing must either be another | or , character followed
  1097.             //  by another leaf or subexpression, or a closing parenthesis, or a
  1098.             //  PE ref.
  1099.             //
  1100.             if (fReaderMgr->lookingAtChar(chPercent))
  1101.             {
  1102.                 checkForPERef(false, false, true);
  1103.             }
  1104.              else if (fReaderMgr->skippedSpace())
  1105.             {
  1106.                 // Just skip whitespace
  1107.                 fReaderMgr->skipPastSpaces();
  1108.             }
  1109.              else if (fReaderMgr->skippedChar(chCloseParen))
  1110.             {
  1111.                 //
  1112.                 //  We've hit the end of this section, so break out. But, we
  1113.                 //  need to see if we left a partial sequence of choice node
  1114.                 //  without a second node. If so, we have to undo that and
  1115.                 //  put its left child into the right node of the previous
  1116.                 //  node.
  1117.                 //
  1118.                 if ((curNode->getType() == ContentSpecNode::Choice)
  1119.                 ||  (curNode->getType() == ContentSpecNode::Sequence))
  1120.                 {
  1121.                     if (!curNode->getSecond())
  1122.                     {
  1123.                         ContentSpecNode* saveFirst = curNode->orphanFirst();
  1124.                         lastNode->setSecond(saveFirst);
  1125.                         curNode = lastNode;
  1126.                     }
  1127.                 }
  1128.                 break;
  1129.             }
  1130.              else if (fReaderMgr->skippedChar(opCh))
  1131.             {
  1132.                 // Check for a PE ref here, but don't require spaces
  1133.                 checkForPERef(false, false, true);
  1134.                 if (fReaderMgr->skippedChar(chOpenParen))
  1135.                 {
  1136.                     curReader = fReaderMgr->getCurrentReaderNum();
  1137.                     // Recurse to handle this new guy
  1138.                     ContentSpecNode* subNode = scanChildren(elemDecl, bufToUse);
  1139.                     // If it failed, we are done, clean up here and return failure
  1140.                     if (!subNode)
  1141.                     {
  1142.                         delete headNode;
  1143.                         return 0;
  1144.                     }
  1145.                     if (curReader != fReaderMgr->getCurrentReaderNum() && fScanner->getDoValidation())
  1146.                         fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE);
  1147.                     // Else patch it in and make it the new current
  1148.                     ContentSpecNode* newCur = new ContentSpecNode
  1149.                     (
  1150.                         curType
  1151.                         , subNode
  1152.                         , 0
  1153.                     );
  1154.                     curNode->setSecond(newCur);
  1155.                     lastNode = curNode;
  1156.                     curNode = newCur;
  1157.                 }
  1158.                  else
  1159.                 {
  1160.                     //
  1161.                     //  Got to be a leaf node, so get a name. If we cannot get
  1162.                     //  one, then clean up and get outa here.
  1163.                     //
  1164.                     if (!fReaderMgr->getName(bufToUse))
  1165.                     {
  1166.                         delete headNode;
  1167.                         fScanner->emitError(XMLErrs::ExpectedElementName);
  1168.                         return 0;
  1169.                     }
  1170.                     //
  1171.                     //  Create a leaf node for it. If we can find the element
  1172.                     //  id for this element, then use it. Else, we have to
  1173.                     //  fault in an element decl, marked as created because
  1174.                     //  of being in a content model.
  1175.                     //
  1176.                     XMLElementDecl* decl = fDTDGrammar->getElemDecl(fEmptyNamespaceId, 0, bufToUse.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE);
  1177.                     if (!decl)
  1178.                     {
  1179.                         decl = new DTDElementDecl(bufToUse.getRawBuffer(), fEmptyNamespaceId);
  1180.                         decl->setCreateReason(XMLElementDecl::InContentModel);
  1181.                         decl->setExternalElemDeclaration(isReadingExternalEntity());
  1182.                         fDTDGrammar->putElemDecl(decl);
  1183.                     }
  1184.                     ContentSpecNode* tmpLeaf = new ContentSpecNode(decl->getElementName());
  1185.                     // Check for a repetition character after the leaf
  1186.                     const XMLCh repCh = fReaderMgr->peekNextChar();
  1187.                     ContentSpecNode* tmpLeaf2 = makeRepNode(repCh, tmpLeaf);
  1188.                     if (tmpLeaf != tmpLeaf2)
  1189.                         fReaderMgr->getNextChar();
  1190.                     //
  1191.                     //  Create a new sequence or choice node, with the leaf
  1192.                     //  (or rep surrounding it) we just got as its first node.
  1193.                     //  Make the new node the second node of the current node,
  1194.                     //  and then make it the current node.
  1195.                     //
  1196.                     ContentSpecNode* newCur = new ContentSpecNode
  1197.                     (
  1198.                         curType
  1199.                         , tmpLeaf2
  1200.                         , 0
  1201.                     );
  1202.                     curNode->setSecond(newCur);
  1203.                     lastNode = curNode;
  1204.                     curNode = newCur;
  1205.                 }
  1206.             }
  1207.              else
  1208.             {
  1209.                 // Cannot be valid
  1210.                 if (opCh == chComma)
  1211.                 {
  1212.                     fScanner->emitError(XMLErrs::ExpectedChoiceOrCloseParen);
  1213.                 }
  1214.                  else
  1215.                 {
  1216.                     fScanner->emitError
  1217.                     (
  1218.                         XMLErrs::ExpectedSeqOrCloseParen
  1219.                         , elemDecl.getFullName()
  1220.                     );
  1221.                 }
  1222.                 delete headNode;
  1223.                 return 0;
  1224.             }
  1225.         }
  1226.     }
  1227.     //
  1228.     //  We saw the terminating parenthesis so lets check for any repetition
  1229.     //  character, and create a node for that, making the head node the child
  1230.     //  of it.
  1231.     //
  1232.     XMLCh repCh = fReaderMgr->peekNextChar();
  1233.     ContentSpecNode* retNode = makeRepNode(repCh, headNode);
  1234.     if (retNode != headNode)
  1235.         fReaderMgr->getNextChar();
  1236.     return retNode;
  1237. }
  1238. //
  1239. //  We get here after the '<!--' part of the comment. We scan past the
  1240. //  terminating '-->' It will calls the appropriate handler with the comment
  1241. //  text, if one is provided. A comment can be in either the document or
  1242. //  the DTD, so the fInDocument flag is used to know which handler to send
  1243. //  it to.
  1244. //
  1245. void DTDScanner::scanComment()
  1246. {
  1247.     enum States
  1248.     {
  1249.         InText
  1250.         , OneDash
  1251.         , TwoDashes
  1252.     };
  1253.     // Get a buffer for this
  1254.     XMLBufBid bbComment(fBufMgr);
  1255.     //
  1256.     //  Get the comment text into a temp buffer. Be sure to use temp buffer
  1257.     //  two here, since its to be used for stuff that is potentially longer
  1258.     //  than just a name.
  1259.     //
  1260.     States curState = InText;
  1261.     while (true)
  1262.     {
  1263.         // Get the next character
  1264.         const XMLCh nextCh = fReaderMgr->getNextChar();
  1265.         //  Watch for an end of file
  1266.         if (!nextCh)
  1267.         {
  1268.             fScanner->emitError(XMLErrs::UnterminatedComment);
  1269.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  1270.         }
  1271.         // Make sure its a valid XML character
  1272.         if (!XMLReader::isXMLChar(nextCh))
  1273.         {
  1274.             XMLCh tmpBuf[9];
  1275.             XMLString::binToText
  1276.             (
  1277.                 nextCh
  1278.                 , tmpBuf
  1279.                 , 8
  1280.                 , 16
  1281.             );
  1282.             fScanner->emitError(XMLErrs::InvalidCharacter, tmpBuf);
  1283.         }
  1284.         if (curState == InText)
  1285.         {
  1286.             // If its a dash, go to OneDash state. Otherwise take as text
  1287.             if (nextCh == chDash)
  1288.                 curState = OneDash;
  1289.             else
  1290.                 bbComment.append(nextCh);
  1291.         }
  1292.          else if (curState == OneDash)
  1293.         {
  1294.             //
  1295.             //  If its another dash, then we change to the two dashes states.
  1296.             //  Otherwise, we have to put in the deficit dash and the new
  1297.             //  character and go back to InText.
  1298.             //
  1299.             if (nextCh == chDash)
  1300.             {
  1301.                 curState = TwoDashes;
  1302.             }
  1303.              else
  1304.             {
  1305.                 bbComment.append(chDash);
  1306.                 bbComment.append(nextCh);
  1307.                 curState = InText;
  1308.             }
  1309.         }
  1310.          else if (curState == TwoDashes)
  1311.         {
  1312.             // The next character must be the closing bracket
  1313.             if (nextCh != chCloseAngle)
  1314.             {
  1315.                 fScanner->emitError(XMLErrs::IllegalSequenceInComment);
  1316.                 fReaderMgr->skipPastChar(chCloseAngle);
  1317.                 return;
  1318.             }
  1319.             break;
  1320.         }
  1321.     }
  1322.     // If there is a doc type handler, then pass on the comment stuff
  1323.     if (fDocTypeHandler)
  1324.         fDocTypeHandler->doctypeComment(bbComment.getRawBuffer());
  1325. }
  1326. bool DTDScanner::scanContentSpec(DTDElementDecl& toFill)
  1327. {
  1328.     //
  1329.     //  Check for for a couple of the predefined content type strings. If
  1330.     //  its not one of these, its got to be a parenthesized reg ex type
  1331.     //  expression.
  1332.     //
  1333.     if (fReaderMgr->skippedString(XMLUni::fgEmptyString))
  1334.     {
  1335.         toFill.setModelType(DTDElementDecl::Empty);
  1336.         return true;
  1337.     }
  1338.     if (fReaderMgr->skippedString(XMLUni::fgAnyString))
  1339.     {
  1340.         toFill.setModelType(DTDElementDecl::Any);
  1341.         return true;
  1342.     }
  1343.     // Its got to be a parenthesized regular expression
  1344.     if (!fReaderMgr->skippedChar(chOpenParen))
  1345.     {
  1346.         fScanner->emitError
  1347.         (
  1348.             XMLErrs::ExpectedContentSpecExpr
  1349.             , toFill.getFullName()
  1350.         );
  1351.         return false;
  1352.     }
  1353.     // Get the current reader id, so we can test for partial markup
  1354.     const unsigned int curReader = fReaderMgr->getCurrentReaderNum();
  1355.     // We could have a PE ref here, but don't require space
  1356.     checkForPERef(false, false, true);
  1357.     //
  1358.     //  Now we look for a PCDATA string. If its PCDATA, then it must be a
  1359.     //  MIXED model. Otherwise, it must be a regular list of children in
  1360.     //  a regular expression perhaps.
  1361.     //
  1362.     bool status;
  1363.     if (fReaderMgr->skippedString(XMLUni::fgPCDATAString))
  1364.     {
  1365.         // Set the model to mixed
  1366.         toFill.setModelType(DTDElementDecl::Mixed_Simple);
  1367.         status = scanMixed(toFill);
  1368.         //
  1369.         //  If we are validating we have to check that there are no multiple
  1370.         //  uses of any child elements.
  1371.         //
  1372.         if (fScanner->getDoValidation())
  1373.         {
  1374.             if (((const MixedContentModel*)toFill.getContentModel())->hasDups())
  1375.                 fScanner->getValidator()->emitError(XMLValid::RepElemInMixed);
  1376.         }
  1377.     }
  1378.      else
  1379.     {
  1380.         //
  1381.         //  We have to do a recursive scan of the content model. Create a
  1382.         //  buffer for it to use, for efficiency. It returns the top ofthe
  1383.         //  content spec node tree, which we set if successful.
  1384.         //
  1385.         toFill.setModelType(DTDElementDecl::Children);
  1386.         XMLBufBid bbTmp(fBufMgr);
  1387.         ContentSpecNode* resNode = scanChildren(toFill, bbTmp.getBuffer());
  1388.         status = (resNode != 0);
  1389.         if (status)
  1390.             toFill.setContentSpec(resNode);
  1391.     }
  1392.     // Make sure we are on the same reader as where we started
  1393.     if (curReader != fReaderMgr->getCurrentReaderNum() && fScanner->getDoValidation())
  1394.         fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE);
  1395.     return status;
  1396. }
  1397. void DTDScanner::scanDefaultDecl(DTDAttDef& toFill)
  1398. {
  1399.     if (fReaderMgr->skippedString(XMLUni::fgRequiredString))
  1400.     {
  1401.         toFill.setDefaultType(XMLAttDef::Required);
  1402.         return;
  1403.     }
  1404.     if (fReaderMgr->skippedString(XMLUni::fgImpliedString))
  1405.     {
  1406.         toFill.setDefaultType(XMLAttDef::Implied);
  1407.         return;
  1408.     }
  1409.     if (fReaderMgr->skippedString(XMLUni::fgFixedString))
  1410.     {
  1411.         //
  1412.         //  There must be space before the fixed value. If there is not, then
  1413.         //  emit an error but keep going.
  1414.         //
  1415.         if (!fReaderMgr->skippedSpace())
  1416.             fScanner->emitError(XMLErrs::ExpectedWhitespace);
  1417.         else
  1418.             fReaderMgr->skipPastSpaces();
  1419.         toFill.setDefaultType(XMLAttDef::Fixed);
  1420.     }
  1421.      else
  1422.     {
  1423.         toFill.setDefaultType(XMLAttDef::Default);
  1424.     }
  1425.     //
  1426.     //  If we got here, its fixed or default, so we need to get a value.
  1427.     //  If we don't, then emit an error but just set the default value to
  1428.     //  an empty string and try to keep going.
  1429.     //
  1430.     XMLBufBid bbValue(fBufMgr);
  1431.     if (!scanAttValue(toFill.getFullName(), bbValue.getBuffer(), toFill.getType()))
  1432.         fScanner->emitError(XMLErrs::ExpectedDefAttrDecl);
  1433.     toFill.setValue(bbValue.getRawBuffer());
  1434. }
  1435. //
  1436. //  This method handles the high level logic of scanning the DOCType
  1437. //  declaration. This kicks off both the scanning of the internal subset and
  1438. //  the scanning of the external subset, if any.
  1439. //
  1440. //  When we get here the '<!DOCTYPE' part has already been scanned, which is
  1441. //  what told us that we had a doc type decl to parse.
  1442. //
  1443. void DTDScanner::scanDocTypeDecl(const bool reuseGrammar)
  1444. {
  1445.     // There must be some space after DOCTYPE
  1446.     if (!fReaderMgr->skipPastSpaces())
  1447.     {
  1448.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  1449.         // Just skip the Doctype declaration and return
  1450.         fReaderMgr->skipPastChar(chCloseAngle);
  1451.         return;
  1452.     }
  1453.     // Get a buffer for the root element
  1454.     XMLBufBid bbRootName(fBufMgr);
  1455.     //
  1456.     //  Get a name from the input, which should be the name of the root
  1457.     //  element of the upcoming content.
  1458.     //
  1459.     fReaderMgr->getName(bbRootName.getBuffer());
  1460.     if (bbRootName.isEmpty())
  1461.     {
  1462.         fScanner->emitError(XMLErrs::NoRootElemInDOCTYPE);
  1463.         fReaderMgr->skipPastChar(chCloseAngle);
  1464.         return;
  1465.     }
  1466.     //
  1467.     //  Store the root element name for later check
  1468.     //
  1469.     fScanner->setRootElemName(bbRootName.getRawBuffer());
  1470.     //
  1471.     //  This element obviously is not going to exist in the element decl
  1472.     //  pool yet, but we need to call docTypeDecl. So force it into
  1473.     //  the element decl pool, marked as being there because it was in
  1474.     //  the DOCTYPE. Later, when its declared, the status will be updated.
  1475.     //
  1476.     //  Only do this if we are not reusing the validator! If we are reusing,
  1477.     //  then look it up instead. It has to exist!
  1478.     //
  1479.     DTDElementDecl* rootDecl;
  1480.     Janitor<DTDElementDecl> janSrc(0);
  1481.     if (reuseGrammar)
  1482.     {
  1483.         Grammar* fGrammar = fDTDGrammar;
  1484.         if (fGrammar->getGrammarType() == Grammar::DTDGrammarType) {
  1485.             rootDecl = (DTDElementDecl*) fDTDGrammar->getElemDecl(fEmptyNamespaceId, 0, bbRootName.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE);
  1486.             if (rootDecl)
  1487.                 fDTDGrammar->setRootElemId(rootDecl->getId());
  1488.             else {
  1489.                 rootDecl = new DTDElementDecl(bbRootName.getRawBuffer(), fEmptyNamespaceId);
  1490.                 rootDecl->setCreateReason(DTDElementDecl::AsRootElem);
  1491.                 rootDecl->setExternalElemDeclaration(isReadingExternalEntity());
  1492.                 fDTDGrammar->setRootElemId(fDTDGrammar->putElemDecl(rootDecl));
  1493.             }
  1494.         }
  1495.         else {
  1496.             rootDecl = new DTDElementDecl(bbRootName.getRawBuffer(), fEmptyNamespaceId);
  1497.             rootDecl->setCreateReason(DTDElementDecl::AsRootElem);
  1498.             rootDecl->setExternalElemDeclaration(isReadingExternalEntity());
  1499.             janSrc.reset(rootDecl);
  1500.         }
  1501.     }
  1502.      else
  1503.     {
  1504.         rootDecl = new DTDElementDecl(bbRootName.getRawBuffer(), fEmptyNamespaceId);
  1505.         rootDecl->setCreateReason(DTDElementDecl::AsRootElem);
  1506.         rootDecl->setExternalElemDeclaration(isReadingExternalEntity());
  1507.         fDTDGrammar->setRootElemId(fDTDGrammar->putElemDecl(rootDecl));
  1508.     }
  1509.     // Skip any spaces after the name
  1510.     fReaderMgr->skipPastSpaces();
  1511.     //
  1512.     //  And now if we are looking at a >, then we are done. It is not
  1513.     //  required to have an internal or external subset, though why you
  1514.     //  would not escapes me.
  1515.     //
  1516.     if (fReaderMgr->skippedChar(chCloseAngle)) {
  1517.         //
  1518.         //  If we have a doc type handler and advanced callbacks are enabled,
  1519.         //  call the doctype event.
  1520.         //
  1521.         if (fDocTypeHandler)
  1522.             fDocTypeHandler->doctypeDecl(*rootDecl, 0, 0, false);
  1523.         return;
  1524.     }
  1525.     // either internal/external subset
  1526.     if(!reuseGrammar) {
  1527.         if (fScanner->getValidationScheme() == XMLScanner::Val_Auto)
  1528.             fScanner->setDoValidation(true, false);
  1529.     }
  1530.     bool    hasIntSubset = false;
  1531.     bool    hasExtSubset = false;
  1532.     XMLCh*  sysId = 0;
  1533.     XMLCh*  pubId = 0;
  1534.     //
  1535.     //  If the next character is '[' then we have no external subset cause
  1536.     //  there is no system id, just the opening character of the internal
  1537.     //  subset. Else, has to be an id.
  1538.     //
  1539.     // Just look at the next char, don't eat it.
  1540.     if (fReaderMgr->peekNextChar() == chOpenSquare)
  1541.     {
  1542.         hasIntSubset = true;
  1543.     }
  1544.      else
  1545.     {
  1546.         // Indicate we have an external subset
  1547.         hasExtSubset = true;
  1548.         fScanner->setHasNoDTD(false);
  1549.         // Get buffers for the ids
  1550.         XMLBufBid bbPubId(fBufMgr);
  1551.         XMLBufBid bbSysId(fBufMgr);
  1552.         // Get the external subset id
  1553.         if (!scanId(bbPubId.getBuffer(), bbSysId.getBuffer(), IDType_External))
  1554.         {
  1555.             fReaderMgr->skipPastChar(chCloseAngle);
  1556.             return;
  1557.         }
  1558.         // Get copies of the ids we got
  1559.         pubId = XMLString::replicate(bbPubId.getRawBuffer());
  1560.         sysId = XMLString::replicate(bbSysId.getRawBuffer());
  1561.         // Skip spaces and check again for the opening of an internal subset
  1562.         fReaderMgr->skipPastSpaces();
  1563.         // Just look at the next char, don't eat it.
  1564.         if (fReaderMgr->peekNextChar() == chOpenSquare) {
  1565.             hasIntSubset = true;
  1566.         }
  1567.     }
  1568.     // Insure that the ids get cleaned up, if they got allocated
  1569.     ArrayJanitor<XMLCh> janSysId(sysId);
  1570.     ArrayJanitor<XMLCh> janPubId(pubId);
  1571.     //
  1572.     //  If we have a doc type handler and advanced callbacks are enabled,
  1573.     //  call the doctype event.
  1574.     //
  1575.     if (fDocTypeHandler)
  1576.         fDocTypeHandler->doctypeDecl(*rootDecl, pubId, sysId, hasIntSubset);
  1577.     //
  1578.     //  Ok, if we had an internal subset, we are just past the [ character
  1579.     //  and need to parse that first.
  1580.     //
  1581.     if (hasIntSubset)
  1582.     {
  1583.         // Eat the opening square bracket
  1584.         fReaderMgr->getNextChar();
  1585.         // We can't have any internal subset if we are reusing the validator
  1586.         if (reuseGrammar)
  1587.             ThrowXML(RuntimeException, XMLExcepts::Val_CantHaveIntSS);
  1588.         // Indicate we are in the internal subset now
  1589.         FlagJanitor<bool> janContentFlag(&fInternalSubset, true);
  1590.         //
  1591.         //  And try to scan the internal subset. If we fail, try to recover
  1592.         //  by skipping forward tot he close angle and returning.
  1593.         //
  1594.         if (!scanInternalSubset())
  1595.         {
  1596.             fReaderMgr->skipPastChar(chCloseAngle);
  1597.             return;
  1598.         }
  1599.         //
  1600.         //  Do a sanity check that some expanded PE did not propogate out of
  1601.         //  the doctype. This could happen if it was terminated early by bad
  1602.         //  syntax.
  1603.         //
  1604.         if (fReaderMgr->getReaderDepth() > 1)
  1605.         {
  1606.             fScanner->emitError(XMLErrs::PEPropogated);
  1607.             // Ask the reader manager to pop back down to the main level
  1608.             fReaderMgr->cleanStackBackTo(1);
  1609.         }
  1610.         fReaderMgr->skipPastSpaces();
  1611.     }
  1612.     // And that should leave us at the closing > of the DOCTYPE line
  1613.     if (!fReaderMgr->skippedChar(chCloseAngle))
  1614.     {
  1615.         //
  1616.         //  Do a special check for the common scenario of an extra ] char at
  1617.         //  the end. This is easy to recover from.
  1618.         //
  1619.         if (fReaderMgr->skippedChar(chCloseSquare)
  1620.         &&  fReaderMgr->skippedChar(chCloseAngle))
  1621.         {
  1622.             fScanner->emitError(XMLErrs::ExtraCloseSquare);
  1623.         }
  1624.          else
  1625.         {
  1626.             fScanner->emitError(XMLErrs::UnterminatedDOCTYPE);
  1627.             fReaderMgr->skipPastChar(chCloseAngle);
  1628.         }
  1629.     }
  1630.     //
  1631.     //  If we had an external subset, then we need to deal with that one
  1632.     //  next. If we are reusing the validator, then don't scan it.
  1633.     //
  1634.     if (hasExtSubset && !reuseGrammar)
  1635.     {
  1636.         // Indicate we are in the external subset now
  1637.         FlagJanitor<bool> janContentFlag(&fInternalSubset, false);
  1638.         // And now create a reader to read this entity
  1639.         InputSource* srcUsed;
  1640.         XMLReader* reader = fReaderMgr->createReader
  1641.         (
  1642.             sysId
  1643.             , pubId
  1644.             , false
  1645.             , XMLReader::RefFrom_NonLiteral
  1646.             , XMLReader::Type_General
  1647.             , XMLReader::Source_External
  1648.             , srcUsed
  1649.         );
  1650.         // Put a janitor on the input source
  1651.         Janitor<InputSource> janSrc(srcUsed);
  1652.         //
  1653.         //  If it failed then throw an exception
  1654.         //
  1655.         if (!reader)
  1656.             ThrowXML1(RuntimeException, XMLExcepts::Gen_CouldNotOpenDTD, srcUsed->getSystemId());
  1657.         //
  1658.         //  In order to make the processing work consistently, we have to
  1659.         //  make this look like an external entity. So create an entity
  1660.         //  decl and fill it in and push it with the reader, as happens
  1661.         //  with an external entity. Put a janitor on it to insure it gets
  1662.         //  cleaned up. The reader manager does not adopt them.
  1663.         //
  1664.         const XMLCh gDTDStr[] = { chLatin_D, chLatin_T, chLatin_D , chNull };
  1665.         DTDEntityDecl* declDTD = new DTDEntityDecl(gDTDStr);
  1666.         declDTD->setSystemId(sysId);
  1667.         Janitor<DTDEntityDecl> janDecl(declDTD);
  1668.         // Mark this one as a throw at end
  1669.         reader->setThrowAtEnd(true);
  1670.         // And push it onto the stack, with its pseudo name
  1671.         fReaderMgr->pushReader(reader, declDTD);
  1672.         // Tell it its not in an include section
  1673.         scanExtSubsetDecl(false);
  1674.     }
  1675. }
  1676. //
  1677. //  This is called after seeing '<!ELEMENT' which indicates that an element
  1678. //  markup is starting. This guy scans the rest of it and adds it to the
  1679. //  element decl pool if it has not already been declared.
  1680. //
  1681. void DTDScanner::scanElementDecl()
  1682. {
  1683.     //
  1684.     //  Space is legal (required actually) here so check for a PE ref. If
  1685.     //  we don't get our whitespace, then issue and error, but try to keep
  1686.     //  going.
  1687.     //
  1688.     if (!checkForPERef(true, false, true))
  1689.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  1690.     // Get a buffer for the element name and scan in the name
  1691.     XMLBufBid bbName(fBufMgr);
  1692.     if (!fReaderMgr->getName(bbName.getBuffer()))
  1693.     {
  1694.         fScanner->emitError(XMLErrs::ExpectedElementName);
  1695.         fReaderMgr->skipPastChar(chCloseAngle);
  1696.         return;
  1697.     }
  1698.     // Look this guy up in the element decl pool
  1699.     DTDElementDecl* decl = (DTDElementDecl*) fDTDGrammar->getElemDecl(fEmptyNamespaceId, 0, bbName.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE);
  1700.     //
  1701.     //  If it does not exist, then we need to create it. If it does and
  1702.     //  its marked as declared, then that's an error, but we still need to
  1703.     //  scan over the content model so use the dummy declaration that the
  1704.     //  parsing code can fill in.
  1705.     //
  1706.     if (decl)
  1707.     {
  1708.         if (decl->isDeclared())
  1709.         {
  1710.             if (fScanner->getDoValidation())
  1711.                 fScanner->getValidator()->emitError(XMLValid::ElementAlreadyExists, bbName.getRawBuffer());
  1712.             if (!fDumElemDecl)
  1713.                 fDumElemDecl = new DTDElementDecl(bbName.getRawBuffer(), fEmptyNamespaceId);
  1714.             else
  1715.                 fDumElemDecl->setElementName(bbName.getRawBuffer(),fEmptyNamespaceId);
  1716.         }
  1717.     }
  1718.      else
  1719.     {
  1720.         //
  1721.         //  Create the new empty declaration to fill in and put it into
  1722.         //  the decl pool.
  1723.         //
  1724.         decl = new DTDElementDecl(bbName.getRawBuffer(), fEmptyNamespaceId);
  1725.         fDTDGrammar->putElemDecl(decl);
  1726.     }
  1727.     // Set a flag for whether we will ignore this one
  1728.     const bool isIgnored = (decl == fDumElemDecl);
  1729.     // Mark this one if being externally declared
  1730.     decl->setExternalElemDeclaration(isReadingExternalEntity());
  1731.     // Mark this one as being declared
  1732.     decl->setCreateReason(XMLElementDecl::Declared);
  1733.     // Another check for a PE ref, with at least required whitespace
  1734.     if (!checkForPERef(true, false, true))
  1735.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  1736.     // And now scan the content model for this guy.
  1737.     if (!scanContentSpec(*decl))
  1738.     {
  1739.         fReaderMgr->skipPastChar(chCloseAngle);
  1740.         return;
  1741.     }
  1742.     // Another check for a PE ref, but we don't require whitespace here
  1743.     checkForPERef(false, false, true);
  1744.     // And we should have the ending angle bracket
  1745.     if (!fReaderMgr->skippedChar(chCloseAngle))
  1746.     {
  1747.         fScanner->emitError(XMLErrs::UnterminatedElementDecl, bbName.getRawBuffer());
  1748.         fReaderMgr->skipPastChar(chCloseAngle);
  1749.     }
  1750.     //
  1751.     //  If we have a DTD handler tell it about the new element decl. We
  1752.     //  tell it if its one that can be ignored, cause its an override of a
  1753.     //  previously existing decl. If it is being ignored, only call back
  1754.     //  if advanced callbacks are enabled.
  1755.     //
  1756.     if (fDocTypeHandler)
  1757.         fDocTypeHandler->elementDecl(*decl, isIgnored);
  1758. }
  1759. //
  1760. //  This method will process a general or parameter entity reference. The
  1761. //  entity name and entity text will be stored in the entity pool. The value
  1762. //  of the entity will be scanned for any other parameter entity or char
  1763. //  references which will be expanded. So the stored value can only have
  1764. //  general entity references when done.
  1765. //
  1766. void DTDScanner::scanEntityDecl()
  1767. {
  1768.     //
  1769.     //  Space is required here, but we cannot check for a PE Ref since
  1770.     //  there could be a legal (no-ref) percent sign here. Since any
  1771.     //  entity that ended here would be illegal, we just skip spaces
  1772.     //  and then check for a percent.
  1773.     //
  1774.     if (!fReaderMgr->lookingAtSpace())
  1775.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  1776.     else
  1777.         fReaderMgr->skipPastSpaces();
  1778.     const bool isPEDecl = fReaderMgr->skippedChar(chPercent);
  1779.     //
  1780.     //  If a PE decl, then eat the percent and check for spaces or a
  1781.     //  PE ref on the other side of it. At least spaces are required.
  1782.     //
  1783.     if (isPEDecl)
  1784.     {
  1785.         if (!checkForPERef(true, false, true))
  1786.             fScanner->emitError(XMLErrs::ExpectedWhitespace);
  1787.     }
  1788.     //
  1789.     //  Now lets get a name, which should be the name of the entity. We
  1790.     //  have to get a buffer for this.
  1791.     //
  1792.     XMLBufBid bbName(fBufMgr);
  1793.     if (!fReaderMgr->getName(bbName.getBuffer()))
  1794.     {
  1795.         fScanner->emitError(XMLErrs::ExpectedPEName);
  1796.         fReaderMgr->skipPastChar(chCloseAngle);
  1797.         return;
  1798.     }
  1799.     // If namespaces are enabled, then no colons allowed
  1800.     if (fScanner->getDoNamespaces())
  1801.     {
  1802.         if (XMLString::indexOf(bbName.getRawBuffer(), chColon) != -1)
  1803.             fScanner->emitError(XMLErrs::ColonNotLegalWithNS);
  1804.     }
  1805.     //
  1806.     //  See if this entity already exists. If so, then the existing one
  1807.     //  takes precendence. So we use the local dummy decl to parse into
  1808.     //  and just ignore the results.
  1809.     //
  1810.     DTDEntityDecl* entityDecl;
  1811.     if (isPEDecl)
  1812.         entityDecl = fPEntityDeclPool->getByKey(bbName.getRawBuffer());
  1813.     else
  1814.         entityDecl = fEntityDeclPool->getByKey(bbName.getRawBuffer());
  1815.     if (entityDecl)
  1816.     {
  1817.         if (!fDumEntityDecl)
  1818.             fDumEntityDecl = new DTDEntityDecl;
  1819.         fDumEntityDecl->setName(bbName.getRawBuffer());
  1820.         entityDecl = fDumEntityDecl;
  1821.     }
  1822.      else
  1823.     {
  1824.         // Its not in existence already, then create an entity decl for it
  1825.         entityDecl = new DTDEntityDecl(bbName.getRawBuffer());
  1826.         //
  1827.         //  Set the declaration location. The parameter indicates whether its
  1828.         //  declared in the content/internal subset, so we know whether or not
  1829.         //  its in the external subset.
  1830.         //
  1831.         entityDecl->setDeclaredInIntSubset(fInternalSubset);
  1832.         // Add it to the appropriate entity decl pool
  1833.         if (isPEDecl)
  1834.             fPEntityDeclPool->put(entityDecl);
  1835.          else
  1836.             fEntityDeclPool->put(entityDecl);
  1837.     }
  1838.     // Set a flag that indicates whether we are ignoring this one
  1839.     const bool isIgnored = (entityDecl == fDumEntityDecl);
  1840.     // Set the PE flag on it
  1841.     entityDecl->setIsParameter(isPEDecl);
  1842.     //
  1843.     //  Space is legal (required actually) here so check for a PE ref. If
  1844.     //  we don't get our whitespace, then issue an error, but try to keep
  1845.     //  going.
  1846.     //
  1847.     if (!checkForPERef(true, false, true))
  1848.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  1849.     // save the hasNoDTD status for Entity Constraint Checking
  1850.     bool hasNoDTD = fScanner->getHasNoDTD();
  1851.     if (hasNoDTD && isPEDecl)
  1852.         fScanner->setHasNoDTD(false);
  1853.     // According to the type call the value scanning method
  1854.     if (!scanEntityDef(*entityDecl, isPEDecl))
  1855.     {
  1856.         fReaderMgr->skipPastChar(chCloseAngle);
  1857.         fScanner->setHasNoDTD(true);
  1858.         fScanner->emitError(XMLErrs::ExpectedEntityValue);
  1859.         return;
  1860.     }
  1861.     if (hasNoDTD)
  1862.         fScanner->setHasNoDTD(true);
  1863.     // Space is legal (but not required) here so check for a PE ref
  1864.     checkForPERef(false, false, true);
  1865.     // And then we have to have the closing angle bracket
  1866.     if (!fReaderMgr->skippedChar(chCloseAngle))
  1867.     {
  1868.         fScanner->emitError(XMLErrs::UnterminatedEntityDecl, entityDecl->getName());
  1869.         fReaderMgr->skipPastChar(chCloseAngle);
  1870.     }
  1871.     //
  1872.     //  If we have a doc type handler, then call it. But only call it for
  1873.     //  ignored elements if advanced callbacks are enabled.
  1874.     //
  1875.     if (fDocTypeHandler)
  1876.         fDocTypeHandler->entityDecl(*entityDecl, isPEDecl, isIgnored);
  1877. }
  1878. //
  1879. //  This method will scan a general/character entity ref. It will either
  1880. //  expand a char ref and return the value directly, or it will expand
  1881. //  a general entity and a reader for it onto the reader stack.
  1882. //
  1883. //  The return value indicates whether the value was returned directly or
  1884. //  pushed as a reader or it failed.
  1885. //
  1886. //  The escaped flag tells the caller whether the returnd parameter resulted
  1887. //  from a character reference, which escapes the character in some cases. It
  1888. //  only makes any difference if the return indicates the value was returned
  1889. //  directly.
  1890. //
  1891. //  NOTE: This is only called when scanning attribute values, so we always
  1892. //  expand general entities.
  1893. //
  1894. DTDScanner::EntityExpRes
  1895. DTDScanner::scanEntityRef(XMLCh& firstCh, XMLCh& secondCh, bool& escaped)
  1896. {
  1897.     // Assume no escape and no second char
  1898.     escaped = false;
  1899.     secondCh = 0;
  1900.     // We have to insure its all done in a single entity
  1901.     const unsigned int curReader = fReaderMgr->getCurrentReaderNum();
  1902.     //
  1903.     //  If the next char is a pound, then its a character reference and we
  1904.     //  need to expand it always.
  1905.     //
  1906.     if (fReaderMgr->skippedChar(chPound))
  1907.     {
  1908.         //
  1909.         //  Its a character reference, so scan it and get back the numeric
  1910.         //  value it represents. If it fails, just return immediately.
  1911.         //
  1912.         if (!scanCharRef(firstCh, secondCh))
  1913.             return EntityExp_Failed;
  1914.         if (curReader != fReaderMgr->getCurrentReaderNum())
  1915.             fScanner->emitError(XMLErrs::PartialMarkupInEntity);
  1916.         // Its now escaped since it was a char ref
  1917.         escaped = true;
  1918.         return EntityExp_Returned;
  1919.     }
  1920.     // Get the name of the general entity
  1921.     XMLBufBid bbName(fBufMgr);
  1922.     if (!fReaderMgr->getName(bbName.getBuffer()))
  1923.     {
  1924.         fScanner->emitError(XMLErrs::ExpectedEntityRefName);
  1925.         return EntityExp_Failed;
  1926.     }
  1927.     //
  1928.     //  Next char must be a semi-colon. But if its not, just emit
  1929.     //  an error and try to continue.
  1930.     //
  1931.     if (!fReaderMgr->skippedChar(chSemiColon))
  1932.         fScanner->emitError(XMLErrs::UnterminatedEntityRef, bbName.getRawBuffer());
  1933.     // Make sure it was all in one entity reader
  1934.     if (curReader != fReaderMgr->getCurrentReaderNum())
  1935.         fScanner->emitError(XMLErrs::PartialMarkupInEntity);
  1936.     // Look it up the name the general entity pool
  1937.     XMLEntityDecl* decl = fEntityDeclPool->getByKey(bbName.getRawBuffer());
  1938.     // If it does not exist, then obviously an error
  1939.     if (!decl)
  1940.     {
  1941.         // XML 1.0 Section 4.1
  1942.         if (fScanner->getStandalone() || fScanner->getHasNoDTD()) {
  1943.             fScanner->emitError(XMLErrs::EntityNotFound, bbName.getRawBuffer());
  1944.         }
  1945.         else {
  1946.             if (fScanner->getDoValidation())
  1947.                 fScanner->getValidator()->emitError(XMLValid::VC_EntityNotFound, bbName.getRawBuffer());
  1948.         }
  1949.         return EntityExp_Failed;
  1950.     }
  1951.     //
  1952.     //  If we are a standalone document, then it has to have been declared
  1953.     //  in the internal subset. Keep going though.
  1954.     //
  1955.     if (fScanner->getDoValidation() && fScanner->getStandalone() && !decl->getDeclaredInIntSubset())
  1956.         fScanner->getValidator()->emitError(XMLValid::IllegalRefInStandalone, bbName.getRawBuffer());
  1957.     //
  1958.     //  If its a special char reference, then its escaped and we can return
  1959.     //  it directly.
  1960.     //
  1961.     if (decl->getIsSpecialChar())
  1962.     {
  1963.         firstCh = decl->getValue()[0];
  1964.         escaped = true;
  1965.         return EntityExp_Returned;
  1966.     }
  1967.     if (decl->isExternal())
  1968.     {
  1969.         // If its unparsed, then its not valid here
  1970.         // XML 1.0 Section 4.4.4 the appearance of a reference to an unparsed entity is forbidden.
  1971.         if (decl->isUnparsed())
  1972.         {
  1973.             fScanner->emitError(XMLErrs::NoUnparsedEntityRefs, bbName.getRawBuffer());
  1974.             return EntityExp_Failed;
  1975.         }
  1976.         // We are in an attribute value, so not valid.
  1977.         // XML 1.0 Section 4.4.4 a reference to an external entity in an attribute value is forbidden.
  1978.         fScanner->emitError(XMLErrs::NoExtRefsInAttValue);
  1979.         // And now create a reader to read this entity
  1980.         InputSource* srcUsed;
  1981.         XMLReader* reader = fReaderMgr->createReader
  1982.         (
  1983.             decl->getSystemId()
  1984.             , decl->getPublicId()
  1985.             , false
  1986.             , XMLReader::RefFrom_NonLiteral
  1987.             , XMLReader::Type_General
  1988.             , XMLReader::Source_External
  1989.             , srcUsed
  1990.         );
  1991.         // Put a janitor on the source so it gets cleaned up on exit
  1992.         Janitor<InputSource> janSrc(srcUsed);
  1993.         //
  1994.         //  If the creation failed then throw an exception
  1995.         //
  1996.         if (!reader)
  1997.             ThrowXML1(RuntimeException, XMLExcepts::Gen_CouldNotOpenExtEntity, srcUsed->getSystemId());
  1998.         //
  1999.         //  Push the reader. If its a recursive expansion, then emit an error
  2000.         //  and return an failure.
  2001.         //
  2002.         if (!fReaderMgr->pushReader(reader, decl))
  2003.         {
  2004.             fScanner->emitError(XMLErrs::RecursiveEntity, decl->getName());
  2005.             return EntityExp_Failed;
  2006.         }
  2007.         // If it starts with the XML string, then parse a text decl
  2008.         if (fScanner->checkXMLDecl(true))
  2009.             scanTextDecl();
  2010.     }
  2011.      else
  2012.     {
  2013.         //
  2014.         //  Create a reader over a memory stream over the entity value
  2015.         //  We force it to assume UTF-16 by passing in an encoding
  2016.         //  string. This way it won't both trying to predecode the
  2017.         //  first line, looking for an XML/TextDecl.
  2018.         //
  2019.         XMLReader* valueReader = fReaderMgr->createIntEntReader
  2020.         (
  2021.             decl->getName()
  2022.             , XMLReader::RefFrom_NonLiteral
  2023.             , XMLReader::Type_General
  2024.             , decl->getValue()
  2025.             , decl->getValueLen()
  2026.             , false
  2027.         );
  2028.         //
  2029.         //  Trt to push the entity reader onto the reader manager stack,
  2030.         //  where it will become the subsequent input. If it fails, that
  2031.         //  means the entity is recursive, so issue an error. The reader
  2032.         //  will have just been discarded, but we just keep going.
  2033.         //
  2034.         if (!fReaderMgr->pushReader(valueReader, decl))
  2035.             fScanner->emitError(XMLErrs::RecursiveEntity, decl->getName());
  2036.     }
  2037.     return EntityExp_Pushed;
  2038. }
  2039. //
  2040. //  This method will scan a quoted literal of an entity value. It has to
  2041. //  deal with replacement of PE references; however, since this is a DTD
  2042. //  scanner, all such entity literals are in entity decls and therefore
  2043. //  general entities are not expanded.
  2044. //
  2045. bool DTDScanner::scanEntityLiteral(XMLBuffer& toFill, const bool isPE)
  2046. {
  2047.     toFill.reset();
  2048.     // Get the next char which must be a single or double quote
  2049.     XMLCh quoteCh;
  2050.     if (!fReaderMgr->skipIfQuote(quoteCh))
  2051.         return false;
  2052.     // Get a buffer for pulling in entity names when we see GE refs
  2053.     XMLBufBid bbName(fBufMgr);
  2054.     XMLBuffer& nameBuf = bbName.getBuffer();
  2055.     // Remember the current reader
  2056.     const unsigned int orgReader = fReaderMgr->getCurrentReaderNum();
  2057.     //
  2058.     //  Loop until we see the ending quote character, handling any references
  2059.     //  in the process.
  2060.     //
  2061.     XMLCh   nextCh;
  2062.     XMLCh   secondCh = 0;
  2063.     bool    gotLeadingSurrogate = false;
  2064.     while (true)
  2065.     {
  2066.         // Get the second char if we have one, else get another
  2067.         if (secondCh)
  2068.         {
  2069.             nextCh = secondCh;
  2070.             secondCh = 0;
  2071.         }
  2072.          else
  2073.         {
  2074.             nextCh = fReaderMgr->getNextChar();
  2075.         }
  2076.         //
  2077.         //  Watch specifically for EOF and issue a more meaningful error
  2078.         //  if that occurs (since an unterminated quoted char can cause
  2079.         //  this easily.)
  2080.         //
  2081.         if (!nextCh)
  2082.         {
  2083.             fScanner->emitError(XMLErrs::UnterminatedEntityLiteral);
  2084.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  2085.         }
  2086.         //
  2087.         //  Break out on our terminating quote char when we are back in the
  2088.         //  same reader. Otherwise, we might trigger on a nested quote char
  2089.         //  in an expanded entity.
  2090.         //
  2091.         if ((nextCh == quoteCh)
  2092.         &&  (fReaderMgr->getCurrentReaderNum() == orgReader))
  2093.         {
  2094.             break;
  2095.         }
  2096.         if (nextCh == chPercent)
  2097.         {
  2098.             //
  2099.             //  Put the PE's value on the reader stack and then jump back
  2100.             //  to the top to start processing it. The parameter indicates
  2101.             //  that it should not scan the reference's content as an external
  2102.             //  subset.
  2103.             //
  2104.             expandPERef(false, true, true);
  2105.             continue;
  2106.         }
  2107.         //
  2108.         //  Ok, now that all the other special stuff is checked, we can
  2109.         //  look for a general entity. In here, we cannot have a naked &
  2110.         //  and will only expand numerical char refs or the intrinsic char
  2111.         //  refs. Others will be left alone.
  2112.         //
  2113.         if (nextCh == chAmpersand)
  2114.         {
  2115.             //
  2116.             //  Here, we only expand numeric char refs, but not any general
  2117.             //  entities. However, the stupid XML spec requires that we check
  2118.             //  and make sure it does refer to a general entity if its not
  2119.             //  a char ref (i.e. no naked '&' chars.)
  2120.             //
  2121.             if (fReaderMgr->skippedChar(chPound))
  2122.             {
  2123.                 // If it failed, then just jump back to the top and try to pick up
  2124.                 if (!scanCharRef(nextCh, secondCh))
  2125.                 {
  2126.                     gotLeadingSurrogate = false;
  2127.                     continue;
  2128.                 }
  2129.             }
  2130.              else
  2131.             {
  2132.                 if (!fReaderMgr->getName(nameBuf))
  2133.                 {
  2134.                     fScanner->emitError(XMLErrs::ExpectedEntityRefName);
  2135.                 }
  2136.                  else
  2137.                 {
  2138.                     //
  2139.                     //  Since we are not expanding any of this, we have to
  2140.                     //  put the amp and name into the target buffer as data.
  2141.                     //
  2142.                     toFill.append(chAmpersand);
  2143.                     toFill.append(nameBuf.getRawBuffer());
  2144.                     // Make sure we skipped a trailing semicolon
  2145.                     if (!fReaderMgr->skippedChar(chSemiColon))
  2146.                     {
  2147.                         fScanner->emitError
  2148.                         (
  2149.                             XMLErrs::UnterminatedEntityRef
  2150.                             , nameBuf.getRawBuffer()
  2151.                         );
  2152.                     }
  2153.                     // And make the new character the semicolon
  2154.                     nextCh = chSemiColon;
  2155.                 }
  2156.                 // Either way here we reset the surrogate flag
  2157.                 gotLeadingSurrogate = false;
  2158.             }
  2159.         }
  2160.         if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
  2161.         {
  2162.             if (gotLeadingSurrogate)
  2163.                 fScanner->emitError(XMLErrs::Expected2ndSurrogateChar);
  2164.             else
  2165.                 gotLeadingSurrogate = true;
  2166.         }
  2167.          else
  2168.         {
  2169.             if (gotLeadingSurrogate)
  2170.             {
  2171.                 if ((nextCh < 0xDC00) && (nextCh > 0xDFFF))
  2172.                     fScanner->emitError(XMLErrs::Expected2ndSurrogateChar);
  2173.             }
  2174.              else if (!XMLReader::isXMLChar(nextCh))
  2175.             {
  2176.                 XMLCh tmpBuf[9];
  2177.                 XMLString::binToText
  2178.                 (
  2179.                     nextCh
  2180.                     , tmpBuf
  2181.                     , 8
  2182.                     , 16
  2183.                 );
  2184.                 fScanner->emitError(XMLErrs::InvalidCharacter, tmpBuf);
  2185.                 fReaderMgr->skipPastChar(quoteCh);
  2186.                 return false;
  2187.             }
  2188.             gotLeadingSurrogate = false;
  2189.         }
  2190.         // Looks ok, so add it to the literal
  2191.         toFill.append(nextCh);
  2192.     }
  2193.     //
  2194.     //  If we got here and did not get back to the original reader level,
  2195.     //  then we propogated some entity out of the literal, so issue an
  2196.     //  error, but don't fail.
  2197.     //
  2198.     if (fReaderMgr->getCurrentReaderNum() != orgReader && fScanner->getDoValidation())
  2199.         fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE);
  2200.     return true;
  2201. }
  2202. //
  2203. //  This method is called after the entity name has been scanned, and any
  2204. //  PE referenced following the name is handled. The passed decl will be
  2205. //  filled in with the info scanned.
  2206. //
  2207. bool DTDScanner::scanEntityDef(DTDEntityDecl& decl, const bool isPEDecl)
  2208. {
  2209.     // Its got to be an entity literal
  2210.     if (fReaderMgr->lookingAtChar(chSingleQuote)
  2211.     ||  fReaderMgr->lookingAtChar(chDoubleQuote))
  2212.     {
  2213.         // Get a buffer for the literal
  2214.         XMLBufBid bbValue(fBufMgr);
  2215.         if (!scanEntityLiteral(bbValue.getBuffer(), isPEDecl))
  2216.             return false;
  2217.         // Set it on the entity decl
  2218.         decl.setValue(bbValue.getRawBuffer());
  2219.         return true;
  2220.     }
  2221.     //
  2222.     //  Its got to be an external entity, so there must be an external id.
  2223.     //  Get buffers for them and scan an external id into them.
  2224.     //
  2225.     XMLBufBid bbPubId(fBufMgr);
  2226.     XMLBufBid bbSysId(fBufMgr);
  2227.     if (!scanId(bbPubId.getBuffer(), bbSysId.getBuffer(), IDType_External))
  2228.         return false;
  2229.     // Fill in the id fields of the decl with the info we got
  2230.     decl.setPublicId(bbPubId.getRawBuffer());
  2231.     decl.setSystemId(bbSysId.getRawBuffer());
  2232.     // If its a PE decl, we are done
  2233.     bool gotSpaces = checkForPERef(false, false, true);
  2234.     if (isPEDecl)
  2235.     {
  2236.         //
  2237.         //  Check for a common error here. NDATA is not allowed for PEs
  2238.         //  so check for the NDATA string. If found give a nice meaningful
  2239.         //  error and continue parsing to eat the NDATA text.
  2240.         //
  2241.         if (gotSpaces)
  2242.         {
  2243.             if (fReaderMgr->skippedString(XMLUni::fgNDATAString))
  2244.                 fScanner->emitError(XMLErrs::NDATANotValidForPE);
  2245.         }
  2246.          else
  2247.         {
  2248.             return true;
  2249.         }
  2250.     }
  2251.     // If looking at close angle now, we are done
  2252.     if (fReaderMgr->lookingAtChar(chCloseAngle))
  2253.         return true;
  2254.     // Else we had to have seem the whitespace
  2255.     if (!gotSpaces)
  2256.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  2257.     // We now have to see a notation data string
  2258.     if (!fReaderMgr->skippedString(XMLUni::fgNDATAString))
  2259.         fScanner->emitError(XMLErrs::ExpectedNDATA);
  2260.     // Space is required here, but try to go on if not
  2261.     if (!checkForPERef(false, false, true))
  2262.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  2263.     // Get a name
  2264.     XMLBufBid bbName(fBufMgr);
  2265.     if (!fReaderMgr->getName(bbName.getBuffer()))
  2266.     {
  2267.         fScanner->emitError(XMLErrs::ExpectedNotationName);
  2268.         return false;
  2269.     }
  2270.     // Set the decl's notation name
  2271.     decl.setNotationName(bbName.getRawBuffer());
  2272.     return true;
  2273. }
  2274. //
  2275. //  This method is called after an attribute decl name or a notation decl has
  2276. //  been scanned and then an opening parenthesis was see, indicating the list
  2277. //  of values. It scans the enumeration values and creates a single string
  2278. //  which has a single space between each value.
  2279. //
  2280. //  The terminating close paren ends this scan.
  2281. //
  2282. bool DTDScanner::scanEnumeration( const   DTDAttDef&  attDef
  2283.                                     ,       XMLBuffer&  toFill
  2284.                                     , const bool        notation)
  2285. {
  2286.     // Reset the passed buffer
  2287.     toFill.reset();
  2288.     // Check for PE ref but don't require space
  2289.     checkForPERef(false, false, true);
  2290.     // If this is a notation, we need an opening paren
  2291.     if (notation)
  2292.     {
  2293.         if (!fReaderMgr->skippedChar(chOpenParen))
  2294.             fScanner->emitError(XMLErrs::ExpectedOpenParen);
  2295.     }
  2296.     // We need a local buffer to use as well
  2297.     XMLBufBid bbTmp(fBufMgr);
  2298.     while (true)
  2299.     {
  2300.         // Space is allowed here for either type so check for PE ref
  2301.         checkForPERef(false, false, true);
  2302.         // And then get either a name or a name token
  2303.         bool success;
  2304.         if (notation)
  2305.             success = fReaderMgr->getName(bbTmp.getBuffer());
  2306.         else
  2307.             success = fReaderMgr->getNameToken(bbTmp.getBuffer());
  2308.         if (!success)
  2309.         {
  2310.             fScanner->emitError
  2311.             (
  2312.                 XMLErrs::ExpectedEnumValue
  2313.                 , attDef.getFullName()
  2314.             );
  2315.             return false;
  2316.         }
  2317.         // Append this value to the target value
  2318.         toFill.append(bbTmp.getRawBuffer(), bbTmp.getLen());
  2319.         // Space is allowed here for either type so check for PE ref
  2320.         checkForPERef(false, false, true);
  2321.         // Check for the terminating paren
  2322.         if (fReaderMgr->skippedChar(chCloseParen))
  2323.             break;
  2324.         // And append a space separator
  2325.         toFill.append(chSpace);
  2326.         // Check for the pipe character separator
  2327.         if (!fReaderMgr->skippedChar(chPipe))
  2328.         {
  2329.             fScanner->emitError(XMLErrs::ExpectedEnumSepOrParen);
  2330.             return false;
  2331.         }
  2332.     }
  2333.     return true;
  2334. }
  2335. bool DTDScanner::scanEq()
  2336. {
  2337.     fReaderMgr->skipPastSpaces();
  2338.     if (fReaderMgr->skippedChar(chEqual))
  2339.     {
  2340.         fReaderMgr->skipPastSpaces();
  2341.         return true;
  2342.     }
  2343.     return false;
  2344. }
  2345. //
  2346. //  This method is called when an external entity reference is seen in the
  2347. //  DTD or an external DTD subset is encountered, and their contents pushed
  2348. //  onto the reader stack. This method will scan that contents.
  2349. //
  2350. void DTDScanner::scanExtSubsetDecl(const bool inIncludeSect)
  2351. {
  2352.     bool bAcceptDecl = !inIncludeSect;
  2353.     // Get a buffer for whitespace
  2354.     XMLBufBid bbSpace(fBufMgr);
  2355.     //
  2356.     //  If we have a doc type handler and we are not being called recursively
  2357.     //  to handle an include section, tell it the ext subset starts
  2358.     //
  2359.     if (fDocTypeHandler && !inIncludeSect)
  2360.         fDocTypeHandler->startExtSubset();
  2361.     //
  2362.     //  We have to play a trick here if the current entity we are parsing
  2363.     //  is a PE. Because the spooling code will put out a whitespace before
  2364.     //  and after an expanded PE if its being scanned outside the context of
  2365.     //  a literal entity, this will confuse this external subset code.
  2366.     //
  2367.     //  So, we see if that is what is happening and, if so, eat the single
  2368.     //  space, a check for the <?xml string. If we find it, we parse that
  2369.     //  markup right now and put the space back.
  2370.     //
  2371.     if (fReaderMgr->isScanningPERefOutOfLiteral())
  2372.     {
  2373.         if (fReaderMgr->skippedSpace())
  2374.         {
  2375.             if (fScanner->checkXMLDecl(true))
  2376.             {
  2377.                 scanTextDecl();
  2378.                 bAcceptDecl = false;
  2379.                 // <TBD> Figure out how to do this
  2380.                 // fReaderMgr->unGet(chSpace);
  2381.             }
  2382.         }
  2383.     }
  2384.     // Get the current reader number
  2385.     const unsigned int orgReader = fReaderMgr->getCurrentReaderNum();
  2386.     //
  2387.     //  Loop until we hit the end of the external subset entity. Note that
  2388.     //  we use a double loop here in order to avoid the overhead of doing
  2389.     //  the exception setup/teardown work on every loop.
  2390.     //
  2391.     bool inMarkup = false;
  2392.     bool inCharData = false;
  2393.     while (true)
  2394.     {
  2395.     try
  2396.     {
  2397.         while (true)
  2398.         {
  2399.             const XMLCh nextCh = fReaderMgr->peekNextChar();
  2400.             if (nextCh == chOpenAngle)
  2401.             {
  2402.                 // Get the reader we started this on
  2403.                 const unsigned int orgReader = fReaderMgr->getCurrentReaderNum();
  2404.                 //
  2405.                 //  Now scan the markup. Set the flag so that we will know that
  2406.                 //  we were in markup if an end of entity exception occurs.
  2407.                 //
  2408.                 fReaderMgr->getNextChar();
  2409.                 inMarkup = true;
  2410.                 scanMarkupDecl(bAcceptDecl);
  2411.                 inMarkup = false;
  2412.                 //
  2413.                 //  And see if we got back to the same level. If not, then its
  2414.                 //  a partial markup error.
  2415.                 //
  2416.                 if (fReaderMgr->getCurrentReaderNum() != orgReader && fScanner->getDoValidation())
  2417.                     fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE);
  2418.             }
  2419.              else if (XMLReader::isWhitespace(nextCh))
  2420.             {
  2421.                 //
  2422.                 //  If we have a doc type handler, and advanced callbacks are
  2423.                 //  enabled, then gather up whitespace and call back. Otherwise
  2424.                 //  just skip whitespaces.
  2425.                 //
  2426.                 if (fDocTypeHandler)
  2427.                 {
  2428.                     inCharData = true;
  2429.                     fReaderMgr->getSpaces(bbSpace.getBuffer());
  2430.                     inCharData = false;
  2431.                     fDocTypeHandler->doctypeWhitespace
  2432.                     (
  2433.                         bbSpace.getRawBuffer()
  2434.                         , bbSpace.getLen()
  2435.                     );
  2436.                 }
  2437.                  else
  2438.                 {
  2439.                     //
  2440.                     //  If we hit an end of entity in the middle of white
  2441.                     //  space, that's fine. We'll just come back in here
  2442.                     //  again on the next round and skip some more.
  2443.                     //
  2444.                     fReaderMgr->skipPastSpaces();
  2445.                 }
  2446.             }
  2447.              else if (nextCh == chPercent)
  2448.             {
  2449.                 //
  2450.                 //  Expand (and scan if external) the reference value. Tell
  2451.                 //  it to throw an end of entity exception at the end of the
  2452.                 //  entity.
  2453.                 //
  2454.                 fReaderMgr->getNextChar();
  2455.                 expandPERef(true, false, false, true);
  2456.             }
  2457.              else if (inIncludeSect && (nextCh == chCloseSquare))
  2458.             {
  2459.                 //
  2460.                 //  Its the end of a conditional include section. So scan it and
  2461.                 //  decrement the include depth counter.
  2462.                 //
  2463.                 fReaderMgr->getNextChar();
  2464.                 if (!fReaderMgr->skippedChar(chCloseSquare))
  2465.                 {
  2466.                     fScanner->emitError(XMLErrs::ExpectedEndOfConditional);
  2467.                     fReaderMgr->skipPastChar(chCloseAngle);
  2468.                 }
  2469.                  else if (!fReaderMgr->skippedChar(chCloseAngle))
  2470.                 {
  2471.                     fScanner->emitError(XMLErrs::ExpectedEndOfConditional);
  2472.                     fReaderMgr->skipPastChar(chCloseAngle);
  2473.                 }
  2474.                 return;
  2475.             }
  2476.              else
  2477.             {
  2478.                 fReaderMgr->getNextChar();
  2479.                 if (!XMLReader::isXMLChar(nextCh))
  2480.                 {
  2481.                     XMLCh tmpBuf[9];
  2482.                     XMLString::binToText
  2483.                     (
  2484.                         nextCh
  2485.                         , tmpBuf
  2486.                         , 8
  2487.                         , 16
  2488.                     );
  2489.                     fScanner->emitError(XMLErrs::InvalidCharacter, tmpBuf);
  2490.                 }
  2491.                  else
  2492.                 {
  2493.                     fScanner->emitError(XMLErrs::InvalidDocumentStructure);
  2494.                 }
  2495.                 // Try to get realigned
  2496.                 static const XMLCh toSkip[] =
  2497.                 {
  2498.                     chPercent, chCloseSquare, chOpenAngle, chNull
  2499.                 };
  2500.                 fReaderMgr->skipUntilInOrWS(toSkip);
  2501.             }
  2502.             bAcceptDecl = false;
  2503.         }
  2504.     }
  2505.     catch(const EndOfEntityException& toCatch)
  2506.     {
  2507.         //
  2508.         //  If the external entity ended while we were in markup, then that's
  2509.         //  a partial markup error.
  2510.         //
  2511.         if (inMarkup)
  2512.         {
  2513.             fScanner->emitError(XMLErrs::PartialMarkupInEntity);
  2514.             inMarkup = false;
  2515.         }
  2516.         // If we were in char data, then send what we got
  2517.         if (inCharData)
  2518.         {
  2519.             // Send what we got, then rethrow
  2520.             if (fDocTypeHandler)
  2521.             {
  2522.                 fDocTypeHandler->doctypeWhitespace
  2523.                 (
  2524.                     bbSpace.getRawBuffer()
  2525.                     , bbSpace.getLen()
  2526.                 );
  2527.             }
  2528.             inCharData = false;
  2529.         }
  2530.         //
  2531.         //  If the entity that just ended was the entity that we started
  2532.         //  on, then this is the end of the external subset.
  2533.         //
  2534.         if (orgReader == toCatch.getReaderNum())
  2535.             break;
  2536.     }
  2537.     }
  2538.     // If we have a doc type handler, tell it the ext subset ends
  2539.     if (fDocTypeHandler)
  2540.         fDocTypeHandler->endExtSubset();
  2541. }
  2542. //
  2543. //  This method will scan for an id, either public or external.
  2544. //
  2545. //
  2546. // [75] ExternalID ::= 'SYSTEM' S SystemLiteral
  2547. //                     | 'PUBLIC' S PubidLiteral S SystemLiteral
  2548. // [83] PublicID ::= 'PUBLIC' S PubidLiteral
  2549. //
  2550. bool DTDScanner::scanId(          XMLBuffer&  pubIdToFill
  2551.                             ,       XMLBuffer&  sysIdToFill
  2552.                             , const IDTypes     whatKind)
  2553. {
  2554.     // Clean out both return buffers
  2555.     pubIdToFill.reset();
  2556.     sysIdToFill.reset();
  2557.     //
  2558.     //  Check first for the system id first. If we find it, and system id
  2559.     //  is one of the legal values, then lets try to scan it.
  2560.     //
  2561.     // 'SYSTEM' S SystemLiteral
  2562.     if (fReaderMgr->skippedString(XMLUni::fgSysIDString))
  2563.     {
  2564.         // If they were looking for a public id, then we failed
  2565.         if (whatKind == IDType_Public)
  2566.         {
  2567.             fScanner->emitError(XMLErrs::ExpectedPublicId);
  2568.             return false;
  2569.         }
  2570.         // We must skip spaces
  2571.         if (!fReaderMgr->skipPastSpaces())
  2572.         {
  2573.             fScanner->emitError(XMLErrs::ExpectedWhitespace);
  2574.             return false;
  2575.         }
  2576.         // Get the system literal value
  2577.         return scanSystemLiteral(sysIdToFill);
  2578.     }
  2579.     // Now scan for public id
  2580.     // 'PUBLIC' S PubidLiteral S SystemLiteral
  2581.     //  or
  2582.     // 'PUBLIC' S PubidLiteral
  2583.     // If we don't have any public id string => Error
  2584.     if (!fReaderMgr->skippedString(XMLUni::fgPubIDString)) {
  2585.         fScanner->emitError(XMLErrs::ExpectedSystemOrPublicId);
  2586.         return false;
  2587.     }
  2588.     //
  2589.     //  So following this we must have whitespace, a public literal, whitespace,
  2590.     //  and a system literal.
  2591.     //
  2592.     if (!fReaderMgr->skipPastSpaces())
  2593.     {
  2594.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  2595.         //
  2596.         //  Just in case, if they just forgot the whitespace but the next char
  2597.         //  is a single or double quote, then keep going.
  2598.         //
  2599.         const XMLCh chPeek = fReaderMgr->peekNextChar();
  2600.         if ((chPeek != chDoubleQuote) && (chPeek != chSingleQuote))
  2601.             return false;
  2602.     }
  2603.     if (!scanPublicLiteral(pubIdToFill))
  2604.         return false;
  2605.     // If they wanted a public id, then this is all
  2606.     if (whatKind == IDType_Public)
  2607.         return true;
  2608.     // check if there is any space follows
  2609.     bool hasSpace = fReaderMgr->skipPastSpaces();
  2610.     //
  2611.     //  In order to recover best here we need to see if
  2612.     //  the next thing is a quote or not
  2613.     //
  2614.     const XMLCh chPeek = fReaderMgr->peekNextChar();
  2615.     const bool bIsQuote =  ((chPeek == chDoubleQuote)
  2616.                          || (chPeek == chSingleQuote));
  2617.     if (!hasSpace)
  2618.     {
  2619.         if (whatKind == IDType_External)
  2620.         {
  2621.             //
  2622.             //  If its an external Id, then we need to see the system id.
  2623.             //  So, emit the error. But, if the next char is a quote, don't
  2624.             //  give up since its probably going to work. The user just
  2625.             //  missed the separating space. Otherwise, fail.
  2626.             //
  2627.             fScanner->emitError(XMLErrs::ExpectedWhitespace);
  2628.             if (!bIsQuote)
  2629.                 return false;
  2630.         }
  2631.          else
  2632.         {
  2633.             //
  2634.             //  We can legally return here. But, if the next char is a quote,
  2635.             //  then that's probably not what was desired, since its probably
  2636.             //  just that space was forgotten and there really is a system
  2637.             //  id to follow.
  2638.             //
  2639.             //  So treat it like missing whitespace if so and keep going.
  2640.             //  Else, just return success.
  2641.             //
  2642.             if (bIsQuote)
  2643.                 fScanner->emitError(XMLErrs::ExpectedWhitespace);
  2644.              else
  2645.                 return true;
  2646.         }
  2647.     }
  2648.     if (bIsQuote) {
  2649.         // there is a quote coming, scan the system literal
  2650.         if (!scanSystemLiteral(sysIdToFill))
  2651.             return false;
  2652.     }
  2653.     else {
  2654.         // no quote, if expecting exteral id, this is an error
  2655.         if (whatKind == IDType_External)
  2656.             fScanner->emitError(XMLErrs::ExpectedQuotedString);
  2657.     }
  2658.     return true;
  2659. }
  2660. //
  2661. //  This method will scan the contents of an ignored section. It assumes that
  2662. //  we already are in the body, i.e. we've seen <![IGNORE[ at this point. So
  2663. //  we have to just scan until we see a matching ]]> closing markup.
  2664. //
  2665. void DTDScanner::scanIgnoredSection()
  2666. {
  2667.     //
  2668.     //  Depth starts at one because we are already in one section and want
  2669.     //  to parse until we hit its end.
  2670.     //
  2671.     unsigned long depth = 1;
  2672.     while (true)
  2673.     {
  2674.         const XMLCh nextCh = fReaderMgr->getNextChar();
  2675.         if (!nextCh)
  2676.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  2677.         if (nextCh == chOpenAngle)
  2678.         {
  2679.             if (fReaderMgr->skippedChar(chBang)
  2680.             &&  fReaderMgr->skippedChar(chOpenSquare))
  2681.             {
  2682.                 depth++;
  2683.             }
  2684.         }
  2685.          else if (nextCh == chCloseSquare)
  2686.         {
  2687.             if (fReaderMgr->skippedChar(chCloseSquare))
  2688.             {
  2689.                 while (fReaderMgr->skippedChar(chCloseSquare))
  2690.                 {
  2691.                     // Do nothing, just skip them
  2692.                 }
  2693.                 if (fReaderMgr->skippedChar(chCloseAngle))
  2694.                 {
  2695.                     depth--;
  2696.                     if (!depth)
  2697.                         break;
  2698.                 }
  2699.             }
  2700.         }
  2701.          else if (!XMLReader::isXMLChar(nextCh))
  2702.         {
  2703.             XMLCh tmpBuf[9];
  2704.             XMLString::binToText
  2705.             (
  2706.                 nextCh
  2707.                 , tmpBuf
  2708.                 , 8
  2709.                 , 16
  2710.             );
  2711.             fScanner->emitError(XMLErrs::InvalidCharacter, tmpBuf);
  2712.         }
  2713.     }
  2714. }
  2715. //
  2716. //  This method scans the entire internal subset. All we can have here is
  2717. //  decl markup, and PE references. The expanded PE references must contain
  2718. //  whole markup, so we don't have to worry about their content at this
  2719. //  level. We just scan them, expand them, push them, and parse their content
  2720. //  right there, via the expandERef() method.
  2721. //
  2722. bool DTDScanner::scanInternalSubset()
  2723. {
  2724.     // If we have a doc type handler, tell it the internal subset starts
  2725.     if (fDocTypeHandler)
  2726.         fDocTypeHandler->startIntSubset();
  2727.     // Get a buffer for whitespace
  2728.     XMLBufBid bbSpace(fBufMgr);
  2729.     bool noErrors = true;
  2730.     while (true)
  2731.     {
  2732.         const XMLCh nextCh = fReaderMgr->peekNextChar();
  2733.         //
  2734.         //  If we get an end of file marker, just unget it and return a
  2735.         //  failure status. The caller will then see the end of file and
  2736.         //  faill out correctly.
  2737.         //
  2738.         if (!nextCh)
  2739.             return false;
  2740.         // Watch for the end of internal subset marker
  2741.         if (nextCh == chCloseSquare)
  2742.         {
  2743.             fReaderMgr->getNextChar();
  2744.             break;
  2745.         }
  2746.         if (nextCh == chPercent)
  2747.         {
  2748.             //
  2749.             //  Expand (and scan if external) the reference value. Tell
  2750.             //  it to set the reader to cause an end of entity exception
  2751.             //  when this reader dies, which is what the scanExtSubset
  2752.             //  method wants (who is called to scan this.)
  2753.             //
  2754.             fReaderMgr->getNextChar();
  2755.             expandPERef(true, false, false, true);
  2756.         }
  2757.          else if (nextCh == chOpenAngle)
  2758.         {
  2759.             // Remember this reader before we start the scan
  2760.             const unsigned int orgReader = fReaderMgr->getCurrentReaderNum();
  2761.             // And scan this markup
  2762.             fReaderMgr->getNextChar();
  2763.             scanMarkupDecl(false);
  2764.             // If we did not get back to entry level, then partial markup
  2765.             if (fReaderMgr->getCurrentReaderNum() != orgReader && fScanner->getDoValidation())
  2766.                 fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE);
  2767.         }
  2768.          else if (XMLReader::isWhitespace(nextCh))
  2769.         {
  2770.             //
  2771.             //  IF we are doing advanced callbacks and have a doc type
  2772.             //  handler, then get the whitespace and call the doc type
  2773.             //  handler with it. Otherwise, just skip whitespace.
  2774.             //
  2775.             if (fDocTypeHandler)
  2776.             {
  2777.                 fReaderMgr->getSpaces(bbSpace.getBuffer());
  2778.                 fDocTypeHandler->doctypeWhitespace
  2779.                 (
  2780.                     bbSpace.getRawBuffer()
  2781.                     , bbSpace.getLen()
  2782.                 );
  2783.             }
  2784.              else
  2785.             {
  2786.                 fReaderMgr->skipPastSpaces();
  2787.             }
  2788.         }
  2789.          else
  2790.         {
  2791.             // Not valid, so emit an error
  2792.             XMLCh tmpBuf[9];
  2793.             XMLString::binToText
  2794.             (
  2795.                 fReaderMgr->getNextChar()
  2796.                 , tmpBuf
  2797.                 , 8
  2798.                 , 16
  2799.             );
  2800.             fScanner->emitError
  2801.             (
  2802.                 XMLErrs::InvalidCharacterInIntSubset
  2803.                 , tmpBuf
  2804.             );
  2805.             //
  2806.             //  If an '>', then probably an abnormally terminated
  2807.             //  internal subset so just return.
  2808.             //
  2809.             if (nextCh == chCloseAngle)
  2810.             {
  2811.                 noErrors = false;
  2812.                 break;
  2813.             }
  2814.             //
  2815.             //  Otherwise, try to sync back up by scanning forward for
  2816.             //  a reasonable start character.
  2817.             //
  2818.             static const XMLCh toSkip[] =
  2819.             {
  2820.                 chPercent, chCloseSquare, chOpenAngle, chNull
  2821.             };
  2822.             fReaderMgr->skipUntilInOrWS(toSkip);
  2823.         }
  2824.     }
  2825.     // If we have a doc type handler, tell it the internal subset ends
  2826.     if (fDocTypeHandler)
  2827.         fDocTypeHandler->endIntSubset();
  2828.     return noErrors;
  2829. }
  2830. //
  2831. //  This method is called once we see a < in the input of an int/ext subset,
  2832. //  which indicates the start of some sort of markup.
  2833. //
  2834. void DTDScanner::scanMarkupDecl(const bool parseTextDecl)
  2835. {
  2836.     //
  2837.     //  We only have two valid first characters here. One is a ! which opens
  2838.     //  some markup decl. The other is a ?, which could begin either a PI
  2839.     //  or a text decl. If parseTextDecl is false, we cannot accept a text
  2840.     //  decl.
  2841.     //
  2842.     const XMLCh nextCh = fReaderMgr->getNextChar();
  2843.     if (nextCh == chBang)
  2844.     {
  2845.         if (fReaderMgr->skippedChar(chDash))
  2846.         {
  2847.             if (fReaderMgr->skippedChar(chDash))
  2848.             {
  2849.                 scanComment();
  2850.             }
  2851.              else
  2852.             {
  2853.                 fScanner->emitError(XMLErrs::CommentsMustStartWith);
  2854.                 fReaderMgr->skipPastChar(chCloseAngle);
  2855.             }
  2856.         }
  2857.          else if (fReaderMgr->skippedChar(chOpenSquare))
  2858.         {
  2859.             //
  2860.             //  Its a conditional section. This is only valid in the external
  2861.             //  subset, so issue an error if we aren't there.
  2862.             //
  2863.             if (fInternalSubset)
  2864.             {
  2865.                 fScanner->emitError(XMLErrs::ConditionalSectInIntSubset);
  2866.                 fReaderMgr->skipPastChar(chCloseAngle);
  2867.                 return;
  2868.             }
  2869.             // A PE ref can happen here, but space is not required
  2870.             checkForPERef(false, false, true);
  2871.             if (fReaderMgr->skippedString(XMLUni::fgIncludeString))
  2872.             {
  2873.                 checkForPERef(false, false, true);
  2874.                 // Check for the following open square bracket
  2875.                 if (!fReaderMgr->skippedChar(chOpenSquare))
  2876.                     fScanner->emitError(XMLErrs::ExpectedINCLUDEBracket);
  2877.                 checkForPERef(false, false, true);
  2878.                 //
  2879.                 //  Recurse back to the ext subset call again, telling it its
  2880.                 //  in an include section.
  2881.                 //
  2882.                 scanExtSubsetDecl(true);
  2883.             }
  2884.              else if (fReaderMgr->skippedString(XMLUni::fgIgnoreString))
  2885.             {
  2886.                 checkForPERef(false, false, true);
  2887.                 // Check for the following open square bracket
  2888.                 if (!fReaderMgr->skippedChar(chOpenSquare))
  2889.                     fScanner->emitError(XMLErrs::ExpectedINCLUDEBracket);
  2890.                 // And scan over the ignored part
  2891.                 scanIgnoredSection();
  2892.             }
  2893.              else
  2894.             {
  2895.                 fScanner->emitError(XMLErrs::ExpectedIncOrIgn);
  2896.                 fReaderMgr->skipPastChar(chCloseAngle);
  2897.             }
  2898.         }
  2899.          else if (fReaderMgr->skippedString(XMLUni::fgAttListString))
  2900.         {
  2901.             scanAttListDecl();
  2902.         }
  2903.          else if (fReaderMgr->skippedString(XMLUni::fgElemString))
  2904.         {
  2905.             scanElementDecl();
  2906.         }
  2907.          else if (fReaderMgr->skippedString(XMLUni::fgEntityString))
  2908.         {
  2909.             scanEntityDecl();
  2910.         }
  2911.          else if (fReaderMgr->skippedString(XMLUni::fgNotationString))
  2912.         {
  2913.             scanNotationDecl();
  2914.         }
  2915.          else
  2916.         {
  2917.             fScanner->emitError(XMLErrs::ExpectedMarkupDecl);
  2918.             fReaderMgr->skipPastChar(chCloseAngle);
  2919.         }
  2920.     }
  2921.      else if (nextCh == chQuestion)
  2922.     {
  2923.         // It could be a PI or the XML declaration. Check for Decl
  2924.         if (fScanner->checkXMLDecl(false))
  2925.         {
  2926.             // If we are not accepting text decls, its an error
  2927.             if (parseTextDecl)
  2928.             {
  2929.                 scanTextDecl();
  2930.             }
  2931.              else
  2932.             {
  2933.                 // Emit the error and skip past this markup
  2934.                 fScanner->emitError(XMLErrs::TextDeclNotLegalHere);
  2935.                 fReaderMgr->skipPastChar(chCloseAngle);
  2936.             }
  2937.         }
  2938.          else
  2939.         {
  2940.             // It has to be a PI
  2941.             scanPI();
  2942.         }
  2943.     }
  2944.      else
  2945.     {
  2946.         // Can't be valid so emit error and try to skip past end of this decl
  2947.         fScanner->emitError(XMLErrs::ExpectedMarkupDecl);
  2948.         fReaderMgr->skipPastChar(chCloseAngle);
  2949.     }
  2950. }
  2951. //
  2952. //  This method is called for a mixed model element's content mode. We've
  2953. //  already scanned past the '(PCDATA' part by the time we get here. So
  2954. //  everything else is element names separated by | characters until we
  2955. //  hit the end. The passed element decl's content model is filled in with
  2956. //  the information found.
  2957. //
  2958. bool DTDScanner::scanMixed(DTDElementDecl& toFill)
  2959. {
  2960.     //
  2961.     //  The terminating star is only required if there is something more
  2962.     //  than (PCDATA).
  2963.     //
  2964.     bool starRequired = false;
  2965.     // Get a buffer to be used below to get element names
  2966.     XMLBufBid bbName(fBufMgr);
  2967.     XMLBuffer& nameBuf = bbName.getBuffer();
  2968.     //
  2969.     //  Create an initial content spec node. Its just a leaf node with a
  2970.     //  PCDATA element id. This current node pointer will be pushed down the
  2971.     //  tree as we go.
  2972.     //
  2973.     ContentSpecNode* curNode =
  2974.                  new ContentSpecNode(new QName(XMLUni::fgZeroLenString,
  2975.                                                XMLUni::fgZeroLenString,
  2976.                                                XMLElementDecl::fgPCDataElemId),
  2977.                                      false);
  2978.     //
  2979.     //  Set the initial leaf as the temporary head. If we hit the first choice
  2980.     //  node, it will be set up here. When done, this is the node that's set
  2981.     //  as the content spec for the element.
  2982.     //
  2983.     ContentSpecNode* headNode = curNode;
  2984.     // Remember the original node so we can sense the first choice node
  2985.     ContentSpecNode* orgNode = curNode;
  2986.     //
  2987.     //  We just loop around, getting the | character at the top and then
  2988.     //  looking for the next element name. We keep up with the last node
  2989.     //  and add each new one to its right node.
  2990.     //
  2991.     while (true)
  2992.     {
  2993.         //
  2994.         //  First of all we check for some grunt work details of skipping
  2995.         //  whitespace, expand PE refs, and catching invalid reps.
  2996.         //
  2997.         if (fReaderMgr->lookingAtChar(chPercent))
  2998.         {
  2999.             // Expand it and continue
  3000.             checkForPERef(false, false, true);
  3001.         }
  3002.          else if (fReaderMgr->skippedChar(chAsterisk))
  3003.         {
  3004.             //
  3005.             //  Tell them they can't have reps in mixed model, but eat
  3006.             //  it and keep going if we are allowed to.
  3007.             //
  3008.             fScanner->emitError(XMLErrs::NoRepInMixed);
  3009.         }
  3010.          else if (fReaderMgr->skippedSpace())
  3011.         {
  3012.             // Spaces are ok at this point, just eat them and continue
  3013.             fReaderMgr->skipPastSpaces();
  3014.         }
  3015.          else
  3016.         {
  3017.             if (!fReaderMgr->skippedChar(chPipe))
  3018.             {
  3019.                 // Has to be the closing paren now.
  3020.                 if (!fReaderMgr->skippedChar(chCloseParen))
  3021.                 {
  3022.                     fScanner->emitError(XMLErrs::UnterminatedContentModel);
  3023.                     delete headNode;
  3024.                     return false;
  3025.                 }
  3026.                 if (!fReaderMgr->skippedChar(chAsterisk) && starRequired)
  3027.                     fScanner->emitError(XMLErrs::ExpectedAsterisk);
  3028.                 //
  3029.                 //  Create a zero or more node and make the original head
  3030.                 //  node its first child.
  3031.                 //
  3032.                 headNode = new ContentSpecNode
  3033.                 (
  3034.                     ContentSpecNode::ZeroOrMore
  3035.                     , headNode
  3036.                     , 0
  3037.                 );
  3038.                 // Store the head node as the content spec of the element.
  3039.                 toFill.setContentSpec(headNode);
  3040.                 break;
  3041.             }
  3042.             // Its more than just a PCDATA, so an ending star will be required now
  3043.             starRequired = true;
  3044.             // Space is legal here so check for a PE ref, but don't require space
  3045.             checkForPERef(false, false, true);
  3046.             // Get a name token
  3047.             if (!fReaderMgr->getName(nameBuf))
  3048.             {
  3049.                 fScanner->emitError(XMLErrs::ExpectedElementName);
  3050.                 delete headNode;
  3051.                 return false;
  3052.             }
  3053.             //
  3054.             //  Create a leaf node for it. If we can find the element id for
  3055.             //  this element, then use it. Else, we have to fault in an element
  3056.             //  decl, marked as created because of being in a content model.
  3057.             //
  3058.             XMLElementDecl* decl = fDTDGrammar->getElemDecl(fEmptyNamespaceId, 0, nameBuf.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE);
  3059.             if (!decl)
  3060.             {
  3061.                 decl = new DTDElementDecl(nameBuf.getRawBuffer(), fEmptyNamespaceId);
  3062.                 decl->setCreateReason(XMLElementDecl::InContentModel);
  3063.                 decl->setExternalElemDeclaration(isReadingExternalEntity());
  3064.                 fDTDGrammar->putElemDecl(decl);
  3065.             }
  3066.             //
  3067.             //  If the current node is the original node, this is the first choice
  3068.             //  node, so create an initial choice node with the current node and
  3069.             //  the new element id. Store this as the head node.
  3070.             //
  3071.             //  Otherwise, we have to steal the right node of the previous choice
  3072.             //  and weave in another choice node there, which has the old choice
  3073.             //  as its left and the new leaf as its right.
  3074.             //
  3075.             if (curNode == orgNode)
  3076.             {
  3077.                 curNode = new ContentSpecNode
  3078.                 (
  3079.                     ContentSpecNode::Choice
  3080.                     , curNode
  3081.                     , new ContentSpecNode(decl->getElementName())
  3082.                 );
  3083.                 // Remember the top node
  3084.                 headNode = curNode;
  3085.             }
  3086.              else
  3087.             {
  3088.                 ContentSpecNode* oldRight = curNode->orphanSecond();
  3089.                 curNode->setSecond
  3090.                 (
  3091.                     new ContentSpecNode
  3092.                     (
  3093.                         ContentSpecNode::Choice
  3094.                         , oldRight
  3095.                         , new ContentSpecNode(decl->getElementName())
  3096.                     )
  3097.                 );
  3098.                 // Make the new right node the current node
  3099.                 curNode = curNode->getSecond();
  3100.             }
  3101.         }
  3102.     }
  3103.     return true;
  3104. }
  3105. //
  3106. //  This method is called when we see a '<!NOTATION' string while scanning
  3107. //  markup decl. It parses out the notation and its id and stores a new
  3108. //  notation decl object in the notation decl pool.
  3109. //
  3110. void DTDScanner::scanNotationDecl()
  3111. {
  3112.     // Space is required here so check for a PE ref, and require space
  3113.     if (!checkForPERef(true, false, true))
  3114.     {
  3115.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  3116.         fReaderMgr->skipPastChar(chCloseAngle);
  3117.         return;
  3118.     }
  3119.     //
  3120.     //  And now we get a name, which is the name of the notation. Get a
  3121.     //  buffer for the name.
  3122.     //
  3123.     XMLBufBid bbName(fBufMgr);
  3124.     if (!fReaderMgr->getName(bbName.getBuffer()))
  3125.     {
  3126.         fScanner->emitError(XMLErrs::ExpectedNotationName);
  3127.         fReaderMgr->skipPastChar(chCloseAngle);
  3128.         return;
  3129.     }
  3130.     // If namespaces are enabled, then no colons allowed
  3131.     if (fScanner->getDoNamespaces())
  3132.     {
  3133.         if (XMLString::indexOf(bbName.getRawBuffer(), chColon) != -1)
  3134.             fScanner->emitError(XMLErrs::ColonNotLegalWithNS);
  3135.     }
  3136.     // Space is required here so check for a PE ref, and require space
  3137.     if (!checkForPERef(true, false, true))
  3138.     {
  3139.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  3140.         fReaderMgr->skipPastChar(chCloseAngle);
  3141.         return;
  3142.     }
  3143.     //
  3144.     //  And scan an external or public id. We need buffers to use for both
  3145.     //  of these.
  3146.     //
  3147.     XMLBufBid bbPubId(fBufMgr);
  3148.     XMLBufBid bbSysId(fBufMgr);
  3149.     if (!scanId(bbPubId.getBuffer(), bbSysId.getBuffer(), IDType_Either))
  3150.     {
  3151.         fReaderMgr->skipPastChar(chCloseAngle);
  3152.         return;
  3153.     }
  3154.     // We can have an optional space or PE ref here
  3155.     checkForPERef(false, false, true);
  3156.     //
  3157.     //  See if it already exists. If so, add it to the notatino decl pool.
  3158.     //  Otherwise, if advanced callbacks are on, create a temp one and
  3159.     //  call out for that one.
  3160.     //
  3161.     XMLNotationDecl* decl = fDTDGrammar->getNotationDecl(bbName.getRawBuffer());
  3162.     bool isIgnoring = (decl != 0);
  3163.     if (isIgnoring)
  3164.     {
  3165.         fScanner->emitError(XMLErrs::NotationAlreadyExists, bbName.getRawBuffer());
  3166.     }
  3167.      else
  3168.     {
  3169.         // Fill in a new notation declaration and add it to the pool
  3170.         decl = new XMLNotationDecl
  3171.         (
  3172.             bbName.getRawBuffer()
  3173.             , bbPubId.getRawBuffer()
  3174.             , bbSysId.getRawBuffer()
  3175.         );
  3176.         fDTDGrammar->putNotationDecl(decl);
  3177.     }
  3178.     //
  3179.     //  If we have a document type handler, then tell it about this. If we
  3180.     //  are ignoring it, only call out if advanced callbacks are enabled.
  3181.     //
  3182.     if (fDocTypeHandler)
  3183.     {
  3184.         fDocTypeHandler->notationDecl
  3185.         (
  3186.             *decl
  3187.             , isIgnoring
  3188.         );
  3189.     }
  3190.     // And one more optional space or PE ref
  3191.     checkForPERef(false, false, true);
  3192.     // And skip the terminating bracket
  3193.     if (!fReaderMgr->skippedChar(chCloseAngle))
  3194.         fScanner->emitError(XMLErrs::UnterminatedNotationDecl);
  3195. }
  3196. //
  3197. //  Scans a PI and calls the appropriate callbacks. A PI can happen in either
  3198. //  the document or the DTD, so it calls the appropriate handler according
  3199. //  to the fInDocument flag.
  3200. //
  3201. //  At entry we have just scanned the <? part, and need to now start on the
  3202. //  PI target name.
  3203. //
  3204. void DTDScanner::scanPI()
  3205. {
  3206.     const XMLCh* namePtr = 0;
  3207.     const XMLCh* targetPtr = 0;
  3208.     //
  3209.     //  If there are any spaces here, then warn about it. If we aren't in
  3210.     //  'first error' mode, then we'll come back and can easily pick up
  3211.     //  again by just skipping them.
  3212.     //
  3213.     if (fReaderMgr->lookingAtSpace())
  3214.     {
  3215.         fScanner->emitError(XMLErrs::PINameExpected);
  3216.         fReaderMgr->skipPastSpaces();
  3217.     }
  3218.     // Get a buffer for the PI name and scan it in
  3219.     XMLBufBid bbName(fBufMgr);
  3220.     if (!fReaderMgr->getName(bbName.getBuffer()))
  3221.     {
  3222.         fScanner->emitError(XMLErrs::PINameExpected);
  3223.         fReaderMgr->skipPastChar(chCloseAngle);
  3224.         return;
  3225.     }
  3226.     // Point the name pointer at the raw data
  3227.     namePtr = bbName.getRawBuffer();
  3228.     // See if it issome form of 'xml' and emit a warning
  3229.     if (!XMLString::compareIString(namePtr, XMLUni::fgXMLString))
  3230.         fScanner->emitError(XMLErrs::NoPIStartsWithXML);
  3231.     // If namespaces are enabled, then no colons allowed
  3232.     if (fScanner->getDoNamespaces())
  3233.     {
  3234.         if (XMLString::indexOf(namePtr, chColon) != -1)
  3235.             fScanner->emitError(XMLErrs::ColonNotLegalWithNS);
  3236.     }
  3237.     //
  3238.     //  If we don't hit a space next, then the PI has no target. If we do
  3239.     //  then get out the target. Get a buffer for it as well
  3240.     //
  3241.     XMLBufBid bbTarget(fBufMgr);
  3242.     if (fReaderMgr->skippedSpace())
  3243.     {
  3244.         // Skip any leading spaces
  3245.         fReaderMgr->skipPastSpaces();
  3246.         // It does have a target, so lets move on to deal with that.
  3247.         while (1)
  3248.         {
  3249.             const XMLCh nextCh = fReaderMgr->getNextChar();
  3250.             // Watch for an end of file, which is always bad here
  3251.             if (!nextCh)
  3252.             {
  3253.                 fScanner->emitError(XMLErrs::UnterminatedPI);
  3254.                 ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  3255.             }
  3256.             // Watch for potential terminating character
  3257.             if (nextCh == chQuestion)
  3258.             {
  3259.                 // It must be followed by '>' to be a termination of the target
  3260.                 if (fReaderMgr->skippedChar(chCloseAngle))
  3261.                     break;
  3262.             }
  3263.             // Watch for invalid chars but try to keep going
  3264.             if (!XMLReader::isXMLChar(nextCh))
  3265.             {
  3266.                 XMLCh tmpBuf[9];
  3267.                 XMLString::binToText
  3268.                 (
  3269.                     nextCh
  3270.                     , tmpBuf
  3271.                     , 8
  3272.                     , 16
  3273.                 );
  3274.                 fScanner->emitError(XMLErrs::InvalidCharacter, tmpBuf);
  3275.             }
  3276.             bbTarget.append(nextCh);
  3277.         }
  3278.     }
  3279.      else
  3280.     {
  3281.         // No target, but make sure its terminated ok
  3282.         if (!fReaderMgr->skippedChar(chQuestion))
  3283.         {
  3284.             fScanner->emitError(XMLErrs::UnterminatedPI);
  3285.             fReaderMgr->skipPastChar(chCloseAngle);
  3286.             return;
  3287.         }
  3288.         if (!fReaderMgr->skippedChar(chCloseAngle))
  3289.         {
  3290.             fScanner->emitError(XMLErrs::UnterminatedPI);
  3291.             fReaderMgr->skipPastChar(chCloseAngle);
  3292.             return;
  3293.         }
  3294.     }
  3295.     // Point the target pointer at the raw data
  3296.     targetPtr = bbTarget.getRawBuffer();
  3297.     //
  3298.     //  If we have a handler, then call it.
  3299.     //
  3300.     if (fDocTypeHandler)
  3301.     {
  3302.         fDocTypeHandler->doctypePI
  3303.         (
  3304.             namePtr
  3305.             , targetPtr
  3306.         );
  3307.     }
  3308. }
  3309. //
  3310. //  This method scans a public literal. It must be quoted and all of its
  3311. //  characters must be valid public id characters. The quotes are discarded
  3312. //  and the results are returned.
  3313. //
  3314. bool DTDScanner::scanPublicLiteral(XMLBuffer& toFill)
  3315. {
  3316.     toFill.reset();
  3317.     // Get the next char which must be a single or double quote
  3318.     XMLCh quoteCh;
  3319.     if (!fReaderMgr->skipIfQuote(quoteCh)) {
  3320.         fScanner->emitError(XMLErrs::ExpectedQuotedString);
  3321.         return false;
  3322.     }
  3323.     while (true)
  3324.     {
  3325.         const XMLCh nextCh = fReaderMgr->getNextChar();
  3326.         // Watch for EOF
  3327.         if (!nextCh)
  3328.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  3329.         if (nextCh == quoteCh)
  3330.             break;
  3331.         //
  3332.         //  If its not a valid public id char, then report it but keep going
  3333.         //  since that's the best recovery scheme.
  3334.         //
  3335.         if (!XMLReader::isPublicIdChar(nextCh))
  3336.         {
  3337.             XMLCh tmpBuf[9];
  3338.             XMLString::binToText
  3339.             (
  3340.                 nextCh
  3341.                 , tmpBuf
  3342.                 , 8
  3343.                 , 16
  3344.             );
  3345.             fScanner->emitError(XMLErrs::InvalidPublicIdChar, tmpBuf);
  3346.         }
  3347.         toFill.append(nextCh);
  3348.     }
  3349.     return true;
  3350. }
  3351. //
  3352. //  This method handles scanning in a quoted system literal. It expects to
  3353. //  start on the open quote and returns after eating the ending quote. There
  3354. //  are not really any restrictions on the contents of system literals.
  3355. //
  3356. bool DTDScanner::scanSystemLiteral(XMLBuffer& toFill)
  3357. {
  3358.     toFill.reset();
  3359.     // Get the next char which must be a single or double quote
  3360.     XMLCh quoteCh;
  3361.     if (!fReaderMgr->skipIfQuote(quoteCh)) {
  3362.         fScanner->emitError(XMLErrs::ExpectedQuotedString);
  3363.         return false;
  3364.     }
  3365.     while (true)
  3366.     {
  3367.         const XMLCh nextCh = fReaderMgr->getNextChar();
  3368.         // Watch for EOF
  3369.         if (!nextCh)
  3370.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  3371.         // Break out on terminating quote
  3372.         if (nextCh == quoteCh)
  3373.             break;
  3374.         toFill.append(nextCh);
  3375.     }
  3376.     return true;
  3377. }
  3378. //
  3379. //  This method is called to scan a text decl line, which can be the first
  3380. //  line in an external entity or external subset.
  3381. //
  3382. //  On entry the <? has been scanned, and next should be 'xml' followed by
  3383. //  some whitespace, version string, etc...
  3384. //    [77] TextDecl::= '<?xml' VersionInfo? EncodingDecl S? '?>'
  3385. //
  3386. void DTDScanner::scanTextDecl()
  3387. {
  3388.     // Skip any subsequent whitespace before the version string
  3389.     fReaderMgr->skipPastSpaces();
  3390.     // Next should be the version string
  3391.     XMLBufBid bbVersion(fBufMgr);
  3392.     if (fReaderMgr->skippedString(XMLUni::fgVersionString))
  3393.     {
  3394.         if (!scanEq())
  3395.         {
  3396.             fScanner->emitError(XMLErrs::ExpectedEqSign);
  3397.             fReaderMgr->skipPastChar(chCloseAngle);
  3398.             return;
  3399.         }
  3400.         //
  3401.         //  Followed by a single or double quoted version. Get a buffer for
  3402.         //  the string.
  3403.         //
  3404.         if (!getQuotedString(bbVersion.getBuffer()))
  3405.         {
  3406.             fScanner->emitError(XMLErrs::BadXMLVersion);
  3407.             fReaderMgr->skipPastChar(chCloseAngle);
  3408.             return;
  3409.         }
  3410.         // If its not our supported version, issue an error but continue
  3411.         if (XMLString::compareString(bbVersion.getRawBuffer(), XMLUni::fgSupportedVersion))
  3412.             fScanner->emitError(XMLErrs::UnsupportedXMLVersion, bbVersion.getRawBuffer());
  3413.     }
  3414.     // Ok, now we must have an encoding string
  3415.     XMLBufBid bbEncoding(fBufMgr);
  3416.     fReaderMgr->skipPastSpaces();
  3417.     bool gotEncoding = false;
  3418.     if (fReaderMgr->skippedString(XMLUni::fgEncodingString))
  3419.     {
  3420.         // There must be a equal sign next
  3421.         if (!scanEq())
  3422.         {
  3423.             fScanner->emitError(XMLErrs::ExpectedEqSign);
  3424.             fReaderMgr->skipPastChar(chCloseAngle);
  3425.             return;
  3426.         }
  3427.         // Followed by a single or double quoted version string
  3428.         getQuotedString(bbEncoding.getBuffer());
  3429.         if (bbEncoding.isEmpty())
  3430.         {
  3431.             fScanner->emitError(XMLErrs::BadXMLEncoding, bbEncoding.getRawBuffer());
  3432.             fReaderMgr->skipPastChar(chCloseAngle);
  3433.             return;
  3434.         }
  3435.         // Indicate that we got an encoding
  3436.         gotEncoding = true;
  3437.     }
  3438.     //
  3439.     // Encoding declarations are required in the external entity
  3440.     // if there is a text declaration present
  3441.     //
  3442.     if (!gotEncoding)
  3443.     {
  3444.       fScanner->emitError(XMLErrs::EncodingRequired);
  3445.       fReaderMgr->skipPastChar(chCloseAngle);
  3446.       return;
  3447.     }
  3448.     fReaderMgr->skipPastSpaces();
  3449.     if (!fReaderMgr->skippedChar(chQuestion))
  3450.     {
  3451.         fScanner->emitError(XMLErrs::UnterminatedXMLDecl);
  3452.         fReaderMgr->skipPastChar(chCloseAngle);
  3453.     }
  3454.      else if (!fReaderMgr->skippedChar(chCloseAngle))
  3455.     {
  3456.         fScanner->emitError(XMLErrs::UnterminatedXMLDecl);
  3457.         fReaderMgr->skipPastChar(chCloseAngle);
  3458.     }
  3459.     //
  3460.     //  If we have a document type handler and advanced callbacks are on,
  3461.     //  then call the TextDecl callback
  3462.     //
  3463.     if (fDocTypeHandler)
  3464.     {
  3465.         fDocTypeHandler->TextDecl
  3466.         (
  3467.             bbVersion.getRawBuffer()
  3468.             , bbEncoding.getRawBuffer()
  3469.         );
  3470.     }
  3471.     //
  3472.     //  If we got an encoding string, then we have to call back on the reader
  3473.     //  to tell it what the encoding is.
  3474.     //
  3475.     if (!bbEncoding.isEmpty())
  3476.     {
  3477.         if (!fReaderMgr->getCurrentReader()->setEncoding(bbEncoding.getRawBuffer()))
  3478.             fScanner->emitError(XMLErrs::ContradictoryEncoding, bbEncoding.getRawBuffer());
  3479.     }
  3480. }