Skip to content
Snippets Groups Projects
SGXMLScanner.cpp 179 KiB
Newer Older
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
PeiYong Zhang's avatar
PeiYong Zhang committed
    fICHandler = new (fMemoryManager) IdentityConstraintHandler(this, fMemoryManager);
Khaled Noaman's avatar
Khaled Noaman committed

    //  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>
    (
Neil Graham's avatar
Neil Graham committed
        131, false, new (fMemoryManager)HashPtr(), fMemoryManager
    );
    fUndeclaredAttrRegistryNS = new (fMemoryManager) RefHash2KeysTableOf<unsigned int>
    (
        7, false, fMemoryManager
    fPSVIAttrList = new (fMemoryManager) PSVIAttributeList(fMemoryManager);

    if (fValidator)
    {
        if (!fValidator->handlesSchema())
            ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Gen_NoSchemaValidator, fMemoryManager);
    }
    else
    {
        fValidator = fSchemaValidator;
    }
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;
    fMemoryManager->deallocate(fRawAttrColonList);
Khaled Noaman's avatar
Khaled Noaman committed
    delete fSchemaValidator;
PeiYong Zhang's avatar
PeiYong Zhang committed
    delete fICHandler;
    delete fAttDefRegistry;
    delete fUndeclaredAttrRegistryNS;
    delete fPSVIAttrList;
    if (fPSVIElement)
        delete fPSVIElement;

    if (fErrorStack)
        delete fErrorStack;
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;
}

void SGXMLScanner::resizeRawAttrColonList() {

    unsigned int newSize = fRawAttrColonListSize * 2;
    int* newRawAttrColonList = (int*) fMemoryManager->allocate
    (
        newSize * sizeof(int)
    ); //new int[newSize];

    // Copy the existing values
    unsigned int index = 0;
    for (; index < fRawAttrColonListSize; index++)
        newRawAttrColonList[index] = fRawAttrColonList[index];

    // Delete the old array and udpate our members
    fMemoryManager->deallocate(fRawAttrColonList); //delete [] fRawAttrColonList;
    fRawAttrColonList = newRawAttrColonList;
    fRawAttrColonListSize = 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.
Khaled Noaman's avatar
Khaled Noaman committed
SGXMLScanner::buildAttList(const  RefVectorOf<KVStringPair>&  providedAttrs
                          , const XMLSize_t                   attCount
Khaled Noaman's avatar
Khaled Noaman committed
                          ,       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.
    DatatypeValidator *currDV = 0;
    ComplexTypeInfo *currType = 0;

    if (fValidate)
    {
        currType = ((SchemaValidator*)fValidator)->getCurrentTypeInfo();
        if (!currType) {
            currDV = ((SchemaValidator*)fValidator)->getCurrentDatatypeValidator();
        }
    }

    const bool hasDefs = (currType && fValidate)
Khaled Noaman's avatar
Khaled Noaman committed
            ? currType->hasAttDefs()
            : elemDecl->hasAttDefs();
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
    XMLSize_t retCount = 0;
Khaled Noaman's avatar
Khaled Noaman committed

    //  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 XMLSize_t curAttListSize = toFill.size();
Khaled Noaman's avatar
Khaled Noaman committed

    //  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.
Khaled Noaman's avatar
Khaled Noaman committed
    for (index = 0; index < attCount; index++)
    {
        PSVIItem::VALIDITY_STATE attrValid = PSVIItem::VALIDITY_VALID;
        PSVIItem::ASSESSMENT_TYPE attrAssessed = PSVIItem::VALIDATION_FULL;
Khaled Noaman's avatar
Khaled Noaman committed
        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);
Khaled Noaman's avatar
Khaled Noaman committed

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

        const int colonInd = fRawAttrColonList[index];
Khaled Noaman's avatar
Khaled Noaman committed
        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();
            }

Khaled Noaman's avatar
Khaled Noaman committed
        }
        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)
