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