Skip to content
Snippets Groups Projects
SGXMLScanner.cpp 174 KiB
Newer Older
Khaled Noaman's avatar
Khaled Noaman committed
    if (XMLString::equals(prefix, XMLUni::fgXMLNSString))
        return fXMLNSNamespaceId;
    else if (XMLString::equals(prefix, XMLUni::fgXMLString))
        return fXMLNamespaceId;

    //  Ask the element stack to search up itself for a mapping for the
    //  passed prefix.
    bool unknown;
    unsigned int uriId = fElemStack.mapPrefixToURI(prefix, mode, unknown);

    // If it was unknown, then the URI was faked in but we have to issue an error
    if (unknown)
        emitError(XMLErrs::UnknownPrefix, prefix);

    getURIText(uriId,bufToFill);

    return uriId;
}


//  This method will reset the scanner data structures, and related plugged
//  in stuff, for a new scan session. We get the input source for the primary
//  XML entity, create the reader for it, and push it on the stack so that
//  upon successful return from here we are ready to go.
void SGXMLScanner::scanReset(const InputSource& src)
{

    //  This call implicitly tells us that we are going to reuse the scanner
    //  if it was previously used. So tell the validator to reset itself.
    //
    //  But, if the fUseCacheGrammar flag is set, then don't reset it.
    //
    //  NOTE:   The ReaderMgr is flushed on the way out, because that is
    //          required to insure that files are closed.
    fGrammarResolver->cacheGrammarFromParse(fToCacheGrammar);
    fGrammarResolver->useCachedGrammarInParse(fUseCachedGrammar);

    // fModel may need updating, as fGrammarResolver could have cleaned it
    if(fModel && getPSVIHandler())
        fModel = fGrammarResolver->getXSModel();

    // Create dummy schema grammar
    if (!fSchemaGrammar) {
        fSchemaGrammar = new (fGrammarPoolMemoryManager) SchemaGrammar(fGrammarPoolMemoryManager);
    }

Khaled Noaman's avatar
Khaled Noaman committed
    fGrammar = fSchemaGrammar;
    fGrammarType = Grammar::DTDGrammarType;
    fRootGrammar = 0;

    fValidator->setGrammar(fGrammar);
    if (fValidatorFromUser) {

        ((SchemaValidator*) fValidator)->setErrorReporter(fErrorReporter);
        ((SchemaValidator*) fValidator)->setGrammarResolver(fGrammarResolver);
        ((SchemaValidator*) fValidator)->setExitOnFirstFatal(fExitOnFirstFatal);
    }

    // Reset validation
    fValidate = (fValScheme == Val_Always) ? true : false;
Khaled Noaman's avatar
Khaled Noaman committed

    //  And for all installed handlers, send reset events. This gives them
    //  a chance to flush any cached data.
    if (fDocHandler)
        fDocHandler->resetDocument();
    if (fEntityHandler)
        fEntityHandler->resetEntities();
    if (fErrorReporter)
        fErrorReporter->resetErrors();

    // Clear out the id reference list
    resetValidationContext();
Khaled Noaman's avatar
Khaled Noaman committed

    // Reset the Root Element Name
    fMemoryManager->deallocate(fRootElemName);//delete [] fRootElemName;
    fRootElemName = 0;

Khaled Noaman's avatar
Khaled Noaman committed
    // Reset IdentityConstraints
PeiYong Zhang's avatar
PeiYong Zhang committed
    if (fICHandler)
        fICHandler->reset();
Khaled Noaman's avatar
Khaled Noaman committed

    //  Reset the element stack, and give it the latest ids for the special
    //  URIs it has to know about.
    fElemStack.reset
    (
        fEmptyNamespaceId
        , fUnknownNamespaceId
        , fXMLNamespaceId
        , fXMLNSNamespaceId
    );

    if (!fSchemaNamespaceId)
        fSchemaNamespaceId  = fURIStringPool->addOrFind(SchemaSymbols::fgURI_XSI);

    // Reset some status flags
    fInException = false;
    fStandalone = false;
    fErrorCount = 0;
    fHasNoDTD = true;
    fSeeXsi = false;
    fDoNamespaces = true;
    fDoSchema = true;

    // Reset PSVI context
    // Note that we always need this around for DOMTypeInfo
    if (!fPSVIElement)
        fPSVIElement = new (fMemoryManager) PSVIElement(fMemoryManager);
        fErrorStack = new (fMemoryManager) ValueStackOf<bool>(8, fMemoryManager);
Khaled Noaman's avatar
Khaled Noaman committed

    resetPSVIElemContext();
Khaled Noaman's avatar
Khaled Noaman committed
    // Reset the validators
    fSchemaValidator->reset();
    fSchemaValidator->setErrorReporter(fErrorReporter);
    fSchemaValidator->setExitOnFirstFatal(fExitOnFirstFatal);
    fSchemaValidator->setGrammarResolver(fGrammarResolver);
    if (fValidatorFromUser)
        fValidator->reset();

    //  Handle the creation of the XML reader object for this input source.
    //  This will provide us with transcoding and basic lexing services.
    XMLReader* newReader = fReaderMgr.createReader
    (
        src
        , true
        , XMLReader::RefFrom_NonLiteral
        , XMLReader::Type_General
        , XMLReader::Source_External
        , fCalculateSrcOfs
    );

    if (!newReader) {
        if (src.getIssueFatalErrorIfNotFound())
            ThrowXMLwithMemMgr1(RuntimeException, XMLExcepts::Scan_CouldNotOpenSource, src.getSystemId(), fMemoryManager);
Khaled Noaman's avatar
Khaled Noaman committed
        else
            ThrowXMLwithMemMgr1(RuntimeException, XMLExcepts::Scan_CouldNotOpenSource_Warning, src.getSystemId(), fMemoryManager);
Khaled Noaman's avatar
Khaled Noaman committed
    }

    // Push this read onto the reader manager
    fReaderMgr.pushReader(newReader, 0);

    // and reset security-related things if necessary:
    if(fSecurityManager != 0) 
    {
        fEntityExpansionLimit = fSecurityManager->getEntityExpansionLimit();
        fEntityExpansionCount = 0;
    }
    fElemCount = 0;
    if(fUIntPoolRowTotal >= 32) 
    { // 8 KB tied up with validating attributes...
        fAttDefRegistry->removeAll();
        recreateUIntPool();
    }
    else
    {
        // note that this will implicitly reset the values of the hashtables,
        // though their buckets will still be tied up
        resetUIntPool();
    }
    fUndeclaredAttrRegistryNS->removeAll();
Khaled Noaman's avatar
Khaled Noaman committed
}


