1 /*
2  * rasqal_xsd_datatypes.c - Rasqal XML Schema Datatypes support
3  *
4  * Copyright (C) 2005-2010, David Beckett http://www.dajobe.org/
5  * Copyright (C) 2005-2005, University of Bristol, UK http://www.bristol.ac.uk/
6  *
7  * This package is Free Software and part of Redland http://librdf.org/
8  *
9  * It is licensed under the following three licenses as alternatives:
10  *   1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
11  *   2. GNU General Public License (GPL) V2 or any newer version
12  *   3. Apache License, V2.0 or any newer version
13  *
14  * You may not use this file except in compliance with at least one of
15  * the above three licenses.
16  *
17  * See LICENSE.html or LICENSE.txt at the top of this package for the
18  * complete terms and further detail along with the license texts for
19  * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
20  *
21  *
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include <rasqal_config.h>
26 #endif
27 
28 #ifdef WIN32
29 #include <win32_rasqal_config.h>
30 #endif
31 
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35 #ifdef HAVE_STDLIB_H
36 #include <stdlib.h>
37 #endif
38 #include <stdarg.h>
39 #ifdef HAVE_LIMITS_H
40 #include <limits.h>
41 #endif
42 #ifdef HAVE_ERRNO_H
43 #include <errno.h>
44 #endif
45 
46 #include "rasqal.h"
47 #include "rasqal_internal.h"
48 
49 /* local prototypes */
50 int rasqal_xsd_check_double_format(const unsigned char* string, int flags);
51 
52 
53 #ifndef STANDALONE
54 
55 /*
56  *
57  * References
58  *
59  * XPath Functions and Operators
60  * http://www.w3.org/TR/xpath-functions/
61  *
62  * Datatypes hierarchy
63  * http://www.w3.org/TR/xpath-functions/#datatypes
64  *
65  * Casting
66  * http://www.w3.org/TR/xpath-functions/#casting-from-primitive-to-primitive
67  *
68  */
69 
70 
71 int
rasqal_xsd_boolean_value_from_string(const unsigned char * string)72 rasqal_xsd_boolean_value_from_string(const unsigned char* string)
73 {
74   int integer = 0;
75 
76   /* FIXME
77    * Strictly only {true, false, 1, 0} are allowed according to
78    * http://www.w3.org/TR/xmlschema-2/#boolean
79    */
80   if(!strcmp(RASQAL_GOOD_CAST(const char*, string), "true") ||
81      !strcmp(RASQAL_GOOD_CAST(const char*, string), "TRUE") ||
82      !strcmp(RASQAL_GOOD_CAST(const char*, string), "1"))
83     integer = 1;
84 
85   return integer;
86 }
87 
88 
89 static int
rasqal_xsd_check_boolean_format(const unsigned char * string,int flags)90 rasqal_xsd_check_boolean_format(const unsigned char* string, int flags)
91 {
92   /* FIXME
93    * Strictly only {true, false, 1, 0} are allowed according to
94    * http://www.w3.org/TR/xmlschema-2/#boolean
95    */
96   if(!strcmp(RASQAL_GOOD_CAST(const char*, string), "true") ||
97      !strcmp(RASQAL_GOOD_CAST(const char*, string), "TRUE") ||
98      !strcmp(RASQAL_GOOD_CAST(const char*, string), "1") ||
99      !strcmp(RASQAL_GOOD_CAST(const char*, string), "false") ||
100      !strcmp(RASQAL_GOOD_CAST(const char*, string), "FALSE") ||
101      !strcmp(RASQAL_GOOD_CAST(const char*, string), "0"))
102     return 1;
103 
104   return 0;
105 }
106 
107 
108 #define ADVANCE_OR_DIE(p) if(!*(++p)) return 0;
109 
110 
111 /**
112  * rasqal_xsd_check_date_format:
113  * @string: lexical form string
114  * flags: flags
115  *
116  * INTERNAL - Check an XSD date lexical form
117  *
118  * Return value: non-0 if the string is valid
119  */
120 static int
rasqal_xsd_check_date_format(const unsigned char * string,int flags)121 rasqal_xsd_check_date_format(const unsigned char* string, int flags)
122 {
123   /* This should be correct according to
124    * http://www.w3.org/TR/xmlschema-2/#date
125    */
126   return rasqal_xsd_date_check(RASQAL_GOOD_CAST(const char*, string));
127 }
128 
129 
130 /**
131  * rasqal_xsd_check_dateTime_format:
132  * @string: lexical form string
133  * flags: flags
134  *
135  * INTERNAL - Check an XSD dateTime lexical form
136  *
137  * Return value: non-0 if the string is valid
138  */
139 static int
rasqal_xsd_check_dateTime_format(const unsigned char * string,int flags)140 rasqal_xsd_check_dateTime_format(const unsigned char* string, int flags)
141 {
142   /* This should be correct according to
143    * http://www.w3.org/TR/xmlschema-2/#dateTime
144    */
145   return rasqal_xsd_datetime_check(RASQAL_GOOD_CAST(const char*, string));
146 }
147 
148 
149 /**
150  * rasqal_xsd_check_decimal_format:
151  * @string: lexical form string
152  * flags: flags
153  *
154  * INTERNAL - Check an XSD decimal lexical form
155  *
156  * Return value: non-0 if the string is valid
157  */
158 static int
rasqal_xsd_check_decimal_format(const unsigned char * string,int flags)159 rasqal_xsd_check_decimal_format(const unsigned char* string, int flags)
160 {
161   const char* p;
162 
163   /* This should be correct according to
164    * http://www.w3.org/TR/xmlschema-2/#decimal
165    */
166   p = RASQAL_GOOD_CAST(const char*, string);
167   if(*p == '+' || *p == '-') {
168     ADVANCE_OR_DIE(p);
169   }
170 
171   while(*p && isdigit(RASQAL_GOOD_CAST(int, *p)))
172     p++;
173   if(!*p)
174     return 1;
175   /* Fail if first non-digit is not '.' */
176   if(*p != '.')
177     return 0;
178   p++;
179 
180   while(*p && isdigit(RASQAL_GOOD_CAST(int, *p)))
181     p++;
182   /* Fail if anything other than a digit seen before NUL */
183   if(*p)
184     return 0;
185 
186   return 1;
187 }
188 
189 
190 /* Legal special double values */
191 #define XSD_DOUBLE_SPECIALS_LEN 3
192 static const char * const xsd_double_specials[XSD_DOUBLE_SPECIALS_LEN] = {
193   "-INF",
194   "INF",
195   "NaN"
196 };
197 
198 /**
199  * rasqal_xsd_check_double_format:
200  * @string: lexical form string
201  * flags: flags
202  *
203  * INTERNAL - Check an XSD double lexical form
204  *
205  * Return value: non-0 if the string is valid
206  */
207 int
rasqal_xsd_check_double_format(const unsigned char * string,int flags)208 rasqal_xsd_check_double_format(const unsigned char* string, int flags)
209 {
210   const char *p = RASQAL_GOOD_CAST(const char*, string);
211   const char *saved_p;
212   int i;
213 
214   if(!*p)
215     return 0;
216 
217   /* Validating http://www.w3.org/TR/xmlschema-2/#double */
218 
219   /* check for specials */
220   for(i = 0; i < XSD_DOUBLE_SPECIALS_LEN; i++) {
221     if(!strcmp(xsd_double_specials[i], p))
222       return 1;
223   }
224 
225   /* mantissa: follows http://www.w3.org/TR/xmlschema-2/#decimal */
226   if(*p == '-' || *p == '+')
227     p++;
228   if(!*p)
229     return 0;
230 
231   saved_p = p;
232   while(isdigit(*p))
233     p++;
234 
235   /* no digits is a failure */
236   if(p == saved_p)
237     return 0;
238 
239   /* ending now is ok - whole number (-1, +2, 3) */
240   if(!*p)
241     return 1;
242 
243   /* .DIGITS is optional */
244   if(*p == '.') {
245     p++;
246     /* ending after . is not ok */
247     if(!*p)
248       return 0;
249 
250     while(isdigit(*p))
251       p++;
252 
253     /* ending with digits now is ok (-1.2, +2.3, 2.3) */
254     if(!*p)
255       return 1;
256   }
257 
258   /* must be an exponent letter here (-1E... +2e... , -1.3E...,
259    * +2.4e..., 2E..., -4e...) */
260   if(*p != 'e' && *p != 'E')
261     return 0;
262   p++;
263 
264   /* exponent: follows http://www.w3.org/TR/xmlschema-2/#integer */
265   if(*p == '-' || *p == '+')
266     p++;
267 
268   saved_p = p;
269   while(isdigit(*p))
270     p++;
271   if(p == saved_p)
272     return 0;
273 
274   if(*p)
275     return 0;
276 
277   return 1;
278 }
279 
280 
281 /**
282  * rasqal_xsd_check_float_format:
283  * @string: lexical form string
284  * flags: flags
285  *
286  * INTERNAL - Check an XSD float lexical form
287  *
288  * Return value: non-0 if the string is valid
289  */
290 static int
rasqal_xsd_check_float_format(const unsigned char * string,int flags)291 rasqal_xsd_check_float_format(const unsigned char* string, int flags)
292 {
293   /* http://www.w3.org/TR/xmlschema-2/#float is the same as double */
294   return rasqal_xsd_check_double_format(string, flags);
295 }
296 
297 
298 /**
299  * rasqal_xsd_check_integer_format:
300  * @string: lexical form string
301  * flags: flags
302  *
303  * INTERNAL - Check an XSD integer lexical form
304  *
305  * Return value: non-0 if the string is valid
306  */
307 static int
rasqal_xsd_check_integer_format(const unsigned char * string,int flags)308 rasqal_xsd_check_integer_format(const unsigned char* string, int flags)
309 {
310   /* This should be correct according to
311    * http://www.w3.org/TR/xmlschema-2/#integer
312    */
313 
314   /* Forbid empty string */
315   if(!*string)
316     return 0;
317 
318   if(*string == '+' || *string == '-') {
319     string++;
320     /* Forbid "+" and "-" */
321     if(!*string)
322       return 0;
323   }
324 
325   /* Digits */
326   for(;*string; string++) {
327     if(*string < '0' || *string > '9')
328       return 0;
329   }
330   return 1;
331 }
332 
333 
334 /**
335  * rasqal_xsd_format_integer:
336  * @i: integer
337  * @len_p: pointer to length of result or NULL
338  *
339  * INTERNAL - Format a C integer as a string in XSD decimal integer format.
340  *
341  * This is suitable for multiple XSD decimal integer types that are
342  * xsd:integer or sub-types such as xsd:short, xsd:int, xsd:long,
343  *
344  * See http://www.w3.org/TR/xmlschema-2/#built-in-datatypes for the full list.
345  *
346  * Return value: new string or NULL on failure
347  */
348 unsigned char*
rasqal_xsd_format_integer(int i,size_t * len_p)349 rasqal_xsd_format_integer(int i, size_t *len_p)
350 {
351   unsigned char* string;
352 
353   /* Buffer sizes need to format:
354    *   4:  8 bit decimal integers (xsd:byte)  "-128" to "127"
355    *   6: 16 bit decimal integers (xsd:short) "-32768" to "32767"
356    *  11: 32 bit decimal integers (xsd:int)   "-2147483648" to "2147483647"
357    *  20: 64 bit decimal integers (xsd:long)  "-9223372036854775808" to "9223372036854775807"
358    * (the lexical form may have leading 0s in non-canonical representations)
359    */
360 #define INTEGER_BUFFER_SIZE 20
361   string = RASQAL_MALLOC(unsigned char*, INTEGER_BUFFER_SIZE + 1);
362   if(!string)
363     return NULL;
364   /* snprintf() takes as length the buffer size including NUL */
365   snprintf(RASQAL_GOOD_CAST(char*, string), INTEGER_BUFFER_SIZE + 1, "%d", i);
366   if(len_p)
367     *len_p = strlen(RASQAL_GOOD_CAST(const char*, string));
368 
369   return string;
370 }
371 
372 
373 /**
374  * rasqal_xsd_format_float:
375  * @i: float
376  * @len_p: pointer to length of result or NULL
377  *
378  * INTERNAL - Format a new an xsd:float correctly
379  *
380  * Return value: new string or NULL on failure
381  */
382 unsigned char*
rasqal_xsd_format_float(float f,size_t * len_p)383 rasqal_xsd_format_float(float f, size_t *len_p)
384 {
385   unsigned char* string;
386 
387   /* FIXME: This is big enough for C float formatted in decimal as %1g */
388 #define FLOAT_BUFFER_SIZE 30
389   string = RASQAL_MALLOC(unsigned char*, FLOAT_BUFFER_SIZE + 1);
390   if(!string)
391     return NULL;
392   /* snprintf() takes as length the buffer size including NUL */
393   /* FIXME: %1g may not be the nearest to XSD xsd:float canonical format */
394   snprintf(RASQAL_GOOD_CAST(char*, string), FLOAT_BUFFER_SIZE + 1, "%1g", (double)f);
395   if(len_p)
396     *len_p = strlen(RASQAL_GOOD_CAST(const char*, string));
397 
398   return string;
399 }
400 
401 
402 /**
403  * rasqal_xsd_format_double:
404  * @d: double
405  * @len_p: pointer to length of result or NULL
406  *
407  * INTERNAL - Format a new an xsd:double correctly
408  *
409  * Return value: new string or NULL on failure
410  */
411 unsigned char*
rasqal_xsd_format_double(double d,size_t * len_p)412 rasqal_xsd_format_double(double d, size_t *len_p)
413 {
414   unsigned int e_index = 0;
415   char have_trailing_zero = 0;
416   size_t trailing_zero_start = 0;
417   unsigned int exponent_start;
418   size_t len = 0;
419   unsigned char* buf = NULL;
420 
421   len = 20;
422   buf = RASQAL_MALLOC(unsigned char*, len + 1);
423   if(!buf)
424     return NULL;
425 
426   /* snprintf needs the length + 1 because it writes a \0 too */
427   snprintf(RASQAL_GOOD_CAST(char*, buf), len + 1, "%1.14E", d);
428 
429   /* find the 'e' and start of mantissa trailing zeros */
430 
431   for( ; buf[e_index]; ++e_index) {
432     if(e_index > 0 && buf[e_index] == '0' && buf[e_index - 1] != '0') {
433       trailing_zero_start = e_index;
434       have_trailing_zero = 1;
435     }
436 
437     else if(buf[e_index] == 'E')
438       break;
439   }
440 
441   if(have_trailing_zero) {
442     if(buf[trailing_zero_start - 1] == '.')
443       ++trailing_zero_start;
444 
445     /* write an 'E' where the trailing zeros started */
446     buf[trailing_zero_start] = 'E';
447     if(buf[e_index + 1] == '-') {
448       buf[trailing_zero_start + 1] = '-';
449       ++trailing_zero_start;
450     }
451   } else {
452     buf[e_index] = 'E';
453     trailing_zero_start = e_index + 1;
454     have_trailing_zero = 1;
455   }
456 
457   exponent_start = e_index + 2;
458   while(buf[exponent_start] == '0')
459     ++exponent_start;
460 
461   if(have_trailing_zero) {
462     len = strlen(RASQAL_GOOD_CAST(const char*, buf));
463     if(exponent_start == len) {
464       len = trailing_zero_start + 2;
465       buf[len - 1] = '0';
466       buf[len] = '\0';
467     } else {
468       /* copy the exponent (minus leading zeros) after the new E */
469       memmove(buf + trailing_zero_start + 1, buf + exponent_start,
470               len - exponent_start + 1);
471       len = strlen(RASQAL_GOOD_CAST(const char*, buf));
472     }
473   }
474 
475   if(len_p)
476     *len_p = len;
477 
478   return buf;
479 }
480 
481 
482 typedef rasqal_literal* (*rasqal_extension_fn)(raptor_uri* name, raptor_sequence *args, char **error_p);
483 
484 
485 typedef struct {
486   const unsigned char *name;
487   int min_nargs;
488   int max_nargs;
489   rasqal_extension_fn fn;
490   raptor_uri* uri;
491 } rasqal_xsd_datatype_fn_info;
492 
493 
494 #define XSD_INTEGER_DERIVED_COUNT 12
495 #define XSD_INTEGER_DERIVED_FIRST (RASQAL_LITERAL_LAST_XSD + 1)
496 #define XSD_INTEGER_DERIVED_LAST (RASQAL_LITERAL_LAST_XSD + XSD_INTEGER_DERIVED_COUNT - 1)
497 
498 #define XSD_DATE_OFFSET (XSD_INTEGER_DERIVED_LAST + 2)
499 
500 /* atomic XSD literals + 12 types derived from xsd:integer plus DATE plus a NULL */
501 #define SPARQL_XSD_NAMES_COUNT (RASQAL_LITERAL_LAST_XSD + 1 + XSD_INTEGER_DERIVED_COUNT + 1)
502 
503 
504 static const char* const sparql_xsd_names[SPARQL_XSD_NAMES_COUNT + 1] =
505 {
506   NULL, /* RASQAL_LITERAL_UNKNOWN */
507   NULL, /* ...BLANK */
508   NULL, /* ...URI */
509   NULL, /* ...LITERAL */
510   "string",
511   "boolean",
512   "integer", /* may type-promote all the way to xsd:decimal */
513   "float",
514   "double",
515   "decimal",
516   "dateTime",
517   /* all of the following always type-promote to xsd:integer */
518   "nonPositiveInteger", "negativeInteger",
519   "long", "int", "short", "byte",
520   "nonNegativeInteger", "unsignedLong", "postiveInteger",
521   "unsignedInt", "unsignedShort", "unsignedByte",
522   /* RASQAL_LITERAL_DATE onwards (NOT next to dateTime) */
523   "date",
524   NULL
525 };
526 
527 #define CHECKFNS_COUNT (RASQAL_LITERAL_LAST_XSD - RASQAL_LITERAL_FIRST_XSD + 2)
528 static int (*const sparql_xsd_checkfns[CHECKFNS_COUNT])(const unsigned char* string, int flags) =
529 {
530   NULL, /* RASQAL_LITERAL_XSD_STRING */
531   rasqal_xsd_check_boolean_format, /* RASQAL_LITERAL_BOOLEAN */
532   rasqal_xsd_check_integer_format, /* RASQAL_LITERAL_INTEGER */
533   rasqal_xsd_check_float_format, /* RASQAL_LITERAL_FLOAT */
534   rasqal_xsd_check_double_format, /* RASQAL_LITERAL_DOUBLE */
535   rasqal_xsd_check_decimal_format, /* RASQAL_LITERAL_DECIMAL */
536   rasqal_xsd_check_dateTime_format, /* RASQAL_LITERAL_DATETIME */
537   /* GAP */
538   rasqal_xsd_check_date_format /* RASQAL_LITERAL_DATE */
539 };
540 
541 #define CHECKFN_DATE_OFFSET (RASQAL_LITERAL_DATETIME - RASQAL_LITERAL_FIRST_XSD + 1)
542 
543 
544 int
rasqal_xsd_init(rasqal_world * world)545 rasqal_xsd_init(rasqal_world* world)
546 {
547   int i;
548 
549   world->xsd_namespace_uri = raptor_new_uri(world->raptor_world_ptr,
550                                             raptor_xmlschema_datatypes_namespace_uri);
551   if(!world->xsd_namespace_uri)
552     return 1;
553 
554   world->xsd_datatype_uris = RASQAL_CALLOC(raptor_uri**, SPARQL_XSD_NAMES_COUNT + 1, sizeof(raptor_uri*));
555   if(!world->xsd_datatype_uris)
556     return 1;
557 
558   for(i = RASQAL_LITERAL_FIRST_XSD; i < SPARQL_XSD_NAMES_COUNT; i++) {
559     const unsigned char* name = RASQAL_GOOD_CAST(const unsigned char*, sparql_xsd_names[i]);
560     world->xsd_datatype_uris[i] =
561       raptor_new_uri_from_uri_local_name(world->raptor_world_ptr,
562                                          world->xsd_namespace_uri, name);
563     if(!world->xsd_datatype_uris[i])
564       return 1;
565   }
566 
567   return 0;
568 }
569 
570 
571 void
rasqal_xsd_finish(rasqal_world * world)572 rasqal_xsd_finish(rasqal_world* world)
573 {
574   if(world->xsd_datatype_uris) {
575     int i;
576 
577     for(i = RASQAL_LITERAL_FIRST_XSD; i < SPARQL_XSD_NAMES_COUNT; i++) {
578       if(world->xsd_datatype_uris[i])
579         raptor_free_uri(world->xsd_datatype_uris[i]);
580     }
581 
582     RASQAL_FREE(table, world->xsd_datatype_uris);
583     world->xsd_datatype_uris = NULL;
584   }
585 
586   if(world->xsd_namespace_uri) {
587     raptor_free_uri(world->xsd_namespace_uri);
588     world->xsd_namespace_uri = NULL;
589   }
590 }
591 
592 
593 
594 rasqal_literal_type
rasqal_xsd_datatype_uri_to_type(rasqal_world * world,raptor_uri * uri)595 rasqal_xsd_datatype_uri_to_type(rasqal_world* world, raptor_uri* uri)
596 {
597   int i;
598   rasqal_literal_type native_type = RASQAL_LITERAL_UNKNOWN;
599 
600   if(!uri || !world->xsd_datatype_uris)
601     return native_type;
602 
603   for(i = RASQAL_GOOD_CAST(int, RASQAL_LITERAL_FIRST_XSD); i <= RASQAL_GOOD_CAST(int, XSD_INTEGER_DERIVED_LAST); i++) {
604     if(raptor_uri_equals(uri, world->xsd_datatype_uris[i])) {
605       if(i >= XSD_INTEGER_DERIVED_FIRST)
606         native_type = RASQAL_LITERAL_INTEGER_SUBTYPE;
607       else
608         native_type = (rasqal_literal_type)i;
609       break;
610     }
611   }
612 
613   if(native_type == RASQAL_LITERAL_UNKNOWN) {
614     /* DATE is not in the range FIRST_XSD .. INTEGER_DERIVED_LAST */
615     i = RASQAL_GOOD_CAST(int, XSD_DATE_OFFSET);
616     if(raptor_uri_equals(uri, world->xsd_datatype_uris[i]))
617       native_type = RASQAL_LITERAL_DATE;
618   }
619 
620   return native_type;
621 }
622 
623 
624 raptor_uri*
rasqal_xsd_datatype_type_to_uri(rasqal_world * world,rasqal_literal_type type)625 rasqal_xsd_datatype_type_to_uri(rasqal_world* world, rasqal_literal_type type)
626 {
627   if(world->xsd_datatype_uris &&
628      ((type >= RASQAL_LITERAL_FIRST_XSD &&
629        type <= RASQAL_LITERAL_LAST_XSD) ||
630       type == RASQAL_LITERAL_DATE))
631     return world->xsd_datatype_uris[RASQAL_GOOD_CAST(int, type)];
632 
633   return NULL;
634 }
635 
636 
637 /**
638  * rasqal_xsd_datatype_check:
639  * @native_type: rasqal XSD type
640  * @string: string
641  * @flags: check flags
642  *
643  * INTERNAL - check a string as a valid lexical form of an XSD datatype
644  *
645  * Return value: non-0 if the string is valid
646  */
647 int
rasqal_xsd_datatype_check(rasqal_literal_type native_type,const unsigned char * string,int flags)648 rasqal_xsd_datatype_check(rasqal_literal_type native_type,
649                           const unsigned char* string, int flags)
650 {
651   /* calculate check function index in sparql_xsd_checkfns table */
652   int checkidx = -1;
653 
654   if(native_type >= RASQAL_GOOD_CAST(int, RASQAL_LITERAL_FIRST_XSD) &&
655      native_type <= RASQAL_GOOD_CAST(int, RASQAL_LITERAL_LAST_XSD))
656     checkidx = RASQAL_GOOD_CAST(int, native_type - RASQAL_LITERAL_FIRST_XSD);
657   else if(native_type == RASQAL_LITERAL_DATE)
658     checkidx = CHECKFN_DATE_OFFSET;
659 
660   /* test for index out of bounds and check function not defined */
661   if(checkidx < 0 || !sparql_xsd_checkfns[checkidx])
662     return 1;
663 
664   return sparql_xsd_checkfns[checkidx](string, flags);
665 }
666 
667 
668 const char*
rasqal_xsd_datatype_label(rasqal_literal_type native_type)669 rasqal_xsd_datatype_label(rasqal_literal_type native_type)
670 {
671   return sparql_xsd_names[native_type];
672 }
673 
674 
675 int
rasqal_xsd_is_datatype_uri(rasqal_world * world,raptor_uri * uri)676 rasqal_xsd_is_datatype_uri(rasqal_world* world, raptor_uri* uri)
677 {
678   return (rasqal_xsd_datatype_uri_to_type(world, uri) != RASQAL_LITERAL_UNKNOWN);
679 }
680 
681 
682 int
rasqal_xsd_datatype_is_numeric(rasqal_literal_type type)683 rasqal_xsd_datatype_is_numeric(rasqal_literal_type type)
684 {
685   return ((type >= RASQAL_LITERAL_BOOLEAN && type <= RASQAL_LITERAL_DECIMAL) ||
686           (type == RASQAL_LITERAL_INTEGER_SUBTYPE));
687 }
688 
689 
690 static const rasqal_literal_type parent_xsd_type[RASQAL_LITERAL_LAST + 1] =
691 {
692   /*   RASQAL_LITERAL_UNKNOWN  */  RASQAL_LITERAL_UNKNOWN,
693   /* RDF Blank / RDF Term: Blank */
694   /*   RASQAL_LITERAL_BLANK    */  RASQAL_LITERAL_UNKNOWN,
695   /* RDF URI / RDF Term: URI */
696   /*   RASQAL_LITERAL_URI      */  RASQAL_LITERAL_UNKNOWN,
697   /* RDF Plain Literal / RDF Term: Literal */
698   /*   RASQAL_LITERAL_STRING   */  RASQAL_LITERAL_UNKNOWN,
699   /* XSD types / RDF Term Literal */
700   /*   RASQAL_LITERAL_XSD_STRING */  RASQAL_LITERAL_UNKNOWN,
701   /*   RASQAL_LITERAL_BOOLEAN  */  RASQAL_LITERAL_INTEGER,
702   /*   RASQAL_LITERAL_INTEGER  */  RASQAL_LITERAL_FLOAT,
703   /*   RASQAL_LITERAL_FLOAT    */  RASQAL_LITERAL_DOUBLE,
704   /*   RASQAL_LITERAL_DOUBLE   */  RASQAL_LITERAL_DECIMAL,
705   /*   RASQAL_LITERAL_DECIMAL  */  RASQAL_LITERAL_UNKNOWN,
706   /*   RASQAL_LITERAL_DATETIME */  RASQAL_LITERAL_UNKNOWN,
707   /* not datatypes */
708   /*   RASQAL_LITERAL_UDT      */  RASQAL_LITERAL_UNKNOWN,
709   /*   RASQAL_LITERAL_PATTERN  */  RASQAL_LITERAL_UNKNOWN,
710   /*   RASQAL_LITERAL_QNAME    */  RASQAL_LITERAL_UNKNOWN,
711   /*   RASQAL_LITERAL_VARIABLE */  RASQAL_LITERAL_UNKNOWN,
712   /*   RASQAL_LITERAL_INTEGER_SUBTYPE */  RASQAL_LITERAL_UNKNOWN,
713   /*   RASQAL_LITERAL_DATE     */  RASQAL_LITERAL_UNKNOWN
714 };
715 
716 rasqal_literal_type
rasqal_xsd_datatype_parent_type(rasqal_literal_type type)717 rasqal_xsd_datatype_parent_type(rasqal_literal_type type)
718 {
719   if(type == RASQAL_LITERAL_INTEGER_SUBTYPE)
720     return RASQAL_LITERAL_INTEGER;
721 
722   if((type >= RASQAL_LITERAL_FIRST_XSD && type <= RASQAL_LITERAL_LAST_XSD) ||
723      type == RASQAL_LITERAL_DATE)
724     return parent_xsd_type[type];
725 
726   return RASQAL_LITERAL_UNKNOWN;
727 }
728 
729 #endif /* not STANDALONE */
730 
731 
732 #ifdef STANDALONE
733 #include <stdio.h>
734 
735 int main(int argc, char *argv[]);
736 
737 #define N_VALID_TESTS 27
738 const char *double_valid_tests[N_VALID_TESTS+1] = {
739   "-INF", "INF",
740   "NaN",
741   "-0", "+0", "0",
742   "-12", "+12", "12",
743   "-12.34", "+12.34", "12.34",
744   "-1E4", "+1E4", "1267.43233E12", "-1267.43233E12", "12.78E-2",
745   "-1e4", "+1e4", "1267.43233e12", "-1267.43233e12", "12.78e-2",
746   "-1e0", "1e0",  "1267.43233e0",  "-1267.43233e0",  "12.78e-0",
747   NULL
748 };
749 
750 #define N_INVALID_TESTS 27
751 const char *double_invalid_tests[N_INVALID_TESTS+1] = {
752   "-inf", "inf", "+inf", "+INF",
753   "NAN", "nan",
754   "-0.", "+0.", "0.",
755   "-12.", "+12.", "12.",
756   "-E4", "E4", "+E4",
757   "-e4", "e4", "+e4",
758   "-1E", "+1E", "1E",
759   "-1e", "+1e", "1e",
760   "-1.E", "+1.E", "1.E",
761   NULL
762 };
763 
764 int
main(int argc,char * argv[])765 main(int argc, char *argv[])
766 {
767   rasqal_world* world;
768   const char *program = rasqal_basename(argv[0]);
769   int failures = 0;
770   int test = 0;
771 
772   world = rasqal_new_world();
773   if(!world || rasqal_world_open(world)) {
774     fprintf(stderr, "%s: rasqal_world init failed\n", program);
775     failures++;
776     goto tidy;
777   }
778 
779   for(test = 0; test < N_VALID_TESTS; test++) {
780     const unsigned char *str;
781     str = RASQAL_GOOD_CAST(const unsigned char*, double_valid_tests[test]);
782 
783 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
784     fprintf(stderr, "%s: Valid Test %3d value: %s\n", program, test, str);
785 #endif
786     if(!rasqal_xsd_check_double_format(str, 0 /* flags */)) {
787       fprintf(stderr, "%s: Valid Test %3d value: %s FAILED\n",
788               program, test, str);
789       failures++;
790     }
791   }
792 
793   for(test = 0; test < N_INVALID_TESTS; test++) {
794     const unsigned char *str;
795     str = RASQAL_GOOD_CAST(const unsigned char*, double_invalid_tests[test]);
796 
797 #if defined(RASQAL_DEBUG) && RASQAL_DEBUG > 1
798     fprintf(stderr, "%s: Invalid Test %3d value: %s\n", program, test, str);
799 #endif
800     if(rasqal_xsd_check_double_format(str, 0 /* flags */)) {
801       fprintf(stderr,
802               "%s: Invalid Test %3d value: %s PASSED (expected failure)\n",
803               program, test, str);
804       failures++;
805     }
806   }
807 
808   tidy:
809 
810   rasqal_free_world(world);
811 
812   return failures;
813 }
814 #endif /* STANDALONE */
815