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: ListDatatypeValidator.cpp 695949 2008-09-16 15:57:44Z borisk $
20  */
21 
22 // ---------------------------------------------------------------------------
23 //  Includes
24 // ---------------------------------------------------------------------------
25 #include <xercesc/validators/datatype/ListDatatypeValidator.hpp>
26 #include <xercesc/validators/datatype/InvalidDatatypeFacetException.hpp>
27 #include <xercesc/validators/datatype/InvalidDatatypeValueException.hpp>
28 #include <xercesc/util/OutOfMemoryException.hpp>
29 
30 XERCES_CPP_NAMESPACE_BEGIN
31 
32 static const int BUF_LEN = 64;
33 
34 // ---------------------------------------------------------------------------
35 //  Constructors and Destructor
36 // ---------------------------------------------------------------------------
ListDatatypeValidator(MemoryManager * const manager)37 ListDatatypeValidator::ListDatatypeValidator(MemoryManager* const manager)
38 :AbstractStringValidator(0, 0, 0, DatatypeValidator::List, manager)
39 ,fContent(0)
40 {}
41 
ListDatatypeValidator(DatatypeValidator * const baseValidator,RefHashTableOf<KVStringPair> * const facets,RefArrayVectorOf<XMLCh> * const enums,const int finalSet,MemoryManager * const manager)42 ListDatatypeValidator::ListDatatypeValidator(
43                           DatatypeValidator*            const baseValidator
44                         , RefHashTableOf<KVStringPair>* const facets
45                         , RefArrayVectorOf<XMLCh>*           const enums
46                         , const int                           finalSet
47                         , MemoryManager* const manager)
48 :AbstractStringValidator(baseValidator, facets, finalSet, DatatypeValidator::List, manager)
49 ,fContent(0)
50 {
51     //
52     // baseValidator shall either
53     // an atomic DTV which servers as itemType, or
54     // another ListDTV from which, this ListDTV is derived by restriction.
55     //
56     // In either case, it shall be not null
57     //
58     if (!baseValidator)
59         ThrowXMLwithMemMgr(InvalidDatatypeFacetException, XMLExcepts::FACET_List_Null_baseValidator, manager);
60 
61     init(enums, manager);
62 }
63 
~ListDatatypeValidator()64 ListDatatypeValidator::~ListDatatypeValidator()
65 {}
66 
newInstance(RefHashTableOf<KVStringPair> * const facets,RefArrayVectorOf<XMLCh> * const enums,const int finalSet,MemoryManager * const manager)67 DatatypeValidator* ListDatatypeValidator::newInstance
68 (
69       RefHashTableOf<KVStringPair>* const facets
70     , RefArrayVectorOf<XMLCh>* const      enums
71     , const int                           finalSet
72     , MemoryManager* const                manager
73 )
74 {
75     return (DatatypeValidator*) new (manager) ListDatatypeValidator(this, facets, enums, finalSet, manager);
76 }
77 
78 
compare(const XMLCh * const lValue,const XMLCh * const rValue,MemoryManager * const manager)79 int ListDatatypeValidator::compare(const XMLCh*     const lValue
80                                  , const XMLCh*     const rValue
81                                  , MemoryManager*   const manager)
82 {
83     DatatypeValidator* theItemTypeDTV = getItemTypeDTV();
84     BaseRefVectorOf<XMLCh>* lVector = XMLString::tokenizeString(lValue, manager);
85     Janitor<BaseRefVectorOf<XMLCh> > janl(lVector);
86     BaseRefVectorOf<XMLCh>* rVector = XMLString::tokenizeString(rValue, manager);
87     Janitor<BaseRefVectorOf<XMLCh> > janr(rVector);
88 
89     XMLSize_t lNumberOfTokens = lVector->size();
90     XMLSize_t rNumberOfTokens = rVector->size();
91 
92     if (lNumberOfTokens < rNumberOfTokens)
93         return -1;
94     else if (lNumberOfTokens > rNumberOfTokens)
95         return 1;
96     else
97     { //compare each token
98         for ( XMLSize_t i = 0; i < lNumberOfTokens; i++)
99         {
100             int returnValue = theItemTypeDTV->compare(lVector->elementAt(i), rVector->elementAt(i), manager);
101             if (returnValue != 0)
102                 return returnValue; //REVISIT: does it make sense to return -1 or +1..?
103         }
104         return 0;
105     }
106 
107 }
108 
validate(const XMLCh * const content,ValidationContext * const context,MemoryManager * const manager)109 void ListDatatypeValidator::validate( const XMLCh*             const content
110                                     ,       ValidationContext* const context
111                                     ,       MemoryManager*     const manager)
112 {
113     setContent(content);
114     BaseRefVectorOf<XMLCh>* tokenVector = XMLString::tokenizeString(content, manager);
115     Janitor<BaseRefVectorOf<XMLCh> > janName(tokenVector);
116     checkContent(tokenVector, content, context, false, manager);
117 }
118 
checkContent(const XMLCh * const content,ValidationContext * const context,bool asBase,MemoryManager * const manager)119 void ListDatatypeValidator::checkContent( const XMLCh*             const content
120                                          ,      ValidationContext* const context
121                                          ,      bool                     asBase
122                                          ,      MemoryManager*     const manager)
123 {
124     setContent(content);
125     BaseRefVectorOf<XMLCh>* tokenVector = XMLString::tokenizeString(content, manager);
126     Janitor<BaseRefVectorOf<XMLCh> > janName(tokenVector);
127     checkContent(tokenVector, content, context, asBase, manager);
128 }
129 
130 //
131 // here content is a list of items
132 //
checkContent(BaseRefVectorOf<XMLCh> * tokenVector,const XMLCh * const content,ValidationContext * const context,bool asBase,MemoryManager * const manager)133 void ListDatatypeValidator::checkContent(       BaseRefVectorOf<XMLCh>*       tokenVector
134                                         , const XMLCh*                  const content
135                                         ,       ValidationContext*      const context
136                                         ,       bool                          asBase
137                                         ,       MemoryManager*          const manager)
138 {
139     DatatypeValidator* bv = getBaseValidator();
140 
141     if (bv->getType() == DatatypeValidator::List)
142         ((ListDatatypeValidator*)bv)->checkContent(tokenVector, content, context, true, manager);
143     else
144     {   // the ultimate itemType DTV
145         for (unsigned int i = 0; i < tokenVector->size(); i++)
146             bv->validate(tokenVector->elementAt(i), context, manager);
147     }
148 
149     int thisFacetsDefined = getFacetsDefined();
150 
151     // we check pattern first
152     if ( (thisFacetsDefined & DatatypeValidator::FACET_PATTERN ) != 0 )
153     {
154         //check every item in the list as a whole
155         if (getRegex()->matches(content, manager) == false)
156         {
157             ThrowXMLwithMemMgr2(InvalidDatatypeValueException
158                     , XMLExcepts::VALUE_NotMatch_Pattern
159                     , content
160                     , getPattern()
161                     , manager);
162         }
163 
164     }
165 
166     // if this is a base validator, we only need to check pattern facet
167     // all other facet were inherited by the derived type
168     if (asBase)
169         return;
170 
171     XMLSize_t tokenNumber = tokenVector->size();
172 
173     if (((thisFacetsDefined & DatatypeValidator::FACET_MAXLENGTH) != 0) &&
174         (tokenNumber > getMaxLength()))
175     {
176         XMLCh value1[BUF_LEN+1];
177         XMLCh value2[BUF_LEN+1];
178         XMLString::sizeToText(tokenNumber, value1, BUF_LEN, 10, manager);
179         XMLString::sizeToText(getMaxLength(), value2, BUF_LEN, 10, manager);
180 
181         ThrowXMLwithMemMgr3(InvalidDatatypeValueException
182                 , XMLExcepts::VALUE_GT_maxLen
183                 , getContent()
184                 , value1
185                 , value2
186                 , manager);
187     }
188 
189     if (((thisFacetsDefined & DatatypeValidator::FACET_MINLENGTH) != 0) &&
190         (tokenNumber < getMinLength()))
191     {
192         XMLCh value1[BUF_LEN+1];
193         XMLCh value2[BUF_LEN+1];
194         XMLString::sizeToText(tokenNumber, value1, BUF_LEN, 10, manager);
195         XMLString::sizeToText(getMinLength(), value2, BUF_LEN, 10, manager);
196 
197         ThrowXMLwithMemMgr3(InvalidDatatypeValueException
198                 , XMLExcepts::VALUE_LT_minLen
199                 , getContent()
200                 , value1
201                 , value2
202                 , manager);
203     }
204 
205     if (((thisFacetsDefined & DatatypeValidator::FACET_LENGTH) != 0) &&
206         (tokenNumber != AbstractStringValidator::getLength()))
207     {
208         XMLCh value1[BUF_LEN+1];
209         XMLCh value2[BUF_LEN+1];
210         XMLString::sizeToText(tokenNumber, value1, BUF_LEN, 10, manager);
211         XMLString::sizeToText(AbstractStringValidator::getLength(), value2, BUF_LEN, 10, manager);
212 
213         ThrowXMLwithMemMgr3(InvalidDatatypeValueException
214                 , XMLExcepts::VALUE_NE_Len
215                 , getContent()
216                 , value1
217                 , value2
218                 , manager);
219     }
220 
221     if ((thisFacetsDefined & DatatypeValidator::FACET_ENUMERATION) != 0 &&
222         (getEnumeration() != 0))
223     {
224         XMLSize_t i;
225         XMLSize_t enumLength = getEnumeration()->size();
226 
227         for ( i = 0; i < enumLength; i++)
228         {
229             //optimization: we do a lexical comparision first
230             // this may be faster for string and its derived
231             if (XMLString::equals(getEnumeration()->elementAt(i), getContent()))
232                 break; // a match found
233 
234             // do a value space check
235             // this is needed for decimal (and probably other types
236             // such as datetime related)
237             // eg.
238             // tokenVector = "1 2 3.0 4" vs enumeration = "1 2 3 4.0"
239             //
240             if (valueSpaceCheck(tokenVector, getEnumeration()->elementAt(i), manager))
241                 break;
242         }
243 
244         if (i == enumLength)
245             ThrowXMLwithMemMgr1(InvalidDatatypeValueException, XMLExcepts::VALUE_NotIn_Enumeration, getContent(), manager);
246 
247     } // enumeration
248 
249 }
250 
valueSpaceCheck(BaseRefVectorOf<XMLCh> * tokenVector,const XMLCh * const enumStr,MemoryManager * const manager) const251 bool ListDatatypeValidator::valueSpaceCheck(BaseRefVectorOf<XMLCh>* tokenVector
252                                           , const XMLCh*    const  enumStr
253                                           , MemoryManager*  const  manager) const
254 {
255     DatatypeValidator* theItemTypeDTV = getItemTypeDTV();
256     BaseRefVectorOf<XMLCh>* enumVector = XMLString::tokenizeString(enumStr, manager);
257     Janitor<BaseRefVectorOf<XMLCh> > janName(enumVector);
258 
259     if (tokenVector->size() != enumVector->size())
260         return false;
261 
262     for ( unsigned int j = 0; j < tokenVector->size(); j++ )
263     {
264         if (theItemTypeDTV->compare(tokenVector->elementAt(j), enumVector->elementAt(j), manager) != 0)
265             return false;
266     }
267 
268     return true;
269 }
270 
getItemTypeDTV() const271 DatatypeValidator* ListDatatypeValidator::getItemTypeDTV() const
272 {
273     DatatypeValidator* bdv = this->getBaseValidator();
274 
275     while (bdv->getType() == DatatypeValidator::List)
276         bdv = bdv->getBaseValidator();
277 
278     return bdv;
279 }
280 
281 // ---------------------------------------------------------------------------
282 //  Utilities
283 // ---------------------------------------------------------------------------
284 
checkValueSpace(const XMLCh * const,MemoryManager * const)285 void ListDatatypeValidator::checkValueSpace(const XMLCh* const
286                                             , MemoryManager* const)
287 {}
288 
getLength(const XMLCh * const content,MemoryManager * const manager) const289 XMLSize_t ListDatatypeValidator::getLength(const XMLCh* const content
290                                      , MemoryManager* const manager) const
291 {
292     BaseRefVectorOf<XMLCh>* tokenVector = XMLString::tokenizeString(content, manager);
293     Janitor<BaseRefVectorOf<XMLCh> > janName(tokenVector);
294 
295     return tokenVector->size();
296 }
297 
inspectFacetBase(MemoryManager * const manager)298 void ListDatatypeValidator::inspectFacetBase(MemoryManager* const manager)
299 {
300 
301     //
302     // we are pretty sure baseValidator is not null
303     //
304 
305     if (getBaseValidator()->getType() == DatatypeValidator::List)
306     {
307         AbstractStringValidator::inspectFacetBase(manager);
308     }
309     else
310     {
311         // the first level ListDTV
312         // check 4.3.5.c0 must: enumeration values from the value space of base
313         if ( ((getFacetsDefined() & DatatypeValidator::FACET_ENUMERATION) != 0) &&
314              (getEnumeration() !=0)                                              )
315         {
316             XMLSize_t i;
317             XMLSize_t enumLength = getEnumeration()->size();
318             try
319             {
320                 for ( i = 0; i < enumLength; i++)
321                 {
322                     // ask the itemType for a complete check
323                     BaseRefVectorOf<XMLCh>* tempList = XMLString::tokenizeString(getEnumeration()->elementAt(i), manager);
324                     Janitor<BaseRefVectorOf<XMLCh> >    jan(tempList);
325                     XMLSize_t tokenNumber = tempList->size();
326 
327                     try
328                     {
329                         for ( XMLSize_t j = 0; j < tokenNumber; j++)
330                             getBaseValidator()->validate(tempList->elementAt(j), (ValidationContext*)0, manager);
331                     }
332                     catch(const OutOfMemoryException&)
333                     {
334                         jan.release();
335 
336                         throw;
337                     }
338 #if 0
339 // spec says that only base has to checkContent
340                     // enum shall pass this->checkContent() as well.
341                     checkContent(getEnumeration()->elementAt(i), (ValidationContext*)0, false, manager);
342 #endif
343                 }
344             }
345 
346             catch ( XMLException& )
347             {
348                 ThrowXMLwithMemMgr1(InvalidDatatypeFacetException
349                         , XMLExcepts::FACET_enum_base
350                         , getEnumeration()->elementAt(i)
351                         , manager);
352             }
353 
354         }
355 
356     }
357 
358 }// End of inspectFacetBase()
359 
inheritFacet()360 void ListDatatypeValidator::inheritFacet()
361 {
362 
363     //iff the base validator is List, then we inherit
364     //
365     if (getBaseValidator()->getType() == DatatypeValidator::List)
366     {
367         AbstractStringValidator::inheritFacet();
368     }
369 
370 }
371 
372 /***
373  * 2.5.1.2 List datatypes
374  *
375  * The canonical-lexical-representation for the list datatype is defined as
376  * the lexical form in which each item in the list has the canonical
377  * lexical representation of its itemType.
378  ***/
getCanonicalRepresentation(const XMLCh * const rawData,MemoryManager * const memMgr,bool toValidate) const379 const XMLCh* ListDatatypeValidator::getCanonicalRepresentation(const XMLCh*         const rawData
380                                                              ,       MemoryManager* const memMgr
381                                                              ,       bool                 toValidate) const
382 {
383     MemoryManager* toUse = memMgr? memMgr : getMemoryManager();
384     ListDatatypeValidator* temp = (ListDatatypeValidator*) this;
385     temp->setContent(rawData);
386     BaseRefVectorOf<XMLCh>* tokenVector = XMLString::tokenizeString(rawData, toUse);
387     Janitor<BaseRefVectorOf<XMLCh> > janName(tokenVector);
388 
389     if (toValidate)
390     {
391         try
392         {
393             temp->checkContent(tokenVector, rawData, 0, false, toUse);
394         }
395         catch (...)
396         {
397             return 0;
398         }
399     }
400 
401     XMLSize_t retBufSize = 2 * XMLString::stringLen(rawData);
402     XMLCh* retBuf = (XMLCh*) toUse->allocate(retBufSize * sizeof(XMLCh));
403     retBuf[0] = 0;
404     XMLCh* retBufPtr = retBuf;
405     DatatypeValidator* itemDv = this->getItemTypeDTV();
406 
407     try
408     {
409         for (unsigned int i = 0; i < tokenVector->size(); i++)
410         {
411             XMLCh* itemCanRep = (XMLCh*) itemDv->getCanonicalRepresentation(tokenVector->elementAt(i), toUse, false);
412             XMLSize_t itemLen = XMLString::stringLen(itemCanRep);
413 
414             if(retBufPtr+itemLen+2 >= retBuf+retBufSize)
415             {
416                 // need to resize
417                 XMLCh * oldBuf = retBuf;
418                 retBuf = (XMLCh*) toUse->allocate(retBufSize * sizeof(XMLCh) * 4);
419                 memcpy(retBuf, oldBuf, retBufSize * sizeof(XMLCh ));
420                 retBufPtr = (retBufPtr - oldBuf) + retBuf;
421                 toUse->deallocate(oldBuf);
422                 retBufSize <<= 2;
423             }
424 
425             XMLString::catString(retBufPtr, itemCanRep);
426             retBufPtr = retBufPtr + itemLen;
427             *(retBufPtr++) = chSpace;
428             *(retBufPtr) = chNull;
429             toUse->deallocate(itemCanRep);
430         }
431 
432         return retBuf;
433 
434     }
435     catch (...)
436     {
437         return 0;
438     }
439 }
440 
441 /***
442  * Support for Serialization/De-serialization
443  ***/
444 
IMPL_XSERIALIZABLE_TOCREATE(ListDatatypeValidator)445 IMPL_XSERIALIZABLE_TOCREATE(ListDatatypeValidator)
446 
447 void ListDatatypeValidator::serialize(XSerializeEngine& serEng)
448 {
449     AbstractStringValidator::serialize(serEng);
450 
451     //don't serialize fContent, since it is NOT owned and
452     //will be reset each time validate()/checkContent() invoked.
453 }
454 
455 XERCES_CPP_NAMESPACE_END
456 
457 /**
458   * End of file ListDatatypeValidator.cpp
459   */
460