//  This method is called between markup in content. It scans for character
//  data that is sent to the document handler. It watches for any markup
//  characters that would indicate that the character data has ended. It also
//  handles expansion of general and character entities.
//
//  sendData() is a local static helper for this method which handles some
//  code that must be done in three different places here.
void SGXMLScanner::sendCharData(XMLBuffer& toSend)
{
    // If no data in the buffer, then nothing to do
    if (toSend.isEmpty())
        return;

    //  We do different things according to whether we are validating or
    //  not. If not, its always just characters; else, it depends on the
    //  current element's content model.
    if (fValidate)
    {
        // Get the raw data we need for the callback
        const XMLCh* rawBuf = toSend.getRawBuffer();
Khaled Noaman's avatar
Khaled Noaman committed
        const unsigned int len = toSend.getLen();

        // Get the character data opts for the current element
        XMLElementDecl::CharDataOpts charOpts = XMLElementDecl::AllCharData;
        // And see if the current element is a 'Children' style content model
        ComplexTypeInfo *currType = ((SchemaValidator*)fValidator)->getCurrentTypeInfo();
        if(currType) 
        {
            SchemaElementDecl::ModelTypes modelType = (SchemaElementDecl::ModelTypes) currType->getContentType(); 
            if(modelType == SchemaElementDecl::Children) 
                charOpts = XMLElementDecl::SpacesOk;
            else if(modelType == SchemaElementDecl::Empty) 
                charOpts = XMLElementDecl::NoCharData; 
        } 

        // should not be necessary once PSVI method on element decls
        // are removed
Khaled Noaman's avatar
Khaled Noaman committed
        if (charOpts == XMLElementDecl::NoCharData)
        {
            // They definitely cannot handle any type of char data
            fValidator->emitError(XMLValid::NoCharDataInCM);
            if (getPSVIHandler())
            {
                // REVISIT:           
                // PSVIElement->setValidity(PSVIItem::VALIDITY_INVALID);
            }
Khaled Noaman's avatar
Khaled Noaman committed
        }
Tinny Ng's avatar
Tinny Ng committed
        else if (fReaderMgr.getCurrentReader()->isAllSpaces(rawBuf, len))
Khaled Noaman's avatar
Khaled Noaman committed
        {
            //  Its all spaces. So, if they can take spaces, then send it
            //  as ignorable whitespace. If they can handle any char data
            //  send it as characters.
            if (charOpts == XMLElementDecl::SpacesOk) {
                if (fDocHandler)
                    fDocHandler->ignorableWhitespace(rawBuf, len, false);
            }
            else if (charOpts == XMLElementDecl::AllCharData)
            {
                unsigned int xsLen;
                const XMLCh* xsNormalized;
                DatatypeValidator* tempDV = ((SchemaValidator*) fValidator)->getCurrentDatatypeValidator();
                if (tempDV && tempDV->getWSFacet() != DatatypeValidator::PRESERVE)
                    // normalize the character according to schema whitespace facet
                    ((SchemaValidator*) fValidator)->normalizeWhiteSpace(tempDV, rawBuf, fWSNormalizeBuf);
                    xsNormalized = fWSNormalizeBuf.getRawBuffer();
                    xsLen = fWSNormalizeBuf.getLen();
                }
                else {
                    xsNormalized = rawBuf;
                    xsLen = len;
Khaled Noaman's avatar
Khaled Noaman committed
                }

                // tell the schema validation about the character data for checkContent later
                ((SchemaValidator*)fValidator)->setDatatypeBuffer(xsNormalized);
Khaled Noaman's avatar
Khaled Noaman committed

                // call all active identity constraints
                if (toCheckIdentityConstraint() && fICHandler->getMatcherCount()) {
                    fContent.append(xsNormalized, xsLen);
                }
Khaled Noaman's avatar
Khaled Noaman committed

                if (fDocHandler) {
                    if (fNormalizeData) {
                        fDocHandler->docCharacters(xsNormalized, xsLen, false);
                    }
                    else {
                        fDocHandler->docCharacters(rawBuf, len, false);
                    }
                }
Khaled Noaman's avatar
Khaled Noaman committed
            }
        }
        else
        {
            //  If they can take any char data, then send it. Otherwise, they
            //  can only handle whitespace and can't handle this stuff so
            //  issue an error.
            if (charOpts == XMLElementDecl::AllCharData)
            {
                unsigned int xsLen;
                const XMLCh *xsNormalized;
                DatatypeValidator* tempDV = ((SchemaValidator*) fValidator)->getCurrentDatatypeValidator();
                if (tempDV && tempDV->getWSFacet() != DatatypeValidator::PRESERVE)
                    ((SchemaValidator*) fValidator)->normalizeWhiteSpace(tempDV, rawBuf, fWSNormalizeBuf);
                    xsNormalized = fWSNormalizeBuf.getRawBuffer();
                    xsLen = fWSNormalizeBuf.getLen();
                }
                else {
                    xsNormalized = rawBuf;
                    xsLen = len;
Khaled Noaman's avatar
Khaled Noaman committed
                }

                // tell the schema validation about the character data for checkContent later
                ((SchemaValidator*)fValidator)->setDatatypeBuffer(xsNormalized);
Khaled Noaman's avatar
Khaled Noaman committed

                // call all active identity constraints
                if (toCheckIdentityConstraint() && fICHandler->getMatcherCount()) {
                    fContent.append(xsNormalized, xsLen);
                }
Khaled Noaman's avatar
Khaled Noaman committed

                if (fDocHandler) {
                    if (fNormalizeData) {
                        fDocHandler->docCharacters(xsNormalized, xsLen, false);
                    }
                    else {
                        fDocHandler->docCharacters(rawBuf, len, false);
                    }
                }
Khaled Noaman's avatar
Khaled Noaman committed
            }
            else
            {
                fValidator->emitError(XMLValid::NoCharDataInCM);
                if (getPSVIHandler())
                {
                    // REVISIT:                
                    // PSVIElement->setValidity(PSVIItem::VALIDITY_INVALID);
                }
Khaled Noaman's avatar
Khaled Noaman committed
            }
        }
    }
    else
    {
        // call all active identity constraints
PeiYong Zhang's avatar
PeiYong Zhang committed
        if (toCheckIdentityConstraint() && fICHandler->getMatcherCount())
            fContent.append(toSend.getRawBuffer(), toSend.getLen());
Khaled Noaman's avatar
Khaled Noaman committed

        // Always assume its just char data if not validating
        if (fDocHandler)
            fDocHandler->docCharacters(toSend.getRawBuffer(), toSend.getLen(), false);
    }

    // Reset buffer
    toSend.reset();
}