Khaled Noaman's avatar
Khaled Noaman committed
                              || 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 = XMLAttDef::CData;
        DatatypeValidator *attrValidator = 0;
        bool otherXSI = false;

        if (isNSAttr)
        {
            if(fUndeclaredAttrRegistryNS->containsKey(suffPtr, uriId))
            {
                emitError
                    XMLErrs::AttrAlreadyUsedInSTag
                    , namePtr
                    , elemDecl->getFullName()
                );
                fPSVIElemContext.fErrorOccurred = true;
            }
            else
            {
                bool ValueValidate = false;
                bool tokenizeBuffer = false;

                if (uriId == fXMLNSNamespaceId)
                {
                    attrValidator = DatatypeValidatorFactory::getBuiltInRegistry()->get(SchemaSymbols::fgDT_ANYURI);
                }
                else if (XMLString::equals(getURIText(uriId), SchemaSymbols::fgURI_XSI))
                {
                    if (XMLString::equals(suffPtr, SchemaSymbols::fgATT_NILL))
                    {
                        attrValidator = DatatypeValidatorFactory::getBuiltInRegistry()->get(SchemaSymbols::fgDT_BOOLEAN);

                        ValueValidate = true;
                    }
                    else if (XMLString::equals(suffPtr, SchemaSymbols::fgXSI_SCHEMALOCACTION))
                    {
                        // use anyURI as the validator
                        // tokenize the data and use the anyURI data for each piece
                        attrValidator = DatatypeValidatorFactory::getBuiltInRegistry()->get(SchemaSymbols::fgDT_ANYURI);
                        //We should validate each value in the schema location however
                        //this lead to a performance degradation of around 4%.  Since
                        //the first value of each pair needs to match what is in the
                        //schema document and the second value needs to be valid in
                        //order to open the document we won't validate it.  Need to
                        //do performance analysis of the anyuri datatype.
                        //ValueValidate = true;
                        ValueValidate = false;
                    }
                    else if (XMLString::equals(suffPtr, SchemaSymbols::fgXSI_NONAMESPACESCHEMALOCACTION))
                    {
                        attrValidator = DatatypeValidatorFactory::getBuiltInRegistry()->get(SchemaSymbols::fgDT_ANYURI);
                        //We should validate this value however
                        //this lead to a performance degradation of around 4%.  Since
                        //the value needs to be valid in
                        //order to open the document we won't validate it.  Need to
                        //do performance analysis of the anyuri datatype.
                        //ValueValidate = true;
                        ValueValidate = false;
                    }
                    else if (XMLString::equals(suffPtr, SchemaSymbols::fgXSI_TYPE))
                    {
                        attrValidator = DatatypeValidatorFactory::getBuiltInRegistry()->get(SchemaSymbols::fgDT_QNAME);

                        ValueValidate = true;
                    }
                    else {
                    }
                }

                if (!otherXSI) {
                    fUndeclaredAttrRegistryNS->put((void *)suffPtr, uriId, 0);

                    normalizeAttRawValue
                    (
                        namePtr
                        , curPair->getValue()
                        , normBuf

                    if (fValidate && attrValidator && ValueValidate)
                    {
                        ValidationContext* const    theContext =
                            getValidationContext();

                        if (theContext)
                        {
                            try
                            {
                                if (tokenizeBuffer) {
                                    XMLStringTokenizer tokenizer(normBuf.getRawBuffer(), fMemoryManager);
                                    while (tokenizer.hasMoreTokens()) {
                                        attrValidator->validate(
                                            tokenizer.nextToken(),
                                            theContext,
                                            fMemoryManager);
                                }
                                else {
                                    attrValidator->validate(
                                        normBuf.getRawBuffer(),
                                        theContext,
                                        fMemoryManager);
                                }
                            }
                            catch (const XMLException& idve)
                            {
Boris Kolpackov's avatar
Boris Kolpackov committed
                                fValidator->emitError (XMLValid::DatatypeError, idve.getCode(), idve.getMessage());
                            }
                        }
                    }

                    if(getPSVIHandler() && fGrammarType == Grammar::SchemaGrammarType)
                    {
	                    psviAttr = fPSVIAttrList->getPSVIAttributeToFill(suffPtr, fURIStringPool->getValueForId(uriId));
	                    XSSimpleTypeDefinition *validatingType = (attrValidator)
                            ? (XSSimpleTypeDefinition *)fModel->getXSObject(attrValidator)
                            : 0;
                        // no attribute declarations for these...
	                    psviAttr->reset(
	                        fRootElemName
	                        , PSVIItem::VALIDITY_NOTKNOWN
	                        , PSVIItem::VALIDATION_NONE
	                        , validatingType
	                        , 0
	                        , 0
                            , false
	                        , 0
                            , attrValidator
                        );
                    }
                }
            }
        }

Khaled Noaman's avatar
Khaled Noaman committed
        {
            // 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) {
Khaled Noaman's avatar
Khaled Noaman committed

                //retrieve the att def
                SchemaAttDef* attWildCard = 0;
                if (currType) {
                    attDef = currType->getAttDef(suffPtr, uriId);
                    attWildCard = currType->getAttWildCard();
                }
                else if (!currDV) { // check explicitly-set wildcard
                    attWildCard = ((SchemaElementDecl*)elemDecl)->getAttWildCard();
                }
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)) {

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

                            if(!skipThisOne)
                            {
                                SchemaGrammar* sGrammar = (SchemaGrammar*) fGrammarResolver->getGrammar(getURIText(uriId));
                                if (sGrammar && sGrammar->getGrammarType() == Grammar::SchemaGrammarType) {
                                    RefHashTableOf<XMLAttDef>* attRegistry = sGrammar->getAttributeDeclRegistry();
                                    if (attRegistry) {
                                        attDefForWildCard = attRegistry->get(suffPtr);
                                    }
Khaled Noaman's avatar
Khaled Noaman committed
                        // 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()
                                );
                                fPSVIElemContext.fErrorOccurred = true;
                                    attrValid = 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()
                                );
                                fPSVIElemContext.fErrorOccurred = true;
                                    attrValid = PSVIItem::VALIDITY_INVALID;
            // 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;
                if(!fUndeclaredAttrRegistryNS->containsKey(suffPtr, uriId))
                    fUndeclaredAttrRegistryNS->put((void *)suffPtr, uriId, 0);
                        XMLErrs::AttrAlreadyUsedInSTag
                        , namePtr
                        , elemDecl->getFullName()
                    );
                    fPSVIElemContext.fErrorOccurred = true;
            // 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)
                {
                    fPSVIElemContext.fErrorOccurred = true;
                    if(!laxThisOne && !skipThisOne)
                        attrValid = PSVIItem::VALIDITY_INVALID;
                    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()
                );
            }

            //  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) {
                normalizeAttValue(
                    attDefForWildCard, namePtr, curPair->getValue(), normBuf
Khaled Noaman's avatar
Khaled Noaman committed
                );

                //  If we found an attdef for this one, then lets validate it.
                const XMLCh* xsNormalized = normBuf.getRawBuffer();
                DatatypeValidator* tempDV = ((SchemaAttDef*) attDefForWildCard)->getDatatypeValidator();
                if (tempDV && tempDV->getWSFacet() != DatatypeValidator::PRESERVE)
