source: icXML/icXML-devel/src/icxercesc/validators/DTD/DTDValidator.cpp @ 2721

Last change on this file since 2721 was 2721, checked in by cameron, 6 years ago

Fix imports in icXML modified Xerces files

File size: 17.1 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/*
19 * $Id: DTDValidator.cpp 729944 2008-12-29 17:03:32Z amassari $
20 */
21
22
23// ---------------------------------------------------------------------------
24//  Includes
25// ---------------------------------------------------------------------------
26#include <xercesc/util/Janitor.hpp>
27#include <xercesc/util/XMLUniDefs.hpp>
28#include <xercesc/util/XMLUni.hpp>
29#include <icxercesc/internal/ReaderMgr.hpp>
30#include <icxercesc/internal/XMLScanner.hpp>
31#include <icxercesc/validators/DTD/DTDValidator.hpp>
32
33XERCES_CPP_NAMESPACE_BEGIN
34
35// ---------------------------------------------------------------------------
36//  DTDValidator: Constructors and Destructor
37// ---------------------------------------------------------------------------
38DTDValidator::DTDValidator(XMLErrorReporter* const errReporter) :
39
40        XMLValidator(errReporter)
41        , fDTDGrammar(0)
42{
43        reset();
44}
45
46DTDValidator::~DTDValidator()
47{
48}
49
50
51// ---------------------------------------------------------------------------
52//  DTDValidator: Implementation of the XMLValidator interface
53// ---------------------------------------------------------------------------
54bool DTDValidator::checkContent
55(
56        XMLElementDecl* const           elemDecl
57        #ifdef STORE_CHILDREN_INFORMATION_IN_PARSER
58        , XMLElementDecl ** const       children
59        #else
60        , QName** const                         children
61        #endif
62        , XMLSize_t                                     childCount
63        , XMLSize_t*                            indexOfFailingChild
64)
65{
66        //
67        //  Look up the element id in our element decl pool. This will get us
68        //  the element decl in our own way of looking at them.
69        //
70        if (!elemDecl)
71                ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Val_InvalidElemId, getScanner()->getMemoryManager());
72
73        //
74        //  Get the content spec type of this element. This will tell us what
75        //  to do to validate it.
76        //
77        const DTDElementDecl::ModelTypes modelType = ((DTDElementDecl*) elemDecl)->getModelType();
78
79        if (modelType == DTDElementDecl::Empty)
80        {
81                //
82                //  We can do this one here. It cannot have any children. If it does
83                //  we return 0 as the index of the first bad child.
84                //
85                if (childCount)
86                {
87                        *indexOfFailingChild=0;
88                        return false;
89                }
90        }
91        else if (modelType == DTDElementDecl::Any)
92        {
93                // We pass no judgement on this one, anything goes
94        }
95        else if ((modelType == DTDElementDecl::Mixed_Simple) || (modelType == DTDElementDecl::Children))
96        {
97                // Get the element's content model or fault it in
98                const XMLContentModel* elemCM = elemDecl->getContentModel();
99
100                // Ask it to validate and return its return
101                return elemCM->validateContent
102                (
103                        children
104                        , childCount
105                        , indexOfFailingChild
106                        , getScanner()->getMemoryManager()
107                );
108        }
109         else
110        {
111                ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::CM_UnknownCMType, getScanner()->getMemoryManager());
112        }
113
114        // Went ok, so return success
115        return true;
116}
117
118
119void DTDValidator::faultInAttr(XMLAttr& toFill, const XMLAttDef& attDef) const
120{
121        DTDAttDef* dtdAttDef = (DTDAttDef*) &attDef;
122        QName* attName = dtdAttDef->getAttName();
123
124        toFill.set
125        (
126                attName
127                , dtdAttDef->getValue()
128                , dtdAttDef->getType()
129        );
130}
131
132void DTDValidator::reset()
133{
134}
135
136
137bool DTDValidator::requiresNamespaces() const
138{
139        // Namespaces are not supported for DTDs
140        return false;
141}
142
143
144void
145DTDValidator::validateAttrValue(const   XMLAttDef*      attDef
146                                                                , const XMLCh* const    attrValue
147                                                                , bool                  preValidation
148                                                                , const XMLElementDecl*)
149{
150        //
151        //  Get quick refs to lost of of the stuff in the passed objects in
152        //  order to simplify the code below, which will reference them very
153        //  often.
154        //
155        const XMLAttDef::AttTypes       type = attDef->getType();
156        const XMLAttDef::DefAttTypes    defType = attDef->getDefaultType();
157        const XMLCh* const              valueText = attDef->getValue();
158        const XMLCh* const              fullName = attDef->getFullName();
159        const XMLCh* const              enumList = attDef->getEnumeration();
160
161        //
162        //  If the default type is fixed, then make sure the passed value maps
163        //  to the fixed value.
164        //  If during preContentValidation, the value we are validating is the fixed value itself
165        //  so no need to compare.
166        //  Only need to do this for regular attribute value validation
167        //
168        if (defType == XMLAttDef::Fixed && !preValidation)
169        {
170                if (!XMLString::equals(attrValue, valueText))
171                        emitError(XMLValid::NotSameAsFixedValue, fullName, attrValue, valueText);
172        }
173
174        //
175        //  If its a CDATA attribute, then we are done with any DTD level
176        //  validation else do the rest.
177        //
178        if (type == XMLAttDef::CData)
179                return;
180
181
182
183        // An empty string cannot be valid for any of the other types
184        if (!attrValue[0])
185        {
186                emitError(XMLValid::InvalidEmptyAttValue, fullName);
187                return;
188        }
189
190        // See whether we are doing multiple values or not
191        const bool multipleValues =
192        (
193                (type == XMLAttDef::IDRefs)
194                || (type == XMLAttDef::Entities)
195                || (type == XMLAttDef::NmTokens)
196                || (type == XMLAttDef::Notation)
197                || (type == XMLAttDef::Enumeration)
198        );
199
200        // And whether we must check for a first name char
201        const bool firstNameChar =
202        (
203                (type == XMLAttDef::ID)
204                || (type == XMLAttDef::IDRef)
205                || (type == XMLAttDef::IDRefs)
206                || (type == XMLAttDef::Entity)
207                || (type == XMLAttDef::Entities)
208                || (type == XMLAttDef::Notation)
209        );
210
211        // Whether it requires ref checking stuff
212        const bool isARefType
213        (
214                (type == XMLAttDef::ID)
215                || (type == XMLAttDef::IDRef)
216                || (type == XMLAttDef::IDRefs)
217        );
218
219        // Some trigger flags to avoid issuing redundant errors and whatnot
220        bool alreadyCapped = false;
221
222        //
223        //  Make a copy of the text that we can mangle and get a pointer we can
224        //  move through the value
225        //
226
227        // Use a stack-based buffer, when possible...
228        XMLCh   tempBuffer[100];
229
230        XMLCh* pszTmpVal = 0;
231
232        ArrayJanitor<XMLCh> janTmpVal(0);
233
234        if (XMLString::stringLen(attrValue) < sizeof(tempBuffer) / sizeof(tempBuffer[0]))
235        {
236                XMLString::copyString(tempBuffer, attrValue);
237                pszTmpVal = tempBuffer;
238        }
239        else
240        {
241                janTmpVal.reset(XMLString::replicate(attrValue, getScanner()->getMemoryManager()), getScanner()->getMemoryManager());
242                pszTmpVal = janTmpVal.get();
243        }
244
245        XMLCh* valPtr = pszTmpVal;
246
247        bool doNamespace = getScanner()->getDoNamespaces();
248
249        while (true)
250        {
251                //
252                //  Make sure the first character is a valid first name char, i.e.
253                //  if its a Name value. For NmToken values we don't treat the first
254                //  char any differently.
255                //
256                if (firstNameChar)
257                {
258                        // If its not, emit and error but try to keep going
259                        if (!getReaderMgr()->getCurrentReader()->isFirstNameChar(*valPtr))
260                                emitError(XMLValid::AttrValNotName, valPtr, fullName);
261                        valPtr++;
262                }
263
264                // Make sure all the remaining chars are valid name chars
265                while (*valPtr)
266                {
267                        //
268                        //  If we hit a whitespace, its either a break between two
269                        //  or more values, or an error if we have a single value.
270                        //
271                        //
272                        //   XML1.0-3rd
273                        //
274                        //   [6]   Names   ::=   Name (#x20 Name)*
275                        //   [8]   Nmtokens   ::=   Nmtoken (#x20 Nmtoken)*
276                        //
277                        //   only and only ONE #x20 is allowed to be the delimiter
278                        //
279                        if (*valPtr==chSpace)
280                        {
281                                if (!multipleValues)
282                                {
283                                        emitError(XMLValid::NoMultipleValues, fullName);
284                                        return;
285                                }
286
287                                break;
288                        }
289
290                        // Now this attribute can be of type
291                        //     ID, IDREF, IDREFS, ENTITY, ENTITIES, NOTATION, NMTOKEN, NMTOKENS, ENUMERATION
292                        //  All these must be valid XMLName
293                        // If namespace is enabled, colon is not allowed in the first 6
294
295                        if (doNamespace && *valPtr == chColon && firstNameChar)
296                                emitError(XMLValid::ColonNotValidWithNS);
297
298                        if (!getReaderMgr()->getCurrentReader()->isNameChar(*valPtr))
299                        {
300                                emitError(XMLValid::AttrValNotName, valPtr, fullName);
301                                return;
302                        }
303                        valPtr++;
304                }
305
306                //
307                //  Cap it off at the current non-name char. If already capped,
308                //  then remember this.
309                //
310                if (!(*valPtr))
311                        alreadyCapped = true;
312                *valPtr = 0;
313
314                //
315                //  If this type of attribute requires that we track reference
316                //  stuff, then handle that.
317                //
318                if (isARefType)
319                {
320                        if ((type == XMLAttDef::ID)
321                        ||  (type == XMLAttDef::IDRef)
322                        ||  (type == XMLAttDef::IDRefs))
323                        {
324                                XMLRefInfo* find = getScanner()->getIDRefList()->get(pszTmpVal);
325                                if (find)
326                                {
327                                        if (find->getDeclared() && (type == XMLAttDef::ID))
328                                                emitError(XMLValid::ReusedIDValue, pszTmpVal);
329                                }
330                                 else
331                                {
332                                        find = new (getScanner()->getMemoryManager()) XMLRefInfo
333                                        (
334                                                pszTmpVal
335                                                , false
336                                                , false
337                                                , getScanner()->getMemoryManager()
338                                        );
339                                        getScanner()->getIDRefList()->put((void*)find->getRefName(), find);
340                                }
341
342                                //
343                                //  Mark it declared or used, which might be redundant in some cases
344                                //  but not worth checking
345                                //
346                                if (type == XMLAttDef::ID)
347                                        find->setDeclared(true);
348                                else {
349                                        if (!preValidation) {
350                                                find->setUsed(true);
351                                        }
352                                }
353                        }
354                }
355                 else if (!preValidation && ((type == XMLAttDef::Entity) || (type == XMLAttDef::Entities)))
356                {
357                        //
358                        //  If its refering to a entity, then look up the name in the
359                        //  general entity pool. If not there, then its an error. If its
360                        //  not an external unparsed entity, then its an error.
361                        //
362                        //  In case of pre-validation, the above errors should be ignored.
363                        //
364                        const XMLEntityDecl* decl = fDTDGrammar->getEntityDecl(pszTmpVal);
365                        if (decl)
366                        {
367                                if (!decl->isUnparsed())
368                                        emitError(XMLValid::BadEntityRefAttr, pszTmpVal, fullName);
369                        }
370                         else
371                        {
372                                emitError
373                                (
374                                        XMLValid::UnknownEntityRefAttr
375                                        , fullName
376                                        , pszTmpVal
377                                );
378                        }
379                }
380                 else if ((type == XMLAttDef::Notation) || (type == XMLAttDef::Enumeration))
381                {
382                        //
383                        //  Make sure that this value maps to one of the enumeration or
384                        //  notation values in the enumList parameter. We don't have to
385                        //  look it up in the notation pool (if a notation) because we
386                        //  will look up the enumerated values themselves. If they are in
387                        //  the notation pool (after the DTD is parsed), then obviously
388                        //  this value will be legal since it matches one of them.
389                        //
390                        if (!XMLString::isInList(pszTmpVal, enumList))
391                                emitError(XMLValid::DoesNotMatchEnumList, pszTmpVal, fullName);
392                }
393
394                // If not doing multiple values, then we are done
395                if (!multipleValues)
396                        break;
397
398                //
399                //  If we are at the end, then break out now, else move up to the
400                //  next char and update the base pointer.
401                //
402                if (alreadyCapped)
403                        break;
404
405                valPtr++;
406                pszTmpVal = valPtr;
407        }
408
409}
410
411void DTDValidator::preContentValidation(bool
412#if defined(XERCES_DEBUG)
413                                                                                reuseGrammar
414#endif
415                                                                           ,bool validateDefAttr)
416{
417        //
418        //  Lets enumerate all of the elements in the element decl pool
419        //  and put out an error for any that did not get declared.
420        //  We also check all of the attributes as well.
421        //
422        NameIdPoolEnumerator<DTDElementDecl> elemEnum = fDTDGrammar->getElemEnumerator();
423        fDTDGrammar->setValidated(true);
424        while (elemEnum.hasMoreElements())
425        {
426                const DTDElementDecl& curElem = elemEnum.nextElement();
427                const DTDElementDecl::CreateReasons reason = curElem.getCreateReason();
428
429                //
430                //  See if this element decl was ever marked as declared. If
431                //  not, then put out an error. In some cases its just
432                //  a warning, such as being referenced in a content model.
433                //
434                if (reason != XMLElementDecl::Declared)
435                {
436                        if (reason == XMLElementDecl::AttList)
437                        {
438                                getScanner()->emitError
439                                (
440                                        XMLErrs::UndeclaredElemInAttList
441                                        , curElem.getFullName()
442                                );
443                        }
444                         else if (reason == XMLElementDecl::AsRootElem)
445                        {
446                                // It's ok that the root element is not declared in the DTD
447                                /*
448                                emitError
449                                (
450                                        XMLValid::UndeclaredElemInDocType
451                                        , curElem.getFullName()
452                                );*/
453                        }
454                         else if (reason == XMLElementDecl::InContentModel)
455                        {
456                                getScanner()->emitError
457                                (
458                                        XMLErrs::UndeclaredElemInCM
459                                        , curElem.getFullName()
460                                );
461                        }
462                        else
463                        {
464                                #if defined(XERCES_DEBUG)
465                                  if(reuseGrammar && reason == XMLElementDecl::JustFaultIn){
466                                  }
467                                  else
468                                          ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::DTD_UnknownCreateReason, getScanner()->getMemoryManager());
469                                #endif
470                        }
471                }
472
473                //
474                //  Check all of the attributes of the current element.
475                //  We check for:
476                //
477                //  1) Multiple ID attributes
478                //  2) That all of the default values of attributes are
479                //      valid for their type.
480                //  3) That for any notation types, that their lists
481                //      of possible values refer to declared notations.
482                //
483                //  4) XML1.0(3rd edition)
484                //
485                //     Validity constraint: One Notation Per Element Type
486                //     An element type MUST NOT have more than one NOTATION attribute specified.
487                //
488                //     Validity constraint: No Notation on Empty Element
489                //     For compatibility, an attribute of type NOTATION MUST NOT be declared on an element declared EMPTY.
490                //
491                //     Validity constraint: No Duplicate Tokens
492                //     The notation names in a single NotationType attribute declaration, as well as
493                //     the NmTokens in a single Enumeration attribute declaration, MUST all be distinct.
494                //
495
496                XMLAttDefList& attDefList = curElem.getAttDefList();
497                bool seenId = false;
498                bool seenNOTATION = false;
499                bool elemEmpty = (curElem.getModelType() == DTDElementDecl::Empty);
500
501                for(XMLSize_t i=0; i<attDefList.getAttDefCount(); i++)
502                {
503                        const XMLAttDef& curAttDef = attDefList.getAttDef(i);
504
505                        if (curAttDef.getType() == XMLAttDef::ID)
506                        {
507                                if (seenId)
508                                {
509                                        emitError
510                                        (
511                                                XMLValid::MultipleIdAttrs
512                                                , curElem.getFullName()
513                                        );
514                                        break;
515                                }
516
517                                seenId = true;
518                        }
519                         else if (curAttDef.getType() == XMLAttDef::Notation)
520                        {
521                                if (seenNOTATION)
522                                {
523                                        emitError
524                                        (
525                                                XMLValid::ElemOneNotationAttr
526                                          , curElem.getFullName()
527                                        );
528
529                                        break;
530                                }
531
532                                seenNOTATION = true;
533
534                                // no notation attribute on empty element
535                                if (elemEmpty)
536                                {
537                                        emitError
538                                   (
539                                          XMLValid::EmptyElemNotationAttr
540                                        , curElem.getFullName()
541                                        , curAttDef.getFullName()
542                                        );
543
544                                        break;
545                                }
546
547                                //go through enumeration list to check
548                                // distinct
549                                // notation declaration
550                                if (curAttDef.getEnumeration())
551                                {
552                                        checkTokenList(curAttDef, true);
553                                }
554                         }
555                         else if (curAttDef.getType() == XMLAttDef::Enumeration )
556                         {
557                                //go through enumeration list to check
558                                // distinct only
559                                if (curAttDef.getEnumeration())
560                                {
561                                        checkTokenList(curAttDef, false);
562                                }
563                         }
564
565                        // If it has a default/fixed value, then validate it
566                        if (validateDefAttr && curAttDef.getValue())
567                        {
568                                validateAttrValue
569                                (
570                                        &curAttDef
571                                        , curAttDef.getValue()
572                                        , true
573                                        , &curElem
574                                );
575                        }
576                }
577        }
578
579        //
580        //  And enumerate all of the general entities. If any of them
581        //  reference a notation, then make sure the notation exists.
582        //
583        NameIdPoolEnumerator<DTDEntityDecl> entEnum = fDTDGrammar->getEntityEnumerator();
584        while (entEnum.hasMoreElements())
585        {
586                const DTDEntityDecl& curEntity = entEnum.nextElement();
587
588                if (!curEntity.getNotationName())
589                        continue;
590
591                // It has a notation name, so look it up
592                if (!fDTDGrammar->getNotationDecl(curEntity.getNotationName()))
593                {
594                        emitError
595                        (
596                                XMLValid::NotationNotDeclared
597                                , curEntity.getNotationName()
598                        );
599                }
600        }
601}
602
603void DTDValidator::postParseValidation()
604{
605        //
606        //  At this time, there is nothing to do here. The scanner itself handles
607        //  ID/IDREF validation, since that is the same no matter what kind of
608        //  validator.
609        //
610}
611
612//
613//  We need to verify that all of its possible values
614//  (in the enum list)
615//   is distinct and
616//   refer to valid notations if toValidateNotation is set on
617//
618void DTDValidator::checkTokenList(const XMLAttDef&  curAttDef
619                                                                ,       bool        toValidateNotation)
620{
621
622        XMLCh* list = XMLString::replicate(curAttDef.getEnumeration(), getScanner()->getMemoryManager());
623        ArrayJanitor<XMLCh> janList(list, getScanner()->getMemoryManager());
624
625        //
626        //  Search forward for a space or a null. If a null,
627        //  we are done. If a space, cap it and look it up.
628        //
629        bool    breakFlag = false;
630        XMLCh*  listPtr = list;
631        XMLCh*  lastPtr = listPtr;
632        while (true)
633        {
634                while (*listPtr && (*listPtr != chSpace))
635                        listPtr++;
636
637                //
638                //  If at the end, indicate we need to break after
639                //  this one. Else, cap it off here.
640                //
641                if (!*listPtr)
642                        breakFlag = true;
643                else
644                        *listPtr++ = chNull;
645
646                //distinction check
647                //there should be no same token found in the remaining list
648                if (XMLString::isInList(lastPtr, listPtr))
649                {
650                        emitError
651                                (
652                                XMLValid::AttrDupToken
653                                , curAttDef.getFullName()
654                                , lastPtr
655                                );
656                }
657
658                if (toValidateNotation && !fDTDGrammar->getNotationDecl(lastPtr))
659                {
660                        emitError
661                                (
662                                XMLValid::UnknownNotRefAttr
663                                , curAttDef.getFullName()
664                                , lastPtr
665                                );
666                }
667
668                // Break out if we hit the end last time
669                if (breakFlag)
670                        break;
671
672                // Else move upwards and try again
673                lastPtr = listPtr;
674        }
675}
676
677XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.