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

词法分析

开发平台:

Visual C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  *
  4.  * Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  *
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  *
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  *
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  *
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written
  29.  *    permission, please contact apache@apache.org.
  30.  *
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their name, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 1999, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Id: DTDValidator.cpp,v 1.14 2003/05/16 21:43:19 knoaman Exp $
  58.  */
  59. // ---------------------------------------------------------------------------
  60. //  Includes
  61. // ---------------------------------------------------------------------------
  62. #include <xercesc/util/Janitor.hpp>
  63. #include <xercesc/util/XMLUniDefs.hpp>
  64. #include <xercesc/util/XMLUni.hpp>
  65. #include <xercesc/internal/ReaderMgr.hpp>
  66. #include <xercesc/internal/XMLScanner.hpp>
  67. #include <xercesc/validators/DTD/DTDValidator.hpp>
  68. XERCES_CPP_NAMESPACE_BEGIN
  69. // ---------------------------------------------------------------------------
  70. //  DTDValidator: Constructors and Destructor
  71. // ---------------------------------------------------------------------------
  72. DTDValidator::DTDValidator(XMLErrorReporter* const errReporter) :
  73.     XMLValidator(errReporter)
  74.     , fDTDGrammar(0)
  75. {
  76.     reset();
  77. }
  78. DTDValidator::~DTDValidator()
  79. {
  80. }
  81. // ---------------------------------------------------------------------------
  82. //  DTDValidator: Implementation of the XMLValidator interface
  83. // ---------------------------------------------------------------------------
  84. int DTDValidator::checkContent(XMLElementDecl* const elemDecl
  85.                               , QName** const        children
  86.                               , const unsigned int   childCount)
  87. {
  88.     //
  89.     //  Look up the element id in our element decl pool. This will get us
  90.     //  the element decl in our own way of looking at them.
  91.     //
  92.     if (!elemDecl)
  93.         ThrowXML(RuntimeException, XMLExcepts::Val_InvalidElemId);
  94.     //
  95.     //  Get the content spec type of this element. This will tell us what
  96.     //  to do to validate it.
  97.     //
  98.     const DTDElementDecl::ModelTypes modelType = ((DTDElementDecl*) elemDecl)->getModelType();
  99.     if (modelType == DTDElementDecl::Empty)
  100.     {
  101.         //
  102.         //  We can do this one here. It cannot have any children. If it does
  103.         //  we return 0 as the index of the first bad child.
  104.         //
  105.         if (childCount)
  106.             return 0;
  107.     }
  108.      else if (modelType == DTDElementDecl::Any)
  109.     {
  110.         // We pass no judgement on this one, anything goes
  111.     }
  112.      else if ((modelType == DTDElementDecl::Mixed_Simple)
  113.           ||  (modelType == DTDElementDecl::Children))
  114.     {
  115.         // Get the element's content model or fault it in
  116.         const XMLContentModel* elemCM = elemDecl->getContentModel();
  117.         // Ask it to validate and return its return
  118.         return elemCM->validateContent(children, childCount, getScanner()->getEmptyNamespaceId());
  119.     }
  120.      else
  121.     {
  122.         ThrowXML(RuntimeException, XMLExcepts::CM_UnknownCMType);
  123.     }
  124.     // Went ok, so return success
  125.     return -1;
  126. }
  127. void DTDValidator::faultInAttr(XMLAttr& toFill, const XMLAttDef& attDef) const
  128. {
  129.     //
  130.     //  At this level, we cannot set the URI id. So we just set it to zero
  131.     //  and leave it at that. The scanner, who called us, will look at the
  132.     //  prefix we stored (if any), resolve it, and store the URL id if any.
  133.     //
  134.     const XMLCh* fullName = attDef.getFullName();
  135.     const int colonInd = XMLString::indexOf(fullName, chColon);
  136.     if (colonInd == -1)
  137.     {
  138.         // There is no prefix, so we just do a simple and quick setting
  139.         toFill.set
  140.         (
  141.             0
  142.             , fullName
  143.             , XMLUni::fgZeroLenString
  144.             , attDef.getValue()
  145.             , attDef.getType()
  146.         );
  147.     }
  148.      else
  149.     {
  150.         //
  151.         //  There is a colon, so we have to split apart the name and prefix
  152.         //  part.
  153.         //
  154.         XMLCh* tmpNameBuf = XMLString::replicate(fullName);
  155.         ArrayJanitor<XMLCh> janNameBuf(tmpNameBuf);
  156.         // Put a null where the colon is, to split it into two strings
  157.         tmpNameBuf[colonInd] = chNull;
  158.         //
  159.         //  And now we can set the attribute object with the prefix and name
  160.         //  parts.
  161.         //
  162.         toFill.set
  163.         (
  164.             0
  165.             , &tmpNameBuf[colonInd+1]
  166.             , tmpNameBuf
  167.             , attDef.getValue()
  168.             , attDef.getType()
  169.         );
  170.     }
  171. }
  172. void DTDValidator::reset()
  173. {
  174. }
  175. bool DTDValidator::requiresNamespaces() const
  176. {
  177.     // Namespaces are not supported for DTDs
  178.     return false;
  179. }
  180. void
  181. DTDValidator::validateAttrValue(const   XMLAttDef*      attDef
  182.                                 , const XMLCh* const    attrValue
  183.                                 , bool                  preValidation
  184.                                 , const XMLElementDecl* elemDecl)
  185. {
  186.     //
  187.     //  Get quick refs to lost of of the stuff in the passed objects in
  188.     //  order to simplify the code below, which will reference them very
  189.     //  often.
  190.     //
  191.     const XMLAttDef::AttTypes       type = attDef->getType();
  192.     const XMLAttDef::DefAttTypes    defType = attDef->getDefaultType();
  193.     const XMLCh* const              valueText = attDef->getValue();
  194.     const XMLCh* const              fullName = attDef->getFullName();
  195.     const XMLCh* const              enumList = attDef->getEnumeration();
  196.     //
  197.     //  If the default type is fixed, then make sure the passed value maps
  198.     //  to the fixed value.
  199.     //  If during preContentValidation, the value we are validating is the fixed value itself
  200.     //  so no need to compare.
  201.     //  Only need to do this for regular attribute value validation
  202.     //
  203.     if (defType == XMLAttDef::Fixed && !preValidation)
  204.     {
  205.         if (!XMLString::equals(attrValue, valueText))
  206.             emitError(XMLValid::NotSameAsFixedValue, fullName, attrValue, valueText);
  207.     }
  208.     //
  209.     //  If its a CDATA attribute, then we are done with any DTD level
  210.     //  validation else do the rest.
  211.     //
  212.     if (type == XMLAttDef::CData)
  213.         return;
  214.     // An empty string cannot be valid for any of the other types
  215.     if (!attrValue[0])
  216.     {
  217.         emitError(XMLValid::InvalidEmptyAttValue, fullName);
  218.         return;
  219.     }
  220.     // See whether we are doing multiple values or not
  221.     const bool multipleValues =
  222.     (
  223.         (type == XMLAttDef::IDRefs)
  224.         || (type == XMLAttDef::Entities)
  225.         || (type == XMLAttDef::NmTokens)
  226.         || (type == XMLAttDef::Notation)
  227.         || (type == XMLAttDef::Enumeration)
  228.     );
  229.     // And whether we must check for a first name char
  230.     const bool firstNameChar =
  231.     (
  232.         (type == XMLAttDef::ID)
  233.         || (type == XMLAttDef::IDRef)
  234.         || (type == XMLAttDef::IDRefs)
  235.         || (type == XMLAttDef::Entity)
  236.         || (type == XMLAttDef::Entities)
  237.         || (type == XMLAttDef::Notation)
  238.     );
  239.     // Whether it requires ref checking stuff
  240.     const bool isARefType
  241.     (
  242.         (type == XMLAttDef::ID)
  243.         || (type == XMLAttDef::IDRef)
  244.         || (type == XMLAttDef::IDRefs)
  245.     );
  246.     // Some trigger flags to avoid issuing redundant errors and whatnot
  247.     bool sawOneValue;
  248.     bool alreadyCapped = false;
  249.     //
  250.     //  Make a copy of the text that we can mangle and get a pointer we can
  251.     //  move through the value
  252.     //
  253.     // Use a stack-based buffer, when possible...
  254.     XMLCh   tempBuffer[100];
  255.     XMLCh* pszTmpVal = 0;
  256.     ArrayJanitor<XMLCh> janTmpVal(0);
  257.     if (XMLString::stringLen(attrValue) < sizeof(tempBuffer) / sizeof(tempBuffer[0]))
  258.     {
  259.         XMLString::copyString(tempBuffer, attrValue);
  260.         pszTmpVal = tempBuffer;
  261.     }
  262.     else
  263.     {
  264.         janTmpVal.reset(XMLString::replicate(attrValue));
  265.         pszTmpVal = janTmpVal.get();
  266.     }
  267.     XMLCh* valPtr = pszTmpVal;
  268.     bool doNamespace = getScanner()->getDoNamespaces();
  269.     while (true)
  270.     {
  271.         // Reset the trigger flags
  272.         sawOneValue = false;
  273.         //
  274.         //  Make sure the first character is a valid first name char, i.e.
  275.         //  if its a Name value. For NmToken values we don't treat the first
  276.         //  char any differently.
  277.         //
  278.         if (firstNameChar)
  279.         {
  280.             // If its not, emit and error but try to keep going
  281.             if (!getReaderMgr()->getCurrentReader()->isFirstNameChar(*valPtr))
  282.                 emitError(XMLValid::AttrValNotName, fullName);
  283.             valPtr++;
  284.         }
  285.         // Make sure all the remaining chars are valid name chars
  286.         while (*valPtr)
  287.         {
  288.             //
  289.             //  If we hit a whitespace, its either a break between two
  290.             //  or more values, or an error if we have a single value.
  291.             //
  292.             if (getReaderMgr()->getCurrentReader()->isWhitespace(*valPtr))
  293.             {
  294.                 if (!multipleValues)
  295.                 {
  296.                     emitError(XMLValid::NoMultipleValues, fullName);
  297.                     return;
  298.                 }
  299.                 break;
  300.             }
  301.             // Now this attribute can be of type
  302.             //     ID, IDREF, IDREFS, ENTITY, ENTITIES, NOTATION, NMTOKEN, NMTOKENS, ENUMERATION
  303.             //  All these must be valid XMLName
  304.             // If namespace is enabled, colon is not allowed in the first 6
  305.             if (doNamespace && *valPtr == chColon && firstNameChar)
  306.                 emitError(XMLValid::ColonNotValidWithNS);
  307.             if (!getReaderMgr()->getCurrentReader()->isNameChar(*valPtr))
  308.             {
  309.                 emitError(XMLValid::AttrValNotName, fullName);
  310.                 return;
  311.             }
  312.             valPtr++;
  313.         }
  314.         //
  315.         //  Cap it off at the current non-name char. If already capped,
  316.         //  then remember this.
  317.         //
  318.         if (!(*valPtr))
  319.             alreadyCapped = true;
  320.         *valPtr = 0;
  321.         //
  322.         //  If this type of attribute requires that we track reference
  323.         //  stuff, then handle that.
  324.         //
  325.         if (isARefType)
  326.         {
  327.             if ((type == XMLAttDef::ID)
  328.             ||  (type == XMLAttDef::IDRef)
  329.             ||  (type == XMLAttDef::IDRefs))
  330.             {
  331.                 XMLRefInfo* find = getScanner()->getIDRefList()->get(pszTmpVal);
  332.                 if (find)
  333.                 {
  334.                     if (find->getDeclared() && (type == XMLAttDef::ID))
  335.                         emitError(XMLValid::ReusedIDValue, pszTmpVal);
  336.                 }
  337.                  else
  338.                 {
  339.                     find = new (getScanner()->getMemoryManager()) XMLRefInfo
  340.                     (
  341.                         pszTmpVal
  342.                         , false
  343.                         , false
  344.                         , getScanner()->getMemoryManager()
  345.                     );
  346.                     getScanner()->getIDRefList()->put((void*)find->getRefName(), find);
  347.                 }
  348.                 //
  349.                 //  Mark it declared or used, which might be redundant in some cases
  350.                 //  but not worth checking
  351.                 //
  352.                 if (type == XMLAttDef::ID)
  353.                     find->setDeclared(true);
  354.                 else {
  355.                     if (!preValidation) {
  356.                         find->setUsed(true);
  357.                     }
  358.                 }
  359.             }
  360.         }
  361.          else if ((type == XMLAttDef::Entity) || (type == XMLAttDef::Entities))
  362.         {
  363.             //
  364.             //  If its refering to a entity, then look up the name in the
  365.             //  general entity pool. If not there, then its an error. If its
  366.             //  not an external unparsed entity, then its an error.
  367.             //
  368.             const XMLEntityDecl* decl = fDTDGrammar->getEntityDecl(pszTmpVal);
  369.             if (decl)
  370.             {
  371.                 if (!decl->isUnparsed())
  372.                     emitError(XMLValid::BadEntityRefAttr, fullName);
  373.             }
  374.              else
  375.             {
  376.                 emitError
  377.                 (
  378.                     XMLValid::UnknownEntityRefAttr
  379.                     , fullName
  380.                     , pszTmpVal
  381.                 );
  382.             }
  383.         }
  384.          else if ((type == XMLAttDef::Notation) || (type == XMLAttDef::Enumeration))
  385.         {
  386.             //
  387.             //  Make sure that this value maps to one of the enumeration or
  388.             //  notation values in the enumList parameter. We don't have to
  389.             //  look it up in the notation pool (if a notation) because we
  390.             //  will look up the enumerated values themselves. If they are in
  391.             //  the notation pool (after the DTD is parsed), then obviously
  392.             //  this value will be legal since it matches one of them.
  393.             //
  394.             if (!XMLString::isInList(pszTmpVal, enumList))
  395.                 emitError(XMLValid::DoesNotMatchEnumList, fullName);
  396.         }
  397.         // If not doing multiple values, then we are done
  398.         if (!multipleValues)
  399.             break;
  400.         //
  401.         //  If we are at the end, then break out now, else move up to the
  402.         //  next char and update the base pointer.
  403.         //
  404.         if (alreadyCapped)
  405.             break;
  406.         valPtr++;
  407.         pszTmpVal = valPtr;
  408.     }
  409. }
  410. void DTDValidator::preContentValidation(bool reuseGrammar,
  411.                                         bool validateDefAttr)
  412. {
  413.     //
  414.     //  Lets enumerate all of the elements in the element decl pool
  415.     //  and put out an error for any that did not get declared.
  416.     //  We also check all of the attributes as well.
  417.     //
  418.     NameIdPoolEnumerator<DTDElementDecl> elemEnum = fDTDGrammar->getElemEnumerator();
  419.     while (elemEnum.hasMoreElements())
  420.     {
  421.         const DTDElementDecl& curElem = elemEnum.nextElement();
  422.         const DTDElementDecl::CreateReasons reason = curElem.getCreateReason();
  423.         //
  424.         //  See if this element decl was ever marked as declared. If
  425.         //  not, then put out an error. In some cases its just
  426.         //  a warning, such as being referenced in a content model.
  427.         //
  428.         if (reason != XMLElementDecl::Declared)
  429.         {
  430.             if (reason == XMLElementDecl::AttList)
  431.             {
  432.                 getScanner()->emitError
  433.                 (
  434.                     XMLErrs::UndeclaredElemInAttList
  435.                     , curElem.getFullName()
  436.                 );
  437.             }
  438.              else if (reason == XMLElementDecl::AsRootElem)
  439.             {
  440.                 // It's ok that the root element is not declared in the DTD
  441.                 /*
  442.                 emitError
  443.                 (
  444.                     XMLValid::UndeclaredElemInDocType
  445.                     , curElem.getFullName()
  446.                 );*/
  447.             }
  448.              else if (reason == XMLElementDecl::InContentModel)
  449.             {
  450.                 getScanner()->emitError
  451.                 (
  452.                     XMLErrs::UndeclaredElemInCM
  453.                     , curElem.getFullName()
  454.                 );
  455.             }
  456.             else
  457.             {
  458.                 #if defined(XERCES_DEBUG)
  459.                   if(reuseGrammar && reason == XMLElementDecl::JustFaultIn){
  460.                   }
  461.                   else
  462.                       ThrowXML(RuntimeException, XMLExcepts::DTD_UnknownCreateReason);
  463.                 #endif
  464.             }
  465.         }
  466.         //
  467.         //  Check all of the attributes of the current element.
  468.         //  We check for:
  469.         //
  470.         //  1) Multiple ID attributes
  471.         //  2) That all of the default values of attributes are
  472.         //      valid for their type.
  473.         //  3) That for any notation types, that their lists
  474.         //      of possible values refer to declared notations.
  475.         //
  476.         XMLAttDefList& attDefList = curElem.getAttDefList();
  477.         bool seenId = false;
  478.         while (attDefList.hasMoreElements())
  479.         {
  480.             const XMLAttDef& curAttDef = attDefList.nextElement();
  481.             if (curAttDef.getType() == XMLAttDef::ID)
  482.             {
  483.                 if (seenId)
  484.                 {
  485.                     emitError
  486.                     (
  487.                         XMLValid::MultipleIdAttrs
  488.                         , curElem.getFullName()
  489.                     );
  490.                     break;
  491.                 }
  492.                 seenId = true;
  493.             }
  494.              else if (curAttDef.getType() == XMLAttDef::Notation && curAttDef.getEnumeration())
  495.             {
  496.                 //
  497.                 //  We need to verify that all of its possible values
  498.                 //  (in the enum list) refer to valid notations.
  499.                 //
  500.                 XMLCh* list = XMLString::replicate(curAttDef.getEnumeration());
  501.                 ArrayJanitor<XMLCh> janList(list);
  502.                 //
  503.                 //  Search forward for a space or a null. If a null,
  504.                 //  we are done. If a space, cap it and look it up.
  505.                 //
  506.                 bool    breakFlag = false;
  507.                 XMLCh*  listPtr = list;
  508.                 XMLCh*  lastPtr = listPtr;
  509.                 while (true)
  510.                 {
  511.                     while (*listPtr && (*listPtr != chSpace))
  512.                         listPtr++;
  513.                     //
  514.                     //  If at the end, indicate we need to break after
  515.                     //  this one. Else, cap it off here.
  516.                     //
  517.                     if (!*listPtr)
  518.                         breakFlag = true;
  519.                     else
  520.                         *listPtr = chNull;
  521.                     if (!fDTDGrammar->getNotationDecl(lastPtr))
  522.                     {
  523.                         emitError
  524.                         (
  525.                             XMLValid::UnknownNotRefAttr
  526.                             , curAttDef.getFullName()
  527.                             , lastPtr
  528.                         );
  529.                     }
  530.                     // Break out if we hit the end last time
  531.                     if (breakFlag)
  532.                         break;
  533.                     // Else move upwards and try again
  534.                     listPtr++;
  535.                     lastPtr = listPtr;
  536.                 }
  537.             }
  538.             // If it has a default/fixed value, then validate it
  539.             if (validateDefAttr && curAttDef.getValue())
  540.             {
  541.                 validateAttrValue
  542.                 (
  543.                     &curAttDef
  544.                     , curAttDef.getValue()
  545.                     , true
  546.                     , &curElem
  547.                 );
  548.             }
  549.         }
  550.     }
  551.     //
  552.     //  And enumerate all of the general entities. If any of them
  553.     //  reference a notation, then make sure the notation exists.
  554.     //
  555.     NameIdPoolEnumerator<DTDEntityDecl> entEnum = fDTDGrammar->getEntityEnumerator();
  556.     while (entEnum.hasMoreElements())
  557.     {
  558.         const DTDEntityDecl& curEntity = entEnum.nextElement();
  559.         if (!curEntity.getNotationName())
  560.             continue;
  561.         // It has a notation name, so look it up
  562.         if (!fDTDGrammar->getNotationDecl(curEntity.getNotationName()))
  563.         {
  564.             emitError
  565.             (
  566.                 XMLValid::NotationNotDeclared
  567.                 , curEntity.getNotationName()
  568.             );
  569.         }
  570.     }
  571. }
  572. void DTDValidator::postParseValidation()
  573. {
  574.     //
  575.     //  At this time, there is nothing to do here. The scanner itself handles
  576.     //  ID/IDREF validation, since that is the same no matter what kind of
  577.     //  validator.
  578.     //
  579. }
  580. XERCES_CPP_NAMESPACE_END