//  This method is called with a key/value string pair that represents an
//  xmlns="yyy" or xmlns:xxx="yyy" attribute. This method will update the
//  current top of the element stack based on this data. We know that when
//  we get here, that it is one of these forms, so we don't bother confirming
//  it.
//
//  But we have to ensure
//      1. xxx is not xmlns
//      2. if xxx is xml, then yyy must match XMLUni::fgXMLURIName, and vice versa
//      3. yyy is not XMLUni::fgXMLNSURIName
//      4. if xxx is not null, then yyy cannot be an empty string.
void SGXMLScanner::updateNSMap(const  XMLCh* const    attrName
                              , const XMLCh* const    attrValue)
{
    updateNSMap(attrName, attrValue, XMLString::indexOf(attrName, chColon));
}

void SGXMLScanner::updateNSMap(const  XMLCh* const    attrName
                              , const XMLCh* const    attrValue
                              , const int colonOfs)
Khaled Noaman's avatar
Khaled Noaman committed
{
    // We need a buffer to normalize the attribute value into
    XMLBufBid bbNormal(&fBufMgr);
    XMLBuffer& normalBuf = bbNormal.getBuffer();

    //  Normalize the value into the passed buffer. In this case, we don't
    //  care about the return value. An error was issued for the error, which
    //  is all we care about here.
    normalizeAttRawValue(attrName, attrValue, normalBuf);
    XMLCh* namespaceURI = normalBuf.getRawBuffer();

    //  We either have the default prefix (""), or we point it into the attr
    //  name parameter. Note that the xmlns is not the prefix we care about
    //  here. To us, the 'prefix' is really the local part of the attrName
    //  parameter.
    //
    //  Check 1. xxx is not xmlns
    //        2. if xxx is xml, then yyy must match XMLUni::fgXMLURIName, and vice versa
    //        3. yyy is not XMLUni::fgXMLNSURIName
    //        4. if xxx is not null, then yyy cannot be an empty string.
    const XMLCh* prefPtr = XMLUni::fgZeroLenString;    
Khaled Noaman's avatar
Khaled Noaman committed
    if (colonOfs != -1) {
        prefPtr = &attrName[colonOfs + 1];

        if (XMLString::equals(prefPtr, XMLUni::fgXMLNSString))
            emitError(XMLErrs::NoUseOfxmlnsAsPrefix);
        else if (XMLString::equals(prefPtr, XMLUni::fgXMLString)) {
            if (!XMLString::equals(namespaceURI, XMLUni::fgXMLURIName))
                emitError(XMLErrs::PrefixXMLNotMatchXMLURI);
        }

        if (!namespaceURI)
            emitError(XMLErrs::NoEmptyStrNamespace, attrName);
        else if(!*namespaceURI && fXMLVersion == XMLReader::XMLV1_0)
Khaled Noaman's avatar
Khaled Noaman committed
            emitError(XMLErrs::NoEmptyStrNamespace, attrName);
    }

    if (XMLString::equals(namespaceURI, XMLUni::fgXMLNSURIName))
        emitError(XMLErrs::NoUseOfxmlnsURI);
    else if (XMLString::equals(namespaceURI, XMLUni::fgXMLURIName)) {
        if (!XMLString::equals(prefPtr, XMLUni::fgXMLString))
            emitError(XMLErrs::XMLURINotMatchXMLPrefix);
    }

    //  Ok, we have to get the unique id for the attribute value, which is the
    //  URI that this value should be mapped to. The validator has the
    //  namespace string pool, so we ask him to find or add this new one. Then
    //  we ask the element stack to add this prefix to URI Id mapping.
    fElemStack.addPrefix
    (
        prefPtr
        , fURIStringPool->addOrFind(namespaceURI)
    );
}

