Skip to content
Snippets Groups Projects
SGXMLScanner.cpp 167 KiB
Newer Older
Khaled Noaman's avatar
Khaled Noaman committed
    //  And we need one for the raw attribute scan. This just stores key/
    //  value string pairs (prior to any processing.)
    fRawAttrList = new (fMemoryManager) RefVectorOf<KVStringPair>(32, true, fMemoryManager);
Khaled Noaman's avatar
Khaled Noaman committed

    // Create dummy schema grammar
    fSchemaGrammar = new (fGrammarPoolMemoryManager) SchemaGrammar(fGrammarPoolMemoryManager);
Khaled Noaman's avatar
Khaled Noaman committed

    //  Create the Validator and init them
    fSchemaValidator = new (fMemoryManager) SchemaValidator(0, fMemoryManager);
Khaled Noaman's avatar
Khaled Noaman committed
    initValidator(fSchemaValidator);

    // Create IdentityConstraint info
    fMatcherStack = new (fMemoryManager) XPathMatcherStack(fMemoryManager);
    fValueStoreCache = new (fMemoryManager) ValueStoreCache(fMemoryManager);
    fFieldActivator = new (fMemoryManager) FieldActivator(fValueStoreCache, fMatcherStack, fMemoryManager);
Khaled Noaman's avatar
Khaled Noaman committed
    fValueStoreCache->setScanner(this);

    //  Add the default entity entries for the character refs that must always
    //  be present.
    fEntityTable = new (fMemoryManager) ValueHashTableOf<XMLCh>(11, fMemoryManager);
Khaled Noaman's avatar
Khaled Noaman committed
    fEntityTable->put((void*) XMLUni::fgAmp, chAmpersand);
    fEntityTable->put((void*) XMLUni::fgLT, chOpenAngle);
    fEntityTable->put((void*) XMLUni::fgGT, chCloseAngle);
    fEntityTable->put((void*) XMLUni::fgQuot, chDoubleQuote);
    fEntityTable->put((void*) XMLUni::fgApos, chSingleQuote);
    fElemNonDeclPool = new (fMemoryManager) RefHash3KeysIdPool<SchemaElementDecl>(29, true, 128, fMemoryManager);
    fAttDefRegistry = new (fMemoryManager) RefHashTableOf<unsigned int>
    (
        509, false, new (fMemoryManager)HashPtr(), fMemoryManager
    );
    fUndeclaredAttrRegistryNS = new (fMemoryManager) RefHash2KeysTableOf<unsigned int>
    (
        509, false, new (fMemoryManager)HashXMLCh(), fMemoryManager
    );
Khaled Noaman's avatar
Khaled Noaman committed
}

void SGXMLScanner::cleanUp()
{
    fMemoryManager->deallocate(fElemState); //delete [] fElemState;
Khaled Noaman's avatar
Khaled Noaman committed
    delete fSchemaGrammar;
    delete fEntityTable;
    delete fRawAttrList;
    delete fSchemaValidator;
    delete fFieldActivator;
    delete fMatcherStack;
    delete fValueStoreCache;
    delete fAttDefRegistry;
    delete fUndeclaredAttrRegistryNS;
Khaled Noaman's avatar
Khaled Noaman committed
}

void SGXMLScanner::resizeElemState() {

    unsigned int newSize = fElemStateSize * 2;
    unsigned int* newElemState = (unsigned int*) fMemoryManager->allocate
    (
        newSize * sizeof(unsigned int)
    ); //new unsigned int[newSize];
Khaled Noaman's avatar
Khaled Noaman committed

    // Copy the existing values
    unsigned int index = 0;
    for (; index < fElemStateSize; index++)
        newElemState[index] = fElemState[index];

    for (; index < newSize; index++)
        newElemState[index] = 0;

    // Delete the old array and udpate our members
    fMemoryManager->deallocate(fElemState); //delete [] fElemState;
Khaled Noaman's avatar
Khaled Noaman committed
    fElemState = newElemState;
    fElemStateSize = newSize;
}

