1 /* -*- Mode: c; c-basic-offset: 2 -*-
2 *
3 * rasqal_expr_numerics.c - Rasqal expression evaluation
4 *
5 * Copyright (C) 2011, David Beckett http://www.dajobe.org/
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
40 #include "rasqal.h"
41 #include "rasqal_internal.h"
42
43 #if defined(RASQAL_UUID_OSSP)
44 #include <uuid.h>
45 #endif
46 #if defined(RASQAL_UUID_LIBUUID)
47 #include <uuid.h>
48 #endif
49 #ifdef RASQAL_UUID_LIBC
50 #include <uuid/uuid.h>
51 #endif
52
53 #define DEBUG_FH stderr
54
55
56 /*
57 * rasqal_expression_evaluate_abs:
58 * @e: The expression to evaluate.
59 * @eval_context: Evaluation context
60 *
61 * INTERNAL - Evaluate SPARQL 1.1 RASQAL_EXPR_ABS (numeric) expression.
62 *
63 * Return value: A #rasqal_literal value or NULL on failure.
64 */
65 rasqal_literal*
rasqal_expression_evaluate_abs(rasqal_expression * e,rasqal_evaluation_context * eval_context,int * error_p)66 rasqal_expression_evaluate_abs(rasqal_expression *e,
67 rasqal_evaluation_context *eval_context,
68 int *error_p)
69 {
70 rasqal_literal* l1;
71 rasqal_literal* result = NULL;
72
73 l1 = rasqal_expression_evaluate2(e->arg1, eval_context, error_p);
74 if((error_p && *error_p) || !l1)
75 goto failed;
76
77 if(!rasqal_literal_is_numeric(l1))
78 goto failed;
79
80 result = rasqal_literal_abs(l1, error_p);
81 rasqal_free_literal(l1);
82 l1 = NULL;
83
84 if(error_p && *error_p)
85 goto failed;
86
87 return result;
88
89 failed:
90 if(error_p)
91 *error_p = 1;
92
93 if(l1)
94 rasqal_free_literal(l1);
95
96 return NULL;
97 }
98
99
100 /*
101 * rasqal_expression_evaluate_round:
102 * @e: The expression to evaluate.
103 * @eval_context: Evaluation context
104 *
105 * INTERNAL - Evaluate SPARQL 1.1 RASQAL_EXPR_ROUND (numeric) expression.
106 *
107 * Return value: A #rasqal_literal value or NULL on failure.
108 */
109 rasqal_literal*
rasqal_expression_evaluate_round(rasqal_expression * e,rasqal_evaluation_context * eval_context,int * error_p)110 rasqal_expression_evaluate_round(rasqal_expression *e,
111 rasqal_evaluation_context *eval_context,
112 int *error_p)
113 {
114 rasqal_literal* l1;
115 rasqal_literal* result = NULL;
116
117 l1 = rasqal_expression_evaluate2(e->arg1, eval_context, error_p);
118 if((error_p && *error_p) || !l1)
119 goto failed;
120
121 if(!rasqal_literal_is_numeric(l1))
122 goto failed;
123
124 result = rasqal_literal_round(l1, error_p);
125 rasqal_free_literal(l1);
126 l1 = NULL;
127
128 if(error_p && *error_p)
129 goto failed;
130
131 return result;
132
133 failed:
134 if(error_p)
135 *error_p = 1;
136
137 if(l1)
138 rasqal_free_literal(l1);
139
140 return NULL;
141 }
142
143
144 /*
145 * rasqal_expression_evaluate_ceil:
146 * @e: The expression to evaluate.
147 * @eval_context: Evaluation context
148 *
149 * INTERNAL - Evaluate SPARQL 1.1 RASQAL_EXPR_CEIL (numeric) expression.
150 *
151 * Return value: A #rasqal_literal value or NULL on failure.
152 */
153 rasqal_literal*
rasqal_expression_evaluate_ceil(rasqal_expression * e,rasqal_evaluation_context * eval_context,int * error_p)154 rasqal_expression_evaluate_ceil(rasqal_expression *e,
155 rasqal_evaluation_context *eval_context,
156 int *error_p)
157 {
158 rasqal_literal* l1;
159 rasqal_literal* result = NULL;
160
161 l1 = rasqal_expression_evaluate2(e->arg1, eval_context, error_p);
162 if((error_p && *error_p) || !l1)
163 goto failed;
164
165 if(!rasqal_literal_is_numeric(l1))
166 goto failed;
167
168 result = rasqal_literal_ceil(l1, error_p);
169 rasqal_free_literal(l1);
170 l1 = NULL;
171
172 if(error_p && *error_p)
173 goto failed;
174
175 return result;
176
177 failed:
178 if(error_p)
179 *error_p = 1;
180
181 if(l1)
182 rasqal_free_literal(l1);
183
184 return NULL;
185 }
186
187
188 /*
189 * rasqal_expression_evaluate_floor:
190 * @e: The expression to evaluate.
191 * @eval_context: Evaluation context
192 *
193 * INTERNAL - Evaluate SPARQL 1.1 RASQAL_EXPR_FLOOR (numeric) expression.
194 *
195 * Return value: A #rasqal_literal value or NULL on failure.
196 */
197 rasqal_literal*
rasqal_expression_evaluate_floor(rasqal_expression * e,rasqal_evaluation_context * eval_context,int * error_p)198 rasqal_expression_evaluate_floor(rasqal_expression *e,
199 rasqal_evaluation_context *eval_context,
200 int *error_p)
201 {
202 rasqal_literal* l1;
203 rasqal_literal* result = NULL;
204
205 l1 = rasqal_expression_evaluate2(e->arg1, eval_context, error_p);
206 if((error_p && *error_p) || !l1)
207 goto failed;
208
209 if(!rasqal_literal_is_numeric(l1))
210 goto failed;
211
212 result = rasqal_literal_floor(l1, error_p);
213 rasqal_free_literal(l1);
214 l1 = NULL;
215
216 if(error_p && *error_p)
217 goto failed;
218
219 return result;
220
221 failed:
222 if(error_p)
223 *error_p = 1;
224
225 if(l1)
226 rasqal_free_literal(l1);
227
228 return NULL;
229 }
230
231
232 /*
233 * rasqal_expression_evaluate_rand:
234 * @e: The expression to evaluate.
235 * @eval_context: Evaluation context
236 *
237 * INTERNAL - Evaluate SPARQL 1.1 RASQAL_EXPR_RAND (integer expr) expression.
238 *
239 * Return value: A #rasqal_literal xsd:double value in range [0, 1) or NULL on failure.
240 */
241 rasqal_literal*
rasqal_expression_evaluate_rand(rasqal_expression * e,rasqal_evaluation_context * eval_context,int * error_p)242 rasqal_expression_evaluate_rand(rasqal_expression *e,
243 rasqal_evaluation_context *eval_context,
244 int *error_p)
245 {
246 rasqal_world* world = eval_context->world;
247 double d;
248
249 d = rasqal_random_drand(eval_context->random);
250
251 return rasqal_new_double_literal(world, d);
252 }
253
254
255 /*
256 * rasqal_expression_evaluate_digest:
257 * @e: The expression to evaluate.
258 * @eval_context: Evaluation context
259 * @error_p: pointer to error flag or NULL
260 *
261 * INTERNAL - Evaluate SPARQL 1.1 RASQAL_EXPR_MD5, RASQAL_EXPR_SHA1,
262 * RASQAL_EXPR_SHA224, RASQAL_EXPR_SHA256, RASQAL_EXPR_SHA384,
263 * RASQAL_EXPR_SHA512 (string) expression.
264 *
265 * Return value: A #rasqal_literal xsd:string value or NULL on failure.
266 */
267 rasqal_literal*
rasqal_expression_evaluate_digest(rasqal_expression * e,rasqal_evaluation_context * eval_context,int * error_p)268 rasqal_expression_evaluate_digest(rasqal_expression *e,
269 rasqal_evaluation_context *eval_context,
270 int *error_p)
271 {
272 rasqal_world* world = eval_context->world;
273 rasqal_digest_type md_type = RASQAL_DIGEST_NONE;
274 rasqal_literal* l1 = NULL;
275 const unsigned char *s;
276 unsigned char *new_s;
277 size_t len;
278 int output_len;
279 unsigned char *output = NULL;
280 unsigned int i;
281 unsigned char* p;
282
283 /* Turn EXPR enum into DIGEST enum - we know they are ordered the same */
284 if(e->op >= RASQAL_EXPR_MD5 && e->op <= RASQAL_EXPR_SHA512)
285 md_type = RASQAL_GOOD_CAST(rasqal_digest_type, e->op - RASQAL_EXPR_MD5 + RASQAL_DIGEST_MD5);
286 else
287 goto failed;
288
289 l1 = rasqal_expression_evaluate2(e->arg1, eval_context, error_p);
290 if((error_p && *error_p) || !l1)
291 goto failed;
292
293 s = rasqal_literal_as_counted_string(l1, &len, eval_context->flags, error_p);
294 if(error_p && *error_p)
295 goto failed;
296
297 output_len = rasqal_digest_buffer(md_type, NULL, NULL, 0);
298 if(output_len < 0)
299 goto failed;
300
301 output = RASQAL_MALLOC(unsigned char*, RASQAL_GOOD_CAST(size_t, output_len));
302 if(!output)
303 goto failed;
304
305 output_len = rasqal_digest_buffer(md_type, output, s, len);
306 if(output_len < 0)
307 goto failed;
308
309 new_s = RASQAL_MALLOC(unsigned char*, (RASQAL_GOOD_CAST(size_t, output_len) * 2) + 1);
310 if(!new_s)
311 goto failed;
312
313 p = new_s;
314 for(i = 0; i < RASQAL_GOOD_CAST(unsigned int, output_len); i++) {
315 unsigned short hex;
316 unsigned char c = output[i];
317
318 hex = (c & 0xf0) >> 4;
319 *p++ = RASQAL_GOOD_CAST(unsigned char, (hex < 10) ? ('0' + hex) : ('a' + hex - 10));
320 hex = (c & 0x0f);
321 *p++ = RASQAL_GOOD_CAST(unsigned char, (hex < 10) ? ('0' + hex) : ('a' + hex - 10));
322 }
323 *p = '\0';
324
325 RASQAL_FREE(char, output);
326 rasqal_free_literal(l1);
327
328 /* after this new_s becomes owned by result */
329 return rasqal_new_string_literal(world, new_s, NULL, NULL, NULL);
330
331 failed:
332 if(error_p)
333 *error_p = 1;
334
335 if(output)
336 RASQAL_FREE(char, output);
337 if(l1)
338 rasqal_free_literal(l1);
339
340 return NULL;
341 }
342
343
344 #define RASQAL_UUID_LEN 16
345 #define RASQAL_UUID_HEXDIGIT_LEN (RASQAL_UUID_LEN << 1)
346 /* 4 '-' chars added after 8, 12, 16, 20 output hex digit */
347 #define RASQAL_UUID_STRING_LEN (RASQAL_UUID_HEXDIGIT_LEN + 4)
348 #define RASQAL_UUID_URI_PREFIX "urn:uuid:"
349 #define RASQAL_UUID_URI_PREFIX_LEN 9
350
351
352 #ifdef RASQAL_UUID_INTERNAL
353 typedef union {
354 unsigned char b[16];
355 int16_t w[8];
356 } uuid_t;
357
358 /*
359 * rasqal_uuid_generate:
360 * @eval_context: evaluation context
361 * @uuid: uuid object
362 *
363 * INTERNAL - Generate a random UUID based on rasqal random
364 *
365 * Byte offset
366 * 0 1 2 3 4 5 6 7 8 9 101112131415
367 * xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx Hex string
368 *
369 * where x is any hexadecimal digit and y is one of 8, 9, a, or b.
370 */
371 static void
rasqal_uuid_generate(rasqal_evaluation_context * eval_context,uuid_t ptr)372 rasqal_uuid_generate(rasqal_evaluation_context *eval_context, uuid_t ptr)
373 {
374 int16_t* out = ptr.w;
375 unsigned char* outc = ptr.b;
376 unsigned int i;
377 for(i = 0; i < (RASQAL_UUID_LEN / sizeof(int16_t)); i++) {
378 *out++ = rasqal_random_irand(eval_context->random);
379 }
380
381 outc[6] = (outc[6] & 0x0F) | 0x40;
382 outc[8] = (outc[8] & 0x3F) | 0x80;
383 }
384 #endif
385
386 /*
387 * rasqal_expression_evaluate_uuid:
388 * @e: The expression to evaluate.
389 * @eval_context: Evaluation context
390 * @want_uri: non-0 to return URI otherwise string
391 *
392 * INTERNAL - Evaluate SPARQL 1.1 RASQAL_EXPR_UUID, RASQAL_EXPR_STRUUID
393 *
394 * Return value: A #rasqal_literal URI / string value or NULL on failure.
395 */
396 static rasqal_literal*
rasqal_expression_evaluate_uuid(rasqal_expression * e,rasqal_evaluation_context * eval_context,int * error_p,int want_uri)397 rasqal_expression_evaluate_uuid(rasqal_expression *e,
398 rasqal_evaluation_context *eval_context,
399 int *error_p,
400 int want_uri)
401 {
402 #ifdef RASQAL_UUID_NONE
403 return NULL;
404
405 #else
406
407 rasqal_world* world = eval_context->world;
408 #if defined(RASQAL_UUID_OSSP)
409 uuid_t* data;
410 #else
411 uuid_t data; /* static */
412 int i;
413 #endif
414 size_t output_len = RASQAL_UUID_STRING_LEN;
415 unsigned char* output;
416 unsigned char* p;
417
418 #if defined(RASQAL_UUID_LIBUUID) || defined(RASQAL_UUID_LIBC)
419 uuid_generate(data);
420 #endif
421 #if defined(RASQAL_UUID_OSSP)
422 uuid_create(&data);
423 uuid_make(data, UUID_MAKE_V1);
424 #endif
425 #ifdef RASQAL_UUID_INTERNAL
426 rasqal_uuid_generate(eval_context, data);
427 #endif
428
429 if(want_uri)
430 output_len += RASQAL_UUID_URI_PREFIX_LEN;
431
432 output = RASQAL_MALLOC(unsigned char*, output_len + 1);
433 if(!output) {
434 #if defined(RASQAL_UUID_OSSP)
435 uuid_destroy(data);
436 #endif
437 return NULL;
438 }
439
440 p = output;
441 if(want_uri) {
442 memcpy(p, RASQAL_UUID_URI_PREFIX, RASQAL_UUID_URI_PREFIX_LEN);
443 p += RASQAL_UUID_URI_PREFIX_LEN;
444 }
445
446 #if defined(RASQAL_UUID_OSSP)
447 uuid_export(data, UUID_FMT_STR, p, /* data_len */ NULL);
448 uuid_destroy(data);
449 #else
450 for(i = 0; i < RASQAL_UUID_LEN; i++) {
451 unsigned short hex;
452 #ifdef RASQAL_UUID_INTERNAL
453 unsigned char c = data.b[i];
454 #else
455 unsigned char c = data[i];
456 #endif
457
458 hex = (c & 0xf0) >> 4;
459 *p++ = RASQAL_GOOD_CAST(unsigned char, (hex < 10) ? ('0' + hex) : ('a' + hex - 10));
460 hex = (c & 0x0f);
461 *p++ = RASQAL_GOOD_CAST(unsigned char, (hex < 10) ? ('0' + hex) : ('a' + hex - 10));
462 if(i == 3 || i == 5 || i == 7 || i == 9)
463 *p++ = '-';
464 }
465 *p = '\0';
466 #endif /* end if !RASQAL_UUID_OSSP */
467
468 /* after this output becomes owned by result */
469 if(want_uri) {
470 raptor_uri* u;
471 rasqal_literal* l = NULL;
472
473 u = raptor_new_uri(world->raptor_world_ptr, output);
474 if(u)
475 l = rasqal_new_uri_literal(world, u);
476
477 RASQAL_FREE(char*, output);
478 return l;
479 } else {
480 return rasqal_new_string_literal(world, output, NULL, NULL, NULL);
481 }
482 #endif
483 }
484
485
486 /*
487 * rasqal_expression_evaluate_uriuuid:
488 * @e: The expression to evaluate.
489 * @eval_context: Evaluation context
490 * @want_uri: non-0 to return URI otherwise string
491 *
492 * INTERNAL - Evaluate SPARQL 1.1 RASQAL_EXPR_UUID
493 *
494 * Return value: A #rasqal_literal URI value or NULL on failure.
495 */
496 rasqal_literal*
rasqal_expression_evaluate_uriuuid(rasqal_expression * e,rasqal_evaluation_context * eval_context,int * error_p)497 rasqal_expression_evaluate_uriuuid(rasqal_expression *e,
498 rasqal_evaluation_context *eval_context,
499 int *error_p)
500 {
501 return rasqal_expression_evaluate_uuid(e, eval_context, error_p, 1);
502 }
503
504 /*
505 * rasqal_expression_evaluate_uuid:
506 * @e: The expression to evaluate.
507 * @eval_context: Evaluation context
508 * @want_uri: non-0 to return URI otherwise string
509 *
510 * INTERNAL - Evaluate SPARQL 1.1 RASQAL_EXPR_STRUUID
511 *
512 * Return value: A #rasqal_literal string value or NULL on failure.
513 */
514 rasqal_literal*
rasqal_expression_evaluate_struuid(rasqal_expression * e,rasqal_evaluation_context * eval_context,int * error_p)515 rasqal_expression_evaluate_struuid(rasqal_expression *e,
516 rasqal_evaluation_context *eval_context,
517 int *error_p)
518 {
519 return rasqal_expression_evaluate_uuid(e, eval_context, error_p, 0);
520 }
521
522