void SGXMLScanner::scanRawAttrListforNameSpaces(int attCount)
Khaled Noaman's avatar
Khaled Noaman committed
{
    //  Make an initial pass through the list and find any xmlns attributes or
    //  schema attributes.
    //  When we find one, send it off to be used to update the element stack's
    //  namespace mappings.
Khaled Noaman's avatar
Khaled Noaman committed
    for (index = 0; index < attCount; index++)
    {
        // each attribute has the prefix:suffix="value"
        const KVStringPair* curPair = fRawAttrList->elementAt(index);
        const XMLCh* rawPtr = curPair->getKey();

        //  If either the key begins with "xmlns:" or its just plain
        //  "xmlns", then use it to update the map.
        if (!XMLString::compareNString(rawPtr, XMLUni::fgXMLNSColonString, 6)
        ||  XMLString::equals(rawPtr, XMLUni::fgXMLNSString))
        {
            const XMLCh* valuePtr = curPair->getValue();

            updateNSMap(rawPtr, valuePtr, fRawAttrColonList[index]);
Khaled Noaman's avatar
Khaled Noaman committed

            // if the schema URI is seen in the the valuePtr, set the boolean seeXsi
            if (XMLString::equals(valuePtr, SchemaSymbols::fgURI_XSI)) {
                fSeeXsi = true;
            }
        }
    }

    // walk through the list again to deal with "xsi:...."
    if (fSeeXsi)
    {
        //  Schema Xsi Type yyyy (e.g. xsi:type="yyyyy")
        XMLBufBid bbXsi(&fBufMgr);
        XMLBuffer& fXsiType = bbXsi.getBuffer();

        QName attName(fMemoryManager);
Khaled Noaman's avatar
Khaled Noaman committed

        for (index = 0; index < attCount; index++)
        {
            // each attribute has the prefix:suffix="value"
            const KVStringPair* curPair = fRawAttrList->elementAt(index);
            const XMLCh* rawPtr = curPair->getKey();

            attName.setName(rawPtr, fEmptyNamespaceId);
            const XMLCh* prefPtr = attName.getPrefix();

            // if schema URI has been seen, scan for the schema location and uri
            // and resolve the schema grammar; or scan for schema type
            if (resolvePrefix(prefPtr, ElemStack::Mode_Attribute) == fSchemaNamespaceId) {

                const XMLCh* valuePtr = curPair->getValue();
                const XMLCh* suffPtr = attName.getLocalPart();

                if (XMLString::equals(suffPtr, SchemaSymbols::fgXSI_SCHEMALOCACTION))
                    parseSchemaLocation(valuePtr);
                else if (XMLString::equals(suffPtr, SchemaSymbols::fgXSI_NONAMESPACESCHEMALOCACTION))
                    resolveSchemaGrammar(valuePtr, XMLUni::fgZeroLenString);

                if (XMLString::equals(suffPtr, SchemaSymbols::fgXSI_TYPE)) {
                        fXsiType.set(valuePtr);
                }
                else if (XMLString::equals(suffPtr, SchemaSymbols::fgATT_NILL)
                         && fValidator && fValidator->handlesSchema()
                         && XMLString::equals(valuePtr, SchemaSymbols::fgATTVAL_TRUE)) {
                            ((SchemaValidator*)fValidator)->setNillable(true);
                }
            }
        }

        if (fValidator && fValidator->handlesSchema()) {
            if (!fXsiType.isEmpty()) {
                int colonPos = -1;
                unsigned int uriId = resolveQName (
                      fXsiType.getRawBuffer()
                    , fPrefixBuf
                    , ElemStack::Mode_Element
                    , colonPos
                );
                ((SchemaValidator*)fValidator)->setXsiType(fPrefixBuf.getRawBuffer(), fXsiType.getRawBuffer() + colonPos + 1, uriId);
            }
        }
    }
}

