void SGXMLScanner::resolveSchemaGrammar()

in src/xercesc/internal/SGXMLScanner.cpp [3586:3847]


void SGXMLScanner::resolveSchemaGrammar(const XMLCh* const loc, const XMLCh* const uri, bool ignoreLoadSchema) {

    Grammar* grammar = 0;

    {
        XMLSchemaDescriptionImpl    theSchemaDescription(uri, fMemoryManager);
        theSchemaDescription.setLocationHints(loc);
        grammar = fGrammarResolver->getGrammar(&theSchemaDescription);
    }

    // If multi-import is enabled, make sure the existing grammar came
    // from the import directive. Otherwise we may end up reloading
    // the same schema that came from the external grammar pool. Ideally,
    // we would move fSchemaInfoList to XMLGrammarPool so that it survives
    // the destruction of the scanner in which case we could rely on the
    // same logic we use to weed out duplicate schemas below.
    //
    if (!grammar || grammar->getGrammarType() == Grammar::DTDGrammarType ||
        (getHandleMultipleImports() &&
         ((XMLSchemaDescription*)grammar->getGrammarDescription())->
         getContextType () == XMLSchemaDescription::CONTEXT_IMPORT))
    {
      if (fLoadSchema || ignoreLoadSchema)
      {
        XSDDOMParser parser(0, fMemoryManager, 0);

        parser.setValidationScheme(XercesDOMParser::Val_Never);
        parser.setDoNamespaces(true);
        parser.setUserEntityHandler(fEntityHandler);
        parser.setUserErrorReporter(fErrorReporter);

        //Normalize sysId
        XMLBufBid nnSys(&fBufMgr);
        XMLBuffer& normalizedSysId = nnSys.getBuffer();
        XMLString::removeChar(loc, 0xFFFF, normalizedSysId);
        const XMLCh* normalizedURI = normalizedSysId.getRawBuffer();

        // Create a buffer for expanding the system id
        XMLBufBid bbSys(&fBufMgr);
        XMLBuffer& expSysId = bbSys.getBuffer();

        //  Allow the entity handler to expand the system id if they choose
        //  to do so.
        InputSource* srcToFill = 0;
        if (fEntityHandler)
        {
            if (!fEntityHandler->expandSystemId(normalizedURI, expSysId))
                expSysId.set(normalizedURI);

            ReaderMgr::LastExtEntityInfo lastInfo;
            fReaderMgr.getLastExtEntityInfo(lastInfo);
            XMLResourceIdentifier resourceIdentifier(XMLResourceIdentifier::SchemaGrammar,
                            expSysId.getRawBuffer(), uri, XMLUni::fgZeroLenString, lastInfo.systemId,
                            &fReaderMgr);
            srcToFill = fEntityHandler->resolveEntity(&resourceIdentifier);
        }
        else
        {
            expSysId.set(normalizedURI);
        }

        //  If they didn't create a source via the entity handler, then we
        //  have to create one on our own.
        if (!srcToFill)
        {
            if (fDisableDefaultEntityResolution)
                return;

            ReaderMgr::LastExtEntityInfo lastInfo;
            fReaderMgr.getLastExtEntityInfo(lastInfo);

            XMLURL urlTmp(fMemoryManager);
            if ((!urlTmp.setURL(lastInfo.systemId, expSysId.getRawBuffer(), urlTmp)) ||
                (urlTmp.isRelative()))
            {
                if (!fStandardUriConformant)
                {
                    XMLBufBid  ddSys(&fBufMgr);
                    XMLBuffer& resolvedSysId = ddSys.getBuffer();
                    XMLUri::normalizeURI(expSysId.getRawBuffer(), resolvedSysId);

                    srcToFill = new (fMemoryManager) LocalFileInputSource
                    (
                        lastInfo.systemId
                        , resolvedSysId.getRawBuffer()
                        , fMemoryManager
                    );
                }
                else
                    ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager);
            }
            else
            {
                if (fStandardUriConformant && urlTmp.hasInvalidChar())
                    ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager);

                srcToFill = new (fMemoryManager) URLInputSource(urlTmp, fMemoryManager);
            }
        }

        // Put a janitor on the input source
        Janitor<InputSource> janSrc(srcToFill);

        // Check if this exact schema has already been seen.
        //
        const XMLCh* sysId = srcToFill->getSystemId();
        unsigned int uriId = (uri && *uri) ? fURIStringPool->addOrFind(uri) : fEmptyNamespaceId;
        SchemaInfo* importSchemaInfo = 0;

        if (fUseCachedGrammar)
          importSchemaInfo = fCachedSchemaInfoList->get(sysId, uriId);

        if (!importSchemaInfo && !fToCacheGrammar)
          importSchemaInfo = fSchemaInfoList->get(sysId, uriId);

        if (importSchemaInfo)
        {
          // We haven't added any new grammars so it is safe to just
          // return.
          //
          return;
        }

        // Should just issue warning if the schema is not found
        bool flag = srcToFill->getIssueFatalErrorIfNotFound();
        srcToFill->setIssueFatalErrorIfNotFound(false);

        parser.parse(*srcToFill);

        // Reset the InputSource
        srcToFill->setIssueFatalErrorIfNotFound(flag);

        if (parser.getSawFatal() && fExitOnFirstFatal)
            emitError(XMLErrs::SchemaScanFatalError);

        DOMDocument* document = parser.getDocument(); //Our Grammar

        if (document != 0) {

            DOMElement* root = document->getDocumentElement();// This is what we pass to TraverserSchema
            if (root != 0)
            {
                const XMLCh* newUri = root->getAttribute(SchemaSymbols::fgATT_TARGETNAMESPACE);
                bool newGrammar = false;
                if (!XMLString::equals(newUri, uri)) {
                    if (fValidate || fValScheme == Val_Auto) {
                        fValidator->emitError(XMLValid::WrongTargetNamespace, loc, uri);
                    }

                    grammar = fGrammarResolver->getGrammar(newUri);
                    newGrammar = true;
                }

                if (!grammar ||
                    grammar->getGrammarType() == Grammar::DTDGrammarType ||
                    (getHandleMultipleImports() &&
                     ((XMLSchemaDescription*) grammar->getGrammarDescription())->
                     getContextType () == XMLSchemaDescription::CONTEXT_IMPORT))
                {
                    // If we switched namespace URI, recheck the schema info.
                    //
                    if (newGrammar)
                    {
                      unsigned int newUriId = (newUri && *newUri) ? fURIStringPool->addOrFind(newUri) : fEmptyNamespaceId;

                      if (fUseCachedGrammar)
                        importSchemaInfo = fCachedSchemaInfoList->get(sysId, newUriId);

                      if (!importSchemaInfo && !fToCacheGrammar)
                        importSchemaInfo = fSchemaInfoList->get(sysId, newUriId);

                      if (importSchemaInfo)
                        return;
                    }

                    //  Since we have seen a grammar, set our validation flag
                    //  at this point if the validation scheme is auto
                    if (fValScheme == Val_Auto && !fValidate) {
                        fValidate = true;
                        fElemStack.setValidationFlag(fValidate);
                    }

                    bool grammarFound = grammar &&
                      grammar->getGrammarType() == Grammar::SchemaGrammarType;

                    SchemaGrammar* schemaGrammar;

                    if (grammarFound) {
                      schemaGrammar = (SchemaGrammar*) grammar;
                    }
                    else {
                      schemaGrammar = new (fGrammarPoolMemoryManager) SchemaGrammar(fGrammarPoolMemoryManager);
                    }

                    XMLSchemaDescription* gramDesc = (XMLSchemaDescription*) schemaGrammar->getGrammarDescription();

                    gramDesc->setContextType(XMLSchemaDescription::CONTEXT_PREPARSE);
                    gramDesc->setLocationHints(sysId);

                    TraverseSchema traverseSchema
                    (
                        root
                        , fURIStringPool
                        , schemaGrammar
                        , fGrammarResolver
                        , fUseCachedGrammar ? fCachedSchemaInfoList : fSchemaInfoList
                        , fToCacheGrammar ? fCachedSchemaInfoList : fSchemaInfoList
                        , this
                        , sysId
                        , fEntityHandler
                        , fErrorReporter
                        , fMemoryManager
                        , grammarFound
                    );

                    // Reset the now invalid schema roots in the collected
                    // schema info entries.
                    //
                    {
                      RefHash2KeysTableOfEnumerator<SchemaInfo> i (
                        fToCacheGrammar ? fCachedSchemaInfoList : fSchemaInfoList);

                      while (i.hasMoreElements ())
                        i.nextElement().resetRoot ();
                    }

                    if (fGrammarType == Grammar::DTDGrammarType) {
                        fGrammar = schemaGrammar;
                        fGrammarType = Grammar::SchemaGrammarType;
                        fValidator->setGrammar(fGrammar);
                    }

                    if (fValidate) {
                        //  validate the Schema scan so far
                        fValidator->preContentValidation(false);
                    }
                }
            }
        }
      }
    }
    else
    {
        //  Since we have seen a grammar, set our validation flag
        //  at this point if the validation scheme is auto
        if (fValScheme == Val_Auto && !fValidate) {
            fValidate = true;
            fElemStack.setValidationFlag(fValidate);
        }

        // we have seen a schema, so set up the fValidator as fSchemaValidator
        if (fGrammarType == Grammar::DTDGrammarType) {
            fGrammar = grammar;
            fGrammarType = Grammar::SchemaGrammarType;
            fValidator->setGrammar(fGrammar);
        }
    }
    // update fModel; rely on the grammar resolver to do this
    // efficiently
    if(getPSVIHandler())
        fModel = fGrammarResolver->getXSModel();
}