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: XSAXMLScanner.cpp 833045 2009-11-05 13:21:27Z borisk $
20  */
21 
22 
23 // ---------------------------------------------------------------------------
24 //  Includes
25 // ---------------------------------------------------------------------------
26 #include <xercesc/internal/XSAXMLScanner.hpp>
27 
28 #include <xercesc/sax/InputSource.hpp>
29 #include <xercesc/framework/XMLEntityHandler.hpp>
30 #include <xercesc/framework/XMLDocumentHandler.hpp>
31 #include <xercesc/framework/psvi/XSAnnotation.hpp>
32 #include <xercesc/validators/schema/SchemaValidator.hpp>
33 
34 
35 XERCES_CPP_NAMESPACE_BEGIN
36 
37 // ---------------------------------------------------------------------------
38 //  XSAXMLScanner: Constructors and Destructor
39 // ---------------------------------------------------------------------------
XSAXMLScanner(GrammarResolver * const grammarResolver,XMLStringPool * const uriStringPool,SchemaGrammar * const xsaGrammar,MemoryManager * const manager)40 XSAXMLScanner::XSAXMLScanner( GrammarResolver* const grammarResolver
41                             , XMLStringPool* const   uriStringPool
42                             , SchemaGrammar* const   xsaGrammar
43                             , MemoryManager* const manager) :
44 
45     SGXMLScanner(0, grammarResolver, manager)
46 {
47     fSchemaGrammar = xsaGrammar;
48     setURIStringPool(uriStringPool);
49 }
50 
~XSAXMLScanner()51 XSAXMLScanner::~XSAXMLScanner()
52 {
53 }
54 
55 // ---------------------------------------------------------------------------
56 //  XSAXMLScanner: SGXMLScanner virtual methods
57 // ---------------------------------------------------------------------------
58 //  This method will kick off the scanning of the primary content of the
scanEndTag(bool & gotData)59 void XSAXMLScanner::scanEndTag(bool& gotData)
60 {
61     //  Assume we will still have data until proven otherwise. It will only
62     //  ever be false if this is the end of the root element.
63     gotData = true;
64 
65     //  Check if the element stack is empty. If so, then this is an unbalanced
66     //  element (i.e. more ends than starts, perhaps because of bad text
67     //  causing one to be skipped.)
68     if (fElemStack.isEmpty())
69     {
70         emitError(XMLErrs::MoreEndThanStartTags);
71         fReaderMgr.skipPastChar(chCloseAngle);
72         ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Scan_UnbalancedStartEnd, fMemoryManager);
73     }
74 
75     //  Pop the stack of the element we are supposed to be ending. Remember
76     //  that we don't own this. The stack just keeps them and reuses them.
77     unsigned int uriId = fElemStack.getCurrentURI();
78 
79     // Make sure that its the end of the element that we expect
80     const XMLCh *elemName = fElemStack.getCurrentSchemaElemName();
81     const ElemStack::StackElem* topElem = fElemStack.popTop();
82     if (!fReaderMgr.skippedStringLong(elemName))
83     {
84         emitError
85         (
86             XMLErrs::ExpectedEndOfTagX, elemName
87         );
88         fReaderMgr.skipPastChar(chCloseAngle);
89         return;
90     }
91 
92     // See if it was the root element, to avoid multiple calls below
93     const bool isRoot = fElemStack.isEmpty();
94 
95     // Make sure we are back on the same reader as where we started
96     if (topElem->fReaderNum != fReaderMgr.getCurrentReaderNum())
97         emitError(XMLErrs::PartialTagMarkupError);
98 
99     // Skip optional whitespace
100     fReaderMgr.skipPastSpaces();
101 
102     // Make sure we find the closing bracket
103     if (!fReaderMgr.skippedChar(chCloseAngle))
104     {
105         emitError
106         (
107             XMLErrs::UnterminatedEndTag, topElem->fThisElement->getFullName()
108         );
109     }
110 
111     //  If validation is enabled, then lets pass him the list of children and
112     //  this element and let him validate it.
113     if (fValidate)
114     {
115         XMLSize_t failure;
116         bool res = fValidator->checkContent
117         (
118             topElem->fThisElement
119             , topElem->fChildren
120             , topElem->fChildCount
121             , &failure
122         );
123 
124         if (!res)
125         {
126             //  One of the elements is not valid for the content. NOTE that
127             //  if no children were provided but the content model requires
128             //  them, it comes back with a zero value. But we cannot use that
129             //  to index the child array in this case, and have to put out a
130             //  special message.
131             if (!topElem->fChildCount)
132             {
133                 fValidator->emitError
134                 (
135                     XMLValid::EmptyNotValidForContent
136                     , topElem->fThisElement->getFormattedContentModel()
137                 );
138             }
139             else if (failure >= topElem->fChildCount)
140             {
141                 fValidator->emitError
142                 (
143                     XMLValid::NotEnoughElemsForCM
144                     , topElem->fThisElement->getFormattedContentModel()
145                 );
146             }
147             else
148             {
149                 fValidator->emitError
150                 (
151                     XMLValid::ElementNotValidForContent
152                     , topElem->fChildren[failure]->getRawName()
153                     , topElem->fThisElement->getFormattedContentModel()
154                 );
155             }
156         }
157     }
158 
159     // now we can reset the datatype buffer, since the
160     // application has had a chance to copy the characters somewhere else
161     ((SchemaValidator *)fValidator)->clearDatatypeBuffer();
162 
163     // If we have a doc handler, tell it about the end tag
164     if (fDocHandler)
165     {
166         if (topElem->fPrefixColonPos != -1)
167             fPrefixBuf.set(elemName, topElem->fPrefixColonPos);
168         else
169             fPrefixBuf.reset();
170         fDocHandler->endElement
171         (
172             *topElem->fThisElement
173             , uriId
174             , isRoot
175             , fPrefixBuf.getRawBuffer()
176         );
177     }
178 
179     // If this was the root, then done with content
180     gotData = !isRoot;
181 
182     if (gotData) {
183 
184         // Restore the grammar
185         fGrammar = fElemStack.getCurrentGrammar();
186         fGrammarType = fGrammar->getGrammarType();
187         fValidator->setGrammar(fGrammar);
188 
189         // Restore the validation flag
190         fValidate = fElemStack.getValidationFlag();
191     }
192 }
193 
scanStartTag(bool & gotData)194 bool XSAXMLScanner::scanStartTag(bool& gotData)
195 {
196     //  Assume we will still have data until proven otherwise. It will only
197     //  ever be false if this is the root and its empty.
198     gotData = true;
199 
200     // Reset element content
201     fContent.reset();
202 
203     //  The current position is after the open bracket, so we need to read in
204     //  in the element name.
205     int prefixColonPos;
206     if (!fReaderMgr.getQName(fQNameBuf, &prefixColonPos))
207     {
208         if (fQNameBuf.isEmpty())
209             emitError(XMLErrs::ExpectedElementName);
210         else
211             emitError(XMLErrs::InvalidElementName, fQNameBuf.getRawBuffer());
212         fReaderMgr.skipToChar(chOpenAngle);
213         return false;
214     }
215 
216     // See if its the root element
217     const bool isRoot = fElemStack.isEmpty();
218 
219     // Skip any whitespace after the name
220     fReaderMgr.skipPastSpaces();
221 
222     //  First we have to do the rawest attribute scan. We don't do any
223     //  normalization of them at all, since we don't know yet what type they
224     //  might be (since we need the element decl in order to do that.)
225     const XMLCh* qnameRawBuf = fQNameBuf.getRawBuffer();
226     bool isEmpty;
227     XMLSize_t attCount = rawAttrScan(qnameRawBuf, *fRawAttrList, isEmpty);
228 
229     // save the contentleafname and currentscope before addlevel, for later use
230     ContentLeafNameTypeVector* cv = 0;
231     XMLContentModel* cm = 0;
232     unsigned int currentScope = Grammar::TOP_LEVEL_SCOPE;
233     bool laxThisOne = false;
234     if (!isRoot)
235     {
236         // schema validator will have correct type if validating
237         SchemaElementDecl* tempElement = (SchemaElementDecl*)
238             fElemStack.topElement()->fThisElement;
239         SchemaElementDecl::ModelTypes modelType = tempElement->getModelType();
240         ComplexTypeInfo *currType = 0;
241 
242         if (fValidate)
243         {
244             currType = ((SchemaValidator*)fValidator)->getCurrentTypeInfo();
245             if (currType)
246                 modelType = (SchemaElementDecl::ModelTypes)currType->getContentType();
247             else // something must have gone wrong
248                 modelType = SchemaElementDecl::Any;
249         }
250         else {
251             currType = tempElement->getComplexTypeInfo();
252         }
253 
254         if ((modelType == SchemaElementDecl::Mixed_Simple)
255           ||  (modelType == SchemaElementDecl::Mixed_Complex)
256           ||  (modelType == SchemaElementDecl::Children))
257         {
258             cm = currType->getContentModel();
259             cv = cm->getContentLeafNameTypeVector();
260             currentScope = fElemStack.getCurrentScope();
261         }
262         else if (modelType == SchemaElementDecl::Any) {
263             laxThisOne = true;
264         }
265     }
266 
267     //  Now, since we might have to update the namespace map for this element,
268     //  but we don't have the element decl yet, we just tell the element stack
269     //  to expand up to get ready.
270     XMLSize_t elemDepth = fElemStack.addLevel();
271     fElemStack.setValidationFlag(fValidate);
272     fElemStack.setPrefixColonPos(prefixColonPos);
273 
274     //  Make an initial pass through the list and find any xmlns attributes or
275     //  schema attributes.
276     if (attCount)
277         scanRawAttrListforNameSpaces(attCount);
278 
279     //  Resolve the qualified name to a URI and name so that we can look up
280     //  the element decl for this element. We have now update the prefix to
281     //  namespace map so we should get the correct element now.
282     unsigned int uriId = resolveQNameWithColon
283     (
284         qnameRawBuf, fPrefixBuf, ElemStack::Mode_Element, prefixColonPos
285     );
286 
287     //if schema, check if we should lax or skip the validation of this element
288     bool parentValidation = fValidate;
289     if (cv) {
290         QName element(fPrefixBuf.getRawBuffer(), &qnameRawBuf[prefixColonPos + 1], uriId, fMemoryManager);
291         // elementDepth will be > 0, as cv is only constructed if element is not
292         // root.
293         laxThisOne = laxElementValidation(&element, cv, cm, elemDepth - 1);
294     }
295 
296     //  Look up the element now in the grammar. This will get us back a
297     //  generic element decl object. We tell him to fault one in if he does
298     //  not find it.
299     bool wasAdded = false;
300     const XMLCh* nameRawBuf = &qnameRawBuf[prefixColonPos + 1];
301     XMLElementDecl* elemDecl = fGrammar->getElemDecl
302     (
303         uriId, nameRawBuf, qnameRawBuf, currentScope
304     );
305 
306     if (!elemDecl)
307     {
308         // URI is different, so we try to switch grammar
309         if (uriId != fURIStringPool->getId(fGrammar->getTargetNamespace())) {
310             switchGrammar(getURIText(uriId), laxThisOne);
311         }
312 
313         // look for a global element declaration
314         elemDecl = fGrammar->getElemDecl(
315             uriId, nameRawBuf, qnameRawBuf, Grammar::TOP_LEVEL_SCOPE
316         );
317 
318         if (!elemDecl)
319         {
320             // if still not found, look in list of undeclared elements
321             elemDecl = fElemNonDeclPool->getByKey(
322                 nameRawBuf, uriId, (int)Grammar::TOP_LEVEL_SCOPE);
323 
324             if (!elemDecl)
325             {
326                 elemDecl = new (fMemoryManager) SchemaElementDecl
327                 (
328                     fPrefixBuf.getRawBuffer(), nameRawBuf, uriId
329                     , SchemaElementDecl::Any, Grammar::TOP_LEVEL_SCOPE
330                     , fMemoryManager
331                 );
332 
333                 elemDecl->setId (fElemNonDeclPool->put(
334                       (void*)elemDecl->getBaseName(),
335                       uriId,
336                       (int)Grammar::TOP_LEVEL_SCOPE,
337                       (SchemaElementDecl*)elemDecl));
338 
339                 wasAdded = true;
340             }
341 		}
342     }
343 
344     //  We do something different here according to whether we found the
345     //  element or not.
346     bool bXsiTypeSet= (fValidator)?((SchemaValidator*)fValidator)->getIsXsiTypeSet():false;
347     if (wasAdded || !elemDecl->isDeclared())
348     {
349         if (laxThisOne && !bXsiTypeSet) {
350             fValidate = false;
351             fElemStack.setValidationFlag(fValidate);
352         }
353 
354         // If validating then emit an error
355         if (fValidate)
356         {
357             // This is to tell the reuse Validator that this element was
358             // faulted-in, was not an element in the grammar pool originally
359             elemDecl->setCreateReason(XMLElementDecl::JustFaultIn);
360 
361             if(!bXsiTypeSet)
362                 fValidator->emitError
363                 (
364                     XMLValid::ElementNotDefined, elemDecl->getFullName()
365                 );
366         }
367     }
368 
369     //  Now we can update the element stack to set the current element
370     //  decl. We expanded the stack above, but couldn't store the element
371     //  decl because we didn't know it yet.
372     fElemStack.setElement(elemDecl, fReaderMgr.getCurrentReaderNum());
373     fElemStack.setCurrentURI(uriId);
374 
375     if (isRoot) {
376         fRootElemName = XMLString::replicate(qnameRawBuf, fMemoryManager);
377     }
378 
379     //  Validate the element
380     if (fValidate) {
381         fValidator->validateElement(elemDecl);
382     }
383 
384     // squirrel away the element's QName, so that we can do an efficient
385     // end-tag match
386     fElemStack.setCurrentSchemaElemName(fQNameBuf.getRawBuffer());
387 
388     ComplexTypeInfo* typeinfo = (fValidate)
389         ? ((SchemaValidator*)fValidator)->getCurrentTypeInfo()
390         : ((SchemaElementDecl*) elemDecl)->getComplexTypeInfo();
391 
392     if (typeinfo)
393     {
394         currentScope = typeinfo->getScopeDefined();
395 
396         // switch grammar if the typeinfo has a different grammar
397         XMLCh* typeName = typeinfo->getTypeName();
398         int comma = XMLString::indexOf(typeName, chComma);
399         if (comma > 0)
400         {
401             XMLBufBid bbPrefix(&fBufMgr);
402             XMLBuffer& prefixBuf = bbPrefix.getBuffer();
403 
404             prefixBuf.append(typeName, comma);
405             switchGrammar(prefixBuf.getRawBuffer(), laxThisOne);
406         }
407     }
408     fElemStack.setCurrentScope(currentScope);
409 
410     // Set element next state
411     if (elemDepth >= fElemStateSize) {
412         resizeElemState();
413     }
414 
415     fElemState[elemDepth] = 0;
416     fElemLoopState[elemDepth] = 0;
417     fElemStack.setCurrentGrammar(fGrammar);
418 
419     //  If this is the first element and we are validating, check the root
420     //  element.
421     if (!isRoot && parentValidation) {
422         fElemStack.addChild(elemDecl->getElementName(), true);
423     }
424 
425     //  Now lets get the fAttrList filled in. This involves faulting in any
426     //  defaulted and fixed attributes and normalizing the values of any that
427     //  we got explicitly.
428     //
429     //  We update the attCount value with the total number of attributes, but
430     //  it goes in with the number of values we got during the raw scan of
431     //  explictly provided attrs above.
432     attCount = buildAttList(*fRawAttrList, attCount, elemDecl, *fAttrList);
433 
434     if(attCount)
435     {
436         // clean up after ourselves:
437         // clear the map used to detect duplicate attributes
438         fUndeclaredAttrRegistry->removeAll();
439     }
440 
441     // Since the element may have default values, call start tag now regardless if it is empty or not
442     // If we have a document handler, then tell it about this start tag
443     if (fDocHandler)
444     {
445         fDocHandler->startElement
446         (
447             *elemDecl, uriId, fPrefixBuf.getRawBuffer(), *fAttrList
448             , attCount, false, isRoot
449         );
450     } // may be where we output something...
451 
452     //  If empty, validate content right now if we are validating and then
453     //  pop the element stack top. Else, we have to update the current stack
454     //  top's namespace mapping elements.
455     if (isEmpty)
456     {
457         // Pop the element stack back off since it'll never be used now
458         fElemStack.popTop();
459 
460         // If validating, then insure that its legal to have no content
461         if (fValidate)
462         {
463             XMLSize_t failure;
464             bool res = fValidator->checkContent(elemDecl, 0, 0, &failure);
465             if (!res)
466             {
467                 // REVISIT:  in the case of xsi:type, this may
468                 // return the wrong string...
469                 fValidator->emitError
470                 (
471                     XMLValid::ElementNotValidForContent
472                     , elemDecl->getFullName()
473                     , elemDecl->getFormattedContentModel()
474                 );
475             }
476         }
477 
478         // If we have a doc handler, tell it about the end tag
479         if (fDocHandler)
480         {
481             fDocHandler->endElement
482             (
483                 *elemDecl, uriId, isRoot, fPrefixBuf.getRawBuffer()
484             );
485         }
486 
487         // If the elem stack is empty, then it was an empty root
488         if (isRoot) {
489             gotData = false;
490         }
491         else
492         {
493             // Restore the grammar
494             fGrammar = fElemStack.getCurrentGrammar();
495             fGrammarType = fGrammar->getGrammarType();
496             fValidator->setGrammar(fGrammar);
497 
498             // Restore the validation flag
499             fValidate = fElemStack.getValidationFlag();
500         }
501     }
502 
503     return true;
504 }
505 
506 // ---------------------------------------------------------------------------
507 //  XSAXMLScanner: XMLScanner virtual methods
508 // ---------------------------------------------------------------------------
509 //  This method will reset the scanner data structures, and related plugged
510 //  in stuff, for a new scan session. We get the input source for the primary
511 //  XML entity, create the reader for it, and push it on the stack so that
512 //  upon successful return from here we are ready to go.
scanReset(const InputSource & src)513 void XSAXMLScanner::scanReset(const InputSource& src)
514 {
515     fGrammar = fSchemaGrammar;
516     fGrammarType = Grammar::SchemaGrammarType;
517     fRootGrammar = fSchemaGrammar;
518 
519     fValidator->setGrammar(fGrammar);
520 
521     // Reset validation
522     fValidate = true;
523 
524     //  And for all installed handlers, send reset events. This gives them
525     //  a chance to flush any cached data.
526     if (fDocHandler)
527         fDocHandler->resetDocument();
528     if (fEntityHandler)
529         fEntityHandler->resetEntities();
530     if (fErrorReporter)
531         fErrorReporter->resetErrors();
532 
533     // Clear out the id reference list
534     resetValidationContext();
535 
536     // Reset the Root Element Name
537     if (fRootElemName) {
538         fMemoryManager->deallocate(fRootElemName);//delete [] fRootElemName;
539     }
540 
541     fRootElemName = 0;
542 
543     //  Reset the element stack, and give it the latest ids for the special
544     //  URIs it has to know about.
545     fElemStack.reset
546     (
547         fEmptyNamespaceId, fUnknownNamespaceId, fXMLNamespaceId, fXMLNSNamespaceId
548     );
549 
550     if (!fSchemaNamespaceId)
551         fSchemaNamespaceId  = fURIStringPool->addOrFind(SchemaSymbols::fgURI_XSI);
552 
553     // Reset some status flags
554     fInException = false;
555     fStandalone = false;
556     fErrorCount = 0;
557     fHasNoDTD = true;
558     fSeeXsi = false;
559     fDoNamespaces = true;
560     fDoSchema = true;
561 
562     // Reset the validators
563     fSchemaValidator->reset();
564     fSchemaValidator->setErrorReporter(fErrorReporter);
565     fSchemaValidator->setExitOnFirstFatal(fExitOnFirstFatal);
566     fSchemaValidator->setGrammarResolver(fGrammarResolver);
567 
568     //  Handle the creation of the XML reader object for this input source.
569     //  This will provide us with transcoding and basic lexing services.
570     XMLReader* newReader = fReaderMgr.createReader
571     (
572         src
573         , true
574         , XMLReader::RefFrom_NonLiteral
575         , XMLReader::Type_General
576         , XMLReader::Source_External
577         , fCalculateSrcOfs
578         , fLowWaterMark
579     );
580 
581     if (!newReader) {
582         if (src.getIssueFatalErrorIfNotFound())
583             ThrowXMLwithMemMgr1(RuntimeException, XMLExcepts::Scan_CouldNotOpenSource, src.getSystemId(), fMemoryManager);
584         else
585             ThrowXMLwithMemMgr1(RuntimeException, XMLExcepts::Scan_CouldNotOpenSource_Warning, src.getSystemId(), fMemoryManager);
586     }
587 
588     // Push this read onto the reader manager
589     fReaderMgr.pushReader(newReader, 0);
590 
591     // and reset security-related things if necessary:
592     if(fSecurityManager != 0)
593     {
594         fEntityExpansionLimit = fSecurityManager->getEntityExpansionLimit();
595         fEntityExpansionCount = 0;
596     }
597     fElemCount = 0;
598     if (fUIntPoolRowTotal >= 32)
599     { // 8 KB tied up with validating attributes...
600         fAttDefRegistry->removeAll();
601         recreateUIntPool();
602     }
603     else
604     {
605         // note that this will implicitly reset the values of the hashtables,
606         // though their buckets will still be tied up
607         resetUIntPool();
608     }
609     fUndeclaredAttrRegistry->removeAll();
610 }
611 
612 
scanRawAttrListforNameSpaces(XMLSize_t attCount)613 void XSAXMLScanner::scanRawAttrListforNameSpaces(XMLSize_t attCount)
614 {
615     //  Make an initial pass through the list and find any xmlns attributes or
616     //  schema attributes.
617     //  When we find one, send it off to be used to update the element stack's
618     //  namespace mappings.
619     XMLSize_t index = 0;
620     for (index = 0; index < attCount; index++)
621     {
622         // each attribute has the prefix:suffix="value"
623         const KVStringPair* curPair = fRawAttrList->elementAt(index);
624         const XMLCh* rawPtr = curPair->getKey();
625 
626         //  If either the key begins with "xmlns:" or its just plain
627         //  "xmlns", then use it to update the map.
628         if (!XMLString::compareNString(rawPtr, XMLUni::fgXMLNSColonString, 6)
629         ||  XMLString::equals(rawPtr, XMLUni::fgXMLNSString))
630         {
631             const XMLCh* valuePtr = curPair->getValue();
632 
633             updateNSMap(rawPtr, valuePtr, fRawAttrColonList[index]);
634 
635             // if the schema URI is seen in the the valuePtr, set the boolean seeXsi
636             if (XMLString::equals(valuePtr, SchemaSymbols::fgURI_XSI)) {
637                 fSeeXsi = true;
638             }
639         }
640     }
641 
642     // walk through the list again to deal with "xsi:...."
643     if (fSeeXsi)
644     {
645         //  Schema Xsi Type yyyy (e.g. xsi:type="yyyyy")
646         XMLBufBid bbXsi(&fBufMgr);
647         XMLBuffer& fXsiType = bbXsi.getBuffer();
648 
649         QName attName(fMemoryManager);
650 
651         for (index = 0; index < attCount; index++)
652         {
653             // each attribute has the prefix:suffix="value"
654             const KVStringPair* curPair = fRawAttrList->elementAt(index);
655             const XMLCh* rawPtr = curPair->getKey();
656 
657             attName.setName(rawPtr, fEmptyNamespaceId);
658             const XMLCh* prefPtr = attName.getPrefix();
659 
660             // if schema URI has been seen, scan for the schema location and uri
661             // and resolve the schema grammar; or scan for schema type
662             if (resolvePrefix(prefPtr, ElemStack::Mode_Attribute) == fSchemaNamespaceId) {
663 
664                 const XMLCh* valuePtr = curPair->getValue();
665                 const XMLCh* suffPtr = attName.getLocalPart();
666 
667                 if (XMLString::equals(suffPtr, SchemaSymbols::fgXSI_TYPE))
668                 {
669                     // normalize the attribute according to schema whitespace facet
670                     DatatypeValidator* tempDV = DatatypeValidatorFactory::getBuiltInRegistry()->get(SchemaSymbols::fgDT_QNAME);
671                     ((SchemaValidator*) fValidator)->normalizeWhiteSpace(tempDV, valuePtr, fXsiType, true);
672                 }
673                 else if (XMLString::equals(suffPtr, SchemaSymbols::fgATT_NILL))
674                 {
675                     // normalize the attribute according to schema whitespace facet
676                     XMLBuffer& fXsiNil = fBufMgr.bidOnBuffer();
677                     DatatypeValidator* tempDV = DatatypeValidatorFactory::getBuiltInRegistry()->get(SchemaSymbols::fgDT_BOOLEAN);
678                     ((SchemaValidator*) fValidator)->normalizeWhiteSpace(tempDV, valuePtr, fXsiNil, true);
679                     if(XMLString::equals(fXsiNil.getRawBuffer(), SchemaSymbols::fgATTVAL_TRUE))
680                         ((SchemaValidator*)fValidator)->setNillable(true);
681                     else if(XMLString::equals(fXsiNil.getRawBuffer(), SchemaSymbols::fgATTVAL_FALSE))
682                         ((SchemaValidator*)fValidator)->setNillable(false);
683                     else
684                         emitError(XMLErrs::InvalidAttValue, fXsiNil.getRawBuffer(), valuePtr);
685                     fBufMgr.releaseBuffer(fXsiNil);
686                 }
687             }
688         }
689 
690         if (!fXsiType.isEmpty())
691         {
692             int colonPos = -1;
693             unsigned int uriId = resolveQName
694             (
695                 fXsiType.getRawBuffer(), fPrefixBuf, ElemStack::Mode_Element, colonPos
696             );
697             ((SchemaValidator*)fValidator)->setXsiType(fPrefixBuf.getRawBuffer(), fXsiType.getRawBuffer() + colonPos + 1, uriId);
698         }
699     }
700 }
701 
switchGrammar(const XMLCh * const uriStr,bool laxValidate)702 void XSAXMLScanner::switchGrammar( const XMLCh* const uriStr
703                                  , bool laxValidate)
704 {
705     Grammar* tempGrammar = 0;
706 
707     if (XMLString::equals(uriStr, SchemaSymbols::fgURI_SCHEMAFORSCHEMA)) {
708         tempGrammar = fSchemaGrammar;
709     }
710     else {
711         tempGrammar = fGrammarResolver->getGrammar(uriStr);
712     }
713 
714     if (tempGrammar && tempGrammar->getGrammarType() == Grammar::SchemaGrammarType)
715     {
716         fGrammar = tempGrammar;
717         fGrammarType = Grammar::SchemaGrammarType;
718         fValidator->setGrammar(fGrammar);
719     }
720     else if(!laxValidate) {
721         fValidator->emitError(XMLValid::GrammarNotFound, uriStr);
722     }
723 }
724 
725 XERCES_CPP_NAMESPACE_END
726