Khaled Noaman's avatar
Khaled Noaman committed
                {
                    // normalize the attribute according to schema whitespace facet
                    ((SchemaValidator*) fValidator)->normalizeWhiteSpace(tempDV, xsNormalized, fWSNormalizeBuf);
                    xsNormalized = fWSNormalizeBuf.getRawBuffer();
                    if (fNormalizeData && fValidate) {
                        normBuf.set(xsNormalized);
                    fValidator->validateAttrValue(
                        attDefForWildCard, xsNormalized, false, elemDecl
Khaled Noaman's avatar
Khaled Noaman committed
                    );
                    attrValidator = ((SchemaValidator *)fValidator)->getMostRecentAttrValidator();
                    if(((SchemaValidator *)fValidator)->getErrorOccurred())
                    {
                        fPSVIElemContext.fErrorOccurred = true;
                        if(getPSVIHandler())
                            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();
            }
            else {
                normalizeAttValue(
                    attDef, namePtr, curPair->getValue(), normBuf
Khaled Noaman's avatar
Khaled Noaman committed
                );

                //  If we found an attdef for this one, then lets validate it.
Khaled Noaman's avatar
Khaled Noaman committed
                {
                    const XMLCh* xsNormalized = normBuf.getRawBuffer();
                    if (fGrammarType == Grammar::SchemaGrammarType)
Khaled Noaman's avatar
Khaled Noaman committed
                    {
                        DatatypeValidator* tempDV = ((SchemaAttDef*) attDef)->getDatatypeValidator();
                        if (tempDV && tempDV->getWSFacet() != DatatypeValidator::PRESERVE)
                        {
                            // normalize the attribute according to schema whitespace facet
                            ((SchemaValidator*) fValidator)->normalizeWhiteSpace(tempDV, xsNormalized, fWSNormalizeBuf);
                            xsNormalized = fWSNormalizeBuf.getRawBuffer();
                            if (fNormalizeData && fValidate && !skipThisOne) {
                                normBuf.set(xsNormalized);
                            }
Khaled Noaman's avatar
Khaled Noaman committed
                    }

                    if (fValidate && !skipThisOne)
                    {
                        fValidator->validateAttrValue(
                            attDef, xsNormalized, false, elemDecl
Khaled Noaman's avatar
Khaled Noaman committed
                        );
                        attrValidator = ((SchemaValidator *)fValidator)->getMostRecentAttrValidator();
                        if(((SchemaValidator *)fValidator)->getErrorOccurred())
                        {
                            fPSVIElemContext.fErrorOccurred = true;
                            if(getPSVIHandler())
                                attrValid = PSVIItem::VALIDITY_INVALID;
Khaled Noaman's avatar
Khaled Noaman committed
                    }
                        attrValidator = DatatypeValidatorFactory::getBuiltInRegistry()->get(SchemaSymbols::fgDT_ANYSIMPLETYPE);
Khaled Noaman's avatar
Khaled Noaman committed
                }
                    attrValidator = DatatypeValidatorFactory::getBuiltInRegistry()->get(SchemaSymbols::fgDT_ANYSIMPLETYPE);
Khaled Noaman's avatar
Khaled Noaman committed

                // Save the type for later use
Khaled Noaman's avatar
Khaled Noaman committed
            }

            // now fill in the PSVIAttributes entry for this attribute:
	        if(getPSVIHandler())
	        {
Neil Graham's avatar
Neil Graham committed
	            psviAttr = fPSVIAttrList->getPSVIAttributeToFill(suffPtr, fURIStringPool->getValueForId(uriId));
	            SchemaAttDef *actualAttDef = 0;
	            if(attDef)
	                actualAttDef = (SchemaAttDef *)attDef;
	            else if (attDefForWildCard)
	                actualAttDef = (SchemaAttDef *)attDefForWildCard;
                if(actualAttDef)
                {
	                XSAttributeDeclaration *attrDecl = (XSAttributeDeclaration *)fModel->getXSObject(actualAttDef);
                    DatatypeValidator * attrDataType = actualAttDef->getDatatypeValidator();
	                XSSimpleTypeDefinition *validatingType = (XSSimpleTypeDefinition *)fModel->getXSObject(attrDataType);
	                if(attrValid != PSVIItem::VALIDITY_VALID)
	                {
Neil Graham's avatar
Neil Graham committed
	                    psviAttr->reset
                        (
	                        fRootElemName
	                        , attrValid
	                        , attrAssessed
	                        , validatingType
	                        , 0
	                        , actualAttDef->getValue()
	                        , false
	                        , attrDecl
                            , 0
	                    );
	                }
	                else
	                {
	                    XSSimpleTypeDefinition *memberType = 0;
	                    if(validatingType->getVariety() == XSSimpleTypeDefinition::VARIETY_UNION)
	                        memberType = (XSSimpleTypeDefinition *)fModel->getXSObject(attrValidator);
Neil Graham's avatar
Neil Graham committed
	                    psviAttr->reset
                        (
	                        fRootElemName
	                        , attrValid
	                        , attrAssessed
	                        , validatingType
	                        , memberType
	                        , actualAttDef->getValue()
	                        , false
	                        , attrDecl
                            , (memberType)?attrValidator:attrDataType
	                    );
	                }
                }
Neil Graham's avatar
Neil Graham committed
                else
                {
	                psviAttr->reset
                    (
	                    fRootElemName
	                    , attrValid
	                    , attrAssessed
	                    , 0
	                    , 0
                        , 0
	                    , false
	                    , 0
                        , 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;
        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
            );
            curAttr->setSpecified(true);
        }
        if(psviAttr)
            psviAttr->setValue(curAttr->getValue());
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(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
                // 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
                        );
                        fPSVIElemContext.fErrorOccurred = true;
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());
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++;
                    if(getPSVIHandler())
                    {
                        QName *attName = ((SchemaAttDef *)curDef)->getAttName();
                        PSVIAttribute *defAttrToFill = fPSVIAttrList->getPSVIAttributeToFill
                        (
                            attName->getLocalPart(), fURIStringPool->getValueForId( attName->getURI())
                        );
                        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
                                , defAttrType
                                , 0
                                , curDef->getValue()
                                , defAttrDecl
                            );
                        }
                        else
                        {
                            XSSimpleTypeDefinition *defAttrMemberType = 0;
                            if(defAttrType->getVariety() == XSSimpleTypeDefinition::VARIETY_UNION)
                            {
                                defAttrMemberType = (XSSimpleTypeDefinition *)fModel->getXSObject
                                (
                                    ((SchemaValidator*)fValidator)->getMostRecentAttrValidator()
                                );
                            }
                                fRootElemName
                                , PSVIItem::VALIDITY_VALID
                                , PSVIItem::VALIDATION_FULL
                                , defAttrType
                                , defAttrMemberType
                                , curDef->getValue()
                                , true
                                , defAttrDecl
                                , (defAttrMemberType)?((SchemaValidator *)fValidator)->getMostRecentAttrValidator():attrDataType
                        defAttrToFill->setValue(curDef->getValue());
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
                    );
                    fPSVIElemContext.fErrorOccurred = true;
                        QName *attQName = ((SchemaAttDef *)curDef)->getAttName();
                        // bad luck...
                        PSVIAttribute *prohibitedAttr = fPSVIAttrList->getAttributePSVIByName
                        (
                            fURIStringPool->getValueForId(attQName->getURI())
                        );
                        prohibitedAttr->updateValidity(PSVIItem::VALIDITY_INVALID);
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
                                      , const XMLCh* const        attName
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.
Khaled Noaman's avatar
Khaled Noaman committed
    bool firstNonWS = false;
    XMLCh nextCh;
    const XMLCh* srcPtr = value;

    if (type == XMLAttDef::CData || type > XMLAttDef::Notation) {
        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;
            // Do we have an escaped character ?
            if (nextCh == 0xFFFF)
Khaled Noaman's avatar
Khaled Noaman committed
            {
                nextCh = *++srcPtr;
            else if ( (nextCh <= 0x0D) && (nextCh == 0x09 || nextCh == 0x0A || nextCh == 0x0D) ) {
                // Check Validity Constraint for Standalone document declaration
                // XML 1.0, Section 2.9
                if (fStandalone && fValidate && isAttExternal)
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);
Khaled Noaman's avatar
Khaled Noaman committed
                }
                nextCh = chSpace;
            }
            else if (nextCh == chOpenAngle) {
                //  If its not escaped, then make sure its not a < character, which is
                emitError(XMLErrs::BracketInAttrValue, attName);
Khaled Noaman's avatar
Khaled Noaman committed
            }

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

            // And move up to the next character in the source
            srcPtr++;
Khaled Noaman's avatar
Khaled Noaman committed
        }
Khaled Noaman's avatar
Khaled Noaman committed
        {
            //  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;

            // Do we have an escaped character ?
            if (nextCh == 0xFFFF)
            {
                nextCh = *++srcPtr;
                //  If its not escaped, then make sure its not a < character, which is
                emitError(XMLErrs::BracketInAttrValue, attName);
                retVal = false;
            }

Khaled Noaman's avatar
Khaled Noaman committed
            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;
                }