1 /*
2 * Copyright (c) 2000-2006 All rights reserved,
3 * Alberto Reggiori <areggiori@webweaving.org>,
4 * Dirk-Willem van Gulik <dirkx@webweaving.org>.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * 1. Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 *
17 * 3. The end-user documentation included with the redistribution, if any, must
18 * include the following acknowledgment: "This product includes software
19 * developed by Alberto Reggiori <areggiori@webweaving.org> and Dirk-Willem
20 * van Gulik <dirkx@webweaving.org>." Alternately, this acknowledgment may
21 * appear in the software itself, if and wherever such third-party
22 * acknowledgments normally appear.
23 *
24 * 4. All advertising materials mentioning features or use of this software must
25 * display the following acknowledgement: This product includes software
26 * developed by the University of California, Berkeley and its contributors.
27 *
28 * 5. Neither the name of the University nor the names of its contributors may
29 * be used to endorse or promote products derived from this software without
30 * specific prior written permission.
31 *
32 * 6. Products derived from this software may not be called "RDFStore" nor may
33 * "RDFStore" appear in their names without prior written permission.
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
36 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
41 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
42 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 * SUCH DAMAGE.
46 *
47 * ====================================================================
48 *
49 * This software consists of work developed by Alberto Reggiori and Dirk-Willem
50 * van Gulik. The RDF specific part is based based on public domain software
51 * written at the Stanford University Database Group by Sergey Melnik. For
52 * more information on the RDF API Draft work, please see
53 * <http://www-db.stanford.edu/~melnik/rdf/api.html> The DBMS TCP/IP server
54 * part is based on software originally written by Dirk-Willem van Gulik for
55 * Web Weaving Internet Engineering m/v Enschede, The Netherlands.
56 *
57 */
58
59 #if !defined(WIN32)
60 #include <sys/param.h>
61 #endif
62
63 #include <sys/types.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <errno.h>
67 #include <strings.h>
68 #include <fcntl.h>
69
70 #include <time.h>
71 #include <sys/stat.h>
72
73 #include "rdfstore_log.h"
74 #include "rdfstore_xsd.h"
75
76 /*
77 #define MX { printf(" MX %s:%d - %p\n",__FILE__,__LINE__,me->nindex->free); }
78 */
79
80 /*
81 * #define RDFSTORE_XSD_DEBUG
82 */
83
84 time_t _rdfstore_xsd_mktime(const struct tm * t);
85
rdfstore_xsd_serialize_decimal(const double value,char * result)86 void rdfstore_xsd_serialize_decimal( const double value, char * result ) {
87 sprintf( result, RDFSTORE_XSD_DECIMAL_FORMAT, value );
88 };
89
rdfstore_xsd_deserialize_decimal(const char * string,double * val)90 int rdfstore_xsd_deserialize_decimal( const char * string, double * val ) {
91 return rdfstore_xsd_deserialize_double( string, (double *) val );
92 };
93
rdfstore_xsd_serialize_float(const float value,char * result)94 void rdfstore_xsd_serialize_float( const float value, char * result ) {
95 sprintf( result, RDFSTORE_XSD_FLOAT_FORMAT, value );
96 };
97
rdfstore_xsd_deserialize_float(const char * string,float * val)98 int rdfstore_xsd_deserialize_float( const char * string, float * val ) {
99 return rdfstore_xsd_deserialize_double( string, (double *) val );
100 };
101
rdfstore_xsd_serialize_double(const double value,char * result)102 void rdfstore_xsd_serialize_double( const double value, char * result ) {
103 sprintf( result, RDFSTORE_XSD_DOUBLE_FORMAT, value );
104 };
105
106 /*
107 parse a char string as double/float if possible and returns it
108
109 NOTEs:
110 strings like <foo:prop> 123.333344477 foo bar</foo:prop> are not considered numbers while
111 strings like <foo:prop>
112 123.333344477
113 </foo:prop> are valid numbers
114 */
rdfstore_xsd_deserialize_double(const char * string,double * val)115 int rdfstore_xsd_deserialize_double( const char * string, double * val ) {
116 char *endptr;
117
118 if (string == NULL) {
119 return 0;
120 };
121
122 *val = (double) strtod(string, &endptr);
123
124 if (endptr > string) { /* if a conversion was made */
125 /* check if we really got a number or a literal/string... */
126 while ( *endptr ) {
127 if ( isspace(*endptr) == 0 )
128 return 0;
129 endptr++;
130 };
131
132 if( errno == ERANGE )
133 return 0;
134
135 return 1;
136 };
137
138 return 0;
139 };
140
rdfstore_xsd_serialize_integer(const long value,char * result)141 void rdfstore_xsd_serialize_integer( const long value, char * result ) {
142 sprintf( result, RDFSTORE_XSD_INTEGER_FORMAT, value );
143 };
144
rdfstore_xsd_deserialize_integer(const char * string,long * val)145 int rdfstore_xsd_deserialize_integer( const char * string, long * val ) {
146 char *endptr;
147
148 if (string == NULL) {
149 return 0;
150 };
151
152 /* strtod should trim the string itself... */
153 *val = (long) strtol(string, &endptr, 10); /* base 10 or should be any base '0' ? */
154
155 if (endptr > string) { /* if a conversion was made */
156 /* check if we really got a number or a literal/string... */
157 while ( *endptr ) {
158 if ( isspace(*endptr) == 0 )
159 return 0;
160 endptr++;
161 };
162
163 if( errno == ERANGE )
164 return 0;
165
166 return 1;
167 };
168
169 return 0;
170 };
171
rdfstore_xsd_serialize_date(const struct tm value,char * result)172 void rdfstore_xsd_serialize_date( const struct tm value, char * result ) {
173 strftime( result, RDFSTORE_XSD_DATE_FORMAT_SIZE, "%Y-%m-%dZ", &value );
174
175 #ifdef RDFSTORE_XSD_DEBUG
176 printf("PROCESSED SUCCESSFULY DATE '%s'\n", result);
177 #endif
178 };
179
rdfstore_xsd_deserialize_date(const char * string,struct tm * val)180 int rdfstore_xsd_deserialize_date( const char * string, struct tm * val ) {
181 char * ptr=(char*)string;
182 char * ptr1=(char*)(string+strlen(string)-1);
183 char * tzsign;
184 char * temp;
185 char * temp2;
186 int status=0;
187 unsigned int len;
188 time_t now;
189 time_t timestamp;
190 struct tm* ptm;
191 struct tm t1;
192 struct tm t2;
193 time_t d;
194
195 bzero(val, sizeof( struct tm ) );
196
197 if (string == NULL) {
198 return 0;
199 };
200
201 time(&now);
202
203 ptm = gmtime(&now);
204 memcpy(&t1, ptm, sizeof(struct tm));
205
206 ptm = localtime(&now);
207 memcpy(&t2, ptm, sizeof(struct tm));
208
209 d = _rdfstore_xsd_mktime(&t1) - _rdfstore_xsd_mktime(&t2); /* carry out the difference in second between local and UTC */
210
211 if (d == -1) {
212 return 0;
213 };
214
215 /* trim the value */
216 while( ( ptr <= (string + strlen(string) ) ) &&
217 ( (*ptr == ' ' ) || ( *ptr == '\n' ) || ( *ptr == '\r' ) || ( *ptr == '\f' ) || ( *ptr == '\t' ) ) ) {
218 ptr++;
219 };
220 while( ( ptr1 > ptr ) &&
221 ( (*ptr1 == ' ' ) || ( *ptr1 == '\n' ) || ( *ptr1 == '\r' ) || ( *ptr1 == '\f' ) || ( *ptr1 == '\t' ) ) ) {
222 ptr1--;
223 };
224
225 /* primitive date parsing... */
226
227 /* this expression should cover xsd:date and xsd:dateTime - see http://www.w3.org/TR/xmlschema-2/#date and http://www.w3.org/TR/xmlschema-2/#dateTime */
228 /* date ::= '-'? yyyy '-' mm '-' dd ((('+' | '-') hh ':' mm) | 'Z')? */
229
230 if( sscanf( ptr, "%d-%02d-%02d", &val->tm_year,
231 &val->tm_mon, &val->tm_mday ) != 3 ) {
232 return 0;
233 };
234
235 val->tm_year -= 1900;
236 val->tm_mon--;
237 val->tm_hour = 0;
238 val->tm_min = 0;
239 val->tm_sec = 0;
240 val->tm_isdst = -1;
241 #if !defined(WIN32) && !defined(AIX) && !defined( __OS400__ ) && !defined(__sun)
242 val->tm_zone = NULL;
243 val->tm_gmtoff = -1;
244 #endif
245
246 temp2 = strpbrk(ptr, ":");
247
248 if( ( temp = strpbrk( ptr, "Z") ) != NULL ) { /* got canonical UTC date */
249 time_t tt = _rdfstore_xsd_mktime(val);
250 if( temp != ptr1 ) {
251 return 0;
252 };
253
254 if (tt == -1) {
255 return 0;
256 };
257 ptm = localtime (&tt);
258 } else if( temp2 != NULL ) { /* ok now we need to normalize +/-hh:mm timezone to UTC - hehheee! */
259 int hours = 0;
260 int minutes = 0;
261 int secs;
262 time_t t;
263
264 tzsign = strrchr(ptr, '+');
265
266 if (tzsign == NULL) {
267 tzsign = strrchr(ptr, '-');
268 };
269
270 if( *(tzsign-3) != '-' ) {
271 return 0;
272 };
273
274 timestamp = _rdfstore_xsd_mktime(val);
275 if ( timestamp == -1 ) {
276 return 0;
277 };
278
279 if( sscanf( tzsign+1, "%02d:%02d", &hours, &minutes) != 2 ) {
280 return 0;
281 };
282
283 secs = hours * 60 * 60 + minutes * 60;
284 if( (temp = strpbrk(tzsign, "+")) != NULL ) {
285 timestamp += secs;
286 } else {
287 timestamp -= secs;
288 };
289
290 ptm = localtime(×tamp);
291 memcpy(val, ptm, sizeof(struct tm));
292 t = _rdfstore_xsd_mktime(val);
293 if( t == -1 ) {
294 return 0;
295 };
296
297 t = labs(t - d);
298 ptm = gmtime(&t);
299 } else { /*else it is assumed that the sent time is localtime */
300 if( ( *ptr1 < 48 ) ||
301 ( *ptr1 > 57 ) ||
302 ( *(ptr1-2) != '-' ) ) {
303 return 0;
304 };
305
306 timestamp = _rdfstore_xsd_mktime(val);
307 if( timestamp == -1 ) {
308 return 0;
309 };
310
311 ptm = gmtime(×tamp);
312 };
313
314 if( ptm!= NULL ) {
315 #ifdef RDFSTORE_XSD_DEBUG
316 printf("rdfstore_xsd_deserialize_date( '%s' ) is a valid date\n", ptr);
317 #endif
318
319 return 1;
320 } else {
321 #ifdef RDFSTORE_XSD_DEBUG
322 printf("rdfstore_xsd_deserialize_date( '%s' ) is NOT a valid date\n", ptr);
323 #endif
324
325 return 0;
326 };
327 };
328
rdfstore_xsd_serialize_dateTime(const struct tm value,char * result)329 void rdfstore_xsd_serialize_dateTime( const struct tm value, char * result ) {
330 strftime( result, RDFSTORE_XSD_DATETIME_FORMAT_SIZE, "%Y-%m-%dT%H:%M:%SZ", &value );
331
332 #ifdef RDFSTORE_XSD_DEBUG
333 printf("PROCESSED SUCCESSFULY DATETIME '%s'\n", result);
334 #endif
335 };
336
rdfstore_xsd_deserialize_dateTime(const char * string,struct tm * val)337 int rdfstore_xsd_deserialize_dateTime( const char * string, struct tm * val ) {
338 char * ptr=(char*)string;
339 char * ptr1=(char*)(string+strlen(string)-1);
340 char * tzsign;
341 char * temp;
342 char * temp2;
343 char * temp3;
344 int status=0;
345 unsigned int len;
346 time_t now;
347 time_t timestamp;
348 struct tm* ptm;
349 struct tm t1;
350 struct tm t2;
351 time_t d;
352
353 bzero(val, sizeof( struct tm ) );
354
355 if (string == NULL) {
356 return 0;
357 };
358
359 time(&now);
360
361 ptm = gmtime(&now);
362 memcpy(&t1, ptm, sizeof(struct tm));
363
364 ptm = localtime(&now);
365 memcpy(&t2, ptm, sizeof(struct tm));
366
367 d = _rdfstore_xsd_mktime(&t1) - _rdfstore_xsd_mktime(&t2); /* carry out the difference in second between local and UTC */
368
369 if (d == -1) {
370 return 0;
371 };
372
373 /* trim the value */
374 while( ( ptr <= (string + strlen(string) ) ) &&
375 ( (*ptr == ' ' ) || ( *ptr == '\n' ) || ( *ptr == '\r' ) || ( *ptr == '\f' ) || ( *ptr == '\t' ) ) ) {
376 ptr++;
377 };
378 while( ( ptr1 > ptr ) &&
379 ( (*ptr1 == ' ' ) || ( *ptr1 == '\n' ) || ( *ptr1 == '\r' ) || ( *ptr1 == '\f' ) || ( *ptr1 == '\t' ) ) ) {
380 ptr1--;
381 };
382
383 /* primitive date parsing... */
384
385 /* this expression should cover xsd:date and xsd:dateTime - see http://www.w3.org/TR/xmlschema-2/#date and http://www.w3.org/TR/xmlschema-2/#dateTime */
386 /* date ::= '-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? ((('+' | '-') hh ':' mm) | 'Z')? */
387
388 if( sscanf( ptr, "%d-%02d-%02dT%02d:%02d:%02d", &val->tm_year,
389 &val->tm_mon, &val->tm_mday, &val->tm_hour, &val->tm_min, &val->tm_sec) != 6 ) {
390 return 0;
391 };
392
393 val->tm_year -= 1900;
394 val->tm_mon--;
395 val->tm_isdst = -1;
396 #if !defined(WIN32) && !defined(AIX) && !defined( __OS400__ ) && !defined(__sun)
397 val->tm_zone = NULL;
398 val->tm_gmtoff = -1;
399 #endif
400
401 temp2 = strpbrk(ptr, "T");
402 temp3 = strrchr(temp2, ':');
403 temp3[0] = '\0';
404 len = strlen(temp2);
405 temp3[0] = ':';
406
407 if( ( temp = strpbrk( ptr, "Z") ) != NULL ) { /* got canonical UTC date */
408 time_t tt = _rdfstore_xsd_mktime(val);
409 if( temp != ptr1 ) {
410 return 0;
411 };
412
413 if (tt == -1) {
414 return 0;
415 };
416 ptm = localtime (&tt);
417 } else if( len > (sizeof(char) * 6) ) { /* ok now we need to normalize +/-hh:mm timezone to UTC - hehheee! */
418 int hours = 0;
419 int minutes = 0;
420 int secs;
421 time_t t;
422
423 tzsign = strpbrk (temp2, "+");
424
425 if (tzsign == NULL) {
426 tzsign = strpbrk (temp2, "-");
427 };
428
429 timestamp = _rdfstore_xsd_mktime(val);
430 if ( timestamp == -1 ) {
431 return 0;
432 };
433
434 if( sscanf( tzsign+1, "%02d:%02d", &hours, &minutes) != 2 ) {
435 return 0;
436 };
437
438 secs = hours * 60 * 60 + minutes * 60;
439 if( (temp = strpbrk(tzsign, "+")) != NULL ) {
440 timestamp += secs;
441 } else {
442 timestamp -= secs;
443 };
444
445 ptm = localtime(×tamp);
446 memcpy(val, ptm, sizeof(struct tm));
447 t = _rdfstore_xsd_mktime(val);
448 if( t == -1 ) {
449 return 0;
450 };
451
452 t = labs(t - d);
453 ptm = gmtime(&t);
454 } else { /*else it is assumed that the sent time is localtime */
455 if( ( *ptr1 < 48 ) ||
456 ( *ptr1 > 57 ) ||
457 ( *(ptr1-2) != ':' ) ) {
458 return 0;
459 };
460
461 timestamp = _rdfstore_xsd_mktime(val);
462 if( timestamp == -1 ) {
463 return 0;
464 };
465
466 ptm = gmtime(×tamp);
467 };
468
469 if( ptm!= NULL ) {
470 #ifdef RDFSTORE_XSD_DEBUG
471 printf("rdfstore_xsd_deserialize_dateTime( '%s' ) is a valid date\n", ptr);
472 #endif
473
474 return 1;
475 } else {
476 #ifdef RDFSTORE_XSD_DEBUG
477 printf("rdfstore_xsd_deserialize_dateTime( '%s' ) is NOT a valid date\n", ptr);
478 #endif
479
480 return 0;
481 };
482 };
483
rdfstore_xsd_serialize_string(const char * value,char * result)484 void rdfstore_xsd_serialize_string( const char * value, char * result ) {
485 };
486
487 int rdfstore_xsd_deserialize_string( const char * string, char * val );
488
489 /* this routine is faster than standard mktime() */
_rdfstore_xsd_mktime(const struct tm * t)490 time_t _rdfstore_xsd_mktime(const struct tm * t) {
491 int year;
492 time_t days;
493 static const int dayoffset[12] = {306, 337, 0, 31, 61, 92, 122, 153, 184, 214, 245, 275};
494
495 year = t->tm_year;
496
497 if (year < 70 || ((sizeof(time_t) <= 4) && (year >= 138)))
498 return RDFSTORE_XSD_BAD_DATE;
499
500 /* shift new year to 1st March in order to make leap year calc easy */
501
502 if (t->tm_mon < 2)
503 year--;
504
505 /* Find number of days since 1st March 1900 (in the Gregorian calendar). */
506
507 days = year * 365 + year / 4 - year / 100 + (year / 100 + 3) / 4;
508 days += dayoffset[t->tm_mon] + t->tm_mday - 1;
509 days -= 25508; /* 1 jan 1970 is 25508 days since 1 mar 1900 */
510
511 days = ((days * 24 + t->tm_hour) * 60 + t->tm_min) * 60 + t->tm_sec;
512
513 if (days < 0)
514 return RDFSTORE_XSD_BAD_DATE; /* must have overflowed */
515 else
516 return days; /* must be a valid time */
517 };
518
519