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