void SGXMLScanner::parseSchemaLocation(const XMLCh* const schemaLocationStr)
{
    BaseRefVectorOf<XMLCh>* schemaLocation = XMLString::tokenizeString(schemaLocationStr, fMemoryManager);
    Janitor<BaseRefVectorOf<XMLCh> > janLoc(schemaLocation);
Khaled Noaman's avatar
Khaled Noaman committed
    unsigned int size = schemaLocation->size();
    if (size % 2 != 0 ) {
        emitError(XMLErrs::BadSchemaLocation);
    } else {
        for(unsigned int i=0; i<size; i=i+2) {
            resolveSchemaGrammar(schemaLocation->elementAt(i+1), schemaLocation->elementAt(i));
        }
    }
}

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

    Grammar* grammar = 0;
 
    {
        XMLSchemaDescriptionImpl    theSchemaDescription(uri, fMemoryManager);   
        theSchemaDescription.setLocationHints(loc); 
        grammar = fGrammarResolver->getGrammar(&theSchemaDescription);
    }
Khaled Noaman's avatar
Khaled Noaman committed

    if (!grammar || grammar->getGrammarType() == Grammar::DTDGrammarType) {
        XSDDOMParser parser(0, fMemoryManager, 0);
Khaled Noaman's avatar
Khaled Noaman committed

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

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

Khaled Noaman's avatar
Khaled Noaman committed
        // 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);
            srcToFill = fEntityHandler->resolveEntity(&resourceIdentifier);
Khaled Noaman's avatar
Khaled Noaman committed
        }
        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;

