Skip to content
Snippets Groups Projects
IGXMLScanner2.cpp 127 KiB
Newer Older
Khaled Noaman's avatar
Khaled Noaman committed
/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2002, 2003 The Apache Software Foundation.  All rights
Khaled Noaman's avatar
Khaled Noaman committed
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */


// ---------------------------------------------------------------------------
//  This file holds some of the grunt work methods of IGXMLScanner.cpp to keep
//  it a little more readable.
// ---------------------------------------------------------------------------


// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/internal/IGXMLScanner.hpp>
#include <xercesc/internal/EndOfEntityException.hpp>
#include <xercesc/util/UnexpectedEOFException.hpp>
#include <xercesc/framework/LocalFileInputSource.hpp>
#include <xercesc/framework/URLInputSource.hpp>
#include <xercesc/framework/XMLDocumentHandler.hpp>
#include <xercesc/framework/XMLEntityHandler.hpp>
#include <xercesc/framework/XMLPScanToken.hpp>
#include <xercesc/framework/XMLRefInfo.hpp>
#include <xercesc/framework/XMLGrammarPool.hpp>
PeiYong Zhang's avatar
PeiYong Zhang committed
#include <xercesc/framework/XMLDTDDescription.hpp>
#include <xercesc/framework/XMLSchemaDescription.hpp>
#include <xercesc/framework/psvi/PSVIAttributeList.hpp>
#include <xercesc/framework/psvi/PSVIElement.hpp>
Khaled Noaman's avatar
Khaled Noaman committed
#include <xercesc/validators/common/ContentLeafNameTypeVector.hpp>
#include <xercesc/validators/DTD/DTDGrammar.hpp>
#include <xercesc/validators/DTD/DTDValidator.hpp>
#include <xercesc/validators/datatype/DatatypeValidator.hpp>
#include <xercesc/validators/schema/SchemaGrammar.hpp>
#include <xercesc/validators/schema/SchemaValidator.hpp>
#include <xercesc/validators/schema/TraverseSchema.hpp>
#include <xercesc/validators/schema/SubstitutionGroupComparator.hpp>
#include <xercesc/validators/schema/identity/XPathMatcherStack.hpp>
#include <xercesc/validators/schema/XSDDOMParser.hpp>
#include <xercesc/validators/schema/identity/ValueStoreCache.hpp>
#include <xercesc/util/XMLResourceIdentifier.hpp>
Khaled Noaman's avatar
Khaled Noaman committed

XERCES_CPP_NAMESPACE_BEGIN

inline XMLAttDefList& getAttDefList(bool              isSchemaGrammar
                                  , ComplexTypeInfo*  currType
                                  , XMLElementDecl*   elemDecl);

Khaled Noaman's avatar
Khaled Noaman committed
// ---------------------------------------------------------------------------
//  IGXMLScanner: Private helper methods
// ---------------------------------------------------------------------------

