| /* |
| * 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$ |
| */ |
| |
| // --------------------------------------------------------------------------- |
| // Includes |
| // --------------------------------------------------------------------------- |
| #include <xercesc/internal/XMLScanner.hpp> |
| #include <xercesc/framework/XMLValidator.hpp> |
| #include <xercesc/validators/datatype/DatatypeValidator.hpp> |
| #include <xercesc/validators/schema/identity/FieldActivator.hpp> |
| #include <xercesc/validators/schema/identity/ValueStore.hpp> |
| #include <xercesc/validators/schema/identity/IC_Field.hpp> |
| #include <xercesc/validators/schema/identity/IC_KeyRef.hpp> |
| #include <xercesc/validators/schema/identity/ValueStoreCache.hpp> |
| |
| XERCES_CPP_NAMESPACE_BEGIN |
| |
| // |
| // --------------------------------------------------------------------------- |
| // ICValueHasher: the hasher for identity constraints values |
| // --------------------------------------------------------------------------- |
| XMLSize_t ICValueHasher::getHashVal(const void* key, XMLSize_t mod) const |
| { |
| const FieldValueMap* valueMap=(const FieldValueMap*)key; |
| XMLSize_t hashVal = 0; |
| |
| XMLSize_t size = valueMap->size(); |
| for (XMLSize_t j=0; j<size; j++) { |
| // reach the most generic datatype validator |
| DatatypeValidator* dv = valueMap->getDatatypeValidatorAt(j); |
| while(dv && dv->getBaseValidator()) |
| dv = dv->getBaseValidator(); |
| const XMLCh* const val = valueMap->getValueAt(j); |
| const XMLCh* canonVal = (dv && val)?dv->getCanonicalRepresentation(val, fMemoryManager):0; |
| if(canonVal) |
| { |
| hashVal += XMLString::hash(canonVal, mod); |
| fMemoryManager->deallocate((void*)canonVal); |
| } |
| else if(val) |
| hashVal += XMLString::hash(val, mod); |
| } |
| |
| return hashVal % mod; |
| } |
| |
| bool ICValueHasher::equals(const void *const key1, const void *const key2) const |
| { |
| const FieldValueMap* left=(const FieldValueMap*)key1; |
| const FieldValueMap* right=(const FieldValueMap*)key2; |
| |
| XMLSize_t lSize = left->size(); |
| XMLSize_t rSize = right->size(); |
| if (lSize == rSize) |
| { |
| bool matchFound = true; |
| |
| for (XMLSize_t j=0; j<rSize; j++) { |
| if (!isDuplicateOf(left->getDatatypeValidatorAt(j), left->getValueAt(j), |
| right->getDatatypeValidatorAt(j), right->getValueAt(j))) { |
| matchFound = false; |
| break; |
| } |
| } |
| |
| if (matchFound) { // found it |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool ICValueHasher::isDuplicateOf(DatatypeValidator* const dv1, const XMLCh* const val1, |
| DatatypeValidator* const dv2, const XMLCh* const val2) const |
| { |
| |
| // if either validator's null, fall back on string comparison |
| if(!dv1 || !dv2) { |
| return (XMLString::equals(val1, val2)); |
| } |
| |
| bool val1IsEmpty = (val1==0 || *val1==0); |
| bool val2IsEmpty = (val2==0 || *val2==0); |
| |
| if (val1IsEmpty && val2IsEmpty) { |
| |
| if (dv1 == dv2) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| if (val1IsEmpty || val2IsEmpty) { |
| return false; |
| } |
| |
| // find the common ancestor, if there is one |
| DatatypeValidator* tempVal1 = dv1; |
| while(tempVal1) |
| { |
| DatatypeValidator* tempVal2 = dv2; |
| for(; tempVal2 != NULL && tempVal2 != tempVal1; tempVal2 = tempVal2->getBaseValidator()) ; |
| if (tempVal2) |
| return ((tempVal2->compare(val1, val2, fMemoryManager)) == 0); |
| tempVal1=tempVal1->getBaseValidator(); |
| } |
| |
| // if we're here it means the types weren't related. They are different: |
| return false; |
| } |
| |
| // --------------------------------------------------------------------------- |
| // ValueStore: Constructors and Destructor |
| // --------------------------------------------------------------------------- |
| ValueStore::ValueStore(IdentityConstraint* const ic, |
| XMLScanner* const scanner, |
| MemoryManager* const manager) |
| : fDoReportError(false) |
| , fValuesCount(0) |
| , fIdentityConstraint(ic) |
| , fValues(manager) |
| , fValueTuples(0) |
| , fScanner(scanner) |
| , fMemoryManager(manager) |
| { |
| fDoReportError = (scanner && (scanner->getValidationScheme() == XMLScanner::Val_Always)); |
| } |
| |
| |
| ValueStore::~ValueStore() |
| { |
| delete fValueTuples; |
| } |
| |
| // --------------------------------------------------------------------------- |
| // ValueStore: Helper methods |
| // --------------------------------------------------------------------------- |
| void ValueStore::addValue(FieldActivator* const fieldActivator, |
| IC_Field* const field, |
| DatatypeValidator* const dv, |
| const XMLCh* const value) { |
| |
| if (!fieldActivator->getMayMatch(field) && fDoReportError) { |
| fScanner->getValidator()->emitError(XMLValid::IC_FieldMultipleMatch); |
| } |
| |
| // do we even know this field? |
| XMLSize_t index; |
| bool bFound = fValues.indexOf(field, index); |
| |
| if (!bFound) { |
| |
| if (fDoReportError) { |
| fScanner->getValidator()->emitError(XMLValid::IC_UnknownField); |
| } |
| |
| return; |
| } |
| |
| // store value |
| if (!fValues.getDatatypeValidatorAt(index) && |
| !fValues.getValueAt(index)) { |
| fValuesCount++; |
| } |
| |
| fValues.put(field, dv, value); |
| |
| if (fValuesCount == fValues.size()) { |
| |
| // is this value as a group duplicated? |
| if (contains(&fValues)) { |
| duplicateValue(); |
| } |
| |
| // store values |
| if (!fValueTuples) { |
| fValueTuples = new (fMemoryManager) RefHashTableOf<FieldValueMap, ICValueHasher>(107, true, ICValueHasher(fMemoryManager), fMemoryManager); |
| } |
| |
| FieldValueMap* pICItem = new (fMemoryManager) FieldValueMap(fValues); |
| fValueTuples->put(pICItem, pICItem); |
| } |
| } |
| |
| void ValueStore::append(const ValueStore* const other) { |
| |
| if (!other->fValueTuples) { |
| return; |
| } |
| |
| RefHashTableOfEnumerator<FieldValueMap, ICValueHasher> iter(other->fValueTuples, false, fMemoryManager); |
| while(iter.hasMoreElements()) |
| { |
| FieldValueMap& valueMap = iter.nextElement(); |
| |
| if (!contains(&valueMap)) { |
| |
| if (!fValueTuples) { |
| fValueTuples = new (fMemoryManager) RefHashTableOf<FieldValueMap, ICValueHasher>(107, true, ICValueHasher(fMemoryManager), fMemoryManager); |
| } |
| |
| FieldValueMap* pICItem = new (fMemoryManager) FieldValueMap(valueMap); |
| fValueTuples->put(pICItem, pICItem); |
| } |
| } |
| } |
| |
| void ValueStore::startValueScope() { |
| |
| fValuesCount = 0; |
| |
| XMLSize_t count = fIdentityConstraint->getFieldCount(); |
| |
| for (XMLSize_t i = 0; i < count; i++) { |
| fValues.put(fIdentityConstraint->getFieldAt(i), 0, 0); |
| } |
| } |
| |
| void ValueStore::endValueScope() { |
| |
| if (fValuesCount == 0) { |
| |
| if (fIdentityConstraint->getType() == IdentityConstraint::ICType_KEY && fDoReportError) { |
| fScanner->getValidator()->emitError(XMLValid::IC_AbsentKeyValue, |
| fIdentityConstraint->getElementName()); |
| } |
| |
| return; |
| } |
| |
| // do we have enough values? |
| if ((fValuesCount != fIdentityConstraint->getFieldCount()) && fDoReportError) { |
| |
| if(fIdentityConstraint->getType()==IdentityConstraint::ICType_KEY) |
| { |
| fScanner->getValidator()->emitError(XMLValid::IC_KeyNotEnoughValues, |
| fIdentityConstraint->getElementName(), fIdentityConstraint->getIdentityConstraintName()); |
| } |
| } |
| } |
| |
| bool ValueStore::contains(const FieldValueMap* const other) { |
| |
| if (fValueTuples) |
| return fValueTuples->get(other)!=0; |
| |
| return false; |
| } |
| |
| void ValueStore::clear() |
| { |
| fValuesCount=0; |
| fValues.clear(); |
| if(fValueTuples) |
| fValueTuples->removeAll(); |
| } |
| |
| // --------------------------------------------------------------------------- |
| // ValueStore: Document handling methods |
| // --------------------------------------------------------------------------- |
| void ValueStore::endDocumentFragment(ValueStoreCache* const valueStoreCache) { |
| |
| if (fIdentityConstraint->getType() == IdentityConstraint::ICType_KEYREF) { |
| |
| // verify references |
| // get the key store corresponding (if it exists): |
| ValueStore* keyValueStore = valueStoreCache->getGlobalValueStoreFor(((IC_KeyRef*) fIdentityConstraint)->getKey()); |
| |
| if (!keyValueStore) { |
| |
| if (fDoReportError) { |
| fScanner->getValidator()->emitError(XMLValid::IC_KeyRefOutOfScope, |
| fIdentityConstraint->getIdentityConstraintName()); |
| } |
| |
| return; |
| } |
| |
| if(fValueTuples) |
| { |
| RefHashTableOfEnumerator<FieldValueMap, ICValueHasher> iter(fValueTuples, false, fMemoryManager); |
| while(iter.hasMoreElements()) |
| { |
| FieldValueMap& valueMap = iter.nextElement(); |
| |
| if (!keyValueStore->contains(&valueMap) && fDoReportError) { |
| |
| fScanner->getValidator()->emitError(XMLValid::IC_KeyNotFound, |
| fIdentityConstraint->getElementName()); |
| } |
| } |
| } |
| } |
| } |
| |
| // --------------------------------------------------------------------------- |
| // ValueStore: Error reporting methods |
| // --------------------------------------------------------------------------- |
| void ValueStore::reportNilError(IdentityConstraint* const ic) { |
| |
| if (fDoReportError && ic->getType() == IdentityConstraint::ICType_KEY) { |
| fScanner->getValidator()->emitError(XMLValid::IC_KeyMatchesNillable, |
| ic->getElementName()); |
| } |
| } |
| |
| void ValueStore::duplicateValue() { |
| |
| if (fDoReportError) { |
| |
| switch (fIdentityConstraint->getType()) { |
| case IdentityConstraint::ICType_UNIQUE: |
| { |
| fScanner->getValidator()->emitError(XMLValid::IC_DuplicateUnique, |
| fIdentityConstraint->getElementName()); |
| break; |
| } |
| case IdentityConstraint::ICType_KEY: |
| { |
| fScanner->getValidator()->emitError(XMLValid::IC_DuplicateKey, |
| fIdentityConstraint->getElementName()); |
| break; |
| } |
| } |
| } |
| } |
| |
| XERCES_CPP_NAMESPACE_END |
| |
| /** |
| * End of file ValueStore.cpp |
| */ |
| |