1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <raptor.h>
5 #include <ladspa.h>
6 #include <time.h>
7 #include <sys/types.h>
8 #include <unistd.h>
9 #include <sys/time.h>
10 #include "md5.h"
11
12 #include "lrdf.h"
13
14 /* XXX The size if that hash table, should be dyunamic, but this will do for
15 * now */
16 #define LRDF_HASH_SIZE 1024
17
18 static unsigned int lrdf_uid = 0; /* A unique(ish) id to append to genid's to
19 * avoid clashses */
20
21 static raptor_world *world = NULL;
22 static lrdf_statement *triples = NULL;
23 static lrdf_statement *free_triples;
24 static lrdf_string_hash *resources_hash[LRDF_HASH_SIZE];
25 static lrdf_string_hash *literals_hash[LRDF_HASH_SIZE];
26 static lrdf_triple_hash *subj_hash[LRDF_HASH_SIZE];
27 static lrdf_triple_hash *obj_hash[LRDF_HASH_SIZE];
28 static lrdf_triple_hash *pred_hash[LRDF_HASH_SIZE];
29 static lrdf_closure_hash *subclass_hash[LRDF_HASH_SIZE];
30 static lrdf_closure_hash *superclass_hash[LRDF_HASH_SIZE];
31 static lrdf_hash rdf_resource_h;
32
33 /* Internal functions */
34 void lrdf_more_triples(int count);
35 lrdf_statement *lrdf_alloc_statement();
36 lrdf_statement *lrdf_all_triples();
37 static char *lrdf_check_hash(lrdf_string_hash ** tbl, lrdf_hash hash, const char
38 *str);
39 static char *lrdf_find_string_hash(lrdf_string_hash ** tbl,
40 lrdf_hash hash);
41 static void lrdf_add_triple_hash(lrdf_triple_hash ** tbl, lrdf_hash hash,
42 lrdf_statement * s);
43 static void lrdf_remove_triple_hash(lrdf_triple_hash ** tbl,
44 lrdf_hash hash, lrdf_statement * s);
45 static void lrdf_add_closure_hash(lrdf_closure_hash ** tbl,
46 lrdf_hash subject, lrdf_hash object);
47 static void lrdf_store(void *user_data, raptor_statement * statement);
48 void lrdf_free_statements(lrdf_statement * s);
49 void lrdf_copy_statement(lrdf_statement * from, lrdf_statement * to);
50 void lrdf_rebuild_taxonomic_closure(lrdf_closure_hash ** fwd_tbl,
51 lrdf_closure_hash ** rev_tbl);
52 static lrdf_uris *lrdf_uris_new(int size);
53 int lrdf_read_file_intl(const char *uri);
54 static void lrdf_uris_append(lrdf_uris * base, lrdf_uris * add);
55 static inline lrdf_hash lrdf_gen_hash(const char *str);
56 void lrdf_free_string_hash(lrdf_string_hash * h[]);
57 void lrdf_free_triple_hash(lrdf_triple_hash * h[]);
58 void lrdf_free_closure_hash(lrdf_closure_hash * h[]);
59
lrdf_gen_hash(const char * str)60 static inline lrdf_hash lrdf_gen_hash(const char *str)
61 {
62 lrdf_hash data[2];
63
64 MD5_CTX ctx;
65 MD5_Init(&ctx);
66 MD5_Update(&ctx, str, strlen(str));
67 MD5_Final((unsigned char*)data, &ctx);
68
69 return data[0];
70 }
71
lrdf_init()72 void lrdf_init()
73 {
74 unsigned int i;
75 struct timeval tv;
76
77 world = raptor_new_world();
78 lrdf_more_triples(256);
79
80 /* A UID to add to genids to make them safer */
81 gettimeofday(&tv, NULL);
82 lrdf_uid = (unsigned int) getpid();
83 lrdf_uid ^= (unsigned int) tv.tv_usec;
84
85 /* Global value for the hash of rdf:Resource, saves time */
86 rdf_resource_h = lrdf_gen_hash(RDF_RESOURCE);
87
88 /* Make sure all the hashes are empty, just incase */
89 for (i = 0; i < LRDF_HASH_SIZE; i++) {
90 resources_hash[i] = NULL;
91 literals_hash[i] = NULL;
92 subj_hash[i] = NULL;
93 obj_hash[i] = NULL;
94 pred_hash[i] = NULL;
95 subclass_hash[i] = NULL;
96 superclass_hash[i] = NULL;
97 }
98
99 /* Make sure we have rdf:Resource in our hash tables */
100 lrdf_check_hash(resources_hash, rdf_resource_h, RDF_RESOURCE);
101 }
102
lrdf_more_triples(int count)103 void lrdf_more_triples(int count)
104 {
105 int i;
106 lrdf_statement *new;
107
108 new = (lrdf_statement *) calloc(count, sizeof(lrdf_statement));
109 for (i = 0; i < count - 1; i++) {
110 new[i].next = new + i + 1;
111 }
112 new[count - 1].next = free_triples;
113 free_triples = new;
114 }
115
lrdf_cleanup()116 void lrdf_cleanup()
117 {
118 raptor_free_world(world);
119 world = NULL;
120
121 lrdf_free_string_hash(resources_hash);
122 lrdf_free_string_hash(literals_hash);
123 lrdf_free_triple_hash(subj_hash);
124 lrdf_free_triple_hash(obj_hash);
125 lrdf_free_triple_hash(pred_hash);
126 lrdf_free_closure_hash(subclass_hash);
127 lrdf_free_closure_hash(superclass_hash);
128 }
129
lrdf_alloc_statement()130 lrdf_statement *lrdf_alloc_statement()
131 {
132 lrdf_statement *s;
133
134 if (free_triples == NULL) {
135 lrdf_more_triples(256);
136 }
137 s = free_triples;
138 free_triples = free_triples->next;
139 s->next = NULL;
140
141 return s;
142 }
143
lrdf_free_statements(lrdf_statement * s)144 void lrdf_free_statements(lrdf_statement * s)
145 {
146 lrdf_statement *next;
147
148 for (; s != NULL; s = next) {
149 next = s->next;
150 s->next = free_triples;
151 free_triples = s;
152 }
153 }
154
lrdf_add_triple(const char * source,const char * subject,const char * predicate,const char * object,enum lrdf_objtype literal)155 void lrdf_add_triple(const char *source, const char *subject, const char
156 *predicate, const char *object,
157 enum lrdf_objtype literal)
158 {
159 lrdf_statement *s = lrdf_alloc_statement();
160
161 s->shash = lrdf_gen_hash(subject);
162 s->phash = lrdf_gen_hash(predicate);
163 s->ohash = lrdf_gen_hash(object);
164 s->next = triples;
165 triples = s;
166
167 s->subject = lrdf_check_hash(resources_hash, s->shash, subject);
168 s->predicate = lrdf_check_hash(resources_hash, s->phash, predicate);
169 if (literal == lrdf_literal) {
170 s->object = lrdf_check_hash(literals_hash, s->ohash, object);
171 s->object_type = lrdf_literal;
172 } else {
173 s->object = lrdf_check_hash(resources_hash, s->ohash, object);
174 s->object_type = lrdf_uri;
175 }
176
177 lrdf_add_triple_hash(subj_hash, s->shash, s);
178 lrdf_add_triple_hash(obj_hash, s->ohash, s);
179 lrdf_add_triple_hash(pred_hash, s->phash, s);
180
181 if (source) {
182 s->source = lrdf_gen_hash(source);
183 } else {
184 s->source = 0;
185 }
186 }
187
lrdf_remove_uri_matches(const char * uri)188 void lrdf_remove_uri_matches(const char *uri)
189 {
190 lrdf_statement p;
191
192 p.subject = (char *)uri;
193 p.predicate = NULL;
194 p.object = NULL;
195 lrdf_remove_matches(&p);
196 p.subject = NULL;
197 p.predicate = (char *)uri;
198 lrdf_remove_matches(&p);
199 p.predicate = NULL;
200 p.object = (char *)uri;
201 lrdf_remove_matches(&p);
202
203 /* we could also remove the hash of the uri from the lookup tables, but we
204 * don't. natch */
205 }
206
lrdf_remove_matches(lrdf_statement * pattern)207 void lrdf_remove_matches(lrdf_statement *pattern)
208 {
209 lrdf_statement *s;
210 lrdf_statement *it;
211
212 while ((s = lrdf_one_match(pattern))) {
213 /* If the head triple is the one we want to remove */
214 if (triples == s) {
215 triples = s->next;
216 lrdf_remove_triple_hash(subj_hash, s->shash, s);
217 lrdf_remove_triple_hash(pred_hash, s->phash, s);
218 lrdf_remove_triple_hash(obj_hash, s->ohash, s);
219 s->next = NULL;
220 lrdf_free_statements(s);
221 continue;
222 }
223
224 /* Else its somwehere in the tail of the list */
225 for (it = triples; it; it = it->next) {
226 if (it->next == s) {
227 it->next = it->next->next;
228 lrdf_remove_triple_hash(subj_hash, s->shash, s);
229 lrdf_remove_triple_hash(pred_hash, s->phash, s);
230 lrdf_remove_triple_hash(obj_hash, s->ohash, s);
231 s->next = NULL;
232 lrdf_free_statements(s);
233 break;
234 }
235 }
236 }
237 }
238
lrdf_term_as_string(char * tmp,int tmp_len,const raptor_term * term)239 static const char *lrdf_term_as_string(char *tmp, int tmp_len,
240 const raptor_term *term)
241 {
242 switch (term->type) {
243 case RAPTOR_TERM_TYPE_URI:
244 return (const char *) raptor_uri_as_string(term->value.uri);
245 case RAPTOR_TERM_TYPE_LITERAL:
246 return (const char *) term->value.literal.string;
247 case RAPTOR_TERM_TYPE_BLANK:
248 snprintf(tmp, tmp_len, "_:%s.%x", term->value.blank.string, lrdf_uid);
249 return tmp;
250 default:
251 return "(?)";
252 }
253 }
254
lrdf_store(void * user_data,raptor_statement * statement)255 static void lrdf_store(void *user_data, raptor_statement * statement)
256 {
257 lrdf_statement *s = lrdf_alloc_statement();
258 char tmps[128], tmpp[128], tmpo[128];
259 const char *subj = lrdf_term_as_string(tmps, 128, statement->subject),
260 *pred = lrdf_term_as_string(tmpp, 128, statement->predicate),
261 *obj = lrdf_term_as_string(tmpo, 128, statement->object);
262
263 s->shash = lrdf_gen_hash(subj);
264 s->phash = lrdf_gen_hash(pred);
265 s->ohash = lrdf_gen_hash(obj);
266 s->next = triples;
267 triples = s;
268
269 s->subject = lrdf_check_hash(resources_hash, s->shash, subj);
270 s->predicate = lrdf_check_hash(resources_hash, s->phash, pred);
271 if (statement->object->type == RAPTOR_TERM_TYPE_LITERAL) {
272 s->object = lrdf_check_hash(literals_hash, s->ohash, obj);
273 s->object_type = lrdf_literal;
274 } else {
275 s->object = lrdf_check_hash(resources_hash, s->ohash, obj);
276 s->object_type = lrdf_uri;
277 }
278
279 lrdf_add_triple_hash(subj_hash, s->shash, s);
280 lrdf_add_triple_hash(obj_hash, s->ohash, s);
281 lrdf_add_triple_hash(pred_hash, s->phash, s);
282
283 s->source = *((lrdf_hash *) user_data);
284 }
285
lrdf_check_hash(lrdf_string_hash ** tbl,lrdf_hash hash,const char * str)286 static char *lrdf_check_hash(lrdf_string_hash ** tbl, lrdf_hash hash, const char
287 *str)
288 {
289 lrdf_string_hash *tmp, *newe;
290 char *tmps, *newstr;
291
292 if ((tmps = lrdf_find_string_hash(tbl, hash))) {
293 return tmps;
294 } else {
295 tmp = tbl[hash & (LRDF_HASH_SIZE - 1)];
296 newstr = strdup(str);
297 newe = (lrdf_string_hash *) malloc(sizeof(lrdf_string_hash));
298 newe->hash = hash;
299 newe->str = newstr;
300 newe->next = tmp;
301 tbl[hash & (LRDF_HASH_SIZE - 1)] = newe;
302
303 return newstr;
304 }
305 }
306
lrdf_find_string_hash(lrdf_string_hash ** tbl,lrdf_hash hash)307 static char *lrdf_find_string_hash(lrdf_string_hash ** tbl, lrdf_hash hash)
308 {
309 lrdf_string_hash *p = tbl[hash & (LRDF_HASH_SIZE - 1)];
310
311 while (p) {
312 if (p->hash == hash) {
313 return p->str;
314 }
315 p = p->next;
316 }
317
318 return NULL;
319 }
320
lrdf_add_triple_hash(lrdf_triple_hash ** tbl,lrdf_hash hash,lrdf_statement * s)321 static void lrdf_add_triple_hash(lrdf_triple_hash ** tbl, lrdf_hash hash,
322 lrdf_statement * s)
323 {
324 lrdf_triple_hash *p = tbl[hash & (LRDF_HASH_SIZE - 1)];
325 lrdf_triple_hash *newe = malloc(sizeof(lrdf_triple_hash));
326
327 newe->hash = hash;
328 newe->triple = s;
329 newe->next = p;
330 tbl[hash & (LRDF_HASH_SIZE - 1)] = newe;
331 }
332
lrdf_remove_triple_hash(lrdf_triple_hash ** tbl,lrdf_hash hash,lrdf_statement * s)333 static void lrdf_remove_triple_hash(lrdf_triple_hash ** tbl,
334 lrdf_hash hash, lrdf_statement * s)
335 {
336 lrdf_triple_hash *p = tbl[hash & (LRDF_HASH_SIZE - 1)];
337 lrdf_triple_hash *it;
338
339 /* The entry we want to remove is the first */
340 if (p && p->triple == s) {
341 it = p->next;
342 free(p);
343 tbl[hash & (LRDF_HASH_SIZE - 1)] = it;
344 return;
345 }
346
347 /* The entry is somewhere in the list */
348 for (it = p; it; it = it->next) {
349 if (it->next && it->next->triple == s) {
350 p = it->next;
351 it->next = it->next->next;
352 free(p);
353 return;
354 }
355 }
356
357 fprintf(stderr,
358 "lrdf: tried to remove non-existant triple hash %llx\n", hash);
359 }
360
lrdf_add_closure_hash(lrdf_closure_hash ** tbl,lrdf_hash subject,lrdf_hash object)361 static void lrdf_add_closure_hash(lrdf_closure_hash ** tbl,
362 lrdf_hash subject, lrdf_hash object)
363 {
364 lrdf_closure_hash *p = tbl[subject & (LRDF_HASH_SIZE - 1)];
365 lrdf_closure_hash *newe = malloc(sizeof(lrdf_closure_hash));
366
367 newe->subject = subject;
368 newe->object = object;
369 newe->next = p;
370 tbl[subject & (LRDF_HASH_SIZE - 1)] = newe;
371 }
372
lrdf_export_by_source(const char * src,const char * file)373 int lrdf_export_by_source(const char *src, const char *file)
374 {
375 lrdf_hash source = lrdf_gen_hash(src);
376 lrdf_statement *s;
377 const char *outfile = file;
378 FILE *out;
379
380 if (!strncasecmp(file, "file:", 5)) {
381 outfile = file + 5;
382 }
383 if (!(out = fopen(outfile, "w"))) {
384 fprintf(stderr, "lrdf: trying to write '%s'\n", outfile);
385 perror("");
386 return -1;
387 }
388
389 for (s = triples; s; s = s->next) {
390 if (s->source == source) {
391 if (s->object_type == lrdf_uri) {
392 fprintf(out, "<%s> <%s> <%s> .\n", s->subject,
393 s->predicate, s->object);
394 } else {
395 fprintf(out, "<%s> <%s> \"%s\" .\n",
396 s->subject, s->predicate, s->object);
397 }
398 }
399 }
400 fclose(out);
401
402 return 0;
403 }
404
lrdf_rebuild_caches()405 void lrdf_rebuild_caches()
406 {
407 lrdf_rebuild_taxonomic_closure(subclass_hash, superclass_hash);
408 }
409
lrdf_rebuild_taxonomic_closure(lrdf_closure_hash ** fwd_tbl,lrdf_closure_hash ** rev_tbl)410 void lrdf_rebuild_taxonomic_closure(lrdf_closure_hash ** fwd_tbl,
411 lrdf_closure_hash ** rev_tbl)
412 {
413 lrdf_string_hash *tmp[LRDF_HASH_SIZE];
414 lrdf_string_hash *hit;
415 char **uris;
416 int *pathto;
417 lrdf_statement q;
418 lrdf_statement *m;
419 lrdf_statement *it;
420 unsigned int class_count = 0;
421 unsigned int i, j, k;
422
423 /* Ensure the tmp table is cleared out */
424 for (i = 0; i < LRDF_HASH_SIZE; i++) {
425 tmp[i] = NULL;
426 }
427
428 /* Find all explicitly named classes */
429 q.subject = NULL;
430 q.predicate = RDF_TYPE;
431 q.object = RDFS_CLASS;
432 m = lrdf_matches(&q);
433 for (it = m; it; it = it->next) {
434 lrdf_check_hash(tmp, it->shash, it->subject);
435 }
436 lrdf_free_statements(m);
437
438 /* Find all implicitly name classes */
439 q.subject = NULL;
440 q.predicate = RDFS_SUBCLASSOF;
441 q.object = NULL;
442 m = lrdf_matches(&q);
443 for (it = m; it != NULL; it = it->next) {
444 lrdf_check_hash(tmp, it->shash, it->subject);
445 lrdf_check_hash(tmp, it->ohash, it->object);
446 }
447
448 /* Count unique class uris */
449 for (i = 0; i < LRDF_HASH_SIZE; i++) {
450 for (hit = tmp[i]; hit; hit = hit->next) {
451 class_count++;
452 }
453 }
454
455 uris = malloc(class_count * sizeof(char *));
456 class_count = 0;
457 for (i = 0; i < LRDF_HASH_SIZE; i++) {
458 for (hit = tmp[i]; hit; hit = hit->next) {
459 uris[class_count] = hit->str;
460 hit->str = (char *) class_count++;
461 }
462 }
463
464 pathto = calloc(class_count * class_count, sizeof(int));
465 for (it = m; it != NULL; it = it->next) {
466 /* The subclass is the matrix column */
467 int c = (int) lrdf_find_string_hash(tmp, it->shash);
468 /* And the superclass is the row */
469 int r = (int) lrdf_find_string_hash(tmp, it->ohash);
470
471 pathto[c + class_count * r] = 1;
472 }
473 lrdf_free_statements(m);
474
475 /* Warshall's algorithm
476 *
477 * $adjacent[X][Z] and $adjacent[Z][Y] => $adjacent[X][Y]
478 */
479
480 for (k = 0; k < class_count; k++) {
481 for (i = 0; i < class_count; i++) {
482 for (j = 0; j < class_count; j++) {
483 if (pathto[i + class_count * j] != 1) {
484 pathto[i + class_count * j] =
485 pathto[i + class_count * k] &&
486 pathto[k + class_count * j];
487 }
488 }
489 }
490 }
491
492 /* Clear out and free the forward and reverse tables */
493 for (i = 0; i < LRDF_HASH_SIZE; i++) {
494 lrdf_closure_hash *next;
495 lrdf_closure_hash *hit;
496
497 for (hit = fwd_tbl[i]; hit; hit = next) {
498 next = hit->next;
499 free(hit);
500 }
501 fwd_tbl[i] = NULL;
502 for (hit = rev_tbl[i]; hit; hit = next) {
503 next = hit->next;
504 free(hit);
505 }
506 rev_tbl[i] = NULL;
507 }
508
509 for (i = 0; i < class_count; i++) {
510 lrdf_hash class_h = lrdf_gen_hash(uris[i]);
511 lrdf_hash subclass_h;
512
513 /* Every class is a subclass of itsself */
514 lrdf_add_closure_hash(fwd_tbl, class_h, class_h);
515 lrdf_add_closure_hash(rev_tbl, class_h, class_h);
516
517 /* ...and rdf:Resource */
518 lrdf_add_closure_hash(fwd_tbl, rdf_resource_h, class_h);
519 lrdf_add_closure_hash(rev_tbl, class_h, rdf_resource_h);
520
521 for (j = 0; j < class_count; j++) {
522 subclass_h = lrdf_gen_hash(uris[j]);
523 if (pathto[j + class_count * i]) {
524 lrdf_add_closure_hash(fwd_tbl, class_h, subclass_h);
525 lrdf_add_closure_hash(rev_tbl, subclass_h, class_h);
526 }
527 }
528 }
529
530 for (i = 0; i < LRDF_HASH_SIZE; i++) {
531 lrdf_string_hash *next;
532 lrdf_string_hash *hit;
533
534 for (hit = tmp[i]; hit; hit = next) {
535 next = hit->next;
536 free(hit);
537 }
538 }
539
540 for (i = 0; i < class_count; i++) {
541 free(uris[i]);
542 }
543 free(uris);
544 free(pathto);
545 }
546
547 static void lrdf_log_handler(void *data, raptor_log_message *message);
548
lrdf_log_handler(void * data,raptor_log_message * message)549 static void lrdf_log_handler(void *data, raptor_log_message *message)
550 {
551 const char *severity = "error";
552 if (message->level == RAPTOR_LOG_LEVEL_WARN) {
553 severity = "warning";
554 }
555
556 fprintf(stderr, "liblrdf: %s - ", severity);
557 raptor_locator_print(message->locator, stderr);
558 fprintf(stderr, " - %s\n", message->text);
559
560 if (message->level != RAPTOR_LOG_LEVEL_WARN) {
561 raptor_parser_parse_abort((raptor_parser*)data);
562 }
563 }
564
565
lrdf_read_files(const char * uri[])566 int lrdf_read_files(const char *uri[])
567 {
568 unsigned int i;
569
570 for (i = 0; uri[i] != NULL; i++) {
571 if (lrdf_read_file_intl(uri[i]) != 0) {
572 return 1;
573 }
574 }
575 lrdf_rebuild_caches();
576
577 return 0;
578 }
579
lrdf_read_file(const char * uri)580 int lrdf_read_file(const char *uri)
581 {
582 int ret;
583
584 ret = lrdf_read_file_intl(uri);
585 lrdf_rebuild_caches();
586
587 return ret;
588 }
589
lrdf_read_file_intl(const char * uri)590 int lrdf_read_file_intl(const char *uri)
591 {
592 raptor_parser *parser = NULL;
593 raptor_uri *ruri, *furi;
594 lrdf_hash source;
595
596 //printf("lrdf: reading %s\n", uri);
597 ruri = raptor_new_uri(world, (const unsigned char *) uri);
598 furi = raptor_new_uri(world, (const unsigned char *) uri);
599 source = lrdf_gen_hash(uri);
600 lrdf_check_hash(resources_hash, source, uri);
601
602 if (strstr(uri, ".rdf")) {
603 parser = raptor_new_parser(world, "rdfxml");
604 } else {
605 parser = raptor_new_parser(world, "ntriples");
606 }
607 if (!parser) {
608 fprintf(stderr, "liblrdf: failed to create parser\n");
609 raptor_free_uri(ruri);
610 return 1;
611 }
612
613 raptor_world_set_log_handler(world, parser, lrdf_log_handler);
614 raptor_parser_set_statement_handler(parser, &source, lrdf_store);
615 raptor_world_set_generate_bnodeid_parameters(world, NULL, ++lrdf_uid);
616
617 if (raptor_parser_parse_file(parser, furi, ruri)) {
618 raptor_free_uri(furi);
619 raptor_free_uri(ruri);
620 raptor_free_parser(parser);
621 return 1;
622 }
623
624 raptor_free_uri(ruri);
625 raptor_free_parser(parser);
626
627 return 0;
628 }
629
lrdf_get_default_uri(unsigned long id)630 char *lrdf_get_default_uri(unsigned long id)
631 {
632 lrdf_statement *types;
633 lrdf_statement *it;
634 lrdf_statement type_s;
635 lrdf_statement plugin_s;
636 char *uri = NULL;
637 char plugin_uri[64];
638
639 snprintf(plugin_uri, 64, "http://ladspa.org/ontology#%ld", id);
640 type_s.subject = NULL;
641 type_s.predicate = RDF_TYPE;
642 type_s.object_type = lrdf_uri;
643 type_s.object = "http://ladspa.org/ontology#Default";
644 types = lrdf_matches(&type_s);
645 for (it = types; it != NULL; it = it->next) {
646 plugin_s.subject = plugin_uri;
647 plugin_s.predicate = LADSPA_BASE "hasSetting";
648 plugin_s.object = it->subject;
649 if (lrdf_exists_match(&plugin_s)) {
650 uri = it->subject;
651 break;
652 }
653 }
654 lrdf_free_statements(types);
655
656 return uri;
657 }
658
lrdf_get_setting_uris(unsigned long id)659 lrdf_uris *lrdf_get_setting_uris(unsigned long id)
660 {
661 lrdf_statement *settings;
662 lrdf_statement *it;
663 lrdf_statement plugin_s;
664 lrdf_uris *ret;
665 char **uris;
666 char plugin_uri[64];
667 int scnt = 0;
668
669 snprintf(plugin_uri, 64, "http://ladspa.org/ontology#%ld", id);
670 plugin_s.subject = plugin_uri;
671 plugin_s.predicate = LADSPA_BASE "hasSetting";
672 plugin_s.object = NULL;
673 settings = lrdf_matches(&plugin_s);
674 for (it = settings; it != NULL; it = it->next) {
675 scnt++;
676 }
677
678 ret = malloc(sizeof(lrdf_uris));
679 uris = (char **) calloc(scnt + 1, sizeof(char **));
680 ret->items = uris;
681
682 for (it = settings, scnt = 0; it != NULL; it = it->next) {
683 uris[scnt++] = it->object;
684 }
685 lrdf_free_statements(settings);
686 ret->count = scnt;
687
688 return ret;
689 }
690
lrdf_get_setting_values(const char * uri)691 lrdf_defaults *lrdf_get_setting_values(const char *uri)
692 {
693 lrdf_statement *portvalues;
694 lrdf_statement *it;
695 lrdf_statement *port;
696 lrdf_statement portv_s;
697 lrdf_statement port_s;
698 lrdf_defaults *ret;
699 lrdf_portvalue *list;
700 int pvcount = 0;
701 char *pos;
702 char *port_uri;
703
704 if (!uri) {
705 return NULL;
706 }
707
708 /* Find portvalues associated with setting URI */
709 portv_s.subject = (char *)uri;
710 portv_s.predicate = LADSPA_BASE "hasPortValue";
711 portv_s.object = NULL;
712 portvalues = lrdf_matches(&portv_s);
713
714 for (it = portvalues; it != NULL; it = it->next) {
715 pvcount++;
716 }
717 if (pvcount == 0) {
718 return NULL;
719 }
720
721 ret = (lrdf_defaults *) calloc(1, sizeof(lrdf_defaults));
722 list = (lrdf_portvalue *) calloc(pvcount, sizeof(lrdf_portvalue));
723 ret->count = pvcount;
724 ret->items = list;
725
726 for (it = portvalues, pvcount = 0; it != NULL;
727 it = it->next, pvcount++) {
728 /* Find setting's port */
729 port_s.subject = it->object;
730 port_s.predicate = LADSPA_BASE "forPort";
731 port_s.object = NULL;
732 port = lrdf_one_match(&port_s);
733 if (port != NULL) {
734 port_uri = port->object;
735 pos = strrchr(port_uri, '.');
736 list[pvcount].pid = atoi(pos + 1);
737
738 /* Find port's set value */
739 port_s.predicate = RDF_BASE "value";
740 port = lrdf_one_match(&port_s);
741 if (port != NULL) {
742 list[pvcount].value = atof(port->object);
743 }
744
745 /* Find port's short name */
746 port_s.subject = port_uri;
747 port_s.predicate = LADSPA_BASE "hasLabel";
748 port_s.object = NULL;
749 port = lrdf_one_match(&port_s);
750 if (port != NULL && port->object != NULL) {
751 list[pvcount].label = port->object;
752 }
753 }
754 }
755
756 return ret;
757 }
758
lrdf_get_scale_values(unsigned long id,unsigned long port)759 lrdf_defaults *lrdf_get_scale_values(unsigned long id, unsigned long port)
760 {
761 char port_uri[128];
762 lrdf_statement scale_p;
763 lrdf_statement *scale_s;
764 char *scale_uri;
765 lrdf_statement p1;
766 lrdf_uris *ulist;
767 lrdf_defaults *ret;
768 lrdf_portvalue *list;
769 int i;
770
771 snprintf(port_uri, 127, LADSPA_BASE "%ld.%ld", id, port);
772
773 /* Find Scale associated with port */
774 scale_p.subject = port_uri;
775 scale_p.predicate = LADSPA_BASE "hasScale";
776 scale_p.object = NULL;
777 scale_s = lrdf_matches(&scale_p);
778
779 if (!scale_s) {
780 return NULL;
781 }
782
783 scale_uri = scale_s->object;
784
785 p1.subject = scale_uri;
786 p1.predicate = LADSPA_BASE "hasPoint";
787 p1.object = "?";
788 p1.next = NULL;
789 ulist = lrdf_match_multi(&p1);
790 if (!ulist) {
791 return NULL;
792 }
793
794 ret = (lrdf_defaults *) calloc(1, sizeof(lrdf_defaults));
795 list = (lrdf_portvalue *) calloc(ulist->count, sizeof(lrdf_portvalue));
796 ret->count = ulist->count;
797 ret->items = list;
798
799 for (i=0; i < ulist->count; i++) {
800 list[i].pid = port;
801
802 scale_p.subject = ulist->items[i];
803 scale_p.predicate = RDF_BASE "value";
804 scale_p.object = NULL;
805 scale_s = lrdf_one_match(&scale_p);
806 list[i].value = atof(scale_s->object);
807
808 scale_p.predicate = LADSPA_BASE "hasLabel";
809 scale_s = lrdf_one_match(&scale_p);
810 list[i].label = scale_s->object;
811 }
812
813 return ret;
814 }
815
lrdf_free_setting_values(lrdf_defaults * def)816 void lrdf_free_setting_values(lrdf_defaults * def)
817 {
818 if (def) {
819 free(def->items);
820 free(def);
821 }
822 }
823
lrdf_get_setting_metadata(const char * uri,const char * element)824 char *lrdf_get_setting_metadata(const char *uri, const char *element)
825 {
826 lrdf_statement meta_s;
827 lrdf_statement *m;
828 char dc_uri[128];
829
830 snprintf(dc_uri, 128, DC_BASE "%s", element);
831 meta_s.subject = (char *)uri;
832 meta_s.predicate = dc_uri;
833 meta_s.object = NULL;
834
835 m = lrdf_one_match(&meta_s);
836 if (m) {
837 return m->object;
838 }
839
840 return NULL;
841 }
842
843 /* lrdf_free_uris:
844 *
845 * Called on the return values from lrdf_get_subclasses etc. to free up the
846 * memory allocated by them.
847 */
848
lrdf_free_uris(lrdf_uris * u)849 void lrdf_free_uris(lrdf_uris * u)
850 {
851 if (u) {
852 free(u->items);
853 free(u);
854 }
855 }
856
lrdf_uris_new(int size)857 static lrdf_uris *lrdf_uris_new(int size)
858 {
859 lrdf_uris *nu;
860
861 nu = malloc(sizeof(lrdf_uris));
862 nu->items = malloc(size * sizeof(char *));
863 nu->size = size;
864 nu->count = 0;
865
866 return nu;
867 }
868
lrdf_uris_append(lrdf_uris * base,lrdf_uris * add)869 static void lrdf_uris_append(lrdf_uris * base, lrdf_uris * add)
870 {
871 unsigned int i;
872
873 if (!add) {
874 return;
875 }
876
877 if (base->count + add->count > base->size) {
878 base->size *= 2;
879 base->items = realloc(base->items, base->size);
880 }
881 for (i = 0; i < add->count; i++) {
882 base->items[i + base->count] = add->items[i];
883 }
884 base->count += add->count;
885 }
886
887 /* lrdf_get_subclasses
888 *
889 * Returns a list of the direct subclasses of a given class
890 */
891
lrdf_get_subclasses(const char * uri)892 lrdf_uris *lrdf_get_subclasses(const char *uri)
893 {
894 lrdf_statement sc_s;
895 lrdf_statement *m;
896 lrdf_statement *it;
897 lrdf_uris *ret;
898 char **uris;
899 int count = 0;
900
901 ret = malloc(sizeof(lrdf_uris));
902 uris = malloc(256 * sizeof(char *));
903 ret->items = uris;
904
905 sc_s.subject = NULL;
906 sc_s.predicate = RDFS_BASE "subClassOf";
907 sc_s.object = (char *)uri;
908 m = lrdf_matches(&sc_s);
909 if (m == NULL) {
910 free(ret);
911 free(uris);
912
913 return NULL;
914 }
915 for (it = m; it != NULL; it = it->next) {
916 uris[count++] = it->subject;
917 }
918 lrdf_free_statements(m);
919 ret->count = count;
920
921 return ret;
922 }
923
924 /* lrdf_get_all_subclasses:
925 *
926 * Returns a list of all the subclasses of uri
927 */
lrdf_get_all_subclasses(const char * uri)928 lrdf_uris *lrdf_get_all_subclasses(const char *uri)
929 {
930 lrdf_uris *ret;
931 lrdf_closure_hash *ch;
932 lrdf_closure_hash *hit;
933 lrdf_hash class;
934 int count = 0;
935
936 ret = malloc(sizeof(lrdf_uris));
937
938 class = lrdf_gen_hash(uri);
939 ch = subclass_hash[class & (LRDF_HASH_SIZE - 1)];
940 for (hit = ch; hit; hit = hit->next) {
941 if (class == hit->subject) {
942 count++;
943 }
944 }
945 if (count == 0) {
946 return NULL;
947 }
948 ret = lrdf_uris_new(count);
949 ret->count = count;
950 count = 0;
951 for (hit = ch; hit; hit = hit->next) {
952 if (class == hit->subject) {
953 ret->items[count++] =
954 lrdf_find_string_hash(resources_hash, hit->object);
955 }
956 }
957
958 return ret;
959 }
960
961 /* lrdf_get_all_superclasses:
962 *
963 * Returns a list of all the superlasses of uri
964 */
lrdf_get_all_superclasses(const char * uri)965 lrdf_uris *lrdf_get_all_superclasses(const char *uri)
966 {
967 lrdf_uris *ret;
968 lrdf_closure_hash *ch;
969 lrdf_closure_hash *hit;
970 lrdf_hash class;
971 int count = 0;
972
973 ret = malloc(sizeof(lrdf_uris));
974
975 class = lrdf_gen_hash(uri);
976 ch = superclass_hash[class & (LRDF_HASH_SIZE - 1)];
977 for (hit = ch; hit; hit = hit->next) {
978 if (class == hit->subject) {
979 count++;
980 }
981 }
982 if (count == 0) {
983 return NULL;
984 }
985 ret = lrdf_uris_new(count);
986 ret->count = count;
987 count = 0;
988 for (hit = ch; hit; hit = hit->next) {
989 if (class == hit->subject) {
990 ret->items[count++] =
991 lrdf_find_string_hash(resources_hash, hit->object);
992 }
993 }
994
995 return ret;
996 }
997
998 /* lrdf_get_instances
999 *
1000 * Returns a list of the instances of a given class
1001 */
1002
lrdf_get_instances(const char * uri)1003 lrdf_uris *lrdf_get_instances(const char *uri)
1004 {
1005 lrdf_statement inst_s;
1006 lrdf_statement *m;
1007 lrdf_statement *it;
1008 lrdf_uris *ret;
1009 char **uris;
1010 int count = 0;
1011
1012 ret = lrdf_uris_new(256);
1013 uris = ret->items;
1014
1015 inst_s.subject = NULL;
1016 inst_s.predicate = RDF_BASE "type";
1017 inst_s.object = (char *)uri;
1018 m = lrdf_matches(&inst_s);
1019 if (m == NULL) {
1020 free(ret);
1021 free(uris);
1022
1023 return NULL;
1024 }
1025 for (it = m; it != NULL; it = it->next) {
1026 uris[count++] = it->subject;
1027 }
1028 lrdf_free_statements(m);
1029 ret->count = count;
1030
1031 return ret;
1032 }
1033
1034 /* lrdf_get_all_instances:
1035 *
1036 * Returns the URIs of all the instances of 'uri' and all the instances of all
1037 * its subclasses.
1038 */
1039
lrdf_get_all_instances(const char * uri)1040 lrdf_uris *lrdf_get_all_instances(const char *uri)
1041 {
1042 unsigned int i;
1043 lrdf_uris *u, *v;
1044 lrdf_uris *ret = NULL;
1045
1046 u = lrdf_get_all_subclasses(uri);
1047 if (u->count > 0) {
1048 ret = lrdf_uris_new(256);
1049 for (i = 0; i < u->count; i++) {
1050 v = lrdf_get_instances(u->items[i]);
1051 lrdf_uris_append(ret, v);
1052 lrdf_free_uris(v);
1053 }
1054 }
1055
1056 return ret;
1057 }
1058
lrdf_get_label(const char * uri)1059 char *lrdf_get_label(const char *uri)
1060 {
1061 lrdf_statement lab_s;
1062 lrdf_statement *label;
1063
1064 lab_s.subject = (char *)uri;
1065 lab_s.predicate = LADSPA_BASE "hasLabel";
1066 lab_s.object = NULL;
1067 label = lrdf_one_match(&lab_s);
1068
1069 if (label == NULL) {
1070 return NULL;
1071 }
1072
1073 return label->object;
1074 }
1075
1076 /* XXX nasty hack */
1077
lrdf_get_uid(const char * uri)1078 unsigned long lrdf_get_uid(const char *uri)
1079 {
1080 char *pos;
1081
1082 pos = strrchr(uri, '#');
1083 if (pos != NULL) {
1084 return atol(pos + 1);
1085 }
1086
1087 return 0;
1088 }
1089
1090 /* lrdf_matches:
1091 *
1092 * Returns a NULL terminated vector of lrdf_statements that match the
1093 * sepecifed pattern, where a NULL in any position matches any uri.
1094 */
1095
lrdf_matches(lrdf_statement * pattern)1096 lrdf_statement *lrdf_matches(lrdf_statement * pattern)
1097 {
1098 lrdf_triple_hash *th;
1099 lrdf_triple_hash *start;
1100 lrdf_statement *s;
1101 lrdf_statement *ret = NULL;
1102
1103 #ifdef DEBUG
1104 printf("Looking for (%s, %s, %s)\n", pattern->subject,
1105 pattern->predicate, pattern->object);
1106 #endif
1107
1108 if (pattern->subject) {
1109 pattern->shash = lrdf_gen_hash(pattern->subject);
1110 }
1111 if (pattern->predicate) {
1112 pattern->phash = lrdf_gen_hash(pattern->predicate);
1113 }
1114 if (pattern->object) {
1115 pattern->ohash = lrdf_gen_hash(pattern->object);
1116 }
1117
1118 if (pattern->subject) {
1119 start = subj_hash[pattern->shash & (LRDF_HASH_SIZE - 1)];
1120 } else if (pattern->predicate) {
1121 start = pred_hash[pattern->phash & (LRDF_HASH_SIZE - 1)];
1122 } else if (pattern->object) {
1123 start = obj_hash[pattern->ohash & (LRDF_HASH_SIZE - 1)];
1124 } else {
1125 /* None of the triple parts were specified, can't do anything
1126 * useful with that, except return everything and that is
1127 * stupid. If you want everything look thorugh the list */
1128 fprintf(stderr, "lrdf: null triple specified for search\n");
1129 return NULL;
1130 }
1131
1132 for (th = start; th; th = th->next) {
1133 s = th->triple;
1134
1135 if ((pattern->subject == NULL ||
1136 pattern->shash == s->shash) &&
1137 (pattern->predicate == NULL ||
1138 pattern->phash == s->phash) &&
1139 (pattern->object == NULL || pattern->ohash == s->ohash)) {
1140 lrdf_statement *new = lrdf_alloc_statement();
1141
1142 #ifdef DEBUG
1143 printf("Found (%s, %s, %s)\n", pattern->subject,
1144 pattern->predicate, pattern->object);
1145 printf(" = (%s, %s, %s)\n", s->subject, s->predicate,
1146 s->object);
1147 printf(" (%llx, %llx, %llx)\n", pattern->shash,
1148 pattern->phash, pattern->ohash);
1149 printf(" = (%llx, %llx, %llx)\n", s->shash, s->phash,
1150 s->ohash);
1151 #endif
1152 lrdf_copy_statement(s, new);
1153 new->next = ret;
1154 ret = new;
1155 }
1156 }
1157
1158 return ret;
1159 }
1160
1161 /* lrdf_one_match:
1162 *
1163 * returns a pointer to the first matching triple if one exists, or NULL
1164 * otherwise
1165 */
1166
lrdf_one_match(lrdf_statement * pattern)1167 lrdf_statement *lrdf_one_match(lrdf_statement *pattern)
1168 {
1169 lrdf_triple_hash *th;
1170 lrdf_triple_hash *start;
1171 lrdf_statement *s;
1172
1173 if (pattern->subject) {
1174 pattern->shash = lrdf_gen_hash(pattern->subject);
1175 }
1176 if (pattern->predicate) {
1177 pattern->phash = lrdf_gen_hash(pattern->predicate);
1178 }
1179 if (pattern->object) {
1180 pattern->ohash = lrdf_gen_hash(pattern->object);
1181 }
1182
1183 if (pattern->subject) {
1184 start = subj_hash[pattern->shash & (LRDF_HASH_SIZE - 1)];
1185 } else if (pattern->predicate) {
1186 start = pred_hash[pattern->phash & (LRDF_HASH_SIZE - 1)];
1187 } else if (pattern->object) {
1188 start = obj_hash[pattern->ohash & (LRDF_HASH_SIZE - 1)];
1189 } else {
1190 /* None of the triple parts were specified, can't do anything
1191 * useful with that, except return everything and that is
1192 * stupid. If you want everything look thorugh the list */
1193 fprintf(stderr, "lrdf: null triple specified for search\n");
1194 return NULL;
1195 }
1196
1197 for (th = start; th; th = th->next) {
1198 s = th->triple;
1199
1200 if ((pattern->subject == NULL ||
1201 pattern->shash == s->shash) &&
1202 (pattern->predicate == NULL ||
1203 pattern->phash == s->phash) &&
1204 (pattern->object == NULL || pattern->ohash == s->ohash)) {
1205 return s;
1206 }
1207 }
1208
1209 return NULL;
1210 }
1211
1212 /* lrdf_exists_match:
1213 *
1214 * returns true if a triple mathcing the pattern exists, false otherwise
1215 */
1216
lrdf_exists_match(lrdf_statement * pattern)1217 int lrdf_exists_match(lrdf_statement *pattern)
1218 {
1219 return (lrdf_one_match(pattern) != NULL);
1220 }
1221
1222 /* lrdf_copy_statement:
1223 *
1224 * copies the subject, predicate and object of a statement to another
1225 * statement. does not affect the linked list pointer.
1226 */
1227
lrdf_copy_statement(lrdf_statement * from,lrdf_statement * to)1228 void lrdf_copy_statement(lrdf_statement * from, lrdf_statement * to)
1229 {
1230 to->subject = from->subject;
1231 to->predicate = from->predicate;
1232 to->object = from->object;
1233 to->object_type = from->object_type;
1234 to->shash = from->shash;
1235 to->phash = from->phash;
1236 to->ohash = from->ohash;
1237 }
1238
lrdf_free_string_hash(lrdf_string_hash * h[])1239 void lrdf_free_string_hash(lrdf_string_hash * h[])
1240 {
1241 unsigned int i;
1242
1243 for (i = 0; i < LRDF_HASH_SIZE; i++) {
1244 lrdf_string_hash *next;
1245 lrdf_string_hash *hit;
1246
1247 for (hit = h[i]; hit; hit = next) {
1248 next = hit->next;
1249 free(hit->str);
1250 free(hit);
1251 }
1252 }
1253 }
1254
lrdf_free_triple_hash(lrdf_triple_hash * h[])1255 void lrdf_free_triple_hash(lrdf_triple_hash * h[])
1256 {
1257 unsigned int i;
1258
1259 for (i = 0; i < LRDF_HASH_SIZE; i++) {
1260 lrdf_triple_hash *next;
1261 lrdf_triple_hash *hit;
1262
1263 for (hit = h[i]; hit; hit = next) {
1264 next = hit->next;
1265 free(hit);
1266 }
1267 }
1268 }
1269
lrdf_free_closure_hash(lrdf_closure_hash * h[])1270 void lrdf_free_closure_hash(lrdf_closure_hash * h[])
1271 {
1272 unsigned int i;
1273
1274 for (i = 0; i < LRDF_HASH_SIZE; i++) {
1275 lrdf_closure_hash *next;
1276 lrdf_closure_hash *hit;
1277
1278 for (hit = h[i]; hit; hit = next) {
1279 next = hit->next;
1280 free(hit);
1281 }
1282 }
1283 }
1284
lrdf_all_statements()1285 lrdf_statement *lrdf_all_statements()
1286 {
1287 return triples;
1288 }
1289
lrdf_add_preset(const char * source,const char * label,unsigned long id,lrdf_defaults * vals)1290 char* lrdf_add_preset(const char *source, const char *label, unsigned long id,
1291 lrdf_defaults *vals)
1292 {
1293 char plugin_uri[64];
1294 char* setting_uri;
1295 static int sid = 0;
1296 int i;
1297 setting_uri = malloc(64 * sizeof(char));
1298
1299 snprintf(plugin_uri, 64, "http://ladspa.org/ontology#%ld", id);
1300 snprintf(setting_uri, 64, "http://plugin.org.uk/genid#%d.%d", lrdf_uid, sid++);
1301
1302 lrdf_add_triple(source, plugin_uri, LADSPA_BASE "hasSetting", setting_uri,
1303 lrdf_uri);
1304 lrdf_add_triple(source, setting_uri, RDF_BASE "type", LADSPA_BASE "Preset",
1305 lrdf_uri);
1306 lrdf_add_triple(source, setting_uri, LADSPA_BASE "hasLabel", label,
1307 lrdf_literal);
1308
1309 for (i=0; i<vals->count; i++) {
1310 char value_uri[64];
1311 char port_uri[64];
1312 char value_lit[64];
1313 snprintf(value_uri, 64, "http://plugin.org.uk/genid#%d.%d", lrdf_uid,
1314 sid++);
1315 snprintf(port_uri, 64, "%s.%ld", plugin_uri, vals->items[i].pid);
1316 snprintf(value_lit, 64, "%f", vals->items[i].value);
1317
1318 lrdf_add_triple(source, setting_uri, LADSPA_BASE "hasPortValue",
1319 value_uri, lrdf_uri);
1320 lrdf_add_triple(source, value_uri, RDF_BASE "value",
1321 value_lit, lrdf_literal);
1322 lrdf_add_triple(source, value_uri, LADSPA_BASE "forPort",
1323 port_uri, lrdf_uri);
1324 }
1325
1326 return setting_uri;
1327 }
1328
1329 /* vi:set ts=8 sts=4 sw=4: */
1330