Khaled Noaman's avatar
Khaled Noaman committed
            ReaderMgr::LastExtEntityInfo lastInfo;
            fReaderMgr.getLastExtEntityInfo(lastInfo);

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

                    srcToFill = new (fMemoryManager) LocalFileInputSource
                    ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager);            
Khaled Noaman's avatar
Khaled Noaman committed
            }
            else
            {
                if (fStandardUriConformant && urlTmp.hasInvalidChar())
                    ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager);
                srcToFill = new (fMemoryManager) URLInputSource(urlTmp, fMemoryManager);
            }        
Khaled Noaman's avatar
Khaled Noaman committed
        }

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

        // Should just issue warning if the schema is not found
        bool flag = srcToFill->getIssueFatalErrorIfNotFound();
Khaled Noaman's avatar
Khaled Noaman committed
        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);
                if (!XMLString::equals(newUri, uri)) {
                    if (fValidate || fValScheme == Val_Auto) {
Khaled Noaman's avatar
Khaled Noaman committed
                        fValidator->emitError(XMLValid::WrongTargetNamespace, loc, uri);
                    grammar = fGrammarResolver->getGrammar(newUri);
Khaled Noaman's avatar
Khaled Noaman committed
                }

                if (!grammar || grammar->getGrammarType() == Grammar::DTDGrammarType) {

                    //  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);
                    }

                    grammar = new (fGrammarPoolMemoryManager) SchemaGrammar(fGrammarPoolMemoryManager);
                    XMLSchemaDescription* gramDesc = (XMLSchemaDescription*) grammar->getGrammarDescription();
                    gramDesc->setContextType(XMLSchemaDescription::CONTEXT_PREPARSE);
                    gramDesc->setLocationHints(srcToFill->getSystemId());
                    TraverseSchema traverseSchema
                    (
                        root
                        , fURIStringPool
                        , (SchemaGrammar*) grammar
                        , fGrammarResolver
                        , this
                        , srcToFill->getSystemId()
                        , fEntityHandler
                        , fErrorReporter
                        , fMemoryManager
                    );
Khaled Noaman's avatar
Khaled Noaman committed

                    if (fGrammarType == Grammar::DTDGrammarType) {
                        fGrammar = grammar;
                        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();
InputSource* SGXMLScanner::resolveSystemId(const XMLCh* const sysId
                                          ,const XMLCh* const pubId)
Khaled Noaman's avatar
Khaled Noaman committed
{
PeiYong Zhang's avatar
PeiYong Zhang committed
    //Normalize sysId 
    XMLBufBid nnSys(&fBufMgr);
    XMLBuffer& normalizedSysId = nnSys.getBuffer();
    XMLString::removeChar(sysId, 0xFFFF, normalizedSysId);
    const XMLCh* normalizedURI = normalizedSysId.getRawBuffer();

Khaled Noaman's avatar
Khaled Noaman committed
    // Create a buffer for expanding the system id
    XMLBufBid bbSys(&fBufMgr);
    XMLBuffer& expSysId = bbSys.getBuffer();
Khaled Noaman's avatar
Khaled Noaman committed
    //  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);
Khaled Noaman's avatar
Khaled Noaman committed

        ReaderMgr::LastExtEntityInfo lastInfo;
        fReaderMgr.getLastExtEntityInfo(lastInfo);
        XMLResourceIdentifier resourceIdentifier(XMLResourceIdentifier::ExternalEntity,
                            expSysId.getRawBuffer(), 0, pubId, lastInfo.systemId);
        srcToFill = fEntityHandler->resolveEntity(&resourceIdentifier);
Khaled Noaman's avatar
Khaled Noaman committed
    }
    else
    {
Khaled Noaman's avatar
Khaled Noaman committed
    }

    //  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 0;

Khaled Noaman's avatar
Khaled Noaman committed
        ReaderMgr::LastExtEntityInfo lastInfo;
        fReaderMgr.getLastExtEntityInfo(lastInfo);

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

                srcToFill = new (fMemoryManager) LocalFileInputSource
                ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager);            
Khaled Noaman's avatar
Khaled Noaman committed
        }
        else
        {
            if (fStandardUriConformant && urlTmp.hasInvalidChar())
                ThrowXMLwithMemMgr(MalformedURLException, XMLExcepts::URL_MalformedURL, fMemoryManager);
            srcToFill = new (fMemoryManager) URLInputSource(urlTmp, fMemoryManager);
        }              
