| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 1999 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Xerces" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache\@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * nor may "Apache" appear in their name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation, and was |
| * originally based on software copyright (c) 1999, International |
| * Business Machines, Inc., http://www.ibm.com . For more information |
| * on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| /** |
| * $Log$ |
| * Revision 1.1 1999/11/09 01:03:43 twl |
| * Initial revision |
| * |
| * Revision 1.3 1999/11/08 20:45:43 rahul |
| * Swat for adding in Product name and CVS comment log variable. |
| * |
| */ |
| |
| |
| // --------------------------------------------------------------------------- |
| // Includes |
| // --------------------------------------------------------------------------- |
| #include <memory.h> |
| #include <string.h> |
| #include <util/RuntimeException.hpp> |
| #include <framework/XMLElementDecl.hpp> |
| #include <framework/XMLValidator.hpp> |
| #include <validators/DTD/ContentSpecNode.hpp> |
| #include <validators/DTD/DTDElementDecl.hpp> |
| #include <validators/DTD/MixedContentModel.hpp> |
| #include <validators/DTD/CMStateSet.hpp> |
| |
| |
| // --------------------------------------------------------------------------- |
| // MixedContentModel: Constructors and Destructor |
| // --------------------------------------------------------------------------- |
| MixedContentModel::MixedContentModel(const DTDElementDecl& parentElem) |
| { |
| // |
| // Create a vector of unsigned ints that will be filled in with the |
| // ids of the child nodes. It will be expanded as needed but we give |
| // it an initial capacity of 64 which should be more than enough for |
| // 99% of the scenarios. |
| // |
| ValueVectorOf<unsigned int> childIds(64); |
| |
| // |
| // Get the parent element's content spec. This is the head of the tree |
| // of nodes that describes the content model. We will iterate this |
| // tree. |
| // |
| const ContentSpecNode* curNode = parentElem.getContentSpec(); |
| if (!curNode) |
| { |
| // <TBD> This is an error |
| } |
| |
| // And now call the private recursive method that iterates the tree |
| buildChildList(*curNode, childIds); |
| |
| // |
| // And now we know how many elements we need in our member list. So |
| // fill them in. |
| // |
| fCount = childIds.size(); |
| fChildIds = new unsigned int[fCount]; |
| memcpy(fChildIds, childIds.rawData(), fCount * sizeof(unsigned int)); |
| } |
| |
| |
| MixedContentModel::~MixedContentModel() |
| { |
| delete [] fChildIds; |
| } |
| |
| |
| // --------------------------------------------------------------------------- |
| // MixedContentModel: Getter methods |
| // --------------------------------------------------------------------------- |
| bool MixedContentModel::hasDups() const |
| { |
| // Can't have dups if only one child |
| if (fCount == 1) |
| return false; |
| |
| for (unsigned int index = 0; index < fCount; index++) |
| { |
| const unsigned int curVal = fChildIds[index]; |
| for (unsigned int iIndex = 0; iIndex < fCount; iIndex++) |
| { |
| if (iIndex == index) |
| continue; |
| |
| if (curVal == fChildIds[iIndex]) |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| // --------------------------------------------------------------------------- |
| // MixedContentModel: Implementation of the ContentModel virtual interface |
| // --------------------------------------------------------------------------- |
| bool MixedContentModel::getIsAmbiguous() const |
| { |
| if (fCount < 2) |
| return false; |
| |
| unsigned int index; |
| |
| // |
| // Run through the children and remember the min and max element ids. |
| // These will be used to create a bit set that will map to element ids |
| // (adjusted by the min value.) |
| // |
| // Note that we skip the 0th element because its the PCDATA one. |
| // |
| unsigned int minId = 0xFFFFFFFF; |
| unsigned int maxId = 0; |
| for (index = 1; index < fCount; index++) |
| { |
| const unsigned int curId = fChildIds[index]; |
| if (curId < minId) |
| minId = curId; |
| |
| if (curId > maxId) |
| maxId = curId; |
| } |
| |
| // |
| // Ok, now we can create a range value that represents the spread |
| // between the min/max element value. |
| // |
| // With this number we can create a state set that has a bit per |
| // possible entry in the leaf array. |
| // |
| const unsigned int idRange = (maxId - minId) + 1; |
| CMStateSet idSet(idRange); |
| |
| for (index = 1; index < fCount; index++) |
| { |
| const unsigned int adjustedId = fChildIds[index] - minId; |
| if (idSet.getBit(adjustedId)) |
| return true; |
| idSet.setBit(adjustedId); |
| } |
| return false; |
| } |
| |
| int |
| MixedContentModel::validateContent( const unsigned int* childIds |
| , const unsigned int childCount) const |
| { |
| // Use an outer index to search the passed list of children |
| for (unsigned int outIndex = 0; outIndex < childCount; outIndex++) |
| { |
| // Get the current child out of the source index |
| const unsigned int curChild = childIds[outIndex]; |
| |
| // If its PCDATA, then we just accept that |
| if (curChild == XMLElementDecl::fgPCDataElemId) |
| continue; |
| |
| // Otherwise try to find it in our list using an inner index |
| unsigned int inIndex = 0; |
| for (; inIndex < fCount; inIndex++) |
| { |
| if (curChild == fChildIds[inIndex]) |
| break; |
| } |
| |
| // |
| // We did not find this one, so the validation failed. We return |
| // the outer index, which is the index of the child that failed. |
| // |
| if (inIndex == fCount) |
| return outIndex; |
| } |
| |
| // Return success |
| return XMLValidator::Success; |
| } |
| |
| |
| // --------------------------------------------------------------------------- |
| // MixedContentModel: Private helper methods |
| // --------------------------------------------------------------------------- |
| void |
| MixedContentModel::buildChildList( const ContentSpecNode& curNode |
| , ValueVectorOf<unsigned int>& toFill) |
| { |
| // Get the type of spec node our current node is |
| const ContentSpecNode::NodeTypes curType = curNode.getType(); |
| |
| // If its a leaf, then store its id in the target list |
| if (curType == ContentSpecNode::Leaf) |
| { |
| toFill.addElement(curNode.getElemId()); |
| return; |
| } |
| |
| // Get both the child node pointers |
| const ContentSpecNode* leftNode = curNode.getFirst(); |
| const ContentSpecNode* rightNode = curNode.getSecond(); |
| |
| // And recurse according to the type of node |
| if ((curType == ContentSpecNode::Choice) |
| || (curType == ContentSpecNode::Sequence)) |
| { |
| // Recurse on the left and right nodes |
| buildChildList(*leftNode, toFill); |
| |
| // The last node of a choice or sequence has a null right |
| if (rightNode) |
| buildChildList(*rightNode, toFill); |
| } |
| else if ((curType == ContentSpecNode::OneOrMore) |
| || (curType == ContentSpecNode::ZeroOrOne) |
| || (curType == ContentSpecNode::ZeroOrMore)) |
| { |
| // Just do the left node on this one |
| buildChildList(*leftNode, toFill); |
| } |
| } |