1 | /* |
2 | * schemastypes.c : implementation of the XML Schema Datatypes |
3 | * definition and validity checking |
4 | * |
5 | * See Copyright for the status of this software. |
6 | * |
7 | * Daniel Veillard <veillard@redhat.com> |
8 | */ |
9 | |
10 | /* To avoid EBCDIC trouble when parsing on zOS */ |
11 | #if defined(__MVS__) |
12 | #pragma convert("ISO8859-1") |
13 | #endif |
14 | |
15 | #define IN_LIBXML |
16 | #include "libxml.h" |
17 | |
18 | #ifdef LIBXML_SCHEMAS_ENABLED |
19 | |
20 | #include <string.h> |
21 | #include <libxml/xmlmemory.h> |
22 | #include <libxml/parser.h> |
23 | #include <libxml/parserInternals.h> |
24 | #include <libxml/hash.h> |
25 | #include <libxml/valid.h> |
26 | #include <libxml/xpath.h> |
27 | #include <libxml/uri.h> |
28 | |
29 | #include <libxml/xmlschemas.h> |
30 | #include <libxml/schemasInternals.h> |
31 | #include <libxml/xmlschemastypes.h> |
32 | |
33 | #ifdef HAVE_MATH_H |
34 | #include <math.h> |
35 | #endif |
36 | #ifdef HAVE_FLOAT_H |
37 | #include <float.h> |
38 | #endif |
39 | |
40 | #define DEBUG |
41 | |
42 | #ifndef LIBXML_XPATH_ENABLED |
43 | extern double xmlXPathNAN; |
44 | extern double xmlXPathPINF; |
45 | extern double xmlXPathNINF; |
46 | #endif |
47 | |
48 | #define TODO \ |
49 | xmlGenericError(xmlGenericErrorContext, \ |
50 | "Unimplemented block at %s:%d\n", \ |
51 | __FILE__, __LINE__); |
52 | |
53 | #define XML_SCHEMAS_NAMESPACE_NAME \ |
54 | (const xmlChar *)"http://www.w3.org/2001/XMLSchema" |
55 | |
56 | #define IS_WSP_REPLACE_CH(c) ((((c) == 0x9) || ((c) == 0xa)) || \ |
57 | ((c) == 0xd)) |
58 | |
59 | #define IS_WSP_SPACE_CH(c) ((c) == 0x20) |
60 | |
61 | #define IS_WSP_BLANK_CH(c) IS_BLANK_CH(c) |
62 | |
63 | /* Date value */ |
64 | typedef struct _xmlSchemaValDate xmlSchemaValDate; |
65 | typedef xmlSchemaValDate *xmlSchemaValDatePtr; |
66 | struct _xmlSchemaValDate { |
67 | long year; |
68 | unsigned int mon :4; /* 1 <= mon <= 12 */ |
69 | unsigned int day :5; /* 1 <= day <= 31 */ |
70 | unsigned int hour :5; /* 0 <= hour <= 24 */ |
71 | unsigned int min :6; /* 0 <= min <= 59 */ |
72 | double sec; |
73 | unsigned int tz_flag :1; /* is tzo explicitely set? */ |
74 | signed int tzo :12; /* -1440 <= tzo <= 1440; |
75 | currently only -840 to +840 are needed */ |
76 | }; |
77 | |
78 | /* Duration value */ |
79 | typedef struct _xmlSchemaValDuration xmlSchemaValDuration; |
80 | typedef xmlSchemaValDuration *xmlSchemaValDurationPtr; |
81 | struct _xmlSchemaValDuration { |
82 | long mon; /* mon stores years also */ |
83 | long day; |
84 | double sec; /* sec stores min and hour also */ |
85 | }; |
86 | |
87 | typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal; |
88 | typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr; |
89 | struct _xmlSchemaValDecimal { |
90 | /* would use long long but not portable */ |
91 | unsigned long lo; |
92 | unsigned long mi; |
93 | unsigned long hi; |
94 | unsigned int ; |
95 | unsigned int sign:1; |
96 | unsigned int frac:7; |
97 | unsigned int total:8; |
98 | }; |
99 | |
100 | typedef struct _xmlSchemaValQName xmlSchemaValQName; |
101 | typedef xmlSchemaValQName *xmlSchemaValQNamePtr; |
102 | struct _xmlSchemaValQName { |
103 | xmlChar *name; |
104 | xmlChar *uri; |
105 | }; |
106 | |
107 | typedef struct _xmlSchemaValHex xmlSchemaValHex; |
108 | typedef xmlSchemaValHex *xmlSchemaValHexPtr; |
109 | struct _xmlSchemaValHex { |
110 | xmlChar *str; |
111 | unsigned int total; |
112 | }; |
113 | |
114 | typedef struct _xmlSchemaValBase64 xmlSchemaValBase64; |
115 | typedef xmlSchemaValBase64 *xmlSchemaValBase64Ptr; |
116 | struct _xmlSchemaValBase64 { |
117 | xmlChar *str; |
118 | unsigned int total; |
119 | }; |
120 | |
121 | struct _xmlSchemaVal { |
122 | xmlSchemaValType type; |
123 | struct _xmlSchemaVal *next; |
124 | union { |
125 | xmlSchemaValDecimal decimal; |
126 | xmlSchemaValDate date; |
127 | xmlSchemaValDuration dur; |
128 | xmlSchemaValQName qname; |
129 | xmlSchemaValHex hex; |
130 | xmlSchemaValBase64 base64; |
131 | float f; |
132 | double d; |
133 | int b; |
134 | xmlChar *str; |
135 | } value; |
136 | }; |
137 | |
138 | static int xmlSchemaTypesInitialized = 0; |
139 | static xmlHashTablePtr xmlSchemaTypesBank = NULL; |
140 | |
141 | /* |
142 | * Basic types |
143 | */ |
144 | static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL; |
145 | static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL; |
146 | static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL; |
147 | static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL; |
148 | static xmlSchemaTypePtr xmlSchemaTypeDatetimeDef = NULL; |
149 | static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL; |
150 | static xmlSchemaTypePtr xmlSchemaTypeTimeDef = NULL; |
151 | static xmlSchemaTypePtr xmlSchemaTypeGYearDef = NULL; |
152 | static xmlSchemaTypePtr xmlSchemaTypeGYearMonthDef = NULL; |
153 | static xmlSchemaTypePtr xmlSchemaTypeGDayDef = NULL; |
154 | static xmlSchemaTypePtr xmlSchemaTypeGMonthDayDef = NULL; |
155 | static xmlSchemaTypePtr xmlSchemaTypeGMonthDef = NULL; |
156 | static xmlSchemaTypePtr xmlSchemaTypeDurationDef = NULL; |
157 | static xmlSchemaTypePtr xmlSchemaTypeFloatDef = NULL; |
158 | static xmlSchemaTypePtr xmlSchemaTypeBooleanDef = NULL; |
159 | static xmlSchemaTypePtr xmlSchemaTypeDoubleDef = NULL; |
160 | static xmlSchemaTypePtr xmlSchemaTypeHexBinaryDef = NULL; |
161 | static xmlSchemaTypePtr xmlSchemaTypeBase64BinaryDef = NULL; |
162 | static xmlSchemaTypePtr xmlSchemaTypeAnyURIDef = NULL; |
163 | |
164 | /* |
165 | * Derived types |
166 | */ |
167 | static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL; |
168 | static xmlSchemaTypePtr xmlSchemaTypeNonPositiveIntegerDef = NULL; |
169 | static xmlSchemaTypePtr xmlSchemaTypeNegativeIntegerDef = NULL; |
170 | static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL; |
171 | static xmlSchemaTypePtr xmlSchemaTypeIntegerDef = NULL; |
172 | static xmlSchemaTypePtr xmlSchemaTypeLongDef = NULL; |
173 | static xmlSchemaTypePtr xmlSchemaTypeIntDef = NULL; |
174 | static xmlSchemaTypePtr xmlSchemaTypeShortDef = NULL; |
175 | static xmlSchemaTypePtr xmlSchemaTypeByteDef = NULL; |
176 | static xmlSchemaTypePtr xmlSchemaTypeUnsignedLongDef = NULL; |
177 | static xmlSchemaTypePtr xmlSchemaTypeUnsignedIntDef = NULL; |
178 | static xmlSchemaTypePtr xmlSchemaTypeUnsignedShortDef = NULL; |
179 | static xmlSchemaTypePtr xmlSchemaTypeUnsignedByteDef = NULL; |
180 | static xmlSchemaTypePtr xmlSchemaTypeNormStringDef = NULL; |
181 | static xmlSchemaTypePtr xmlSchemaTypeTokenDef = NULL; |
182 | static xmlSchemaTypePtr xmlSchemaTypeLanguageDef = NULL; |
183 | static xmlSchemaTypePtr xmlSchemaTypeNameDef = NULL; |
184 | static xmlSchemaTypePtr xmlSchemaTypeQNameDef = NULL; |
185 | static xmlSchemaTypePtr xmlSchemaTypeNCNameDef = NULL; |
186 | static xmlSchemaTypePtr xmlSchemaTypeIdDef = NULL; |
187 | static xmlSchemaTypePtr xmlSchemaTypeIdrefDef = NULL; |
188 | static xmlSchemaTypePtr xmlSchemaTypeIdrefsDef = NULL; |
189 | static xmlSchemaTypePtr xmlSchemaTypeEntityDef = NULL; |
190 | static xmlSchemaTypePtr xmlSchemaTypeEntitiesDef = NULL; |
191 | static xmlSchemaTypePtr xmlSchemaTypeNotationDef = NULL; |
192 | static xmlSchemaTypePtr xmlSchemaTypeNmtokenDef = NULL; |
193 | static xmlSchemaTypePtr xmlSchemaTypeNmtokensDef = NULL; |
194 | |
195 | /************************************************************************ |
196 | * * |
197 | * Datatype error handlers * |
198 | * * |
199 | ************************************************************************/ |
200 | /** |
201 | * xmlSchemaTypeErrMemory: |
202 | * @extra: extra informations |
203 | * |
204 | * Handle an out of memory condition |
205 | */ |
206 | static void |
207 | xmlSchemaTypeErrMemory(xmlNodePtr node, const char *) |
208 | { |
209 | __xmlSimpleError(XML_FROM_DATATYPE, XML_ERR_NO_MEMORY, node, NULL, extra); |
210 | } |
211 | |
212 | /************************************************************************ |
213 | * * |
214 | * Base types support * |
215 | * * |
216 | ************************************************************************/ |
217 | |
218 | /** |
219 | * xmlSchemaNewValue: |
220 | * @type: the value type |
221 | * |
222 | * Allocate a new simple type value |
223 | * |
224 | * Returns a pointer to the new value or NULL in case of error |
225 | */ |
226 | static xmlSchemaValPtr |
227 | xmlSchemaNewValue(xmlSchemaValType type) { |
228 | xmlSchemaValPtr value; |
229 | |
230 | value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal)); |
231 | if (value == NULL) { |
232 | return(NULL); |
233 | } |
234 | memset(value, 0, sizeof(xmlSchemaVal)); |
235 | value->type = type; |
236 | return(value); |
237 | } |
238 | |
239 | static xmlSchemaFacetPtr |
240 | xmlSchemaNewMinLengthFacet(int value) |
241 | { |
242 | xmlSchemaFacetPtr ret; |
243 | |
244 | ret = xmlSchemaNewFacet(); |
245 | if (ret == NULL) { |
246 | return(NULL); |
247 | } |
248 | ret->type = XML_SCHEMA_FACET_MINLENGTH; |
249 | ret->val = xmlSchemaNewValue(XML_SCHEMAS_NNINTEGER); |
250 | if (ret->val == NULL) { |
251 | xmlFree(ret); |
252 | return(NULL); |
253 | } |
254 | ret->val->value.decimal.lo = value; |
255 | return (ret); |
256 | } |
257 | |
258 | /* |
259 | * xmlSchemaInitBasicType: |
260 | * @name: the type name |
261 | * @type: the value type associated |
262 | * |
263 | * Initialize one primitive built-in type |
264 | */ |
265 | static xmlSchemaTypePtr |
266 | xmlSchemaInitBasicType(const char *name, xmlSchemaValType type, |
267 | xmlSchemaTypePtr baseType) { |
268 | xmlSchemaTypePtr ret; |
269 | |
270 | ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType)); |
271 | if (ret == NULL) { |
272 | xmlSchemaTypeErrMemory(NULL, "could not initialize basic types" ); |
273 | return(NULL); |
274 | } |
275 | memset(ret, 0, sizeof(xmlSchemaType)); |
276 | ret->name = (const xmlChar *)name; |
277 | ret->targetNamespace = XML_SCHEMAS_NAMESPACE_NAME; |
278 | ret->type = XML_SCHEMA_TYPE_BASIC; |
279 | ret->baseType = baseType; |
280 | ret->contentType = XML_SCHEMA_CONTENT_BASIC; |
281 | /* |
282 | * Primitive types. |
283 | */ |
284 | switch (type) { |
285 | case XML_SCHEMAS_STRING: |
286 | case XML_SCHEMAS_DECIMAL: |
287 | case XML_SCHEMAS_DATE: |
288 | case XML_SCHEMAS_DATETIME: |
289 | case XML_SCHEMAS_TIME: |
290 | case XML_SCHEMAS_GYEAR: |
291 | case XML_SCHEMAS_GYEARMONTH: |
292 | case XML_SCHEMAS_GMONTH: |
293 | case XML_SCHEMAS_GMONTHDAY: |
294 | case XML_SCHEMAS_GDAY: |
295 | case XML_SCHEMAS_DURATION: |
296 | case XML_SCHEMAS_FLOAT: |
297 | case XML_SCHEMAS_DOUBLE: |
298 | case XML_SCHEMAS_BOOLEAN: |
299 | case XML_SCHEMAS_ANYURI: |
300 | case XML_SCHEMAS_HEXBINARY: |
301 | case XML_SCHEMAS_BASE64BINARY: |
302 | case XML_SCHEMAS_QNAME: |
303 | case XML_SCHEMAS_NOTATION: |
304 | ret->flags |= XML_SCHEMAS_TYPE_BUILTIN_PRIMITIVE; |
305 | break; |
306 | default: |
307 | break; |
308 | } |
309 | /* |
310 | * Set variety. |
311 | */ |
312 | switch (type) { |
313 | case XML_SCHEMAS_ANYTYPE: |
314 | case XML_SCHEMAS_ANYSIMPLETYPE: |
315 | break; |
316 | case XML_SCHEMAS_IDREFS: |
317 | case XML_SCHEMAS_NMTOKENS: |
318 | case XML_SCHEMAS_ENTITIES: |
319 | ret->flags |= XML_SCHEMAS_TYPE_VARIETY_LIST; |
320 | ret->facets = xmlSchemaNewMinLengthFacet(1); |
321 | ret->flags |= XML_SCHEMAS_TYPE_HAS_FACETS; |
322 | break; |
323 | default: |
324 | ret->flags |= XML_SCHEMAS_TYPE_VARIETY_ATOMIC; |
325 | break; |
326 | } |
327 | xmlHashAddEntry2(xmlSchemaTypesBank, ret->name, |
328 | XML_SCHEMAS_NAMESPACE_NAME, ret); |
329 | ret->builtInType = type; |
330 | return(ret); |
331 | } |
332 | |
333 | /* |
334 | * WARNING: Those type reside normally in xmlschemas.c but are |
335 | * redefined here locally in oder of being able to use them for xs:anyType- |
336 | * TODO: Remove those definition if we move the types to a header file. |
337 | * TODO: Always keep those structs up-to-date with the originals. |
338 | */ |
339 | #define UNBOUNDED (1 << 30) |
340 | |
341 | typedef struct _xmlSchemaTreeItem xmlSchemaTreeItem; |
342 | typedef xmlSchemaTreeItem *xmlSchemaTreeItemPtr; |
343 | struct _xmlSchemaTreeItem { |
344 | xmlSchemaTypeType type; |
345 | xmlSchemaAnnotPtr annot; |
346 | xmlSchemaTreeItemPtr next; |
347 | xmlSchemaTreeItemPtr children; |
348 | }; |
349 | |
350 | typedef struct _xmlSchemaParticle xmlSchemaParticle; |
351 | typedef xmlSchemaParticle *xmlSchemaParticlePtr; |
352 | struct _xmlSchemaParticle { |
353 | xmlSchemaTypeType type; |
354 | xmlSchemaAnnotPtr annot; |
355 | xmlSchemaTreeItemPtr next; |
356 | xmlSchemaTreeItemPtr children; |
357 | int minOccurs; |
358 | int maxOccurs; |
359 | xmlNodePtr node; |
360 | }; |
361 | |
362 | typedef struct _xmlSchemaModelGroup xmlSchemaModelGroup; |
363 | typedef xmlSchemaModelGroup *xmlSchemaModelGroupPtr; |
364 | struct _xmlSchemaModelGroup { |
365 | xmlSchemaTypeType type; |
366 | xmlSchemaAnnotPtr annot; |
367 | xmlSchemaTreeItemPtr next; |
368 | xmlSchemaTreeItemPtr children; |
369 | xmlNodePtr node; |
370 | }; |
371 | |
372 | static xmlSchemaParticlePtr |
373 | xmlSchemaAddParticle(void) |
374 | { |
375 | xmlSchemaParticlePtr ret = NULL; |
376 | |
377 | ret = (xmlSchemaParticlePtr) |
378 | xmlMalloc(sizeof(xmlSchemaParticle)); |
379 | if (ret == NULL) { |
380 | xmlSchemaTypeErrMemory(NULL, "allocating particle component" ); |
381 | return (NULL); |
382 | } |
383 | memset(ret, 0, sizeof(xmlSchemaParticle)); |
384 | ret->type = XML_SCHEMA_TYPE_PARTICLE; |
385 | ret->minOccurs = 1; |
386 | ret->maxOccurs = 1; |
387 | return (ret); |
388 | } |
389 | |
390 | /* |
391 | * xmlSchemaInitTypes: |
392 | * |
393 | * Initialize the default XML Schemas type library |
394 | */ |
395 | void |
396 | xmlSchemaInitTypes(void) |
397 | { |
398 | if (xmlSchemaTypesInitialized != 0) |
399 | return; |
400 | xmlSchemaTypesBank = xmlHashCreate(40); |
401 | |
402 | |
403 | /* |
404 | * 3.4.7 Built-in Complex Type Definition |
405 | */ |
406 | xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType" , |
407 | XML_SCHEMAS_ANYTYPE, |
408 | NULL); |
409 | xmlSchemaTypeAnyTypeDef->baseType = xmlSchemaTypeAnyTypeDef; |
410 | xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED; |
411 | /* |
412 | * Init the content type. |
413 | */ |
414 | xmlSchemaTypeAnyTypeDef->contentType = XML_SCHEMA_CONTENT_MIXED; |
415 | { |
416 | xmlSchemaParticlePtr particle; |
417 | xmlSchemaModelGroupPtr sequence; |
418 | xmlSchemaWildcardPtr wild; |
419 | /* First particle. */ |
420 | particle = xmlSchemaAddParticle(); |
421 | if (particle == NULL) |
422 | return; |
423 | xmlSchemaTypeAnyTypeDef->subtypes = (xmlSchemaTypePtr) particle; |
424 | /* Sequence model group. */ |
425 | sequence = (xmlSchemaModelGroupPtr) |
426 | xmlMalloc(sizeof(xmlSchemaModelGroup)); |
427 | if (sequence == NULL) { |
428 | xmlSchemaTypeErrMemory(NULL, "allocating model group component" ); |
429 | return; |
430 | } |
431 | memset(sequence, 0, sizeof(xmlSchemaModelGroup)); |
432 | sequence->type = XML_SCHEMA_TYPE_SEQUENCE; |
433 | particle->children = (xmlSchemaTreeItemPtr) sequence; |
434 | /* Second particle. */ |
435 | particle = xmlSchemaAddParticle(); |
436 | if (particle == NULL) |
437 | return; |
438 | particle->minOccurs = 0; |
439 | particle->maxOccurs = UNBOUNDED; |
440 | sequence->children = (xmlSchemaTreeItemPtr) particle; |
441 | /* The wildcard */ |
442 | wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard)); |
443 | if (wild == NULL) { |
444 | xmlSchemaTypeErrMemory(NULL, "allocating wildcard component" ); |
445 | return; |
446 | } |
447 | memset(wild, 0, sizeof(xmlSchemaWildcard)); |
448 | wild->type = XML_SCHEMA_TYPE_ANY; |
449 | wild->any = 1; |
450 | wild->processContents = XML_SCHEMAS_ANY_LAX; |
451 | particle->children = (xmlSchemaTreeItemPtr) wild; |
452 | /* |
453 | * Create the attribute wildcard. |
454 | */ |
455 | wild = (xmlSchemaWildcardPtr) xmlMalloc(sizeof(xmlSchemaWildcard)); |
456 | if (wild == NULL) { |
457 | xmlSchemaTypeErrMemory(NULL, "could not create an attribute " |
458 | "wildcard on anyType" ); |
459 | return; |
460 | } |
461 | memset(wild, 0, sizeof(xmlSchemaWildcard)); |
462 | wild->any = 1; |
463 | wild->processContents = XML_SCHEMAS_ANY_LAX; |
464 | xmlSchemaTypeAnyTypeDef->attributeWildcard = wild; |
465 | } |
466 | xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType" , |
467 | XML_SCHEMAS_ANYSIMPLETYPE, |
468 | xmlSchemaTypeAnyTypeDef); |
469 | /* |
470 | * primitive datatypes |
471 | */ |
472 | xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string" , |
473 | XML_SCHEMAS_STRING, |
474 | xmlSchemaTypeAnySimpleTypeDef); |
475 | xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal" , |
476 | XML_SCHEMAS_DECIMAL, |
477 | xmlSchemaTypeAnySimpleTypeDef); |
478 | xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date" , |
479 | XML_SCHEMAS_DATE, |
480 | xmlSchemaTypeAnySimpleTypeDef); |
481 | xmlSchemaTypeDatetimeDef = xmlSchemaInitBasicType("dateTime" , |
482 | XML_SCHEMAS_DATETIME, |
483 | xmlSchemaTypeAnySimpleTypeDef); |
484 | xmlSchemaTypeTimeDef = xmlSchemaInitBasicType("time" , |
485 | XML_SCHEMAS_TIME, |
486 | xmlSchemaTypeAnySimpleTypeDef); |
487 | xmlSchemaTypeGYearDef = xmlSchemaInitBasicType("gYear" , |
488 | XML_SCHEMAS_GYEAR, |
489 | xmlSchemaTypeAnySimpleTypeDef); |
490 | xmlSchemaTypeGYearMonthDef = xmlSchemaInitBasicType("gYearMonth" , |
491 | XML_SCHEMAS_GYEARMONTH, |
492 | xmlSchemaTypeAnySimpleTypeDef); |
493 | xmlSchemaTypeGMonthDef = xmlSchemaInitBasicType("gMonth" , |
494 | XML_SCHEMAS_GMONTH, |
495 | xmlSchemaTypeAnySimpleTypeDef); |
496 | xmlSchemaTypeGMonthDayDef = xmlSchemaInitBasicType("gMonthDay" , |
497 | XML_SCHEMAS_GMONTHDAY, |
498 | xmlSchemaTypeAnySimpleTypeDef); |
499 | xmlSchemaTypeGDayDef = xmlSchemaInitBasicType("gDay" , |
500 | XML_SCHEMAS_GDAY, |
501 | xmlSchemaTypeAnySimpleTypeDef); |
502 | xmlSchemaTypeDurationDef = xmlSchemaInitBasicType("duration" , |
503 | XML_SCHEMAS_DURATION, |
504 | xmlSchemaTypeAnySimpleTypeDef); |
505 | xmlSchemaTypeFloatDef = xmlSchemaInitBasicType("float" , |
506 | XML_SCHEMAS_FLOAT, |
507 | xmlSchemaTypeAnySimpleTypeDef); |
508 | xmlSchemaTypeDoubleDef = xmlSchemaInitBasicType("double" , |
509 | XML_SCHEMAS_DOUBLE, |
510 | xmlSchemaTypeAnySimpleTypeDef); |
511 | xmlSchemaTypeBooleanDef = xmlSchemaInitBasicType("boolean" , |
512 | XML_SCHEMAS_BOOLEAN, |
513 | xmlSchemaTypeAnySimpleTypeDef); |
514 | xmlSchemaTypeAnyURIDef = xmlSchemaInitBasicType("anyURI" , |
515 | XML_SCHEMAS_ANYURI, |
516 | xmlSchemaTypeAnySimpleTypeDef); |
517 | xmlSchemaTypeHexBinaryDef = xmlSchemaInitBasicType("hexBinary" , |
518 | XML_SCHEMAS_HEXBINARY, |
519 | xmlSchemaTypeAnySimpleTypeDef); |
520 | xmlSchemaTypeBase64BinaryDef |
521 | = xmlSchemaInitBasicType("base64Binary" , XML_SCHEMAS_BASE64BINARY, |
522 | xmlSchemaTypeAnySimpleTypeDef); |
523 | xmlSchemaTypeNotationDef = xmlSchemaInitBasicType("NOTATION" , |
524 | XML_SCHEMAS_NOTATION, |
525 | xmlSchemaTypeAnySimpleTypeDef); |
526 | xmlSchemaTypeQNameDef = xmlSchemaInitBasicType("QName" , |
527 | XML_SCHEMAS_QNAME, |
528 | xmlSchemaTypeAnySimpleTypeDef); |
529 | |
530 | /* |
531 | * derived datatypes |
532 | */ |
533 | xmlSchemaTypeIntegerDef = xmlSchemaInitBasicType("integer" , |
534 | XML_SCHEMAS_INTEGER, |
535 | xmlSchemaTypeDecimalDef); |
536 | xmlSchemaTypeNonPositiveIntegerDef = |
537 | xmlSchemaInitBasicType("nonPositiveInteger" , |
538 | XML_SCHEMAS_NPINTEGER, |
539 | xmlSchemaTypeIntegerDef); |
540 | xmlSchemaTypeNegativeIntegerDef = |
541 | xmlSchemaInitBasicType("negativeInteger" , XML_SCHEMAS_NINTEGER, |
542 | xmlSchemaTypeNonPositiveIntegerDef); |
543 | xmlSchemaTypeLongDef = |
544 | xmlSchemaInitBasicType("long" , XML_SCHEMAS_LONG, |
545 | xmlSchemaTypeIntegerDef); |
546 | xmlSchemaTypeIntDef = xmlSchemaInitBasicType("int" , XML_SCHEMAS_INT, |
547 | xmlSchemaTypeLongDef); |
548 | xmlSchemaTypeShortDef = xmlSchemaInitBasicType("short" , |
549 | XML_SCHEMAS_SHORT, |
550 | xmlSchemaTypeIntDef); |
551 | xmlSchemaTypeByteDef = xmlSchemaInitBasicType("byte" , |
552 | XML_SCHEMAS_BYTE, |
553 | xmlSchemaTypeShortDef); |
554 | xmlSchemaTypeNonNegativeIntegerDef = |
555 | xmlSchemaInitBasicType("nonNegativeInteger" , |
556 | XML_SCHEMAS_NNINTEGER, |
557 | xmlSchemaTypeIntegerDef); |
558 | xmlSchemaTypeUnsignedLongDef = |
559 | xmlSchemaInitBasicType("unsignedLong" , XML_SCHEMAS_ULONG, |
560 | xmlSchemaTypeNonNegativeIntegerDef); |
561 | xmlSchemaTypeUnsignedIntDef = |
562 | xmlSchemaInitBasicType("unsignedInt" , XML_SCHEMAS_UINT, |
563 | xmlSchemaTypeUnsignedLongDef); |
564 | xmlSchemaTypeUnsignedShortDef = |
565 | xmlSchemaInitBasicType("unsignedShort" , XML_SCHEMAS_USHORT, |
566 | xmlSchemaTypeUnsignedIntDef); |
567 | xmlSchemaTypeUnsignedByteDef = |
568 | xmlSchemaInitBasicType("unsignedByte" , XML_SCHEMAS_UBYTE, |
569 | xmlSchemaTypeUnsignedShortDef); |
570 | xmlSchemaTypePositiveIntegerDef = |
571 | xmlSchemaInitBasicType("positiveInteger" , XML_SCHEMAS_PINTEGER, |
572 | xmlSchemaTypeNonNegativeIntegerDef); |
573 | xmlSchemaTypeNormStringDef = xmlSchemaInitBasicType("normalizedString" , |
574 | XML_SCHEMAS_NORMSTRING, |
575 | xmlSchemaTypeStringDef); |
576 | xmlSchemaTypeTokenDef = xmlSchemaInitBasicType("token" , |
577 | XML_SCHEMAS_TOKEN, |
578 | xmlSchemaTypeNormStringDef); |
579 | xmlSchemaTypeLanguageDef = xmlSchemaInitBasicType("language" , |
580 | XML_SCHEMAS_LANGUAGE, |
581 | xmlSchemaTypeTokenDef); |
582 | xmlSchemaTypeNameDef = xmlSchemaInitBasicType("Name" , |
583 | XML_SCHEMAS_NAME, |
584 | xmlSchemaTypeTokenDef); |
585 | xmlSchemaTypeNmtokenDef = xmlSchemaInitBasicType("NMTOKEN" , |
586 | XML_SCHEMAS_NMTOKEN, |
587 | xmlSchemaTypeTokenDef); |
588 | xmlSchemaTypeNCNameDef = xmlSchemaInitBasicType("NCName" , |
589 | XML_SCHEMAS_NCNAME, |
590 | xmlSchemaTypeNameDef); |
591 | xmlSchemaTypeIdDef = xmlSchemaInitBasicType("ID" , XML_SCHEMAS_ID, |
592 | xmlSchemaTypeNCNameDef); |
593 | xmlSchemaTypeIdrefDef = xmlSchemaInitBasicType("IDREF" , |
594 | XML_SCHEMAS_IDREF, |
595 | xmlSchemaTypeNCNameDef); |
596 | xmlSchemaTypeEntityDef = xmlSchemaInitBasicType("ENTITY" , |
597 | XML_SCHEMAS_ENTITY, |
598 | xmlSchemaTypeNCNameDef); |
599 | /* |
600 | * Derived list types. |
601 | */ |
602 | /* ENTITIES */ |
603 | xmlSchemaTypeEntitiesDef = xmlSchemaInitBasicType("ENTITIES" , |
604 | XML_SCHEMAS_ENTITIES, |
605 | xmlSchemaTypeAnySimpleTypeDef); |
606 | xmlSchemaTypeEntitiesDef->subtypes = xmlSchemaTypeEntityDef; |
607 | /* IDREFS */ |
608 | xmlSchemaTypeIdrefsDef = xmlSchemaInitBasicType("IDREFS" , |
609 | XML_SCHEMAS_IDREFS, |
610 | xmlSchemaTypeAnySimpleTypeDef); |
611 | xmlSchemaTypeIdrefsDef->subtypes = xmlSchemaTypeIdrefDef; |
612 | |
613 | /* NMTOKENS */ |
614 | xmlSchemaTypeNmtokensDef = xmlSchemaInitBasicType("NMTOKENS" , |
615 | XML_SCHEMAS_NMTOKENS, |
616 | xmlSchemaTypeAnySimpleTypeDef); |
617 | xmlSchemaTypeNmtokensDef->subtypes = xmlSchemaTypeNmtokenDef; |
618 | |
619 | xmlSchemaTypesInitialized = 1; |
620 | } |
621 | |
622 | static void |
623 | xmlSchemaFreeTypeEntry(void *type, const xmlChar *name ATTRIBUTE_UNUSED) { |
624 | xmlSchemaFreeType((xmlSchemaTypePtr) type); |
625 | } |
626 | |
627 | /** |
628 | * xmlSchemaCleanupTypes: |
629 | * |
630 | * Cleanup the default XML Schemas type library |
631 | */ |
632 | void |
633 | xmlSchemaCleanupTypes(void) { |
634 | if (xmlSchemaTypesInitialized == 0) |
635 | return; |
636 | /* |
637 | * Free xs:anyType. |
638 | */ |
639 | { |
640 | xmlSchemaParticlePtr particle; |
641 | /* Attribute wildcard. */ |
642 | xmlSchemaFreeWildcard(xmlSchemaTypeAnyTypeDef->attributeWildcard); |
643 | /* Content type. */ |
644 | particle = (xmlSchemaParticlePtr) xmlSchemaTypeAnyTypeDef->subtypes; |
645 | /* Wildcard. */ |
646 | xmlSchemaFreeWildcard((xmlSchemaWildcardPtr) |
647 | particle->children->children->children); |
648 | xmlFree((xmlSchemaParticlePtr) particle->children->children); |
649 | /* Sequence model group. */ |
650 | xmlFree((xmlSchemaModelGroupPtr) particle->children); |
651 | xmlFree((xmlSchemaParticlePtr) particle); |
652 | xmlSchemaTypeAnyTypeDef->subtypes = NULL; |
653 | } |
654 | xmlHashFree(xmlSchemaTypesBank, xmlSchemaFreeTypeEntry); |
655 | xmlSchemaTypesInitialized = 0; |
656 | } |
657 | |
658 | /** |
659 | * xmlSchemaIsBuiltInTypeFacet: |
660 | * @type: the built-in type |
661 | * @facetType: the facet type |
662 | * |
663 | * Evaluates if a specific facet can be |
664 | * used in conjunction with a type. |
665 | * |
666 | * Returns 1 if the facet can be used with the given built-in type, |
667 | * 0 otherwise and -1 in case the type is not a built-in type. |
668 | */ |
669 | int |
670 | xmlSchemaIsBuiltInTypeFacet(xmlSchemaTypePtr type, int facetType) |
671 | { |
672 | if (type == NULL) |
673 | return (-1); |
674 | if (type->type != XML_SCHEMA_TYPE_BASIC) |
675 | return (-1); |
676 | switch (type->builtInType) { |
677 | case XML_SCHEMAS_BOOLEAN: |
678 | if ((facetType == XML_SCHEMA_FACET_PATTERN) || |
679 | (facetType == XML_SCHEMA_FACET_WHITESPACE)) |
680 | return (1); |
681 | else |
682 | return (0); |
683 | case XML_SCHEMAS_STRING: |
684 | case XML_SCHEMAS_NOTATION: |
685 | case XML_SCHEMAS_QNAME: |
686 | case XML_SCHEMAS_ANYURI: |
687 | case XML_SCHEMAS_BASE64BINARY: |
688 | case XML_SCHEMAS_HEXBINARY: |
689 | if ((facetType == XML_SCHEMA_FACET_LENGTH) || |
690 | (facetType == XML_SCHEMA_FACET_MINLENGTH) || |
691 | (facetType == XML_SCHEMA_FACET_MAXLENGTH) || |
692 | (facetType == XML_SCHEMA_FACET_PATTERN) || |
693 | (facetType == XML_SCHEMA_FACET_ENUMERATION) || |
694 | (facetType == XML_SCHEMA_FACET_WHITESPACE)) |
695 | return (1); |
696 | else |
697 | return (0); |
698 | case XML_SCHEMAS_DECIMAL: |
699 | if ((facetType == XML_SCHEMA_FACET_TOTALDIGITS) || |
700 | (facetType == XML_SCHEMA_FACET_FRACTIONDIGITS) || |
701 | (facetType == XML_SCHEMA_FACET_PATTERN) || |
702 | (facetType == XML_SCHEMA_FACET_WHITESPACE) || |
703 | (facetType == XML_SCHEMA_FACET_ENUMERATION) || |
704 | (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) || |
705 | (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) || |
706 | (facetType == XML_SCHEMA_FACET_MININCLUSIVE) || |
707 | (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE)) |
708 | return (1); |
709 | else |
710 | return (0); |
711 | case XML_SCHEMAS_TIME: |
712 | case XML_SCHEMAS_GDAY: |
713 | case XML_SCHEMAS_GMONTH: |
714 | case XML_SCHEMAS_GMONTHDAY: |
715 | case XML_SCHEMAS_GYEAR: |
716 | case XML_SCHEMAS_GYEARMONTH: |
717 | case XML_SCHEMAS_DATE: |
718 | case XML_SCHEMAS_DATETIME: |
719 | case XML_SCHEMAS_DURATION: |
720 | case XML_SCHEMAS_FLOAT: |
721 | case XML_SCHEMAS_DOUBLE: |
722 | if ((facetType == XML_SCHEMA_FACET_PATTERN) || |
723 | (facetType == XML_SCHEMA_FACET_ENUMERATION) || |
724 | (facetType == XML_SCHEMA_FACET_WHITESPACE) || |
725 | (facetType == XML_SCHEMA_FACET_MAXINCLUSIVE) || |
726 | (facetType == XML_SCHEMA_FACET_MAXEXCLUSIVE) || |
727 | (facetType == XML_SCHEMA_FACET_MININCLUSIVE) || |
728 | (facetType == XML_SCHEMA_FACET_MINEXCLUSIVE)) |
729 | return (1); |
730 | else |
731 | return (0); |
732 | default: |
733 | break; |
734 | } |
735 | return (0); |
736 | } |
737 | |
738 | /** |
739 | * xmlSchemaGetBuiltInType: |
740 | * @type: the type of the built in type |
741 | * |
742 | * Gives you the type struct for a built-in |
743 | * type by its type id. |
744 | * |
745 | * Returns the type if found, NULL otherwise. |
746 | */ |
747 | xmlSchemaTypePtr |
748 | xmlSchemaGetBuiltInType(xmlSchemaValType type) |
749 | { |
750 | if (xmlSchemaTypesInitialized == 0) |
751 | xmlSchemaInitTypes(); |
752 | switch (type) { |
753 | |
754 | case XML_SCHEMAS_ANYSIMPLETYPE: |
755 | return (xmlSchemaTypeAnySimpleTypeDef); |
756 | case XML_SCHEMAS_STRING: |
757 | return (xmlSchemaTypeStringDef); |
758 | case XML_SCHEMAS_NORMSTRING: |
759 | return (xmlSchemaTypeNormStringDef); |
760 | case XML_SCHEMAS_DECIMAL: |
761 | return (xmlSchemaTypeDecimalDef); |
762 | case XML_SCHEMAS_TIME: |
763 | return (xmlSchemaTypeTimeDef); |
764 | case XML_SCHEMAS_GDAY: |
765 | return (xmlSchemaTypeGDayDef); |
766 | case XML_SCHEMAS_GMONTH: |
767 | return (xmlSchemaTypeGMonthDef); |
768 | case XML_SCHEMAS_GMONTHDAY: |
769 | return (xmlSchemaTypeGMonthDayDef); |
770 | case XML_SCHEMAS_GYEAR: |
771 | return (xmlSchemaTypeGYearDef); |
772 | case XML_SCHEMAS_GYEARMONTH: |
773 | return (xmlSchemaTypeGYearMonthDef); |
774 | case XML_SCHEMAS_DATE: |
775 | return (xmlSchemaTypeDateDef); |
776 | case XML_SCHEMAS_DATETIME: |
777 | return (xmlSchemaTypeDatetimeDef); |
778 | case XML_SCHEMAS_DURATION: |
779 | return (xmlSchemaTypeDurationDef); |
780 | case XML_SCHEMAS_FLOAT: |
781 | return (xmlSchemaTypeFloatDef); |
782 | case XML_SCHEMAS_DOUBLE: |
783 | return (xmlSchemaTypeDoubleDef); |
784 | case XML_SCHEMAS_BOOLEAN: |
785 | return (xmlSchemaTypeBooleanDef); |
786 | case XML_SCHEMAS_TOKEN: |
787 | return (xmlSchemaTypeTokenDef); |
788 | case XML_SCHEMAS_LANGUAGE: |
789 | return (xmlSchemaTypeLanguageDef); |
790 | case XML_SCHEMAS_NMTOKEN: |
791 | return (xmlSchemaTypeNmtokenDef); |
792 | case XML_SCHEMAS_NMTOKENS: |
793 | return (xmlSchemaTypeNmtokensDef); |
794 | case XML_SCHEMAS_NAME: |
795 | return (xmlSchemaTypeNameDef); |
796 | case XML_SCHEMAS_QNAME: |
797 | return (xmlSchemaTypeQNameDef); |
798 | case XML_SCHEMAS_NCNAME: |
799 | return (xmlSchemaTypeNCNameDef); |
800 | case XML_SCHEMAS_ID: |
801 | return (xmlSchemaTypeIdDef); |
802 | case XML_SCHEMAS_IDREF: |
803 | return (xmlSchemaTypeIdrefDef); |
804 | case XML_SCHEMAS_IDREFS: |
805 | return (xmlSchemaTypeIdrefsDef); |
806 | case XML_SCHEMAS_ENTITY: |
807 | return (xmlSchemaTypeEntityDef); |
808 | case XML_SCHEMAS_ENTITIES: |
809 | return (xmlSchemaTypeEntitiesDef); |
810 | case XML_SCHEMAS_NOTATION: |
811 | return (xmlSchemaTypeNotationDef); |
812 | case XML_SCHEMAS_ANYURI: |
813 | return (xmlSchemaTypeAnyURIDef); |
814 | case XML_SCHEMAS_INTEGER: |
815 | return (xmlSchemaTypeIntegerDef); |
816 | case XML_SCHEMAS_NPINTEGER: |
817 | return (xmlSchemaTypeNonPositiveIntegerDef); |
818 | case XML_SCHEMAS_NINTEGER: |
819 | return (xmlSchemaTypeNegativeIntegerDef); |
820 | case XML_SCHEMAS_NNINTEGER: |
821 | return (xmlSchemaTypeNonNegativeIntegerDef); |
822 | case XML_SCHEMAS_PINTEGER: |
823 | return (xmlSchemaTypePositiveIntegerDef); |
824 | case XML_SCHEMAS_INT: |
825 | return (xmlSchemaTypeIntDef); |
826 | case XML_SCHEMAS_UINT: |
827 | return (xmlSchemaTypeUnsignedIntDef); |
828 | case XML_SCHEMAS_LONG: |
829 | return (xmlSchemaTypeLongDef); |
830 | case XML_SCHEMAS_ULONG: |
831 | return (xmlSchemaTypeUnsignedLongDef); |
832 | case XML_SCHEMAS_SHORT: |
833 | return (xmlSchemaTypeShortDef); |
834 | case XML_SCHEMAS_USHORT: |
835 | return (xmlSchemaTypeUnsignedShortDef); |
836 | case XML_SCHEMAS_BYTE: |
837 | return (xmlSchemaTypeByteDef); |
838 | case XML_SCHEMAS_UBYTE: |
839 | return (xmlSchemaTypeUnsignedByteDef); |
840 | case XML_SCHEMAS_HEXBINARY: |
841 | return (xmlSchemaTypeHexBinaryDef); |
842 | case XML_SCHEMAS_BASE64BINARY: |
843 | return (xmlSchemaTypeBase64BinaryDef); |
844 | case XML_SCHEMAS_ANYTYPE: |
845 | return (xmlSchemaTypeAnyTypeDef); |
846 | default: |
847 | return (NULL); |
848 | } |
849 | } |
850 | |
851 | /** |
852 | * xmlSchemaValueAppend: |
853 | * @prev: the value |
854 | * @cur: the value to be appended |
855 | * |
856 | * Appends a next sibling to a list of computed values. |
857 | * |
858 | * Returns 0 if succeeded and -1 on API errors. |
859 | */ |
860 | int |
861 | xmlSchemaValueAppend(xmlSchemaValPtr prev, xmlSchemaValPtr cur) { |
862 | |
863 | if ((prev == NULL) || (cur == NULL)) |
864 | return (-1); |
865 | prev->next = cur; |
866 | return (0); |
867 | } |
868 | |
869 | /** |
870 | * xmlSchemaValueGetNext: |
871 | * @cur: the value |
872 | * |
873 | * Accessor for the next sibling of a list of computed values. |
874 | * |
875 | * Returns the next value or NULL if there was none, or on |
876 | * API errors. |
877 | */ |
878 | xmlSchemaValPtr |
879 | xmlSchemaValueGetNext(xmlSchemaValPtr cur) { |
880 | |
881 | if (cur == NULL) |
882 | return (NULL); |
883 | return (cur->next); |
884 | } |
885 | |
886 | /** |
887 | * xmlSchemaValueGetAsString: |
888 | * @val: the value |
889 | * |
890 | * Accessor for the string value of a computed value. |
891 | * |
892 | * Returns the string value or NULL if there was none, or on |
893 | * API errors. |
894 | */ |
895 | const xmlChar * |
896 | xmlSchemaValueGetAsString(xmlSchemaValPtr val) |
897 | { |
898 | if (val == NULL) |
899 | return (NULL); |
900 | switch (val->type) { |
901 | case XML_SCHEMAS_STRING: |
902 | case XML_SCHEMAS_NORMSTRING: |
903 | case XML_SCHEMAS_ANYSIMPLETYPE: |
904 | case XML_SCHEMAS_TOKEN: |
905 | case XML_SCHEMAS_LANGUAGE: |
906 | case XML_SCHEMAS_NMTOKEN: |
907 | case XML_SCHEMAS_NAME: |
908 | case XML_SCHEMAS_NCNAME: |
909 | case XML_SCHEMAS_ID: |
910 | case XML_SCHEMAS_IDREF: |
911 | case XML_SCHEMAS_ENTITY: |
912 | case XML_SCHEMAS_ANYURI: |
913 | return (BAD_CAST val->value.str); |
914 | default: |
915 | break; |
916 | } |
917 | return (NULL); |
918 | } |
919 | |
920 | /** |
921 | * xmlSchemaValueGetAsBoolean: |
922 | * @val: the value |
923 | * |
924 | * Accessor for the boolean value of a computed value. |
925 | * |
926 | * Returns 1 if true and 0 if false, or in case of an error. Hmm. |
927 | */ |
928 | int |
929 | xmlSchemaValueGetAsBoolean(xmlSchemaValPtr val) |
930 | { |
931 | if ((val == NULL) || (val->type != XML_SCHEMAS_BOOLEAN)) |
932 | return (0); |
933 | return (val->value.b); |
934 | } |
935 | |
936 | /** |
937 | * xmlSchemaNewStringValue: |
938 | * @type: the value type |
939 | * @value: the value |
940 | * |
941 | * Allocate a new simple type value. The type can be |
942 | * of XML_SCHEMAS_STRING. |
943 | * WARNING: This one is intended to be expanded for other |
944 | * string based types. We need this for anySimpleType as well. |
945 | * The given value is consumed and freed with the struct. |
946 | * |
947 | * Returns a pointer to the new value or NULL in case of error |
948 | */ |
949 | xmlSchemaValPtr |
950 | xmlSchemaNewStringValue(xmlSchemaValType type, |
951 | const xmlChar *value) |
952 | { |
953 | xmlSchemaValPtr val; |
954 | |
955 | if (type != XML_SCHEMAS_STRING) |
956 | return(NULL); |
957 | val = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal)); |
958 | if (val == NULL) { |
959 | return(NULL); |
960 | } |
961 | memset(val, 0, sizeof(xmlSchemaVal)); |
962 | val->type = type; |
963 | val->value.str = (xmlChar *) value; |
964 | return(val); |
965 | } |
966 | |
967 | /** |
968 | * xmlSchemaNewNOTATIONValue: |
969 | * @name: the notation name |
970 | * @ns: the notation namespace name or NULL |
971 | * |
972 | * Allocate a new NOTATION value. |
973 | * The given values are consumed and freed with the struct. |
974 | * |
975 | * Returns a pointer to the new value or NULL in case of error |
976 | */ |
977 | xmlSchemaValPtr |
978 | xmlSchemaNewNOTATIONValue(const xmlChar *name, |
979 | const xmlChar *ns) |
980 | { |
981 | xmlSchemaValPtr val; |
982 | |
983 | val = xmlSchemaNewValue(XML_SCHEMAS_NOTATION); |
984 | if (val == NULL) |
985 | return (NULL); |
986 | |
987 | val->value.qname.name = (xmlChar *)name; |
988 | if (ns != NULL) |
989 | val->value.qname.uri = (xmlChar *)ns; |
990 | return(val); |
991 | } |
992 | |
993 | /** |
994 | * xmlSchemaNewQNameValue: |
995 | * @namespaceName: the namespace name |
996 | * @localName: the local name |
997 | * |
998 | * Allocate a new QName value. |
999 | * The given values are consumed and freed with the struct. |
1000 | * |
1001 | * Returns a pointer to the new value or NULL in case of an error. |
1002 | */ |
1003 | xmlSchemaValPtr |
1004 | xmlSchemaNewQNameValue(const xmlChar *namespaceName, |
1005 | const xmlChar *localName) |
1006 | { |
1007 | xmlSchemaValPtr val; |
1008 | |
1009 | val = xmlSchemaNewValue(XML_SCHEMAS_QNAME); |
1010 | if (val == NULL) |
1011 | return (NULL); |
1012 | |
1013 | val->value.qname.name = (xmlChar *) localName; |
1014 | val->value.qname.uri = (xmlChar *) namespaceName; |
1015 | return(val); |
1016 | } |
1017 | |
1018 | /** |
1019 | * xmlSchemaFreeValue: |
1020 | * @value: the value to free |
1021 | * |
1022 | * Cleanup the default XML Schemas type library |
1023 | */ |
1024 | void |
1025 | xmlSchemaFreeValue(xmlSchemaValPtr value) { |
1026 | xmlSchemaValPtr prev; |
1027 | |
1028 | while (value != NULL) { |
1029 | switch (value->type) { |
1030 | case XML_SCHEMAS_STRING: |
1031 | case XML_SCHEMAS_NORMSTRING: |
1032 | case XML_SCHEMAS_TOKEN: |
1033 | case XML_SCHEMAS_LANGUAGE: |
1034 | case XML_SCHEMAS_NMTOKEN: |
1035 | case XML_SCHEMAS_NMTOKENS: |
1036 | case XML_SCHEMAS_NAME: |
1037 | case XML_SCHEMAS_NCNAME: |
1038 | case XML_SCHEMAS_ID: |
1039 | case XML_SCHEMAS_IDREF: |
1040 | case XML_SCHEMAS_IDREFS: |
1041 | case XML_SCHEMAS_ENTITY: |
1042 | case XML_SCHEMAS_ENTITIES: |
1043 | case XML_SCHEMAS_ANYURI: |
1044 | case XML_SCHEMAS_ANYSIMPLETYPE: |
1045 | if (value->value.str != NULL) |
1046 | xmlFree(value->value.str); |
1047 | break; |
1048 | case XML_SCHEMAS_NOTATION: |
1049 | case XML_SCHEMAS_QNAME: |
1050 | if (value->value.qname.uri != NULL) |
1051 | xmlFree(value->value.qname.uri); |
1052 | if (value->value.qname.name != NULL) |
1053 | xmlFree(value->value.qname.name); |
1054 | break; |
1055 | case XML_SCHEMAS_HEXBINARY: |
1056 | if (value->value.hex.str != NULL) |
1057 | xmlFree(value->value.hex.str); |
1058 | break; |
1059 | case XML_SCHEMAS_BASE64BINARY: |
1060 | if (value->value.base64.str != NULL) |
1061 | xmlFree(value->value.base64.str); |
1062 | break; |
1063 | default: |
1064 | break; |
1065 | } |
1066 | prev = value; |
1067 | value = value->next; |
1068 | xmlFree(prev); |
1069 | } |
1070 | } |
1071 | |
1072 | /** |
1073 | * xmlSchemaGetPredefinedType: |
1074 | * @name: the type name |
1075 | * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema" |
1076 | * |
1077 | * Lookup a type in the default XML Schemas type library |
1078 | * |
1079 | * Returns the type if found, NULL otherwise |
1080 | */ |
1081 | xmlSchemaTypePtr |
1082 | xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) { |
1083 | if (xmlSchemaTypesInitialized == 0) |
1084 | xmlSchemaInitTypes(); |
1085 | if (name == NULL) |
1086 | return(NULL); |
1087 | return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns)); |
1088 | } |
1089 | |
1090 | /** |
1091 | * xmlSchemaGetBuiltInListSimpleTypeItemType: |
1092 | * @type: the built-in simple type. |
1093 | * |
1094 | * Lookup function |
1095 | * |
1096 | * Returns the item type of @type as defined by the built-in datatype |
1097 | * hierarchy of XML Schema Part 2: Datatypes, or NULL in case of an error. |
1098 | */ |
1099 | xmlSchemaTypePtr |
1100 | xmlSchemaGetBuiltInListSimpleTypeItemType(xmlSchemaTypePtr type) |
1101 | { |
1102 | if ((type == NULL) || (type->type != XML_SCHEMA_TYPE_BASIC)) |
1103 | return (NULL); |
1104 | switch (type->builtInType) { |
1105 | case XML_SCHEMAS_NMTOKENS: |
1106 | return (xmlSchemaTypeNmtokenDef ); |
1107 | case XML_SCHEMAS_IDREFS: |
1108 | return (xmlSchemaTypeIdrefDef); |
1109 | case XML_SCHEMAS_ENTITIES: |
1110 | return (xmlSchemaTypeEntityDef); |
1111 | default: |
1112 | return (NULL); |
1113 | } |
1114 | } |
1115 | |
1116 | /**************************************************************** |
1117 | * * |
1118 | * Convenience macros and functions * |
1119 | * * |
1120 | ****************************************************************/ |
1121 | |
1122 | #define IS_TZO_CHAR(c) \ |
1123 | ((c == 0) || (c == 'Z') || (c == '+') || (c == '-')) |
1124 | |
1125 | #define VALID_YEAR(yr) (yr != 0) |
1126 | #define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12)) |
1127 | /* VALID_DAY should only be used when month is unknown */ |
1128 | #define VALID_DAY(day) ((day >= 1) && (day <= 31)) |
1129 | #define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23)) |
1130 | #define VALID_MIN(min) ((min >= 0) && (min <= 59)) |
1131 | #define VALID_SEC(sec) ((sec >= 0) && (sec < 60)) |
1132 | #define VALID_TZO(tzo) ((tzo > -840) && (tzo < 840)) |
1133 | #define IS_LEAP(y) \ |
1134 | (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0)) |
1135 | |
1136 | static const unsigned int daysInMonth[12] = |
1137 | { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
1138 | static const unsigned int daysInMonthLeap[12] = |
1139 | { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; |
1140 | |
1141 | #define MAX_DAYINMONTH(yr,mon) \ |
1142 | (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1]) |
1143 | |
1144 | #define VALID_MDAY(dt) \ |
1145 | (IS_LEAP(dt->year) ? \ |
1146 | (dt->day <= daysInMonthLeap[dt->mon - 1]) : \ |
1147 | (dt->day <= daysInMonth[dt->mon - 1])) |
1148 | |
1149 | #define VALID_DATE(dt) \ |
1150 | (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt)) |
1151 | |
1152 | #define VALID_END_OF_DAY(dt) \ |
1153 | ((dt)->hour == 24 && (dt)->min == 0 && (dt)->sec == 0) |
1154 | |
1155 | #define VALID_TIME(dt) \ |
1156 | (((VALID_HOUR(dt->hour) && VALID_MIN(dt->min) && \ |
1157 | VALID_SEC(dt->sec)) || VALID_END_OF_DAY(dt)) && \ |
1158 | VALID_TZO(dt->tzo)) |
1159 | |
1160 | #define VALID_DATETIME(dt) \ |
1161 | (VALID_DATE(dt) && VALID_TIME(dt)) |
1162 | |
1163 | #define SECS_PER_MIN (60) |
1164 | #define SECS_PER_HOUR (60 * SECS_PER_MIN) |
1165 | #define SECS_PER_DAY (24 * SECS_PER_HOUR) |
1166 | |
1167 | static const long dayInYearByMonth[12] = |
1168 | { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; |
1169 | static const long dayInLeapYearByMonth[12] = |
1170 | { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }; |
1171 | |
1172 | #define DAY_IN_YEAR(day, month, year) \ |
1173 | ((IS_LEAP(year) ? \ |
1174 | dayInLeapYearByMonth[month - 1] : \ |
1175 | dayInYearByMonth[month - 1]) + day) |
1176 | |
1177 | #ifdef DEBUG |
1178 | #define DEBUG_DATE(dt) \ |
1179 | xmlGenericError(xmlGenericErrorContext, \ |
1180 | "type=%o %04ld-%02u-%02uT%02u:%02u:%03f", \ |
1181 | dt->type,dt->value.date.year,dt->value.date.mon, \ |
1182 | dt->value.date.day,dt->value.date.hour,dt->value.date.min, \ |
1183 | dt->value.date.sec); \ |
1184 | if (dt->value.date.tz_flag) \ |
1185 | if (dt->value.date.tzo != 0) \ |
1186 | xmlGenericError(xmlGenericErrorContext, \ |
1187 | "%+05d\n",dt->value.date.tzo); \ |
1188 | else \ |
1189 | xmlGenericError(xmlGenericErrorContext, "Z\n"); \ |
1190 | else \ |
1191 | xmlGenericError(xmlGenericErrorContext,"\n") |
1192 | #else |
1193 | #define DEBUG_DATE(dt) |
1194 | #endif |
1195 | |
1196 | /** |
1197 | * _xmlSchemaParseGYear: |
1198 | * @dt: pointer to a date structure |
1199 | * @str: pointer to the string to analyze |
1200 | * |
1201 | * Parses a xs:gYear without time zone and fills in the appropriate |
1202 | * field of the @dt structure. @str is updated to point just after the |
1203 | * xs:gYear. It is supposed that @dt->year is big enough to contain |
1204 | * the year. |
1205 | * |
1206 | * Returns 0 or the error code |
1207 | */ |
1208 | static int |
1209 | _xmlSchemaParseGYear (xmlSchemaValDatePtr dt, const xmlChar **str) { |
1210 | const xmlChar *cur = *str, *firstChar; |
1211 | int isneg = 0, digcnt = 0; |
1212 | |
1213 | if (((*cur < '0') || (*cur > '9')) && |
1214 | (*cur != '-') && (*cur != '+')) |
1215 | return -1; |
1216 | |
1217 | if (*cur == '-') { |
1218 | isneg = 1; |
1219 | cur++; |
1220 | } |
1221 | |
1222 | firstChar = cur; |
1223 | |
1224 | while ((*cur >= '0') && (*cur <= '9')) { |
1225 | dt->year = dt->year * 10 + (*cur - '0'); |
1226 | cur++; |
1227 | digcnt++; |
1228 | } |
1229 | |
1230 | /* year must be at least 4 digits (CCYY); over 4 |
1231 | * digits cannot have a leading zero. */ |
1232 | if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0'))) |
1233 | return 1; |
1234 | |
1235 | if (isneg) |
1236 | dt->year = - dt->year; |
1237 | |
1238 | if (!VALID_YEAR(dt->year)) |
1239 | return 2; |
1240 | |
1241 | *str = cur; |
1242 | return 0; |
1243 | } |
1244 | |
1245 | /** |
1246 | * PARSE_2_DIGITS: |
1247 | * @num: the integer to fill in |
1248 | * @cur: an #xmlChar * |
1249 | * @invalid: an integer |
1250 | * |
1251 | * Parses a 2-digits integer and updates @num with the value. @cur is |
1252 | * updated to point just after the integer. |
1253 | * In case of error, @invalid is set to %TRUE, values of @num and |
1254 | * @cur are undefined. |
1255 | */ |
1256 | #define PARSE_2_DIGITS(num, cur, invalid) \ |
1257 | if ((cur[0] < '0') || (cur[0] > '9') || \ |
1258 | (cur[1] < '0') || (cur[1] > '9')) \ |
1259 | invalid = 1; \ |
1260 | else \ |
1261 | num = (cur[0] - '0') * 10 + (cur[1] - '0'); \ |
1262 | cur += 2; |
1263 | |
1264 | /** |
1265 | * PARSE_FLOAT: |
1266 | * @num: the double to fill in |
1267 | * @cur: an #xmlChar * |
1268 | * @invalid: an integer |
1269 | * |
1270 | * Parses a float and updates @num with the value. @cur is |
1271 | * updated to point just after the float. The float must have a |
1272 | * 2-digits integer part and may or may not have a decimal part. |
1273 | * In case of error, @invalid is set to %TRUE, values of @num and |
1274 | * @cur are undefined. |
1275 | */ |
1276 | #define PARSE_FLOAT(num, cur, invalid) \ |
1277 | PARSE_2_DIGITS(num, cur, invalid); \ |
1278 | if (!invalid && (*cur == '.')) { \ |
1279 | double mult = 1; \ |
1280 | cur++; \ |
1281 | if ((*cur < '0') || (*cur > '9')) \ |
1282 | invalid = 1; \ |
1283 | while ((*cur >= '0') && (*cur <= '9')) { \ |
1284 | mult /= 10; \ |
1285 | num += (*cur - '0') * mult; \ |
1286 | cur++; \ |
1287 | } \ |
1288 | } |
1289 | |
1290 | /** |
1291 | * _xmlSchemaParseGMonth: |
1292 | * @dt: pointer to a date structure |
1293 | * @str: pointer to the string to analyze |
1294 | * |
1295 | * Parses a xs:gMonth without time zone and fills in the appropriate |
1296 | * field of the @dt structure. @str is updated to point just after the |
1297 | * xs:gMonth. |
1298 | * |
1299 | * Returns 0 or the error code |
1300 | */ |
1301 | static int |
1302 | _xmlSchemaParseGMonth (xmlSchemaValDatePtr dt, const xmlChar **str) { |
1303 | const xmlChar *cur = *str; |
1304 | int ret = 0; |
1305 | unsigned int value = 0; |
1306 | |
1307 | PARSE_2_DIGITS(value, cur, ret); |
1308 | if (ret != 0) |
1309 | return ret; |
1310 | |
1311 | if (!VALID_MONTH(value)) |
1312 | return 2; |
1313 | |
1314 | dt->mon = value; |
1315 | |
1316 | *str = cur; |
1317 | return 0; |
1318 | } |
1319 | |
1320 | /** |
1321 | * _xmlSchemaParseGDay: |
1322 | * @dt: pointer to a date structure |
1323 | * @str: pointer to the string to analyze |
1324 | * |
1325 | * Parses a xs:gDay without time zone and fills in the appropriate |
1326 | * field of the @dt structure. @str is updated to point just after the |
1327 | * xs:gDay. |
1328 | * |
1329 | * Returns 0 or the error code |
1330 | */ |
1331 | static int |
1332 | _xmlSchemaParseGDay (xmlSchemaValDatePtr dt, const xmlChar **str) { |
1333 | const xmlChar *cur = *str; |
1334 | int ret = 0; |
1335 | unsigned int value = 0; |
1336 | |
1337 | PARSE_2_DIGITS(value, cur, ret); |
1338 | if (ret != 0) |
1339 | return ret; |
1340 | |
1341 | if (!VALID_DAY(value)) |
1342 | return 2; |
1343 | |
1344 | dt->day = value; |
1345 | *str = cur; |
1346 | return 0; |
1347 | } |
1348 | |
1349 | /** |
1350 | * _xmlSchemaParseTime: |
1351 | * @dt: pointer to a date structure |
1352 | * @str: pointer to the string to analyze |
1353 | * |
1354 | * Parses a xs:time without time zone and fills in the appropriate |
1355 | * fields of the @dt structure. @str is updated to point just after the |
1356 | * xs:time. |
1357 | * In case of error, values of @dt fields are undefined. |
1358 | * |
1359 | * Returns 0 or the error code |
1360 | */ |
1361 | static int |
1362 | _xmlSchemaParseTime (xmlSchemaValDatePtr dt, const xmlChar **str) { |
1363 | const xmlChar *cur = *str; |
1364 | int ret = 0; |
1365 | int value = 0; |
1366 | |
1367 | PARSE_2_DIGITS(value, cur, ret); |
1368 | if (ret != 0) |
1369 | return ret; |
1370 | if (*cur != ':') |
1371 | return 1; |
1372 | if (!VALID_HOUR(value) && value != 24 /* Allow end-of-day hour */) |
1373 | return 2; |
1374 | cur++; |
1375 | |
1376 | /* the ':' insures this string is xs:time */ |
1377 | dt->hour = value; |
1378 | |
1379 | PARSE_2_DIGITS(value, cur, ret); |
1380 | if (ret != 0) |
1381 | return ret; |
1382 | if (!VALID_MIN(value)) |
1383 | return 2; |
1384 | dt->min = value; |
1385 | |
1386 | if (*cur != ':') |
1387 | return 1; |
1388 | cur++; |
1389 | |
1390 | PARSE_FLOAT(dt->sec, cur, ret); |
1391 | if (ret != 0) |
1392 | return ret; |
1393 | |
1394 | if (!VALID_TIME(dt)) |
1395 | return 2; |
1396 | |
1397 | *str = cur; |
1398 | return 0; |
1399 | } |
1400 | |
1401 | /** |
1402 | * _xmlSchemaParseTimeZone: |
1403 | * @dt: pointer to a date structure |
1404 | * @str: pointer to the string to analyze |
1405 | * |
1406 | * Parses a time zone without time zone and fills in the appropriate |
1407 | * field of the @dt structure. @str is updated to point just after the |
1408 | * time zone. |
1409 | * |
1410 | * Returns 0 or the error code |
1411 | */ |
1412 | static int |
1413 | _xmlSchemaParseTimeZone (xmlSchemaValDatePtr dt, const xmlChar **str) { |
1414 | const xmlChar *cur; |
1415 | int ret = 0; |
1416 | |
1417 | if (str == NULL) |
1418 | return -1; |
1419 | cur = *str; |
1420 | |
1421 | switch (*cur) { |
1422 | case 0: |
1423 | dt->tz_flag = 0; |
1424 | dt->tzo = 0; |
1425 | break; |
1426 | |
1427 | case 'Z': |
1428 | dt->tz_flag = 1; |
1429 | dt->tzo = 0; |
1430 | cur++; |
1431 | break; |
1432 | |
1433 | case '+': |
1434 | case '-': { |
1435 | int isneg = 0, tmp = 0; |
1436 | isneg = (*cur == '-'); |
1437 | |
1438 | cur++; |
1439 | |
1440 | PARSE_2_DIGITS(tmp, cur, ret); |
1441 | if (ret != 0) |
1442 | return ret; |
1443 | if (!VALID_HOUR(tmp)) |
1444 | return 2; |
1445 | |
1446 | if (*cur != ':') |
1447 | return 1; |
1448 | cur++; |
1449 | |
1450 | dt->tzo = tmp * 60; |
1451 | |
1452 | PARSE_2_DIGITS(tmp, cur, ret); |
1453 | if (ret != 0) |
1454 | return ret; |
1455 | if (!VALID_MIN(tmp)) |
1456 | return 2; |
1457 | |
1458 | dt->tzo += tmp; |
1459 | if (isneg) |
1460 | dt->tzo = - dt->tzo; |
1461 | |
1462 | if (!VALID_TZO(dt->tzo)) |
1463 | return 2; |
1464 | |
1465 | dt->tz_flag = 1; |
1466 | break; |
1467 | } |
1468 | default: |
1469 | return 1; |
1470 | } |
1471 | |
1472 | *str = cur; |
1473 | return 0; |
1474 | } |
1475 | |
1476 | /** |
1477 | * _xmlSchemaBase64Decode: |
1478 | * @ch: a character |
1479 | * |
1480 | * Converts a base64 encoded character to its base 64 value. |
1481 | * |
1482 | * Returns 0-63 (value), 64 (pad), or -1 (not recognized) |
1483 | */ |
1484 | static int |
1485 | _xmlSchemaBase64Decode (const xmlChar ch) { |
1486 | if (('A' <= ch) && (ch <= 'Z')) return ch - 'A'; |
1487 | if (('a' <= ch) && (ch <= 'z')) return ch - 'a' + 26; |
1488 | if (('0' <= ch) && (ch <= '9')) return ch - '0' + 52; |
1489 | if ('+' == ch) return 62; |
1490 | if ('/' == ch) return 63; |
1491 | if ('=' == ch) return 64; |
1492 | return -1; |
1493 | } |
1494 | |
1495 | /**************************************************************** |
1496 | * * |
1497 | * XML Schema Dates/Times Datatypes Handling * |
1498 | * * |
1499 | ****************************************************************/ |
1500 | |
1501 | /** |
1502 | * PARSE_DIGITS: |
1503 | * @num: the integer to fill in |
1504 | * @cur: an #xmlChar * |
1505 | * @num_type: an integer flag |
1506 | * |
1507 | * Parses a digits integer and updates @num with the value. @cur is |
1508 | * updated to point just after the integer. |
1509 | * In case of error, @num_type is set to -1, values of @num and |
1510 | * @cur are undefined. |
1511 | */ |
1512 | #define PARSE_DIGITS(num, cur, num_type) \ |
1513 | if ((*cur < '0') || (*cur > '9')) \ |
1514 | num_type = -1; \ |
1515 | else \ |
1516 | while ((*cur >= '0') && (*cur <= '9')) { \ |
1517 | num = num * 10 + (*cur - '0'); \ |
1518 | cur++; \ |
1519 | } |
1520 | |
1521 | /** |
1522 | * PARSE_NUM: |
1523 | * @num: the double to fill in |
1524 | * @cur: an #xmlChar * |
1525 | * @num_type: an integer flag |
1526 | * |
1527 | * Parses a float or integer and updates @num with the value. @cur is |
1528 | * updated to point just after the number. If the number is a float, |
1529 | * then it must have an integer part and a decimal part; @num_type will |
1530 | * be set to 1. If there is no decimal part, @num_type is set to zero. |
1531 | * In case of error, @num_type is set to -1, values of @num and |
1532 | * @cur are undefined. |
1533 | */ |
1534 | #define PARSE_NUM(num, cur, num_type) \ |
1535 | num = 0; \ |
1536 | PARSE_DIGITS(num, cur, num_type); \ |
1537 | if (!num_type && (*cur == '.')) { \ |
1538 | double mult = 1; \ |
1539 | cur++; \ |
1540 | if ((*cur < '0') || (*cur > '9')) \ |
1541 | num_type = -1; \ |
1542 | else \ |
1543 | num_type = 1; \ |
1544 | while ((*cur >= '0') && (*cur <= '9')) { \ |
1545 | mult /= 10; \ |
1546 | num += (*cur - '0') * mult; \ |
1547 | cur++; \ |
1548 | } \ |
1549 | } |
1550 | |
1551 | /** |
1552 | * xmlSchemaValidateDates: |
1553 | * @type: the expected type or XML_SCHEMAS_UNKNOWN |
1554 | * @dateTime: string to analyze |
1555 | * @val: the return computed value |
1556 | * |
1557 | * Check that @dateTime conforms to the lexical space of one of the date types. |
1558 | * if true a value is computed and returned in @val. |
1559 | * |
1560 | * Returns 0 if this validates, a positive error code number otherwise |
1561 | * and -1 in case of internal or API error. |
1562 | */ |
1563 | static int |
1564 | xmlSchemaValidateDates (xmlSchemaValType type, |
1565 | const xmlChar *dateTime, xmlSchemaValPtr *val, |
1566 | int collapse) { |
1567 | xmlSchemaValPtr dt; |
1568 | int ret; |
1569 | const xmlChar *cur = dateTime; |
1570 | |
1571 | #define RETURN_TYPE_IF_VALID(t) \ |
1572 | if (IS_TZO_CHAR(*cur)) { \ |
1573 | ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); \ |
1574 | if (ret == 0) { \ |
1575 | if (*cur != 0) \ |
1576 | goto error; \ |
1577 | dt->type = t; \ |
1578 | goto done; \ |
1579 | } \ |
1580 | } |
1581 | |
1582 | if (dateTime == NULL) |
1583 | return -1; |
1584 | |
1585 | if (collapse) |
1586 | while IS_WSP_BLANK_CH(*cur) cur++; |
1587 | |
1588 | if ((*cur != '-') && (*cur < '0') && (*cur > '9')) |
1589 | return 1; |
1590 | |
1591 | dt = xmlSchemaNewValue(XML_SCHEMAS_UNKNOWN); |
1592 | if (dt == NULL) |
1593 | return -1; |
1594 | |
1595 | if ((cur[0] == '-') && (cur[1] == '-')) { |
1596 | /* |
1597 | * It's an incomplete date (xs:gMonthDay, xs:gMonth or |
1598 | * xs:gDay) |
1599 | */ |
1600 | cur += 2; |
1601 | |
1602 | /* is it an xs:gDay? */ |
1603 | if (*cur == '-') { |
1604 | if (type == XML_SCHEMAS_GMONTH) |
1605 | goto error; |
1606 | ++cur; |
1607 | ret = _xmlSchemaParseGDay(&(dt->value.date), &cur); |
1608 | if (ret != 0) |
1609 | goto error; |
1610 | |
1611 | RETURN_TYPE_IF_VALID(XML_SCHEMAS_GDAY); |
1612 | |
1613 | goto error; |
1614 | } |
1615 | |
1616 | /* |
1617 | * it should be an xs:gMonthDay or xs:gMonth |
1618 | */ |
1619 | ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur); |
1620 | if (ret != 0) |
1621 | goto error; |
1622 | |
1623 | /* |
1624 | * a '-' char could indicate this type is xs:gMonthDay or |
1625 | * a negative time zone offset. Check for xs:gMonthDay first. |
1626 | * Also the first three char's of a negative tzo (-MM:SS) can |
1627 | * appear to be a valid day; so even if the day portion |
1628 | * of the xs:gMonthDay verifies, we must insure it was not |
1629 | * a tzo. |
1630 | */ |
1631 | if (*cur == '-') { |
1632 | const xmlChar *rewnd = cur; |
1633 | cur++; |
1634 | |
1635 | ret = _xmlSchemaParseGDay(&(dt->value.date), &cur); |
1636 | if ((ret == 0) && ((*cur == 0) || (*cur != ':'))) { |
1637 | |
1638 | /* |
1639 | * we can use the VALID_MDAY macro to validate the month |
1640 | * and day because the leap year test will flag year zero |
1641 | * as a leap year (even though zero is an invalid year). |
1642 | * FUTURE TODO: Zero will become valid in XML Schema 1.1 |
1643 | * probably. |
1644 | */ |
1645 | if (VALID_MDAY((&(dt->value.date)))) { |
1646 | |
1647 | RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTHDAY); |
1648 | |
1649 | goto error; |
1650 | } |
1651 | } |
1652 | |
1653 | /* |
1654 | * not xs:gMonthDay so rewind and check if just xs:gMonth |
1655 | * with an optional time zone. |
1656 | */ |
1657 | cur = rewnd; |
1658 | } |
1659 | |
1660 | RETURN_TYPE_IF_VALID(XML_SCHEMAS_GMONTH); |
1661 | |
1662 | goto error; |
1663 | } |
1664 | |
1665 | /* |
1666 | * It's a right-truncated date or an xs:time. |
1667 | * Try to parse an xs:time then fallback on right-truncated dates. |
1668 | */ |
1669 | if ((*cur >= '0') && (*cur <= '9')) { |
1670 | ret = _xmlSchemaParseTime(&(dt->value.date), &cur); |
1671 | if (ret == 0) { |
1672 | /* it's an xs:time */ |
1673 | RETURN_TYPE_IF_VALID(XML_SCHEMAS_TIME); |
1674 | } |
1675 | } |
1676 | |
1677 | /* fallback on date parsing */ |
1678 | cur = dateTime; |
1679 | |
1680 | ret = _xmlSchemaParseGYear(&(dt->value.date), &cur); |
1681 | if (ret != 0) |
1682 | goto error; |
1683 | |
1684 | /* is it an xs:gYear? */ |
1685 | RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEAR); |
1686 | |
1687 | if (*cur != '-') |
1688 | goto error; |
1689 | cur++; |
1690 | |
1691 | ret = _xmlSchemaParseGMonth(&(dt->value.date), &cur); |
1692 | if (ret != 0) |
1693 | goto error; |
1694 | |
1695 | /* is it an xs:gYearMonth? */ |
1696 | RETURN_TYPE_IF_VALID(XML_SCHEMAS_GYEARMONTH); |
1697 | |
1698 | if (*cur != '-') |
1699 | goto error; |
1700 | cur++; |
1701 | |
1702 | ret = _xmlSchemaParseGDay(&(dt->value.date), &cur); |
1703 | if ((ret != 0) || !VALID_DATE((&(dt->value.date)))) |
1704 | goto error; |
1705 | |
1706 | /* is it an xs:date? */ |
1707 | RETURN_TYPE_IF_VALID(XML_SCHEMAS_DATE); |
1708 | |
1709 | if (*cur != 'T') |
1710 | goto error; |
1711 | cur++; |
1712 | |
1713 | /* it should be an xs:dateTime */ |
1714 | ret = _xmlSchemaParseTime(&(dt->value.date), &cur); |
1715 | if (ret != 0) |
1716 | goto error; |
1717 | |
1718 | ret = _xmlSchemaParseTimeZone(&(dt->value.date), &cur); |
1719 | if (collapse) |
1720 | while IS_WSP_BLANK_CH(*cur) cur++; |
1721 | if ((ret != 0) || (*cur != 0) || (!(VALID_DATETIME((&(dt->value.date)))))) |
1722 | goto error; |
1723 | |
1724 | |
1725 | dt->type = XML_SCHEMAS_DATETIME; |
1726 | |
1727 | done: |
1728 | #if 1 |
1729 | if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) |
1730 | goto error; |
1731 | #else |
1732 | /* |
1733 | * insure the parsed type is equal to or less significant (right |
1734 | * truncated) than the desired type. |
1735 | */ |
1736 | if ((type != XML_SCHEMAS_UNKNOWN) && (type != dt->type)) { |
1737 | |
1738 | /* time only matches time */ |
1739 | if ((type == XML_SCHEMAS_TIME) && (dt->type == XML_SCHEMAS_TIME)) |
1740 | goto error; |
1741 | |
1742 | if ((type == XML_SCHEMAS_DATETIME) && |
1743 | ((dt->type != XML_SCHEMAS_DATE) || |
1744 | (dt->type != XML_SCHEMAS_GYEARMONTH) || |
1745 | (dt->type != XML_SCHEMAS_GYEAR))) |
1746 | goto error; |
1747 | |
1748 | if ((type == XML_SCHEMAS_DATE) && |
1749 | ((dt->type != XML_SCHEMAS_GYEAR) || |
1750 | (dt->type != XML_SCHEMAS_GYEARMONTH))) |
1751 | goto error; |
1752 | |
1753 | if ((type == XML_SCHEMAS_GYEARMONTH) && (dt->type != XML_SCHEMAS_GYEAR)) |
1754 | goto error; |
1755 | |
1756 | if ((type == XML_SCHEMAS_GMONTHDAY) && (dt->type != XML_SCHEMAS_GMONTH)) |
1757 | goto error; |
1758 | } |
1759 | #endif |
1760 | |
1761 | if (val != NULL) |
1762 | *val = dt; |
1763 | else |
1764 | xmlSchemaFreeValue(dt); |
1765 | |
1766 | return 0; |
1767 | |
1768 | error: |
1769 | if (dt != NULL) |
1770 | xmlSchemaFreeValue(dt); |
1771 | return 1; |
1772 | } |
1773 | |
1774 | /** |
1775 | * xmlSchemaValidateDuration: |
1776 | * @type: the predefined type |
1777 | * @duration: string to analyze |
1778 | * @val: the return computed value |
1779 | * |
1780 | * Check that @duration conforms to the lexical space of the duration type. |
1781 | * if true a value is computed and returned in @val. |
1782 | * |
1783 | * Returns 0 if this validates, a positive error code number otherwise |
1784 | * and -1 in case of internal or API error. |
1785 | */ |
1786 | static int |
1787 | xmlSchemaValidateDuration (xmlSchemaTypePtr type ATTRIBUTE_UNUSED, |
1788 | const xmlChar *duration, xmlSchemaValPtr *val, |
1789 | int collapse) { |
1790 | const xmlChar *cur = duration; |
1791 | xmlSchemaValPtr dur; |
1792 | int isneg = 0; |
1793 | unsigned int seq = 0; |
1794 | double num; |
1795 | int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */ |
1796 | const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'}; |
1797 | const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0}; |
1798 | |
1799 | if (duration == NULL) |
1800 | return -1; |
1801 | |
1802 | if (collapse) |
1803 | while IS_WSP_BLANK_CH(*cur) cur++; |
1804 | |
1805 | if (*cur == '-') { |
1806 | isneg = 1; |
1807 | cur++; |
1808 | } |
1809 | |
1810 | /* duration must start with 'P' (after sign) */ |
1811 | if (*cur++ != 'P') |
1812 | return 1; |
1813 | |
1814 | if (*cur == 0) |
1815 | return 1; |
1816 | |
1817 | dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION); |
1818 | if (dur == NULL) |
1819 | return -1; |
1820 | |
1821 | while (*cur != 0) { |
1822 | |
1823 | /* input string should be empty or invalid date/time item */ |
1824 | if (seq >= sizeof(desig)) |
1825 | goto error; |
1826 | |
1827 | /* T designator must be present for time items */ |
1828 | if (*cur == 'T') { |
1829 | if (seq <= 3) { |
1830 | seq = 3; |
1831 | cur++; |
1832 | } else |
1833 | return 1; |
1834 | } else if (seq == 3) |
1835 | goto error; |
1836 | |
1837 | /* parse the number portion of the item */ |
1838 | PARSE_NUM(num, cur, num_type); |
1839 | |
1840 | if ((num_type == -1) || (*cur == 0)) |
1841 | goto error; |
1842 | |
1843 | /* update duration based on item type */ |
1844 | while (seq < sizeof(desig)) { |
1845 | if (*cur == desig[seq]) { |
1846 | |
1847 | /* verify numeric type; only seconds can be float */ |
1848 | if ((num_type != 0) && (seq < (sizeof(desig)-1))) |
1849 | goto error; |
1850 | |
1851 | switch (seq) { |
1852 | case 0: |
1853 | dur->value.dur.mon = (long)num * 12; |
1854 | break; |
1855 | case 1: |
1856 | dur->value.dur.mon += (long)num; |
1857 | break; |
1858 | default: |
1859 | /* convert to seconds using multiplier */ |
1860 | dur->value.dur.sec += num * multi[seq]; |
1861 | seq++; |
1862 | break; |
1863 | } |
1864 | |
1865 | break; /* exit loop */ |
1866 | } |
1867 | /* no date designators found? */ |
1868 | if ((++seq == 3) || (seq == 6)) |
1869 | goto error; |
1870 | } |
1871 | cur++; |
1872 | if (collapse) |
1873 | while IS_WSP_BLANK_CH(*cur) cur++; |
1874 | } |
1875 | |
1876 | if (isneg) { |
1877 | dur->value.dur.mon = -dur->value.dur.mon; |
1878 | dur->value.dur.day = -dur->value.dur.day; |
1879 | dur->value.dur.sec = -dur->value.dur.sec; |
1880 | } |
1881 | |
1882 | if (val != NULL) |
1883 | *val = dur; |
1884 | else |
1885 | xmlSchemaFreeValue(dur); |
1886 | |
1887 | return 0; |
1888 | |
1889 | error: |
1890 | if (dur != NULL) |
1891 | xmlSchemaFreeValue(dur); |
1892 | return 1; |
1893 | } |
1894 | |
1895 | /** |
1896 | * xmlSchemaStrip: |
1897 | * @value: a value |
1898 | * |
1899 | * Removes the leading and ending spaces of a string |
1900 | * |
1901 | * Returns the new string or NULL if no change was required. |
1902 | */ |
1903 | static xmlChar * |
1904 | xmlSchemaStrip(const xmlChar *value) { |
1905 | const xmlChar *start = value, *end, *f; |
1906 | |
1907 | if (value == NULL) return(NULL); |
1908 | while ((*start != 0) && (IS_BLANK_CH(*start))) start++; |
1909 | end = start; |
1910 | while (*end != 0) end++; |
1911 | f = end; |
1912 | end--; |
1913 | while ((end > start) && (IS_BLANK_CH(*end))) end--; |
1914 | end++; |
1915 | if ((start == value) && (f == end)) return(NULL); |
1916 | return(xmlStrndup(start, end - start)); |
1917 | } |
1918 | |
1919 | /** |
1920 | * xmlSchemaWhiteSpaceReplace: |
1921 | * @value: a value |
1922 | * |
1923 | * Replaces 0xd, 0x9 and 0xa with a space. |
1924 | * |
1925 | * Returns the new string or NULL if no change was required. |
1926 | */ |
1927 | xmlChar * |
1928 | xmlSchemaWhiteSpaceReplace(const xmlChar *value) { |
1929 | const xmlChar *cur = value; |
1930 | xmlChar *ret = NULL, *mcur; |
1931 | |
1932 | if (value == NULL) |
1933 | return(NULL); |
1934 | |
1935 | while ((*cur != 0) && |
1936 | (((*cur) != 0xd) && ((*cur) != 0x9) && ((*cur) != 0xa))) { |
1937 | cur++; |
1938 | } |
1939 | if (*cur == 0) |
1940 | return (NULL); |
1941 | ret = xmlStrdup(value); |
1942 | /* TODO FIXME: I guess gcc will bark at this. */ |
1943 | mcur = (xmlChar *) (ret + (cur - value)); |
1944 | do { |
1945 | if ( ((*mcur) == 0xd) || ((*mcur) == 0x9) || ((*mcur) == 0xa) ) |
1946 | *mcur = ' '; |
1947 | mcur++; |
1948 | } while (*mcur != 0); |
1949 | return(ret); |
1950 | } |
1951 | |
1952 | /** |
1953 | * xmlSchemaCollapseString: |
1954 | * @value: a value |
1955 | * |
1956 | * Removes and normalize white spaces in the string |
1957 | * |
1958 | * Returns the new string or NULL if no change was required. |
1959 | */ |
1960 | xmlChar * |
1961 | xmlSchemaCollapseString(const xmlChar *value) { |
1962 | const xmlChar *start = value, *end, *f; |
1963 | xmlChar *g; |
1964 | int col = 0; |
1965 | |
1966 | if (value == NULL) return(NULL); |
1967 | while ((*start != 0) && (IS_BLANK_CH(*start))) start++; |
1968 | end = start; |
1969 | while (*end != 0) { |
1970 | if ((*end == ' ') && (IS_BLANK_CH(end[1]))) { |
1971 | col = end - start; |
1972 | break; |
1973 | } else if ((*end == 0xa) || (*end == 0x9) || (*end == 0xd)) { |
1974 | col = end - start; |
1975 | break; |
1976 | } |
1977 | end++; |
1978 | } |
1979 | if (col == 0) { |
1980 | f = end; |
1981 | end--; |
1982 | while ((end > start) && (IS_BLANK_CH(*end))) end--; |
1983 | end++; |
1984 | if ((start == value) && (f == end)) return(NULL); |
1985 | return(xmlStrndup(start, end - start)); |
1986 | } |
1987 | start = xmlStrdup(start); |
1988 | if (start == NULL) return(NULL); |
1989 | g = (xmlChar *) (start + col); |
1990 | end = g; |
1991 | while (*end != 0) { |
1992 | if (IS_BLANK_CH(*end)) { |
1993 | end++; |
1994 | while (IS_BLANK_CH(*end)) end++; |
1995 | if (*end != 0) |
1996 | *g++ = ' '; |
1997 | } else |
1998 | *g++ = *end++; |
1999 | } |
2000 | *g = 0; |
2001 | return((xmlChar *) start); |
2002 | } |
2003 | |
2004 | /** |
2005 | * xmlSchemaValAtomicListNode: |
2006 | * @type: the predefined atomic type for a token in the list |
2007 | * @value: the list value to check |
2008 | * @ret: the return computed value |
2009 | * @node: the node containing the value |
2010 | * |
2011 | * Check that a value conforms to the lexical space of the predefined |
2012 | * list type. if true a value is computed and returned in @ret. |
2013 | * |
2014 | * Returns the number of items if this validates, a negative error code |
2015 | * number otherwise |
2016 | */ |
2017 | static int |
2018 | xmlSchemaValAtomicListNode(xmlSchemaTypePtr type, const xmlChar *value, |
2019 | xmlSchemaValPtr *ret, xmlNodePtr node) { |
2020 | xmlChar *val, *cur, *endval; |
2021 | int nb_values = 0; |
2022 | int tmp = 0; |
2023 | |
2024 | if (value == NULL) { |
2025 | return(-1); |
2026 | } |
2027 | val = xmlStrdup(value); |
2028 | if (val == NULL) { |
2029 | return(-1); |
2030 | } |
2031 | if (ret != NULL) { |
2032 | *ret = NULL; |
2033 | } |
2034 | cur = val; |
2035 | /* |
2036 | * Split the list |
2037 | */ |
2038 | while (IS_BLANK_CH(*cur)) *cur++ = 0; |
2039 | while (*cur != 0) { |
2040 | if (IS_BLANK_CH(*cur)) { |
2041 | *cur = 0; |
2042 | cur++; |
2043 | while (IS_BLANK_CH(*cur)) *cur++ = 0; |
2044 | } else { |
2045 | nb_values++; |
2046 | cur++; |
2047 | while ((*cur != 0) && (!IS_BLANK_CH(*cur))) cur++; |
2048 | } |
2049 | } |
2050 | if (nb_values == 0) { |
2051 | xmlFree(val); |
2052 | return(nb_values); |
2053 | } |
2054 | endval = cur; |
2055 | cur = val; |
2056 | while ((*cur == 0) && (cur != endval)) cur++; |
2057 | while (cur != endval) { |
2058 | tmp = xmlSchemaValPredefTypeNode(type, cur, NULL, node); |
2059 | if (tmp != 0) |
2060 | break; |
2061 | while (*cur != 0) cur++; |
2062 | while ((*cur == 0) && (cur != endval)) cur++; |
2063 | } |
2064 | /* TODO what return value ? c.f. bug #158628 |
2065 | if (ret != NULL) { |
2066 | TODO |
2067 | } */ |
2068 | xmlFree(val); |
2069 | if (tmp == 0) |
2070 | return(nb_values); |
2071 | return(-1); |
2072 | } |
2073 | |
2074 | /** |
2075 | * xmlSchemaParseUInt: |
2076 | * @str: pointer to the string R/W |
2077 | * @llo: pointer to the low result |
2078 | * @lmi: pointer to the mid result |
2079 | * @lhi: pointer to the high result |
2080 | * |
2081 | * Parse an unsigned long into 3 fields. |
2082 | * |
2083 | * Returns the number of significant digits in the number or |
2084 | * -1 if overflow of the capacity and -2 if it's not a number. |
2085 | */ |
2086 | static int |
2087 | xmlSchemaParseUInt(const xmlChar **str, unsigned long *llo, |
2088 | unsigned long *lmi, unsigned long *lhi) { |
2089 | unsigned long lo = 0, mi = 0, hi = 0; |
2090 | const xmlChar *tmp, *cur = *str; |
2091 | int ret = 0, i = 0; |
2092 | |
2093 | if (!((*cur >= '0') && (*cur <= '9'))) |
2094 | return(-2); |
2095 | |
2096 | while (*cur == '0') { /* ignore leading zeroes */ |
2097 | cur++; |
2098 | } |
2099 | tmp = cur; |
2100 | while ((*tmp != 0) && (*tmp >= '0') && (*tmp <= '9')) { |
2101 | i++;tmp++;ret++; |
2102 | } |
2103 | if (i > 24) { |
2104 | *str = tmp; |
2105 | return(-1); |
2106 | } |
2107 | while (i > 16) { |
2108 | hi = hi * 10 + (*cur++ - '0'); |
2109 | i--; |
2110 | } |
2111 | while (i > 8) { |
2112 | mi = mi * 10 + (*cur++ - '0'); |
2113 | i--; |
2114 | } |
2115 | while (i > 0) { |
2116 | lo = lo * 10 + (*cur++ - '0'); |
2117 | i--; |
2118 | } |
2119 | |
2120 | *str = cur; |
2121 | *llo = lo; |
2122 | *lmi = mi; |
2123 | *lhi = hi; |
2124 | return(ret); |
2125 | } |
2126 | |
2127 | /** |
2128 | * xmlSchemaValAtomicType: |
2129 | * @type: the predefined type |
2130 | * @value: the value to check |
2131 | * @val: the return computed value |
2132 | * @node: the node containing the value |
2133 | * flags: flags to control the vlidation |
2134 | * |
2135 | * Check that a value conforms to the lexical space of the atomic type. |
2136 | * if true a value is computed and returned in @val. |
2137 | * This checks the value space for list types as well (IDREFS, NMTOKENS). |
2138 | * |
2139 | * Returns 0 if this validates, a positive error code number otherwise |
2140 | * and -1 in case of internal or API error. |
2141 | */ |
2142 | static int |
2143 | xmlSchemaValAtomicType(xmlSchemaTypePtr type, const xmlChar * value, |
2144 | xmlSchemaValPtr * val, xmlNodePtr node, int flags, |
2145 | xmlSchemaWhitespaceValueType ws, |
2146 | int normOnTheFly, int applyNorm, int createStringValue) |
2147 | { |
2148 | xmlSchemaValPtr v; |
2149 | xmlChar *norm = NULL; |
2150 | int ret = 0; |
2151 | |
2152 | if (xmlSchemaTypesInitialized == 0) |
2153 | xmlSchemaInitTypes(); |
2154 | if (type == NULL) |
2155 | return (-1); |
2156 | |
2157 | /* |
2158 | * validating a non existant text node is similar to validating |
2159 | * an empty one. |
2160 | */ |
2161 | if (value == NULL) |
2162 | value = BAD_CAST "" ; |
2163 | |
2164 | if (val != NULL) |
2165 | *val = NULL; |
2166 | if ((flags == 0) && (value != NULL)) { |
2167 | |
2168 | if ((type->builtInType != XML_SCHEMAS_STRING) && |
2169 | (type->builtInType != XML_SCHEMAS_ANYTYPE) && |
2170 | (type->builtInType != XML_SCHEMAS_ANYSIMPLETYPE)) { |
2171 | if (type->builtInType == XML_SCHEMAS_NORMSTRING) |
2172 | norm = xmlSchemaWhiteSpaceReplace(value); |
2173 | else |
2174 | norm = xmlSchemaCollapseString(value); |
2175 | if (norm != NULL) |
2176 | value = norm; |
2177 | } |
2178 | } |
2179 | |
2180 | switch (type->builtInType) { |
2181 | case XML_SCHEMAS_UNKNOWN: |
2182 | goto error; |
2183 | case XML_SCHEMAS_ANYTYPE: |
2184 | case XML_SCHEMAS_ANYSIMPLETYPE: |
2185 | if ((createStringValue) && (val != NULL)) { |
2186 | v = xmlSchemaNewValue(XML_SCHEMAS_ANYSIMPLETYPE); |
2187 | if (v != NULL) { |
2188 | v->value.str = xmlStrdup(value); |
2189 | *val = v; |
2190 | } else { |
2191 | goto error; |
2192 | } |
2193 | } |
2194 | goto return0; |
2195 | case XML_SCHEMAS_STRING: |
2196 | if (! normOnTheFly) { |
2197 | const xmlChar *cur = value; |
2198 | |
2199 | if (ws == XML_SCHEMA_WHITESPACE_REPLACE) { |
2200 | while (*cur != 0) { |
2201 | if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) { |
2202 | goto return1; |
2203 | } else { |
2204 | cur++; |
2205 | } |
2206 | } |
2207 | } else if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) { |
2208 | while (*cur != 0) { |
2209 | if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) { |
2210 | goto return1; |
2211 | } else if IS_WSP_SPACE_CH(*cur) { |
2212 | cur++; |
2213 | if IS_WSP_SPACE_CH(*cur) |
2214 | goto return1; |
2215 | } else { |
2216 | cur++; |
2217 | } |
2218 | } |
2219 | } |
2220 | } |
2221 | if (createStringValue && (val != NULL)) { |
2222 | if (applyNorm) { |
2223 | if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) |
2224 | norm = xmlSchemaCollapseString(value); |
2225 | else if (ws == XML_SCHEMA_WHITESPACE_REPLACE) |
2226 | norm = xmlSchemaWhiteSpaceReplace(value); |
2227 | if (norm != NULL) |
2228 | value = norm; |
2229 | } |
2230 | v = xmlSchemaNewValue(XML_SCHEMAS_STRING); |
2231 | if (v != NULL) { |
2232 | v->value.str = xmlStrdup(value); |
2233 | *val = v; |
2234 | } else { |
2235 | goto error; |
2236 | } |
2237 | } |
2238 | goto return0; |
2239 | case XML_SCHEMAS_NORMSTRING:{ |
2240 | if (normOnTheFly) { |
2241 | if (applyNorm) { |
2242 | if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) |
2243 | norm = xmlSchemaCollapseString(value); |
2244 | else |
2245 | norm = xmlSchemaWhiteSpaceReplace(value); |
2246 | if (norm != NULL) |
2247 | value = norm; |
2248 | } |
2249 | } else { |
2250 | const xmlChar *cur = value; |
2251 | while (*cur != 0) { |
2252 | if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) { |
2253 | goto return1; |
2254 | } else { |
2255 | cur++; |
2256 | } |
2257 | } |
2258 | } |
2259 | if (val != NULL) { |
2260 | v = xmlSchemaNewValue(XML_SCHEMAS_NORMSTRING); |
2261 | if (v != NULL) { |
2262 | v->value.str = xmlStrdup(value); |
2263 | *val = v; |
2264 | } else { |
2265 | goto error; |
2266 | } |
2267 | } |
2268 | goto return0; |
2269 | } |
2270 | case XML_SCHEMAS_DECIMAL:{ |
2271 | const xmlChar *cur = value; |
2272 | unsigned int len, neg, integ, hasLeadingZeroes; |
2273 | xmlChar cval[25]; |
2274 | xmlChar *cptr = cval; |
2275 | |
2276 | if ((cur == NULL) || (*cur == 0)) |
2277 | goto return1; |
2278 | |
2279 | /* |
2280 | * xs:decimal has a whitespace-facet value of 'collapse'. |
2281 | */ |
2282 | if (normOnTheFly) |
2283 | while IS_WSP_BLANK_CH(*cur) cur++; |
2284 | |
2285 | /* |
2286 | * First we handle an optional sign. |
2287 | */ |
2288 | neg = 0; |
2289 | if (*cur == '-') { |
2290 | neg = 1; |
2291 | cur++; |
2292 | } else if (*cur == '+') |
2293 | cur++; |
2294 | /* |
2295 | * Disallow: "", "-", "- " |
2296 | */ |
2297 | if (*cur == 0) |
2298 | goto return1; |
2299 | /* |
2300 | * Next we "pre-parse" the number, in preparation for calling |
2301 | * the common routine xmlSchemaParseUInt. We get rid of any |
2302 | * leading zeroes (because we have reserved only 25 chars), |
2303 | * and note the position of a decimal point. |
2304 | */ |
2305 | len = 0; |
2306 | integ = ~0u; |
2307 | hasLeadingZeroes = 0; |
2308 | /* |
2309 | * Skip leading zeroes. |
2310 | */ |
2311 | while (*cur == '0') { |
2312 | cur++; |
2313 | hasLeadingZeroes = 1; |
2314 | } |
2315 | if (*cur != 0) { |
2316 | do { |
2317 | if ((*cur >= '0') && (*cur <= '9')) { |
2318 | *cptr++ = *cur++; |
2319 | len++; |
2320 | } else if (*cur == '.') { |
2321 | cur++; |
2322 | integ = len; |
2323 | do { |
2324 | if ((*cur >= '0') && (*cur <= '9')) { |
2325 | *cptr++ = *cur++; |
2326 | len++; |
2327 | } else |
2328 | break; |
2329 | } while (len < 24); |
2330 | /* |
2331 | * Disallow "." but allow "00." |
2332 | */ |
2333 | if ((len == 0) && (!hasLeadingZeroes)) |
2334 | goto return1; |
2335 | break; |
2336 | } else |
2337 | break; |
2338 | } while (len < 24); |
2339 | } |
2340 | if (normOnTheFly) |
2341 | while IS_WSP_BLANK_CH(*cur) cur++; |
2342 | if (*cur != 0) |
2343 | goto return1; /* error if any extraneous chars */ |
2344 | if (val != NULL) { |
2345 | v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL); |
2346 | if (v != NULL) { |
2347 | /* |
2348 | * Now evaluate the significant digits of the number |
2349 | */ |
2350 | if (len != 0) { |
2351 | |
2352 | if (integ != ~0u) { |
2353 | /* |
2354 | * Get rid of trailing zeroes in the |
2355 | * fractional part. |
2356 | */ |
2357 | while ((len != integ) && (*(cptr-1) == '0')) { |
2358 | cptr--; |
2359 | len--; |
2360 | } |
2361 | } |
2362 | /* |
2363 | * Terminate the (preparsed) string. |
2364 | */ |
2365 | if (len != 0) { |
2366 | *cptr = 0; |
2367 | cptr = cval; |
2368 | |
2369 | xmlSchemaParseUInt((const xmlChar **)&cptr, |
2370 | &v->value.decimal.lo, |
2371 | &v->value.decimal.mi, |
2372 | &v->value.decimal.hi); |
2373 | } |
2374 | } |
2375 | /* |
2376 | * Set the total digits to 1 if a zero value. |
2377 | */ |
2378 | v->value.decimal.sign = neg; |
2379 | if (len == 0) { |
2380 | /* Speedup for zero values. */ |
2381 | v->value.decimal.total = 1; |
2382 | } else { |
2383 | v->value.decimal.total = len; |
2384 | if (integ == ~0u) |
2385 | v->value.decimal.frac = 0; |
2386 | else |
2387 | v->value.decimal.frac = len - integ; |
2388 | } |
2389 | *val = v; |
2390 | } |
2391 | } |
2392 | goto return0; |
2393 | } |
2394 | case XML_SCHEMAS_TIME: |
2395 | case XML_SCHEMAS_GDAY: |
2396 | case XML_SCHEMAS_GMONTH: |
2397 | case XML_SCHEMAS_GMONTHDAY: |
2398 | case XML_SCHEMAS_GYEAR: |
2399 | case XML_SCHEMAS_GYEARMONTH: |
2400 | case XML_SCHEMAS_DATE: |
2401 | case XML_SCHEMAS_DATETIME: |
2402 | ret = xmlSchemaValidateDates(type->builtInType, value, val, |
2403 | normOnTheFly); |
2404 | break; |
2405 | case XML_SCHEMAS_DURATION: |
2406 | ret = xmlSchemaValidateDuration(type, value, val, |
2407 | normOnTheFly); |
2408 | break; |
2409 | case XML_SCHEMAS_FLOAT: |
2410 | case XML_SCHEMAS_DOUBLE: { |
2411 | const xmlChar *cur = value; |
2412 | int neg = 0; |
2413 | int digits_before = 0; |
2414 | int digits_after = 0; |
2415 | |
2416 | if (normOnTheFly) |
2417 | while IS_WSP_BLANK_CH(*cur) cur++; |
2418 | |
2419 | if ((cur[0] == 'N') && (cur[1] == 'a') && (cur[2] == 'N')) { |
2420 | cur += 3; |
2421 | if (*cur != 0) |
2422 | goto return1; |
2423 | if (val != NULL) { |
2424 | if (type == xmlSchemaTypeFloatDef) { |
2425 | v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT); |
2426 | if (v != NULL) { |
2427 | v->value.f = (float) xmlXPathNAN; |
2428 | } else { |
2429 | xmlSchemaFreeValue(v); |
2430 | goto error; |
2431 | } |
2432 | } else { |
2433 | v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE); |
2434 | if (v != NULL) { |
2435 | v->value.d = xmlXPathNAN; |
2436 | } else { |
2437 | xmlSchemaFreeValue(v); |
2438 | goto error; |
2439 | } |
2440 | } |
2441 | *val = v; |
2442 | } |
2443 | goto return0; |
2444 | } |
2445 | if (*cur == '-') { |
2446 | neg = 1; |
2447 | cur++; |
2448 | } |
2449 | if ((cur[0] == 'I') && (cur[1] == 'N') && (cur[2] == 'F')) { |
2450 | cur += 3; |
2451 | if (*cur != 0) |
2452 | goto return1; |
2453 | if (val != NULL) { |
2454 | if (type == xmlSchemaTypeFloatDef) { |
2455 | v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT); |
2456 | if (v != NULL) { |
2457 | if (neg) |
2458 | v->value.f = (float) xmlXPathNINF; |
2459 | else |
2460 | v->value.f = (float) xmlXPathPINF; |
2461 | } else { |
2462 | xmlSchemaFreeValue(v); |
2463 | goto error; |
2464 | } |
2465 | } else { |
2466 | v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE); |
2467 | if (v != NULL) { |
2468 | if (neg) |
2469 | v->value.d = xmlXPathNINF; |
2470 | else |
2471 | v->value.d = xmlXPathPINF; |
2472 | } else { |
2473 | xmlSchemaFreeValue(v); |
2474 | goto error; |
2475 | } |
2476 | } |
2477 | *val = v; |
2478 | } |
2479 | goto return0; |
2480 | } |
2481 | if ((neg == 0) && (*cur == '+')) |
2482 | cur++; |
2483 | if ((cur[0] == 0) || (cur[0] == '+') || (cur[0] == '-')) |
2484 | goto return1; |
2485 | while ((*cur >= '0') && (*cur <= '9')) { |
2486 | cur++; |
2487 | digits_before++; |
2488 | } |
2489 | if (*cur == '.') { |
2490 | cur++; |
2491 | while ((*cur >= '0') && (*cur <= '9')) { |
2492 | cur++; |
2493 | digits_after++; |
2494 | } |
2495 | } |
2496 | if ((digits_before == 0) && (digits_after == 0)) |
2497 | goto return1; |
2498 | if ((*cur == 'e') || (*cur == 'E')) { |
2499 | cur++; |
2500 | if ((*cur == '-') || (*cur == '+')) |
2501 | cur++; |
2502 | while ((*cur >= '0') && (*cur <= '9')) |
2503 | cur++; |
2504 | } |
2505 | if (normOnTheFly) |
2506 | while IS_WSP_BLANK_CH(*cur) cur++; |
2507 | |
2508 | if (*cur != 0) |
2509 | goto return1; |
2510 | if (val != NULL) { |
2511 | if (type == xmlSchemaTypeFloatDef) { |
2512 | v = xmlSchemaNewValue(XML_SCHEMAS_FLOAT); |
2513 | if (v != NULL) { |
2514 | /* |
2515 | * TODO: sscanf seems not to give the correct |
2516 | * value for extremely high/low values. |
2517 | * E.g. "1E-149" results in zero. |
2518 | */ |
2519 | if (sscanf((const char *) value, "%f" , |
2520 | &(v->value.f)) == 1) { |
2521 | *val = v; |
2522 | } else { |
2523 | xmlSchemaFreeValue(v); |
2524 | goto return1; |
2525 | } |
2526 | } else { |
2527 | goto error; |
2528 | } |
2529 | } else { |
2530 | v = xmlSchemaNewValue(XML_SCHEMAS_DOUBLE); |
2531 | if (v != NULL) { |
2532 | /* |
2533 | * TODO: sscanf seems not to give the correct |
2534 | * value for extremely high/low values. |
2535 | */ |
2536 | if (sscanf((const char *) value, "%lf" , |
2537 | &(v->value.d)) == 1) { |
2538 | *val = v; |
2539 | } else { |
2540 | xmlSchemaFreeValue(v); |
2541 | goto return1; |
2542 | } |
2543 | } else { |
2544 | goto error; |
2545 | } |
2546 | } |
2547 | } |
2548 | goto return0; |
2549 | } |
2550 | case XML_SCHEMAS_BOOLEAN:{ |
2551 | const xmlChar *cur = value; |
2552 | |
2553 | if (normOnTheFly) { |
2554 | while IS_WSP_BLANK_CH(*cur) cur++; |
2555 | if (*cur == '0') { |
2556 | ret = 0; |
2557 | cur++; |
2558 | } else if (*cur == '1') { |
2559 | ret = 1; |
2560 | cur++; |
2561 | } else if (*cur == 't') { |
2562 | cur++; |
2563 | if ((*cur++ == 'r') && (*cur++ == 'u') && |
2564 | (*cur++ == 'e')) { |
2565 | ret = 1; |
2566 | } else |
2567 | goto return1; |
2568 | } else if (*cur == 'f') { |
2569 | cur++; |
2570 | if ((*cur++ == 'a') && (*cur++ == 'l') && |
2571 | (*cur++ == 's') && (*cur++ == 'e')) { |
2572 | ret = 0; |
2573 | } else |
2574 | goto return1; |
2575 | } else |
2576 | goto return1; |
2577 | if (*cur != 0) { |
2578 | while IS_WSP_BLANK_CH(*cur) cur++; |
2579 | if (*cur != 0) |
2580 | goto return1; |
2581 | } |
2582 | } else { |
2583 | if ((cur[0] == '0') && (cur[1] == 0)) |
2584 | ret = 0; |
2585 | else if ((cur[0] == '1') && (cur[1] == 0)) |
2586 | ret = 1; |
2587 | else if ((cur[0] == 't') && (cur[1] == 'r') |
2588 | && (cur[2] == 'u') && (cur[3] == 'e') |
2589 | && (cur[4] == 0)) |
2590 | ret = 1; |
2591 | else if ((cur[0] == 'f') && (cur[1] == 'a') |
2592 | && (cur[2] == 'l') && (cur[3] == 's') |
2593 | && (cur[4] == 'e') && (cur[5] == 0)) |
2594 | ret = 0; |
2595 | else |
2596 | goto return1; |
2597 | } |
2598 | if (val != NULL) { |
2599 | v = xmlSchemaNewValue(XML_SCHEMAS_BOOLEAN); |
2600 | if (v != NULL) { |
2601 | v->value.b = ret; |
2602 | *val = v; |
2603 | } else { |
2604 | goto error; |
2605 | } |
2606 | } |
2607 | goto return0; |
2608 | } |
2609 | case XML_SCHEMAS_TOKEN:{ |
2610 | const xmlChar *cur = value; |
2611 | |
2612 | if (! normOnTheFly) { |
2613 | while (*cur != 0) { |
2614 | if ((*cur == 0xd) || (*cur == 0xa) || (*cur == 0x9)) { |
2615 | goto return1; |
2616 | } else if (*cur == ' ') { |
2617 | cur++; |
2618 | if (*cur == 0) |
2619 | goto return1; |
2620 | if (*cur == ' ') |
2621 | goto return1; |
2622 | } else { |
2623 | cur++; |
2624 | } |
2625 | } |
2626 | } |
2627 | if (val != NULL) { |
2628 | v = xmlSchemaNewValue(XML_SCHEMAS_TOKEN); |
2629 | if (v != NULL) { |
2630 | v->value.str = xmlStrdup(value); |
2631 | *val = v; |
2632 | } else { |
2633 | goto error; |
2634 | } |
2635 | } |
2636 | goto return0; |
2637 | } |
2638 | case XML_SCHEMAS_LANGUAGE: |
2639 | if (normOnTheFly) { |
2640 | norm = xmlSchemaCollapseString(value); |
2641 | if (norm != NULL) |
2642 | value = norm; |
2643 | } |
2644 | if (xmlCheckLanguageID(value) == 1) { |
2645 | if (val != NULL) { |
2646 | v = xmlSchemaNewValue(XML_SCHEMAS_LANGUAGE); |
2647 | if (v != NULL) { |
2648 | v->value.str = xmlStrdup(value); |
2649 | *val = v; |
2650 | } else { |
2651 | goto error; |
2652 | } |
2653 | } |
2654 | goto return0; |
2655 | } |
2656 | goto return1; |
2657 | case XML_SCHEMAS_NMTOKEN: |
2658 | if (xmlValidateNMToken(value, 1) == 0) { |
2659 | if (val != NULL) { |
2660 | v = xmlSchemaNewValue(XML_SCHEMAS_NMTOKEN); |
2661 | if (v != NULL) { |
2662 | v->value.str = xmlStrdup(value); |
2663 | *val = v; |
2664 | } else { |
2665 | goto error; |
2666 | } |
2667 | } |
2668 | goto return0; |
2669 | } |
2670 | goto return1; |
2671 | case XML_SCHEMAS_NMTOKENS: |
2672 | ret = xmlSchemaValAtomicListNode(xmlSchemaTypeNmtokenDef, |
2673 | value, val, node); |
2674 | if (ret > 0) |
2675 | ret = 0; |
2676 | else |
2677 | ret = 1; |
2678 | goto done; |
2679 | case XML_SCHEMAS_NAME: |
2680 | ret = xmlValidateName(value, 1); |
2681 | if ((ret == 0) && (val != NULL) && (value != NULL)) { |
2682 | v = xmlSchemaNewValue(XML_SCHEMAS_NAME); |
2683 | if (v != NULL) { |
2684 | const xmlChar *start = value, *end; |
2685 | while (IS_BLANK_CH(*start)) start++; |
2686 | end = start; |
2687 | while ((*end != 0) && (!IS_BLANK_CH(*end))) end++; |
2688 | v->value.str = xmlStrndup(start, end - start); |
2689 | *val = v; |
2690 | } else { |
2691 | goto error; |
2692 | } |
2693 | } |
2694 | goto done; |
2695 | case XML_SCHEMAS_QNAME:{ |
2696 | const xmlChar *uri = NULL; |
2697 | xmlChar *local = NULL; |
2698 | |
2699 | ret = xmlValidateQName(value, 1); |
2700 | if (ret != 0) |
2701 | goto done; |
2702 | if (node != NULL) { |
2703 | xmlChar *prefix; |
2704 | xmlNsPtr ns; |
2705 | |
2706 | local = xmlSplitQName2(value, &prefix); |
2707 | ns = xmlSearchNs(node->doc, node, prefix); |
2708 | if ((ns == NULL) && (prefix != NULL)) { |
2709 | xmlFree(prefix); |
2710 | if (local != NULL) |
2711 | xmlFree(local); |
2712 | goto return1; |
2713 | } |
2714 | if (ns != NULL) |
2715 | uri = ns->href; |
2716 | if (prefix != NULL) |
2717 | xmlFree(prefix); |
2718 | } |
2719 | if (val != NULL) { |
2720 | v = xmlSchemaNewValue(XML_SCHEMAS_QNAME); |
2721 | if (v == NULL) { |
2722 | if (local != NULL) |
2723 | xmlFree(local); |
2724 | goto error; |
2725 | } |
2726 | if (local != NULL) |
2727 | v->value.qname.name = local; |
2728 | else |
2729 | v->value.qname.name = xmlStrdup(value); |
2730 | if (uri != NULL) |
2731 | v->value.qname.uri = xmlStrdup(uri); |
2732 | *val = v; |
2733 | } else |
2734 | if (local != NULL) |
2735 | xmlFree(local); |
2736 | goto done; |
2737 | } |
2738 | case XML_SCHEMAS_NCNAME: |
2739 | ret = xmlValidateNCName(value, 1); |
2740 | if ((ret == 0) && (val != NULL)) { |
2741 | v = xmlSchemaNewValue(XML_SCHEMAS_NCNAME); |
2742 | if (v != NULL) { |
2743 | v->value.str = xmlStrdup(value); |
2744 | *val = v; |
2745 | } else { |
2746 | goto error; |
2747 | } |
2748 | } |
2749 | goto done; |
2750 | case XML_SCHEMAS_ID: |
2751 | ret = xmlValidateNCName(value, 1); |
2752 | if ((ret == 0) && (val != NULL)) { |
2753 | v = xmlSchemaNewValue(XML_SCHEMAS_ID); |
2754 | if (v != NULL) { |
2755 | v->value.str = xmlStrdup(value); |
2756 | *val = v; |
2757 | } else { |
2758 | goto error; |
2759 | } |
2760 | } |
2761 | if ((ret == 0) && (node != NULL) && |
2762 | (node->type == XML_ATTRIBUTE_NODE)) { |
2763 | xmlAttrPtr attr = (xmlAttrPtr) node; |
2764 | |
2765 | /* |
2766 | * NOTE: the IDness might have already be declared in the DTD |
2767 | */ |
2768 | if (attr->atype != XML_ATTRIBUTE_ID) { |
2769 | xmlIDPtr res; |
2770 | xmlChar *strip; |
2771 | |
2772 | strip = xmlSchemaStrip(value); |
2773 | if (strip != NULL) { |
2774 | res = xmlAddID(NULL, node->doc, strip, attr); |
2775 | xmlFree(strip); |
2776 | } else |
2777 | res = xmlAddID(NULL, node->doc, value, attr); |
2778 | if (res == NULL) { |
2779 | ret = 2; |
2780 | } else { |
2781 | attr->atype = XML_ATTRIBUTE_ID; |
2782 | } |
2783 | } |
2784 | } |
2785 | goto done; |
2786 | case XML_SCHEMAS_IDREF: |
2787 | ret = xmlValidateNCName(value, 1); |
2788 | if ((ret == 0) && (val != NULL)) { |
2789 | v = xmlSchemaNewValue(XML_SCHEMAS_IDREF); |
2790 | if (v == NULL) |
2791 | goto error; |
2792 | v->value.str = xmlStrdup(value); |
2793 | *val = v; |
2794 | } |
2795 | if ((ret == 0) && (node != NULL) && |
2796 | (node->type == XML_ATTRIBUTE_NODE)) { |
2797 | xmlAttrPtr attr = (xmlAttrPtr) node; |
2798 | xmlChar *strip; |
2799 | |
2800 | strip = xmlSchemaStrip(value); |
2801 | if (strip != NULL) { |
2802 | xmlAddRef(NULL, node->doc, strip, attr); |
2803 | xmlFree(strip); |
2804 | } else |
2805 | xmlAddRef(NULL, node->doc, value, attr); |
2806 | attr->atype = XML_ATTRIBUTE_IDREF; |
2807 | } |
2808 | goto done; |
2809 | case XML_SCHEMAS_IDREFS: |
2810 | ret = xmlSchemaValAtomicListNode(xmlSchemaTypeIdrefDef, |
2811 | value, val, node); |
2812 | if (ret < 0) |
2813 | ret = 2; |
2814 | else |
2815 | ret = 0; |
2816 | if ((ret == 0) && (node != NULL) && |
2817 | (node->type == XML_ATTRIBUTE_NODE)) { |
2818 | xmlAttrPtr attr = (xmlAttrPtr) node; |
2819 | |
2820 | attr->atype = XML_ATTRIBUTE_IDREFS; |
2821 | } |
2822 | goto done; |
2823 | case XML_SCHEMAS_ENTITY:{ |
2824 | xmlChar *strip; |
2825 | |
2826 | ret = xmlValidateNCName(value, 1); |
2827 | if ((node == NULL) || (node->doc == NULL)) |
2828 | ret = 3; |
2829 | if (ret == 0) { |
2830 | xmlEntityPtr ent; |
2831 | |
2832 | strip = xmlSchemaStrip(value); |
2833 | if (strip != NULL) { |
2834 | ent = xmlGetDocEntity(node->doc, strip); |
2835 | xmlFree(strip); |
2836 | } else { |
2837 | ent = xmlGetDocEntity(node->doc, value); |
2838 | } |
2839 | if ((ent == NULL) || |
2840 | (ent->etype != |
2841 | XML_EXTERNAL_GENERAL_UNPARSED_ENTITY)) |
2842 | ret = 4; |
2843 | } |
2844 | if ((ret == 0) && (val != NULL)) { |
2845 | TODO; |
2846 | } |
2847 | if ((ret == 0) && (node != NULL) && |
2848 | (node->type == XML_ATTRIBUTE_NODE)) { |
2849 | xmlAttrPtr attr = (xmlAttrPtr) node; |
2850 | |
2851 | attr->atype = XML_ATTRIBUTE_ENTITY; |
2852 | } |
2853 | goto done; |
2854 | } |
2855 | case XML_SCHEMAS_ENTITIES: |
2856 | if ((node == NULL) || (node->doc == NULL)) |
2857 | goto return3; |
2858 | ret = xmlSchemaValAtomicListNode(xmlSchemaTypeEntityDef, |
2859 | value, val, node); |
2860 | if (ret <= 0) |
2861 | ret = 1; |
2862 | else |
2863 | ret = 0; |
2864 | if ((ret == 0) && (node != NULL) && |
2865 | (node->type == XML_ATTRIBUTE_NODE)) { |
2866 | xmlAttrPtr attr = (xmlAttrPtr) node; |
2867 | |
2868 | attr->atype = XML_ATTRIBUTE_ENTITIES; |
2869 | } |
2870 | goto done; |
2871 | case XML_SCHEMAS_NOTATION:{ |
2872 | xmlChar *uri = NULL; |
2873 | xmlChar *local = NULL; |
2874 | |
2875 | ret = xmlValidateQName(value, 1); |
2876 | if ((ret == 0) && (node != NULL)) { |
2877 | xmlChar *prefix; |
2878 | |
2879 | local = xmlSplitQName2(value, &prefix); |
2880 | if (prefix != NULL) { |
2881 | xmlNsPtr ns; |
2882 | |
2883 | ns = xmlSearchNs(node->doc, node, prefix); |
2884 | if (ns == NULL) |
2885 | ret = 1; |
2886 | else if (val != NULL) |
2887 | uri = xmlStrdup(ns->href); |
2888 | } |
2889 | if ((local != NULL) && ((val == NULL) || (ret != 0))) |
2890 | xmlFree(local); |
2891 | if (prefix != NULL) |
2892 | xmlFree(prefix); |
2893 | } |
2894 | if ((node == NULL) || (node->doc == NULL)) |
2895 | ret = 3; |
2896 | if (ret == 0) { |
2897 | ret = xmlValidateNotationUse(NULL, node->doc, value); |
2898 | if (ret == 1) |
2899 | ret = 0; |
2900 | else |
2901 | ret = 1; |
2902 | } |
2903 | if ((ret == 0) && (val != NULL)) { |
2904 | v = xmlSchemaNewValue(XML_SCHEMAS_NOTATION); |
2905 | if (v != NULL) { |
2906 | if (local != NULL) |
2907 | v->value.qname.name = local; |
2908 | else |
2909 | v->value.qname.name = xmlStrdup(value); |
2910 | if (uri != NULL) |
2911 | v->value.qname.uri = uri; |
2912 | |
2913 | *val = v; |
2914 | } else { |
2915 | if (local != NULL) |
2916 | xmlFree(local); |
2917 | if (uri != NULL) |
2918 | xmlFree(uri); |
2919 | goto error; |
2920 | } |
2921 | } |
2922 | goto done; |
2923 | } |
2924 | case XML_SCHEMAS_ANYURI:{ |
2925 | if (*value != 0) { |
2926 | xmlURIPtr uri; |
2927 | xmlChar *tmpval, *cur; |
2928 | if (normOnTheFly) { |
2929 | norm = xmlSchemaCollapseString(value); |
2930 | if (norm != NULL) |
2931 | value = norm; |
2932 | } |
2933 | tmpval = xmlStrdup(value); |
2934 | for (cur = tmpval; *cur; ++cur) { |
2935 | if (*cur < 32 || *cur >= 127 || *cur == ' ' || |
2936 | *cur == '<' || *cur == '>' || *cur == '"' || |
2937 | *cur == '{' || *cur == '}' || *cur == '|' || |
2938 | *cur == '\\' || *cur == '^' || *cur == '`' || |
2939 | *cur == '\'') |
2940 | *cur = '_'; |
2941 | } |
2942 | uri = xmlParseURI((const char *) tmpval); |
2943 | xmlFree(tmpval); |
2944 | if (uri == NULL) |
2945 | goto return1; |
2946 | xmlFreeURI(uri); |
2947 | } |
2948 | |
2949 | if (val != NULL) { |
2950 | v = xmlSchemaNewValue(XML_SCHEMAS_ANYURI); |
2951 | if (v == NULL) |
2952 | goto error; |
2953 | v->value.str = xmlStrdup(value); |
2954 | *val = v; |
2955 | } |
2956 | goto return0; |
2957 | } |
2958 | case XML_SCHEMAS_HEXBINARY:{ |
2959 | const xmlChar *cur = value, *start; |
2960 | xmlChar *base; |
2961 | int total, i = 0; |
2962 | |
2963 | if (cur == NULL) |
2964 | goto return1; |
2965 | |
2966 | if (normOnTheFly) |
2967 | while IS_WSP_BLANK_CH(*cur) cur++; |
2968 | |
2969 | start = cur; |
2970 | while (((*cur >= '0') && (*cur <= '9')) || |
2971 | ((*cur >= 'A') && (*cur <= 'F')) || |
2972 | ((*cur >= 'a') && (*cur <= 'f'))) { |
2973 | i++; |
2974 | cur++; |
2975 | } |
2976 | if (normOnTheFly) |
2977 | while IS_WSP_BLANK_CH(*cur) cur++; |
2978 | |
2979 | if (*cur != 0) |
2980 | goto return1; |
2981 | if ((i % 2) != 0) |
2982 | goto return1; |
2983 | |
2984 | if (val != NULL) { |
2985 | |
2986 | v = xmlSchemaNewValue(XML_SCHEMAS_HEXBINARY); |
2987 | if (v == NULL) |
2988 | goto error; |
2989 | /* |
2990 | * Copy only the normalized piece. |
2991 | * CRITICAL TODO: Check this. |
2992 | */ |
2993 | cur = xmlStrndup(start, i); |
2994 | if (cur == NULL) { |
2995 | xmlSchemaTypeErrMemory(node, "allocating hexbin data" ); |
2996 | xmlFree(v); |
2997 | goto return1; |
2998 | } |
2999 | |
3000 | total = i / 2; /* number of octets */ |
3001 | |
3002 | base = (xmlChar *) cur; |
3003 | while (i-- > 0) { |
3004 | if (*base >= 'a') |
3005 | *base = *base - ('a' - 'A'); |
3006 | base++; |
3007 | } |
3008 | |
3009 | v->value.hex.str = (xmlChar *) cur; |
3010 | v->value.hex.total = total; |
3011 | *val = v; |
3012 | } |
3013 | goto return0; |
3014 | } |
3015 | case XML_SCHEMAS_BASE64BINARY:{ |
3016 | /* ISSUE: |
3017 | * |
3018 | * Ignore all stray characters? (yes, currently) |
3019 | * Worry about long lines? (no, currently) |
3020 | * |
3021 | * rfc2045.txt: |
3022 | * |
3023 | * "The encoded output stream must be represented in lines of |
3024 | * no more than 76 characters each. All line breaks or other |
3025 | * characters not found in Table 1 must be ignored by decoding |
3026 | * software. In base64 data, characters other than those in |
3027 | * Table 1, line breaks, and other white space probably |
3028 | * indicate a transmission error, about which a warning |
3029 | * message or even a message rejection might be appropriate |
3030 | * under some circumstances." */ |
3031 | const xmlChar *cur = value; |
3032 | xmlChar *base; |
3033 | int total, i = 0, pad = 0; |
3034 | |
3035 | if (cur == NULL) |
3036 | goto return1; |
3037 | |
3038 | for (; *cur; ++cur) { |
3039 | int decc; |
3040 | |
3041 | decc = _xmlSchemaBase64Decode(*cur); |
3042 | if (decc < 0) ; |
3043 | else if (decc < 64) |
3044 | i++; |
3045 | else |
3046 | break; |
3047 | } |
3048 | for (; *cur; ++cur) { |
3049 | int decc; |
3050 | |
3051 | decc = _xmlSchemaBase64Decode(*cur); |
3052 | if (decc < 0) ; |
3053 | else if (decc < 64) |
3054 | goto return1; |
3055 | if (decc == 64) |
3056 | pad++; |
3057 | } |
3058 | |
3059 | /* rfc2045.txt: "Special processing is performed if fewer than |
3060 | * 24 bits are available at the end of the data being encoded. |
3061 | * A full encoding quantum is always completed at the end of a |
3062 | * body. When fewer than 24 input bits are available in an |
3063 | * input group, zero bits are added (on the right) to form an |
3064 | * integral number of 6-bit groups. Padding at the end of the |
3065 | * data is performed using the "=" character. Since all |
3066 | * base64 input is an integral number of octets, only the |
3067 | * following cases can arise: (1) the final quantum of |
3068 | * encoding input is an integral multiple of 24 bits; here, |
3069 | * the final unit of encoded output will be an integral |
3070 | * multiple ofindent: Standard input:701: Warning:old style |
3071 | * assignment ambiguity in "=*". Assuming "= *" 4 characters |
3072 | * with no "=" padding, (2) the final |
3073 | * quantum of encoding input is exactly 8 bits; here, the |
3074 | * final unit of encoded output will be two characters |
3075 | * followed by two "=" padding characters, or (3) the final |
3076 | * quantum of encoding input is exactly 16 bits; here, the |
3077 | * final unit of encoded output will be three characters |
3078 | * followed by one "=" padding character." */ |
3079 | |
3080 | total = 3 * (i / 4); |
3081 | if (pad == 0) { |
3082 | if (i % 4 != 0) |
3083 | goto return1; |
3084 | } else if (pad == 1) { |
3085 | int decc; |
3086 | |
3087 | if (i % 4 != 3) |
3088 | goto return1; |
3089 | for (decc = _xmlSchemaBase64Decode(*cur); |
3090 | (decc < 0) || (decc > 63); |
3091 | decc = _xmlSchemaBase64Decode(*cur)) |
3092 | --cur; |
3093 | /* 16bits in 24bits means 2 pad bits: nnnnnn nnmmmm mmmm00*/ |
3094 | /* 00111100 -> 0x3c */ |
3095 | if (decc & ~0x3c) |
3096 | goto return1; |
3097 | total += 2; |
3098 | } else if (pad == 2) { |
3099 | int decc; |
3100 | |
3101 | if (i % 4 != 2) |
3102 | goto return1; |
3103 | for (decc = _xmlSchemaBase64Decode(*cur); |
3104 | (decc < 0) || (decc > 63); |
3105 | decc = _xmlSchemaBase64Decode(*cur)) |
3106 | --cur; |
3107 | /* 8bits in 12bits means 4 pad bits: nnnnnn nn0000 */ |
3108 | /* 00110000 -> 0x30 */ |
3109 | if (decc & ~0x30) |
3110 | goto return1; |
3111 | total += 1; |
3112 | } else |
3113 | goto return1; |
3114 | |
3115 | if (val != NULL) { |
3116 | v = xmlSchemaNewValue(XML_SCHEMAS_BASE64BINARY); |
3117 | if (v == NULL) |
3118 | goto error; |
3119 | base = |
3120 | (xmlChar *) xmlMallocAtomic((i + pad + 1) * |
3121 | sizeof(xmlChar)); |
3122 | if (base == NULL) { |
3123 | xmlSchemaTypeErrMemory(node, "allocating base64 data" ); |
3124 | xmlFree(v); |
3125 | goto return1; |
3126 | } |
3127 | v->value.base64.str = base; |
3128 | for (cur = value; *cur; ++cur) |
3129 | if (_xmlSchemaBase64Decode(*cur) >= 0) { |
3130 | *base = *cur; |
3131 | ++base; |
3132 | } |
3133 | *base = 0; |
3134 | v->value.base64.total = total; |
3135 | *val = v; |
3136 | } |
3137 | goto return0; |
3138 | } |
3139 | case XML_SCHEMAS_INTEGER: |
3140 | case XML_SCHEMAS_PINTEGER: |
3141 | case XML_SCHEMAS_NPINTEGER: |
3142 | case XML_SCHEMAS_NINTEGER: |
3143 | case XML_SCHEMAS_NNINTEGER:{ |
3144 | const xmlChar *cur = value; |
3145 | unsigned long lo, mi, hi; |
3146 | int sign = 0; |
3147 | |
3148 | if (cur == NULL) |
3149 | goto return1; |
3150 | if (normOnTheFly) |
3151 | while IS_WSP_BLANK_CH(*cur) cur++; |
3152 | if (*cur == '-') { |
3153 | sign = 1; |
3154 | cur++; |
3155 | } else if (*cur == '+') |
3156 | cur++; |
3157 | ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi); |
3158 | if (ret < 0) |
3159 | goto return1; |
3160 | if (normOnTheFly) |
3161 | while IS_WSP_BLANK_CH(*cur) cur++; |
3162 | if (*cur != 0) |
3163 | goto return1; |
3164 | if (type->builtInType == XML_SCHEMAS_NPINTEGER) { |
3165 | if ((sign == 0) && |
3166 | ((hi != 0) || (mi != 0) || (lo != 0))) |
3167 | goto return1; |
3168 | } else if (type->builtInType == XML_SCHEMAS_PINTEGER) { |
3169 | if (sign == 1) |
3170 | goto return1; |
3171 | if ((hi == 0) && (mi == 0) && (lo == 0)) |
3172 | goto return1; |
3173 | } else if (type->builtInType == XML_SCHEMAS_NINTEGER) { |
3174 | if (sign == 0) |
3175 | goto return1; |
3176 | if ((hi == 0) && (mi == 0) && (lo == 0)) |
3177 | goto return1; |
3178 | } else if (type->builtInType == XML_SCHEMAS_NNINTEGER) { |
3179 | if ((sign == 1) && |
3180 | ((hi != 0) || (mi != 0) || (lo != 0))) |
3181 | goto return1; |
3182 | } |
3183 | if (val != NULL) { |
3184 | v = xmlSchemaNewValue(type->builtInType); |
3185 | if (v != NULL) { |
3186 | if (ret == 0) |
3187 | ret++; |
3188 | v->value.decimal.lo = lo; |
3189 | v->value.decimal.mi = mi; |
3190 | v->value.decimal.hi = hi; |
3191 | v->value.decimal.sign = sign; |
3192 | v->value.decimal.frac = 0; |
3193 | v->value.decimal.total = ret; |
3194 | *val = v; |
3195 | } |
3196 | } |
3197 | goto return0; |
3198 | } |
3199 | case XML_SCHEMAS_LONG: |
3200 | case XML_SCHEMAS_BYTE: |
3201 | case XML_SCHEMAS_SHORT: |
3202 | case XML_SCHEMAS_INT:{ |
3203 | const xmlChar *cur = value; |
3204 | unsigned long lo, mi, hi; |
3205 | int sign = 0; |
3206 | |
3207 | if (cur == NULL) |
3208 | goto return1; |
3209 | if (*cur == '-') { |
3210 | sign = 1; |
3211 | cur++; |
3212 | } else if (*cur == '+') |
3213 | cur++; |
3214 | ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi); |
3215 | if (ret < 0) |
3216 | goto return1; |
3217 | if (*cur != 0) |
3218 | goto return1; |
3219 | if (type->builtInType == XML_SCHEMAS_LONG) { |
3220 | if (hi >= 922) { |
3221 | if (hi > 922) |
3222 | goto return1; |
3223 | if (mi >= 33720368) { |
3224 | if (mi > 33720368) |
3225 | goto return1; |
3226 | if ((sign == 0) && (lo > 54775807)) |
3227 | goto return1; |
3228 | if ((sign == 1) && (lo > 54775808)) |
3229 | goto return1; |
3230 | } |
3231 | } |
3232 | } else if (type->builtInType == XML_SCHEMAS_INT) { |
3233 | if (hi != 0) |
3234 | goto return1; |
3235 | if (mi >= 21) { |
3236 | if (mi > 21) |
3237 | goto return1; |
3238 | if ((sign == 0) && (lo > 47483647)) |
3239 | goto return1; |
3240 | if ((sign == 1) && (lo > 47483648)) |
3241 | goto return1; |
3242 | } |
3243 | } else if (type->builtInType == XML_SCHEMAS_SHORT) { |
3244 | if ((mi != 0) || (hi != 0)) |
3245 | goto return1; |
3246 | if ((sign == 1) && (lo > 32768)) |
3247 | goto return1; |
3248 | if ((sign == 0) && (lo > 32767)) |
3249 | goto return1; |
3250 | } else if (type->builtInType == XML_SCHEMAS_BYTE) { |
3251 | if ((mi != 0) || (hi != 0)) |
3252 | goto return1; |
3253 | if ((sign == 1) && (lo > 128)) |
3254 | goto return1; |
3255 | if ((sign == 0) && (lo > 127)) |
3256 | goto return1; |
3257 | } |
3258 | if (val != NULL) { |
3259 | v = xmlSchemaNewValue(type->builtInType); |
3260 | if (v != NULL) { |
3261 | v->value.decimal.lo = lo; |
3262 | v->value.decimal.mi = mi; |
3263 | v->value.decimal.hi = hi; |
3264 | v->value.decimal.sign = sign; |
3265 | v->value.decimal.frac = 0; |
3266 | v->value.decimal.total = ret; |
3267 | *val = v; |
3268 | } |
3269 | } |
3270 | goto return0; |
3271 | } |
3272 | case XML_SCHEMAS_UINT: |
3273 | case XML_SCHEMAS_ULONG: |
3274 | case XML_SCHEMAS_USHORT: |
3275 | case XML_SCHEMAS_UBYTE:{ |
3276 | const xmlChar *cur = value; |
3277 | unsigned long lo, mi, hi; |
3278 | |
3279 | if (cur == NULL) |
3280 | goto return1; |
3281 | ret = xmlSchemaParseUInt(&cur, &lo, &mi, &hi); |
3282 | if (ret < 0) |
3283 | goto return1; |
3284 | if (*cur != 0) |
3285 | goto return1; |
3286 | if (type->builtInType == XML_SCHEMAS_ULONG) { |
3287 | if (hi >= 1844) { |
3288 | if (hi > 1844) |
3289 | goto return1; |
3290 | if (mi >= 67440737) { |
3291 | if (mi > 67440737) |
3292 | goto return1; |
3293 | if (lo > 9551615) |
3294 | goto return1; |
3295 | } |
3296 | } |
3297 | } else if (type->builtInType == XML_SCHEMAS_UINT) { |
3298 | if (hi != 0) |
3299 | goto return1; |
3300 | if (mi >= 42) { |
3301 | if (mi > 42) |
3302 | goto return1; |
3303 | if (lo > 94967295) |
3304 | goto return1; |
3305 | } |
3306 | } else if (type->builtInType == XML_SCHEMAS_USHORT) { |
3307 | if ((mi != 0) || (hi != 0)) |
3308 | goto return1; |
3309 | if (lo > 65535) |
3310 | goto return1; |
3311 | } else if (type->builtInType == XML_SCHEMAS_UBYTE) { |
3312 | if ((mi != 0) || (hi != 0)) |
3313 | goto return1; |
3314 | if (lo > 255) |
3315 | goto return1; |
3316 | } |
3317 | if (val != NULL) { |
3318 | v = xmlSchemaNewValue(type->builtInType); |
3319 | if (v != NULL) { |
3320 | v->value.decimal.lo = lo; |
3321 | v->value.decimal.mi = mi; |
3322 | v->value.decimal.hi = hi; |
3323 | v->value.decimal.sign = 0; |
3324 | v->value.decimal.frac = 0; |
3325 | v->value.decimal.total = ret; |
3326 | *val = v; |
3327 | } |
3328 | } |
3329 | goto return0; |
3330 | } |
3331 | } |
3332 | |
3333 | done: |
3334 | if (norm != NULL) |
3335 | xmlFree(norm); |
3336 | return (ret); |
3337 | return3: |
3338 | if (norm != NULL) |
3339 | xmlFree(norm); |
3340 | return (3); |
3341 | return1: |
3342 | if (norm != NULL) |
3343 | xmlFree(norm); |
3344 | return (1); |
3345 | return0: |
3346 | if (norm != NULL) |
3347 | xmlFree(norm); |
3348 | return (0); |
3349 | error: |
3350 | if (norm != NULL) |
3351 | xmlFree(norm); |
3352 | return (-1); |
3353 | } |
3354 | |
3355 | /** |
3356 | * xmlSchemaValPredefTypeNode: |
3357 | * @type: the predefined type |
3358 | * @value: the value to check |
3359 | * @val: the return computed value |
3360 | * @node: the node containing the value |
3361 | * |
3362 | * Check that a value conforms to the lexical space of the predefined type. |
3363 | * if true a value is computed and returned in @val. |
3364 | * |
3365 | * Returns 0 if this validates, a positive error code number otherwise |
3366 | * and -1 in case of internal or API error. |
3367 | */ |
3368 | int |
3369 | xmlSchemaValPredefTypeNode(xmlSchemaTypePtr type, const xmlChar *value, |
3370 | xmlSchemaValPtr *val, xmlNodePtr node) { |
3371 | return(xmlSchemaValAtomicType(type, value, val, node, 0, |
3372 | XML_SCHEMA_WHITESPACE_UNKNOWN, 1, 1, 0)); |
3373 | } |
3374 | |
3375 | /** |
3376 | * xmlSchemaValPredefTypeNodeNoNorm: |
3377 | * @type: the predefined type |
3378 | * @value: the value to check |
3379 | * @val: the return computed value |
3380 | * @node: the node containing the value |
3381 | * |
3382 | * Check that a value conforms to the lexical space of the predefined type. |
3383 | * if true a value is computed and returned in @val. |
3384 | * This one does apply any normalization to the value. |
3385 | * |
3386 | * Returns 0 if this validates, a positive error code number otherwise |
3387 | * and -1 in case of internal or API error. |
3388 | */ |
3389 | int |
3390 | xmlSchemaValPredefTypeNodeNoNorm(xmlSchemaTypePtr type, const xmlChar *value, |
3391 | xmlSchemaValPtr *val, xmlNodePtr node) { |
3392 | return(xmlSchemaValAtomicType(type, value, val, node, 1, |
3393 | XML_SCHEMA_WHITESPACE_UNKNOWN, 1, 0, 1)); |
3394 | } |
3395 | |
3396 | /** |
3397 | * xmlSchemaValidatePredefinedType: |
3398 | * @type: the predefined type |
3399 | * @value: the value to check |
3400 | * @val: the return computed value |
3401 | * |
3402 | * Check that a value conforms to the lexical space of the predefined type. |
3403 | * if true a value is computed and returned in @val. |
3404 | * |
3405 | * Returns 0 if this validates, a positive error code number otherwise |
3406 | * and -1 in case of internal or API error. |
3407 | */ |
3408 | int |
3409 | xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value, |
3410 | xmlSchemaValPtr *val) { |
3411 | return(xmlSchemaValPredefTypeNode(type, value, val, NULL)); |
3412 | } |
3413 | |
3414 | /** |
3415 | * xmlSchemaCompareDecimals: |
3416 | * @x: a first decimal value |
3417 | * @y: a second decimal value |
3418 | * |
3419 | * Compare 2 decimals |
3420 | * |
3421 | * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error |
3422 | */ |
3423 | static int |
3424 | xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y) |
3425 | { |
3426 | xmlSchemaValPtr swp; |
3427 | int order = 1, integx, integy, dlen; |
3428 | unsigned long hi, mi, lo; |
3429 | |
3430 | /* |
3431 | * First test: If x is -ve and not zero |
3432 | */ |
3433 | if ((x->value.decimal.sign) && |
3434 | ((x->value.decimal.lo != 0) || |
3435 | (x->value.decimal.mi != 0) || |
3436 | (x->value.decimal.hi != 0))) { |
3437 | /* |
3438 | * Then if y is -ve and not zero reverse the compare |
3439 | */ |
3440 | if ((y->value.decimal.sign) && |
3441 | ((y->value.decimal.lo != 0) || |
3442 | (y->value.decimal.mi != 0) || |
3443 | (y->value.decimal.hi != 0))) |
3444 | order = -1; |
3445 | /* |
3446 | * Otherwise (y >= 0) we have the answer |
3447 | */ |
3448 | else |
3449 | return (-1); |
3450 | /* |
3451 | * If x is not -ve and y is -ve we have the answer |
3452 | */ |
3453 | } else if ((y->value.decimal.sign) && |
3454 | ((y->value.decimal.lo != 0) || |
3455 | (y->value.decimal.mi != 0) || |
3456 | (y->value.decimal.hi != 0))) { |
3457 | return (1); |
3458 | } |
3459 | /* |
3460 | * If it's not simply determined by a difference in sign, |
3461 | * then we need to compare the actual values of the two nums. |
3462 | * To do this, we start by looking at the integral parts. |
3463 | * If the number of integral digits differ, then we have our |
3464 | * answer. |
3465 | */ |
3466 | integx = x->value.decimal.total - x->value.decimal.frac; |
3467 | integy = y->value.decimal.total - y->value.decimal.frac; |
3468 | /* |
3469 | * NOTE: We changed the "total" for values like "0.1" |
3470 | * (or "-0.1" or ".1") to be 1, which was 2 previously. |
3471 | * Therefore the special case, when such values are |
3472 | * compared with 0, needs to be handled separately; |
3473 | * otherwise a zero would be recognized incorrectly as |
3474 | * greater than those values. This has the nice side effect |
3475 | * that we gain an overall optimized comparison with zeroes. |
3476 | * Note that a "0" has a "total" of 1 already. |
3477 | */ |
3478 | if (integx == 1) { |
3479 | if (x->value.decimal.lo == 0) { |
3480 | if (integy != 1) |
3481 | return -order; |
3482 | else if (y->value.decimal.lo != 0) |
3483 | return -order; |
3484 | else |
3485 | return(0); |
3486 | } |
3487 | } |
3488 | if (integy == 1) { |
3489 | if (y->value.decimal.lo == 0) { |
3490 | if (integx != 1) |
3491 | return order; |
3492 | else if (x->value.decimal.lo != 0) |
3493 | return order; |
3494 | else |
3495 | return(0); |
3496 | } |
3497 | } |
3498 | |
3499 | if (integx > integy) |
3500 | return order; |
3501 | else if (integy > integx) |
3502 | return -order; |
3503 | |
3504 | /* |
3505 | * If the number of integral digits is the same for both numbers, |
3506 | * then things get a little more complicated. We need to "normalize" |
3507 | * the numbers in order to properly compare them. To do this, we |
3508 | * look at the total length of each number (length => number of |
3509 | * significant digits), and divide the "shorter" by 10 (decreasing |
3510 | * the length) until they are of equal length. |
3511 | */ |
3512 | dlen = x->value.decimal.total - y->value.decimal.total; |
3513 | if (dlen < 0) { /* y has more digits than x */ |
3514 | swp = x; |
3515 | hi = y->value.decimal.hi; |
3516 | mi = y->value.decimal.mi; |
3517 | lo = y->value.decimal.lo; |
3518 | dlen = -dlen; |
3519 | order = -order; |
3520 | } else { /* x has more digits than y */ |
3521 | swp = y; |
3522 | hi = x->value.decimal.hi; |
3523 | mi = x->value.decimal.mi; |
3524 | lo = x->value.decimal.lo; |
3525 | } |
3526 | while (dlen > 8) { /* in effect, right shift by 10**8 */ |
3527 | lo = mi; |
3528 | mi = hi; |
3529 | hi = 0; |
3530 | dlen -= 8; |
3531 | } |
3532 | while (dlen > 0) { |
3533 | unsigned long rem1, rem2; |
3534 | rem1 = (hi % 10) * 100000000L; |
3535 | hi = hi / 10; |
3536 | rem2 = (mi % 10) * 100000000L; |
3537 | mi = (mi + rem1) / 10; |
3538 | lo = (lo + rem2) / 10; |
3539 | dlen--; |
3540 | } |
3541 | if (hi > swp->value.decimal.hi) { |
3542 | return order; |
3543 | } else if (hi == swp->value.decimal.hi) { |
3544 | if (mi > swp->value.decimal.mi) { |
3545 | return order; |
3546 | } else if (mi == swp->value.decimal.mi) { |
3547 | if (lo > swp->value.decimal.lo) { |
3548 | return order; |
3549 | } else if (lo == swp->value.decimal.lo) { |
3550 | if (x->value.decimal.total == y->value.decimal.total) { |
3551 | return 0; |
3552 | } else { |
3553 | return order; |
3554 | } |
3555 | } |
3556 | } |
3557 | } |
3558 | return -order; |
3559 | } |
3560 | |
3561 | /** |
3562 | * xmlSchemaCompareDurations: |
3563 | * @x: a first duration value |
3564 | * @y: a second duration value |
3565 | * |
3566 | * Compare 2 durations |
3567 | * |
3568 | * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in |
3569 | * case of error |
3570 | */ |
3571 | static int |
3572 | xmlSchemaCompareDurations(xmlSchemaValPtr x, xmlSchemaValPtr y) |
3573 | { |
3574 | long carry, mon, day; |
3575 | double sec; |
3576 | int invert = 1; |
3577 | long xmon, xday, myear, minday, maxday; |
3578 | static const long dayRange [2][12] = { |
3579 | { 0, 28, 59, 89, 120, 150, 181, 212, 242, 273, 303, 334, }, |
3580 | { 0, 31, 62, 92, 123, 153, 184, 215, 245, 276, 306, 337} }; |
3581 | |
3582 | if ((x == NULL) || (y == NULL)) |
3583 | return -2; |
3584 | |
3585 | /* months */ |
3586 | mon = x->value.dur.mon - y->value.dur.mon; |
3587 | |
3588 | /* seconds */ |
3589 | sec = x->value.dur.sec - y->value.dur.sec; |
3590 | carry = (long)(sec / SECS_PER_DAY); |
3591 | sec -= ((double)carry) * SECS_PER_DAY; |
3592 | |
3593 | /* days */ |
3594 | day = x->value.dur.day - y->value.dur.day + carry; |
3595 | |
3596 | /* easy test */ |
3597 | if (mon == 0) { |
3598 | if (day == 0) |
3599 | if (sec == 0.0) |
3600 | return 0; |
3601 | else if (sec < 0.0) |
3602 | return -1; |
3603 | else |
3604 | return 1; |
3605 | else if (day < 0) |
3606 | return -1; |
3607 | else |
3608 | return 1; |
3609 | } |
3610 | |
3611 | if (mon > 0) { |
3612 | if ((day >= 0) && (sec >= 0.0)) |
3613 | return 1; |
3614 | else { |
3615 | xmon = mon; |
3616 | xday = -day; |
3617 | } |
3618 | } else if ((day <= 0) && (sec <= 0.0)) { |
3619 | return -1; |
3620 | } else { |
3621 | invert = -1; |
3622 | xmon = -mon; |
3623 | xday = day; |
3624 | } |
3625 | |
3626 | myear = xmon / 12; |
3627 | if (myear == 0) { |
3628 | minday = 0; |
3629 | maxday = 0; |
3630 | } else { |
3631 | maxday = 366 * ((myear + 3) / 4) + |
3632 | 365 * ((myear - 1) % 4); |
3633 | minday = maxday - 1; |
3634 | } |
3635 | |
3636 | xmon = xmon % 12; |
3637 | minday += dayRange[0][xmon]; |
3638 | maxday += dayRange[1][xmon]; |
3639 | |
3640 | if ((maxday == minday) && (maxday == xday)) |
3641 | return(0); /* can this really happen ? */ |
3642 | if (maxday < xday) |
3643 | return(-invert); |
3644 | if (minday > xday) |
3645 | return(invert); |
3646 | |
3647 | /* indeterminate */ |
3648 | return 2; |
3649 | } |
3650 | |
3651 | /* |
3652 | * macros for adding date/times and durations |
3653 | */ |
3654 | #define FQUOTIENT(a,b) (floor(((double)a/(double)b))) |
3655 | #define MODULO(a,b) (a - FQUOTIENT(a,b) * b) |
3656 | #define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low))) |
3657 | #define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low) |
3658 | |
3659 | /** |
3660 | * xmlSchemaDupVal: |
3661 | * @v: the #xmlSchemaValPtr value to duplicate |
3662 | * |
3663 | * Makes a copy of @v. The calling program is responsible for freeing |
3664 | * the returned value. |
3665 | * |
3666 | * returns a pointer to a duplicated #xmlSchemaValPtr or NULL if error. |
3667 | */ |
3668 | static xmlSchemaValPtr |
3669 | xmlSchemaDupVal (xmlSchemaValPtr v) |
3670 | { |
3671 | xmlSchemaValPtr ret = xmlSchemaNewValue(v->type); |
3672 | if (ret == NULL) |
3673 | return NULL; |
3674 | |
3675 | memcpy(ret, v, sizeof(xmlSchemaVal)); |
3676 | ret->next = NULL; |
3677 | return ret; |
3678 | } |
3679 | |
3680 | /** |
3681 | * xmlSchemaCopyValue: |
3682 | * @val: the precomputed value to be copied |
3683 | * |
3684 | * Copies the precomputed value. This duplicates any string within. |
3685 | * |
3686 | * Returns the copy or NULL if a copy for a data-type is not implemented. |
3687 | */ |
3688 | xmlSchemaValPtr |
3689 | xmlSchemaCopyValue(xmlSchemaValPtr val) |
3690 | { |
3691 | xmlSchemaValPtr ret = NULL, prev = NULL, cur; |
3692 | |
3693 | /* |
3694 | * Copy the string values. |
3695 | */ |
3696 | while (val != NULL) { |
3697 | switch (val->type) { |
3698 | case XML_SCHEMAS_ANYTYPE: |
3699 | case XML_SCHEMAS_IDREFS: |
3700 | case XML_SCHEMAS_ENTITIES: |
3701 | case XML_SCHEMAS_NMTOKENS: |
3702 | xmlSchemaFreeValue(ret); |
3703 | return (NULL); |
3704 | case XML_SCHEMAS_ANYSIMPLETYPE: |
3705 | case XML_SCHEMAS_STRING: |
3706 | case XML_SCHEMAS_NORMSTRING: |
3707 | case XML_SCHEMAS_TOKEN: |
3708 | case XML_SCHEMAS_LANGUAGE: |
3709 | case XML_SCHEMAS_NAME: |
3710 | case XML_SCHEMAS_NCNAME: |
3711 | case XML_SCHEMAS_ID: |
3712 | case XML_SCHEMAS_IDREF: |
3713 | case XML_SCHEMAS_ENTITY: |
3714 | case XML_SCHEMAS_NMTOKEN: |
3715 | case XML_SCHEMAS_ANYURI: |
3716 | cur = xmlSchemaDupVal(val); |
3717 | if (val->value.str != NULL) |
3718 | cur->value.str = xmlStrdup(BAD_CAST val->value.str); |
3719 | break; |
3720 | case XML_SCHEMAS_QNAME: |
3721 | case XML_SCHEMAS_NOTATION: |
3722 | cur = xmlSchemaDupVal(val); |
3723 | if (val->value.qname.name != NULL) |
3724 | cur->value.qname.name = |
3725 | xmlStrdup(BAD_CAST val->value.qname.name); |
3726 | if (val->value.qname.uri != NULL) |
3727 | cur->value.qname.uri = |
3728 | xmlStrdup(BAD_CAST val->value.qname.uri); |
3729 | break; |
3730 | case XML_SCHEMAS_HEXBINARY: |
3731 | cur = xmlSchemaDupVal(val); |
3732 | if (val->value.hex.str != NULL) |
3733 | cur->value.hex.str = xmlStrdup(BAD_CAST val->value.hex.str); |
3734 | break; |
3735 | case XML_SCHEMAS_BASE64BINARY: |
3736 | cur = xmlSchemaDupVal(val); |
3737 | if (val->value.base64.str != NULL) |
3738 | cur->value.base64.str = |
3739 | xmlStrdup(BAD_CAST val->value.base64.str); |
3740 | break; |
3741 | default: |
3742 | cur = xmlSchemaDupVal(val); |
3743 | break; |
3744 | } |
3745 | if (ret == NULL) |
3746 | ret = cur; |
3747 | else |
3748 | prev->next = cur; |
3749 | prev = cur; |
3750 | val = val->next; |
3751 | } |
3752 | return (ret); |
3753 | } |
3754 | |
3755 | /** |
3756 | * _xmlSchemaDateAdd: |
3757 | * @dt: an #xmlSchemaValPtr |
3758 | * @dur: an #xmlSchemaValPtr of type #XS_DURATION |
3759 | * |
3760 | * Compute a new date/time from @dt and @dur. This function assumes @dt |
3761 | * is either #XML_SCHEMAS_DATETIME, #XML_SCHEMAS_DATE, #XML_SCHEMAS_GYEARMONTH, |
3762 | * or #XML_SCHEMAS_GYEAR. The returned #xmlSchemaVal is the same type as |
3763 | * @dt. The calling program is responsible for freeing the returned value. |
3764 | * |
3765 | * Returns a pointer to a new #xmlSchemaVal or NULL if error. |
3766 | */ |
3767 | static xmlSchemaValPtr |
3768 | _xmlSchemaDateAdd (xmlSchemaValPtr dt, xmlSchemaValPtr dur) |
3769 | { |
3770 | xmlSchemaValPtr ret, tmp; |
3771 | long carry, tempdays, temp; |
3772 | xmlSchemaValDatePtr r, d; |
3773 | xmlSchemaValDurationPtr u; |
3774 | |
3775 | if ((dt == NULL) || (dur == NULL)) |
3776 | return NULL; |
3777 | |
3778 | ret = xmlSchemaNewValue(dt->type); |
3779 | if (ret == NULL) |
3780 | return NULL; |
3781 | |
3782 | /* make a copy so we don't alter the original value */ |
3783 | tmp = xmlSchemaDupVal(dt); |
3784 | if (tmp == NULL) { |
3785 | xmlSchemaFreeValue(ret); |
3786 | return NULL; |
3787 | } |
3788 | |
3789 | r = &(ret->value.date); |
3790 | d = &(tmp->value.date); |
3791 | u = &(dur->value.dur); |
3792 | |
3793 | /* normalization */ |
3794 | if (d->mon == 0) |
3795 | d->mon = 1; |
3796 | |
3797 | /* normalize for time zone offset */ |
3798 | u->sec -= (d->tzo * 60); |
3799 | d->tzo = 0; |
3800 | |
3801 | /* normalization */ |
3802 | if (d->day == 0) |
3803 | d->day = 1; |
3804 | |
3805 | /* month */ |
3806 | carry = d->mon + u->mon; |
3807 | r->mon = (unsigned int) MODULO_RANGE(carry, 1, 13); |
3808 | carry = (long) FQUOTIENT_RANGE(carry, 1, 13); |
3809 | |
3810 | /* year (may be modified later) */ |
3811 | r->year = d->year + carry; |
3812 | if (r->year == 0) { |
3813 | if (d->year > 0) |
3814 | r->year--; |
3815 | else |
3816 | r->year++; |
3817 | } |
3818 | |
3819 | /* time zone */ |
3820 | r->tzo = d->tzo; |
3821 | r->tz_flag = d->tz_flag; |
3822 | |
3823 | /* seconds */ |
3824 | r->sec = d->sec + u->sec; |
3825 | carry = (long) FQUOTIENT((long)r->sec, 60); |
3826 | if (r->sec != 0.0) { |
3827 | r->sec = MODULO(r->sec, 60.0); |
3828 | } |
3829 | |
3830 | /* minute */ |
3831 | carry += d->min; |
3832 | r->min = (unsigned int) MODULO(carry, 60); |
3833 | carry = (long) FQUOTIENT(carry, 60); |
3834 | |
3835 | /* hours */ |
3836 | carry += d->hour; |
3837 | r->hour = (unsigned int) MODULO(carry, 24); |
3838 | carry = (long)FQUOTIENT(carry, 24); |
3839 | |
3840 | /* |
3841 | * days |
3842 | * Note we use tempdays because the temporary values may need more |
3843 | * than 5 bits |
3844 | */ |
3845 | if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) && |
3846 | (d->day > MAX_DAYINMONTH(r->year, r->mon))) |
3847 | tempdays = MAX_DAYINMONTH(r->year, r->mon); |
3848 | else if (d->day < 1) |
3849 | tempdays = 1; |
3850 | else |
3851 | tempdays = d->day; |
3852 | |
3853 | tempdays += u->day + carry; |
3854 | |
3855 | while (1) { |
3856 | if (tempdays < 1) { |
3857 | long tmon = (long) MODULO_RANGE((int)r->mon-1, 1, 13); |
3858 | long tyr = r->year + (long)FQUOTIENT_RANGE((int)r->mon-1, 1, 13); |
3859 | if (tyr == 0) |
3860 | tyr--; |
3861 | /* |
3862 | * Coverity detected an overrun in daysInMonth |
3863 | * of size 12 at position 12 with index variable "((r)->mon - 1)" |
3864 | */ |
3865 | if (tmon < 1) |
3866 | tmon = 1; |
3867 | if (tmon > 12) |
3868 | tmon = 12; |
3869 | tempdays += MAX_DAYINMONTH(tyr, tmon); |
3870 | carry = -1; |
3871 | } else if (VALID_YEAR(r->year) && VALID_MONTH(r->mon) && |
3872 | tempdays > (long) MAX_DAYINMONTH(r->year, r->mon)) { |
3873 | tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon); |
3874 | carry = 1; |
3875 | } else |
3876 | break; |
3877 | |
3878 | temp = r->mon + carry; |
3879 | r->mon = (unsigned int) MODULO_RANGE(temp, 1, 13); |
3880 | r->year = r->year + (unsigned int) FQUOTIENT_RANGE(temp, 1, 13); |
3881 | if (r->year == 0) { |
3882 | if (temp < 1) |
3883 | r->year--; |
3884 | else |
3885 | r->year++; |
3886 | } |
3887 | } |
3888 | |
3889 | r->day = tempdays; |
3890 | |
3891 | /* |
3892 | * adjust the date/time type to the date values |
3893 | */ |
3894 | if (ret->type != XML_SCHEMAS_DATETIME) { |
3895 | if ((r->hour) || (r->min) || (r->sec)) |
3896 | ret->type = XML_SCHEMAS_DATETIME; |
3897 | else if (ret->type != XML_SCHEMAS_DATE) { |
3898 | if ((r->mon != 1) && (r->day != 1)) |
3899 | ret->type = XML_SCHEMAS_DATE; |
3900 | else if ((ret->type != XML_SCHEMAS_GYEARMONTH) && (r->mon != 1)) |
3901 | ret->type = XML_SCHEMAS_GYEARMONTH; |
3902 | } |
3903 | } |
3904 | |
3905 | xmlSchemaFreeValue(tmp); |
3906 | |
3907 | return ret; |
3908 | } |
3909 | |
3910 | /** |
3911 | * xmlSchemaDateNormalize: |
3912 | * @dt: an #xmlSchemaValPtr of a date/time type value. |
3913 | * @offset: number of seconds to adjust @dt by. |
3914 | * |
3915 | * Normalize @dt to GMT time. The @offset parameter is subtracted from |
3916 | * the return value is a time-zone offset is present on @dt. |
3917 | * |
3918 | * Returns a normalized copy of @dt or NULL if error. |
3919 | */ |
3920 | static xmlSchemaValPtr |
3921 | xmlSchemaDateNormalize (xmlSchemaValPtr dt, double offset) |
3922 | { |
3923 | xmlSchemaValPtr dur, ret; |
3924 | |
3925 | if (dt == NULL) |
3926 | return NULL; |
3927 | |
3928 | if (((dt->type != XML_SCHEMAS_TIME) && |
3929 | (dt->type != XML_SCHEMAS_DATETIME) && |
3930 | (dt->type != XML_SCHEMAS_DATE)) || (dt->value.date.tzo == 0)) |
3931 | return xmlSchemaDupVal(dt); |
3932 | |
3933 | dur = xmlSchemaNewValue(XML_SCHEMAS_DURATION); |
3934 | if (dur == NULL) |
3935 | return NULL; |
3936 | |
3937 | dur->value.date.sec -= offset; |
3938 | |
3939 | ret = _xmlSchemaDateAdd(dt, dur); |
3940 | if (ret == NULL) |
3941 | return NULL; |
3942 | |
3943 | xmlSchemaFreeValue(dur); |
3944 | |
3945 | /* ret->value.date.tzo = 0; */ |
3946 | return ret; |
3947 | } |
3948 | |
3949 | /** |
3950 | * _xmlSchemaDateCastYMToDays: |
3951 | * @dt: an #xmlSchemaValPtr |
3952 | * |
3953 | * Convert mon and year of @dt to total number of days. Take the |
3954 | * number of years since (or before) 1 AD and add the number of leap |
3955 | * years. This is a function because negative |
3956 | * years must be handled a little differently and there is no zero year. |
3957 | * |
3958 | * Returns number of days. |
3959 | */ |
3960 | static long |
3961 | _xmlSchemaDateCastYMToDays (const xmlSchemaValPtr dt) |
3962 | { |
3963 | long ret; |
3964 | int mon; |
3965 | |
3966 | mon = dt->value.date.mon; |
3967 | if (mon <= 0) mon = 1; /* normalization */ |
3968 | |
3969 | if (dt->value.date.year <= 0) |
3970 | ret = (dt->value.date.year * 365) + |
3971 | (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+ |
3972 | ((dt->value.date.year+1)/400)) + |
3973 | DAY_IN_YEAR(0, mon, dt->value.date.year); |
3974 | else |
3975 | ret = ((dt->value.date.year-1) * 365) + |
3976 | (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+ |
3977 | ((dt->value.date.year-1)/400)) + |
3978 | DAY_IN_YEAR(0, mon, dt->value.date.year); |
3979 | |
3980 | return ret; |
3981 | } |
3982 | |
3983 | /** |
3984 | * TIME_TO_NUMBER: |
3985 | * @dt: an #xmlSchemaValPtr |
3986 | * |
3987 | * Calculates the number of seconds in the time portion of @dt. |
3988 | * |
3989 | * Returns seconds. |
3990 | */ |
3991 | #define TIME_TO_NUMBER(dt) \ |
3992 | ((double)((dt->value.date.hour * SECS_PER_HOUR) + \ |
3993 | (dt->value.date.min * SECS_PER_MIN) + \ |
3994 | (dt->value.date.tzo * SECS_PER_MIN)) + \ |
3995 | dt->value.date.sec) |
3996 | |
3997 | /** |
3998 | * xmlSchemaCompareDates: |
3999 | * @x: a first date/time value |
4000 | * @y: a second date/time value |
4001 | * |
4002 | * Compare 2 date/times |
4003 | * |
4004 | * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in |
4005 | * case of error |
4006 | */ |
4007 | static int |
4008 | xmlSchemaCompareDates (xmlSchemaValPtr x, xmlSchemaValPtr y) |
4009 | { |
4010 | unsigned char xmask, ymask, xor_mask, and_mask; |
4011 | xmlSchemaValPtr p1, p2, q1, q2; |
4012 | long p1d, p2d, q1d, q2d; |
4013 | |
4014 | if ((x == NULL) || (y == NULL)) |
4015 | return -2; |
4016 | |
4017 | if (x->value.date.tz_flag) { |
4018 | |
4019 | if (!y->value.date.tz_flag) { |
4020 | p1 = xmlSchemaDateNormalize(x, 0); |
4021 | p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day; |
4022 | /* normalize y + 14:00 */ |
4023 | q1 = xmlSchemaDateNormalize(y, (14 * SECS_PER_HOUR)); |
4024 | |
4025 | q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day; |
4026 | if (p1d < q1d) { |
4027 | xmlSchemaFreeValue(p1); |
4028 | xmlSchemaFreeValue(q1); |
4029 | return -1; |
4030 | } else if (p1d == q1d) { |
4031 | double sec; |
4032 | |
4033 | sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1); |
4034 | if (sec < 0.0) { |
4035 | xmlSchemaFreeValue(p1); |
4036 | xmlSchemaFreeValue(q1); |
4037 | return -1; |
4038 | } else { |
4039 | int ret = 0; |
4040 | /* normalize y - 14:00 */ |
4041 | q2 = xmlSchemaDateNormalize(y, -(14 * SECS_PER_HOUR)); |
4042 | q2d = _xmlSchemaDateCastYMToDays(q2) + q2->value.date.day; |
4043 | if (p1d > q2d) |
4044 | ret = 1; |
4045 | else if (p1d == q2d) { |
4046 | sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q2); |
4047 | if (sec > 0.0) |
4048 | ret = 1; |
4049 | else |
4050 | ret = 2; /* indeterminate */ |
4051 | } |
4052 | xmlSchemaFreeValue(p1); |
4053 | xmlSchemaFreeValue(q1); |
4054 | xmlSchemaFreeValue(q2); |
4055 | if (ret != 0) |
4056 | return(ret); |
4057 | } |
4058 | } else { |
4059 | xmlSchemaFreeValue(p1); |
4060 | xmlSchemaFreeValue(q1); |
4061 | } |
4062 | } |
4063 | } else if (y->value.date.tz_flag) { |
4064 | q1 = xmlSchemaDateNormalize(y, 0); |
4065 | q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day; |
4066 | |
4067 | /* normalize x - 14:00 */ |
4068 | p1 = xmlSchemaDateNormalize(x, -(14 * SECS_PER_HOUR)); |
4069 | p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day; |
4070 | |
4071 | if (p1d < q1d) { |
4072 | xmlSchemaFreeValue(p1); |
4073 | xmlSchemaFreeValue(q1); |
4074 | return -1; |
4075 | } else if (p1d == q1d) { |
4076 | double sec; |
4077 | |
4078 | sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1); |
4079 | if (sec < 0.0) { |
4080 | xmlSchemaFreeValue(p1); |
4081 | xmlSchemaFreeValue(q1); |
4082 | return -1; |
4083 | } else { |
4084 | int ret = 0; |
4085 | /* normalize x + 14:00 */ |
4086 | p2 = xmlSchemaDateNormalize(x, (14 * SECS_PER_HOUR)); |
4087 | p2d = _xmlSchemaDateCastYMToDays(p2) + p2->value.date.day; |
4088 | |
4089 | if (p2d > q1d) { |
4090 | ret = 1; |
4091 | } else if (p2d == q1d) { |
4092 | sec = TIME_TO_NUMBER(p2) - TIME_TO_NUMBER(q1); |
4093 | if (sec > 0.0) |
4094 | ret = 1; |
4095 | else |
4096 | ret = 2; /* indeterminate */ |
4097 | } |
4098 | xmlSchemaFreeValue(p1); |
4099 | xmlSchemaFreeValue(q1); |
4100 | xmlSchemaFreeValue(p2); |
4101 | if (ret != 0) |
4102 | return(ret); |
4103 | } |
4104 | } else { |
4105 | xmlSchemaFreeValue(p1); |
4106 | xmlSchemaFreeValue(q1); |
4107 | } |
4108 | } |
4109 | |
4110 | /* |
4111 | * if the same type then calculate the difference |
4112 | */ |
4113 | if (x->type == y->type) { |
4114 | int ret = 0; |
4115 | q1 = xmlSchemaDateNormalize(y, 0); |
4116 | q1d = _xmlSchemaDateCastYMToDays(q1) + q1->value.date.day; |
4117 | |
4118 | p1 = xmlSchemaDateNormalize(x, 0); |
4119 | p1d = _xmlSchemaDateCastYMToDays(p1) + p1->value.date.day; |
4120 | |
4121 | if (p1d < q1d) { |
4122 | ret = -1; |
4123 | } else if (p1d > q1d) { |
4124 | ret = 1; |
4125 | } else { |
4126 | double sec; |
4127 | |
4128 | sec = TIME_TO_NUMBER(p1) - TIME_TO_NUMBER(q1); |
4129 | if (sec < 0.0) |
4130 | ret = -1; |
4131 | else if (sec > 0.0) |
4132 | ret = 1; |
4133 | |
4134 | } |
4135 | xmlSchemaFreeValue(p1); |
4136 | xmlSchemaFreeValue(q1); |
4137 | return(ret); |
4138 | } |
4139 | |
4140 | switch (x->type) { |
4141 | case XML_SCHEMAS_DATETIME: |
4142 | xmask = 0xf; |
4143 | break; |
4144 | case XML_SCHEMAS_DATE: |
4145 | xmask = 0x7; |
4146 | break; |
4147 | case XML_SCHEMAS_GYEAR: |
4148 | xmask = 0x1; |
4149 | break; |
4150 | case XML_SCHEMAS_GMONTH: |
4151 | xmask = 0x2; |
4152 | break; |
4153 | case XML_SCHEMAS_GDAY: |
4154 | xmask = 0x3; |
4155 | break; |
4156 | case XML_SCHEMAS_GYEARMONTH: |
4157 | xmask = 0x3; |
4158 | break; |
4159 | case XML_SCHEMAS_GMONTHDAY: |
4160 | xmask = 0x6; |
4161 | break; |
4162 | case XML_SCHEMAS_TIME: |
4163 | xmask = 0x8; |
4164 | break; |
4165 | default: |
4166 | xmask = 0; |
4167 | break; |
4168 | } |
4169 | |
4170 | switch (y->type) { |
4171 | case XML_SCHEMAS_DATETIME: |
4172 | ymask = 0xf; |
4173 | break; |
4174 | case XML_SCHEMAS_DATE: |
4175 | ymask = 0x7; |
4176 | break; |
4177 | case XML_SCHEMAS_GYEAR: |
4178 | ymask = 0x1; |
4179 | break; |
4180 | case XML_SCHEMAS_GMONTH: |
4181 | ymask = 0x2; |
4182 | break; |
4183 | case XML_SCHEMAS_GDAY: |
4184 | ymask = 0x3; |
4185 | break; |
4186 | case XML_SCHEMAS_GYEARMONTH: |
4187 | ymask = 0x3; |
4188 | break; |
4189 | case XML_SCHEMAS_GMONTHDAY: |
4190 | ymask = 0x6; |
4191 | break; |
4192 | case XML_SCHEMAS_TIME: |
4193 | ymask = 0x8; |
4194 | break; |
4195 | default: |
4196 | ymask = 0; |
4197 | break; |
4198 | } |
4199 | |
4200 | xor_mask = xmask ^ ymask; /* mark type differences */ |
4201 | and_mask = xmask & ymask; /* mark field specification */ |
4202 | |
4203 | /* year */ |
4204 | if (xor_mask & 1) |
4205 | return 2; /* indeterminate */ |
4206 | else if (and_mask & 1) { |
4207 | if (x->value.date.year < y->value.date.year) |
4208 | return -1; |
4209 | else if (x->value.date.year > y->value.date.year) |
4210 | return 1; |
4211 | } |
4212 | |
4213 | /* month */ |
4214 | if (xor_mask & 2) |
4215 | return 2; /* indeterminate */ |
4216 | else if (and_mask & 2) { |
4217 | if (x->value.date.mon < y->value.date.mon) |
4218 | return -1; |
4219 | else if (x->value.date.mon > y->value.date.mon) |
4220 | return 1; |
4221 | } |
4222 | |
4223 | /* day */ |
4224 | if (xor_mask & 4) |
4225 | return 2; /* indeterminate */ |
4226 | else if (and_mask & 4) { |
4227 | if (x->value.date.day < y->value.date.day) |
4228 | return -1; |
4229 | else if (x->value.date.day > y->value.date.day) |
4230 | return 1; |
4231 | } |
4232 | |
4233 | /* time */ |
4234 | if (xor_mask & 8) |
4235 | return 2; /* indeterminate */ |
4236 | else if (and_mask & 8) { |
4237 | if (x->value.date.hour < y->value.date.hour) |
4238 | return -1; |
4239 | else if (x->value.date.hour > y->value.date.hour) |
4240 | return 1; |
4241 | else if (x->value.date.min < y->value.date.min) |
4242 | return -1; |
4243 | else if (x->value.date.min > y->value.date.min) |
4244 | return 1; |
4245 | else if (x->value.date.sec < y->value.date.sec) |
4246 | return -1; |
4247 | else if (x->value.date.sec > y->value.date.sec) |
4248 | return 1; |
4249 | } |
4250 | |
4251 | return 0; |
4252 | } |
4253 | |
4254 | /** |
4255 | * xmlSchemaComparePreserveReplaceStrings: |
4256 | * @x: a first string value |
4257 | * @y: a second string value |
4258 | * @invert: inverts the result if x < y or x > y. |
4259 | * |
4260 | * Compare 2 string for their normalized values. |
4261 | * @x is a string with whitespace of "preserve", @y is |
4262 | * a string with a whitespace of "replace". I.e. @x could |
4263 | * be an "xsd:string" and @y an "xsd:normalizedString". |
4264 | * |
4265 | * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in |
4266 | * case of error |
4267 | */ |
4268 | static int |
4269 | xmlSchemaComparePreserveReplaceStrings(const xmlChar *x, |
4270 | const xmlChar *y, |
4271 | int invert) |
4272 | { |
4273 | int tmp; |
4274 | |
4275 | while ((*x != 0) && (*y != 0)) { |
4276 | if (IS_WSP_REPLACE_CH(*y)) { |
4277 | if (! IS_WSP_SPACE_CH(*x)) { |
4278 | if ((*x - 0x20) < 0) { |
4279 | if (invert) |
4280 | return(1); |
4281 | else |
4282 | return(-1); |
4283 | } else { |
4284 | if (invert) |
4285 | return(-1); |
4286 | else |
4287 | return(1); |
4288 | } |
4289 | } |
4290 | } else { |
4291 | tmp = *x - *y; |
4292 | if (tmp < 0) { |
4293 | if (invert) |
4294 | return(1); |
4295 | else |
4296 | return(-1); |
4297 | } |
4298 | if (tmp > 0) { |
4299 | if (invert) |
4300 | return(-1); |
4301 | else |
4302 | return(1); |
4303 | } |
4304 | } |
4305 | x++; |
4306 | y++; |
4307 | } |
4308 | if (*x != 0) { |
4309 | if (invert) |
4310 | return(-1); |
4311 | else |
4312 | return(1); |
4313 | } |
4314 | if (*y != 0) { |
4315 | if (invert) |
4316 | return(1); |
4317 | else |
4318 | return(-1); |
4319 | } |
4320 | return(0); |
4321 | } |
4322 | |
4323 | /** |
4324 | * xmlSchemaComparePreserveCollapseStrings: |
4325 | * @x: a first string value |
4326 | * @y: a second string value |
4327 | * |
4328 | * Compare 2 string for their normalized values. |
4329 | * @x is a string with whitespace of "preserve", @y is |
4330 | * a string with a whitespace of "collapse". I.e. @x could |
4331 | * be an "xsd:string" and @y an "xsd:normalizedString". |
4332 | * |
4333 | * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in |
4334 | * case of error |
4335 | */ |
4336 | static int |
4337 | xmlSchemaComparePreserveCollapseStrings(const xmlChar *x, |
4338 | const xmlChar *y, |
4339 | int invert) |
4340 | { |
4341 | int tmp; |
4342 | |
4343 | /* |
4344 | * Skip leading blank chars of the collapsed string. |
4345 | */ |
4346 | while IS_WSP_BLANK_CH(*y) |
4347 | y++; |
4348 | |
4349 | while ((*x != 0) && (*y != 0)) { |
4350 | if IS_WSP_BLANK_CH(*y) { |
4351 | if (! IS_WSP_SPACE_CH(*x)) { |
4352 | /* |
4353 | * The yv character would have been replaced to 0x20. |
4354 | */ |
4355 | if ((*x - 0x20) < 0) { |
4356 | if (invert) |
4357 | return(1); |
4358 | else |
4359 | return(-1); |
4360 | } else { |
4361 | if (invert) |
4362 | return(-1); |
4363 | else |
4364 | return(1); |
4365 | } |
4366 | } |
4367 | x++; |
4368 | y++; |
4369 | /* |
4370 | * Skip contiguous blank chars of the collapsed string. |
4371 | */ |
4372 | while IS_WSP_BLANK_CH(*y) |
4373 | y++; |
4374 | } else { |
4375 | tmp = *x++ - *y++; |
4376 | if (tmp < 0) { |
4377 | if (invert) |
4378 | return(1); |
4379 | else |
4380 | return(-1); |
4381 | } |
4382 | if (tmp > 0) { |
4383 | if (invert) |
4384 | return(-1); |
4385 | else |
4386 | return(1); |
4387 | } |
4388 | } |
4389 | } |
4390 | if (*x != 0) { |
4391 | if (invert) |
4392 | return(-1); |
4393 | else |
4394 | return(1); |
4395 | } |
4396 | if (*y != 0) { |
4397 | /* |
4398 | * Skip trailing blank chars of the collapsed string. |
4399 | */ |
4400 | while IS_WSP_BLANK_CH(*y) |
4401 | y++; |
4402 | if (*y != 0) { |
4403 | if (invert) |
4404 | return(1); |
4405 | else |
4406 | return(-1); |
4407 | } |
4408 | } |
4409 | return(0); |
4410 | } |
4411 | |
4412 | /** |
4413 | * xmlSchemaComparePreserveCollapseStrings: |
4414 | * @x: a first string value |
4415 | * @y: a second string value |
4416 | * |
4417 | * Compare 2 string for their normalized values. |
4418 | * @x is a string with whitespace of "preserve", @y is |
4419 | * a string with a whitespace of "collapse". I.e. @x could |
4420 | * be an "xsd:string" and @y an "xsd:normalizedString". |
4421 | * |
4422 | * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in |
4423 | * case of error |
4424 | */ |
4425 | static int |
4426 | xmlSchemaCompareReplaceCollapseStrings(const xmlChar *x, |
4427 | const xmlChar *y, |
4428 | int invert) |
4429 | { |
4430 | int tmp; |
4431 | |
4432 | /* |
4433 | * Skip leading blank chars of the collapsed string. |
4434 | */ |
4435 | while IS_WSP_BLANK_CH(*y) |
4436 | y++; |
4437 | |
4438 | while ((*x != 0) && (*y != 0)) { |
4439 | if IS_WSP_BLANK_CH(*y) { |
4440 | if (! IS_WSP_BLANK_CH(*x)) { |
4441 | /* |
4442 | * The yv character would have been replaced to 0x20. |
4443 | */ |
4444 | if ((*x - 0x20) < 0) { |
4445 | if (invert) |
4446 | return(1); |
4447 | else |
4448 | return(-1); |
4449 | } else { |
4450 | if (invert) |
4451 | return(-1); |
4452 | else |
4453 | return(1); |
4454 | } |
4455 | } |
4456 | x++; |
4457 | y++; |
4458 | /* |
4459 | * Skip contiguous blank chars of the collapsed string. |
4460 | */ |
4461 | while IS_WSP_BLANK_CH(*y) |
4462 | y++; |
4463 | } else { |
4464 | if IS_WSP_BLANK_CH(*x) { |
4465 | /* |
4466 | * The xv character would have been replaced to 0x20. |
4467 | */ |
4468 | if ((0x20 - *y) < 0) { |
4469 | if (invert) |
4470 | return(1); |
4471 | else |
4472 | return(-1); |
4473 | } else { |
4474 | if (invert) |
4475 | return(-1); |
4476 | else |
4477 | return(1); |
4478 | } |
4479 | } |
4480 | tmp = *x++ - *y++; |
4481 | if (tmp < 0) |
4482 | return(-1); |
4483 | if (tmp > 0) |
4484 | return(1); |
4485 | } |
4486 | } |
4487 | if (*x != 0) { |
4488 | if (invert) |
4489 | return(-1); |
4490 | else |
4491 | return(1); |
4492 | } |
4493 | if (*y != 0) { |
4494 | /* |
4495 | * Skip trailing blank chars of the collapsed string. |
4496 | */ |
4497 | while IS_WSP_BLANK_CH(*y) |
4498 | y++; |
4499 | if (*y != 0) { |
4500 | if (invert) |
4501 | return(1); |
4502 | else |
4503 | return(-1); |
4504 | } |
4505 | } |
4506 | return(0); |
4507 | } |
4508 | |
4509 | |
4510 | /** |
4511 | * xmlSchemaCompareReplacedStrings: |
4512 | * @x: a first string value |
4513 | * @y: a second string value |
4514 | * |
4515 | * Compare 2 string for their normalized values. |
4516 | * |
4517 | * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in |
4518 | * case of error |
4519 | */ |
4520 | static int |
4521 | xmlSchemaCompareReplacedStrings(const xmlChar *x, |
4522 | const xmlChar *y) |
4523 | { |
4524 | int tmp; |
4525 | |
4526 | while ((*x != 0) && (*y != 0)) { |
4527 | if IS_WSP_BLANK_CH(*y) { |
4528 | if (! IS_WSP_BLANK_CH(*x)) { |
4529 | if ((*x - 0x20) < 0) |
4530 | return(-1); |
4531 | else |
4532 | return(1); |
4533 | } |
4534 | } else { |
4535 | if IS_WSP_BLANK_CH(*x) { |
4536 | if ((0x20 - *y) < 0) |
4537 | return(-1); |
4538 | else |
4539 | return(1); |
4540 | } |
4541 | tmp = *x - *y; |
4542 | if (tmp < 0) |
4543 | return(-1); |
4544 | if (tmp > 0) |
4545 | return(1); |
4546 | } |
4547 | x++; |
4548 | y++; |
4549 | } |
4550 | if (*x != 0) |
4551 | return(1); |
4552 | if (*y != 0) |
4553 | return(-1); |
4554 | return(0); |
4555 | } |
4556 | |
4557 | /** |
4558 | * xmlSchemaCompareNormStrings: |
4559 | * @x: a first string value |
4560 | * @y: a second string value |
4561 | * |
4562 | * Compare 2 string for their normalized values. |
4563 | * |
4564 | * Returns -1 if x < y, 0 if x == y, 1 if x > y, and -2 in |
4565 | * case of error |
4566 | */ |
4567 | static int |
4568 | xmlSchemaCompareNormStrings(const xmlChar *x, |
4569 | const xmlChar *y) { |
4570 | int tmp; |
4571 | |
4572 | while (IS_BLANK_CH(*x)) x++; |
4573 | while (IS_BLANK_CH(*y)) y++; |
4574 | while ((*x != 0) && (*y != 0)) { |
4575 | if (IS_BLANK_CH(*x)) { |
4576 | if (!IS_BLANK_CH(*y)) { |
4577 | tmp = *x - *y; |
4578 | return(tmp); |
4579 | } |
4580 | while (IS_BLANK_CH(*x)) x++; |
4581 | while (IS_BLANK_CH(*y)) y++; |
4582 | } else { |
4583 | tmp = *x++ - *y++; |
4584 | if (tmp < 0) |
4585 | return(-1); |
4586 | if (tmp > 0) |
4587 | return(1); |
4588 | } |
4589 | } |
4590 | if (*x != 0) { |
4591 | while (IS_BLANK_CH(*x)) x++; |
4592 | if (*x != 0) |
4593 | return(1); |
4594 | } |
4595 | if (*y != 0) { |
4596 | while (IS_BLANK_CH(*y)) y++; |
4597 | if (*y != 0) |
4598 | return(-1); |
4599 | } |
4600 | return(0); |
4601 | } |
4602 | |
4603 | /** |
4604 | * xmlSchemaCompareFloats: |
4605 | * @x: a first float or double value |
4606 | * @y: a second float or double value |
4607 | * |
4608 | * Compare 2 values |
4609 | * |
4610 | * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in |
4611 | * case of error |
4612 | */ |
4613 | static int |
4614 | xmlSchemaCompareFloats(xmlSchemaValPtr x, xmlSchemaValPtr y) { |
4615 | double d1, d2; |
4616 | |
4617 | if ((x == NULL) || (y == NULL)) |
4618 | return(-2); |
4619 | |
4620 | /* |
4621 | * Cast everything to doubles. |
4622 | */ |
4623 | if (x->type == XML_SCHEMAS_DOUBLE) |
4624 | d1 = x->value.d; |
4625 | else if (x->type == XML_SCHEMAS_FLOAT) |
4626 | d1 = x->value.f; |
4627 | else |
4628 | return(-2); |
4629 | |
4630 | if (y->type == XML_SCHEMAS_DOUBLE) |
4631 | d2 = y->value.d; |
4632 | else if (y->type == XML_SCHEMAS_FLOAT) |
4633 | d2 = y->value.f; |
4634 | else |
4635 | return(-2); |
4636 | |
4637 | /* |
4638 | * Check for special cases. |
4639 | */ |
4640 | if (xmlXPathIsNaN(d1)) { |
4641 | if (xmlXPathIsNaN(d2)) |
4642 | return(0); |
4643 | return(1); |
4644 | } |
4645 | if (xmlXPathIsNaN(d2)) |
4646 | return(-1); |
4647 | if (d1 == xmlXPathPINF) { |
4648 | if (d2 == xmlXPathPINF) |
4649 | return(0); |
4650 | return(1); |
4651 | } |
4652 | if (d2 == xmlXPathPINF) |
4653 | return(-1); |
4654 | if (d1 == xmlXPathNINF) { |
4655 | if (d2 == xmlXPathNINF) |
4656 | return(0); |
4657 | return(-1); |
4658 | } |
4659 | if (d2 == xmlXPathNINF) |
4660 | return(1); |
4661 | |
4662 | /* |
4663 | * basic tests, the last one we should have equality, but |
4664 | * portability is more important than speed and handling |
4665 | * NaN or Inf in a portable way is always a challenge, so ... |
4666 | */ |
4667 | if (d1 < d2) |
4668 | return(-1); |
4669 | if (d1 > d2) |
4670 | return(1); |
4671 | if (d1 == d2) |
4672 | return(0); |
4673 | return(2); |
4674 | } |
4675 | |
4676 | /** |
4677 | * xmlSchemaCompareValues: |
4678 | * @x: a first value |
4679 | * @xvalue: the first value as a string (optional) |
4680 | * @xwtsp: the whitespace type |
4681 | * @y: a second value |
4682 | * @xvalue: the second value as a string (optional) |
4683 | * @ywtsp: the whitespace type |
4684 | * |
4685 | * Compare 2 values |
4686 | * |
4687 | * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, 3 if not |
4688 | * comparable and -2 in case of error |
4689 | */ |
4690 | static int |
4691 | xmlSchemaCompareValuesInternal(xmlSchemaValType xtype, |
4692 | xmlSchemaValPtr x, |
4693 | const xmlChar *xvalue, |
4694 | xmlSchemaWhitespaceValueType xws, |
4695 | xmlSchemaValType ytype, |
4696 | xmlSchemaValPtr y, |
4697 | const xmlChar *yvalue, |
4698 | xmlSchemaWhitespaceValueType yws) |
4699 | { |
4700 | switch (xtype) { |
4701 | case XML_SCHEMAS_UNKNOWN: |
4702 | case XML_SCHEMAS_ANYTYPE: |
4703 | return(-2); |
4704 | case XML_SCHEMAS_INTEGER: |
4705 | case XML_SCHEMAS_NPINTEGER: |
4706 | case XML_SCHEMAS_NINTEGER: |
4707 | case XML_SCHEMAS_NNINTEGER: |
4708 | case XML_SCHEMAS_PINTEGER: |
4709 | case XML_SCHEMAS_INT: |
4710 | case XML_SCHEMAS_UINT: |
4711 | case XML_SCHEMAS_LONG: |
4712 | case XML_SCHEMAS_ULONG: |
4713 | case XML_SCHEMAS_SHORT: |
4714 | case XML_SCHEMAS_USHORT: |
4715 | case XML_SCHEMAS_BYTE: |
4716 | case XML_SCHEMAS_UBYTE: |
4717 | case XML_SCHEMAS_DECIMAL: |
4718 | if ((x == NULL) || (y == NULL)) |
4719 | return(-2); |
4720 | if (ytype == xtype) |
4721 | return(xmlSchemaCompareDecimals(x, y)); |
4722 | if ((ytype == XML_SCHEMAS_DECIMAL) || |
4723 | (ytype == XML_SCHEMAS_INTEGER) || |
4724 | (ytype == XML_SCHEMAS_NPINTEGER) || |
4725 | (ytype == XML_SCHEMAS_NINTEGER) || |
4726 | (ytype == XML_SCHEMAS_NNINTEGER) || |
4727 | (ytype == XML_SCHEMAS_PINTEGER) || |
4728 | (ytype == XML_SCHEMAS_INT) || |
4729 | (ytype == XML_SCHEMAS_UINT) || |
4730 | (ytype == XML_SCHEMAS_LONG) || |
4731 | (ytype == XML_SCHEMAS_ULONG) || |
4732 | (ytype == XML_SCHEMAS_SHORT) || |
4733 | (ytype == XML_SCHEMAS_USHORT) || |
4734 | (ytype == XML_SCHEMAS_BYTE) || |
4735 | (ytype == XML_SCHEMAS_UBYTE)) |
4736 | return(xmlSchemaCompareDecimals(x, y)); |
4737 | return(-2); |
4738 | case XML_SCHEMAS_DURATION: |
4739 | if ((x == NULL) || (y == NULL)) |
4740 | return(-2); |
4741 | if (ytype == XML_SCHEMAS_DURATION) |
4742 | return(xmlSchemaCompareDurations(x, y)); |
4743 | return(-2); |
4744 | case XML_SCHEMAS_TIME: |
4745 | case XML_SCHEMAS_GDAY: |
4746 | case XML_SCHEMAS_GMONTH: |
4747 | case XML_SCHEMAS_GMONTHDAY: |
4748 | case XML_SCHEMAS_GYEAR: |
4749 | case XML_SCHEMAS_GYEARMONTH: |
4750 | case XML_SCHEMAS_DATE: |
4751 | case XML_SCHEMAS_DATETIME: |
4752 | if ((x == NULL) || (y == NULL)) |
4753 | return(-2); |
4754 | if ((ytype == XML_SCHEMAS_DATETIME) || |
4755 | (ytype == XML_SCHEMAS_TIME) || |
4756 | (ytype == XML_SCHEMAS_GDAY) || |
4757 | (ytype == XML_SCHEMAS_GMONTH) || |
4758 | (ytype == XML_SCHEMAS_GMONTHDAY) || |
4759 | (ytype == XML_SCHEMAS_GYEAR) || |
4760 | (ytype == XML_SCHEMAS_DATE) || |
4761 | (ytype == XML_SCHEMAS_GYEARMONTH)) |
4762 | return (xmlSchemaCompareDates(x, y)); |
4763 | return (-2); |
4764 | /* |
4765 | * Note that we will support comparison of string types against |
4766 | * anySimpleType as well. |
4767 | */ |
4768 | case XML_SCHEMAS_ANYSIMPLETYPE: |
4769 | case XML_SCHEMAS_STRING: |
4770 | case XML_SCHEMAS_NORMSTRING: |
4771 | case XML_SCHEMAS_TOKEN: |
4772 | case XML_SCHEMAS_LANGUAGE: |
4773 | case XML_SCHEMAS_NMTOKEN: |
4774 | case XML_SCHEMAS_NAME: |
4775 | case XML_SCHEMAS_NCNAME: |
4776 | case XML_SCHEMAS_ID: |
4777 | case XML_SCHEMAS_IDREF: |
4778 | case XML_SCHEMAS_ENTITY: |
4779 | case XML_SCHEMAS_ANYURI: |
4780 | { |
4781 | const xmlChar *xv, *yv; |
4782 | |
4783 | if (x == NULL) |
4784 | xv = xvalue; |
4785 | else |
4786 | xv = x->value.str; |
4787 | if (y == NULL) |
4788 | yv = yvalue; |
4789 | else |
4790 | yv = y->value.str; |
4791 | /* |
4792 | * TODO: Compare those against QName. |
4793 | */ |
4794 | if (ytype == XML_SCHEMAS_QNAME) { |
4795 | TODO |
4796 | if (y == NULL) |
4797 | return(-2); |
4798 | return (-2); |
4799 | } |
4800 | if ((ytype == XML_SCHEMAS_ANYSIMPLETYPE) || |
4801 | (ytype == XML_SCHEMAS_STRING) || |
4802 | (ytype == XML_SCHEMAS_NORMSTRING) || |
4803 | (ytype == XML_SCHEMAS_TOKEN) || |
4804 | (ytype == XML_SCHEMAS_LANGUAGE) || |
4805 | (ytype == XML_SCHEMAS_NMTOKEN) || |
4806 | (ytype == XML_SCHEMAS_NAME) || |
4807 | (ytype == XML_SCHEMAS_NCNAME) || |
4808 | (ytype == XML_SCHEMAS_ID) || |
4809 | (ytype == XML_SCHEMAS_IDREF) || |
4810 | (ytype == XML_SCHEMAS_ENTITY) || |
4811 | (ytype == XML_SCHEMAS_ANYURI)) { |
4812 | |
4813 | if (xws == XML_SCHEMA_WHITESPACE_PRESERVE) { |
4814 | |
4815 | if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) { |
4816 | /* TODO: What about x < y or x > y. */ |
4817 | if (xmlStrEqual(xv, yv)) |
4818 | return (0); |
4819 | else |
4820 | return (2); |
4821 | } else if (yws == XML_SCHEMA_WHITESPACE_REPLACE) |
4822 | return (xmlSchemaComparePreserveReplaceStrings(xv, yv, 0)); |
4823 | else if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE) |
4824 | return (xmlSchemaComparePreserveCollapseStrings(xv, yv, 0)); |
4825 | |
4826 | } else if (xws == XML_SCHEMA_WHITESPACE_REPLACE) { |
4827 | |
4828 | if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) |
4829 | return (xmlSchemaComparePreserveReplaceStrings(yv, xv, 1)); |
4830 | if (yws == XML_SCHEMA_WHITESPACE_REPLACE) |
4831 | return (xmlSchemaCompareReplacedStrings(xv, yv)); |
4832 | if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE) |
4833 | return (xmlSchemaCompareReplaceCollapseStrings(xv, yv, 0)); |
4834 | |
4835 | } else if (xws == XML_SCHEMA_WHITESPACE_COLLAPSE) { |
4836 | |
4837 | if (yws == XML_SCHEMA_WHITESPACE_PRESERVE) |
4838 | return (xmlSchemaComparePreserveCollapseStrings(yv, xv, 1)); |
4839 | if (yws == XML_SCHEMA_WHITESPACE_REPLACE) |
4840 | return (xmlSchemaCompareReplaceCollapseStrings(yv, xv, 1)); |
4841 | if (yws == XML_SCHEMA_WHITESPACE_COLLAPSE) |
4842 | return (xmlSchemaCompareNormStrings(xv, yv)); |
4843 | } else |
4844 | return (-2); |
4845 | |
4846 | } |
4847 | return (-2); |
4848 | } |
4849 | case XML_SCHEMAS_QNAME: |
4850 | case XML_SCHEMAS_NOTATION: |
4851 | if ((x == NULL) || (y == NULL)) |
4852 | return(-2); |
4853 | if ((ytype == XML_SCHEMAS_QNAME) || |
4854 | (ytype == XML_SCHEMAS_NOTATION)) { |
4855 | if ((xmlStrEqual(x->value.qname.name, y->value.qname.name)) && |
4856 | (xmlStrEqual(x->value.qname.uri, y->value.qname.uri))) |
4857 | return(0); |
4858 | return(2); |
4859 | } |
4860 | return (-2); |
4861 | case XML_SCHEMAS_FLOAT: |
4862 | case XML_SCHEMAS_DOUBLE: |
4863 | if ((x == NULL) || (y == NULL)) |
4864 | return(-2); |
4865 | if ((ytype == XML_SCHEMAS_FLOAT) || |
4866 | (ytype == XML_SCHEMAS_DOUBLE)) |
4867 | return (xmlSchemaCompareFloats(x, y)); |
4868 | return (-2); |
4869 | case XML_SCHEMAS_BOOLEAN: |
4870 | if ((x == NULL) || (y == NULL)) |
4871 | return(-2); |
4872 | if (ytype == XML_SCHEMAS_BOOLEAN) { |
4873 | if (x->value.b == y->value.b) |
4874 | return(0); |
4875 | if (x->value.b == 0) |
4876 | return(-1); |
4877 | return(1); |
4878 | } |
4879 | return (-2); |
4880 | case XML_SCHEMAS_HEXBINARY: |
4881 | if ((x == NULL) || (y == NULL)) |
4882 | return(-2); |
4883 | if (ytype == XML_SCHEMAS_HEXBINARY) { |
4884 | if (x->value.hex.total == y->value.hex.total) { |
4885 | int ret = xmlStrcmp(x->value.hex.str, y->value.hex.str); |
4886 | if (ret > 0) |
4887 | return(1); |
4888 | else if (ret == 0) |
4889 | return(0); |
4890 | } |
4891 | else if (x->value.hex.total > y->value.hex.total) |
4892 | return(1); |
4893 | |
4894 | return(-1); |
4895 | } |
4896 | return (-2); |
4897 | case XML_SCHEMAS_BASE64BINARY: |
4898 | if ((x == NULL) || (y == NULL)) |
4899 | return(-2); |
4900 | if (ytype == XML_SCHEMAS_BASE64BINARY) { |
4901 | if (x->value.base64.total == y->value.base64.total) { |
4902 | int ret = xmlStrcmp(x->value.base64.str, |
4903 | y->value.base64.str); |
4904 | if (ret > 0) |
4905 | return(1); |
4906 | else if (ret == 0) |
4907 | return(0); |
4908 | else |
4909 | return(-1); |
4910 | } |
4911 | else if (x->value.base64.total > y->value.base64.total) |
4912 | return(1); |
4913 | else |
4914 | return(-1); |
4915 | } |
4916 | return (-2); |
4917 | case XML_SCHEMAS_IDREFS: |
4918 | case XML_SCHEMAS_ENTITIES: |
4919 | case XML_SCHEMAS_NMTOKENS: |
4920 | TODO |
4921 | break; |
4922 | } |
4923 | return -2; |
4924 | } |
4925 | |
4926 | /** |
4927 | * xmlSchemaCompareValues: |
4928 | * @x: a first value |
4929 | * @y: a second value |
4930 | * |
4931 | * Compare 2 values |
4932 | * |
4933 | * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in |
4934 | * case of error |
4935 | */ |
4936 | int |
4937 | xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) { |
4938 | xmlSchemaWhitespaceValueType xws, yws; |
4939 | |
4940 | if ((x == NULL) || (y == NULL)) |
4941 | return(-2); |
4942 | if (x->type == XML_SCHEMAS_STRING) |
4943 | xws = XML_SCHEMA_WHITESPACE_PRESERVE; |
4944 | else if (x->type == XML_SCHEMAS_NORMSTRING) |
4945 | xws = XML_SCHEMA_WHITESPACE_REPLACE; |
4946 | else |
4947 | xws = XML_SCHEMA_WHITESPACE_COLLAPSE; |
4948 | |
4949 | if (y->type == XML_SCHEMAS_STRING) |
4950 | yws = XML_SCHEMA_WHITESPACE_PRESERVE; |
4951 | else if (y->type == XML_SCHEMAS_NORMSTRING) |
4952 | yws = XML_SCHEMA_WHITESPACE_REPLACE; |
4953 | else |
4954 | yws = XML_SCHEMA_WHITESPACE_COLLAPSE; |
4955 | |
4956 | return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type, |
4957 | y, NULL, yws)); |
4958 | } |
4959 | |
4960 | /** |
4961 | * xmlSchemaCompareValuesWhtsp: |
4962 | * @x: a first value |
4963 | * @xws: the whitespace value of x |
4964 | * @y: a second value |
4965 | * @yws: the whitespace value of y |
4966 | * |
4967 | * Compare 2 values |
4968 | * |
4969 | * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in |
4970 | * case of error |
4971 | */ |
4972 | int |
4973 | xmlSchemaCompareValuesWhtsp(xmlSchemaValPtr x, |
4974 | xmlSchemaWhitespaceValueType xws, |
4975 | xmlSchemaValPtr y, |
4976 | xmlSchemaWhitespaceValueType yws) |
4977 | { |
4978 | if ((x == NULL) || (y == NULL)) |
4979 | return(-2); |
4980 | return(xmlSchemaCompareValuesInternal(x->type, x, NULL, xws, y->type, |
4981 | y, NULL, yws)); |
4982 | } |
4983 | |
4984 | /** |
4985 | * xmlSchemaCompareValuesWhtspExt: |
4986 | * @x: a first value |
4987 | * @xws: the whitespace value of x |
4988 | * @y: a second value |
4989 | * @yws: the whitespace value of y |
4990 | * |
4991 | * Compare 2 values |
4992 | * |
4993 | * Returns -1 if x < y, 0 if x == y, 1 if x > y, 2 if x <> y, and -2 in |
4994 | * case of error |
4995 | */ |
4996 | static int |
4997 | xmlSchemaCompareValuesWhtspExt(xmlSchemaValType xtype, |
4998 | xmlSchemaValPtr x, |
4999 | const xmlChar *xvalue, |
5000 | xmlSchemaWhitespaceValueType xws, |
5001 | xmlSchemaValType ytype, |
5002 | xmlSchemaValPtr y, |
5003 | const xmlChar *yvalue, |
5004 | xmlSchemaWhitespaceValueType yws) |
5005 | { |
5006 | return(xmlSchemaCompareValuesInternal(xtype, x, xvalue, xws, ytype, y, |
5007 | yvalue, yws)); |
5008 | } |
5009 | |
5010 | /** |
5011 | * xmlSchemaNormLen: |
5012 | * @value: a string |
5013 | * |
5014 | * Computes the UTF8 length of the normalized value of the string |
5015 | * |
5016 | * Returns the length or -1 in case of error. |
5017 | */ |
5018 | static int |
5019 | xmlSchemaNormLen(const xmlChar *value) { |
5020 | const xmlChar *utf; |
5021 | int ret = 0; |
5022 | |
5023 | if (value == NULL) |
5024 | return(-1); |
5025 | utf = value; |
5026 | while (IS_BLANK_CH(*utf)) utf++; |
5027 | while (*utf != 0) { |
5028 | if (utf[0] & 0x80) { |
5029 | if ((utf[1] & 0xc0) != 0x80) |
5030 | return(-1); |
5031 | if ((utf[0] & 0xe0) == 0xe0) { |
5032 | if ((utf[2] & 0xc0) != 0x80) |
5033 | return(-1); |
5034 | if ((utf[0] & 0xf0) == 0xf0) { |
5035 | if ((utf[0] & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80) |
5036 | return(-1); |
5037 | utf += 4; |
5038 | } else { |
5039 | utf += 3; |
5040 | } |
5041 | } else { |
5042 | utf += 2; |
5043 | } |
5044 | } else if (IS_BLANK_CH(*utf)) { |
5045 | while (IS_BLANK_CH(*utf)) utf++; |
5046 | if (*utf == 0) |
5047 | break; |
5048 | } else { |
5049 | utf++; |
5050 | } |
5051 | ret++; |
5052 | } |
5053 | return(ret); |
5054 | } |
5055 | |
5056 | /** |
5057 | * xmlSchemaGetFacetValueAsULong: |
5058 | * @facet: an schemas type facet |
5059 | * |
5060 | * Extract the value of a facet |
5061 | * |
5062 | * Returns the value as a long |
5063 | */ |
5064 | unsigned long |
5065 | xmlSchemaGetFacetValueAsULong(xmlSchemaFacetPtr facet) |
5066 | { |
5067 | /* |
5068 | * TODO: Check if this is a decimal. |
5069 | */ |
5070 | if (facet == NULL) |
5071 | return 0; |
5072 | return ((unsigned long) facet->val->value.decimal.lo); |
5073 | } |
5074 | |
5075 | /** |
5076 | * xmlSchemaValidateListSimpleTypeFacet: |
5077 | * @facet: the facet to check |
5078 | * @value: the lexical repr of the value to validate |
5079 | * @actualLen: the number of list items |
5080 | * @expectedLen: the resulting expected number of list items |
5081 | * |
5082 | * Checks the value of a list simple type against a facet. |
5083 | * |
5084 | * Returns 0 if the value is valid, a positive error code |
5085 | * number otherwise and -1 in case of an internal error. |
5086 | */ |
5087 | int |
5088 | xmlSchemaValidateListSimpleTypeFacet(xmlSchemaFacetPtr facet, |
5089 | const xmlChar *value, |
5090 | unsigned long actualLen, |
5091 | unsigned long *expectedLen) |
5092 | { |
5093 | if (facet == NULL) |
5094 | return(-1); |
5095 | /* |
5096 | * TODO: Check if this will work with large numbers. |
5097 | * (compare value.decimal.mi and value.decimal.hi as well?). |
5098 | */ |
5099 | if (facet->type == XML_SCHEMA_FACET_LENGTH) { |
5100 | if (actualLen != facet->val->value.decimal.lo) { |
5101 | if (expectedLen != NULL) |
5102 | *expectedLen = facet->val->value.decimal.lo; |
5103 | return (XML_SCHEMAV_CVC_LENGTH_VALID); |
5104 | } |
5105 | } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) { |
5106 | if (actualLen < facet->val->value.decimal.lo) { |
5107 | if (expectedLen != NULL) |
5108 | *expectedLen = facet->val->value.decimal.lo; |
5109 | return (XML_SCHEMAV_CVC_MINLENGTH_VALID); |
5110 | } |
5111 | } else if (facet->type == XML_SCHEMA_FACET_MAXLENGTH) { |
5112 | if (actualLen > facet->val->value.decimal.lo) { |
5113 | if (expectedLen != NULL) |
5114 | *expectedLen = facet->val->value.decimal.lo; |
5115 | return (XML_SCHEMAV_CVC_MAXLENGTH_VALID); |
5116 | } |
5117 | } else |
5118 | /* |
5119 | * NOTE: That we can pass NULL as xmlSchemaValPtr to |
5120 | * xmlSchemaValidateFacet, since the remaining facet types |
5121 | * are: XML_SCHEMA_FACET_PATTERN, XML_SCHEMA_FACET_ENUMERATION. |
5122 | */ |
5123 | return(xmlSchemaValidateFacet(NULL, facet, value, NULL)); |
5124 | return (0); |
5125 | } |
5126 | |
5127 | /** |
5128 | * xmlSchemaValidateLengthFacet: |
5129 | * @type: the built-in type |
5130 | * @facet: the facet to check |
5131 | * @value: the lexical repr. of the value to be validated |
5132 | * @val: the precomputed value |
5133 | * @ws: the whitespace type of the value |
5134 | * @length: the actual length of the value |
5135 | * |
5136 | * Checka a value against a "length", "minLength" and "maxLength" |
5137 | * facet; sets @length to the computed length of @value. |
5138 | * |
5139 | * Returns 0 if the value is valid, a positive error code |
5140 | * otherwise and -1 in case of an internal or API error. |
5141 | */ |
5142 | static int |
5143 | xmlSchemaValidateLengthFacetInternal(xmlSchemaFacetPtr facet, |
5144 | xmlSchemaValType valType, |
5145 | const xmlChar *value, |
5146 | xmlSchemaValPtr val, |
5147 | unsigned long *length, |
5148 | xmlSchemaWhitespaceValueType ws) |
5149 | { |
5150 | unsigned int len = 0; |
5151 | |
5152 | if ((length == NULL) || (facet == NULL)) |
5153 | return (-1); |
5154 | *length = 0; |
5155 | if ((facet->type != XML_SCHEMA_FACET_LENGTH) && |
5156 | (facet->type != XML_SCHEMA_FACET_MAXLENGTH) && |
5157 | (facet->type != XML_SCHEMA_FACET_MINLENGTH)) |
5158 | return (-1); |
5159 | |
5160 | /* |
5161 | * TODO: length, maxLength and minLength must be of type |
5162 | * nonNegativeInteger only. Check if decimal is used somehow. |
5163 | */ |
5164 | if ((facet->val == NULL) || |
5165 | ((facet->val->type != XML_SCHEMAS_DECIMAL) && |
5166 | (facet->val->type != XML_SCHEMAS_NNINTEGER)) || |
5167 | (facet->val->value.decimal.frac != 0)) { |
5168 | return(-1); |
5169 | } |
5170 | if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY)) |
5171 | len = val->value.hex.total; |
5172 | else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY)) |
5173 | len = val->value.base64.total; |
5174 | else { |
5175 | switch (valType) { |
5176 | case XML_SCHEMAS_STRING: |
5177 | case XML_SCHEMAS_NORMSTRING: |
5178 | if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) { |
5179 | /* |
5180 | * This is to ensure API compatibility with the old |
5181 | * xmlSchemaValidateLengthFacet(). Anyway, this was and |
5182 | * is not the correct handling. |
5183 | * TODO: Get rid of this case somehow. |
5184 | */ |
5185 | if (valType == XML_SCHEMAS_STRING) |
5186 | len = xmlUTF8Strlen(value); |
5187 | else |
5188 | len = xmlSchemaNormLen(value); |
5189 | } else if (value != NULL) { |
5190 | if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) |
5191 | len = xmlSchemaNormLen(value); |
5192 | else |
5193 | /* |
5194 | * Should be OK for "preserve" as well. |
5195 | */ |
5196 | len = xmlUTF8Strlen(value); |
5197 | } |
5198 | break; |
5199 | case XML_SCHEMAS_IDREF: |
5200 | case XML_SCHEMAS_TOKEN: |
5201 | case XML_SCHEMAS_LANGUAGE: |
5202 | case XML_SCHEMAS_NMTOKEN: |
5203 | case XML_SCHEMAS_NAME: |
5204 | case XML_SCHEMAS_NCNAME: |
5205 | case XML_SCHEMAS_ID: |
5206 | /* |
5207 | * FIXME: What exactly to do with anyURI? |
5208 | */ |
5209 | case XML_SCHEMAS_ANYURI: |
5210 | if (value != NULL) |
5211 | len = xmlSchemaNormLen(value); |
5212 | break; |
5213 | case XML_SCHEMAS_QNAME: |
5214 | case XML_SCHEMAS_NOTATION: |
5215 | /* |
5216 | * For QName and NOTATION, those facets are |
5217 | * deprecated and should be ignored. |
5218 | */ |
5219 | return (0); |
5220 | default: |
5221 | TODO |
5222 | } |
5223 | } |
5224 | *length = (unsigned long) len; |
5225 | /* |
5226 | * TODO: Return the whole expected value, i.e. "lo", "mi" and "hi". |
5227 | */ |
5228 | if (facet->type == XML_SCHEMA_FACET_LENGTH) { |
5229 | if (len != facet->val->value.decimal.lo) |
5230 | return(XML_SCHEMAV_CVC_LENGTH_VALID); |
5231 | } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) { |
5232 | if (len < facet->val->value.decimal.lo) |
5233 | return(XML_SCHEMAV_CVC_MINLENGTH_VALID); |
5234 | } else { |
5235 | if (len > facet->val->value.decimal.lo) |
5236 | return(XML_SCHEMAV_CVC_MAXLENGTH_VALID); |
5237 | } |
5238 | |
5239 | return (0); |
5240 | } |
5241 | |
5242 | /** |
5243 | * xmlSchemaValidateLengthFacet: |
5244 | * @type: the built-in type |
5245 | * @facet: the facet to check |
5246 | * @value: the lexical repr. of the value to be validated |
5247 | * @val: the precomputed value |
5248 | * @length: the actual length of the value |
5249 | * |
5250 | * Checka a value against a "length", "minLength" and "maxLength" |
5251 | * facet; sets @length to the computed length of @value. |
5252 | * |
5253 | * Returns 0 if the value is valid, a positive error code |
5254 | * otherwise and -1 in case of an internal or API error. |
5255 | */ |
5256 | int |
5257 | xmlSchemaValidateLengthFacet(xmlSchemaTypePtr type, |
5258 | xmlSchemaFacetPtr facet, |
5259 | const xmlChar *value, |
5260 | xmlSchemaValPtr val, |
5261 | unsigned long *length) |
5262 | { |
5263 | if (type == NULL) |
5264 | return(-1); |
5265 | return (xmlSchemaValidateLengthFacetInternal(facet, |
5266 | type->builtInType, value, val, length, |
5267 | XML_SCHEMA_WHITESPACE_UNKNOWN)); |
5268 | } |
5269 | |
5270 | /** |
5271 | * xmlSchemaValidateLengthFacetWhtsp: |
5272 | * @facet: the facet to check |
5273 | * @valType: the built-in type |
5274 | * @value: the lexical repr. of the value to be validated |
5275 | * @val: the precomputed value |
5276 | * @ws: the whitespace type of the value |
5277 | * @length: the actual length of the value |
5278 | * |
5279 | * Checka a value against a "length", "minLength" and "maxLength" |
5280 | * facet; sets @length to the computed length of @value. |
5281 | * |
5282 | * Returns 0 if the value is valid, a positive error code |
5283 | * otherwise and -1 in case of an internal or API error. |
5284 | */ |
5285 | int |
5286 | xmlSchemaValidateLengthFacetWhtsp(xmlSchemaFacetPtr facet, |
5287 | xmlSchemaValType valType, |
5288 | const xmlChar *value, |
5289 | xmlSchemaValPtr val, |
5290 | unsigned long *length, |
5291 | xmlSchemaWhitespaceValueType ws) |
5292 | { |
5293 | return (xmlSchemaValidateLengthFacetInternal(facet, valType, value, val, |
5294 | length, ws)); |
5295 | } |
5296 | |
5297 | /** |
5298 | * xmlSchemaValidateFacetInternal: |
5299 | * @facet: the facet to check |
5300 | * @fws: the whitespace type of the facet's value |
5301 | * @valType: the built-in type of the value |
5302 | * @value: the lexical repr of the value to validate |
5303 | * @val: the precomputed value |
5304 | * @ws: the whitespace type of the value |
5305 | * |
5306 | * Check a value against a facet condition |
5307 | * |
5308 | * Returns 0 if the element is schemas valid, a positive error code |
5309 | * number otherwise and -1 in case of internal or API error. |
5310 | */ |
5311 | static int |
5312 | xmlSchemaValidateFacetInternal(xmlSchemaFacetPtr facet, |
5313 | xmlSchemaWhitespaceValueType fws, |
5314 | xmlSchemaValType valType, |
5315 | const xmlChar *value, |
5316 | xmlSchemaValPtr val, |
5317 | xmlSchemaWhitespaceValueType ws) |
5318 | { |
5319 | int ret; |
5320 | int stringType; |
5321 | |
5322 | if (facet == NULL) |
5323 | return(-1); |
5324 | |
5325 | switch (facet->type) { |
5326 | case XML_SCHEMA_FACET_PATTERN: |
5327 | /* |
5328 | * NOTE that for patterns, the @value needs to be the normalized |
5329 | * value, *not* the lexical initial value or the canonical value. |
5330 | */ |
5331 | if (value == NULL) |
5332 | return(-1); |
5333 | /* |
5334 | * If string-derived type, regexp must be tested on the value space of |
5335 | * the datatype. |
5336 | * See https://www.w3.org/TR/xmlschema-2/#rf-pattern |
5337 | */ |
5338 | stringType = val && ((val->type >= XML_SCHEMAS_STRING && val->type <= XML_SCHEMAS_NORMSTRING) |
5339 | || (val->type >= XML_SCHEMAS_TOKEN && val->type <= XML_SCHEMAS_NCNAME)); |
5340 | ret = xmlRegexpExec(facet->regexp, |
5341 | (stringType && val->value.str) ? val->value.str : value); |
5342 | if (ret == 1) |
5343 | return(0); |
5344 | if (ret == 0) |
5345 | return(XML_SCHEMAV_CVC_PATTERN_VALID); |
5346 | return(ret); |
5347 | case XML_SCHEMA_FACET_MAXEXCLUSIVE: |
5348 | ret = xmlSchemaCompareValues(val, facet->val); |
5349 | if (ret == -2) |
5350 | return(-1); |
5351 | if (ret == -1) |
5352 | return(0); |
5353 | return(XML_SCHEMAV_CVC_MAXEXCLUSIVE_VALID); |
5354 | case XML_SCHEMA_FACET_MAXINCLUSIVE: |
5355 | ret = xmlSchemaCompareValues(val, facet->val); |
5356 | if (ret == -2) |
5357 | return(-1); |
5358 | if ((ret == -1) || (ret == 0)) |
5359 | return(0); |
5360 | return(XML_SCHEMAV_CVC_MAXINCLUSIVE_VALID); |
5361 | case XML_SCHEMA_FACET_MINEXCLUSIVE: |
5362 | ret = xmlSchemaCompareValues(val, facet->val); |
5363 | if (ret == -2) |
5364 | return(-1); |
5365 | if (ret == 1) |
5366 | return(0); |
5367 | return(XML_SCHEMAV_CVC_MINEXCLUSIVE_VALID); |
5368 | case XML_SCHEMA_FACET_MININCLUSIVE: |
5369 | ret = xmlSchemaCompareValues(val, facet->val); |
5370 | if (ret == -2) |
5371 | return(-1); |
5372 | if ((ret == 1) || (ret == 0)) |
5373 | return(0); |
5374 | return(XML_SCHEMAV_CVC_MININCLUSIVE_VALID); |
5375 | case XML_SCHEMA_FACET_WHITESPACE: |
5376 | /* TODO whitespaces */ |
5377 | /* |
5378 | * NOTE: Whitespace should be handled to normalize |
5379 | * the value to be validated against a the facets; |
5380 | * not to normalize the value in-between. |
5381 | */ |
5382 | return(0); |
5383 | case XML_SCHEMA_FACET_ENUMERATION: |
5384 | if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) { |
5385 | /* |
5386 | * This is to ensure API compatibility with the old |
5387 | * xmlSchemaValidateFacet(). |
5388 | * TODO: Get rid of this case. |
5389 | */ |
5390 | if ((facet->value != NULL) && |
5391 | (xmlStrEqual(facet->value, value))) |
5392 | return(0); |
5393 | } else { |
5394 | ret = xmlSchemaCompareValuesWhtspExt(facet->val->type, |
5395 | facet->val, facet->value, fws, valType, val, |
5396 | value, ws); |
5397 | if (ret == -2) |
5398 | return(-1); |
5399 | if (ret == 0) |
5400 | return(0); |
5401 | } |
5402 | return(XML_SCHEMAV_CVC_ENUMERATION_VALID); |
5403 | case XML_SCHEMA_FACET_LENGTH: |
5404 | /* |
5405 | * SPEC (1.3) "if {primitive type definition} is QName or NOTATION, |
5406 | * then any {value} is facet-valid." |
5407 | */ |
5408 | if ((valType == XML_SCHEMAS_QNAME) || |
5409 | (valType == XML_SCHEMAS_NOTATION)) |
5410 | return (0); |
5411 | /* Falls through. */ |
5412 | case XML_SCHEMA_FACET_MAXLENGTH: |
5413 | case XML_SCHEMA_FACET_MINLENGTH: { |
5414 | unsigned int len = 0; |
5415 | |
5416 | if ((valType == XML_SCHEMAS_QNAME) || |
5417 | (valType == XML_SCHEMAS_NOTATION)) |
5418 | return (0); |
5419 | /* |
5420 | * TODO: length, maxLength and minLength must be of type |
5421 | * nonNegativeInteger only. Check if decimal is used somehow. |
5422 | */ |
5423 | if ((facet->val == NULL) || |
5424 | ((facet->val->type != XML_SCHEMAS_DECIMAL) && |
5425 | (facet->val->type != XML_SCHEMAS_NNINTEGER)) || |
5426 | (facet->val->value.decimal.frac != 0)) { |
5427 | return(-1); |
5428 | } |
5429 | if ((val != NULL) && (val->type == XML_SCHEMAS_HEXBINARY)) |
5430 | len = val->value.hex.total; |
5431 | else if ((val != NULL) && (val->type == XML_SCHEMAS_BASE64BINARY)) |
5432 | len = val->value.base64.total; |
5433 | else { |
5434 | switch (valType) { |
5435 | case XML_SCHEMAS_STRING: |
5436 | case XML_SCHEMAS_NORMSTRING: |
5437 | if (ws == XML_SCHEMA_WHITESPACE_UNKNOWN) { |
5438 | /* |
5439 | * This is to ensure API compatibility with the old |
5440 | * xmlSchemaValidateFacet(). Anyway, this was and |
5441 | * is not the correct handling. |
5442 | * TODO: Get rid of this case somehow. |
5443 | */ |
5444 | if (valType == XML_SCHEMAS_STRING) |
5445 | len = xmlUTF8Strlen(value); |
5446 | else |
5447 | len = xmlSchemaNormLen(value); |
5448 | } else if (value != NULL) { |
5449 | if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) |
5450 | len = xmlSchemaNormLen(value); |
5451 | else |
5452 | /* |
5453 | * Should be OK for "preserve" as well. |
5454 | */ |
5455 | len = xmlUTF8Strlen(value); |
5456 | } |
5457 | break; |
5458 | case XML_SCHEMAS_IDREF: |
5459 | case XML_SCHEMAS_TOKEN: |
5460 | case XML_SCHEMAS_LANGUAGE: |
5461 | case XML_SCHEMAS_NMTOKEN: |
5462 | case XML_SCHEMAS_NAME: |
5463 | case XML_SCHEMAS_NCNAME: |
5464 | case XML_SCHEMAS_ID: |
5465 | case XML_SCHEMAS_ANYURI: |
5466 | if (value != NULL) |
5467 | len = xmlSchemaNormLen(value); |
5468 | break; |
5469 | default: |
5470 | TODO |
5471 | } |
5472 | } |
5473 | if (facet->type == XML_SCHEMA_FACET_LENGTH) { |
5474 | if (len != facet->val->value.decimal.lo) |
5475 | return(XML_SCHEMAV_CVC_LENGTH_VALID); |
5476 | } else if (facet->type == XML_SCHEMA_FACET_MINLENGTH) { |
5477 | if (len < facet->val->value.decimal.lo) |
5478 | return(XML_SCHEMAV_CVC_MINLENGTH_VALID); |
5479 | } else { |
5480 | if (len > facet->val->value.decimal.lo) |
5481 | return(XML_SCHEMAV_CVC_MAXLENGTH_VALID); |
5482 | } |
5483 | break; |
5484 | } |
5485 | case XML_SCHEMA_FACET_TOTALDIGITS: |
5486 | case XML_SCHEMA_FACET_FRACTIONDIGITS: |
5487 | |
5488 | if ((facet->val == NULL) || |
5489 | ((facet->val->type != XML_SCHEMAS_PINTEGER) && |
5490 | (facet->val->type != XML_SCHEMAS_NNINTEGER)) || |
5491 | (facet->val->value.decimal.frac != 0)) { |
5492 | return(-1); |
5493 | } |
5494 | if ((val == NULL) || |
5495 | ((val->type != XML_SCHEMAS_DECIMAL) && |
5496 | (val->type != XML_SCHEMAS_INTEGER) && |
5497 | (val->type != XML_SCHEMAS_NPINTEGER) && |
5498 | (val->type != XML_SCHEMAS_NINTEGER) && |
5499 | (val->type != XML_SCHEMAS_NNINTEGER) && |
5500 | (val->type != XML_SCHEMAS_PINTEGER) && |
5501 | (val->type != XML_SCHEMAS_INT) && |
5502 | (val->type != XML_SCHEMAS_UINT) && |
5503 | (val->type != XML_SCHEMAS_LONG) && |
5504 | (val->type != XML_SCHEMAS_ULONG) && |
5505 | (val->type != XML_SCHEMAS_SHORT) && |
5506 | (val->type != XML_SCHEMAS_USHORT) && |
5507 | (val->type != XML_SCHEMAS_BYTE) && |
5508 | (val->type != XML_SCHEMAS_UBYTE))) { |
5509 | return(-1); |
5510 | } |
5511 | if (facet->type == XML_SCHEMA_FACET_TOTALDIGITS) { |
5512 | if (val->value.decimal.total > facet->val->value.decimal.lo) |
5513 | return(XML_SCHEMAV_CVC_TOTALDIGITS_VALID); |
5514 | |
5515 | } else if (facet->type == XML_SCHEMA_FACET_FRACTIONDIGITS) { |
5516 | if (val->value.decimal.frac > facet->val->value.decimal.lo) |
5517 | return(XML_SCHEMAV_CVC_FRACTIONDIGITS_VALID); |
5518 | } |
5519 | break; |
5520 | default: |
5521 | TODO |
5522 | } |
5523 | return(0); |
5524 | |
5525 | } |
5526 | |
5527 | /** |
5528 | * xmlSchemaValidateFacet: |
5529 | * @base: the base type |
5530 | * @facet: the facet to check |
5531 | * @value: the lexical repr of the value to validate |
5532 | * @val: the precomputed value |
5533 | * |
5534 | * Check a value against a facet condition |
5535 | * |
5536 | * Returns 0 if the element is schemas valid, a positive error code |
5537 | * number otherwise and -1 in case of internal or API error. |
5538 | */ |
5539 | int |
5540 | xmlSchemaValidateFacet(xmlSchemaTypePtr base, |
5541 | xmlSchemaFacetPtr facet, |
5542 | const xmlChar *value, |
5543 | xmlSchemaValPtr val) |
5544 | { |
5545 | /* |
5546 | * This tries to ensure API compatibility regarding the old |
5547 | * xmlSchemaValidateFacet() and the new xmlSchemaValidateFacetInternal() and |
5548 | * xmlSchemaValidateFacetWhtsp(). |
5549 | */ |
5550 | if (val != NULL) |
5551 | return(xmlSchemaValidateFacetInternal(facet, |
5552 | XML_SCHEMA_WHITESPACE_UNKNOWN, val->type, value, val, |
5553 | XML_SCHEMA_WHITESPACE_UNKNOWN)); |
5554 | else if (base != NULL) |
5555 | return(xmlSchemaValidateFacetInternal(facet, |
5556 | XML_SCHEMA_WHITESPACE_UNKNOWN, base->builtInType, value, val, |
5557 | XML_SCHEMA_WHITESPACE_UNKNOWN)); |
5558 | return(-1); |
5559 | } |
5560 | |
5561 | /** |
5562 | * xmlSchemaValidateFacetWhtsp: |
5563 | * @facet: the facet to check |
5564 | * @fws: the whitespace type of the facet's value |
5565 | * @valType: the built-in type of the value |
5566 | * @value: the lexical (or normalized for pattern) repr of the value to validate |
5567 | * @val: the precomputed value |
5568 | * @ws: the whitespace type of the value |
5569 | * |
5570 | * Check a value against a facet condition. This takes value normalization |
5571 | * according to the specified whitespace types into account. |
5572 | * Note that @value needs to be the *normalized* value if the facet |
5573 | * is of type "pattern". |
5574 | * |
5575 | * Returns 0 if the element is schemas valid, a positive error code |
5576 | * number otherwise and -1 in case of internal or API error. |
5577 | */ |
5578 | int |
5579 | xmlSchemaValidateFacetWhtsp(xmlSchemaFacetPtr facet, |
5580 | xmlSchemaWhitespaceValueType fws, |
5581 | xmlSchemaValType valType, |
5582 | const xmlChar *value, |
5583 | xmlSchemaValPtr val, |
5584 | xmlSchemaWhitespaceValueType ws) |
5585 | { |
5586 | return(xmlSchemaValidateFacetInternal(facet, fws, valType, |
5587 | value, val, ws)); |
5588 | } |
5589 | |
5590 | #if 0 |
5591 | #ifndef DBL_DIG |
5592 | #define DBL_DIG 16 |
5593 | #endif |
5594 | #ifndef DBL_EPSILON |
5595 | #define DBL_EPSILON 1E-9 |
5596 | #endif |
5597 | |
5598 | #define INTEGER_DIGITS DBL_DIG |
5599 | #define FRACTION_DIGITS (DBL_DIG + 1) |
5600 | #define EXPONENT_DIGITS (3 + 2) |
5601 | |
5602 | /** |
5603 | * xmlXPathFormatNumber: |
5604 | * @number: number to format |
5605 | * @buffer: output buffer |
5606 | * @buffersize: size of output buffer |
5607 | * |
5608 | * Convert the number into a string representation. |
5609 | */ |
5610 | static void |
5611 | xmlSchemaFormatFloat(double number, char buffer[], int buffersize) |
5612 | { |
5613 | switch (xmlXPathIsInf(number)) { |
5614 | case 1: |
5615 | if (buffersize > (int)sizeof("INF" )) |
5616 | snprintf(buffer, buffersize, "INF" ); |
5617 | break; |
5618 | case -1: |
5619 | if (buffersize > (int)sizeof("-INF" )) |
5620 | snprintf(buffer, buffersize, "-INF" ); |
5621 | break; |
5622 | default: |
5623 | if (xmlXPathIsNaN(number)) { |
5624 | if (buffersize > (int)sizeof("NaN" )) |
5625 | snprintf(buffer, buffersize, "NaN" ); |
5626 | } else if (number == 0) { |
5627 | snprintf(buffer, buffersize, "0.0E0" ); |
5628 | } else { |
5629 | /* 3 is sign, decimal point, and terminating zero */ |
5630 | char work[DBL_DIG + EXPONENT_DIGITS + 3]; |
5631 | int integer_place, fraction_place; |
5632 | char *ptr; |
5633 | char *after_fraction; |
5634 | double absolute_value; |
5635 | int size; |
5636 | |
5637 | absolute_value = fabs(number); |
5638 | |
5639 | /* |
5640 | * Result is in work, and after_fraction points |
5641 | * just past the fractional part. |
5642 | * Use scientific notation |
5643 | */ |
5644 | integer_place = DBL_DIG + EXPONENT_DIGITS + 1; |
5645 | fraction_place = DBL_DIG - 1; |
5646 | snprintf(work, sizeof(work),"%*.*e" , |
5647 | integer_place, fraction_place, number); |
5648 | after_fraction = strchr(work + DBL_DIG, 'e'); |
5649 | /* Remove fractional trailing zeroes */ |
5650 | ptr = after_fraction; |
5651 | while (*(--ptr) == '0') |
5652 | ; |
5653 | if (*ptr != '.') |
5654 | ptr++; |
5655 | while ((*ptr++ = *after_fraction++) != 0); |
5656 | |
5657 | /* Finally copy result back to caller */ |
5658 | size = strlen(work) + 1; |
5659 | if (size > buffersize) { |
5660 | work[buffersize - 1] = 0; |
5661 | size = buffersize; |
5662 | } |
5663 | memmove(buffer, work, size); |
5664 | } |
5665 | break; |
5666 | } |
5667 | } |
5668 | #endif |
5669 | |
5670 | /** |
5671 | * xmlSchemaGetCanonValue: |
5672 | * @val: the precomputed value |
5673 | * @retValue: the returned value |
5674 | * |
5675 | * Get the canonical lexical representation of the value. |
5676 | * The caller has to FREE the returned retValue. |
5677 | * |
5678 | * WARNING: Some value types are not supported yet, resulting |
5679 | * in a @retValue of "???". |
5680 | * |
5681 | * TODO: XML Schema 1.0 does not define canonical representations |
5682 | * for: duration, gYearMonth, gYear, gMonthDay, gMonth, gDay, |
5683 | * anyURI, QName, NOTATION. This will be fixed in XML Schema 1.1. |
5684 | * |
5685 | * |
5686 | * Returns 0 if the value could be built, 1 if the value type is |
5687 | * not supported yet and -1 in case of API errors. |
5688 | */ |
5689 | int |
5690 | xmlSchemaGetCanonValue(xmlSchemaValPtr val, const xmlChar **retValue) |
5691 | { |
5692 | if ((retValue == NULL) || (val == NULL)) |
5693 | return (-1); |
5694 | *retValue = NULL; |
5695 | switch (val->type) { |
5696 | case XML_SCHEMAS_STRING: |
5697 | if (val->value.str == NULL) |
5698 | *retValue = BAD_CAST xmlStrdup(BAD_CAST "" ); |
5699 | else |
5700 | *retValue = |
5701 | BAD_CAST xmlStrdup((const xmlChar *) val->value.str); |
5702 | break; |
5703 | case XML_SCHEMAS_NORMSTRING: |
5704 | if (val->value.str == NULL) |
5705 | *retValue = BAD_CAST xmlStrdup(BAD_CAST "" ); |
5706 | else { |
5707 | *retValue = xmlSchemaWhiteSpaceReplace( |
5708 | (const xmlChar *) val->value.str); |
5709 | if ((*retValue) == NULL) |
5710 | *retValue = BAD_CAST xmlStrdup( |
5711 | (const xmlChar *) val->value.str); |
5712 | } |
5713 | break; |
5714 | case XML_SCHEMAS_TOKEN: |
5715 | case XML_SCHEMAS_LANGUAGE: |
5716 | case XML_SCHEMAS_NMTOKEN: |
5717 | case XML_SCHEMAS_NAME: |
5718 | case XML_SCHEMAS_NCNAME: |
5719 | case XML_SCHEMAS_ID: |
5720 | case XML_SCHEMAS_IDREF: |
5721 | case XML_SCHEMAS_ENTITY: |
5722 | case XML_SCHEMAS_NOTATION: /* Unclear */ |
5723 | case XML_SCHEMAS_ANYURI: /* Unclear */ |
5724 | if (val->value.str == NULL) |
5725 | return (-1); |
5726 | *retValue = |
5727 | BAD_CAST xmlSchemaCollapseString(BAD_CAST val->value.str); |
5728 | if (*retValue == NULL) |
5729 | *retValue = |
5730 | BAD_CAST xmlStrdup((const xmlChar *) val->value.str); |
5731 | break; |
5732 | case XML_SCHEMAS_QNAME: |
5733 | /* TODO: Unclear in XML Schema 1.0. */ |
5734 | if (val->value.qname.uri == NULL) { |
5735 | *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.qname.name); |
5736 | return (0); |
5737 | } else { |
5738 | *retValue = BAD_CAST xmlStrdup(BAD_CAST "{" ); |
5739 | *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue), |
5740 | BAD_CAST val->value.qname.uri); |
5741 | *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue), |
5742 | BAD_CAST "}" ); |
5743 | *retValue = BAD_CAST xmlStrcat((xmlChar *) (*retValue), |
5744 | BAD_CAST val->value.qname.uri); |
5745 | } |
5746 | break; |
5747 | case XML_SCHEMAS_DECIMAL: |
5748 | /* |
5749 | * TODO: Lookout for a more simple implementation. |
5750 | */ |
5751 | if ((val->value.decimal.total == 1) && |
5752 | (val->value.decimal.lo == 0)) { |
5753 | *retValue = xmlStrdup(BAD_CAST "0.0" ); |
5754 | } else { |
5755 | xmlSchemaValDecimal dec = val->value.decimal; |
5756 | int bufsize; |
5757 | char *buf = NULL, *offs; |
5758 | |
5759 | /* Add room for the decimal point as well. */ |
5760 | bufsize = dec.total + 2; |
5761 | if (dec.sign) |
5762 | bufsize++; |
5763 | /* Add room for leading/trailing zero. */ |
5764 | if ((dec.frac == 0) || (dec.frac == dec.total)) |
5765 | bufsize++; |
5766 | buf = xmlMalloc(bufsize); |
5767 | if (buf == NULL) |
5768 | return(-1); |
5769 | offs = buf; |
5770 | if (dec.sign) |
5771 | *offs++ = '-'; |
5772 | if (dec.frac == dec.total) { |
5773 | *offs++ = '0'; |
5774 | *offs++ = '.'; |
5775 | } |
5776 | if (dec.hi != 0) |
5777 | snprintf(offs, bufsize - (offs - buf), |
5778 | "%lu%lu%lu" , dec.hi, dec.mi, dec.lo); |
5779 | else if (dec.mi != 0) |
5780 | snprintf(offs, bufsize - (offs - buf), |
5781 | "%lu%lu" , dec.mi, dec.lo); |
5782 | else |
5783 | snprintf(offs, bufsize - (offs - buf), |
5784 | "%lu" , dec.lo); |
5785 | |
5786 | if (dec.frac != 0) { |
5787 | if (dec.frac != dec.total) { |
5788 | int diff = dec.total - dec.frac; |
5789 | /* |
5790 | * Insert the decimal point. |
5791 | */ |
5792 | memmove(offs + diff + 1, offs + diff, dec.frac +1); |
5793 | offs[diff] = '.'; |
5794 | } else { |
5795 | unsigned int i = 0; |
5796 | /* |
5797 | * Insert missing zeroes behind the decimal point. |
5798 | */ |
5799 | while (*(offs + i) != 0) |
5800 | i++; |
5801 | if (i < dec.total) { |
5802 | memmove(offs + (dec.total - i), offs, i +1); |
5803 | memset(offs, '0', dec.total - i); |
5804 | } |
5805 | } |
5806 | } else { |
5807 | /* |
5808 | * Append decimal point and zero. |
5809 | */ |
5810 | offs = buf + bufsize - 1; |
5811 | *offs-- = 0; |
5812 | *offs-- = '0'; |
5813 | *offs-- = '.'; |
5814 | } |
5815 | *retValue = BAD_CAST buf; |
5816 | } |
5817 | break; |
5818 | case XML_SCHEMAS_INTEGER: |
5819 | case XML_SCHEMAS_PINTEGER: |
5820 | case XML_SCHEMAS_NPINTEGER: |
5821 | case XML_SCHEMAS_NINTEGER: |
5822 | case XML_SCHEMAS_NNINTEGER: |
5823 | case XML_SCHEMAS_LONG: |
5824 | case XML_SCHEMAS_BYTE: |
5825 | case XML_SCHEMAS_SHORT: |
5826 | case XML_SCHEMAS_INT: |
5827 | case XML_SCHEMAS_UINT: |
5828 | case XML_SCHEMAS_ULONG: |
5829 | case XML_SCHEMAS_USHORT: |
5830 | case XML_SCHEMAS_UBYTE: |
5831 | if ((val->value.decimal.total == 1) && |
5832 | (val->value.decimal.lo == 0)) |
5833 | *retValue = xmlStrdup(BAD_CAST "0" ); |
5834 | else { |
5835 | xmlSchemaValDecimal dec = val->value.decimal; |
5836 | int bufsize = dec.total + 1; |
5837 | |
5838 | /* Add room for the decimal point as well. */ |
5839 | if (dec.sign) |
5840 | bufsize++; |
5841 | *retValue = xmlMalloc(bufsize); |
5842 | if (*retValue == NULL) |
5843 | return(-1); |
5844 | if (dec.hi != 0) { |
5845 | if (dec.sign) |
5846 | snprintf((char *) *retValue, bufsize, |
5847 | "-%lu%lu%lu" , dec.hi, dec.mi, dec.lo); |
5848 | else |
5849 | snprintf((char *) *retValue, bufsize, |
5850 | "%lu%lu%lu" , dec.hi, dec.mi, dec.lo); |
5851 | } else if (dec.mi != 0) { |
5852 | if (dec.sign) |
5853 | snprintf((char *) *retValue, bufsize, |
5854 | "-%lu%lu" , dec.mi, dec.lo); |
5855 | else |
5856 | snprintf((char *) *retValue, bufsize, |
5857 | "%lu%lu" , dec.mi, dec.lo); |
5858 | } else { |
5859 | if (dec.sign) |
5860 | snprintf((char *) *retValue, bufsize, "-%lu" , dec.lo); |
5861 | else |
5862 | snprintf((char *) *retValue, bufsize, "%lu" , dec.lo); |
5863 | } |
5864 | } |
5865 | break; |
5866 | case XML_SCHEMAS_BOOLEAN: |
5867 | if (val->value.b) |
5868 | *retValue = BAD_CAST xmlStrdup(BAD_CAST "true" ); |
5869 | else |
5870 | *retValue = BAD_CAST xmlStrdup(BAD_CAST "false" ); |
5871 | break; |
5872 | case XML_SCHEMAS_DURATION: { |
5873 | char buf[100]; |
5874 | unsigned long year; |
5875 | unsigned long mon, day, hour = 0, min = 0; |
5876 | double sec = 0, left; |
5877 | |
5878 | /* TODO: Unclear in XML Schema 1.0 */ |
5879 | /* |
5880 | * TODO: This results in a normalized output of the value |
5881 | * - which is NOT conformant to the spec - |
5882 | * since the exact values of each property are not |
5883 | * recoverable. Think about extending the structure to |
5884 | * provide a field for every property. |
5885 | */ |
5886 | year = (unsigned long) FQUOTIENT(labs(val->value.dur.mon), 12); |
5887 | mon = labs(val->value.dur.mon) - 12 * year; |
5888 | |
5889 | day = (unsigned long) FQUOTIENT(fabs(val->value.dur.sec), 86400); |
5890 | left = fabs(val->value.dur.sec) - day * 86400; |
5891 | if (left > 0) { |
5892 | hour = (unsigned long) FQUOTIENT(left, 3600); |
5893 | left = left - (hour * 3600); |
5894 | if (left > 0) { |
5895 | min = (unsigned long) FQUOTIENT(left, 60); |
5896 | sec = left - (min * 60); |
5897 | } |
5898 | } |
5899 | if ((val->value.dur.mon < 0) || (val->value.dur.sec < 0)) |
5900 | snprintf(buf, 100, "P%luY%luM%luDT%luH%luM%.14gS" , |
5901 | year, mon, day, hour, min, sec); |
5902 | else |
5903 | snprintf(buf, 100, "-P%luY%luM%luDT%luH%luM%.14gS" , |
5904 | year, mon, day, hour, min, sec); |
5905 | *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); |
5906 | } |
5907 | break; |
5908 | case XML_SCHEMAS_GYEAR: { |
5909 | char buf[30]; |
5910 | /* TODO: Unclear in XML Schema 1.0 */ |
5911 | /* TODO: What to do with the timezone? */ |
5912 | snprintf(buf, 30, "%04ld" , val->value.date.year); |
5913 | *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); |
5914 | } |
5915 | break; |
5916 | case XML_SCHEMAS_GMONTH: { |
5917 | /* TODO: Unclear in XML Schema 1.0 */ |
5918 | /* TODO: What to do with the timezone? */ |
5919 | *retValue = xmlMalloc(6); |
5920 | if (*retValue == NULL) |
5921 | return(-1); |
5922 | snprintf((char *) *retValue, 6, "--%02u" , |
5923 | val->value.date.mon); |
5924 | } |
5925 | break; |
5926 | case XML_SCHEMAS_GDAY: { |
5927 | /* TODO: Unclear in XML Schema 1.0 */ |
5928 | /* TODO: What to do with the timezone? */ |
5929 | *retValue = xmlMalloc(6); |
5930 | if (*retValue == NULL) |
5931 | return(-1); |
5932 | snprintf((char *) *retValue, 6, "---%02u" , |
5933 | val->value.date.day); |
5934 | } |
5935 | break; |
5936 | case XML_SCHEMAS_GMONTHDAY: { |
5937 | /* TODO: Unclear in XML Schema 1.0 */ |
5938 | /* TODO: What to do with the timezone? */ |
5939 | *retValue = xmlMalloc(8); |
5940 | if (*retValue == NULL) |
5941 | return(-1); |
5942 | snprintf((char *) *retValue, 8, "--%02u-%02u" , |
5943 | val->value.date.mon, val->value.date.day); |
5944 | } |
5945 | break; |
5946 | case XML_SCHEMAS_GYEARMONTH: { |
5947 | char buf[35]; |
5948 | /* TODO: Unclear in XML Schema 1.0 */ |
5949 | /* TODO: What to do with the timezone? */ |
5950 | if (val->value.date.year < 0) |
5951 | snprintf(buf, 35, "-%04ld-%02u" , |
5952 | labs(val->value.date.year), |
5953 | val->value.date.mon); |
5954 | else |
5955 | snprintf(buf, 35, "%04ld-%02u" , |
5956 | val->value.date.year, val->value.date.mon); |
5957 | *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); |
5958 | } |
5959 | break; |
5960 | case XML_SCHEMAS_TIME: |
5961 | { |
5962 | char buf[30]; |
5963 | |
5964 | if (val->value.date.tz_flag) { |
5965 | xmlSchemaValPtr norm; |
5966 | |
5967 | norm = xmlSchemaDateNormalize(val, 0); |
5968 | if (norm == NULL) |
5969 | return (-1); |
5970 | /* |
5971 | * TODO: Check if "%.14g" is portable. |
5972 | */ |
5973 | snprintf(buf, 30, |
5974 | "%02u:%02u:%02.14gZ" , |
5975 | norm->value.date.hour, |
5976 | norm->value.date.min, |
5977 | norm->value.date.sec); |
5978 | xmlSchemaFreeValue(norm); |
5979 | } else { |
5980 | snprintf(buf, 30, |
5981 | "%02u:%02u:%02.14g" , |
5982 | val->value.date.hour, |
5983 | val->value.date.min, |
5984 | val->value.date.sec); |
5985 | } |
5986 | *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); |
5987 | } |
5988 | break; |
5989 | case XML_SCHEMAS_DATE: |
5990 | { |
5991 | char buf[30]; |
5992 | |
5993 | if (val->value.date.tz_flag) { |
5994 | xmlSchemaValPtr norm; |
5995 | |
5996 | norm = xmlSchemaDateNormalize(val, 0); |
5997 | if (norm == NULL) |
5998 | return (-1); |
5999 | /* |
6000 | * TODO: Append the canonical value of the |
6001 | * recoverable timezone and not "Z". |
6002 | */ |
6003 | snprintf(buf, 30, |
6004 | "%04ld:%02u:%02uZ" , |
6005 | norm->value.date.year, norm->value.date.mon, |
6006 | norm->value.date.day); |
6007 | xmlSchemaFreeValue(norm); |
6008 | } else { |
6009 | snprintf(buf, 30, |
6010 | "%04ld:%02u:%02u" , |
6011 | val->value.date.year, val->value.date.mon, |
6012 | val->value.date.day); |
6013 | } |
6014 | *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); |
6015 | } |
6016 | break; |
6017 | case XML_SCHEMAS_DATETIME: |
6018 | { |
6019 | char buf[50]; |
6020 | |
6021 | if (val->value.date.tz_flag) { |
6022 | xmlSchemaValPtr norm; |
6023 | |
6024 | norm = xmlSchemaDateNormalize(val, 0); |
6025 | if (norm == NULL) |
6026 | return (-1); |
6027 | /* |
6028 | * TODO: Check if "%.14g" is portable. |
6029 | */ |
6030 | snprintf(buf, 50, |
6031 | "%04ld:%02u:%02uT%02u:%02u:%02.14gZ" , |
6032 | norm->value.date.year, norm->value.date.mon, |
6033 | norm->value.date.day, norm->value.date.hour, |
6034 | norm->value.date.min, norm->value.date.sec); |
6035 | xmlSchemaFreeValue(norm); |
6036 | } else { |
6037 | snprintf(buf, 50, |
6038 | "%04ld:%02u:%02uT%02u:%02u:%02.14g" , |
6039 | val->value.date.year, val->value.date.mon, |
6040 | val->value.date.day, val->value.date.hour, |
6041 | val->value.date.min, val->value.date.sec); |
6042 | } |
6043 | *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); |
6044 | } |
6045 | break; |
6046 | case XML_SCHEMAS_HEXBINARY: |
6047 | *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.hex.str); |
6048 | break; |
6049 | case XML_SCHEMAS_BASE64BINARY: |
6050 | /* |
6051 | * TODO: Is the following spec piece implemented?: |
6052 | * SPEC: "Note: For some values the canonical form defined |
6053 | * above does not conform to [RFC 2045], which requires breaking |
6054 | * with linefeeds at appropriate intervals." |
6055 | */ |
6056 | *retValue = BAD_CAST xmlStrdup(BAD_CAST val->value.base64.str); |
6057 | break; |
6058 | case XML_SCHEMAS_FLOAT: { |
6059 | char buf[30]; |
6060 | /* |
6061 | * |m| < 16777216, -149 <= e <= 104. |
6062 | * TODO: Handle, NaN, INF, -INF. The format is not |
6063 | * yet conformant. The c type float does not cover |
6064 | * the whole range. |
6065 | */ |
6066 | snprintf(buf, 30, "%01.14e" , val->value.f); |
6067 | *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); |
6068 | } |
6069 | break; |
6070 | case XML_SCHEMAS_DOUBLE: { |
6071 | char buf[40]; |
6072 | /* |m| < 9007199254740992, -1075 <= e <= 970 */ |
6073 | /* |
6074 | * TODO: Handle, NaN, INF, -INF. The format is not |
6075 | * yet conformant. The c type float does not cover |
6076 | * the whole range. |
6077 | */ |
6078 | snprintf(buf, 40, "%01.14e" , val->value.d); |
6079 | *retValue = BAD_CAST xmlStrdup(BAD_CAST buf); |
6080 | } |
6081 | break; |
6082 | default: |
6083 | *retValue = BAD_CAST xmlStrdup(BAD_CAST "???" ); |
6084 | return (1); |
6085 | } |
6086 | if (*retValue == NULL) |
6087 | return(-1); |
6088 | return (0); |
6089 | } |
6090 | |
6091 | /** |
6092 | * xmlSchemaGetCanonValueWhtsp: |
6093 | * @val: the precomputed value |
6094 | * @retValue: the returned value |
6095 | * @ws: the whitespace type of the value |
6096 | * |
6097 | * Get the canonical representation of the value. |
6098 | * The caller has to free the returned @retValue. |
6099 | * |
6100 | * Returns 0 if the value could be built, 1 if the value type is |
6101 | * not supported yet and -1 in case of API errors. |
6102 | */ |
6103 | int |
6104 | xmlSchemaGetCanonValueWhtsp(xmlSchemaValPtr val, |
6105 | const xmlChar **retValue, |
6106 | xmlSchemaWhitespaceValueType ws) |
6107 | { |
6108 | if ((retValue == NULL) || (val == NULL)) |
6109 | return (-1); |
6110 | if ((ws == XML_SCHEMA_WHITESPACE_UNKNOWN) || |
6111 | (ws > XML_SCHEMA_WHITESPACE_COLLAPSE)) |
6112 | return (-1); |
6113 | |
6114 | *retValue = NULL; |
6115 | switch (val->type) { |
6116 | case XML_SCHEMAS_STRING: |
6117 | if (val->value.str == NULL) |
6118 | *retValue = BAD_CAST xmlStrdup(BAD_CAST "" ); |
6119 | else if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) |
6120 | *retValue = xmlSchemaCollapseString(val->value.str); |
6121 | else if (ws == XML_SCHEMA_WHITESPACE_REPLACE) |
6122 | *retValue = xmlSchemaWhiteSpaceReplace(val->value.str); |
6123 | if ((*retValue) == NULL) |
6124 | *retValue = BAD_CAST xmlStrdup(val->value.str); |
6125 | break; |
6126 | case XML_SCHEMAS_NORMSTRING: |
6127 | if (val->value.str == NULL) |
6128 | *retValue = BAD_CAST xmlStrdup(BAD_CAST "" ); |
6129 | else { |
6130 | if (ws == XML_SCHEMA_WHITESPACE_COLLAPSE) |
6131 | *retValue = xmlSchemaCollapseString(val->value.str); |
6132 | else |
6133 | *retValue = xmlSchemaWhiteSpaceReplace(val->value.str); |
6134 | if ((*retValue) == NULL) |
6135 | *retValue = BAD_CAST xmlStrdup(val->value.str); |
6136 | } |
6137 | break; |
6138 | default: |
6139 | return (xmlSchemaGetCanonValue(val, retValue)); |
6140 | } |
6141 | return (0); |
6142 | } |
6143 | |
6144 | /** |
6145 | * xmlSchemaGetValType: |
6146 | * @val: a schemas value |
6147 | * |
6148 | * Accessor for the type of a value |
6149 | * |
6150 | * Returns the xmlSchemaValType of the value |
6151 | */ |
6152 | xmlSchemaValType |
6153 | xmlSchemaGetValType(xmlSchemaValPtr val) |
6154 | { |
6155 | if (val == NULL) |
6156 | return(XML_SCHEMAS_UNKNOWN); |
6157 | return (val->type); |
6158 | } |
6159 | |
6160 | #define bottom_xmlschemastypes |
6161 | #include "elfgcchack.h" |
6162 | #endif /* LIBXML_SCHEMAS_ENABLED */ |
6163 | |