bool IGXMLScanner::scanStartTagNS()

in src/xercesc/internal/IGXMLScanner.cpp [2115:2854]


bool IGXMLScanner::scanStartTagNS(bool& gotData)
{
    //  Assume we will still have data until proven otherwise. It will only
    //  ever be false if this is the root and its empty.
    gotData = true;

    // Reset element content buffer
    fContent.reset();

    //  The current position is after the open bracket, so we need to read in
    //  in the element name.
    int prefixColonPos;
    if (!fReaderMgr.getQName(fQNameBuf, &prefixColonPos))
    {
        if (fQNameBuf.isEmpty())
            emitError(XMLErrs::ExpectedElementName);
        else
            emitError(XMLErrs::InvalidElementName, fQNameBuf.getRawBuffer());
        fReaderMgr.skipToChar(chOpenAngle);
        return false;
    }

    // See if its the root element
    const bool isRoot = fElemStack.isEmpty();

    // Skip any whitespace after the name
    fReaderMgr.skipPastSpaces();

    //  First we have to do the rawest attribute scan. We don't do any
    //  normalization of them at all, since we don't know yet what type they
    //  might be (since we need the element decl in order to do that.)
    bool isEmpty;
    XMLSize_t attCount = rawAttrScan
    (
        fQNameBuf.getRawBuffer()
        , *fRawAttrList
        , isEmpty
    );

    // save the contentleafname and currentscope before addlevel, for later use
    ContentLeafNameTypeVector* cv = 0;
    XMLContentModel* cm = 0;
    unsigned int currentScope = Grammar::TOP_LEVEL_SCOPE;
    bool laxThisOne = false;

    if (!isRoot && fGrammarType == Grammar::SchemaGrammarType)
    {
        // schema validator will have correct type if validating
        SchemaElementDecl* tempElement = (SchemaElementDecl*)
            fElemStack.topElement()->fThisElement;
        SchemaElementDecl::ModelTypes modelType = tempElement->getModelType();
        ComplexTypeInfo *currType = 0;

        if (fValidate)
        {
            currType = ((SchemaValidator*)fValidator)->getCurrentTypeInfo();
            if (currType)
                modelType = (SchemaElementDecl::ModelTypes)currType->getContentType();
            else // something must have gone wrong
                modelType = SchemaElementDecl::Any;
        }
        else
        {
            currType = tempElement->getComplexTypeInfo();
        }

        if ((modelType == SchemaElementDecl::Mixed_Simple)
          ||  (modelType == SchemaElementDecl::Mixed_Complex)
          ||  (modelType == SchemaElementDecl::Children))
        {
            cm = currType->getContentModel();
            cv = cm->getContentLeafNameTypeVector();
            currentScope = fElemStack.getCurrentScope();
        }
        else if (modelType == SchemaElementDecl::Any) {
            laxThisOne = true;
        }
    }

    //  Now, since we might have to update the namespace map for this element,
    //  but we don't have the element decl yet, we just tell the element stack
    //  to expand up to get ready.
    XMLSize_t elemDepth = fElemStack.addLevel();
    fElemStack.setValidationFlag(fValidate);
    fElemStack.setPrefixColonPos(prefixColonPos);

    //  Check if there is any external schema location specified, and if we are at root,
    //  go through them first before scanning those specified in the instance document
    if (isRoot && fDoSchema
        && (fExternalSchemaLocation || fExternalNoNamespaceSchemaLocation)) {

        if (fExternalSchemaLocation)
            parseSchemaLocation(fExternalSchemaLocation, true);
        if (fExternalNoNamespaceSchemaLocation)
            resolveSchemaGrammar(fExternalNoNamespaceSchemaLocation, XMLUni::fgZeroLenString, true);
    }

    //  Make an initial pass through the list and find any xmlns attributes or
    //  schema attributes.
    if (attCount) {
        scanRawAttrListforNameSpaces(attCount);
    }

    //  Also find any default or fixed xmlns attributes in DTD defined for
    //  this element.
    XMLElementDecl* elemDecl = 0;
    const XMLCh* qnameRawBuf = fQNameBuf.getRawBuffer();

    if (fGrammarType == Grammar::DTDGrammarType) {

        if (!fSkipDTDValidation) {
            elemDecl = fGrammar->getElemDecl(
                fEmptyNamespaceId, 0, qnameRawBuf, Grammar::TOP_LEVEL_SCOPE
            );

            if (elemDecl) {
                if (elemDecl->hasAttDefs()) {
                    XMLAttDefList& attDefList = elemDecl->getAttDefList();
                    for(XMLSize_t i=0; i<attDefList.getAttDefCount(); i++)
                    {
                        // Get the current att def, for convenience and its def type
                        const XMLAttDef& curDef = attDefList.getAttDef(i);
                        const XMLAttDef::DefAttTypes defType = curDef.getDefaultType();

                        // update the NSMap if there are any default/fixed xmlns attributes
                        if ((defType == XMLAttDef::Default)
                        ||  (defType == XMLAttDef::Fixed))
                        {
                            const XMLCh* rawPtr = curDef.getFullName();
                            if (!XMLString::compareNString(rawPtr, XMLUni::fgXMLNSColonString, 6)
                            ||  XMLString::equals(rawPtr, XMLUni::fgXMLNSString))
                                updateNSMap(rawPtr, curDef.getValue());
                        }
                    }
                }
            }
        }

        if (!elemDecl) {
            elemDecl = fDTDElemNonDeclPool->getByKey(qnameRawBuf);
        }
    }

    //  Resolve the qualified name to a URI and name so that we can look up
    //  the element decl for this element. We have now update the prefix to
    //  namespace map so we should get the correct element now.
    unsigned int uriId = resolveQNameWithColon(
        qnameRawBuf, fPrefixBuf, ElemStack::Mode_Element, prefixColonPos
    );

    //if schema, check if we should lax or skip the validation of this element
    bool parentValidation = fValidate;
    if (cv) {
        QName element(fPrefixBuf.getRawBuffer(), &qnameRawBuf[prefixColonPos + 1], uriId, fMemoryManager);
        // elementDepth will be > 0, as cv is only constructed if element is not
        // root.
        laxThisOne = laxElementValidation(&element, cv, cm, elemDepth - 1);
    }

    //  Look up the element now in the grammar. This will get us back a
    //  generic element decl object. We tell him to fault one in if he does
    //  not find it.
    bool wasAdded = false;
    const XMLCh* nameRawBuf = &qnameRawBuf[prefixColonPos + 1];

    if (fDoSchema) {

        if (fGrammarType == Grammar::DTDGrammarType) {
            if (!switchGrammar(getURIText(uriId))) {
                fValidator->emitError(
                    XMLValid::GrammarNotFound, getURIText(uriId)
                );
            }
        }

        if (fGrammarType == Grammar::SchemaGrammarType) {
            elemDecl = fGrammar->getElemDecl(
                uriId, nameRawBuf, qnameRawBuf, currentScope
            );

            // if not found, then it may be a reference, try TOP_LEVEL_SCOPE
            if (!elemDecl) {
                bool checkTopLevel = (currentScope != Grammar::TOP_LEVEL_SCOPE);
                const XMLCh* original_uriStr = fGrammar->getTargetNamespace();
                unsigned int orgGrammarUri = fURIStringPool->getId(original_uriStr);

                if (orgGrammarUri != uriId) {
                    if (switchGrammar(getURIText(uriId))) {
                        checkTopLevel = true;
                    }
                    else {
                        // the laxElementValidation routine (called above) will
                        // set fValidate to false for a "skipped" element
                        if (!laxThisOne && fValidate) {
                            fValidator->emitError(
                                XMLValid::GrammarNotFound, getURIText(uriId)
                            );
                        }
                        checkTopLevel = false;
                    }
                }

                if (checkTopLevel) {
                    elemDecl = fGrammar->getElemDecl(
                        uriId, nameRawBuf, qnameRawBuf, Grammar::TOP_LEVEL_SCOPE
                    );
                }

                if (!elemDecl && currentScope != Grammar::TOP_LEVEL_SCOPE) {

                    if (orgGrammarUri == uriId) {
                        // still not found in specified uri
                        // try emptyNamespace see if element should be
                        // un-qualified.
                        // Use a temp variable until we decide this is the case
                        if (uriId != fEmptyNamespaceId) {
                            XMLElementDecl* tempElemDecl = fGrammar->getElemDecl(
                                fEmptyNamespaceId, nameRawBuf, qnameRawBuf, currentScope
                            );

                            if (tempElemDecl && tempElemDecl->getCreateReason() != XMLElementDecl::JustFaultIn && fValidate) {
                                fValidator->emitError(
                                    XMLValid::ElementNotUnQualified, qnameRawBuf
                                );
                                elemDecl = tempElemDecl;
                            }
                        }
                    }
                    // still Not found in specified uri
                    // go to original Grammar again to see if element needs
                    // to be fully qualified.
                    // Use a temp variable until we decide this is the case
                    else if (uriId == fEmptyNamespaceId) {

                        if (switchGrammar(original_uriStr)) {
                            XMLElementDecl* tempElemDecl = fGrammar->getElemDecl(
                                orgGrammarUri, nameRawBuf, qnameRawBuf, currentScope
                            );
                            if (tempElemDecl && tempElemDecl->getCreateReason() != XMLElementDecl::JustFaultIn && fValidate) {
                                fValidator->emitError(
                                    XMLValid::ElementNotQualified, qnameRawBuf
                                );
                                elemDecl = tempElemDecl;
                            }
                        }
                        else if (!laxThisOne && fValidate) {
                            fValidator->emitError(
                                XMLValid::GrammarNotFound,original_uriStr
                            );
                        }
                    }
                }

                if (!elemDecl) {
                    // still not found
                    // switch back to original grammar first if necessary
                    if (orgGrammarUri != uriId) {
                        switchGrammar(original_uriStr);
                    }

                    // look in the list of undeclared elements, as would have been
                    // done before we made grammars stateless:
                    elemDecl = fSchemaElemNonDeclPool->getByKey(
                        nameRawBuf, uriId, (int)Grammar::TOP_LEVEL_SCOPE
                    );
                }
            }
        }
    }

    if (!elemDecl) {

        if (fGrammarType == Grammar::DTDGrammarType) {
            elemDecl = new (fMemoryManager) DTDElementDecl(
                qnameRawBuf, uriId, DTDElementDecl::Any, fMemoryManager
            );
            elemDecl->setId(fDTDElemNonDeclPool->put((DTDElementDecl*)elemDecl));
        }
        else if (fGrammarType == Grammar::SchemaGrammarType)  {
            elemDecl = new (fMemoryManager) SchemaElementDecl(
                fPrefixBuf.getRawBuffer(), nameRawBuf, uriId
                , SchemaElementDecl::Any, Grammar::TOP_LEVEL_SCOPE
                , fMemoryManager
            );
            elemDecl->setId(
                fSchemaElemNonDeclPool->put((void*)elemDecl->getBaseName()
                , uriId, (int)Grammar::TOP_LEVEL_SCOPE, (SchemaElementDecl*)elemDecl)
            );
        } else {
             fValidator->emitError(
                 XMLValid::GrammarNotFound, getURIText(uriId)
             );
	}
        wasAdded = true;
    }

    // this info needed for DOMTypeInfo
    fPSVIElemContext.fErrorOccurred = false;

    //  We do something different here according to whether we found the
    //  element or not.
    bool bXsiTypeSet= (fValidator && fGrammarType == Grammar::SchemaGrammarType)?((SchemaValidator*)fValidator)->getIsXsiTypeSet():false;
    if (wasAdded)
    {
        if (laxThisOne && !bXsiTypeSet) {
            fValidate = false;
            fElemStack.setValidationFlag(fValidate);
        }
        else if (fValidate)
        {
            // If validating then emit an error

            // This is to tell the reuse Validator that this element was
            // faulted-in, was not an element in the grammar pool originally
            elemDecl->setCreateReason(XMLElementDecl::JustFaultIn);

            // xsi:type was specified, don't complain about missing definition
            if(!bXsiTypeSet)
            {
                fValidator->emitError
                (
                    XMLValid::ElementNotDefined
                    , elemDecl->getFullName()
                );

                if(fGrammarType == Grammar::SchemaGrammarType)
                {
                    fPSVIElemContext.fErrorOccurred = true;
                }
            }
        }
    }
    else
    {
        // If its not marked declared and validating, then emit an error
        if (!elemDecl->isDeclared()) {
            if(elemDecl->getCreateReason() == XMLElementDecl::NoReason) {
                if(!bXsiTypeSet && fGrammarType == Grammar::SchemaGrammarType) {
                    fPSVIElemContext.fErrorOccurred = true;
                }
            }

            if (laxThisOne) {
                fValidate = false;
                fElemStack.setValidationFlag(fValidate);
            }
            else if (fValidate && !bXsiTypeSet)
            {
                fValidator->emitError
                (
                    XMLValid::ElementNotDefined
                    , elemDecl->getFullName()
                );
            }
        }
    }

    //  Now we can update the element stack to set the current element
    //  decl. We expanded the stack above, but couldn't store the element
    //  decl because we didn't know it yet.
    fElemStack.setElement(elemDecl, fReaderMgr.getCurrentReaderNum());
    fElemStack.setCurrentURI(uriId);

    if (isRoot)
    {
        fRootGrammar = fGrammar;
        if (fGrammarType == Grammar::SchemaGrammarType && !fRootElemName)
            fRootElemName = XMLString::replicate(qnameRawBuf, fMemoryManager);
    }

    if (fGrammarType == Grammar::SchemaGrammarType && fPSVIHandler)
    {

        fPSVIElemContext.fElemDepth++;
        if (elemDecl->isDeclared())
        {
            fPSVIElemContext.fNoneValidationDepth = fPSVIElemContext.fElemDepth;
        }
        else
        {
            fPSVIElemContext.fFullValidationDepth = fPSVIElemContext.fElemDepth;

            /******
             * While we report an error for historical reasons, this should
             * actually result in lax assessment - NG.
            if (isRoot && fValidate)
                fPSVIElemContext.fErrorOccurred = true;
            *****/
        }
    }

    //  Validate the element
    if (fValidate)
    {
        fValidator->validateElement(elemDecl);
        if (fValidator->handlesSchema())
        {
            if (((SchemaValidator*) fValidator)->getErrorOccurred())
                fPSVIElemContext.fErrorOccurred = true;
        }
    }

    if (fGrammarType == Grammar::SchemaGrammarType) {

        // squirrel away the element's QName, so that we can do an efficient
        // end-tag match
        fElemStack.setCurrentSchemaElemName(fQNameBuf.getRawBuffer());

        ComplexTypeInfo* typeinfo = (fValidate)
            ? ((SchemaValidator*)fValidator)->getCurrentTypeInfo()
            : ((SchemaElementDecl*) elemDecl)->getComplexTypeInfo();

        if (typeinfo) {
            currentScope = typeinfo->getScopeDefined();

            // switch grammar if the typeinfo has a different grammar (happens when there is xsi:type)
            XMLCh* typeName = typeinfo->getTypeName();
            const int comma = XMLString::indexOf(typeName, chComma);
            if (comma > 0) {
                XMLBuffer prefixBuf(comma+1, fMemoryManager);
                prefixBuf.append(typeName, comma);
                const XMLCh* uriStr = prefixBuf.getRawBuffer();

                bool errorCondition = !switchGrammar(uriStr) && fValidate;
                if (errorCondition && !laxThisOne)
                {
                    fValidator->emitError
                    (
                        XMLValid::GrammarNotFound
                        , prefixBuf.getRawBuffer()
                    );
                }
            }
            else if (comma == 0) {
                bool errorCondition = !switchGrammar(XMLUni::fgZeroLenString) && fValidate;
                if (errorCondition && !laxThisOne)
                {
                    fValidator->emitError
                    (
                        XMLValid::GrammarNotFound
                        , XMLUni::fgZeroLenString
                    );
                }
            }
        }
        fElemStack.setCurrentScope(currentScope);

        // Set element next state
        if (elemDepth >= fElemStateSize) {
            resizeElemState();
        }

        fElemState[elemDepth] = 0;
        fElemLoopState[elemDepth] = 0;
    }

    fElemStack.setCurrentGrammar(fGrammar);

    //  If this is the first element and we are validating, check the root
    //  element.
    if (isRoot)
    {
        if (fValidate)
        {
            //  If a DocType exists, then check if it matches the root name there.
            if (fRootElemName && !XMLString::equals(qnameRawBuf, fRootElemName))
                fValidator->emitError(XMLValid::RootElemNotLikeDocType);
        }
    }
    else if (parentValidation)
    {
        //  If the element stack is not empty, then add this element as a
        //  child of the previous top element. If its empty, this is the root
        //  elem and is not the child of anything.
        fElemStack.addChild(elemDecl->getElementName(), true);
    }

    // PSVI handling:  even if it turns out there are
    // no attributes, we need to reset this list...
    if(getPSVIHandler() && fGrammarType == Grammar::SchemaGrammarType )
        fPSVIAttrList->reset();

    //  Now lets get the fAttrList filled in. This involves faulting in any
    //  defaulted and fixed attributes and normalizing the values of any that
    //  we got explicitly.
    //
    //  We update the attCount value with the total number of attributes, but
    //  it goes in with the number of values we got during the raw scan of
    //  explictly provided attrs above.
    attCount = buildAttList(*fRawAttrList, attCount, elemDecl, *fAttrList);
    if(attCount)
    {
        // clean up after ourselves:
        // clear the map used to detect duplicate attributes
        fUndeclaredAttrRegistry->removeAll();
    }

    // activate identity constraints
    if (fGrammar  &&
        fGrammarType == Grammar::SchemaGrammarType &&
        toCheckIdentityConstraint())
    {
        fICHandler->activateIdentityConstraint
                        (
                          (SchemaElementDecl*) elemDecl
                        , (int) elemDepth
                        , uriId
                        , fPrefixBuf.getRawBuffer()
                        , *fAttrList
                        , attCount
                        , fValidationContext
                        );
    }

    // Since the element may have default values, call start tag now regardless if it is empty or not
    // If we have a document handler, then tell it about this start tag
    if (fDocHandler)
    {
        fDocHandler->startElement
        (
            *elemDecl
            , uriId
            , fPrefixBuf.getRawBuffer()
            , *fAttrList
            , attCount
            , false
            , isRoot
        );
    }

    // if we have a PSVIHandler, now's the time to call
    // its handleAttributesPSVI method:
    if(fPSVIHandler && fGrammarType == Grammar::SchemaGrammarType)
    {
        QName *eName = elemDecl->getElementName();
        fPSVIHandler->handleAttributesPSVI
        (
            eName->getLocalPart()
            , fURIStringPool->getValueForId(eName->getURI())
            , fPSVIAttrList
        );
    }

    //  If empty, validate content right now if we are validating and then
    //  pop the element stack top. Else, we have to update the current stack
    //  top's namespace mapping elements.
    if (isEmpty)
    {
        // Pop the element stack back off since it'll never be used now
        fElemStack.popTop();

        // reset current type info
        DatatypeValidator* psviMemberType = 0;
        if (fGrammarType == Grammar::SchemaGrammarType)
        {
            if (fValidate && elemDecl->isDeclared())
            {
                fPSVIElemContext.fCurrentTypeInfo = ((SchemaValidator*) fValidator)->getCurrentTypeInfo();
                if(!fPSVIElemContext.fCurrentTypeInfo)
                    fPSVIElemContext.fCurrentDV = ((SchemaValidator*) fValidator)->getCurrentDatatypeValidator();
                else
                    fPSVIElemContext.fCurrentDV = 0;
                if(fPSVIHandler)
                {
                    fPSVIElemContext.fNormalizedValue = ((SchemaValidator*) fValidator)->getNormalizedValue();

                    if (XMLString::equals(fPSVIElemContext.fNormalizedValue, XMLUni::fgZeroLenString))
                        fPSVIElemContext.fNormalizedValue = 0;
                }
            }
            else
            {
                fPSVIElemContext.fCurrentDV = 0;
                fPSVIElemContext.fCurrentTypeInfo = 0;
                fPSVIElemContext.fNormalizedValue = 0;
            }
        }

        // If validating, then insure that its legal to have no content
        if (fValidate)
        {
            XMLSize_t failure;
            bool res = fValidator->checkContent(elemDecl, 0, 0, &failure);
            if (!res)
            {
                fValidator->emitError
                (
                    XMLValid::ElementNotValidForContent
                    , elemDecl->getFullName()
                    , elemDecl->getFormattedContentModel()
                );
            }

            if (fGrammarType == Grammar::SchemaGrammarType) {

                if (((SchemaValidator*) fValidator)->getErrorOccurred())
                {
                    fPSVIElemContext.fErrorOccurred = true;
                }
                else
                {
                    if (fPSVIHandler)
                    {
                        fPSVIElemContext.fIsSpecified = ((SchemaValidator*) fValidator)->getIsElemSpecified();
                        if(fPSVIElemContext.fIsSpecified)
                            fPSVIElemContext.fNormalizedValue = ((SchemaElementDecl *)elemDecl)->getDefaultValue();
                    }
                    // note that if we're empty, won't be a current DV
                    if (fPSVIElemContext.fCurrentDV && fPSVIElemContext.fCurrentDV->getType() == DatatypeValidator::Union)
                        psviMemberType = fValidationContext->getValidatingMemberType();
                }

                // call matchers and de-activate context
                if (toCheckIdentityConstraint())
                {
                    fICHandler->deactivateContext
                                   (
                                    (SchemaElementDecl *) elemDecl
                                  , fContent.getRawBuffer()
                                  , fValidationContext
                                  , fPSVIElemContext.fCurrentDV
                                   );
                }

            }
        }
        else if (fGrammarType == Grammar::SchemaGrammarType) {
            ((SchemaValidator*)fValidator)->resetNillable();
        }

        if (fGrammarType == Grammar::SchemaGrammarType)
        {
            if (fPSVIHandler)
            {
                endElementPSVI((SchemaElementDecl*)elemDecl, psviMemberType);
            }
        }

        // If we have a doc handler, tell it about the end tag
        if (fDocHandler)
        {
            fDocHandler->endElement
            (
                *elemDecl
                , uriId
                , isRoot
                , fPrefixBuf.getRawBuffer()
            );
        }

        // If the elem stack is empty, then it was an empty root
        if (isRoot)
            gotData = false;
        else
        {
            // Restore the grammar
            fGrammar = fElemStack.getCurrentGrammar();
            fGrammarType = fGrammar->getGrammarType();
            if (fGrammarType == Grammar::SchemaGrammarType && !fValidator->handlesSchema()) {
                if (fValidatorFromUser)
                    ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Gen_NoSchemaValidator, fMemoryManager);
                else {
                    fValidator = fSchemaValidator;
                }
            }
            else if (fGrammarType == Grammar::DTDGrammarType && !fValidator->handlesDTD()) {
                if (fValidatorFromUser)
                    ThrowXMLwithMemMgr(RuntimeException, XMLExcepts::Gen_NoDTDValidator, fMemoryManager);
                else {
                    fValidator = fDTDValidator;
                }
            }

            fValidator->setGrammar(fGrammar);

            // Restore the validation flag
            fValidate = fElemStack.getValidationFlag();
        }
    }
    else if (fGrammarType == Grammar::SchemaGrammarType)
    {
        // send a partial element psvi
        if (fPSVIHandler)
        {

            ComplexTypeInfo*   curTypeInfo = 0;
            DatatypeValidator* curDV = 0;
            XSTypeDefinition*  typeDef = 0;

            if (fValidate && elemDecl->isDeclared())
            {
                curTypeInfo = ((SchemaValidator*) fValidator)->getCurrentTypeInfo();

                if (curTypeInfo)
                {
                    typeDef = (XSTypeDefinition*) fModel->getXSObject(curTypeInfo);
                }
                else
                {
                    curDV = ((SchemaValidator*) fValidator)->getCurrentDatatypeValidator();

                    if (curDV)
                    {
                        typeDef = (XSTypeDefinition*) fModel->getXSObject(curDV);
                    }
                }
            }

            fPSVIElement->reset
                (
                  PSVIElement::VALIDITY_NOTKNOWN
                , PSVIElement::VALIDATION_NONE
                , fRootElemName
                , ((SchemaValidator*) fValidator)->getIsElemSpecified()
                , (elemDecl->isDeclared()) ? (XSElementDeclaration*) fModel->getXSObject(elemDecl) : 0
                , typeDef
                , 0 //memberType
                , fModel
                , ((SchemaElementDecl*)elemDecl)->getDefaultValue()
                , 0
                , 0
                , 0
                );


            fPSVIHandler->handlePartialElementPSVI
                (
                  elemDecl->getBaseName()
                , fURIStringPool->getValueForId(elemDecl->getURI())
                , fPSVIElement
                );

        }

        // not empty
        fErrorStack->push(fPSVIElemContext.fErrorOccurred);
    }

    return true;
}