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