//  This method is called from scanStartTag() to build up the list of
Khaled Noaman's avatar
Khaled Noaman committed
//  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
SGXMLScanner::buildAttList(const  RefVectorOf<KVStringPair>&  providedAttrs
                          , const unsigned int                attCount
                          ,       XMLElementDecl*             elemDecl
                          ,       RefVectorOf<XMLAttr>&       toFill)
{
    //  Ask the element to clear the 'provided' flag on all of the att defs
    //  that it owns, and to return us a boolean indicating whether it has
    //  any defs.
    ComplexTypeInfo *currType = ((SchemaValidator*)fValidator)->getCurrentTypeInfo();
    const bool hasDefs = (currType && fValidate) 
            ? currType->resetDefs()
            : elemDecl->resetDefs();
Khaled Noaman's avatar
Khaled Noaman committed

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;

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

        //  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)
        {
            // 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()
                                );
                                ((SchemaAttDef *)(attDef))->setValidity(PSVIDefs::INVALID);
                                if (getPSVIHandler())
                                {
                                    // REVISIT:                
                                    // PSVIAttribute->setValidity(PSVIItem::VALIDITY_INVALID);
                                }
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()
                                );
                                ((SchemaAttDef *)(attDef))->setValidity(PSVIDefs::INVALID);
                                if (getPSVIHandler())
                                {
                                    // REVISIT:                
                                    // PSVIAttribute->setValidity(PSVIItem::VALIDITY_INVALID);
                                }
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) {
                attDef = ((SchemaElementDecl *)elemDecl)->getAttDef(suffPtr, uriId);
            // 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()
                    );
                }
            }
            else
            {
                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()
                    );
                }
            }
            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);                
                }   
                // REVISIT: need to check out value...
                if (getPSVIHandler())
                {
                    // REVISIT:                
                    // PSVIAttribute->setValidity(PSVIItem::VALIDITY_VALID);
                }
                ((SchemaAttDef *)(attDef))->setValidationAttempted(PSVIDefs::FULL);
                if (getPSVIHandler())
                {
                    // REVISIT:
                    // PSVIAttribute->setValidationAttempted(PSVIItem::VALIDATION_FULL);
                }
            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(attDef)
                    ((SchemaAttDef *)attDef)->setValidity(PSVIDefs::INVALID);
                if (getPSVIHandler())
                {
                    // REVISIT:                
                    // PSVIAttribute->setValidity(PSVIItem::VALIDITY_INVALID);
                }
            else if(errorCondition && laxThisOne && attDef) {
                ((SchemaAttDef *)(attDef))->setValidationAttempted(PSVIDefs::NONE);
                ((SchemaAttDef *)(attDef))->setValidity(PSVIDefs::UNKNOWN);
                if (getPSVIHandler())
                {
                    // REVISIT:
                    // PSVIAttribute->setValidationAttempted(PSVIItem::VALIDATION_NONE);
                    // PSVIAttribute->setValidity(PSVIItem::VALIDITY_NOTKNOWN);
                }
            /**** REVISIT:  excise this dead code
Khaled Noaman's avatar
Khaled Noaman committed
            //  If its already provided, then there are more than one of
            //  this attribute in this start tag, so emit an error.
            if (attDef->getProvided())
            {
                emitError
                (
                    XMLErrs::AttrAlreadyUsedInSTag
                    , attDef->getFullName()
                    , elemDecl->getFullName()
                );
                ((SchemaAttDef *)(attDef))->setValidity(PSVIDefs::INVALID);
                if (getPSVIHandler())
                {
                    // REVISIT:                
                    // PSVIAttribute->setValidity(PSVIItem::VALIDITY_INVALID);
                }
Khaled Noaman's avatar
Khaled Noaman committed
            }
            else
            {
                attDef->setProvided(true);
            }
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();
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(attDef)
                    ((SchemaElementDecl *)(elemDecl))->updateValidityFromAttribute((SchemaAttDef *)attDef);
                DatatypeValidator* tempDV = ((SchemaAttDef*) attDefForWildCard)->getDatatypeValidator();
                if(tempDV && tempDV->getType() == DatatypeValidator::Union && attDef)
                    ((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
                        );
                        attrValidator = ((SchemaValidator *)fValidator)->getMostRecentAttrValidator();
Khaled Noaman's avatar
Khaled Noaman committed
                    }
                    else
                        attrValidator = DatatypeValidatorFactory::getBuiltInRegistry()->get(SchemaSymbols::fgDT_ANYSIMPLETYPE);
Khaled Noaman's avatar
Khaled Noaman committed
                }
                else 
                    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(attDef)
                {
                    ((SchemaElementDecl *)(elemDecl))->updateValidityFromAttribute((SchemaAttDef *)attDef);
                } 
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);
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;
        if (retCount >= curAttListSize)
        {
            curAttr = new (fMemoryManager) XMLAttr
Khaled Noaman's avatar
Khaled Noaman committed
            (
                uriId
                , suffPtr
                , prefPtr
                , normBuf.getRawBuffer()
                , attType
                , true
Khaled Noaman's avatar
Khaled Noaman committed
            );
            toFill.addElement(curAttr);
        }
        else
        {
            curAttr = toFill.elementAt(retCount);
            curAttr->set
            (
                uriId
                , suffPtr
                , prefPtr
                , normBuf.getRawBuffer()
                , attType
Khaled Noaman's avatar
Khaled Noaman committed
            );
            curAttr->setSpecified(true);
        }

        // 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(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
            XMLAttDef *curDef = &attDefList.getAttDef(i);            
            const XMLAttDef::DefAttTypes defType = curDef->getDefaultType();
Khaled Noaman's avatar
Khaled Noaman committed

            unsigned int *attCountPtr = fAttDefRegistry->get(curDef);
            if (!attCountPtr || *attCountPtr < fElemCount)
            { // did not occur
                ((SchemaAttDef *)curDef)->setValidationAttempted(PSVIDefs::FULL);
                ((SchemaAttDef *)curDef)->setValidity(PSVIDefs::VALID);
                if (getPSVIHandler())
                {
                    // REVISIT:
                    // PSVIAttribute->setValidationAttempted(PSVIItem::VALIDATION_FULL);
                    // PSVIAttribute->setValidity(PSVIItem::VALIDITY_VALID);
                }
                //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
                        );
                        ((SchemaAttDef *)(curDef))->setValidity(PSVIDefs::INVALID);
                        if (getPSVIHandler())
                        {
                            // REVISIT:                
                            // PSVIAttribute->setValidity(PSVIItem::VALIDITY_INVALID);
                        }
Khaled Noaman's avatar
Khaled Noaman committed
                    }
                    else if ((defType == XMLAttDef::Default) ||
                             (defType == XMLAttDef::Fixed)  )
                    {
                        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());
                            ((SchemaAttDef *)(curDef))->setValidity(PSVIDefs::INVALID);
                            if (getPSVIHandler())
                            {
                                // REVISIT:                
                                // PSVIAttribute->setValidity(PSVIItem::VALIDITY_INVALID);
                            }
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
                    }

                    // Indicate it was not explicitly specified and bump count
                    curAtt->setSpecified(false);
                    retCount++;
                }

                ((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
                    );
                    ((SchemaAttDef *)curDef)->setValidity(PSVIDefs::INVALID);         
                    if (getPSVIHandler())
                    {
                        // REVISIT:               
                        // PSVIAttribute->setValidity(PSVIItem::VALIDITY_INVALID);
                    }
                }
                ((SchemaElementDecl *)elemDecl)->updateValidityFromAttribute((SchemaAttDef *)curDef);
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 SGXMLScanner::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, attrName);
            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, attrName);
                        if(attDef)
                            ((SchemaAttDef *)attDef)->setValidity(PSVIDefs::INVALID);     
                        if (getPSVIHandler())
                        {
                            // REVISIT:               
                            // PSVIAttribute->setValidity(PSVIItem::VALIDITY_INVALID);
                        }
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, attrName);
                            if(attDef)
                                ((SchemaAttDef *)attDef)->setValidity(PSVIDefs::INVALID);
                            if (getPSVIHandler())
                            {
                                // REVISIT:                
                                // PSVIAttribute->setValidity(PSVIItem::VALIDITY_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(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 SGXMLScanner::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
SGXMLScanner::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
SGXMLScanner::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 SGXMLScanner::scanReset(const InputSource& src)
{

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

    fGrammar = fSchemaGrammar;
    fGrammarType = Grammar::DTDGrammarType;
    fRootGrammar = 0;

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

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

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

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

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

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