source: icXML/icXML-devel/src/icxercesc/internal/XSAXMLScanner.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: 18.2 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: XSAXMLScanner.cpp 833045 2009-11-05 13:21:27Z borisk $
20 */
21
22
23// ---------------------------------------------------------------------------
24//  Includes
25// ---------------------------------------------------------------------------
26#include <icxercesc/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
35XERCES_CPP_NAMESPACE_BEGIN
36
37// ---------------------------------------------------------------------------
38//  XSAXMLScanner: Constructors and Destructor
39// ---------------------------------------------------------------------------
40XSAXMLScanner::XSAXMLScanner( GrammarResolver* const grammarResolver
41                                                        , XMLStringPool* const
42                                                        , SchemaGrammar* const
43                                                        , MemoryManager* const manager) :
44
45        SGXMLScanner(0, grammarResolver, manager)
46{
47        DEPRECATED_FEATURE_IN_ICXML;
48}
49
50XSAXMLScanner::XSAXMLScanner( GrammarResolver* const grammarResolver
51                                                        , XMLNamespaceResolver* const uriResolver
52                                                        , SchemaGrammar* const   xsaGrammar
53                                                        , MemoryManager* const manager) :
54
55        SGXMLScanner(0, grammarResolver, manager)
56{
57        fSchemaGrammar = xsaGrammar;
58        fUriResolver = uriResolver;
59}
60
61XSAXMLScanner::~XSAXMLScanner()
62{
63}
64
65// ---------------------------------------------------------------------------
66//  XSAXMLScanner: SGXMLScanner virtual methods
67// ---------------------------------------------------------------------------
68//  This method will kick off the scanning of the primary content of the
69void XSAXMLScanner::scanEndTag(bool& gotData)
70{
71        //  Assume we will still have data until proven otherwise. It will only
72        //  ever be false if this is the end of the root element.
73        gotData = true;
74
75        //  Check if the element stack is empty. If so, then this is an unbalanced
76        //  element (i.e. more ends than starts, perhaps because of bad text
77        //  causing one to be skipped.)
78        if (fElemStack.isEmpty())
79        {
80                emitError(XMLErrs::MoreEndThanStartTags);
81                fReaderMgr.skipPastChar(chCloseAngle);
82                ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Scan_UnbalancedStartEnd, fMemoryManager);
83        }
84
85        //  Pop the stack of the element we are supposed to be ending. Remember
86        //  that we don't own this. The stack just keeps them and reuses them.
87        unsigned int uriId = fElemStack.getCurrentURI();
88#ifndef PERFORM_ELEMENT_STACK_MATCHING_IN_PARSER
89        // Make sure that its the end of the element that we expect
90        const XMLCh *elemName = fElemStack.getCurrentSchemaElemName();
91#endif
92
93        const ElemStack::StackElem* topElem = fElemStack.popTop();
94#ifndef PERFORM_ELEMENT_STACK_MATCHING_IN_PARSER
95        if (!fReaderMgr.skippedStringLong(elemName))
96        {
97                emitError
98                (
99                        XMLErrs::ExpectedEndOfTagX, elemName
100                );
101                fReaderMgr.skipPastChar(chCloseAngle);
102                return;
103        }
104#endif
105
106        // See if it was the root element, to avoid multiple calls below
107        const bool isRoot = fElemStack.isEmpty();
108
109        // Make sure we are back on the same reader as where we started
110        if (topElem->fReaderNum != fReaderMgr.getCurrentReaderNum())
111                emitError(XMLErrs::PartialTagMarkupError);
112
113        // Skip optional whitespace
114        fReaderMgr.skipPastSpaces();
115
116        // Make sure we find the closing bracket
117        if (!fReaderMgr.skippedChar(chCloseAngle))
118        {
119                emitError
120                (
121                        XMLErrs::UnterminatedEndTag, topElem->fThisElement->getFullName()
122                );
123        }
124
125        #ifndef STORE_CHILDREN_INFORMATION_IN_PARSER
126        //  If validation is enabled, then lets pass him the list of children and
127        //  this element and let him validate it.
128        if (fValidate)
129        {
130                XMLSize_t failure;
131                bool res = fValidator->checkContent
132                (
133                        topElem->fThisElement
134                        , topElem->fChildren
135                        , topElem->fChildCount
136                        , &failure
137                );
138
139                if (!res)
140                {
141                        //  One of the elements is not valid for the content. NOTE that
142                        //  if no children were provided but the content model requires
143                        //  them, it comes back with a zero value. But we cannot use that
144                        //  to index the child array in this case, and have to put out a
145                        //  special message.
146                        if (!topElem->fChildCount)
147                        {
148                                fValidator->emitError
149                                (
150                                        XMLValid::EmptyNotValidForContent
151                                        , topElem->fThisElement->getFormattedContentModel()
152                                );
153                        }
154                        else if (failure >= topElem->fChildCount)
155                        {
156                                fValidator->emitError
157                                (
158                                        XMLValid::NotEnoughElemsForCM
159                                        , topElem->fThisElement->getFormattedContentModel()
160                                );
161                        }
162                        else
163                        {
164                                fValidator->emitError
165                                (
166                                        XMLValid::ElementNotValidForContent
167                                        , topElem->fChildren[failure]->getRawName()
168                                        , topElem->fThisElement->getFormattedContentModel()
169                                );
170                        }
171                }
172        }
173        #endif
174
175        // now we can reset the datatype buffer, since the
176        // application has had a chance to copy the characters somewhere else
177        ((SchemaValidator *)fValidator)->clearDatatypeBuffer();
178
179        // If we have a doc handler, tell it about the end tag
180        if (fDocHandler)
181        {
182                fDocHandler->endElement
183                (
184                        *topElem->fThisElement
185                        , uriId
186                        , isRoot
187                        , topElem->fThisElement->getElementName()->getPrefix()
188                );
189        }
190
191        // If this was the root, then done with content
192        gotData = !isRoot;
193
194        if (gotData) {
195
196                // Restore the grammar
197                fGrammar = fElemStack.getCurrentGrammar();
198                fGrammarType = fGrammar->getGrammarType();
199                fValidator->setGrammar(fGrammar);
200
201                // Restore the validation flag
202                fValidate = fElemStack.getValidationFlag();
203        }
204}
205
206bool XSAXMLScanner::scanStartTag(bool& gotData)
207{
208        //  Assume we will still have data until proven otherwise. It will only
209        //  ever be false if this is the root and its empty.
210        gotData = true;
211
212        // Reset element content
213        fContent.reset();
214
215        //  The current position is after the open bracket, so we need to read in
216        //  in the element name.
217        int prefixColonPos;
218        if (!fReaderMgr.getQName(fQNameBuf, &prefixColonPos))
219        {
220                if (fQNameBuf.isEmpty())
221                        emitError(XMLErrs::ExpectedElementName);
222                else
223                        emitError(XMLErrs::InvalidElementName, fQNameBuf.getRawBuffer());
224                fReaderMgr.skipToChar(chOpenAngle);
225                return false;
226        }
227
228        // See if its the root element
229        const bool isRoot = fElemStack.isEmpty();
230
231        // Skip any whitespace after the name
232        fReaderMgr.skipPastSpaces();
233
234        //  First we have to do the rawest attribute scan. We don't do any
235        //  normalization of them at all, since we don't know yet what type they
236        //  might be (since we need the element decl in order to do that.)
237        const XMLCh* qnameRawBuf = fQNameBuf.getRawBuffer();
238        bool isEmpty;
239        XMLSize_t attCount = rawAttrScan(qnameRawBuf, *fRawAttrList, isEmpty);
240
241        // save the contentleafname and currentscope before addlevel, for later use
242        ContentLeafNameTypeVector* cv = 0;
243        XMLContentModel* cm = 0;
244        unsigned int currentScope = Grammar::TOP_LEVEL_SCOPE;
245        bool laxThisOne = false;
246        if (!isRoot)
247        {
248                // schema validator will have correct type if validating
249                SchemaElementDecl* tempElement = (SchemaElementDecl*)
250                        fElemStack.topElement()->fThisElement;
251                SchemaElementDecl::ModelTypes modelType = tempElement->getModelType();
252                ComplexTypeInfo *currType = 0;
253
254                if (fValidate)
255                {
256                        currType = ((SchemaValidator*)fValidator)->getCurrentTypeInfo();
257                        if (currType)
258                                modelType = (SchemaElementDecl::ModelTypes)currType->getContentType();
259                        else // something must have gone wrong
260                                modelType = SchemaElementDecl::Any;
261                }
262                else {
263                        currType = tempElement->getComplexTypeInfo();
264                }
265
266                if ((modelType == SchemaElementDecl::Mixed_Simple)
267                  ||  (modelType == SchemaElementDecl::Mixed_Complex)
268                  ||  (modelType == SchemaElementDecl::Children))
269                {
270                        cm = currType->getContentModel();
271                        cv = cm->getContentLeafNameTypeVector();
272                        currentScope = fElemStack.getCurrentScope();
273                }
274                else if (modelType == SchemaElementDecl::Any) {
275                        laxThisOne = true;
276                }
277        }
278
279        //  Now, since we might have to update the namespace map for this element,
280        //  but we don't have the element decl yet, we just tell the element stack
281        //  to expand up to get ready.
282        XMLSize_t elemDepth = fElemStack.addLevel();
283        fElemStack.setValidationFlag(fValidate);
284
285        //fElemStack.setPrefixColonPos(prefixColonPos);
286
287        //  Make an initial pass through the list and find any xmlns attributes or
288        //  schema attributes.
289        if (attCount)
290                scanRawAttrListforNameSpaces(attCount);
291
292        //  Resolve the qualified name to a URI and name so that we can look up
293        //  the element decl for this element. We have now update the prefix to
294        //  namespace map so we should get the correct element now.
295        unsigned int uriId = resolveQNameWithColon
296        (
297                qnameRawBuf, fPrefixBuf, ElemStack::Mode_Element, prefixColonPos
298        );
299
300        //if schema, check if we should lax or skip the validation of this element
301        bool parentValidation = fValidate;
302        if (cv)
303        {
304                QName element(fPrefixBuf.getRawBuffer(), &qnameRawBuf[prefixColonPos + 1], uriId, fMemoryManager);
305                // elementDepth will be > 0, as cv is only constructed if element is not
306                // root.
307                laxThisOne = laxElementValidation(&element, cv, cm, elemDepth - 1);
308        }
309
310        //  Look up the element now in the grammar. This will get us back a
311        //  generic element decl object. We tell him to fault one in if he does
312        //  not find it.
313        bool wasAdded = false;
314        const XMLCh* nameRawBuf = &qnameRawBuf[prefixColonPos + 1];
315        XMLElementDecl* elemDecl = fGrammar->getElemDecl
316        (
317                uriId, nameRawBuf, qnameRawBuf, currentScope
318        );
319
320        if (!elemDecl)
321        {
322                // URI is different, so we try to switch grammar
323                if (uriId != fUriResolver->resolveUriId(fGrammar->getTargetNamespace()))
324                {
325                        switchGrammar(fUriResolver->getUriForId(uriId), laxThisOne);
326                }
327
328
329                // look for a global element declaration
330                elemDecl = fGrammar->getElemDecl(
331                        uriId, nameRawBuf, qnameRawBuf, Grammar::TOP_LEVEL_SCOPE
332                );
333
334                if (!elemDecl)
335                {
336                        // if still not found, look in list of undeclared elements
337                        elemDecl = fElemNonDeclPool->getByKey(
338                                nameRawBuf, uriId, (int)Grammar::TOP_LEVEL_SCOPE);
339
340                        if (!elemDecl)
341                        {
342                                elemDecl = new (fMemoryManager) SchemaElementDecl
343                                (
344                                        fPrefixBuf.getRawBuffer(), nameRawBuf, uriId
345                                        , SchemaElementDecl::Any, Grammar::TOP_LEVEL_SCOPE
346                                        , fMemoryManager
347                                );
348
349                                elemDecl->setId (fElemNonDeclPool->put(
350                                          (void*)elemDecl->getBaseName(),
351                                          uriId,
352                                          (int)Grammar::TOP_LEVEL_SCOPE,
353                                          (SchemaElementDecl*)elemDecl));
354
355                                wasAdded = true;
356                        }
357                                }
358        }
359
360        //  We do something different here according to whether we found the
361        //  element or not.
362        bool bXsiTypeSet= (fValidator)?((SchemaValidator*)fValidator)->getIsXsiTypeSet():false;
363        if (wasAdded || !elemDecl->isDeclared())
364        {
365                if (laxThisOne && !bXsiTypeSet) {
366                        fValidate = false;
367                        fElemStack.setValidationFlag(fValidate);
368                }
369
370                // If validating then emit an error
371                if (fValidate)
372                {
373                        // This is to tell the reuse Validator that this element was
374                        // faulted-in, was not an element in the grammar pool originally
375                        elemDecl->setCreateReason(XMLElementDecl::JustFaultIn);
376
377                        if(!bXsiTypeSet)
378                                fValidator->emitError
379                                (
380                                        XMLValid::ElementNotDefined, elemDecl->getFullName()
381                                );
382                }
383        }
384
385        //  Now we can update the element stack to set the current element
386        //  decl. We expanded the stack above, but couldn't store the element
387        //  decl because we didn't know it yet.
388        fElemStack.setElement(elemDecl, fReaderMgr.getCurrentReaderNum());
389
390        if (isRoot)
391        {
392                fRootElemName = XMLString::replicate(qnameRawBuf, fMemoryManager);
393        }
394
395        //  Validate the element
396        if (fValidate) {
397                fValidator->validateElement(elemDecl);
398        }
399
400        ComplexTypeInfo* typeinfo = (fValidate)
401                ? ((SchemaValidator*)fValidator)->getCurrentTypeInfo()
402                : ((SchemaElementDecl*) elemDecl)->getComplexTypeInfo();
403
404        if (typeinfo)
405        {
406                currentScope = typeinfo->getScopeDefined();
407
408                // switch grammar if the typeinfo has a different grammar
409                XMLCh* typeName = typeinfo->getTypeName();
410                int comma = XMLString::indexOf(typeName, chComma);
411                if (comma > 0)
412                {
413                        XMLBufBid bbPrefix(&fBufMgr);
414                        XMLBuffer& prefixBuf = bbPrefix.getBuffer();
415
416                        prefixBuf.append(typeName, comma);
417                        switchGrammar(prefixBuf.getRawBuffer(), laxThisOne);
418                }
419        }
420        fElemStack.setCurrentScope(currentScope);
421
422        // Set element next state
423        if (elemDepth >= fElemStateSize)
424        {
425                resizeElemState();
426        }
427
428        fElemState[elemDepth] = 0;
429        fElemLoopState[elemDepth] = 0;
430        fElemStack.setCurrentGrammar(fGrammar);
431
432        //  If this is the first element and we are validating, check the root
433        //  element.
434        if (!isRoot && parentValidation)
435        {
436                fElemStack.addChild(elemDecl->getElementName(), true);
437        }
438
439        //  Now lets get the fAttrList filled in. This involves faulting in any
440        //  defaulted and fixed attributes and normalizing the values of any that
441        //  we got explicitly.
442        //
443        //  We update the attCount value with the total number of attributes, but
444        //  it goes in with the number of values we got during the raw scan of
445        //  explictly provided attrs above.
446        attCount = buildAttList(*fRawAttrList, attCount, elemDecl, fAttrList);
447
448        if(attCount)
449        {
450                // clean up after ourselves:
451                // clear the map used to detect duplicate attributes
452                fUndeclaredAttrRegistry->removeAll();
453        }
454
455        // Since the element may have default values, call start tag now regardless if it is empty or not
456        // If we have a document handler, then tell it about this start tag
457        if (fDocHandler)
458        {
459                fDocHandler->startElement
460                (
461                        *elemDecl, uriId, fPrefixBuf.getRawBuffer(), fAttrList
462                        , attCount, false, isRoot
463                );
464        } // may be where we output something...
465
466        //  If empty, validate content right now if we are validating and then
467        //  pop the element stack top. Else, we have to update the current stack
468        //  top's namespace mapping elements.
469        if (isEmpty)
470        {
471                // Pop the element stack back off since it'll never be used now
472                fElemStack.popTop();
473
474                // If validating, then insure that its legal to have no content
475                if (fValidate)
476                {
477                        XMLSize_t failure;
478                        bool res = fValidator->checkContent(elemDecl, ((XMLElementDecl**)0), 0, &failure);
479                        if (!res)
480                        {
481                                // REVISIT:  in the case of xsi:type, this may
482                                // return the wrong string...
483                                fValidator->emitError
484                                (
485                                        XMLValid::ElementNotValidForContent
486                                        , elemDecl->getFullName()
487                                        , elemDecl->getFormattedContentModel()
488                                );
489                        }
490                }
491
492                // If we have a doc handler, tell it about the end tag
493                if (fDocHandler)
494                {
495                        fDocHandler->endElement
496                        (
497                                *elemDecl, uriId, isRoot, fPrefixBuf.getRawBuffer()
498                        );
499                }
500
501                // If the elem stack is empty, then it was an empty root
502                if (isRoot) {
503                        gotData = false;
504                }
505                else
506                {
507                        // Restore the grammar
508                        fGrammar = fElemStack.getCurrentGrammar();
509                        fGrammarType = fGrammar->getGrammarType();
510                        fValidator->setGrammar(fGrammar);
511
512                        // Restore the validation flag
513                        fValidate = fElemStack.getValidationFlag();
514                }
515        }
516
517        return true;
518}
519
520// ---------------------------------------------------------------------------
521//  XSAXMLScanner: XMLScanner virtual methods
522// ---------------------------------------------------------------------------
523//  This method will reset the scanner data structures, and related plugged
524//  in stuff, for a new scan session. We get the input source for the primary
525//  XML entity, create the reader for it, and push it on the stack so that
526//  upon successful return from here we are ready to go.
527void XSAXMLScanner::scanReset(const InputSource& src)
528{
529        fGrammar = fSchemaGrammar;
530        fGrammarType = Grammar::SchemaGrammarType;
531        fRootGrammar = fSchemaGrammar;
532
533        fValidator->setGrammar(fGrammar);
534
535        // Reset validation
536        fValidate = true;
537
538        //  And for all installed handlers, send reset events. This gives them
539        //  a chance to flush any cached data.
540        if (fDocHandler)
541                fDocHandler->resetDocument();
542        if (fEntityHandler)
543                fEntityHandler->resetEntities();
544        if (fErrorReporter)
545                fErrorReporter->resetErrors();
546
547        // Clear out the id reference list
548        resetValidationContext();
549
550        // Reset the Root Element Name
551        fRootElemName = 0;
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        fUndeclaredAttrRegistry->removeAll();
599}
600
601
602void XSAXMLScanner::scanRawAttrListforNameSpaces(XMLSize_t attCount)
603{
604        DEPRECATED_FEATURE_IN_ICXML;
605}
606
607void XSAXMLScanner::switchGrammar( const XMLCh* const uriStr
608                                                                 , bool laxValidate)
609{
610        Grammar* tempGrammar = 0;
611
612        if (XMLString::equals(uriStr, SchemaSymbols::fgURI_SCHEMAFORSCHEMA))
613        {
614                tempGrammar = fSchemaGrammar;
615        }
616        else
617        {
618                tempGrammar = fGrammarResolver->getGrammar(uriStr);
619        }
620
621        if (tempGrammar && tempGrammar->getGrammarType() == Grammar::SchemaGrammarType)
622        {
623                fGrammar = tempGrammar;
624                fGrammarType = Grammar::SchemaGrammarType;
625                fValidator->setGrammar(fGrammar);
626        }
627        else if(!laxValidate) {
628                fValidator->emitError(XMLValid::GrammarNotFound, uriStr);
629        }
630}
631
632XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.