| /* |
| * 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: ListDatatypeValidator.cpp 568078 2007-08-21 11:43:25Z amassari $ |
| */ |
| |
| // --------------------------------------------------------------------------- |
| // Includes |
| // --------------------------------------------------------------------------- |
| #include <xercesc/validators/datatype/ListDatatypeValidator.hpp> |
| #include <xercesc/validators/datatype/InvalidDatatypeFacetException.hpp> |
| #include <xercesc/validators/datatype/InvalidDatatypeValueException.hpp> |
| #include <xercesc/util/OutOfMemoryException.hpp> |
| |
| XERCES_CPP_NAMESPACE_BEGIN |
| |
| static const int BUF_LEN = 64; |
| |
| // --------------------------------------------------------------------------- |
| // Constructors and Destructor |
| // --------------------------------------------------------------------------- |
| ListDatatypeValidator::ListDatatypeValidator(MemoryManager* const manager) |
| :AbstractStringValidator(0, 0, 0, DatatypeValidator::List, manager) |
| ,fContent(0) |
| {} |
| |
| ListDatatypeValidator::ListDatatypeValidator( |
| DatatypeValidator* const baseValidator |
| , RefHashTableOf<KVStringPair>* const facets |
| , RefArrayVectorOf<XMLCh>* const enums |
| , const int finalSet |
| , MemoryManager* const manager) |
| :AbstractStringValidator(baseValidator, facets, finalSet, DatatypeValidator::List, manager) |
| ,fContent(0) |
| { |
| // |
| // baseValidator shall either |
| // an atomic DTV which servers as itemType, or |
| // another ListDTV from which, this ListDTV is derived by restriction. |
| // |
| // In either case, it shall be not null |
| // |
| if (!baseValidator) |
| ThrowXMLwithMemMgr(InvalidDatatypeFacetException, XMLExcepts::FACET_List_Null_baseValidator, manager); |
| |
| init(enums, manager); |
| } |
| |
| ListDatatypeValidator::~ListDatatypeValidator() |
| {} |
| |
| DatatypeValidator* ListDatatypeValidator::newInstance |
| ( |
| RefHashTableOf<KVStringPair>* const facets |
| , RefArrayVectorOf<XMLCh>* const enums |
| , const int finalSet |
| , MemoryManager* const manager |
| ) |
| { |
| return (DatatypeValidator*) new (manager) ListDatatypeValidator(this, facets, enums, finalSet, manager); |
| } |
| |
| |
| int ListDatatypeValidator::compare(const XMLCh* const lValue |
| , const XMLCh* const rValue |
| , MemoryManager* const manager) |
| { |
| DatatypeValidator* theItemTypeDTV = getItemTypeDTV(); |
| BaseRefVectorOf<XMLCh>* lVector = XMLString::tokenizeString(lValue, manager); |
| Janitor<BaseRefVectorOf<XMLCh> > janl(lVector); |
| BaseRefVectorOf<XMLCh>* rVector = XMLString::tokenizeString(rValue, manager); |
| Janitor<BaseRefVectorOf<XMLCh> > janr(rVector); |
| |
| int lNumberOfTokens = lVector->size(); |
| int rNumberOfTokens = rVector->size(); |
| |
| if (lNumberOfTokens < rNumberOfTokens) |
| return -1; |
| else if (lNumberOfTokens > rNumberOfTokens) |
| return 1; |
| else |
| { //compare each token |
| for ( int i = 0; i < lNumberOfTokens; i++) |
| { |
| int returnValue = theItemTypeDTV->compare(lVector->elementAt(i), rVector->elementAt(i), manager); |
| if (returnValue != 0) |
| return returnValue; //REVISIT: does it make sense to return -1 or +1..? |
| } |
| return 0; |
| } |
| |
| } |
| |
| void ListDatatypeValidator::validate( const XMLCh* const content |
| , ValidationContext* const context |
| , MemoryManager* const manager) |
| { |
| setContent(content); |
| BaseRefVectorOf<XMLCh>* tokenVector = XMLString::tokenizeString(content, manager); |
| Janitor<BaseRefVectorOf<XMLCh> > janName(tokenVector); |
| checkContent(tokenVector, content, context, false, manager); |
| } |
| |
| void ListDatatypeValidator::checkContent( const XMLCh* const content |
| , ValidationContext* const context |
| , bool asBase |
| , MemoryManager* const manager) |
| { |
| setContent(content); |
| BaseRefVectorOf<XMLCh>* tokenVector = XMLString::tokenizeString(content, manager); |
| Janitor<BaseRefVectorOf<XMLCh> > janName(tokenVector); |
| checkContent(tokenVector, content, context, asBase, manager); |
| } |
| |
| // |
| // here content is a list of items |
| // |
| void ListDatatypeValidator::checkContent( BaseRefVectorOf<XMLCh>* tokenVector |
| , const XMLCh* const content |
| , ValidationContext* const context |
| , bool asBase |
| , MemoryManager* const manager) |
| { |
| DatatypeValidator* bv = getBaseValidator(); |
| |
| if (bv->getType() == DatatypeValidator::List) |
| ((ListDatatypeValidator*)bv)->checkContent(tokenVector, content, context, true, manager); |
| else |
| { // the ultimate itemType DTV |
| for (unsigned int i = 0; i < tokenVector->size(); i++) |
| bv->validate(tokenVector->elementAt(i), context, manager); |
| } |
| |
| int thisFacetsDefined = getFacetsDefined(); |
| |
| // we check pattern first |
| if ( (thisFacetsDefined & DatatypeValidator::FACET_PATTERN ) != 0 ) |
| { |
| //check every item in the list as a whole |
| if (getRegex()->matches(content, manager) == false) |
| { |
| ThrowXMLwithMemMgr2(InvalidDatatypeValueException |
| , XMLExcepts::VALUE_NotMatch_Pattern |
| , content |
| , getPattern() |
| , manager); |
| } |
| |
| } |
| |
| // if this is a base validator, we only need to check pattern facet |
| // all other facet were inherited by the derived type |
| if (asBase) |
| return; |
| |
| unsigned int tokenNumber = tokenVector->size(); |
| |
| if (((thisFacetsDefined & DatatypeValidator::FACET_MAXLENGTH) != 0) && |
| (tokenNumber > getMaxLength())) |
| { |
| XMLCh value1[BUF_LEN+1]; |
| XMLCh value2[BUF_LEN+1]; |
| XMLString::binToText(tokenNumber, value1, BUF_LEN, 10, manager); |
| XMLString::binToText(getMaxLength(), value2, BUF_LEN, 10, manager); |
| |
| ThrowXMLwithMemMgr3(InvalidDatatypeValueException |
| , XMLExcepts::VALUE_GT_maxLen |
| , getContent() |
| , value1 |
| , value2 |
| , manager); |
| } |
| |
| if (((thisFacetsDefined & DatatypeValidator::FACET_MINLENGTH) != 0) && |
| (tokenNumber < getMinLength())) |
| { |
| XMLCh value1[BUF_LEN+1]; |
| XMLCh value2[BUF_LEN+1]; |
| XMLString::binToText(tokenNumber, value1, BUF_LEN, 10, manager); |
| XMLString::binToText(getMinLength(), value2, BUF_LEN, 10, manager); |
| |
| ThrowXMLwithMemMgr3(InvalidDatatypeValueException |
| , XMLExcepts::VALUE_LT_minLen |
| , getContent() |
| , value1 |
| , value2 |
| , manager); |
| } |
| |
| if (((thisFacetsDefined & DatatypeValidator::FACET_LENGTH) != 0) && |
| (tokenNumber != AbstractStringValidator::getLength())) |
| { |
| XMLCh value1[BUF_LEN+1]; |
| XMLCh value2[BUF_LEN+1]; |
| XMLString::binToText(tokenNumber, value1, BUF_LEN, 10, manager); |
| XMLString::binToText(AbstractStringValidator::getLength(), value2, BUF_LEN, 10, manager); |
| |
| ThrowXMLwithMemMgr3(InvalidDatatypeValueException |
| , XMLExcepts::VALUE_NE_Len |
| , getContent() |
| , value1 |
| , value2 |
| , manager); |
| } |
| |
| if ((thisFacetsDefined & DatatypeValidator::FACET_ENUMERATION) != 0 && |
| (getEnumeration() != 0)) |
| { |
| int i; |
| int enumLength = getEnumeration()->size(); |
| |
| for ( i = 0; i < enumLength; i++) |
| { |
| //optimization: we do a lexical comparision first |
| // this may be faster for string and its derived |
| if (XMLString::equals(getEnumeration()->elementAt(i), getContent())) |
| break; // a match found |
| |
| // do a value space check |
| // this is needed for decimal (and probably other types |
| // such as datetime related) |
| // eg. |
| // tokenVector = "1 2 3.0 4" vs enumeration = "1 2 3 4.0" |
| // |
| if (valueSpaceCheck(tokenVector, getEnumeration()->elementAt(i), manager)) |
| break; |
| } |
| |
| if (i == enumLength) |
| ThrowXMLwithMemMgr1(InvalidDatatypeValueException, XMLExcepts::VALUE_NotIn_Enumeration, getContent(), manager); |
| |
| } // enumeration |
| |
| } |
| |
| bool ListDatatypeValidator::valueSpaceCheck(BaseRefVectorOf<XMLCh>* tokenVector |
| , const XMLCh* const enumStr |
| , MemoryManager* const manager) const |
| { |
| DatatypeValidator* theItemTypeDTV = getItemTypeDTV(); |
| BaseRefVectorOf<XMLCh>* enumVector = XMLString::tokenizeString(enumStr, manager); |
| Janitor<BaseRefVectorOf<XMLCh> > janName(enumVector); |
| |
| if (tokenVector->size() != enumVector->size()) |
| return false; |
| |
| for ( unsigned int j = 0; j < tokenVector->size(); j++ ) |
| { |
| if (theItemTypeDTV->compare(tokenVector->elementAt(j), enumVector->elementAt(j), manager) != 0) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| DatatypeValidator* ListDatatypeValidator::getItemTypeDTV() const |
| { |
| DatatypeValidator* bdv = this->getBaseValidator(); |
| |
| while (bdv->getType() == DatatypeValidator::List) |
| bdv = bdv->getBaseValidator(); |
| |
| return bdv; |
| } |
| |
| // --------------------------------------------------------------------------- |
| // Utilities |
| // --------------------------------------------------------------------------- |
| |
| void ListDatatypeValidator::checkValueSpace(const XMLCh* const |
| , MemoryManager* const) |
| {} |
| |
| int ListDatatypeValidator::getLength(const XMLCh* const content |
| , MemoryManager* const manager) const |
| { |
| BaseRefVectorOf<XMLCh>* tokenVector = XMLString::tokenizeString(content, manager); |
| Janitor<BaseRefVectorOf<XMLCh> > janName(tokenVector); |
| |
| return tokenVector->size(); |
| } |
| |
| void ListDatatypeValidator::inspectFacetBase(MemoryManager* const manager) |
| { |
| |
| // |
| // we are pretty sure baseValidator is not null |
| // |
| |
| if (getBaseValidator()->getType() == DatatypeValidator::List) |
| { |
| AbstractStringValidator::inspectFacetBase(manager); |
| } |
| else |
| { |
| // the first level ListDTV |
| // check 4.3.5.c0 must: enumeration values from the value space of base |
| if ( ((getFacetsDefined() & DatatypeValidator::FACET_ENUMERATION) != 0) && |
| (getEnumeration() !=0) ) |
| { |
| int i; |
| int enumLength = getEnumeration()->size(); |
| try |
| { |
| for ( i = 0; i < enumLength; i++) |
| { |
| // ask the itemType for a complete check |
| BaseRefVectorOf<XMLCh>* tempList = XMLString::tokenizeString(getEnumeration()->elementAt(i), manager); |
| Janitor<BaseRefVectorOf<XMLCh> > jan(tempList); |
| int tokenNumber = tempList->size(); |
| |
| try |
| { |
| for ( int j = 0; j < tokenNumber; j++) |
| getBaseValidator()->validate(tempList->elementAt(j), (ValidationContext*)0, manager); |
| } |
| catch(const OutOfMemoryException&) |
| { |
| jan.release(); |
| |
| throw; |
| } |
| #if 0 |
| // spec says that only base has to checkContent |
| // enum shall pass this->checkContent() as well. |
| checkContent(getEnumeration()->elementAt(i), (ValidationContext*)0, false, manager); |
| #endif |
| } |
| } |
| |
| catch ( XMLException& ) |
| { |
| ThrowXMLwithMemMgr1(InvalidDatatypeFacetException |
| , XMLExcepts::FACET_enum_base |
| , getEnumeration()->elementAt(i) |
| , manager); |
| } |
| |
| } |
| |
| } |
| |
| }// End of inspectFacetBase() |
| |
| void ListDatatypeValidator::inheritFacet() |
| { |
| |
| //iff the base validator is List, then we inherit |
| // |
| if (getBaseValidator()->getType() == DatatypeValidator::List) |
| { |
| AbstractStringValidator::inheritFacet(); |
| } |
| |
| } |
| |
| /*** |
| * 2.5.1.2 List datatypes |
| * |
| * The canonical-lexical-representation for the ·list· datatype is defined as |
| * the lexical form in which each item in the ·list· has the canonical |
| * lexical representation of its ·itemType·. |
| ***/ |
| const XMLCh* ListDatatypeValidator::getCanonicalRepresentation(const XMLCh* const rawData |
| , MemoryManager* const memMgr |
| , bool toValidate) const |
| { |
| MemoryManager* toUse = memMgr? memMgr : getMemoryManager(); |
| ListDatatypeValidator* temp = (ListDatatypeValidator*) this; |
| temp->setContent(rawData); |
| BaseRefVectorOf<XMLCh>* tokenVector = XMLString::tokenizeString(rawData, toUse); |
| Janitor<BaseRefVectorOf<XMLCh> > janName(tokenVector); |
| |
| if (toValidate) |
| { |
| try |
| { |
| temp->checkContent(tokenVector, rawData, 0, false, toUse); |
| } |
| catch (...) |
| { |
| return 0; |
| } |
| } |
| |
| unsigned int retBufSize = 2 * XMLString::stringLen(rawData); |
| XMLCh* retBuf = (XMLCh*) toUse->allocate(retBufSize * sizeof(XMLCh)); |
| retBuf[0] = 0; |
| XMLCh* retBufPtr = retBuf; |
| DatatypeValidator* itemDv = this->getItemTypeDTV(); |
| |
| try |
| { |
| for (unsigned int i = 0; i < tokenVector->size(); i++) |
| { |
| XMLCh* itemCanRep = (XMLCh*) itemDv->getCanonicalRepresentation(tokenVector->elementAt(i), toUse, false); |
| unsigned int itemLen = XMLString::stringLen(itemCanRep); |
| |
| if(retBufPtr+itemLen+2 >= retBuf+retBufSize) |
| { |
| // need to resize |
| XMLCh * oldBuf = retBuf; |
| retBuf = (XMLCh*) toUse->allocate(retBufSize * sizeof(XMLCh) * 4); |
| memcpy(retBuf, oldBuf, retBufSize * sizeof(XMLCh )); |
| retBufPtr = (retBufPtr - oldBuf) + retBuf; |
| toUse->deallocate(oldBuf); |
| retBufSize <<= 2; |
| } |
| |
| XMLString::catString(retBufPtr, itemCanRep); |
| retBufPtr = retBufPtr + itemLen; |
| *(retBufPtr++) = chSpace; |
| *(retBufPtr) = chNull; |
| toUse->deallocate(itemCanRep); |
| } |
| |
| return retBuf; |
| |
| } |
| catch (...) |
| { |
| return 0; |
| } |
| } |
| |
| /*** |
| * Support for Serialization/De-serialization |
| ***/ |
| |
| IMPL_XSERIALIZABLE_TOCREATE(ListDatatypeValidator) |
| |
| void ListDatatypeValidator::serialize(XSerializeEngine& serEng) |
| { |
| AbstractStringValidator::serialize(serEng); |
| |
| //don't serialize fContent, since it is NOT owned and |
| //will be reset each time validate()/checkContent() invoked. |
| } |
| |
| XERCES_CPP_NAMESPACE_END |
| |
| /** |
| * End of file ListDatatypeValidator.cpp |
| */ |