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