blob: 89260a33492cad22676d4f8cbf9252c5f0e9dcce [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* $Id: ContentSpecNode.cpp 568078 2007-08-21 11:43:25Z amassari $
*/
// ---------------------------------------------------------------------------
// Includes
// ---------------------------------------------------------------------------
#include <xercesc/framework/XMLBuffer.hpp>
#include <xercesc/validators/common/ContentSpecNode.hpp>
#include <xercesc/validators/schema/SchemaSymbols.hpp>
XERCES_CPP_NAMESPACE_BEGIN
// ---------------------------------------------------------------------------
// ContentSpecNode: Copy Constructor
//
// Note: this copy constructor has dependency on various get*() methods
// and shall be placed after those method's declaration.
// aka inline function compilation error on AIX 4.2, xlC 3 r ev.1
// ---------------------------------------------------------------------------
ContentSpecNode::ContentSpecNode(const ContentSpecNode& toCopy) :
XSerializable(toCopy)
, XMemory(toCopy)
, fMemoryManager(toCopy.fMemoryManager)
, fElement(0)
, fElementDecl(toCopy.fElementDecl)
, fFirst(0)
, fSecond(0)
, fType(toCopy.fType)
, fAdoptFirst(true)
, fAdoptSecond(true)
, fMinOccurs(toCopy.fMinOccurs)
, fMaxOccurs(toCopy.fMaxOccurs)
{
const QName* tempElement = toCopy.getElement();
if (tempElement)
fElement = new (fMemoryManager) QName(*tempElement);
const ContentSpecNode *tmp = toCopy.getFirst();
if (tmp)
fFirst = new (fMemoryManager) ContentSpecNode(*tmp);
tmp = toCopy.getSecond();
if (tmp)
fSecond = new (fMemoryManager) ContentSpecNode(*tmp);
}
// ---------------------------------------------------------------------------
// Local methods
// ---------------------------------------------------------------------------
static void formatNode( const ContentSpecNode* const curNode
, const ContentSpecNode::NodeTypes parentType
, XMLBuffer& bufToFill)
{
if (!curNode)
return;
const ContentSpecNode* first = curNode->getFirst();
const ContentSpecNode* second = curNode->getSecond();
const ContentSpecNode::NodeTypes curType = curNode->getType();
// Get the type of the first node
const ContentSpecNode::NodeTypes firstType = first ?
first->getType() :
ContentSpecNode::Leaf;
// Calculate the parens flag for the rep nodes
bool doRepParens = false;
if (((firstType != ContentSpecNode::Leaf)
&& (parentType != ContentSpecNode::UnknownType))
|| ((firstType == ContentSpecNode::Leaf)
&& (parentType == ContentSpecNode::UnknownType)))
{
doRepParens = true;
}
// Now handle our type
switch(curType & 0x0f)
{
case ContentSpecNode::Leaf :
if (curNode->getElement()->getURI() == XMLElementDecl::fgPCDataElemId)
bufToFill.append(XMLElementDecl::fgPCDataElemName);
else
bufToFill.append(curNode->getElement()->getRawName());
break;
case ContentSpecNode::ZeroOrOne :
if (doRepParens)
bufToFill.append(chOpenParen);
formatNode(first, curType, bufToFill);
if (doRepParens)
bufToFill.append(chCloseParen);
bufToFill.append(chQuestion);
break;
case ContentSpecNode::ZeroOrMore :
if (doRepParens)
bufToFill.append(chOpenParen);
formatNode(first, curType, bufToFill);
if (doRepParens)
bufToFill.append(chCloseParen);
bufToFill.append(chAsterisk);
break;
case ContentSpecNode::OneOrMore :
if (doRepParens)
bufToFill.append(chOpenParen);
formatNode(first, curType, bufToFill);
if (doRepParens)
bufToFill.append(chCloseParen);
bufToFill.append(chPlus);
break;
case ContentSpecNode::Choice :
if (parentType != curType)
bufToFill.append(chOpenParen);
formatNode(first, curType, bufToFill);
bufToFill.append(chPipe);
formatNode(second, curType, bufToFill);
if (parentType != curType)
bufToFill.append(chCloseParen);
break;
case ContentSpecNode::Sequence :
if (parentType != curType)
bufToFill.append(chOpenParen);
formatNode(first, curType, bufToFill);
bufToFill.append(chComma);
formatNode(second, curType, bufToFill);
if (parentType != curType)
bufToFill.append(chCloseParen);
break;
case ContentSpecNode::All :
if (parentType != curType)
{
bufToFill.append(chLatin_A);
bufToFill.append(chLatin_l);
bufToFill.append(chLatin_l);
bufToFill.append(chOpenParen);
}
formatNode(first, curType, bufToFill);
bufToFill.append(chComma);
formatNode(second, curType, bufToFill);
if (parentType != curType)
bufToFill.append(chCloseParen);
break;
}
}
// ---------------------------------------------------------------------------
// ContentSpecNode: Miscellaneous
// ---------------------------------------------------------------------------
void ContentSpecNode::formatSpec(XMLBuffer& bufToFill) const
{
// Clean out the buffer first
bufToFill.reset();
if (fType == ContentSpecNode::Leaf)
bufToFill.append(chOpenParen);
formatNode
(
this
, UnknownType
, bufToFill
);
if (fType == ContentSpecNode::Leaf)
bufToFill.append(chCloseParen);
}
int ContentSpecNode::getMinTotalRange() const {
int min = fMinOccurs;
if ((fType & 0x0f) == ContentSpecNode::Sequence
|| fType == ContentSpecNode::All
|| (fType & 0x0f) == ContentSpecNode::Choice) {
int minFirst = fFirst->getMinTotalRange();
if (fSecond) {
int minSecond = fSecond->getMinTotalRange();
if ((fType & 0x0f) == ContentSpecNode::Choice) {
min = min * ((minFirst < minSecond)? minFirst : minSecond);
}
else {
min = min * (minFirst + minSecond);
}
}
else
min = min * minFirst;
}
return min;
}
int ContentSpecNode::getMaxTotalRange() const {
int max = fMaxOccurs;
if (max == SchemaSymbols::XSD_UNBOUNDED) {
return SchemaSymbols::XSD_UNBOUNDED;
}
if ((fType & 0x0f) == ContentSpecNode::Sequence
|| fType == ContentSpecNode::All
|| (fType & 0x0f) == ContentSpecNode::Choice) {
int maxFirst = fFirst->getMaxTotalRange();
if (maxFirst == SchemaSymbols::XSD_UNBOUNDED) {
return SchemaSymbols::XSD_UNBOUNDED;
}
if (fSecond) {
int maxSecond = fSecond->getMaxTotalRange();
if (maxSecond == SchemaSymbols::XSD_UNBOUNDED) {
return SchemaSymbols::XSD_UNBOUNDED;
}
else {
if ((fType & 0x0f) == ContentSpecNode::Choice) {
max = max * (maxFirst > maxSecond) ? maxFirst : maxSecond;
}
else {
max = max * (maxFirst + maxSecond);
}
}
}
else {
max = max * maxFirst;
}
}
return max;
}
/***
* Support for Serialization/De-serialization
***/
IMPL_XSERIALIZABLE_TOCREATE(ContentSpecNode)
void ContentSpecNode::serialize(XSerializeEngine& serEng)
{
/***
* Since fElement, fFirst, fSecond are NOT created by the default
* constructor, we need to create them dynamically.
***/
if (serEng.isStoring())
{
serEng<<fElement;
XMLElementDecl::storeElementDecl(serEng, fElementDecl);
serEng<<fFirst;
serEng<<fSecond;
serEng<<(int)fType;
serEng<<fAdoptFirst;
serEng<<fAdoptSecond;
serEng<<fMinOccurs;
serEng<<fMaxOccurs;
}
else
{
serEng>>fElement;
fElementDecl = XMLElementDecl::loadElementDecl(serEng);
serEng>>fFirst;
serEng>>fSecond;
int type;
serEng>>type;
fType = (NodeTypes)type;
serEng>>fAdoptFirst;
serEng>>fAdoptSecond;
serEng>>fMinOccurs;
serEng>>fMaxOccurs;
}
}
XERCES_CPP_NAMESPACE_END