blob: 200047fd2e0c2022d123ff2e3b9698c35c4023c6 [file] [log] [blame]
Daniel Veillard4255d502002-04-16 15:50:10 +00001/*
2 * schemastypes.c : implementation of the XML Schema Datatypes
3 * definition and validity checking
4 *
5 * See Copyright for the status of this software.
6 *
7 * Daniel Veillard <veillard@redhat.com>
8 */
9
10#define IN_LIBXML
11#include "libxml.h"
12
13#ifdef LIBXML_SCHEMAS_ENABLED
14
15#include <string.h>
16#include <libxml/xmlmemory.h>
17#include <libxml/parser.h>
18#include <libxml/parserInternals.h>
19#include <libxml/hash.h>
20#include <libxml/valid.h>
21
22#include <libxml/xmlschemas.h>
23#include <libxml/schemasInternals.h>
24#include <libxml/xmlschemastypes.h>
25
26#define DEBUG
27
28#define TODO \
29 xmlGenericError(xmlGenericErrorContext, \
30 "Unimplemented block at %s:%d\n", \
31 __FILE__, __LINE__);
32
33#define XML_SCHEMAS_NAMESPACE_NAME \
34 (const xmlChar *)"http://www.w3.org/2001/XMLSchema"
35
36typedef enum {
37 XML_SCHEMAS_UNKNOWN = 0,
38 XML_SCHEMAS_STRING,
39 XML_SCHEMAS_NMTOKEN,
40 XML_SCHEMAS_DECIMAL,
41 XML_SCHEMAS_,
42 XML_SCHEMAS_XXX
43} xmlSchemaValType;
44
45unsigned long powten[10] = {
46 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000L,
47 100000000L, 1000000000L
48};
49
50typedef struct _xmlSchemaValDecimal xmlSchemaValDecimal;
51typedef xmlSchemaValDecimal *xmlSchemaValDecimalPtr;
52struct _xmlSchemaValDecimal {
53 /* would use long long but not portable */
54 unsigned long base;
55 unsigned int extra;
56 int sign:1;
57 int frac:7;
58 int total:8;
59};
60
61struct _xmlSchemaVal {
62 xmlSchemaValType type;
63 union {
64 xmlSchemaValDecimal decimal;
65 } value;
66};
67
68static int xmlSchemaTypesInitialized = 0;
69static xmlHashTablePtr xmlSchemaTypesBank = NULL;
70
71static xmlSchemaTypePtr xmlSchemaTypeStringDef = NULL;
72static xmlSchemaTypePtr xmlSchemaTypeAnyTypeDef = NULL;
73static xmlSchemaTypePtr xmlSchemaTypeAnySimpleTypeDef = NULL;
74static xmlSchemaTypePtr xmlSchemaTypeDecimalDef = NULL;
75static xmlSchemaTypePtr xmlSchemaTypeDateDef = NULL;
76static xmlSchemaTypePtr xmlSchemaTypePositiveIntegerDef = NULL;
77static xmlSchemaTypePtr xmlSchemaTypeNonNegativeIntegerDef = NULL;
78static xmlSchemaTypePtr xmlSchemaTypeNmtoken = NULL;
79
80/*
81 * xmlSchemaInitBasicType:
82 * @name: the type name
83 *
84 * Initialize one default type
85 */
86static xmlSchemaTypePtr
87xmlSchemaInitBasicType(const char *name) {
88 xmlSchemaTypePtr ret;
89
90 ret = (xmlSchemaTypePtr) xmlMalloc(sizeof(xmlSchemaType));
91 if (ret == NULL) {
92 xmlGenericError(xmlGenericErrorContext,
93 "Could not initilize type %s: out of memory\n", name);
94 return(NULL);
95 }
96 memset(ret, 0, sizeof(xmlSchemaType));
97 ret->name = xmlStrdup((const xmlChar *)name);
98 ret->type = XML_SCHEMA_TYPE_BASIC;
99 ret->contentType = XML_SCHEMA_CONTENT_BASIC;
100 xmlHashAddEntry2(xmlSchemaTypesBank, ret->name,
101 XML_SCHEMAS_NAMESPACE_NAME, ret);
102 return(ret);
103}
104
105/*
106 * xmlSchemaInitTypes:
107 *
108 * Initialize the default XML Schemas type library
109 */
110void
111xmlSchemaInitTypes(void) {
112 if (xmlSchemaTypesInitialized != 0)
113 return;
114 xmlSchemaTypesBank = xmlHashCreate(40);
115
116 xmlSchemaTypeStringDef = xmlSchemaInitBasicType("string");
117 xmlSchemaTypeAnyTypeDef = xmlSchemaInitBasicType("anyType");
118 xmlSchemaTypeAnySimpleTypeDef = xmlSchemaInitBasicType("anySimpleType");
119 xmlSchemaTypeDecimalDef = xmlSchemaInitBasicType("decimal");
120 xmlSchemaTypeDateDef = xmlSchemaInitBasicType("date");
121 xmlSchemaTypePositiveIntegerDef = xmlSchemaInitBasicType("positiveInteger");
122 xmlSchemaTypeNonNegativeIntegerDef =
123 xmlSchemaInitBasicType("nonNegativeInteger");
124 xmlSchemaTypeNmtoken = xmlSchemaInitBasicType("NMTOKEN");
125
126 xmlSchemaTypesInitialized = 1;
127}
128
129/**
130 * xmlSchemaCleanupTypes:
131 *
132 * Cleanup the default XML Schemas type library
133 */
134void
135xmlSchemaCleanupTypes(void) {
136 if (xmlSchemaTypesInitialized == 0)
137 return;
138 xmlHashFree(xmlSchemaTypesBank, (xmlHashDeallocator) xmlSchemaFreeType);
139 xmlSchemaTypesInitialized = 0;
140}
141
142/**
143 * xmlSchemaNewValue:
144 * @type: the value type
145 *
146 * Allocate a new simple type value
147 *
148 * Returns a pointer to the new value or NULL in case of error
149 */
150static xmlSchemaValPtr
151xmlSchemaNewValue(xmlSchemaValType type) {
152 xmlSchemaValPtr value;
153
154 value = (xmlSchemaValPtr) xmlMalloc(sizeof(xmlSchemaVal));
155 if (value == NULL) {
156 return(NULL);
157 }
158 memset(value, 0, sizeof(xmlSchemaVal));
159 value->type = type;
160 return(value);
161}
162
163/**
164 * xmlSchemaFreeValue:
165 * @value: the value to free
166 *
167 * Cleanup the default XML Schemas type library
168 */
169void
170xmlSchemaFreeValue(xmlSchemaValPtr value) {
171 if (value == NULL)
172 return;
173 xmlFree(value);
174}
175
176/**
177 * xmlSchemaGetPredefinedType:
178 * @name: the type name
179 * @ns: the URI of the namespace usually "http://www.w3.org/2001/XMLSchema"
180 *
181 * Lookup a type in the default XML Schemas type library
182 *
183 * Returns the type if found, NULL otherwise
184 */
185xmlSchemaTypePtr
186xmlSchemaGetPredefinedType(const xmlChar *name, const xmlChar *ns) {
187 if (xmlSchemaTypesInitialized == 0)
188 xmlSchemaInitTypes();
189 if (name == NULL)
190 return(NULL);
191 return((xmlSchemaTypePtr) xmlHashLookup2(xmlSchemaTypesBank, name, ns));
192}
193/**
194 * xmlSchemaValidatePredefinedType:
195 * @type: the predefined type
196 * @value: the value to check
197 * @val: the return computed value
198 *
199 * Check that a value conforms to the lexical space of the predefined type.
200 * if true a value is computed and returned in @val.
201 *
202 * Returns 0 if this validates, a positive error code number otherwise
203 * and -1 in case of internal or API error.
204 */
205int
206xmlSchemaValidatePredefinedType(xmlSchemaTypePtr type, const xmlChar *value,
207 xmlSchemaValPtr *val) {
208 xmlSchemaValPtr v;
209
210 if (xmlSchemaTypesInitialized == 0)
211 return(-1);
212 if (type == NULL)
213 return(-1);
214 if (val != NULL)
215 *val = NULL;
216 if (type == xmlSchemaTypeStringDef) {
217 return(0);
218 } else if (type == xmlSchemaTypeAnyTypeDef) {
219 return(0);
220 } else if (type == xmlSchemaTypeAnySimpleTypeDef) {
221 return(0);
222 } else if (type == xmlSchemaTypeNmtoken) {
223 if (xmlValidateNmtokenValue(value))
224 return(0);
225 return(1);
226 } else if (type == xmlSchemaTypeDecimalDef) {
227 const xmlChar *cur = value, *tmp;
228 int frac = 0, main, neg = 0;
229 unsigned long base = 0;
230 if (cur == NULL)
231 return(1);
232 if (*cur == '+')
233 cur++;
234 else if (*cur == '-') {
235 neg = 1;
236 cur++;
237 }
238 tmp = cur;
239 while ((*cur >= '0') && (*cur <= '9')) {
240 base = base * 10 + (*cur - '0');
241 cur++;
242 }
243 main = cur - tmp;
244 if (*cur == '.') {
245 cur++;
246 tmp = cur;
247 while ((*cur >= '0') && (*cur <= '9')) {
248 base = base * 10 + (*cur - '0');
249 cur++;
250 }
251 frac = cur - tmp;
252 }
253 if (*cur != 0)
254 return(1);
255 if (val != NULL) {
256 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
257 if (v != NULL) {
258 v->value.decimal.base = base;
259 v->value.decimal.sign = neg;
260 v->value.decimal.frac = frac;
261 v->value.decimal.total = frac + main;
262 *val = v;
263 }
264 }
265 return(0);
266 } else if (type == xmlSchemaTypeDateDef) {
267 const xmlChar *cur = value;
268 if (cur == NULL)
269 return(1);
270 if (*cur == '-')
271 cur++;
272 if ((*cur < '0') || (*cur > '9'))
273 return(1);
274 if ((*cur < '0') || (*cur > '9'))
275 return(1);
276 if ((*cur < '0') || (*cur > '9'))
277 return(1);
278 if ((*cur < '0') || (*cur > '9'))
279 return(1);
280 while ((*cur >= '0') && (*cur <= '9'))
281 cur++;
282 if (*cur != '-')
283 return(1);
284 cur++;
285 if ((*cur != '0') && (*cur != '1'))
286 return(1);
287 if ((*cur == '0') && (cur[1] == '0'))
288 return(1);
289 if ((*cur == '1') && ((cur[1] < '0') || (cur[1] > '2')))
290 return(1);
291 cur += 2;
292 if (*cur != '-')
293 return(1);
294 cur++;
295 if ((*cur < '0') || (*cur > '3'))
296 return(1);
297 if ((*cur == '0') && (cur[1] == '0'))
298 return(1);
299 if ((*cur == '3') && ((cur[1] < '0') || (cur[1] > '1')))
300 return(1);
301 cur += 2;
302 if (*cur != 0)
303 return(1);
304 return(0);
305 } else if (type == xmlSchemaTypePositiveIntegerDef) {
306 const xmlChar *cur = value;
307 unsigned long base = 0;
308 int total = 0;
309 if (cur == NULL)
310 return(1);
311 if (*cur == '+')
312 cur++;
313 while ((*cur >= '0') && (*cur <= '9')) {
314 base = base * 10 + (*cur - '0');
315 total++;
316 cur++;
317 }
318 if (*cur != 0)
319 return(1);
320 if (val != NULL) {
321 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
322 if (v != NULL) {
323 v->value.decimal.base = base;
324 v->value.decimal.sign = 0;
325 v->value.decimal.frac = 0;
326 v->value.decimal.total = total;
327 *val = v;
328 }
329 }
330 return(0);
331 } else if (type == xmlSchemaTypeNonNegativeIntegerDef) {
332 const xmlChar *cur = value;
333 unsigned long base = 0;
334 int total = 0;
335 int sign = 0;
336 if (cur == NULL)
337 return(1);
338 if (*cur == '-') {
339 sign = 1;
340 cur++;
341 } else if (*cur == '+')
342 cur++;
343 while ((*cur >= '0') && (*cur <= '9')) {
344 base = base * 10 + (*cur - '0');
345 total++;
346 cur++;
347 }
348 if (*cur != 0)
349 return(1);
350 if ((sign == 1) && (base != 0))
351 return(1);
352 if (val != NULL) {
353 v = xmlSchemaNewValue(XML_SCHEMAS_DECIMAL);
354 if (v != NULL) {
355 v->value.decimal.base = base;
356 v->value.decimal.sign = 0;
357 v->value.decimal.frac = 0;
358 v->value.decimal.total = total;
359 *val = v;
360 }
361 }
362 return(0);
363 } else {
364 TODO
365 return(0);
366 }
367}
368
369/**
370 * xmlSchemaCompareDecimals:
371 * @x: a first decimal value
372 * @y: a second decimal value
373 *
374 * Compare 2 decimals
375 *
376 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
377 */
378static int
379xmlSchemaCompareDecimals(xmlSchemaValPtr x, xmlSchemaValPtr y)
380{
381 xmlSchemaValPtr swp;
382 int order = 1;
383 unsigned long tmp;
384
385 if ((x->value.decimal.sign) && (x->value.decimal.sign))
386 order = -1;
387 else if (x->value.decimal.sign)
388 return (-1);
389 else if (y->value.decimal.sign)
390 return (1);
391 if (x->value.decimal.frac == y->value.decimal.frac) {
392 if (x->value.decimal.base < y->value.decimal.base)
393 return (-1);
394 return (x->value.decimal.base > y->value.decimal.base);
395 }
396 if (y->value.decimal.frac > x->value.decimal.frac) {
397 swp = y;
398 y = x;
399 x = swp;
400 order = -order;
401 }
402 tmp =
403 x->value.decimal.base / powten[x->value.decimal.frac -
404 y->value.decimal.frac];
405 if (tmp > y->value.decimal.base)
406 return (order);
407 if (tmp < y->value.decimal.base)
408 return (-order);
409 tmp =
410 y->value.decimal.base * powten[x->value.decimal.frac -
411 y->value.decimal.frac];
412 if (x->value.decimal.base < tmp)
413 return (-order);
414 if (x->value.decimal.base == tmp)
415 return (0);
416 return (order);
417}
418
419/**
420 * xmlSchemaCompareValues:
421 * @x: a first value
422 * @y: a second value
423 *
424 * Compare 2 values
425 *
426 * Returns -1 if x < y, 0 if x == y, 1 if x > y and -2 in case of error
427 */
Daniel Veillarde19fc232002-04-22 16:01:24 +0000428static int
Daniel Veillard4255d502002-04-16 15:50:10 +0000429xmlSchemaCompareValues(xmlSchemaValPtr x, xmlSchemaValPtr y) {
430 if ((x == NULL) || (y == NULL))
431 return(-2);
432
433 switch (x->type) {
434 case XML_SCHEMAS_STRING:
435 TODO
436 case XML_SCHEMAS_DECIMAL:
437 if (y->type == XML_SCHEMAS_DECIMAL)
438 return(xmlSchemaCompareDecimals(x, y));
439 else
440 return(-2);
441 default:
442 TODO
443 }
444}
445
446/**
447 * xmlSchemaValidateFacet:
448 * @type: the type declaration
449 * @facet: the facet to check
450 * @value: the lexical repr of the value to validate
451 * @val: the precomputed value
452 *
453 * Check a value against a facet condition
454 *
455 * Returns 0 if the element is schemas valid, a positive error code
456 * number otherwise and -1 in case of internal or API error.
457 */
458int
459xmlSchemaValidateFacet(xmlSchemaTypePtr base, xmlSchemaFacetPtr facet,
460 const xmlChar *value, xmlSchemaValPtr val)
461{
462 int ret;
463
464 switch (facet->type) {
465 case XML_SCHEMA_FACET_PATTERN:
466 ret = xmlRegexpExec(facet->regexp, value);
467 if (ret == 1)
468 return(0);
469 if (ret == 0) {
470 TODO /* error code */
471 return(1);
472 }
473 return(ret);
474 case XML_SCHEMA_FACET_MAXEXCLUSIVE:
475 ret = xmlSchemaCompareValues(val, facet->val);
476 if (ret == -2) {
477 TODO /* error code */
478 return(-1);
479 }
480 if (ret == -1)
481 return(0);
482 TODO /* error code */
483 return(1);
Daniel Veillard8651f532002-04-17 09:06:27 +0000484 case XML_SCHEMA_FACET_WHITESPACE:
485 TODO /* whitespaces */
486 return(0);
Daniel Veillarde19fc232002-04-22 16:01:24 +0000487 case XML_SCHEMA_FACET_MAXLENGTH:
488 if ((facet->val != NULL) &&
489 (facet->val->type == XML_SCHEMAS_DECIMAL) &&
490 (facet->val->value.decimal.frac == 0)) {
491 int len;
492
493 if (facet->val->value.decimal.sign == 1)
494 return(1);
495 len = xmlUTF8Strlen(value);
496 if (len > facet->val->value.decimal.base)
497 return(1);
498 return(0);
499 }
500 TODO /* error code */
501 return(1);
Daniel Veillard4255d502002-04-16 15:50:10 +0000502 default:
503 TODO
504 }
505 return(0);
506}
507
508#endif /* LIBXML_SCHEMAS_ENABLED */