source: icXML/icXML-devel/src/icxercesc/internal/XSAXMLScanner.cpp @ 3104

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

Additional files for icXML 0.9

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