Khaled Noaman's avatar
Khaled Noaman committed
    }

    return srcToFill;
}


// ---------------------------------------------------------------------------
//  SGXMLScanner: Private grammar preparsing methods
// ---------------------------------------------------------------------------
Grammar* SGXMLScanner::loadXMLSchemaGrammar(const InputSource& src,
                                          const bool toCache)
{
   // Reset the validators
    fSchemaValidator->reset();
    fSchemaValidator->setErrorReporter(fErrorReporter);
    fSchemaValidator->setExitOnFirstFatal(fExitOnFirstFatal);
    fSchemaValidator->setGrammarResolver(fGrammarResolver);
Khaled Noaman's avatar
Khaled Noaman committed

    if (fValidatorFromUser)
        fValidator->reset();

    XSDDOMParser parser(0, fMemoryManager, 0);
Khaled Noaman's avatar
Khaled Noaman committed

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

    // Should just issue warning if the schema is not found
    bool flag = src.getIssueFatalErrorIfNotFound();
Khaled Noaman's avatar
Khaled Noaman committed
    ((InputSource&) src).setIssueFatalErrorIfNotFound(false);

    parser.parse(src);

    // Reset the InputSource
    ((InputSource&) src).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)
        {
            SchemaGrammar* grammar = new (fGrammarPoolMemoryManager) SchemaGrammar(fGrammarPoolMemoryManager);
            XMLSchemaDescription* gramDesc = (XMLSchemaDescription*) grammar->getGrammarDescription();
            gramDesc->setContextType(XMLSchemaDescription::CONTEXT_PREPARSE);
            gramDesc->setLocationHints(src.getSystemId());

            TraverseSchema traverseSchema
            (
                root
                , fURIStringPool
                , (SchemaGrammar*) grammar
                , fGrammarResolver
                , this
                , src.getSystemId()
                , fEntityHandler
                , fErrorReporter
                , fMemoryManager
            );
Khaled Noaman's avatar
Khaled Noaman committed

            if (fValidate) {
                //  validate the Schema scan so far
                fValidator->setGrammar(grammar);
                fValidator->preContentValidation(false, true);
            }

            if (toCache) {
                fGrammarResolver->cacheGrammars();
            }

            if(getPSVIHandler())
                fModel = fGrammarResolver->getXSModel();

Khaled Noaman's avatar
Khaled Noaman committed
            return grammar;
        }
    }

    return 0;
}



// ---------------------------------------------------------------------------
//  SGXMLScanner: Private parsing methods
// ---------------------------------------------------------------------------

