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