//  This method is called from scanStartTagNS() to build up the list of
//  XMLAttr objects that will be passed out in the start tag callout. We
//  get the key/value pairs from the raw scan of explicitly provided attrs,
//  which have not been normalized. And we get the element declaration from
//  which we will get any defaulted or fixed attribute defs and add those
//  in as well.
unsigned int
IGXMLScanner::buildAttList(const  RefVectorOf<KVStringPair>&  providedAttrs
                          , const unsigned int                attCount
                          ,       XMLElementDecl*             elemDecl
                          ,       RefVectorOf<XMLAttr>&       toFill)
{
    //  If doing DTD's, Ask the element to clear the 'provided' flag on all of the att defs
Khaled Noaman's avatar
Khaled Noaman committed
    //  that it owns, and to return us a boolean indicating whether it has
    //  any defs.  If schemas are being validated, the complexType
    // at the top of the SchemaValidator's stack will
    // know what's best.  REVISIT:  don't modify grammar at all; eliminate
    // this step...
    ComplexTypeInfo *currType = 0;
    if(fGrammar->getGrammarType() == Grammar::SchemaGrammarType)
        currType = ((SchemaValidator*)fValidator)->getCurrentTypeInfo();
    const bool hasDefs = (currType && fValidate)
            ? currType->resetDefs()
            : elemDecl->resetDefs();
Khaled Noaman's avatar
Khaled Noaman committed

    // another set of attributes; increment element counter
    fElemCount++;

Khaled Noaman's avatar
Khaled Noaman committed
    //  If there are no expliclitily provided attributes and there are no
    //  defined attributes for the element, the we don't have anything to do.
    //  So just return zero in this case.
    if (!hasDefs && !attCount)
        return 0;

    // PSVI handling
    if(getPSVIHandler() && fGrammarType == Grammar::SchemaGrammarType )
        fPSVIAttrList->reset();
    PSVIItem::VALIDITY_STATE attrValid = PSVIItem::VALIDITY_VALID;
    PSVIItem::ASSESSMENT_TYPE attrAssessed = PSVIItem::VALIDATION_FULL;

Khaled Noaman's avatar
Khaled Noaman committed
    // Keep up with how many attrs we end up with total
    unsigned int retCount = 0;

    //  And get the current size of the output vector. This lets us use
    //  existing elements until we fill it, then start adding new ones.
    const unsigned int curAttListSize = toFill.size();

    //  We need a buffer into which raw scanned attribute values will be
    //  normalized.
    XMLBufBid bbNormal(&fBufMgr);
    XMLBuffer& normBuf = bbNormal.getBuffer();

    //  Loop through our explicitly provided attributes, which are in the raw
    //  scanned form, and build up XMLAttr objects.
    unsigned int index;
    for (index = 0; index < attCount; index++)
    {
        const KVStringPair* curPair = providedAttrs.elementAt(index);

        //  We have to split the name into its prefix and name parts. Then
        //  we map the prefix to its URI.
        const XMLCh* const namePtr = curPair->getKey();
        ArrayJanitor<XMLCh> janName(0);

        // use a stack-based buffer when possible.
        XMLCh tempBuffer[100];

        const int colonInd = XMLString::indexOf(namePtr, chColon);
        const XMLCh* prefPtr = XMLUni::fgZeroLenString;
        const XMLCh* suffPtr = XMLUni::fgZeroLenString;
        if (colonInd != -1)
        {
            // We have to split the string, so make a copy.
            if (XMLString::stringLen(namePtr) < sizeof(tempBuffer) / sizeof(tempBuffer[0]))
            {
                XMLString::copyString(tempBuffer, namePtr);
                tempBuffer[colonInd] = chNull;
                prefPtr = tempBuffer;
            }
            else
            {
                janName.reset(XMLString::replicate(namePtr, fMemoryManager), fMemoryManager);
Khaled Noaman's avatar
Khaled Noaman committed
                janName[colonInd] = chNull;
                prefPtr = janName.get();
            }

            suffPtr = prefPtr + colonInd + 1;
        }
        else
        {
            // No colon, so we just have a name with no prefix
            suffPtr = namePtr;
        }
Khaled Noaman's avatar
Khaled Noaman committed

        //  Map the prefix to a URI id. We tell him that we are mapping an
        //  attr prefix, so any xmlns attrs at this level will not affect it.
        const unsigned int uriId = resolvePrefix(prefPtr, ElemStack::Mode_Attribute);

        //  If the uri comes back as the xmlns or xml URI or its just a name
        //  and that name is 'xmlns', then we handle it specially. So set a
        //  boolean flag that lets us quickly below know which we are dealing
        //  with.
        const bool isNSAttr = (uriId == fXMLNSNamespaceId)
                              || (uriId == fXMLNamespaceId)
                              || XMLString::equals(suffPtr, XMLUni::fgXMLNSString)
                              || XMLString::equals(getURIText(uriId), SchemaSymbols::fgURI_XSI);


        //  If its not a special case namespace attr of some sort, then we
        //  do normal checking and processing.
        XMLAttDef::AttTypes attType;
        DatatypeValidator *attrValidator = 0;
Khaled Noaman's avatar
Khaled Noaman committed
        if (!isNSAttr || fGrammarType == Grammar::DTDGrammarType)
        {
            // Some checking for attribute wild card first (for schema)
            bool laxThisOne = false;
            bool skipThisOne = false;

            XMLAttDef* attDefForWildCard = 0;
            XMLAttDef*  attDef = 0;

            if (fGrammarType == Grammar::SchemaGrammarType && currType) {
Khaled Noaman's avatar
Khaled Noaman committed

                //retrieve the att def
                attDef = currType->getAttDef(suffPtr, uriId);
Khaled Noaman's avatar
Khaled Noaman committed

                // if not found or faulted in - check for a matching wildcard attribute
                // if no matching wildcard attribute, check (un)qualifed cases and flag
                // appropriate errors
                if (!attDef || (attDef->getCreateReason() == XMLAttDef::JustFaultIn)) {

                    SchemaAttDef* attWildCard = currType->getAttWildCard();
                    if(!attWildCard)
                        // check explicitly-set wildcard
                        attWildCard = ((SchemaElementDecl*)elemDecl)->getAttWildCard();
Khaled Noaman's avatar
Khaled Noaman committed

                    if (attWildCard) {
                        //if schema, see if we should lax or skip the validation of this attribute
                        if (anyAttributeValidation(attWildCard, uriId, skipThisOne, laxThisOne)) {

                            SchemaGrammar* sGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(getURIText(uriId));
Khaled Noaman's avatar
Khaled Noaman committed
                            if (sGrammar && sGrammar->getGrammarType() == Grammar::SchemaGrammarType) {
                                RefHashTableOf<XMLAttDef>* attRegistry = sGrammar->getAttributeDeclRegistry();
                                if (attRegistry) {
                                    attDefForWildCard = attRegistry->get(suffPtr);
                                }
                            }
                        }
                    }
                    else {
                        // not found, see if the attDef should be qualified or not
                        if (uriId == fEmptyNamespaceId) {
                            attDef = currType->getAttDef(suffPtr
                                            , fURIStringPool->getId(fGrammar->getTargetNamespace()));
Khaled Noaman's avatar
Khaled Noaman committed
                            if (fValidate
                                && attDef
                                && attDef->getCreateReason() != XMLAttDef::JustFaultIn) {
                                // the attribute should be qualified
                                fValidator->emitError
                                (
                                    XMLValid::AttributeNotQualified
                                    , attDef->getFullName()
                                );
                                if(fGrammarType == Grammar::SchemaGrammarType) {
                                    ((SchemaAttDef *)(attDef))->setValidity(PSVIDefs::INVALID);
                                    if (getPSVIHandler())
                                        attrValid = PSVIItem::VALIDITY_INVALID;
                                        fPSVIElemContext.fErrorOccurred = true;
Khaled Noaman's avatar
Khaled Noaman committed
                            }
                        }
                        else {
                            attDef = currType->getAttDef(suffPtr
                                            , fEmptyNamespaceId);
Khaled Noaman's avatar
Khaled Noaman committed
                            if (fValidate
                                && attDef
                                && attDef->getCreateReason() != XMLAttDef::JustFaultIn) {
                                // the attribute should be qualified
                                fValidator->emitError
                                (
                                    XMLValid::AttributeNotUnQualified
                                    , attDef->getFullName()
                                );
                                if(fGrammarType == Grammar::SchemaGrammarType) {
                                    ((SchemaAttDef *)(attDef))->setValidity(PSVIDefs::INVALID);
                                    if (getPSVIHandler())
                                        attrValid = PSVIItem::VALIDITY_INVALID;
                                        fPSVIElemContext.fErrorOccurred = true;
Khaled Noaman's avatar
Khaled Noaman committed
                            }
                        }
                    }
                }
            }

            //  Find this attribute within the parent element. We pass both
            //  the uriID/name and the raw QName buffer, since we don't know
            //  how the derived validator and its elements store attributes.
            if (!attDef) {
                if(fGrammarType == Grammar::SchemaGrammarType) 
                    attDef = ((SchemaElementDecl *)elemDecl)->getAttDef( suffPtr , uriId);
                else 
                    attDef = ((DTDElementDecl *)elemDecl)->getAttDef ( namePtr);
            } 

            // now need to prepare for duplicate detection
            if(attDef)
            {
                unsigned int *curCountPtr = fAttDefRegistry->get(attDef);
                if(!curCountPtr)
                {
                    curCountPtr = getNewUIntPtr();
                    *curCountPtr = fElemCount;
                    fAttDefRegistry->put(attDef, curCountPtr);
                }
                else if(*curCountPtr < fElemCount)
                    *curCountPtr = fElemCount;
                else
                {
                    emitError
                    ( 
                        XMLErrs::AttrAlreadyUsedInSTag
                        , attDef->getFullName()
                        , elemDecl->getFullName()
                    );
                    fPSVIElemContext.fErrorOccurred = true;
                }
            }
            else
            {
                if(fGrammarType == Grammar::DTDGrammarType) 
                {
                    unsigned int *curCountPtr = fUndeclaredAttrRegistry->get(namePtr);
                    if(!curCountPtr)
                    {
                        curCountPtr = getNewUIntPtr();
                        *curCountPtr = fElemCount;
                        fUndeclaredAttrRegistry->put((void *)namePtr, curCountPtr);
                    }
                    else if(*curCountPtr < fElemCount)
                        *curCountPtr = fElemCount;
                    else
                    {
                        emitError
                        ( 
                            XMLErrs::AttrAlreadyUsedInSTag
                            , namePtr
                            , elemDecl->getFullName()
                        );
                    }
                }
                else // schema grammar
                {
                    unsigned int *curCountPtr = fUndeclaredAttrRegistryNS->get(suffPtr, uriId);
                    if(!curCountPtr)
                    {
                        curCountPtr = getNewUIntPtr();
                        *curCountPtr = fElemCount;
                        fUndeclaredAttrRegistryNS->put((void *)suffPtr, uriId, curCountPtr);
                    }
                    else if(*curCountPtr < fElemCount)
                        *curCountPtr = fElemCount;
                    else
                    {
                        emitError
                        ( 
                            XMLErrs::AttrAlreadyUsedInSTag
                            , namePtr
                            , elemDecl->getFullName()
                        );
                        fPSVIElemContext.fErrorOccurred = true;
Khaled Noaman's avatar
Khaled Noaman committed
            }

            if(!skipThisOne && fGrammarType == Grammar::SchemaGrammarType && attDef) {
                //we may have set it to invalid already, but this is the first time we are guarenteed to have the attDef
                if(((SchemaAttDef *)(attDef))->getValidity() != PSVIDefs::INVALID)             
                    ((SchemaAttDef *)(attDef))->setValidity(PSVIDefs::VALID);
                ((SchemaAttDef *)(attDef))->setValidationAttempted(PSVIDefs::FULL);
            if(getPSVIHandler() && fGrammarType == Grammar::SchemaGrammarType )
            {
                // if we've found either an attDef or an attDefForWildCard,
                // then we're doing full validation and it may still be valid.
                if(!attDef && !attDefForWildCard)
                    if(!laxThisOne && !skipThisOne)
                        attrValid = PSVIItem::VALIDITY_INVALID;
                        fPSVIElemContext.fErrorOccurred = true;
                    }
                    else if(laxThisOne)
                    {
                        attrValid = PSVIItem::VALIDITY_NOTKNOWN;
                        attrAssessed = PSVIItem::VALIDATION_PARTIAL;
                    }
                    else
                    {
                        attrValid = PSVIItem::VALIDITY_NOTKNOWN;
                        attrAssessed = PSVIItem::VALIDATION_NONE;
                    }
            bool errorCondition = fValidate && !attDefForWildCard && !attDef;
            if (errorCondition && !skipThisOne && !laxThisOne)
Khaled Noaman's avatar
Khaled Noaman committed
            {
                //
                //  Its not valid for this element, so issue an error if we are
                //  validating.
                //
                XMLBufBid bbMsg(&fBufMgr);
                XMLBuffer& bufMsg = bbMsg.getBuffer();
                if (uriId != fEmptyNamespaceId) {
                    XMLBufBid bbURI(&fBufMgr);
                    XMLBuffer& bufURI = bbURI.getBuffer();

                    getURIText(uriId, bufURI);

                    bufMsg.append(chOpenCurly);
                    bufMsg.append(bufURI.getRawBuffer());
                    bufMsg.append(chCloseCurly);
                }
Khaled Noaman's avatar
Khaled Noaman committed
                bufMsg.append(suffPtr);
                fValidator->emitError
                (
                    XMLValid::AttNotDefinedForElement
                    , bufMsg.getRawBuffer()
                    , elemDecl->getFullName()
                );
                if(fGrammarType == Grammar::SchemaGrammarType && attDef) {
                    ((SchemaAttDef *)(attDef))->setValidity(PSVIDefs::INVALID);
                }
Khaled Noaman's avatar
Khaled Noaman committed
            }
            else if(errorCondition && laxThisOne && fGrammarType == Grammar::SchemaGrammarType && attDef) {
                ((SchemaAttDef *)(attDef))->setValidationAttempted(PSVIDefs::NONE);
                ((SchemaAttDef *)(attDef))->setValidity(PSVIDefs::UNKNOWN);
Khaled Noaman's avatar
Khaled Noaman committed
            }

            //  Now normalize the raw value since we have the attribute type. We
            //  don't care about the return status here. If it failed, an error
            //  was issued, which is all we care about.
            if (attDefForWildCard) {
                if(attDef)
                    ((SchemaAttDef*)attDef)->setAnyDatatypeValidator(((SchemaAttDef*) attDefForWildCard)->getDatatypeValidator());
Khaled Noaman's avatar
Khaled Noaman committed
                normalizeAttValue
                (
                    attDefForWildCard
Khaled Noaman's avatar
Khaled Noaman committed
                    , curPair->getValue()
                    , normBuf
                );

                //  If we found an attdef for this one, then lets validate it.
                if (fNormalizeData)
                {
                    DatatypeValidator* tempDV = ((SchemaAttDef*) attDefForWildCard)->getDatatypeValidator();
                    if (tempDV && tempDV->getWSFacet() != DatatypeValidator::PRESERVE)
                    {
                        // normalize the attribute according to schema whitespace facet
                        XMLBufBid bbtemp(&fBufMgr);
                        XMLBuffer& tempBuf = bbtemp.getBuffer();

                        ((SchemaValidator*) fValidator)->normalizeWhiteSpace(tempDV, normBuf.getRawBuffer(), tempBuf);
                        normBuf.set(tempBuf.getRawBuffer());
                    }
Khaled Noaman's avatar
Khaled Noaman committed
                }

                if (fValidate && !skipThisOne) {
                    fValidator->validateAttrValue
                    (
                        attDefForWildCard
                        , normBuf.getRawBuffer()
                        , false
                        , elemDecl
                    );
                    attrValidator = ((SchemaValidator*)fValidator)->getMostRecentAttrValidator();
                    if(getPSVIHandler() && ((SchemaValidator *)fValidator)->getErrorOccurred())
                    {
                        fPSVIElemContext.fErrorOccurred = true;
                        attrValid = PSVIItem::VALIDITY_INVALID;
Khaled Noaman's avatar
Khaled Noaman committed
                }
                else // no decl; default DOMTypeInfo to anySimpleType
                    attrValidator = DatatypeValidatorFactory::getBuiltInRegistry()->get(SchemaSymbols::fgDT_ANYSIMPLETYPE);
Khaled Noaman's avatar
Khaled Noaman committed

                // Save the type for later use
                attType = attDefForWildCard->getType();
                if(fGrammarType == Grammar::SchemaGrammarType && attDef) 
                {
                    ((SchemaElementDecl *)(elemDecl))->updateValidityFromAttribute((SchemaAttDef *)attDef);

                    DatatypeValidator* tempDV = ((SchemaAttDef*) attDefForWildCard)->getDatatypeValidator();
                    if(tempDV && tempDV->getType() == DatatypeValidator::Union )
                        ((SchemaAttDef*)attDef)->setMembertypeValidator(attrValidator);
Khaled Noaman's avatar
Khaled Noaman committed
            }
            else {
                normalizeAttValue
                (
                    attDef
Khaled Noaman's avatar
Khaled Noaman committed
                    , curPair->getValue()
                    , normBuf
                );

                //  If we found an attdef for this one, then lets validate it.
Khaled Noaman's avatar
Khaled Noaman committed
                {
                    if (fNormalizeData && (fGrammarType == Grammar::SchemaGrammarType))
                    {
                        DatatypeValidator* tempDV = ((SchemaAttDef*) attDef)->getDatatypeValidator();
                        if (tempDV && tempDV->getWSFacet() != DatatypeValidator::PRESERVE)
                        {
                            // normalize the attribute according to schema whitespace facet
                            XMLBufBid bbtemp(&fBufMgr);
                            XMLBuffer& tempBuf = bbtemp.getBuffer();

                            ((SchemaValidator*) fValidator)->normalizeWhiteSpace(tempDV, normBuf.getRawBuffer(), tempBuf);
                            normBuf.set(tempBuf.getRawBuffer());
                        }
Khaled Noaman's avatar
Khaled Noaman committed
                    }

                    if (fValidate && !skipThisOne)
                    {
                        fValidator->validateAttrValue
                        (
                            attDef
                            , normBuf.getRawBuffer()
                            , false
                            , elemDecl
                        );

                        if(fGrammarType == Grammar::SchemaGrammarType)
                        {
                            attrValidator = ((SchemaValidator*)fValidator)->getMostRecentAttrValidator();
                            if (getPSVIHandler()
                                && ((SchemaValidator *)fValidator)->getErrorOccurred())
                                attrValid = PSVIItem::VALIDITY_INVALID;
                        }
Khaled Noaman's avatar
Khaled Noaman committed
                    }
                    else if(fGrammarType == Grammar::SchemaGrammarType)
                        attrValidator = DatatypeValidatorFactory::getBuiltInRegistry()->get(SchemaSymbols::fgDT_ANYSIMPLETYPE);
                }
                else // no attDef at all; default to anySimpleType
                {
                    if(fGrammarType == Grammar::SchemaGrammarType) 
                        attrValidator = DatatypeValidatorFactory::getBuiltInRegistry()->get(SchemaSymbols::fgDT_ANYSIMPLETYPE);
Khaled Noaman's avatar
Khaled Noaman committed
                }

                // Save the type for later use
                attType = (attDef)?attDef->getType():XMLAttDef::CData;
                if(fGrammarType == Grammar::SchemaGrammarType && attDef)
                {
                    ((SchemaElementDecl *)(elemDecl))->updateValidityFromAttribute((SchemaAttDef *)attDef);
Khaled Noaman's avatar
Khaled Noaman committed
            }

            // now fill in the PSVIAttributes entry for this attribute:
            if(getPSVIHandler() && fGrammarType == Grammar::SchemaGrammarType)
	        {
	            SchemaAttDef *actualAttDef = 0;
	            if(attDef)
	                actualAttDef = (SchemaAttDef *)attDef;
	            else if (attDefForWildCard)
	                actualAttDef = (SchemaAttDef *)attDefForWildCard;
	            XSAttributeDeclaration *attrDecl = (XSAttributeDeclaration *)fModel->getXSObject(actualAttDef);
	            PSVIAttribute *toFill = fPSVIAttrList->getPSVIAttributeToFill(); 
                DatatypeValidator * attrDataType = actualAttDef->getDatatypeValidator();
	            XSSimpleTypeDefinition *validatingType = (XSSimpleTypeDefinition *)fModel->getXSObject(attrDataType);
	            if(attrValid != PSVIItem::VALIDITY_VALID)
	            {
	                toFill->reset(
	                    fRootElemName
	                    , attrValid
	                    , attrAssessed
	                    , normBuf.getRawBuffer()
	                    , validatingType
	                    , 0
	                    , actualAttDef->getValue()
	                    , false
	                    , attrDecl
	                );
	            }
	            else
	            {
	                XSSimpleTypeDefinition *memberType = 0;
	                if(validatingType->getVariety() == XSSimpleTypeDefinition::VARIETY_UNION)
	                    memberType = (XSSimpleTypeDefinition *)fModel->getXSObject(attrValidator);
	                toFill->reset(
	                    fRootElemName
	                    , attrValid
	                    , attrAssessed
	                    , normBuf.getRawBuffer()
	                    , validatingType
	                    , memberType
	                    , actualAttDef->getValue()
	                    , false
	                    , attrDecl
                        , (memberType)?attrValidator:attrDataType
Khaled Noaman's avatar
Khaled Noaman committed
        else
        {
            // Just normalize as CDATA
            attType = XMLAttDef::CData;
            normalizeAttRawValue
            (
Khaled Noaman's avatar
Khaled Noaman committed
                , curPair->getValue()
                , normBuf
            );
            if((uriId == fXMLNSNamespaceId)
                  || XMLString::equals(getURIText(uriId), SchemaSymbols::fgURI_XSI))
                attrValidator = DatatypeValidatorFactory::getBuiltInRegistry()->get(SchemaSymbols::fgDT_ANYURI);
            if(getPSVIHandler() && fGrammarType == Grammar::SchemaGrammarType)
            {
	            PSVIAttribute *toFill = fPSVIAttrList->getPSVIAttributeToFill(); 
	            XSSimpleTypeDefinition *validatingType = (attrValidator)
                            ? (XSSimpleTypeDefinition *)fModel->getXSObject(attrValidator)
                            : 0;
                // no attribute declarations for these...
	            toFill->reset(
	                fRootElemName
	                , PSVIItem::VALIDITY_NOTKNOWN
	                , PSVIItem::VALIDATION_NONE
                    , normBuf.getRawBuffer()
	                , validatingType
	                , 0
	                , 0
                    , false
	                , 0
Khaled Noaman's avatar
Khaled Noaman committed
        }

        //  Add this attribute to the attribute list that we use to pass them
        //  to the handler. We reuse its existing elements but expand it as
        //  required.
        XMLAttr* curAttr;
        // check for duplicate namespace attributes:
        // by checking for qualified names with the same local part and with prefixes 
        // which have been bound to namespace names that are identical. 
        if (fGrammarType == Grammar::DTDGrammarType) {
            for (unsigned int attrIndex=0; attrIndex < retCount; attrIndex++) {
                curAttr = toFill.elementAt(attrIndex);
                if (uriId == curAttr->getURIId() &&
                    XMLString::equals(suffPtr, curAttr->getName())) {
                    emitError
                    ( 
                        XMLErrs::AttrAlreadyUsedInSTag
                        , curAttr->getName()
                        , elemDecl->getFullName()
                    );
                }
            }  
        }
Khaled Noaman's avatar
Khaled Noaman committed
        if (retCount >= curAttListSize)
        {
            curAttr = new (fMemoryManager) XMLAttr
Khaled Noaman's avatar
Khaled Noaman committed
            (
                uriId
                , suffPtr
                , prefPtr
                , normBuf.getRawBuffer()
                , attType
                , true
                , attrValidator
                , (fGrammarType == Grammar::SchemaGrammarType )
Khaled Noaman's avatar
Khaled Noaman committed
            );
            toFill.addElement(curAttr);
        }
        else
        {
            curAttr = toFill.elementAt(retCount);
            curAttr->set
            (
                uriId
                , suffPtr
                , prefPtr
                , normBuf.getRawBuffer()
                , attType
                , attrValidator
                , (fGrammarType == Grammar::SchemaGrammarType )
Khaled Noaman's avatar
Khaled Noaman committed
            );
            curAttr->setSpecified(true);
        }
Khaled Noaman's avatar
Khaled Noaman committed
        // Bump the count of attrs in the list
        retCount++;
    }

    //  Now, if there are any attributes declared by this element, let's
    //  go through them and make sure that any required ones are provided,
    //  and fault in any fixed ones and defaulted ones that are not provided
    //  literally.
    if (hasDefs)
    {
        // Check after all specified attrs are scanned
        // (1) report error for REQUIRED attrs that are missing (V_TAGc)
        // (2) add default attrs if missing (FIXED and NOT_FIXED)


        XMLAttDefList &attDefList = getAttDefList(fGrammarType == Grammar::SchemaGrammarType, currType, elemDecl);

        for(unsigned int i=0; i<attDefList.getAttDefCount(); i++)
Khaled Noaman's avatar
Khaled Noaman committed
        {
            // Get the current att def, for convenience and its def type
            const XMLAttDef *curDef = &attDefList.getAttDef(i);
            const XMLAttDef::DefAttTypes defType = curDef->getDefaultType();
            unsigned int *attCountPtr = fAttDefRegistry->get((void *)curDef);
            if (!attCountPtr || *attCountPtr < fElemCount)
            { // did not occur
                if(fGrammarType == Grammar::SchemaGrammarType) {
                    ((SchemaAttDef *)curDef)->setValidationAttempted(PSVIDefs::FULL);
                    ((SchemaAttDef *)curDef)->setValidity(PSVIDefs::VALID);
                }
                // note that since there is no attribute information
                // item present, there is no PSVI infoset to augment here *except*
                // that the element is invalid
                //the attribute is not provided
Khaled Noaman's avatar
Khaled Noaman committed
                if (fValidate)
                {
                    // If we are validating and its required, then an error
                    if ((defType == XMLAttDef::Required) ||
                        (defType == XMLAttDef::Required_And_Fixed)  )

                    {
                        fValidator->emitError
                        (
                            XMLValid::RequiredAttrNotProvided
Khaled Noaman's avatar
Khaled Noaman committed
                        );
                        if(fGrammarType == Grammar::SchemaGrammarType) 
                            ((SchemaAttDef *)(curDef))->setValidity(PSVIDefs::INVALID);
                            fPSVIElemContext.fErrorOccurred = true;
Khaled Noaman's avatar
Khaled Noaman committed
                    }
                    else if ((defType == XMLAttDef::Default) ||
                            (defType == XMLAttDef::Fixed)  )
Khaled Noaman's avatar
Khaled Noaman committed
                    {
                        if (fStandalone && curDef->isExternal())
Khaled Noaman's avatar
Khaled Noaman committed
                        {
                            // XML 1.0 Section 2.9
                            // Document is standalone, so attributes must not be defaulted.
                            fValidator->emitError(XMLValid::NoDefAttForStandalone, curDef->getFullName(), elemDecl->getFullName());                                                        
                            if(fGrammarType == Grammar::SchemaGrammarType)
                                ((SchemaAttDef *)(curDef))->setValidity(PSVIDefs::INVALID);
                                fPSVIElemContext.fErrorOccurred = true;
Khaled Noaman's avatar
Khaled Noaman committed
                        }
                    }
                }

                //  Fault in the value if needed, and bump the att count.
                if ((defType == XMLAttDef::Default)
                    ||  (defType == XMLAttDef::Fixed))
Khaled Noaman's avatar
Khaled Noaman committed
                {
                    // Let the validator pass judgement on the attribute value
                    if (fValidate)
                    {
                        fValidator->validateAttrValue
                        (
Khaled Noaman's avatar
Khaled Noaman committed
                            , false
                            , elemDecl
                        );
                    }

                    XMLAttr* curAtt;
                    if (retCount >= curAttListSize)
                    {
                        curAtt = new (fMemoryManager) XMLAttr(fMemoryManager);
                        fValidator->faultInAttr(*curAtt, *curDef);
Khaled Noaman's avatar
Khaled Noaman committed
                        fAttrList->addElement(curAtt);
                    }
                    else
                    {
                        curAtt = fAttrList->elementAt(retCount);
                        fValidator->faultInAttr(*curAtt, *curDef);
Khaled Noaman's avatar
Khaled Noaman committed
                    }

                    if (fGrammarType == Grammar::DTDGrammarType)
                    {
                        //  Map the new attribute's prefix to a URI id and store
                        //  that in the attribute object.
                        curAtt->setURIId
                        (
                            resolvePrefix(curAtt->getPrefix(), ElemStack::Mode_Attribute)
                        );
                    }

                    // Indicate it was not explicitly specified and bump count
                    curAtt->setSpecified(false);
                    retCount++;
                    if(getPSVIHandler() && fGrammarType == Grammar::SchemaGrammarType)
                    {
                        PSVIAttribute *defAttrToFill = fPSVIAttrList->getPSVIAttributeToFill();
                        XSAttributeDeclaration *defAttrDecl = (XSAttributeDeclaration *)fModel->getXSObject((void *)curDef);
                        DatatypeValidator * attrDataType = ((SchemaAttDef *)curDef)->getDatatypeValidator();
                        XSSimpleTypeDefinition *defAttrType = 
                            (XSSimpleTypeDefinition*)fModel->getXSObject(attrDataType);
                        // would have occurred during validation of default value
                        if(((SchemaValidator *)fValidator)->getErrorOccurred())
                        {
                            defAttrToFill->reset(
                                fRootElemName
                                , PSVIItem::VALIDITY_INVALID
                                , PSVIItem::VALIDATION_FULL
                                , curDef->getValue()
                                , defAttrType
                                , 0
                                , curDef->getValue()
                                , true 
                                , defAttrDecl
                            );
                        }
                        else
                        {
                            XSSimpleTypeDefinition *defAttrMemberType = 0;
                            if(defAttrType->getVariety() == XSSimpleTypeDefinition::VARIETY_UNION)
                            {
                                defAttrMemberType = (XSSimpleTypeDefinition *)fModel->getXSObject
                                (
                                    ((SchemaValidator*)fValidator)->getMostRecentAttrValidator()
                                );
                            }
                            defAttrToFill->reset(
                                fRootElemName
                                , PSVIItem::VALIDITY_VALID
                                , PSVIItem::VALIDATION_FULL
                                , curDef->getValue()
                                , defAttrType
                                , defAttrMemberType
                                , curDef->getValue()
                                , true
                                , defAttrDecl
                                , (defAttrMemberType)?((SchemaValidator *)fValidator)->getMostRecentAttrValidator():attrDataType
Khaled Noaman's avatar
Khaled Noaman committed
                }

                if(fGrammarType == Grammar::SchemaGrammarType)
                    ((SchemaElementDecl *)elemDecl)->updateValidityFromAttribute((SchemaAttDef *)curDef);

Khaled Noaman's avatar
Khaled Noaman committed
            }
Khaled Noaman's avatar
Khaled Noaman committed
            {
                //attribute is provided
                // (schema) report error for PROHIBITED attrs that are present (V_TAGc)
                if (defType == XMLAttDef::Prohibited && fValidate) 
                {
Khaled Noaman's avatar
Khaled Noaman committed
                    fValidator->emitError
                    (
                        XMLValid::ProhibitedAttributePresent
Khaled Noaman's avatar
Khaled Noaman committed
                    );
                    if(fGrammarType == Grammar::SchemaGrammarType) 
                    {
                        ((SchemaAttDef *)(curDef))->setValidity(PSVIDefs::INVALID);
                        ((SchemaElementDecl *)elemDecl)->updateValidityFromAttribute((SchemaAttDef *)curDef);
                            QName *attQName = ((SchemaAttDef *)curDef)->getAttName();
                            // bad luck...
                            PSVIAttribute *prohibitedAttr = fPSVIAttrList->getAttributePSVIByName
                            (
                                attQName->getLocalPart(), 
                                fURIStringPool->getValueForId(attQName->getURI())
                            );
                            prohibitedAttr->updateValidity(PSVIItem::VALIDITY_INVALID);
                            fPSVIElemContext.fErrorOccurred = true;
Khaled Noaman's avatar
Khaled Noaman committed
            }
        }
    }
    return retCount;
}


//  This method will take a raw attribute value and normalize it according to
//  the rules of the attribute type. It will put the resulting value into the
//  passed buffer.
//
//  This code assumes that escaped characters in the original value (via char
//  refs) are prefixed by a 0xFFFF character. This is because some characters
//  are legal if escaped only. And some escape chars are not subject to
//  normalization rules.
bool IGXMLScanner::normalizeAttValue( const   XMLAttDef* const    attDef
Khaled Noaman's avatar
Khaled Noaman committed
                                      , const XMLCh* const        value
                                      ,       XMLBuffer&          toFill)
{
    // A simple state value for a whitespace processing state machine
    enum States
    {
        InWhitespace
        , InContent
    };

    // Get the type and name
    const XMLAttDef::AttTypes type = (attDef)
                    ?attDef->getType()
                    :XMLAttDef::CData;
Khaled Noaman's avatar
Khaled Noaman committed

    // Assume its going to go fine, and empty the target buffer in preperation
    bool retVal = true;
    toFill.reset();

    // Get attribute def - to check to see if it's declared externally or not
    bool  isAttExternal = (attDef)
                ?attDef->isExternal()
                :false;
Khaled Noaman's avatar
Khaled Noaman committed

    //  Loop through the chars of the source value and normalize it according
    //  to the type.
    States curState = InContent;
    bool escaped;
    bool firstNonWS = false;
    XMLCh nextCh;
    const XMLCh* srcPtr = value;
    while (*srcPtr)
    {
        //  Get the next character from the source. We have to watch for
        //  escaped characters (which are indicated by a 0xFFFF value followed
        //  by the char that was escaped.)
        nextCh = *srcPtr;
        escaped = (nextCh == 0xFFFF);
        if (escaped)
            nextCh = *++srcPtr;

        //  If its not escaped, then make sure its not a < character, which is
        //  not allowed in attribute values.
        if (!escaped && (*srcPtr == chOpenAngle))
        {
            emitError(XMLErrs::BracketInAttrValue, attName);
Khaled Noaman's avatar
Khaled Noaman committed
            retVal = false;
        }

        if (type == XMLAttDef::CData || type > XMLAttDef::Notation)
        {
            if (!escaped)
            {
                if ((nextCh == 0x09) || (nextCh == 0x0A) || (nextCh == 0x0D))
                {
                    // Check Validity Constraint for Standalone document declaration
                    // XML 1.0, Section 2.9
                    if (fStandalone && fValidate && isAttExternal)
                    {
                         // Can't have a standalone document declaration of "yes" if  attribute
                         // values are subject to normalisation
                         fValidator->emitError(XMLValid::NoAttNormForStandalone, attName);
                         if(fGrammarType == Grammar::SchemaGrammarType && attDef) {
                             ((SchemaAttDef *)(attDef))->setValidity(PSVIDefs::INVALID);
                            // note that schema attributes won't be
                            // subject to this constraint (standalone only relates
                            // to DTD's)
Khaled Noaman's avatar
Khaled Noaman committed
                    }
                    nextCh = chSpace;
                }
            }
        }
        else
        {
            if (curState == InWhitespace)
            {
Tinny Ng's avatar
Tinny Ng committed
                if (!fReaderMgr.getCurrentReader()->isWhitespace(nextCh))
Khaled Noaman's avatar
Khaled Noaman committed
                {
                    if (firstNonWS)
                        toFill.append(chSpace);
                    curState = InContent;
                    firstNonWS = true;
                }
                else
                {
                    srcPtr++;
                    continue;
                }
            }
            else if (curState == InContent)
            {
Tinny Ng's avatar
Tinny Ng committed
                if (fReaderMgr.getCurrentReader()->isWhitespace(nextCh))
Khaled Noaman's avatar
Khaled Noaman committed
                {
                    curState = InWhitespace;
                    srcPtr++;

                    // Check Validity Constraint for Standalone document declaration
                    // XML 1.0, Section 2.9
                    if (fStandalone && fValidate && isAttExternal)
                    {
Tinny Ng's avatar
Tinny Ng committed
                        if (!firstNonWS || (nextCh != chSpace) || (!*srcPtr) || fReaderMgr.getCurrentReader()->isWhitespace(*srcPtr))
Khaled Noaman's avatar
Khaled Noaman committed
                        {
                            // Can't have a standalone document declaration of "yes" if  attribute
                            // values are subject to normalisation
                            fValidator->emitError(XMLValid::NoAttNormForStandalone, attName);
                            if(fGrammarType == Grammar::SchemaGrammarType && attDef) {
                                ((SchemaAttDef *)(attDef))->setValidity(PSVIDefs::INVALID);
Khaled Noaman's avatar
Khaled Noaman committed
                        }
                    }
                    continue;
                }
                firstNonWS = true;
            }
        }

        // Add this char to the target buffer
        toFill.append(nextCh);

        // And move up to the next character in the source
        srcPtr++;
    }
    if(fGrammarType == Grammar::SchemaGrammarType && attDef)
        ((SchemaElementDecl *)fElemStack.topElement()->fThisElement)->updateValidityFromAttribute((SchemaAttDef *)attDef);

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

//  This method will just normalize the input value as CDATA without
//  any standalone checking.
bool IGXMLScanner::normalizeAttRawValue( const   XMLCh* const        attrName
                                      , const XMLCh* const        value
                                      ,       XMLBuffer&          toFill)
{
    // Assume its going to go fine, and empty the target buffer in preperation
    bool retVal = true;
    toFill.reset();

    //  Loop through the chars of the source value and normalize it according
    //  to the type.
    bool escaped;
    XMLCh nextCh;
    const XMLCh* srcPtr = value;
    while (*srcPtr)
    {
        //  Get the next character from the source. We have to watch for
        //  escaped characters (which are indicated by a 0xFFFF value followed
        //  by the char that was escaped.)
        nextCh = *srcPtr;
        escaped = (nextCh == 0xFFFF);
        if (escaped)
            nextCh = *++srcPtr;

        //  If its not escaped, then make sure its not a < character, which is
        //  not allowed in attribute values.
        if (!escaped && (*srcPtr == chOpenAngle))
        {
            emitError(XMLErrs::BracketInAttrValue, attrName);
            retVal = false;
        }

        if (!escaped)
        {
            //  NOTE: Yes this is a little redundant in that a 0x20 is
            //  replaced with an 0x20. But its faster to do this (I think)
            //  than checking for 9, A, and D separately.
Tinny Ng's avatar
Tinny Ng committed
            if (fReaderMgr.getCurrentReader()->isWhitespace(nextCh))
Khaled Noaman's avatar
Khaled Noaman committed
                nextCh = chSpace;
        }

        // Add this char to the target buffer
        toFill.append(nextCh);

        // And move up to the next character in the source
        srcPtr++;
    }
    return retVal;
}

unsigned int
IGXMLScanner::resolvePrefix(  const   XMLCh* const        prefix
                              , const ElemStack::MapModes mode)
{
    //  Watch for the special namespace prefixes. We always map these to
    //  special URIs. 'xml' gets mapped to the official URI that its defined
    //  to map to by the NS spec. xmlns gets mapped to a special place holder
    //  URI that we define (so that it maps to something checkable.)
    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);

    return uriId;
}

unsigned int
IGXMLScanner::resolvePrefix(  const   XMLCh* const        prefix
                              ,       XMLBuffer&          bufToFill
                              , const ElemStack::MapModes mode)
{
    //  Watch for the special namespace prefixes. We always map these to
    //  special URIs. 'xml' gets mapped to the official URI that its defined
    //  to map to by the NS spec. xmlns gets mapped to a special place holder
    //  URI that we define (so that it maps to something checkable.)
    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 IGXMLScanner::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);

    fDTDGrammar = (DTDGrammar*) fGrammarResolver->getGrammar(XMLUni::fgDTDEntityString);
	
    if (!fDTDGrammar) {

        fDTDGrammar = new (fGrammarPoolMemoryManager) DTDGrammar(fGrammarPoolMemoryManager);
        fGrammarResolver->putGrammar(fDTDGrammar);
    }
    else
        fDTDGrammar->reset();

Khaled Noaman's avatar
Khaled Noaman committed
    fGrammar = fDTDGrammar;
    fGrammarType = fGrammar->getGrammarType();
    fRootGrammar = 0;

    if (fValidatorFromUser) {
        if (fValidator->handlesDTD())
            fValidator->setGrammar(fGrammar);
        else if (fValidator->handlesSchema()) {

            ((SchemaValidator*) fValidator)->setErrorReporter(fErrorReporter);
            ((SchemaValidator*) fValidator)->setGrammarResolver(fGrammarResolver);
            ((SchemaValidator*) fValidator)->setExitOnFirstFatal(fExitOnFirstFatal);
        }
    }
    else {
        // set fValidator as fDTDValidator
        fValidator = fDTDValidator;
        fValidator->setGrammar(fGrammar);
    }

    // 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;
Khaled Noaman's avatar
Khaled Noaman committed
    fRootElemName = 0;

    // Reset IdentityConstraints
    fValueStoreCache->startDocument();
    fMatcherStack->clear();

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

    // Reset PSVI context
    if (fPSVIHandler)
    {
        if (!fPSVIElement)
            fPSVIElement = new (fMemoryManager) PSVIElement(fMemoryManager);

Khaled Noaman's avatar
Khaled Noaman committed
        if (!fErrorStack)
            fErrorStack = new (fMemoryManager) ValueStackOf<bool>(8, fMemoryManager);

        resetPSVIElemContext();
    }

Khaled Noaman's avatar
Khaled Noaman committed
    // Reset the validators
    fDTDValidator->reset();
    fDTDValidator->setErrorReporter(fErrorReporter);
    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())
            ThrowXML1(RuntimeException, XMLExcepts::Scan_CouldNotOpenSource, src.getSystemId());
        else
            ThrowXML1(RuntimeException, XMLExcepts::Scan_CouldNotOpenSource_Warning, src.getSystemId());
    }

    // 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();
        fUndeclaredAttrRegistry->removeAll();
        fUndeclaredAttrRegistryNS->removeAll();
        recreateUIntPool();
    }
    else
    {
        // note that this will implicitly reset the values of the hashtables,
        // though their buckets will still be tied up
        resetUIntPool();
    }
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 IGXMLScanner::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
        XMLCh* rawBuf = toSend.getRawBuffer();
        unsigned int len = toSend.getLen();
Khaled Noaman's avatar
Khaled Noaman committed

        // And see if the current element is a 'Children' style content model
        const ElemStack::StackElem* topElem = fElemStack.topElement();

        // Get the character data opts for the current element
        XMLElementDecl::CharDataOpts charOpts = XMLElementDecl::AllCharData;
        if(fGrammar->getGrammarType() == Grammar::SchemaGrammarType) 
        {
            // 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; 
            } 
        } else // DTD grammar
            charOpts = topElem->fThisElement->getCharDataOpts();
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(fGrammarType == Grammar::SchemaGrammarType) 
                ((SchemaElementDecl *)topElem->fThisElement)->setValidity(PSVIDefs::INVALID);
                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)
            {
                if (fGrammarType != Grammar::SchemaGrammarType)
                {
                    if (fDocHandler)
                        fDocHandler->docCharacters(rawBuf, len, false);
                }
                else
                {
                    SchemaValidator *schemaValidator = (SchemaValidator *)fValidator;
Khaled Noaman's avatar
Khaled Noaman committed
                    if (fNormalizeData) {

                        DatatypeValidator* tempDV = ((SchemaValidator*) fValidator)->getCurrentDatatypeValidator();
                        if (tempDV && tempDV->getWSFacet() != DatatypeValidator::PRESERVE)
                        {
                            // normalize the character according to schema whitespace facet
                            XMLBufBid bbtemp(&fBufMgr);
                            XMLBuffer& tempBuf = bbtemp.getBuffer();

                            ((SchemaValidator*) fValidator)->normalizeWhiteSpace(tempDV, rawBuf,  tempBuf);
                            rawBuf = tempBuf.getRawBuffer();
                            len = tempBuf.getLen();
                        }
Khaled Noaman's avatar
Khaled Noaman committed
                    }

                    // tell the schema validation about the character data for checkContent later
                    schemaValidator->setDatatypeBuffer(rawBuf);
Khaled Noaman's avatar
Khaled Noaman committed

                    // call all active identity constraints
                    if (fMatcherStack->getMatcherCount())
                        fContent.append(rawBuf, len);
Khaled Noaman's avatar
Khaled Noaman committed

                    if (fDocHandler)
                        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)
            {
                if (fGrammarType != Grammar::SchemaGrammarType)
                {
                    if (fDocHandler)
                        fDocHandler->docCharacters(rawBuf, len, false);
                }
                else
                {
                    SchemaValidator *schemaValidator = (SchemaValidator*)fValidator;
Khaled Noaman's avatar
Khaled Noaman committed
                    if (fNormalizeData) {

                        DatatypeValidator* tempDV = ((SchemaValidator*) fValidator)->getCurrentDatatypeValidator();
                        if (tempDV && tempDV->getWSFacet() != DatatypeValidator::PRESERVE)
                        {
                            // normalize the character according to schema whitespace facet
                            XMLBufBid bbtemp(&fBufMgr);
                            XMLBuffer& tempBuf = bbtemp.getBuffer();

                            ((SchemaValidator*) fValidator)->normalizeWhiteSpace(tempDV, rawBuf,  tempBuf);
                            rawBuf = tempBuf.getRawBuffer();
                            len = tempBuf.getLen();
                        }
Khaled Noaman's avatar
Khaled Noaman committed
                    }

                    // tell the schema validation about the character data for checkContent later
                    schemaValidator->setDatatypeBuffer(rawBuf);
Khaled Noaman's avatar
Khaled Noaman committed

                    // call all active identity constraints
                    if (fMatcherStack->getMatcherCount())
                        fContent.append(rawBuf, len);
Khaled Noaman's avatar
Khaled Noaman committed

                    if (fDocHandler)
                        fDocHandler->docCharacters(rawBuf, len, false);
Khaled Noaman's avatar
Khaled Noaman committed
                }
            }
            else
            {
                fValidator->emitError(XMLValid::NoCharDataInCM);
                if(fGrammarType == Grammar::SchemaGrammarType) 
                    ((SchemaElementDecl *)topElem->fThisElement)->setValidity(PSVIDefs::INVALID);
                    if (getPSVIHandler())
                    {
                        // REVISIT:                                   
                        // PSVIAttribute->setValidity(PSVIItem::VALIDITY_INVALID);                    
                    }
                }
Khaled Noaman's avatar
Khaled Noaman committed
            }
        }
    }
    else
    {
        // call all active identity constraints
        if (fGrammarType == Grammar::SchemaGrammarType) {

            if (fMatcherStack->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 IGXMLScanner::updateNSMap(const  XMLCh* const    attrName
                            , const XMLCh* const    attrValue)
{
    // 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;
    const int colonOfs = XMLString::indexOf(attrName, chColon);
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 IGXMLScanner::scanRawAttrListforNameSpaces(const RefVectorOf<KVStringPair>* theRawAttrList, int attCount)
{
    //  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.
    int index = 0;
    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);

            // 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 (fDoSchema && fSeeXsi)
    {
        //  Schema Xsi Type yyyy (e.g. xsi:type="yyyyy")
        XMLBufBid bbXsi(&fBufMgr);
        XMLBuffer& fXsiType = bbXsi.getBuffer();

        for (index = 0; index < attCount; index++)
        {
            // each attribute has the prefix:suffix="value"
            const KVStringPair* curPair = fRawAttrList->elementAt(index);
            const XMLCh* rawPtr = curPair->getKey();
            const XMLCh* prefPtr = XMLUni::fgZeroLenString;
            int   colonInd = XMLString::indexOf(rawPtr, chColon);
Khaled Noaman's avatar
Khaled Noaman committed

            if (colonInd != -1) {

                fURIBuf.set(rawPtr, colonInd);
                prefPtr = fURIBuf.getRawBuffer();
            }
Khaled Noaman's avatar
Khaled Noaman committed

            // 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 = &rawPtr[colonInd + 1];
Khaled Noaman's avatar
Khaled Noaman committed

                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 IGXMLScanner::parseSchemaLocation(const XMLCh* const schemaLocationStr)
{
    XMLCh* locStr = XMLString::replicate(schemaLocationStr, fMemoryManager);
    ArrayJanitor<XMLCh> janLoc(locStr, fMemoryManager);

    processSchemaLocation(locStr);
    unsigned int size = fLocationPairs->size();

Khaled Noaman's avatar
Khaled Noaman committed
    if (size % 2 != 0 ) {
        emitError(XMLErrs::BadSchemaLocation);
    } else {
        for(unsigned int i=0; i<size; i=i+2) {
            resolveSchemaGrammar(fLocationPairs->elementAt(i+1), fLocationPairs->elementAt(i));
Khaled Noaman's avatar
Khaled Noaman committed
        }
    }
}

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

    Grammar* grammar = fGrammarResolver->getGrammar(uri);
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);

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

        normalizeURI(loc, normalizedSysId);

        //  Allow the entity handler to expand the system id if they choose
        //  to do so.
        InputSource* srcToFill = 0;
        const XMLCh* normalizedURI = normalizedSysId.getRawBuffer();
        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)
        {
            ReaderMgr::LastExtEntityInfo lastInfo;
            fReaderMgr.getLastExtEntityInfo(lastInfo);

            try
            {
                XMLURL urlTmp(lastInfo.systemId, expSysId.getRawBuffer());
                if (urlTmp.isRelative())
                {
                    ThrowXML
                    (
                        MalformedURLException
                        , XMLExcepts::URL_NoProtocolPresent
                    );
                }
                else {
                    if (fStandardUriConformant && urlTmp.hasInvalidChar())
                        ThrowXML(MalformedURLException, XMLExcepts::URL_MalformedURL);
                    srcToFill = new (fMemoryManager) URLInputSource(urlTmp, fMemoryManager);
            catch(const MalformedURLException& e)
Khaled Noaman's avatar
Khaled Noaman committed
            {
                // Its not a URL, so lets assume its a local file name if non-standard uri is allowed
                if (!fStandardUriConformant)
                    srcToFill = new (fMemoryManager) LocalFileInputSource
                    (
                        lastInfo.systemId
                        , expSysId.getRawBuffer()
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);
                    }

                    // we have seen a schema, so set up the fValidator as fSchemaValidator
                    if (!fValidator->handlesSchema())
                    {
                        if (fValidatorFromUser) {
                            // the fValidator is from user
                            ThrowXML(RuntimeException, XMLExcepts::Gen_NoSchemaValidator);
                        }
                        else {
                            fValidator = fSchemaValidator;
                        }
                    }

                    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 (!fValidator->handlesSchema())
        {
            if (fValidatorFromUser) {
                // the fValidator is from user
                ThrowXML(RuntimeException, XMLExcepts::Gen_NoSchemaValidator);
            }
            else {
                fValidator = fSchemaValidator;
            }
        }

        if (fGrammarType == Grammar::DTDGrammarType) {
            fGrammar = grammar;
            fGrammarType = Grammar::SchemaGrammarType;
            fValidator->setGrammar(fGrammar);
        }
    }
    // fModel may need updating:
    if(getPSVIHandler() && fGrammarType == Grammar::SchemaGrammarType)
        fModel = fGrammarResolver->getXSModel();
Khaled Noaman's avatar
Khaled Noaman committed
}

InputSource* IGXMLScanner::resolveSystemId(const XMLCh* const sysId)
{
    // 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(sysId, expSysId))
            expSysId.set(sysId);

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

    //  If they didn't create a source via the entity handler, then we
    //  have to create one on our own.
    if (!srcToFill)
    {
        ReaderMgr::LastExtEntityInfo lastInfo;
        fReaderMgr.getLastExtEntityInfo(lastInfo);

        try
        {
            XMLURL urlTmp(lastInfo.systemId, expSysId.getRawBuffer());
            if (urlTmp.isRelative())
            {
                ThrowXML
                (
                    MalformedURLException
                    , XMLExcepts::URL_NoProtocolPresent
                );
            }
            else {
                if (fStandardUriConformant && urlTmp.hasInvalidChar())
                    ThrowXML(MalformedURLException, XMLExcepts::URL_MalformedURL);
                srcToFill = new (fMemoryManager) URLInputSource(urlTmp, fMemoryManager);
Khaled Noaman's avatar
Khaled Noaman committed
        }
        catch(const MalformedURLException& e)
Khaled Noaman's avatar
Khaled Noaman committed
        {
            // Its not a URL, so lets assume its a local file name if non-standard uri is allowed
            if (!fStandardUriConformant)
                srcToFill = new (fMemoryManager) LocalFileInputSource
                (
                    lastInfo.systemId
                    , expSysId.getRawBuffer()
Khaled Noaman's avatar
Khaled Noaman committed
        }
    }

    return srcToFill;
}


// ---------------------------------------------------------------------------
//  IGXMLScanner: Private grammar preparsing methods
// ---------------------------------------------------------------------------
Grammar* IGXMLScanner::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();

    if (!fValidator->handlesSchema()) {
        if (fValidatorFromUser && fValidate)
            ThrowXML(RuntimeException, XMLExcepts::Gen_NoSchemaValidator);
        else {
            fValidator = fSchemaValidator;
        }
    }

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



// ---------------------------------------------------------------------------
//  IGXMLScanner: 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 IGXMLScanner::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.
    XMLCh   nextCh;
    XMLCh   secondCh = 0;
    bool    gotLeadingSurrogate = false;
    bool    escaped;
    while (true)
    {
        try
        {
            while(true)
            {
                nextCh = fReaderMgr.getNextChar();
Khaled Noaman's avatar
Khaled Noaman committed

                if (!nextCh)
                    ThrowXML(UnexpectedEOFException, XMLExcepts::Gen_UnexpectedEOF);

                //  Check for our ending quote. It has to be in the same entity
                //  as where we started. Quotes in nested entities are ignored.
                if (nextCh == quoteCh)
                {
                    if (curReader == fReaderMgr.getCurrentReaderNum())
                        return true;

                    // Watch for spillover into a previous entity
                    if (curReader > fReaderMgr.getCurrentReaderNum())
                    {
                        emitError(XMLErrs::PartialMarkupInEntity);
                        return false;
                    }
                }

                //  Check for an entity ref . We ignore the empty flag in
                //  this one.
                escaped = false;
                if (nextCh == chAmpersand)
                {
                    // If it was not returned directly, then jump back up
                    if (scanEntityRef(true, nextCh, secondCh, escaped) != EntityExp_Returned)
                    {
                        gotLeadingSurrogate = false;
                        continue;
                    }
                }
                else if ((nextCh >= 0xD800) && (nextCh <= 0xDBFF))
Khaled Noaman's avatar
Khaled Noaman committed
                {
                    // Deal with surrogate pairs
Khaled Noaman's avatar
Khaled Noaman committed
                    //  Its a leading surrogate. If we already got one, then
                    //  issue an error, else set leading flag to make sure that
                    //  we look for a trailing next time.
                    if (gotLeadingSurrogate)
                    {
                        emitError(XMLErrs::Expected2ndSurrogateChar);
                    }
                    else
                        gotLeadingSurrogate = true;
                }
                else
                {
                    //  If its a trailing surrogate, make sure that we are
                    //  prepared for that. Else, its just a regular char so make
                    //  sure that we were not expected a trailing surrogate.
                    if ((nextCh >= 0xDC00) && (nextCh <= 0xDFFF))
                    {
                        // Its trailing, so make sure we were expecting it
                        if (!gotLeadingSurrogate)
                            emitError(XMLErrs::Unexpected2ndSurrogateChar);
                    }
                    else
                    {
                        //  Its just a char, so make sure we were not expecting a
                        //  trailing surrogate.
                        if (gotLeadingSurrogate) {
                            emitError(XMLErrs::Expected2ndSurrogateChar);
                        }
                        // Its got to at least be a valid XML character
Tinny Ng's avatar
Tinny Ng committed
                        else if (!fReaderMgr.getCurrentReader()->isXMLChar(nextCh))
Khaled Noaman's avatar
Khaled Noaman committed
                        {
                            XMLCh tmpBuf[9];
                            XMLString::binToText
                            (
                                nextCh
                                , tmpBuf
                                , 8
                                , 16
                            );
                            emitError(XMLErrs::InvalidCharacterInAttrValue, attrName, tmpBuf);
Khaled Noaman's avatar
Khaled Noaman committed
                        }
                    }
                    gotLeadingSurrogate = false;
                }

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

                // Else add it to the buffer
                toFill.append(nextCh);

                if (secondCh)
                    toFill.append(secondCh);
Khaled Noaman's avatar
Khaled Noaman committed
            }
        }
        catch(const EndOfEntityException&)
        {
            // Just eat it and continue.
            gotLeadingSurrogate = false;
            escaped = false;
        }
    }
    return true;
}


bool IGXMLScanner::scanAttValue(  const   XMLAttDef* const    attDef
                                  , const XMLCh* const        attrName
Khaled Noaman's avatar
Khaled Noaman committed
                                  ,       XMLBuffer&          toFill)
{
    enum States
    {
        InWhitespace
        , InContent
    };

    // Get the type and name
    const XMLAttDef::AttTypes type = (attDef)
                ?attDef->getType()
                :XMLAttDef::CData;
Khaled Noaman's avatar
Khaled Noaman committed

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

    // Get attribute def - to check to see if it's declared externally or not
    bool  isAttExternal = (attDef)
                ?attDef->isExternal()
                :false;
Khaled Noaman's avatar
Khaled Noaman committed

    //  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.
    XMLCh   nextCh;
    XMLCh   secondCh = 0;
    States  curState = InContent;
Loading
Loading full blame...