//  This method is called to do a raw scan of an attribute value. It does not
//  do normalization (since we don't know their types yet.) It just scans the
//  value and does entity expansion.
//
//  End of entity's must be dealt with here. During DTD scan, they can come
//  from external entities. During content, they can come from any entity.
//  We just eat the end of entity and continue with our scan until we come
//  to the closing quote. If an unterminated value causes us to go through
//  subsequent entities, that will cause errors back in the calling code,
//  but there's little we can do about it here.
bool SGXMLScanner::basicAttrValueScan(const XMLCh* const attrName, XMLBuffer& toFill)
{
    // Reset the target buffer
    toFill.reset();

    // Get the next char which must be a single or double quote
    XMLCh quoteCh;
    if (!fReaderMgr.skipIfQuote(quoteCh))
        return false;

    //  We have to get the current reader because we have to ignore closing
    //  quotes until we hit the same reader again.
    const unsigned int curReader = fReaderMgr.getCurrentReaderNum();

    //  Loop until we get the attribute value. Note that we use a double
    //  loop here to avoid the setup/teardown overhead of the exception
    //  handler on every round.
    while (true)
    {
        try
        {
            while(true)
            {
                XMLCh nextCh = fReaderMgr.getNextChar();
Khaled Noaman's avatar
Khaled Noaman committed

                if (nextCh != quoteCh)
Khaled Noaman's avatar
Khaled Noaman committed
                {
                    if (nextCh != chAmpersand)
Khaled Noaman's avatar
Khaled Noaman committed
                    {
                        if ((nextCh < 0xD800) || (nextCh > 0xDFFF))
                        {
                            // Its got to at least be a valid XML character
                            if (!fReaderMgr.getCurrentReader()->isXMLChar(nextCh))
                            {
                                if (nextCh == 0)
                                    ThrowXMLwithMemMgr(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF, fMemoryManager);
Khaled Noaman's avatar
Khaled Noaman committed

                                XMLCh tmpBuf[9];
                                XMLString::binToText
                                (
                                    nextCh
                                    , tmpBuf
                                    , 8
                                    , 16
                                    , fMemoryManager
                                );
                                emitError(XMLErrs::InvalidCharacterInAttrValue, attrName, tmpBuf);
                            }
                        } else // its a surrogate
                        {
                            // Deal with surrogate pairs

                            //  we expect a a leading surrogate.
                            if (nextCh <= 0xDBFF)
                            {
                                toFill.append(nextCh);

                                //  process the trailing surrogate
                                nextCh = fReaderMgr.getNextChar();

                                //  it should be a trailing surrogate.
                                if ((nextCh < 0xDC00) || (nextCh > 0xDFFF))
                                {
                                    emitError(XMLErrs::Expected2ndSurrogateChar);
                                }
                            } else
                            {
                                //  Its a trailing surrogate, but we are not expecting it
                                emitError(XMLErrs::Unexpected2ndSurrogateChar);
                            }
                        }
                    } else // its a chAmpersand
Khaled Noaman's avatar
Khaled Noaman committed
                    {
                        //  Check for an entity ref . We ignore the empty flag in
                        //  this one.

                        bool    escaped;
                        XMLCh   firstCh;
                        XMLCh   secondCh
                            ;
                        // If it was not returned directly, then jump back up
                        if (scanEntityRef(true, firstCh, secondCh, escaped) == EntityExp_Returned)
                        {
                            //  If it was escaped, then put in a 0xFFFF value. This will
                            //  be used later during validation and normalization of the
                            //  value to know that the following character was via an
                            //  escape char.
                            if (escaped)
                                toFill.append(0xFFFF);

                            toFill.append(firstCh);
                            if (secondCh)
                                toFill.append(secondCh);
                        }
Khaled Noaman's avatar
Khaled Noaman committed
                        continue;
                    }
                } else // its a quoteCh
Khaled Noaman's avatar
Khaled Noaman committed
                {
                    //  Check for our ending quote. It has to be in the same entity
                    //  as where we started. Quotes in nested entities are ignored.

                    if (curReader == fReaderMgr.getCurrentReaderNum())
Khaled Noaman's avatar
Khaled Noaman committed
                    {
Khaled Noaman's avatar
Khaled Noaman committed
                    }

                    // Watch for spillover into a previous entity
                    if (curReader > fReaderMgr.getCurrentReaderNum())
Khaled Noaman's avatar
Khaled Noaman committed
                    {
                        emitError(XMLErrs::PartialMarkupInEntity);
                        return false;
                // add it to the buffer
Khaled Noaman's avatar
Khaled Noaman committed
                toFill.append(nextCh);
Khaled Noaman's avatar
Khaled Noaman committed
            }
        }
        catch(const EndOfEntityException&)
        {
            // Just eat it and continue.
        }
    }
    return true;
}


//  This method scans a CDATA section. It collects the character into one
//  of the temp buffers and calls the document handler, if any, with the
//  characters. It assumes that the <![CDATA string has been scanned before
//  this call.
void SGXMLScanner::scanCDSection()
{
    static const XMLCh CDataClose[] =
    {
            chCloseSquare, chCloseAngle, chNull
    };

    //  The next character should be the opening square bracket. If not
    //  issue an error, but then try to recover by skipping any whitespace
    //  and checking again.
    if (!fReaderMgr.skippedChar(chOpenSquare))
    {
        emitError(XMLErrs::ExpectedOpenSquareBracket);
        fReaderMgr.skipPastSpaces();

        // If we still don't find it, then give up, else keep going