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

词法分析

开发平台:

Visual C++

  1.     entityDecl->setIsParameter(isPEDecl);
  2.     //
  3.     //  Space is legal (required actually) here so check for a PE ref. If
  4.     //  we don't get our whitespace, then issue an error, but try to keep
  5.     //  going.
  6.     //
  7.     if (!checkForPERef(true, false, true))
  8.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  9.     // save the hasNoDTD status for Entity Constraint Checking
  10.     bool hasNoDTD = fScanner->getHasNoDTD();
  11.     if (hasNoDTD && isPEDecl)
  12.         fScanner->setHasNoDTD(false);
  13.     // According to the type call the value scanning method
  14.     if (!scanEntityDef(*entityDecl, isPEDecl))
  15.     {
  16.         fReaderMgr->skipPastChar(chCloseAngle);
  17.         fScanner->setHasNoDTD(true);
  18.         fScanner->emitError(XMLErrs::ExpectedEntityValue);
  19.         return;
  20.     }
  21.     if (hasNoDTD)
  22.         fScanner->setHasNoDTD(true);
  23.     // Space is legal (but not required) here so check for a PE ref
  24.     checkForPERef(false, false, true);
  25.     // And then we have to have the closing angle bracket
  26.     if (!fReaderMgr->skippedChar(chCloseAngle))
  27.     {
  28.         fScanner->emitError(XMLErrs::UnterminatedEntityDecl, entityDecl->getName());
  29.         fReaderMgr->skipPastChar(chCloseAngle);
  30.     }
  31.     //
  32.     //  If we have a doc type handler, then call it. But only call it for
  33.     //  ignored elements if advanced callbacks are enabled.
  34.     //
  35.     if (fDocTypeHandler)
  36.         fDocTypeHandler->entityDecl(*entityDecl, isPEDecl, isIgnored);
  37. }
  38. //
  39. //  This method will scan a general/character entity ref. It will either
  40. //  expand a char ref and return the value directly, or it will expand
  41. //  a general entity and a reader for it onto the reader stack.
  42. //
  43. //  The return value indicates whether the value was returned directly or
  44. //  pushed as a reader or it failed.
  45. //
  46. //  The escaped flag tells the caller whether the returnd parameter resulted
  47. //  from a character reference, which escapes the character in some cases. It
  48. //  only makes any difference if the return indicates the value was returned
  49. //  directly.
  50. //
  51. //  NOTE: This is only called when scanning attribute values, so we always
  52. //  expand general entities.
  53. //
  54. DTDScanner::EntityExpRes
  55. DTDScanner::scanEntityRef(XMLCh& firstCh, XMLCh& secondCh, bool& escaped)
  56. {
  57.     // Assume no escape and no second char
  58.     escaped = false;
  59.     secondCh = 0;
  60.     // We have to insure its all done in a single entity
  61.     const unsigned int curReader = fReaderMgr->getCurrentReaderNum();
  62.     //
  63.     //  If the next char is a pound, then its a character reference and we
  64.     //  need to expand it always.
  65.     //
  66.     if (fReaderMgr->skippedChar(chPound))
  67.     {
  68.         //
  69.         //  Its a character reference, so scan it and get back the numeric
  70.         //  value it represents. If it fails, just return immediately.
  71.         //
  72.         if (!scanCharRef(firstCh, secondCh))
  73.             return EntityExp_Failed;
  74.         if (curReader != fReaderMgr->getCurrentReaderNum())
  75.             fScanner->emitError(XMLErrs::PartialMarkupInEntity);
  76.         // Its now escaped since it was a char ref
  77.         escaped = true;
  78.         return EntityExp_Returned;
  79.     }
  80.     // Get the name of the general entity
  81.     XMLBufBid bbName(fBufMgr);
  82.     if (!fReaderMgr->getName(bbName.getBuffer()))
  83.     {
  84.         fScanner->emitError(XMLErrs::ExpectedEntityRefName);
  85.         return EntityExp_Failed;
  86.     }
  87.     //
  88.     //  Next char must be a semi-colon. But if its not, just emit
  89.     //  an error and try to continue.
  90.     //
  91.     if (!fReaderMgr->skippedChar(chSemiColon))
  92.         fScanner->emitError(XMLErrs::UnterminatedEntityRef, bbName.getRawBuffer());
  93.     // Make sure it was all in one entity reader
  94.     if (curReader != fReaderMgr->getCurrentReaderNum())
  95.         fScanner->emitError(XMLErrs::PartialMarkupInEntity);
  96.     // Look it up the name the general entity pool
  97.     XMLEntityDecl* decl = fDTDGrammar->getEntityDecl(bbName.getRawBuffer());
  98.     // If it does not exist, then obviously an error
  99.     if (!decl)
  100.     {
  101.         // XML 1.0 Section 4.1
  102.         if (fScanner->getStandalone() || fScanner->getHasNoDTD()) {
  103.             fScanner->emitError(XMLErrs::EntityNotFound, bbName.getRawBuffer());
  104.         }
  105.         else {
  106.             if (fScanner->getDoValidation())
  107.                 fScanner->getValidator()->emitError(XMLValid::VC_EntityNotFound, bbName.getRawBuffer());
  108.         }
  109.         return EntityExp_Failed;
  110.     }
  111.     //
  112.     // XML 1.0 Section 4.1
  113.     //  If we are a standalone document, then it has to have been declared
  114.     //  in the internal subset.
  115.     //
  116.     if (fScanner->getStandalone() && !decl->getDeclaredInIntSubset())
  117.         fScanner->emitError(XMLErrs::IllegalRefInStandalone, bbName.getRawBuffer());
  118.     //
  119.     //  If its a special char reference, then its escaped and we can return
  120.     //  it directly.
  121.     //
  122.     if (decl->getIsSpecialChar())
  123.     {
  124.         firstCh = decl->getValue()[0];
  125.         escaped = true;
  126.         return EntityExp_Returned;
  127.     }
  128.     if (decl->isExternal())
  129.     {
  130.         // If its unparsed, then its not valid here
  131.         // XML 1.0 Section 4.4.4 the appearance of a reference to an unparsed entity is forbidden.
  132.         if (decl->isUnparsed())
  133.         {
  134.             fScanner->emitError(XMLErrs::NoUnparsedEntityRefs, bbName.getRawBuffer());
  135.             return EntityExp_Failed;
  136.         }
  137.         // We are in an attribute value, so not valid.
  138.         // XML 1.0 Section 4.4.4 a reference to an external entity in an attribute value is forbidden.
  139.         fScanner->emitError(XMLErrs::NoExtRefsInAttValue);
  140.         // And now create a reader to read this entity
  141.         InputSource* srcUsed;
  142.         XMLReader* reader = fReaderMgr->createReader
  143.         (
  144.             decl->getBaseURI()
  145.             , decl->getSystemId()
  146.             , decl->getPublicId()
  147.             , false
  148.             , XMLReader::RefFrom_NonLiteral
  149.             , XMLReader::Type_General
  150.             , XMLReader::Source_External
  151.             , srcUsed
  152.         );
  153.         // Put a janitor on the source so it gets cleaned up on exit
  154.         Janitor<InputSource> janSrc(srcUsed);
  155.         //
  156.         //  If the creation failed then throw an exception
  157.         //
  158.         if (!reader)
  159.             ThrowXML1(RuntimeException, XMLExcepts::Gen_CouldNotOpenExtEntity, srcUsed->getSystemId());
  160.         //
  161.         //  Push the reader. If its a recursive expansion, then emit an error
  162.         //  and return an failure.
  163.         //
  164.         if (!fReaderMgr->pushReader(reader, decl))
  165.         {
  166.             fScanner->emitError(XMLErrs::RecursiveEntity, decl->getName());
  167.             return EntityExp_Failed;
  168.         }
  169.         // If it starts with the XML string, then parse a text decl
  170.         if (fScanner->checkXMLDecl(true))
  171.             scanTextDecl();
  172.     }
  173.      else
  174.     {
  175.         //
  176.         //  Create a reader over a memory stream over the entity value
  177.         //  We force it to assume UTF-16 by passing in an encoding
  178.         //  string. This way it won't both trying to predecode the
  179.         //  first line, looking for an XML/TextDecl.
  180.         //
  181.         XMLReader* valueReader = fReaderMgr->createIntEntReader
  182.         (
  183.             decl->getName()
  184.             , XMLReader::RefFrom_NonLiteral
  185.             , XMLReader::Type_General
  186.             , decl->getValue()
  187.             , decl->getValueLen()
  188.             , false
  189.         );
  190.         //
  191.         //  Trt to push the entity reader onto the reader manager stack,
  192.         //  where it will become the subsequent input. If it fails, that
  193.         //  means the entity is recursive, so issue an error. The reader
  194.         //  will have just been discarded, but we just keep going.
  195.         //
  196.         if (!fReaderMgr->pushReader(valueReader, decl))
  197.             fScanner->emitError(XMLErrs::RecursiveEntity, decl->getName());
  198.     }
  199.     return EntityExp_Pushed;
  200. }
  201. //
  202. //  This method will scan a quoted literal of an entity value. It has to
  203. //  deal with replacement of PE references; however, since this is a DTD
  204. //  scanner, all such entity literals are in entity decls and therefore
  205. //  general entities are not expanded.
  206. //
  207. bool DTDScanner::scanEntityLiteral(XMLBuffer& toFill, const bool isPE)
  208. {
  209.     toFill.reset();
  210.     // Get the next char which must be a single or double quote
  211.     XMLCh quoteCh;
  212.     if (!fReaderMgr->skipIfQuote(quoteCh))
  213.         return false;
  214.     // Get a buffer for pulling in entity names when we see GE refs
  215.     XMLBufBid bbName(fBufMgr);
  216.     XMLBuffer& nameBuf = bbName.getBuffer();
  217.     // Remember the current reader
  218.     const unsigned int orgReader = fReaderMgr->getCurrentReaderNum();
  219.     //
  220.     //  Loop until we see the ending quote character, handling any references
  221.     //  in the process.
  222.     //
  223.     XMLCh   nextCh;
  224.     XMLCh   secondCh = 0;
  225.     bool    gotLeadingSurrogate = false;
  226.     while (true)
  227.     {
  228.         nextCh = fReaderMgr->getNextChar();
  229.         //
  230.         //  Watch specifically for EOF and issue a more meaningful error
  231.         //  if that occurs (since an unterminated quoted char can cause
  232.         //  this easily.)
  233.         //
  234.         if (!nextCh)
  235.         {
  236.             fScanner->emitError(XMLErrs::UnterminatedEntityLiteral);
  237.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  238.         }
  239.         //
  240.         //  Break out on our terminating quote char when we are back in the
  241.         //  same reader. Otherwise, we might trigger on a nested quote char
  242.         //  in an expanded entity.
  243.         //
  244.         if ((nextCh == quoteCh)
  245.         &&  (fReaderMgr->getCurrentReaderNum() == orgReader))
  246.         {
  247.             break;
  248.         }
  249.         if (nextCh == chPercent)
  250.         {
  251.             //
  252.             //  Put the PE's value on the reader stack and then jump back
  253.             //  to the top to start processing it. The parameter indicates
  254.             //  that it should not scan the reference's content as an external
  255.             //  subset.
  256.             //
  257.             expandPERef(false, true, true);
  258.             continue;
  259.         }
  260.         //
  261.         //  Ok, now that all the other special stuff is checked, we can
  262.         //  look for a general entity. In here, we cannot have a naked &
  263.         //  and will only expand numerical char refs or the intrinsic char
  264.         //  refs. Others will be left alone.
  265.         //
  266.         if (nextCh == chAmpersand)
  267.         {
  268.             //
  269.             //  Here, we only expand numeric char refs, but not any general
  270.             //  entities. However, the stupid XML spec requires that we check
  271.             //  and make sure it does refer to a general entity if its not
  272.             //  a char ref (i.e. no naked '&' chars.)
  273.             //
  274.             if (fReaderMgr->skippedChar(chPound))
  275.             {
  276.                 // If it failed, then just jump back to the top and try to pick up
  277.                 if (!scanCharRef(nextCh, secondCh))
  278.                 {
  279.                     gotLeadingSurrogate = false;
  280.                     continue;
  281.                 }
  282.             }
  283.              else
  284.             {
  285.                 if (!fReaderMgr->getName(nameBuf))
  286.                 {
  287.                     fScanner->emitError(XMLErrs::ExpectedEntityRefName);
  288.                 }
  289.                  else
  290.                 {
  291.                     //
  292.                     //  Since we are not expanding any of this, we have to
  293.                     //  put the amp and name into the target buffer as data.
  294.                     //
  295.                     toFill.append(chAmpersand);
  296.                     toFill.append(nameBuf.getRawBuffer());
  297.                     // Make sure we skipped a trailing semicolon
  298.                     if (!fReaderMgr->skippedChar(chSemiColon))
  299.                     {
  300.                         fScanner->emitError
  301.                         (
  302.                             XMLErrs::UnterminatedEntityRef
  303.                             , nameBuf.getRawBuffer()
  304.                         );
  305.                     }
  306.                     // And make the new character the semicolon
  307.                     nextCh = chSemiColon;
  308.                 }
  309.                 // Either way here we reset the surrogate flag
  310.                 gotLeadingSurrogate = false;
  311.             }
  312.         }
  313.         else if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
  314.         {
  315.             if (gotLeadingSurrogate)
  316.                 fScanner->emitError(XMLErrs::Expected2ndSurrogateChar);
  317.             else
  318.                 gotLeadingSurrogate = true;
  319.         }
  320.          else
  321.         {
  322.             if (gotLeadingSurrogate)
  323.             {
  324.                 if ((nextCh < 0xDC00) || (nextCh > 0xDFFF))
  325.                     fScanner->emitError(XMLErrs::Expected2ndSurrogateChar);
  326.             }
  327.              else if (!fReaderMgr->getCurrentReader()->isXMLChar(nextCh))
  328.             {
  329.                 XMLCh tmpBuf[9];
  330.                 XMLString::binToText
  331.                 (
  332.                     nextCh
  333.                     , tmpBuf
  334.                     , 8
  335.                     , 16
  336.                 );
  337.                 fScanner->emitError(XMLErrs::InvalidCharacter, tmpBuf);
  338.                 fReaderMgr->skipPastChar(quoteCh);
  339.                 return false;
  340.             }
  341.             gotLeadingSurrogate = false;
  342.         }
  343.         // Looks ok, so add it to the literal
  344.         toFill.append(nextCh);
  345.         if (secondCh)
  346.             toFill.append(secondCh);
  347.     }
  348.     //
  349.     //  If we got here and did not get back to the original reader level,
  350.     //  then we propogated some entity out of the literal, so issue an
  351.     //  error, but don't fail.
  352.     //
  353.     if (fReaderMgr->getCurrentReaderNum() != orgReader && fScanner->getDoValidation())
  354.         fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE);
  355.     return true;
  356. }
  357. //
  358. //  This method is called after the entity name has been scanned, and any
  359. //  PE referenced following the name is handled. The passed decl will be
  360. //  filled in with the info scanned.
  361. //
  362. bool DTDScanner::scanEntityDef(DTDEntityDecl& decl, const bool isPEDecl)
  363. {
  364.     // Its got to be an entity literal
  365.     if (fReaderMgr->lookingAtChar(chSingleQuote)
  366.     ||  fReaderMgr->lookingAtChar(chDoubleQuote))
  367.     {
  368.         // Get a buffer for the literal
  369.         XMLBufBid bbValue(fBufMgr);
  370.         if (!scanEntityLiteral(bbValue.getBuffer(), isPEDecl))
  371.             return false;
  372.         // Set it on the entity decl
  373.         decl.setValue(bbValue.getRawBuffer());
  374.         return true;
  375.     }
  376.     //
  377.     //  Its got to be an external entity, so there must be an external id.
  378.     //  Get buffers for them and scan an external id into them.
  379.     //
  380.     XMLBufBid bbPubId(fBufMgr);
  381.     XMLBufBid bbSysId(fBufMgr);
  382.     if (!scanId(bbPubId.getBuffer(), bbSysId.getBuffer(), IDType_External))
  383.         return false;
  384.     ReaderMgr::LastExtEntityInfo lastInfo;
  385.     fReaderMgr->getLastExtEntityInfo(lastInfo);
  386.     // Fill in the id fields of the decl with the info we got
  387.     const XMLCh* publicId = bbPubId.getRawBuffer();
  388.     const XMLCh* systemId = bbSysId.getRawBuffer();
  389.     decl.setPublicId((publicId && *publicId) ? publicId : 0);
  390.     decl.setSystemId((systemId && *systemId) ? systemId : 0);
  391.     decl.setBaseURI((lastInfo.systemId && *lastInfo.systemId) ? lastInfo.systemId : 0);
  392.     // If its a PE decl, we are done
  393.     bool gotSpaces = checkForPERef(false, false, true);
  394.     if (isPEDecl)
  395.     {
  396.         //
  397.         //  Check for a common error here. NDATA is not allowed for PEs
  398.         //  so check for the NDATA string. If found give a nice meaningful
  399.         //  error and continue parsing to eat the NDATA text.
  400.         //
  401.         if (gotSpaces)
  402.         {
  403.             if (fReaderMgr->skippedString(XMLUni::fgNDATAString))
  404.                 fScanner->emitError(XMLErrs::NDATANotValidForPE);
  405.         }
  406.          else
  407.         {
  408.             return true;
  409.         }
  410.     }
  411.     // If looking at close angle now, we are done
  412.     if (fReaderMgr->lookingAtChar(chCloseAngle))
  413.         return true;
  414.     // Else we had to have seem the whitespace
  415.     if (!gotSpaces)
  416.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  417.     // We now have to see a notation data string
  418.     if (!fReaderMgr->skippedString(XMLUni::fgNDATAString))
  419.         fScanner->emitError(XMLErrs::ExpectedNDATA);
  420.     // Space is required here, but try to go on if not
  421.     if (!checkForPERef(false, false, true))
  422.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  423.     // Get a name
  424.     XMLBufBid bbName(fBufMgr);
  425.     if (!fReaderMgr->getName(bbName.getBuffer()))
  426.     {
  427.         fScanner->emitError(XMLErrs::ExpectedNotationName);
  428.         return false;
  429.     }
  430.     // Set the decl's notation name
  431.     decl.setNotationName(bbName.getRawBuffer());
  432.     return true;
  433. }
  434. //
  435. //  This method is called after an attribute decl name or a notation decl has
  436. //  been scanned and then an opening parenthesis was see, indicating the list
  437. //  of values. It scans the enumeration values and creates a single string
  438. //  which has a single space between each value.
  439. //
  440. //  The terminating close paren ends this scan.
  441. //
  442. bool DTDScanner::scanEnumeration( const   DTDAttDef&  attDef
  443.                                     ,       XMLBuffer&  toFill
  444.                                     , const bool        notation)
  445. {
  446.     // Reset the passed buffer
  447.     toFill.reset();
  448.     // Check for PE ref but don't require space
  449.     checkForPERef(false, false, true);
  450.     // If this is a notation, we need an opening paren
  451.     if (notation)
  452.     {
  453.         if (!fReaderMgr->skippedChar(chOpenParen))
  454.             fScanner->emitError(XMLErrs::ExpectedOpenParen);
  455.     }
  456.     // We need a local buffer to use as well
  457.     XMLBufBid bbTmp(fBufMgr);
  458.     while (true)
  459.     {
  460.         // Space is allowed here for either type so check for PE ref
  461.         checkForPERef(false, false, true);
  462.         // And then get either a name or a name token
  463.         bool success;
  464.         if (notation)
  465.             success = fReaderMgr->getName(bbTmp.getBuffer());
  466.         else
  467.             success = fReaderMgr->getNameToken(bbTmp.getBuffer());
  468.         if (!success)
  469.         {
  470.             fScanner->emitError
  471.             (
  472.                 XMLErrs::ExpectedEnumValue
  473.                 , attDef.getFullName()
  474.             );
  475.             return false;
  476.         }
  477.         // Append this value to the target value
  478.         toFill.append(bbTmp.getRawBuffer(), bbTmp.getLen());
  479.         // Space is allowed here for either type so check for PE ref
  480.         checkForPERef(false, false, true);
  481.         // Check for the terminating paren
  482.         if (fReaderMgr->skippedChar(chCloseParen))
  483.             break;
  484.         // And append a space separator
  485.         toFill.append(chSpace);
  486.         // Check for the pipe character separator
  487.         if (!fReaderMgr->skippedChar(chPipe))
  488.         {
  489.             fScanner->emitError(XMLErrs::ExpectedEnumSepOrParen);
  490.             return false;
  491.         }
  492.     }
  493.     return true;
  494. }
  495. bool DTDScanner::scanEq()
  496. {
  497.     fReaderMgr->skipPastSpaces();
  498.     if (fReaderMgr->skippedChar(chEqual))
  499.     {
  500.         fReaderMgr->skipPastSpaces();
  501.         return true;
  502.     }
  503.     return false;
  504. }
  505. //
  506. //  This method is called when an external entity reference is seen in the
  507. //  DTD or an external DTD subset is encountered, and their contents pushed
  508. //  onto the reader stack. This method will scan that contents.
  509. //
  510. void DTDScanner::scanExtSubsetDecl(const bool inIncludeSect, const bool isDTD)
  511. {
  512.     // Indicate we are in the external subset now
  513.     FlagJanitor<bool> janContentFlag(&fInternalSubset, false);
  514.     bool bAcceptDecl = !inIncludeSect;
  515.     // Get a buffer for whitespace
  516.     XMLBufBid bbSpace(fBufMgr);
  517.     //
  518.     //  If we have a doc type handler and we are not being called recursively
  519.     //  to handle an include section, tell it the ext subset starts
  520.     //
  521.     if (fDocTypeHandler && !inIncludeSect)
  522.         fDocTypeHandler->startExtSubset();
  523.     //
  524.     //  We have to play a trick here if the current entity we are parsing
  525.     //  is a PE. Because the spooling code will put out a whitespace before
  526.     //  and after an expanded PE if its being scanned outside the context of
  527.     //  a literal entity, this will confuse this external subset code.
  528.     //
  529.     //  So, we see if that is what is happening and, if so, eat the single
  530.     //  space, a check for the <?xml string. If we find it, we parse that
  531.     //  markup right now and put the space back.
  532.     //
  533.     if (fReaderMgr->isScanningPERefOutOfLiteral())
  534.     {
  535.         if (fReaderMgr->skippedSpace())
  536.         {
  537.             if (fScanner->checkXMLDecl(true))
  538.             {
  539.                 scanTextDecl();
  540.                 bAcceptDecl = false;
  541.                 // <TBD> Figure out how to do this
  542.                 // fReaderMgr->unGet(chSpace);
  543.             }
  544.         }
  545.     }
  546.     // Get the current reader number
  547.     const unsigned int orgReader = fReaderMgr->getCurrentReaderNum();
  548.     //
  549.     //  Loop until we hit the end of the external subset entity. Note that
  550.     //  we use a double loop here in order to avoid the overhead of doing
  551.     //  the exception setup/teardown work on every loop.
  552.     //
  553.     bool inMarkup = false;
  554.     bool inCharData = false;
  555.     while (true)
  556.     {
  557.     try
  558.     {
  559.         while (true)
  560.         {
  561.             const XMLCh nextCh = fReaderMgr->peekNextChar();
  562.             if (nextCh == chOpenAngle)
  563.             {
  564.                 // Get the reader we started this on
  565.                 // XML 1.0 P28a Well-formedness constraint: PE Between Declarations
  566.                 const unsigned int orgReader = fReaderMgr->getCurrentReaderNum();
  567.                 bool wasInPE = (fReaderMgr->getCurrentReader()->getType() == XMLReader::Type_PE);
  568.                 //
  569.                 //  Now scan the markup. Set the flag so that we will know that
  570.                 //  we were in markup if an end of entity exception occurs.
  571.                 //
  572.                 fReaderMgr->getNextChar();
  573.                 inMarkup = true;
  574.                 scanMarkupDecl(bAcceptDecl);
  575.                 inMarkup = false;
  576.                 //
  577.                 //  And see if we got back to the same level. If not, then its
  578.                 //  a partial markup error.
  579.                 //
  580.                 if (fReaderMgr->getCurrentReaderNum() != orgReader){
  581.                     if (wasInPE)
  582.                         fScanner->emitError(XMLErrs::PEBetweenDecl);
  583.                     else if (fScanner->getDoValidation())
  584.                         fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE);
  585.                 }
  586.             }
  587.              else if (fReaderMgr->getCurrentReader()->isWhitespace(nextCh))
  588.             {
  589.                 //
  590.                 //  If we have a doc type handler, and advanced callbacks are
  591.                 //  enabled, then gather up whitespace and call back. Otherwise
  592.                 //  just skip whitespaces.
  593.                 //
  594.                 if (fDocTypeHandler)
  595.                 {
  596.                     inCharData = true;
  597.                     fReaderMgr->getSpaces(bbSpace.getBuffer());
  598.                     inCharData = false;
  599.                     fDocTypeHandler->doctypeWhitespace
  600.                     (
  601.                         bbSpace.getRawBuffer()
  602.                         , bbSpace.getLen()
  603.                     );
  604.                 }
  605.                  else
  606.                 {
  607.                     //
  608.                     //  If we hit an end of entity in the middle of white
  609.                     //  space, that's fine. We'll just come back in here
  610.                     //  again on the next round and skip some more.
  611.                     //
  612.                     fReaderMgr->skipPastSpaces();
  613.                 }
  614.             }
  615.              else if (nextCh == chPercent)
  616.             {
  617.                 //
  618.                 //  Expand (and scan if external) the reference value. Tell
  619.                 //  it to throw an end of entity exception at the end of the
  620.                 //  entity.
  621.                 //
  622.                 fReaderMgr->getNextChar();
  623.                 expandPERef(true, false, false, true);
  624.             }
  625.              else if (inIncludeSect && (nextCh == chCloseSquare))
  626.             {
  627.                 //
  628.                 //  Its the end of a conditional include section. So scan it and
  629.                 //  decrement the include depth counter.
  630.                 //
  631.                 fReaderMgr->getNextChar();
  632.                 if (!fReaderMgr->skippedChar(chCloseSquare))
  633.                 {
  634.                     fScanner->emitError(XMLErrs::ExpectedEndOfConditional);
  635.                     fReaderMgr->skipPastChar(chCloseAngle);
  636.                 }
  637.                  else if (!fReaderMgr->skippedChar(chCloseAngle))
  638.                 {
  639.                     fScanner->emitError(XMLErrs::ExpectedEndOfConditional);
  640.                     fReaderMgr->skipPastChar(chCloseAngle);
  641.                 }
  642.                 return;
  643.             }
  644.              else if (!nextCh)
  645.             {
  646.                 return; // nothing left
  647.             }
  648.             else
  649.             {
  650.                 fReaderMgr->getNextChar();
  651.                 if (!fReaderMgr->getCurrentReader()->isXMLChar(nextCh))
  652.                 {
  653.                     XMLCh tmpBuf[9];
  654.                     XMLString::binToText
  655.                     (
  656.                         nextCh
  657.                         , tmpBuf
  658.                         , 8
  659.                         , 16
  660.                     );
  661.                     fScanner->emitError(XMLErrs::InvalidCharacter, tmpBuf);
  662.                 }
  663.                 else
  664.                 {
  665.                     fScanner->emitError(XMLErrs::InvalidDocumentStructure);
  666.                 }
  667.                 // Try to get realigned
  668.                 static const XMLCh toSkip[] =
  669.                 {
  670.                     chPercent, chCloseSquare, chOpenAngle, chNull
  671.                 };
  672.                 fReaderMgr->skipUntilInOrWS(toSkip);
  673.             }
  674.             bAcceptDecl = false;
  675.         }
  676.     }
  677.     catch(const EndOfEntityException& toCatch)
  678.     {
  679.         //
  680.         //  If the external entity ended while we were in markup, then that's
  681.         //  a partial markup error.
  682.         //
  683.         if (inMarkup)
  684.         {
  685.             fScanner->emitError(XMLErrs::PartialMarkupInEntity);
  686.             inMarkup = false;
  687.         }
  688.         // If we were in char data, then send what we got
  689.         if (inCharData)
  690.         {
  691.             // Send what we got, then rethrow
  692.             if (fDocTypeHandler)
  693.             {
  694.                 fDocTypeHandler->doctypeWhitespace
  695.                 (
  696.                     bbSpace.getRawBuffer()
  697.                     , bbSpace.getLen()
  698.                 );
  699.             }
  700.             inCharData = false;
  701.         }
  702.         //
  703.         //  If the entity that just ended was the entity that we started
  704.         //  on, then this is the end of the external subset.
  705.         //
  706.         if (orgReader == toCatch.getReaderNum())
  707.             break;
  708.     }
  709.     }
  710.     // If we have a doc type handler, tell it the ext subset ends
  711.     if (fDocTypeHandler && isDTD)
  712.         fDocTypeHandler->endExtSubset();
  713. }
  714. //
  715. //  This method will scan for an id, either public or external.
  716. //
  717. //
  718. // [75] ExternalID ::= 'SYSTEM' S SystemLiteral
  719. //                     | 'PUBLIC' S PubidLiteral S SystemLiteral
  720. // [83] PublicID ::= 'PUBLIC' S PubidLiteral
  721. //
  722. bool DTDScanner::scanId(          XMLBuffer&  pubIdToFill
  723.                             ,       XMLBuffer&  sysIdToFill
  724.                             , const IDTypes     whatKind)
  725. {
  726.     // Clean out both return buffers
  727.     pubIdToFill.reset();
  728.     sysIdToFill.reset();
  729.     //
  730.     //  Check first for the system id first. If we find it, and system id
  731.     //  is one of the legal values, then lets try to scan it.
  732.     //
  733.     // 'SYSTEM' S SystemLiteral
  734.     if (fReaderMgr->skippedString(XMLUni::fgSysIDString))
  735.     {
  736.         // If they were looking for a public id, then we failed
  737.         if (whatKind == IDType_Public)
  738.         {
  739.             fScanner->emitError(XMLErrs::ExpectedPublicId);
  740.             return false;
  741.         }
  742.         // We must skip spaces
  743.         if (!fReaderMgr->skipPastSpaces())
  744.         {
  745.             fScanner->emitError(XMLErrs::ExpectedWhitespace);
  746.             return false;
  747.         }
  748.         // Get the system literal value
  749.         return scanSystemLiteral(sysIdToFill);
  750.     }
  751.     // Now scan for public id
  752.     // 'PUBLIC' S PubidLiteral S SystemLiteral
  753.     //  or
  754.     // 'PUBLIC' S PubidLiteral
  755.     // If we don't have any public id string => Error
  756.     if (!fReaderMgr->skippedString(XMLUni::fgPubIDString)) {
  757.         fScanner->emitError(XMLErrs::ExpectedSystemOrPublicId);
  758.         return false;
  759.     }
  760.     //
  761.     //  So following this we must have whitespace, a public literal, whitespace,
  762.     //  and a system literal.
  763.     //
  764.     if (!fReaderMgr->skipPastSpaces())
  765.     {
  766.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  767.         //
  768.         //  Just in case, if they just forgot the whitespace but the next char
  769.         //  is a single or double quote, then keep going.
  770.         //
  771.         const XMLCh chPeek = fReaderMgr->peekNextChar();
  772.         if ((chPeek != chDoubleQuote) && (chPeek != chSingleQuote))
  773.             return false;
  774.     }
  775.     if (!scanPublicLiteral(pubIdToFill))
  776.         return false;
  777.     // If they wanted a public id, then this is all
  778.     if (whatKind == IDType_Public)
  779.         return true;
  780.     // check if there is any space follows
  781.     bool hasSpace = fReaderMgr->skipPastSpaces();
  782.     //
  783.     //  In order to recover best here we need to see if
  784.     //  the next thing is a quote or not
  785.     //
  786.     const XMLCh chPeek = fReaderMgr->peekNextChar();
  787.     const bool bIsQuote =  ((chPeek == chDoubleQuote)
  788.                          || (chPeek == chSingleQuote));
  789.     if (!hasSpace)
  790.     {
  791.         if (whatKind == IDType_External)
  792.         {
  793.             //
  794.             //  If its an external Id, then we need to see the system id.
  795.             //  So, emit the error. But, if the next char is a quote, don't
  796.             //  give up since its probably going to work. The user just
  797.             //  missed the separating space. Otherwise, fail.
  798.             //
  799.             fScanner->emitError(XMLErrs::ExpectedWhitespace);
  800.             if (!bIsQuote)
  801.                 return false;
  802.         }
  803.          else
  804.         {
  805.             //
  806.             //  We can legally return here. But, if the next char is a quote,
  807.             //  then that's probably not what was desired, since its probably
  808.             //  just that space was forgotten and there really is a system
  809.             //  id to follow.
  810.             //
  811.             //  So treat it like missing whitespace if so and keep going.
  812.             //  Else, just return success.
  813.             //
  814.             if (bIsQuote)
  815.                 fScanner->emitError(XMLErrs::ExpectedWhitespace);
  816.              else
  817.                 return true;
  818.         }
  819.     }
  820.     if (bIsQuote) {
  821.         // there is a quote coming, scan the system literal
  822.         if (!scanSystemLiteral(sysIdToFill))
  823.             return false;
  824.     }
  825.     else {
  826.         // no quote, if expecting exteral id, this is an error
  827.         if (whatKind == IDType_External)
  828.             fScanner->emitError(XMLErrs::ExpectedQuotedString);
  829.     }
  830.     return true;
  831. }
  832. //
  833. //  This method will scan the contents of an ignored section. It assumes that
  834. //  we already are in the body, i.e. we've seen <![IGNORE[ at this point. So
  835. //  we have to just scan until we see a matching ]]> closing markup.
  836. //
  837. void DTDScanner::scanIgnoredSection()
  838. {
  839.     //
  840.     //  Depth starts at one because we are already in one section and want
  841.     //  to parse until we hit its end.
  842.     //
  843.     unsigned long depth = 1;
  844.     bool gotLeadingSurrogate = false;
  845.     while (true)
  846.     {
  847.         const XMLCh nextCh = fReaderMgr->getNextChar();
  848.         if (!nextCh)
  849.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  850.         if (nextCh == chOpenAngle)
  851.         {
  852.             if (fReaderMgr->skippedChar(chBang)
  853.             &&  fReaderMgr->skippedChar(chOpenSquare))
  854.             {
  855.                 depth++;
  856.             }
  857.         }
  858.          else if (nextCh == chCloseSquare)
  859.         {
  860.             if (fReaderMgr->skippedChar(chCloseSquare))
  861.             {
  862.                 while (fReaderMgr->skippedChar(chCloseSquare))
  863.                 {
  864.                     // Do nothing, just skip them
  865.                 }
  866.                 if (fReaderMgr->skippedChar(chCloseAngle))
  867.                 {
  868.                     depth--;
  869.                     if (!depth)
  870.                         break;
  871.                 }
  872.             }
  873.         }
  874.         // Deal with surrogate pairs
  875.         else if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
  876.         {
  877.             //  Its a leading surrogate. If we already got one, then
  878.             //  issue an error, else set leading flag to make sure that
  879.             //  we look for a trailing next time.
  880.             if (gotLeadingSurrogate)
  881.                 fScanner->emitError(XMLErrs::Expected2ndSurrogateChar);
  882.             else
  883.                 gotLeadingSurrogate = true;
  884.         }
  885.         else
  886.         {
  887.             //  If its a trailing surrogate, make sure that we are
  888.             //  prepared for that. Else, its just a regular char so make
  889.             //  sure that we were not expected a trailing surrogate.
  890.             if ((nextCh >= 0xDC00) && (nextCh <= 0xDFFF))
  891.             {
  892.                 // Its trailing, so make sure we were expecting it
  893.                 if (!gotLeadingSurrogate)
  894.                     fScanner->emitError(XMLErrs::Unexpected2ndSurrogateChar);
  895.             }
  896.             else
  897.             {
  898.                 //  Its just a char, so make sure we were not expecting a
  899.                 //  trailing surrogate.
  900.                 if (gotLeadingSurrogate)
  901.                     fScanner->emitError(XMLErrs::Expected2ndSurrogateChar);
  902.                 // Its got to at least be a valid XML character
  903.                 else if (!fReaderMgr->getCurrentReader()->isXMLChar(nextCh))
  904.                 {
  905.                     XMLCh tmpBuf[9];
  906.                     XMLString::binToText
  907.                     (
  908.                         nextCh
  909.                         , tmpBuf
  910.                         , 8
  911.                         , 16
  912.                     );
  913.                     fScanner->emitError(XMLErrs::InvalidCharacter, tmpBuf);
  914.                 }
  915.             }
  916.             gotLeadingSurrogate = false;
  917.         }
  918.     }
  919. }
  920. //
  921. //  This method scans the entire internal subset. All we can have here is
  922. //  decl markup, and PE references. The expanded PE references must contain
  923. //  whole markup, so we don't have to worry about their content at this
  924. //  level. We just scan them, expand them, push them, and parse their content
  925. //  right there, via the expandERef() method.
  926. //
  927. bool DTDScanner::scanInternalSubset()
  928. {
  929.     // Indicate we are in the internal subset now
  930.     FlagJanitor<bool> janContentFlag(&fInternalSubset, true);
  931.     // If we have a doc type handler, tell it the internal subset starts
  932.     if (fDocTypeHandler)
  933.         fDocTypeHandler->startIntSubset();
  934.     // Get a buffer for whitespace
  935.     XMLBufBid bbSpace(fBufMgr);
  936.     bool noErrors = true;
  937.     while (true)
  938.     {
  939.         const XMLCh nextCh = fReaderMgr->peekNextChar();
  940.         //
  941.         //  If we get an end of file marker, just unget it and return a
  942.         //  failure status. The caller will then see the end of file and
  943.         //  faill out correctly.
  944.         //
  945.         if (!nextCh)
  946.             return false;
  947.         // Watch for the end of internal subset marker
  948.         if (nextCh == chCloseSquare)
  949.         {
  950.             fReaderMgr->getNextChar();
  951.             break;
  952.         }
  953.         if (nextCh == chPercent)
  954.         {
  955.             //
  956.             //  Expand (and scan if external) the reference value. Tell
  957.             //  it to set the reader to cause an end of entity exception
  958.             //  when this reader dies, which is what the scanExtSubset
  959.             //  method wants (who is called to scan this.)
  960.             //
  961.             fReaderMgr->getNextChar();
  962.             expandPERef(true, false, false, true);
  963.         }
  964.          else if (nextCh == chOpenAngle)
  965.         {
  966.             // Remember this reader before we start the scan, for checking
  967.             // XML 1.0 P28a Well-formedness constraint: PE Between Declarations
  968.             const unsigned int orgReader = fReaderMgr->getCurrentReaderNum();
  969.             bool wasInPE = (fReaderMgr->getCurrentReader()->getType() == XMLReader::Type_PE);
  970.             // And scan this markup
  971.             fReaderMgr->getNextChar();
  972.             scanMarkupDecl(false);
  973.             // If we did not get back to entry level, then partial markup
  974.             if (fReaderMgr->getCurrentReaderNum() != orgReader) {
  975.                 if (wasInPE)
  976.                     fScanner->emitError(XMLErrs::PEBetweenDecl);
  977.                 else if (fScanner->getDoValidation())
  978.                     fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE);
  979.             }
  980.         }
  981.          else if (fReaderMgr->getCurrentReader()->isWhitespace(nextCh))
  982.         {
  983.             //
  984.             //  IF we are doing advanced callbacks and have a doc type
  985.             //  handler, then get the whitespace and call the doc type
  986.             //  handler with it. Otherwise, just skip whitespace.
  987.             //
  988.             if (fDocTypeHandler)
  989.             {
  990.                 fReaderMgr->getSpaces(bbSpace.getBuffer());
  991.                 fDocTypeHandler->doctypeWhitespace
  992.                 (
  993.                     bbSpace.getRawBuffer()
  994.                     , bbSpace.getLen()
  995.                 );
  996.             }
  997.              else
  998.             {
  999.                 fReaderMgr->skipPastSpaces();
  1000.             }
  1001.         }
  1002.          else
  1003.         {
  1004.             // Not valid, so emit an error
  1005.             XMLCh tmpBuf[9];
  1006.             XMLString::binToText
  1007.             (
  1008.                 fReaderMgr->getNextChar()
  1009.                 , tmpBuf
  1010.                 , 8
  1011.                 , 16
  1012.             );
  1013.             fScanner->emitError
  1014.             (
  1015.                 XMLErrs::InvalidCharacterInIntSubset
  1016.                 , tmpBuf
  1017.             );
  1018.             //
  1019.             //  If an '>', then probably an abnormally terminated
  1020.             //  internal subset so just return.
  1021.             //
  1022.             if (nextCh == chCloseAngle)
  1023.             {
  1024.                 noErrors = false;
  1025.                 break;
  1026.             }
  1027.             //
  1028.             //  Otherwise, try to sync back up by scanning forward for
  1029.             //  a reasonable start character.
  1030.             //
  1031.             static const XMLCh toSkip[] =
  1032.             {
  1033.                 chPercent, chCloseSquare, chOpenAngle, chNull
  1034.             };
  1035.             fReaderMgr->skipUntilInOrWS(toSkip);
  1036.         }
  1037.     }
  1038.     // If we have a doc type handler, tell it the internal subset ends
  1039.     if (fDocTypeHandler)
  1040.         fDocTypeHandler->endIntSubset();
  1041.     return noErrors;
  1042. }
  1043. //
  1044. //  This method is called once we see a < in the input of an int/ext subset,
  1045. //  which indicates the start of some sort of markup.
  1046. //
  1047. void DTDScanner::scanMarkupDecl(const bool parseTextDecl)
  1048. {
  1049.     //
  1050.     //  We only have two valid first characters here. One is a ! which opens
  1051.     //  some markup decl. The other is a ?, which could begin either a PI
  1052.     //  or a text decl. If parseTextDecl is false, we cannot accept a text
  1053.     //  decl.
  1054.     //
  1055.     const XMLCh nextCh = fReaderMgr->getNextChar();
  1056.     if (nextCh == chBang)
  1057.     {
  1058.         if (fReaderMgr->skippedChar(chDash))
  1059.         {
  1060.             if (fReaderMgr->skippedChar(chDash))
  1061.             {
  1062.                 scanComment();
  1063.             }
  1064.              else
  1065.             {
  1066.                 fScanner->emitError(XMLErrs::CommentsMustStartWith);
  1067.                 fReaderMgr->skipPastChar(chCloseAngle);
  1068.             }
  1069.         }
  1070.          else if (fReaderMgr->skippedChar(chOpenSquare))
  1071.         {
  1072.             //
  1073.             //  Its a conditional section. This is only valid in the external
  1074.             //  subset, so issue an error if we aren't there.
  1075.             //
  1076.             if (fInternalSubset)
  1077.             {
  1078.                 fScanner->emitError(XMLErrs::ConditionalSectInIntSubset);
  1079.                 fReaderMgr->skipPastChar(chCloseAngle);
  1080.                 return;
  1081.             }
  1082.             // A PE ref can happen here, but space is not required
  1083.             checkForPERef(false, false, true);
  1084.             if (fReaderMgr->skippedString(XMLUni::fgIncludeString))
  1085.             {
  1086.                 checkForPERef(false, false, true);
  1087.                 // Check for the following open square bracket
  1088.                 if (!fReaderMgr->skippedChar(chOpenSquare))
  1089.                     fScanner->emitError(XMLErrs::ExpectedINCLUDEBracket);
  1090.                 // Get the reader we started this on
  1091.                 const unsigned int orgReader = fReaderMgr->getCurrentReaderNum();
  1092.                 checkForPERef(false, false, true);
  1093.                 //
  1094.                 //  Recurse back to the ext subset call again, telling it its
  1095.                 //  in an include section.
  1096.                 //
  1097.                 scanExtSubsetDecl(true, false);
  1098.                 //
  1099.                 //  And see if we got back to the same level. If not, then its
  1100.                 //  a partial markup error.
  1101.                 //
  1102.                 if (fReaderMgr->getCurrentReaderNum() != orgReader && fScanner->getDoValidation())
  1103.                     fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE);
  1104.             }
  1105.              else if (fReaderMgr->skippedString(XMLUni::fgIgnoreString))
  1106.             {
  1107.                 checkForPERef(false, false, true);
  1108.                 // Check for the following open square bracket
  1109.                 if (!fReaderMgr->skippedChar(chOpenSquare))
  1110.                     fScanner->emitError(XMLErrs::ExpectedINCLUDEBracket);
  1111.                 // Get the reader we started this on
  1112.                 const unsigned int orgReader = fReaderMgr->getCurrentReaderNum();
  1113.                 // And scan over the ignored part
  1114.                 scanIgnoredSection();
  1115.                 //
  1116.                 //  And see if we got back to the same level. If not, then its
  1117.                 //  a partial markup error.
  1118.                 //
  1119.                 if (fReaderMgr->getCurrentReaderNum() != orgReader && fScanner->getDoValidation())
  1120.                     fScanner->getValidator()->emitError(XMLValid::PartialMarkupInPE);
  1121.             }
  1122.              else
  1123.             {
  1124.                 fScanner->emitError(XMLErrs::ExpectedIncOrIgn);
  1125.                 fReaderMgr->skipPastChar(chCloseAngle);
  1126.             }
  1127.         }
  1128.          else if (fReaderMgr->skippedString(XMLUni::fgAttListString))
  1129.         {
  1130.             scanAttListDecl();
  1131.         }
  1132.          else if (fReaderMgr->skippedString(XMLUni::fgElemString))
  1133.         {
  1134.             scanElementDecl();
  1135.         }
  1136.          else if (fReaderMgr->skippedString(XMLUni::fgEntityString))
  1137.         {
  1138.             scanEntityDecl();
  1139.         }
  1140.          else if (fReaderMgr->skippedString(XMLUni::fgNotationString))
  1141.         {
  1142.             scanNotationDecl();
  1143.         }
  1144.          else
  1145.         {
  1146.             fScanner->emitError(XMLErrs::ExpectedMarkupDecl);
  1147.             fReaderMgr->skipPastChar(chCloseAngle);
  1148.         }
  1149.     }
  1150.      else if (nextCh == chQuestion)
  1151.     {
  1152.         // It could be a PI or the XML declaration. Check for Decl
  1153.         if (fScanner->checkXMLDecl(false))
  1154.         {
  1155.             // If we are not accepting text decls, its an error
  1156.             if (parseTextDecl)
  1157.             {
  1158.                 scanTextDecl();
  1159.             }
  1160.              else
  1161.             {
  1162.                 // Emit the error and skip past this markup
  1163.                 fScanner->emitError(XMLErrs::TextDeclNotLegalHere);
  1164.                 fReaderMgr->skipPastChar(chCloseAngle);
  1165.             }
  1166.         }
  1167.          else
  1168.         {
  1169.             // It has to be a PI
  1170.             scanPI();
  1171.         }
  1172.     }
  1173.      else
  1174.     {
  1175.         // Can't be valid so emit error and try to skip past end of this decl
  1176.         fScanner->emitError(XMLErrs::ExpectedMarkupDecl);
  1177.         fReaderMgr->skipPastChar(chCloseAngle);
  1178.     }
  1179. }
  1180. //
  1181. //  This method is called for a mixed model element's content mode. We've
  1182. //  already scanned past the '(PCDATA' part by the time we get here. So
  1183. //  everything else is element names separated by | characters until we
  1184. //  hit the end. The passed element decl's content model is filled in with
  1185. //  the information found.
  1186. //
  1187. bool DTDScanner::scanMixed(DTDElementDecl& toFill)
  1188. {
  1189.     //
  1190.     //  The terminating star is only required if there is something more
  1191.     //  than (PCDATA).
  1192.     //
  1193.     bool starRequired = false;
  1194.     // Get a buffer to be used below to get element names
  1195.     XMLBufBid bbName(fBufMgr);
  1196.     XMLBuffer& nameBuf = bbName.getBuffer();
  1197.     //
  1198.     //  Create an initial content spec node. Its just a leaf node with a
  1199.     //  PCDATA element id. This current node pointer will be pushed down the
  1200.     //  tree as we go.
  1201.     //
  1202.     ContentSpecNode* curNode = new (fMemoryManager) ContentSpecNode
  1203.     (
  1204.         new (fMemoryManager) QName
  1205.         (
  1206.             XMLUni::fgZeroLenString
  1207.             , XMLUni::fgZeroLenString
  1208.             , XMLElementDecl::fgPCDataElemId
  1209.             , fMemoryManager
  1210.         )
  1211.         , false
  1212.         , fMemoryManager
  1213.     );
  1214.     //
  1215.     //  Set the initial leaf as the temporary head. If we hit the first choice
  1216.     //  node, it will be set up here. When done, this is the node that's set
  1217.     //  as the content spec for the element.
  1218.     //
  1219.     ContentSpecNode* headNode = curNode;
  1220.     // Remember the original node so we can sense the first choice node
  1221.     ContentSpecNode* orgNode = curNode;
  1222.     //
  1223.     //  We just loop around, getting the | character at the top and then
  1224.     //  looking for the next element name. We keep up with the last node
  1225.     //  and add each new one to its right node.
  1226.     //
  1227.     while (true)
  1228.     {
  1229.         //
  1230.         //  First of all we check for some grunt work details of skipping
  1231.         //  whitespace, expand PE refs, and catching invalid reps.
  1232.         //
  1233.         if (fReaderMgr->lookingAtChar(chPercent))
  1234.         {
  1235.             // Expand it and continue
  1236.             checkForPERef(false, false, true);
  1237.         }
  1238.          else if (fReaderMgr->skippedChar(chAsterisk))
  1239.         {
  1240.             //
  1241.             //  Tell them they can't have reps in mixed model, but eat
  1242.             //  it and keep going if we are allowed to.
  1243.             //
  1244.             fScanner->emitError(XMLErrs::NoRepInMixed);
  1245.         }
  1246.          else if (fReaderMgr->skippedSpace())
  1247.         {
  1248.             // Spaces are ok at this point, just eat them and continue
  1249.             fReaderMgr->skipPastSpaces();
  1250.         }
  1251.          else
  1252.         {
  1253.             if (!fReaderMgr->skippedChar(chPipe))
  1254.             {
  1255.                 // Has to be the closing paren now.
  1256.                 if (!fReaderMgr->skippedChar(chCloseParen))
  1257.                 {
  1258.                     delete headNode;
  1259.                     fScanner->emitError(XMLErrs::UnterminatedContentModel);
  1260.                     return false;
  1261.                 }
  1262.                 bool starSkipped = true;
  1263.                 if (!fReaderMgr->skippedChar(chAsterisk)) {
  1264.                     starSkipped = false;
  1265.                     if (starRequired)
  1266.                         fScanner->emitError(XMLErrs::ExpectedAsterisk);
  1267.                 }
  1268.                 //
  1269.                 //  Create a zero or more node and make the original head
  1270.                 //  node its first child.
  1271.                 //
  1272.                 if (starRequired || starSkipped) {
  1273.                     headNode = new (fMemoryManager) ContentSpecNode
  1274.                     (
  1275.                         ContentSpecNode::ZeroOrMore
  1276.                         , headNode
  1277.                         , 0
  1278.                         , true
  1279.                         , true
  1280.                         , fMemoryManager
  1281.                     );
  1282.                 }
  1283.                 // Store the head node as the content spec of the element.
  1284.                 toFill.setContentSpec(headNode);
  1285.                 break;
  1286.             }
  1287.             // Its more than just a PCDATA, so an ending star will be required now
  1288.             starRequired = true;
  1289.             // Space is legal here so check for a PE ref, but don't require space
  1290.             checkForPERef(false, false, true);
  1291.             // Get a name token
  1292.             if (!fReaderMgr->getName(nameBuf))
  1293.             {
  1294.                 delete headNode;
  1295.                 fScanner->emitError(XMLErrs::ExpectedElementName);
  1296.                 return false;
  1297.             }
  1298.             //
  1299.             //  Create a leaf node for it. If we can find the element id for
  1300.             //  this element, then use it. Else, we have to fault in an element
  1301.             //  decl, marked as created because of being in a content model.
  1302.             //
  1303.             XMLElementDecl* decl = fDTDGrammar->getElemDecl(fEmptyNamespaceId, 0, nameBuf.getRawBuffer(), Grammar::TOP_LEVEL_SCOPE);
  1304.             if (!decl)
  1305.             {
  1306.                 decl = new (fMemoryManager) DTDElementDecl
  1307.                 (
  1308.                     nameBuf.getRawBuffer()
  1309.                     , fEmptyNamespaceId
  1310.                     , DTDElementDecl::Any
  1311.                     , fMemoryManager
  1312.                 );
  1313.                 decl->setCreateReason(XMLElementDecl::InContentModel);
  1314.                 decl->setExternalElemDeclaration(isReadingExternalEntity());
  1315.                 fDTDGrammar->putElemDecl(decl);
  1316.             }
  1317.             //
  1318.             //  If the current node is the original node, this is the first choice
  1319.             //  node, so create an initial choice node with the current node and
  1320.             //  the new element id. Store this as the head node.
  1321.             //
  1322.             //  Otherwise, we have to steal the right node of the previous choice
  1323.             //  and weave in another choice node there, which has the old choice
  1324.             //  as its left and the new leaf as its right.
  1325.             //
  1326.             if (curNode == orgNode)
  1327.             {
  1328.                 curNode = new (fMemoryManager) ContentSpecNode
  1329.                 (
  1330.                     ContentSpecNode::Choice
  1331.                     , curNode
  1332.                     , new (fMemoryManager) ContentSpecNode
  1333.                       (
  1334.                           decl->getElementName()
  1335.                           , fMemoryManager
  1336.                       )
  1337.                     , true
  1338.                     , true
  1339.                     , fMemoryManager
  1340.                 );
  1341.                 // Remember the top node
  1342.                 headNode = curNode;
  1343.             }
  1344.              else
  1345.             {
  1346.                 ContentSpecNode* oldRight = curNode->orphanSecond();
  1347.                 curNode->setSecond
  1348.                 (
  1349.                     new (fMemoryManager) ContentSpecNode
  1350.                     (
  1351.                         ContentSpecNode::Choice
  1352.                         , oldRight
  1353.                         , new (fMemoryManager) ContentSpecNode
  1354.                           (
  1355.                               decl->getElementName()
  1356.                               , fMemoryManager
  1357.                           )
  1358.                         , true
  1359.                         , true
  1360.                         , fMemoryManager
  1361.                     )
  1362.                 );
  1363.                 // Make the new right node the current node
  1364.                 curNode = curNode->getSecond();
  1365.             }
  1366.         }
  1367.     }
  1368.     return true;
  1369. }
  1370. //
  1371. //  This method is called when we see a '<!NOTATION' string while scanning
  1372. //  markup decl. It parses out the notation and its id and stores a new
  1373. //  notation decl object in the notation decl pool.
  1374. //
  1375. void DTDScanner::scanNotationDecl()
  1376. {
  1377.     // Space is required here so check for a PE ref, and require space
  1378.     if (!checkForPERef(true, false, true))
  1379.     {
  1380.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  1381.         fReaderMgr->skipPastChar(chCloseAngle);
  1382.         return;
  1383.     }
  1384.     //
  1385.     //  And now we get a name, which is the name of the notation. Get a
  1386.     //  buffer for the name.
  1387.     //
  1388.     XMLBufBid bbName(fBufMgr);
  1389.     if (!fReaderMgr->getName(bbName.getBuffer()))
  1390.     {
  1391.         fScanner->emitError(XMLErrs::ExpectedNotationName);
  1392.         fReaderMgr->skipPastChar(chCloseAngle);
  1393.         return;
  1394.     }
  1395.     // If namespaces are enabled, then no colons allowed
  1396.     if (fScanner->getDoNamespaces())
  1397.     {
  1398.         if (XMLString::indexOf(bbName.getRawBuffer(), chColon) != -1)
  1399.             fScanner->emitError(XMLErrs::ColonNotLegalWithNS);
  1400.     }
  1401.     // Space is required here so check for a PE ref, and require space
  1402.     if (!checkForPERef(true, false, true))
  1403.     {
  1404.         fScanner->emitError(XMLErrs::ExpectedWhitespace);
  1405.         fReaderMgr->skipPastChar(chCloseAngle);
  1406.         return;
  1407.     }
  1408.     //
  1409.     //  And scan an external or public id. We need buffers to use for both
  1410.     //  of these.
  1411.     //
  1412.     XMLBufBid bbPubId(fBufMgr);
  1413.     XMLBufBid bbSysId(fBufMgr);
  1414.     if (!scanId(bbPubId.getBuffer(), bbSysId.getBuffer(), IDType_Either))
  1415.     {
  1416.         fReaderMgr->skipPastChar(chCloseAngle);
  1417.         return;
  1418.     }
  1419.     // We can have an optional space or PE ref here
  1420.     checkForPERef(false, false, true);
  1421.     //
  1422.     //  See if it already exists. If so, add it to the notatino decl pool.
  1423.     //  Otherwise, if advanced callbacks are on, create a temp one and
  1424.     //  call out for that one.
  1425.     //
  1426.     XMLNotationDecl* decl = fDTDGrammar->getNotationDecl(bbName.getRawBuffer());
  1427.     bool isIgnoring = (decl != 0);
  1428.     if (isIgnoring)
  1429.     {
  1430.         fScanner->emitError(XMLErrs::NotationAlreadyExists, bbName.getRawBuffer());
  1431.     }
  1432.      else
  1433.     {
  1434.         // Fill in a new notation declaration and add it to the pool
  1435.         const XMLCh* publicId = bbPubId.getRawBuffer();
  1436.         const XMLCh* systemId = bbSysId.getRawBuffer();
  1437.         ReaderMgr::LastExtEntityInfo lastInfo;
  1438.         fReaderMgr->getLastExtEntityInfo(lastInfo);
  1439.         decl = new (fMemoryManager) XMLNotationDecl
  1440.         (
  1441.             bbName.getRawBuffer()
  1442.             , (publicId && *publicId) ? publicId : 0
  1443.             , (systemId && *systemId) ? systemId : 0
  1444.             , (lastInfo.systemId && *lastInfo.systemId) ? lastInfo.systemId : 0
  1445.             , fMemoryManager
  1446.         );
  1447.         fDTDGrammar->putNotationDecl(decl);
  1448.     }
  1449.     //
  1450.     //  If we have a document type handler, then tell it about this. If we
  1451.     //  are ignoring it, only call out if advanced callbacks are enabled.
  1452.     //
  1453.     if (fDocTypeHandler)
  1454.     {
  1455.         fDocTypeHandler->notationDecl
  1456.         (
  1457.             *decl
  1458.             , isIgnoring
  1459.         );
  1460.     }
  1461.     // And one more optional space or PE ref
  1462.     checkForPERef(false, false, true);
  1463.     // And skip the terminating bracket
  1464.     if (!fReaderMgr->skippedChar(chCloseAngle))
  1465.         fScanner->emitError(XMLErrs::UnterminatedNotationDecl);
  1466. }
  1467. //
  1468. //  Scans a PI and calls the appropriate callbacks. A PI can happen in either
  1469. //  the document or the DTD, so it calls the appropriate handler according
  1470. //  to the fInDocument flag.
  1471. //
  1472. //  At entry we have just scanned the <? part, and need to now start on the
  1473. //  PI target name.
  1474. //
  1475. void DTDScanner::scanPI()
  1476. {
  1477.     const XMLCh* namePtr = 0;
  1478.     const XMLCh* targetPtr = 0;
  1479.     //
  1480.     //  If there are any spaces here, then warn about it. If we aren't in
  1481.     //  'first error' mode, then we'll come back and can easily pick up
  1482.     //  again by just skipping them.
  1483.     //
  1484.     if (fReaderMgr->lookingAtSpace())
  1485.     {
  1486.         fScanner->emitError(XMLErrs::PINameExpected);
  1487.         fReaderMgr->skipPastSpaces();
  1488.     }
  1489.     // Get a buffer for the PI name and scan it in
  1490.     XMLBufBid bbName(fBufMgr);
  1491.     if (!fReaderMgr->getName(bbName.getBuffer()))
  1492.     {
  1493.         fScanner->emitError(XMLErrs::PINameExpected);
  1494.         fReaderMgr->skipPastChar(chCloseAngle);
  1495.         return;
  1496.     }
  1497.     // Point the name pointer at the raw data
  1498.     namePtr = bbName.getRawBuffer();
  1499.     // See if it issome form of 'xml' and emit a warning
  1500.     if (!XMLString::compareIString(namePtr, XMLUni::fgXMLString))
  1501.         fScanner->emitError(XMLErrs::NoPIStartsWithXML);
  1502.     // If namespaces are enabled, then no colons allowed
  1503.     if (fScanner->getDoNamespaces())
  1504.     {
  1505.         if (XMLString::indexOf(namePtr, chColon) != -1)
  1506.             fScanner->emitError(XMLErrs::ColonNotLegalWithNS);
  1507.     }
  1508.     //
  1509.     //  If we don't hit a space next, then the PI has no target. If we do
  1510.     //  then get out the target. Get a buffer for it as well
  1511.     //
  1512.     XMLBufBid bbTarget(fBufMgr);
  1513.     if (fReaderMgr->skippedSpace())
  1514.     {
  1515.         // Skip any leading spaces
  1516.         fReaderMgr->skipPastSpaces();
  1517.         bool gotLeadingSurrogate = false;
  1518.         // It does have a target, so lets move on to deal with that.
  1519.         while (1)
  1520.         {
  1521.             const XMLCh nextCh = fReaderMgr->getNextChar();
  1522.             // Watch for an end of file, which is always bad here
  1523.             if (!nextCh)
  1524.             {
  1525.                 fScanner->emitError(XMLErrs::UnterminatedPI);
  1526.                 ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  1527.             }
  1528.             // Watch for potential terminating character
  1529.             if (nextCh == chQuestion)
  1530.             {
  1531.                 // It must be followed by '>' to be a termination of the target
  1532.                 if (fReaderMgr->skippedChar(chCloseAngle))
  1533.                     break;
  1534.             }
  1535.             // Check for correct surrogate pairs
  1536.             if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
  1537.             {
  1538.                 if (gotLeadingSurrogate)
  1539.                     fScanner->emitError(XMLErrs::Expected2ndSurrogateChar);
  1540.                 else
  1541.                     gotLeadingSurrogate = true;
  1542.             }
  1543.              else
  1544.             {
  1545.                 if (gotLeadingSurrogate)
  1546.                 {
  1547.                     if ((nextCh < 0xDC00) || (nextCh > 0xDFFF))
  1548.                         fScanner->emitError(XMLErrs::Expected2ndSurrogateChar);
  1549.                 }
  1550.                 // Its got to at least be a valid XML character
  1551.                 else if (!fReaderMgr->getCurrentReader()->isXMLChar(nextCh)) {
  1552.                     XMLCh tmpBuf[9];
  1553.                     XMLString::binToText
  1554.                     (
  1555.                         nextCh
  1556.                         , tmpBuf
  1557.                         , 8
  1558.                         , 16
  1559.                     );
  1560.                     fScanner->emitError(XMLErrs::InvalidCharacter, tmpBuf);
  1561.                 }
  1562.                 gotLeadingSurrogate = false;
  1563.             }
  1564.             bbTarget.append(nextCh);
  1565.         }
  1566.     }
  1567.      else
  1568.     {
  1569.         // No target, but make sure its terminated ok
  1570.         if (!fReaderMgr->skippedChar(chQuestion))
  1571.         {
  1572.             fScanner->emitError(XMLErrs::UnterminatedPI);
  1573.             fReaderMgr->skipPastChar(chCloseAngle);
  1574.             return;
  1575.         }
  1576.         if (!fReaderMgr->skippedChar(chCloseAngle))
  1577.         {
  1578.             fScanner->emitError(XMLErrs::UnterminatedPI);
  1579.             fReaderMgr->skipPastChar(chCloseAngle);
  1580.             return;
  1581.         }
  1582.     }
  1583.     // Point the target pointer at the raw data
  1584.     targetPtr = bbTarget.getRawBuffer();
  1585.     //
  1586.     //  If we have a handler, then call it.
  1587.     //
  1588.     if (fDocTypeHandler)
  1589.     {
  1590.         fDocTypeHandler->doctypePI
  1591.         (
  1592.             namePtr
  1593.             , targetPtr
  1594.         );
  1595.     }
  1596. }
  1597. //
  1598. //  This method scans a public literal. It must be quoted and all of its
  1599. //  characters must be valid public id characters. The quotes are discarded
  1600. //  and the results are returned.
  1601. //
  1602. bool DTDScanner::scanPublicLiteral(XMLBuffer& toFill)
  1603. {
  1604.     toFill.reset();
  1605.     // Get the next char which must be a single or double quote
  1606.     XMLCh quoteCh;
  1607.     if (!fReaderMgr->skipIfQuote(quoteCh)) {
  1608.         fScanner->emitError(XMLErrs::ExpectedQuotedString);
  1609.         return false;
  1610.     }
  1611.     while (true)
  1612.     {
  1613.         const XMLCh nextCh = fReaderMgr->getNextChar();
  1614.         // Watch for EOF
  1615.         if (!nextCh)
  1616.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  1617.         if (nextCh == quoteCh)
  1618.             break;
  1619.         //
  1620.         //  If its not a valid public id char, then report it but keep going
  1621.         //  since that's the best recovery scheme.
  1622.         //
  1623.         if (!fReaderMgr->getCurrentReader()->isPublicIdChar(nextCh))
  1624.         {
  1625.             XMLCh tmpBuf[9];
  1626.             XMLString::binToText
  1627.             (
  1628.                 nextCh
  1629.                 , tmpBuf
  1630.                 , 8
  1631.                 , 16
  1632.             );
  1633.             fScanner->emitError(XMLErrs::InvalidPublicIdChar, tmpBuf);
  1634.         }
  1635.         toFill.append(nextCh);
  1636.     }
  1637.     return true;
  1638. }
  1639. //
  1640. //  This method handles scanning in a quoted system literal. It expects to
  1641. //  start on the open quote and returns after eating the ending quote. There
  1642. //  are not really any restrictions on the contents of system literals.
  1643. //
  1644. bool DTDScanner::scanSystemLiteral(XMLBuffer& toFill)
  1645. {
  1646.     toFill.reset();
  1647.     // Get the next char which must be a single or double quote
  1648.     XMLCh quoteCh;
  1649.     if (!fReaderMgr->skipIfQuote(quoteCh)) {
  1650.         fScanner->emitError(XMLErrs::ExpectedQuotedString);
  1651.         return false;
  1652.     }
  1653.     while (true)
  1654.     {
  1655.         const XMLCh nextCh = fReaderMgr->getNextChar();
  1656.         // Watch for EOF
  1657.         if (!nextCh)
  1658.             ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);
  1659.         // Break out on terminating quote
  1660.         if (nextCh == quoteCh)
  1661.             break;
  1662.         toFill.append(nextCh);
  1663.     }
  1664.     return true;
  1665. }
  1666. //
  1667. //  This method is called to scan a text decl line, which can be the first
  1668. //  line in an external entity or external subset.
  1669. //
  1670. //  On entry the <? has been scanned, and next should be 'xml' followed by
  1671. //  some whitespace, version string, etc...
  1672. //    [77] TextDecl::= '<?xml' VersionInfo? EncodingDecl S? '?>'
  1673. //
  1674. void DTDScanner::scanTextDecl()
  1675. {
  1676.     // Skip any subsequent whitespace before the version string
  1677.     fReaderMgr->skipPastSpaces();
  1678.     // Next should be the version string
  1679.     XMLBufBid bbVersion(fBufMgr);
  1680.     if (fReaderMgr->skippedString(XMLUni::fgVersionString))
  1681.     {
  1682.         if (!scanEq())
  1683.         {
  1684.             fScanner->emitError(XMLErrs::ExpectedEqSign);
  1685.             fReaderMgr->skipPastChar(chCloseAngle);
  1686.             return;
  1687.         }
  1688.         //
  1689.         //  Followed by a single or double quoted version. Get a buffer for
  1690.         //  the string.
  1691.         //
  1692.         if (!getQuotedString(bbVersion.getBuffer()))
  1693.         {
  1694.             fScanner->emitError(XMLErrs::BadXMLVersion);
  1695.             fReaderMgr->skipPastChar(chCloseAngle);
  1696.             return;
  1697.         }
  1698.         // If its not our supported version, issue an error but continue
  1699.         if (XMLString::equals(bbVersion.getRawBuffer(), XMLUni::fgVersion1_1)) {
  1700.             if (fScanner->getXMLVersion() != XMLReader::XMLV1_1)
  1701.              fScanner->emitError(XMLErrs::UnsupportedXMLVersion, bbVersion.getRawBuffer());
  1702.         }
  1703.         else if (!XMLString::equals(bbVersion.getRawBuffer(), XMLUni::fgVersion1_0))
  1704.             fScanner->emitError(XMLErrs::UnsupportedXMLVersion, bbVersion.getRawBuffer());
  1705.     }
  1706.     // Ok, now we must have an encoding string
  1707.     XMLBufBid bbEncoding(fBufMgr);
  1708.     fReaderMgr->skipPastSpaces();
  1709.     bool gotEncoding = false;
  1710.     if (fReaderMgr->skippedString(XMLUni::fgEncodingString))
  1711.     {
  1712.         // There must be a equal sign next
  1713.         if (!scanEq())
  1714.         {
  1715.             fScanner->emitError(XMLErrs::ExpectedEqSign);
  1716.             fReaderMgr->skipPastChar(chCloseAngle);
  1717.             return;
  1718.         }
  1719.         // Followed by a single or double quoted version string
  1720.         getQuotedString(bbEncoding.getBuffer());
  1721.         if (bbEncoding.isEmpty() || !XMLString::isValidEncName(bbEncoding.getRawBuffer()))
  1722.         {
  1723.             fScanner->emitError(XMLErrs::BadXMLEncoding, bbEncoding.getRawBuffer());
  1724.             fReaderMgr->skipPastChar(chCloseAngle);
  1725.             return;
  1726.         }
  1727.         // Indicate that we got an encoding
  1728.         gotEncoding = true;
  1729.     }
  1730.     //
  1731.     // Encoding declarations are required in the external entity
  1732.     // if there is a text declaration present
  1733.     //
  1734.     if (!gotEncoding)
  1735.     {
  1736.       fScanner->emitError(XMLErrs::EncodingRequired);
  1737.       fReaderMgr->skipPastChar(chCloseAngle);
  1738.       return;
  1739.     }
  1740.     fReaderMgr->skipPastSpaces();
  1741.     if (!fReaderMgr->skippedChar(chQuestion))
  1742.     {
  1743.         fScanner->emitError(XMLErrs::UnterminatedXMLDecl);
  1744.         fReaderMgr->skipPastChar(chCloseAngle);
  1745.     }
  1746.      else if (!fReaderMgr->skippedChar(chCloseAngle))
  1747.     {
  1748.         fScanner->emitError(XMLErrs::UnterminatedXMLDecl);
  1749.         fReaderMgr->skipPastChar(chCloseAngle);
  1750.     }
  1751.     //
  1752.     //  If we have a document type handler and advanced callbacks are on,
  1753.     //  then call the TextDecl callback
  1754.     //
  1755.     if (fDocTypeHandler)
  1756.     {
  1757.         fDocTypeHandler->TextDecl
  1758.         (
  1759.             bbVersion.getRawBuffer()
  1760.             , bbEncoding.getRawBuffer()
  1761.         );
  1762.     }
  1763.     //
  1764.     //  If we got an encoding string, then we have to call back on the reader
  1765.     //  to tell it what the encoding is.
  1766.     //
  1767.     if (!bbEncoding.isEmpty())
  1768.     {
  1769.         if (!fReaderMgr->getCurrentReader()->setEncoding(bbEncoding.getRawBuffer()))
  1770.             fScanner->emitError(XMLErrs::ContradictoryEncoding, bbEncoding.getRawBuffer());
  1771.     }
  1772. }
  1773. XERCES_CPP_NAMESPACE_END