1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 /*
19 * $Id$
20 */
21
22 // ---------------------------------------------------------------------------
23 // Includes
24 // ---------------------------------------------------------------------------
25 #include <xercesc/validators/datatype/UnionDatatypeValidator.hpp>
26 #include <xercesc/validators/datatype/InvalidDatatypeFacetException.hpp>
27 #include <xercesc/validators/datatype/InvalidDatatypeValueException.hpp>
28 #include <xercesc/util/OutOfMemoryException.hpp>
29
30 #include <xercesc/internal/XTemplateSerializer.hpp>
31
32 XERCES_CPP_NAMESPACE_BEGIN
33
34 static const unsigned int BUF_LEN = 64;
35
36 // ---------------------------------------------------------------------------
37 // Constructors and Destructor
38 // ---------------------------------------------------------------------------
UnionDatatypeValidator(MemoryManager * const manager)39 UnionDatatypeValidator::UnionDatatypeValidator(MemoryManager* const manager)
40 :DatatypeValidator(0, 0, 0, DatatypeValidator::Union, manager)
41 ,fEnumerationInherited(false)
42 ,fMemberTypesInherited(false)
43 ,fEnumeration(0)
44 ,fMemberTypeValidators(0)
45
46 {}
47
~UnionDatatypeValidator()48 UnionDatatypeValidator::~UnionDatatypeValidator()
49 {
50 cleanUp();
51 }
52
UnionDatatypeValidator(RefVectorOf<DatatypeValidator> * const memberTypeValidators,const int finalSet,MemoryManager * const manager)53 UnionDatatypeValidator::UnionDatatypeValidator(
54 RefVectorOf<DatatypeValidator>* const memberTypeValidators
55 , const int finalSet
56 , MemoryManager* const manager)
57 :DatatypeValidator(0, 0, finalSet, DatatypeValidator::Union, manager)
58 ,fEnumerationInherited(false)
59 ,fMemberTypesInherited(false)
60 ,fEnumeration(0)
61 ,fMemberTypeValidators(0)
62 {
63 if ( !memberTypeValidators )
64 {
65 ThrowXMLwithMemMgr(InvalidDatatypeFacetException
66 , XMLExcepts::FACET_Union_Null_memberTypeValidators, manager);
67 }
68
69 // no pattern, no enumeration
70 fMemberTypeValidators = memberTypeValidators;
71 }
72
73 typedef JanitorMemFunCall<UnionDatatypeValidator> CleanupType;
74
UnionDatatypeValidator(DatatypeValidator * const baseValidator,RefHashTableOf<KVStringPair> * const facets,RefArrayVectorOf<XMLCh> * const enums,const int finalSet,MemoryManager * const manager,RefVectorOf<DatatypeValidator> * const memberTypeValidators,const bool memberTypesInherited)75 UnionDatatypeValidator::UnionDatatypeValidator(
76 DatatypeValidator* const baseValidator
77 , RefHashTableOf<KVStringPair>* const facets
78 , RefArrayVectorOf<XMLCh>* const enums
79 , const int finalSet
80 , MemoryManager* const manager
81 , RefVectorOf<DatatypeValidator>* const memberTypeValidators
82 , const bool memberTypesInherited
83 )
84 :DatatypeValidator(baseValidator, facets, finalSet, DatatypeValidator::Union, manager)
85 ,fEnumerationInherited(false)
86 ,fMemberTypesInherited(memberTypesInherited)
87 ,fEnumeration(0)
88 ,fMemberTypeValidators(memberTypeValidators)
89 {
90 //
91 // baseValidator another UnionDTV from which,
92 // this UnionDTV is derived by restriction.
93 // it shall be not null
94 //
95 if (!baseValidator)
96 {
97 ThrowXMLwithMemMgr(InvalidDatatypeFacetException
98 , XMLExcepts::FACET_Union_Null_baseValidator, manager);
99 }
100
101 if (baseValidator->getType() != DatatypeValidator::Union)
102 {
103 XMLCh value1[BUF_LEN+1];
104 XMLString::binToText(baseValidator->getType(), value1, BUF_LEN, 10, manager);
105 ThrowXMLwithMemMgr1(InvalidDatatypeFacetException
106 , XMLExcepts::FACET_Union_invalid_baseValidatorType
107 , value1
108 , manager);
109 }
110
111 CleanupType cleanup(this, &UnionDatatypeValidator::cleanUp);
112
113 try
114 {
115 init(baseValidator, facets, enums, manager);
116 }
117 catch(const OutOfMemoryException&)
118 {
119 // Don't cleanup when out of memory, since executing the
120 // code can cause problems.
121 cleanup.release();
122
123 throw;
124 }
125
126 cleanup.release();
127 }
128
init(DatatypeValidator * const baseValidator,RefHashTableOf<KVStringPair> * const facets,RefArrayVectorOf<XMLCh> * const enums,MemoryManager * const manager)129 void UnionDatatypeValidator::init(DatatypeValidator* const baseValidator
130 , RefHashTableOf<KVStringPair>* const facets
131 , RefArrayVectorOf<XMLCh>* const enums
132 , MemoryManager* const manager)
133 {
134 if (enums)
135 setEnumeration(enums, false);
136
137 // Set Facets if any defined
138 if (facets)
139 {
140 XMLCh* key;
141 XMLCh* value;
142 RefHashTableOfEnumerator<KVStringPair> e(facets, false, manager);
143
144 while (e.hasMoreElements())
145 {
146 KVStringPair pair = e.nextElement();
147 key = pair.getKey();
148 value = pair.getValue();
149
150 if (XMLString::equals(key, SchemaSymbols::fgELT_PATTERN))
151 {
152 setPattern(value);
153 if (getPattern())
154 setFacetsDefined(DatatypeValidator::FACET_PATTERN);
155 // do not construct regex until needed
156 }
157 else
158 {
159 ThrowXMLwithMemMgr1(InvalidDatatypeFacetException
160 , XMLExcepts::FACET_Invalid_Tag
161 , key
162 , manager);
163 }
164 }//while
165
166 /***
167 Schema constraint: Part I -- self checking
168 ***/
169 // Nil
170
171 /***
172 Schema constraint: Part II base vs derived checking
173 ***/
174 // check 4.3.5.c0 must: enumeration values from the value space of base
175 if ( ((getFacetsDefined() & DatatypeValidator::FACET_ENUMERATION) != 0) &&
176 (getEnumeration() !=0))
177 {
178 XMLSize_t i = 0;
179 XMLSize_t enumLength = getEnumeration()->size();
180 try
181 {
182 for ( ; i < enumLength; i++)
183 {
184 // ask parent do a complete check
185 //
186 // enum need NOT be passed this->checkContent()
187 // since there are no other facets for Union, parent
188 // checking is good enough.
189 //
190 baseValidator->validate(getEnumeration()->elementAt(i), (ValidationContext*)0, manager);
191
192 }
193 }
194
195 catch ( XMLException& )
196 {
197 ThrowXMLwithMemMgr1(InvalidDatatypeFacetException
198 , XMLExcepts::FACET_enum_base
199 , getEnumeration()->elementAt(i)
200 , manager);
201 }
202 }
203
204 }// End of Facet setting
205
206 /***
207 Inherit facets from base.facets
208
209 The reason of this inheriting (or copying values) is to ease
210 schema constraint checking, so that we need NOT trace back to our
211 very first base validator in the hierachy. Instead, we are pretty
212 sure checking against immediate base validator is enough.
213 ***/
214
215 UnionDatatypeValidator *pBaseValidator = (UnionDatatypeValidator*) baseValidator;
216
217 // inherit enumeration
218 if (((pBaseValidator->getFacetsDefined() & DatatypeValidator::FACET_ENUMERATION) !=0) &&
219 ((getFacetsDefined() & DatatypeValidator::FACET_ENUMERATION) == 0))
220 {
221 setEnumeration(pBaseValidator->getEnumeration(), true);
222 }
223
224 }
225
226 //
227 // 1) the bottom level UnionDTV would check against
228 // pattern and enumeration as well
229 // 2) each UnionDTV(s) above the bottom level UnionDTV and
230 // below the native UnionDTV (the top level DTV)
231 // would check against pattern only.
232 // 3) the natvie Union DTV (the top level DTV) would invoke
233 // memberTypeValidator to validate
234 //
checkContent(const XMLCh * const content,ValidationContext * const context,bool asBase,MemoryManager * const manager)235 void UnionDatatypeValidator::checkContent(const XMLCh* const content
236 , ValidationContext* const context
237 , bool asBase
238 , MemoryManager* const manager)
239 {
240
241 DatatypeValidator* bv = getBaseValidator();
242 if (bv)
243 ((UnionDatatypeValidator*)bv)->checkContent(content, context, true, manager);
244 else
245 { // 3) native union type
246 // check content against each member type validator in Union
247 // report an error only in case content is not valid against all member datatypes.
248 //
249 bool memTypeValid = false;
250 for ( unsigned int i = 0; i < fMemberTypeValidators->size(); ++i )
251 {
252 if ( memTypeValid )
253 break;
254
255 try
256 {
257 fMemberTypeValidators->elementAt(i)->validate(content, context, manager);
258 memTypeValid = true;
259
260 //set the validator of the type actually used to validate the content
261 DatatypeValidator *dtv = fMemberTypeValidators->elementAt(i);
262 // context will be null during schema construction
263 if(context)
264 context->setValidatingMemberType(dtv);
265 }
266 catch (XMLException&)
267 {
268 //absorbed
269 }
270 } // for
271
272 if ( !memTypeValid )
273 {
274 ThrowXMLwithMemMgr1(InvalidDatatypeValueException
275 , XMLExcepts::VALUE_no_match_memberType
276 , content
277 , manager);
278 //( "Content '"+content+"' does not match any union types" );
279 }
280 }
281
282 // 1) and 2). we check pattern first
283 if ( (getFacetsDefined() & DatatypeValidator::FACET_PATTERN ) != 0 )
284 {
285 if (getRegex()->matches(content, manager) == false)
286 {
287 ThrowXMLwithMemMgr2(InvalidDatatypeValueException
288 , XMLExcepts::VALUE_NotMatch_Pattern
289 , content
290 , getPattern()
291 , manager);
292 }
293 }
294
295 // if this is a base validator, we only need to check pattern facet
296 // all other facet were inherited by the derived type
297 if (asBase)
298 return;
299
300 if ((getFacetsDefined() & DatatypeValidator::FACET_ENUMERATION) != 0 &&
301 (getEnumeration() != 0))
302 {
303
304 // If the content match (compare equal) any enumeration with
305 // any of the member types, it is considerd valid.
306 //
307 RefVectorOf<DatatypeValidator>* memberDTV = getMemberTypeValidators();
308 RefArrayVectorOf<XMLCh>* tmpEnum = getEnumeration();
309 XMLSize_t memberTypeNumber = memberDTV->size();
310 XMLSize_t enumLength = tmpEnum->size();
311
312 for ( XMLSize_t memberIndex = 0; memberIndex < memberTypeNumber; ++memberIndex)
313 {
314 for ( XMLSize_t enumIndex = 0; enumIndex < enumLength; ++enumIndex)
315 {
316 try
317 {
318 if (memberDTV->elementAt(memberIndex)->compare(content, tmpEnum->elementAt(enumIndex), manager) == 0)
319 return;
320 }
321 catch (XMLException&)
322 {
323 //absorbed
324 }
325 } // for enumIndex
326 } // for memberIndex
327
328 ThrowXMLwithMemMgr1(InvalidDatatypeValueException, XMLExcepts::VALUE_NotIn_Enumeration, content, manager);
329
330 } // enumeration
331
332 }
333
334 //
335 //
336 //
compare(const XMLCh * const lValue,const XMLCh * const rValue,MemoryManager * const manager)337 int UnionDatatypeValidator::compare(const XMLCh* const lValue
338 , const XMLCh* const rValue
339 , MemoryManager* const manager)
340 {
341 RefVectorOf<DatatypeValidator>* memberDTV = getMemberTypeValidators();
342 XMLSize_t memberTypeNumber = memberDTV->size();
343
344 for ( XMLSize_t memberIndex = 0; memberIndex < memberTypeNumber; ++memberIndex)
345 {
346 // 'compare' can throw exceptions when the datatype is not valid, or just
347 // return -1; so attempt to validate both values to get the right validator
348 try
349 {
350 memberDTV->elementAt(memberIndex)->validate(lValue, 0, manager);
351 memberDTV->elementAt(memberIndex)->validate(rValue, 0, manager);
352 if (memberDTV->elementAt(memberIndex)->compare(lValue, rValue, manager) ==0)
353 return 0;
354 }
355 catch (XMLException&)
356 {
357 //absorbed
358 }
359 }
360
361 //REVISIT: what does it mean for UNION1 to be <less than> or <greater than> UNION2 ?
362 // As long as -1 or +1 indicates an unequality, return either of them is ok.
363 return -1;
364 }
365
getEnumString() const366 const RefArrayVectorOf<XMLCh>* UnionDatatypeValidator::getEnumString() const
367 {
368 return getEnumeration();
369 }
370
371 /***
372 * 2.5.1.3 Union datatypes
373 *
374 * The canonical-lexical-representation for a union datatype is defined as the lexical form
375 * in which the values have the canonical lexical representation of the appropriate memberTypes.
376 ***/
getCanonicalRepresentation(const XMLCh * const rawData,MemoryManager * const memMgr,bool toValidate) const377 const XMLCh* UnionDatatypeValidator::getCanonicalRepresentation(const XMLCh* const rawData
378 , MemoryManager* const memMgr
379 , bool toValidate) const
380 {
381 MemoryManager* toUse = memMgr? memMgr : getMemoryManager();
382 UnionDatatypeValidator* temp = (UnionDatatypeValidator*) this;
383
384 if (toValidate)
385 {
386 try
387 {
388 temp->checkContent(rawData, 0, false, toUse);
389 }
390 catch (...)
391 {
392 return 0;
393 }
394 }
395
396 //get the native unionDv
397 UnionDatatypeValidator* bdv = (UnionDatatypeValidator*) temp->getBaseValidator();
398 while (bdv)
399 {
400 temp = bdv;
401 bdv = (UnionDatatypeValidator*) temp->getBaseValidator();
402 }
403
404 //let the member dv which recognize the rawData, to return
405 //us the canonical form
406 for ( unsigned int i = 0; i < temp->fMemberTypeValidators->size(); ++i )
407 {
408 try
409 {
410 temp->fMemberTypeValidators->elementAt(i)->validate(rawData, 0, toUse);
411 return temp->fMemberTypeValidators->elementAt(i)->getCanonicalRepresentation(rawData, toUse, false);
412 }
413 catch (XMLException&)
414 {
415 //absorbed
416 }
417 }
418
419 //if no member dv recognize it
420 return 0;
421 }
422
423
424 /***
425 * Support for Serialization/De-serialization
426 ***/
427
IMPL_XSERIALIZABLE_TOCREATE(UnionDatatypeValidator)428 IMPL_XSERIALIZABLE_TOCREATE(UnionDatatypeValidator)
429
430 void UnionDatatypeValidator::serialize(XSerializeEngine& serEng)
431 {
432
433 DatatypeValidator::serialize(serEng);
434
435 if (serEng.isStoring())
436 {
437 serEng<<fEnumerationInherited;
438 serEng<<fMemberTypesInherited;
439
440 /***
441 * Serialize RefArrayVectorOf<XMLCh>
442 * Serialize RefVectorOf<DatatypeValidator>
443 ***/
444 XTemplateSerializer::storeObject(fEnumeration, serEng);
445 XTemplateSerializer::storeObject(fMemberTypeValidators, serEng);
446 }
447 else
448 {
449 serEng>>fEnumerationInherited;
450 serEng>>fMemberTypesInherited;
451
452 /***
453 * Deserialize RefArrayVectorOf<XMLCh>
454 * Deserialize RefVectorOf<DatatypeValidator>
455 ***/
456 XTemplateSerializer::loadObject(&fEnumeration, 8, true, serEng);
457 XTemplateSerializer::loadObject(&fMemberTypeValidators, 4, false, serEng);
458 }
459 }
460
461 XERCES_CPP_NAMESPACE_END
462
463 /**
464 * End of file UnionDatatypeValidator.cpp
465 */
466