/* * 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 #include #include #include #include #include #include #include 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; jgetDatatypeValidatorAt(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; jgetDatatypeValidatorAt(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(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 iter(other->fValueTuples, false, fMemoryManager); while(iter.hasMoreElements()) { FieldValueMap& valueMap = iter.nextElement(); if (!contains(&valueMap)) { if (!fValueTuples) { fValueTuples = new (fMemoryManager) RefHashTableOf(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 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 */