summaryrefslogtreecommitdiffstats
path: root/src/sratom.c
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2012-03-01 06:39:57 +0000
committerDavid Robillard <d@drobilla.net>2012-03-01 06:39:57 +0000
commit6408ee7d93ed041a053627e3506c444e215654d4 (patch)
treeda8888efd3d243018e9d56e09a60ef0aecfb5c01 /src/sratom.c
parent6e4c4ee8a1fccebedf48b750151a258a559fc50b (diff)
downloadsratom-6408ee7d93ed041a053627e3506c444e215654d4.tar.gz
sratom-6408ee7d93ed041a053627e3506c444e215654d4.tar.bz2
sratom-6408ee7d93ed041a053627e3506c444e215654d4.zip
Implement Turtle reading (except for atom:Vector).
git-svn-id: http://svn.drobilla.net/lad/trunk/sratom@4006 a436a847-0d15-0410-975c-d299462d15a1
Diffstat (limited to 'src/sratom.c')
-rw-r--r--src/sratom.c348
1 files changed, 297 insertions, 51 deletions
diff --git a/src/sratom.c b/src/sratom.c
index f919f89..b38b304 100644
--- a/src/sratom.c
+++ b/src/sratom.c
@@ -23,34 +23,56 @@
#include "sratom/sratom.h"
+#define NS_ATOM (const uint8_t*)"http://lv2plug.in/ns/ext/atom#"
+#define NS_MIDI (const uint8_t*)"http://lv2plug.in/ns/ext/midi#"
#define NS_RDF (const uint8_t*)"http://www.w3.org/1999/02/22-rdf-syntax-ns#"
#define NS_XSD (const uint8_t*)"http://www.w3.org/2001/XMLSchema#"
-#define NS_MIDI (const uint8_t*)"http://lv2plug.in/ns/ext/midi#"
#define USTR(str) ((const uint8_t*)(str))
+typedef enum {
+ MODE_NORMAL,
+ MODE_SEQUENCE,
+} ReadMode;
+
struct SratomImpl {
- SerdWriter* writer;
LV2_URID_Map* map;
LV2_URID_Unmap* unmap;
LV2_Atom_Forge forge;
LV2_URID atom_Event;
LV2_URID midi_MidiEvent;
unsigned next_id;
+ struct {
+ SordNode* atom_frameTime;
+ SordNode* rdf_first;
+ SordNode* rdf_rest;
+ SordNode* rdf_type;
+ SordNode* rdf_value;
+ } nodes;
};
+static void
+sratom_read_internal(Sratom* sratom,
+ LV2_Atom_Forge* forge,
+ SordWorld* world,
+ SordModel* model,
+ const SordNode* node,
+ ReadMode mode);
+
SRATOM_API
Sratom*
sratom_new(LV2_URID_Map* map,
LV2_URID_Unmap* unmap)
{
Sratom* sratom = (Sratom*)malloc(sizeof(Sratom));
- sratom->writer = NULL;
sratom->map = map;
sratom->unmap = unmap;
- sratom->atom_Event = map->map(map->handle, LV2_ATOM_URI "#Event");
- sratom->midi_MidiEvent = map->map(map->handle, (const char*)NS_MIDI "MidiEvent");
+ sratom->atom_Event = map->map(map->handle,
+ (const char*)NS_ATOM "#Event");
+ sratom->midi_MidiEvent = map->map(map->handle,
+ (const char*)NS_MIDI "MidiEvent");
sratom->next_id = 0;
+ memset(&sratom->nodes, 0, sizeof(sratom->nodes));
lv2_atom_forge_init(&sratom->forge, map);
return sratom;
}
@@ -85,24 +107,24 @@ gensym(SerdNode* out, char c, unsigned num)
}
static void
-list_append(Sratom* sratom,
- unsigned* flags,
- SerdNode* s,
- SerdNode* p,
- SerdNode* node,
- uint32_t type,
- uint32_t size,
- void* body)
+list_append(Sratom* sratom,
+ SerdWriter* writer,
+ unsigned* flags,
+ SerdNode* s,
+ SerdNode* p,
+ SerdNode* node,
+ uint32_t type,
+ uint32_t size,
+ void* body)
{
// Generate a list node
gensym(node, 'l', sratom->next_id);
- serd_writer_write_statement(sratom->writer, *flags, NULL,
- s, p, node, NULL, NULL);
+ serd_writer_write_statement(writer, *flags, NULL, s, p, node, NULL, NULL);
// _:node rdf:first value
*flags = SERD_LIST_CONT;
*p = serd_node_from_string(SERD_URI, NS_RDF "first");
- sratom_write(sratom, SERD_LIST_CONT, node, p, type, size, body);
+ sratom_write(sratom, writer, SERD_LIST_CONT, node, p, type, size, body);
// Set subject to node and predicate to rdf:rest for next time
gensym(node, 'l', ++sratom->next_id);
@@ -121,6 +143,7 @@ list_end(SerdWriter* writer, unsigned* flags, SerdNode* s, SerdNode* p)
static void
start_object(Sratom* sratom,
+ SerdWriter* writer,
uint32_t flags,
const SerdNode* subject,
const SerdNode* predicate,
@@ -128,13 +151,13 @@ start_object(Sratom* sratom,
const char* type)
{
serd_writer_write_statement(
- sratom->writer, flags|SERD_ANON_O_BEGIN, NULL,
+ writer, flags|SERD_ANON_O_BEGIN, NULL,
subject, predicate, node, NULL, NULL);
if (type) {
SerdNode p = serd_node_from_string(SERD_URI, NS_RDF "type");
SerdNode o = serd_node_from_string(SERD_URI, USTR(type));
serd_writer_write_statement(
- sratom->writer, SERD_ANON_CONT, NULL,
+ writer, SERD_ANON_CONT, NULL,
node, &p, &o, NULL, NULL);
}
}
@@ -142,6 +165,7 @@ start_object(Sratom* sratom,
SRATOM_API
void
sratom_write(Sratom* sratom,
+ SerdWriter* writer,
uint32_t flags,
const SerdNode* subject,
const SerdNode* predicate,
@@ -187,7 +211,7 @@ sratom_write(Sratom* sratom,
object = serd_node_from_string(SERD_URI, str);
} else if (type_urid == sratom->forge.Path) {
const uint8_t* str = USTR(body);
- object = serd_node_from_string(SERD_LITERAL, str);
+ object = serd_node_from_string(SERD_LITERAL, str);
datatype = serd_node_from_string(SERD_URI, USTR(LV2_ATOM__Path));
} else if (type_urid == sratom->forge.URI) {
const uint8_t* str = USTR(body);
@@ -216,45 +240,46 @@ sratom_write(Sratom* sratom,
} else if (type_urid == sratom->midi_MidiEvent) {
new_node = true;
datatype = serd_node_from_string(SERD_URI, NS_MIDI "MidiEvent");
- uint8_t* str = calloc(size * 2, 1);
+ uint8_t* str = calloc(size * 2 + 1, 1);
for (uint32_t i = 0; i < size; ++i) {
- sprintf((char*)str + (2 * i), "%02X",
- (unsigned)(uint8_t)*((uint8_t*)body + i));
+ snprintf((char*)str + (2 * i), size * 2 + 1, "%02X",
+ (unsigned)(uint8_t)*((uint8_t*)body + i));
}
object = serd_node_from_string(SERD_LITERAL, USTR(str));
} else if (type_urid == sratom->atom_Event) {
const LV2_Atom_Event* ev = (const LV2_Atom_Event*)body;
gensym(&id, 'e', sratom->next_id++);
- start_object(sratom, flags, subject, predicate, &id, NULL);
+ start_object(sratom, writer, flags, subject, predicate, &id, NULL);
// TODO: beat time
- SerdNode p = serd_node_from_string(SERD_URI, USTR(LV2_ATOM__frameTime));
SerdNode time = serd_node_new_integer(ev->time.frames);
+ SerdNode p = serd_node_from_string(SERD_URI,
+ USTR(LV2_ATOM__frameTime));
datatype = serd_node_from_string(SERD_URI, NS_XSD "decimal");
- serd_writer_write_statement(sratom->writer, SERD_ANON_CONT, NULL,
+ serd_writer_write_statement(writer, SERD_ANON_CONT, NULL,
&id, &p, &time,
&datatype, &language);
serd_node_free(&time);
-
+
p = serd_node_from_string(SERD_URI, NS_RDF "value");
- sratom_write(sratom, SERD_ANON_CONT, &id, &p,
+ sratom_write(sratom, writer, SERD_ANON_CONT, &id, &p,
ev->body.type, ev->body.size,
LV2_ATOM_BODY(&ev->body));
- serd_writer_end_anon(sratom->writer, &id);
+ serd_writer_end_anon(writer, &id);
} else if (type_urid == sratom->forge.Tuple) {
gensym(&id, 't', sratom->next_id++);
- start_object(sratom, flags, subject, predicate, &id, type);
+ start_object(sratom, writer, flags, subject, predicate, &id, type);
SerdNode p = serd_node_from_string(SERD_URI, NS_RDF "value");
flags |= SERD_LIST_O_BEGIN;
LV2_TUPLE_BODY_FOREACH(body, size, i) {
- list_append(sratom, &flags, &id, &p, &node,
+ list_append(sratom, writer, &flags, &id, &p, &node,
i->type, i->size, LV2_ATOM_BODY(i));
}
- list_end(sratom->writer, &flags, &id, &p);
- serd_writer_end_anon(sratom->writer, &id);
+ list_end(writer, &flags, &id, &p);
+ serd_writer_end_anon(writer, &id);
} else if (type_urid == sratom->forge.Vector) {
const LV2_Atom_Vector_Body* vec = (const LV2_Atom_Vector_Body*)body;
gensym(&id, 'v', sratom->next_id++);
- start_object(sratom, flags, subject, predicate, &id, type);
+ start_object(sratom, writer, flags, subject, predicate, &id, type);
SerdNode p = serd_node_from_string(SERD_URI, NS_RDF "value");
const uint32_t content_size = size - sizeof(LV2_Atom_Vector_Body);
const uint32_t elem_size = content_size / vec->elem_count;
@@ -262,46 +287,47 @@ sratom_write(Sratom* sratom,
for (char* i = (char*)(vec + 1);
i < (char*)vec + size;
i += elem_size) {
- list_append(sratom, &flags, &id, &p, &node,
+ list_append(sratom, writer, &flags, &id, &p, &node,
vec->elem_type, elem_size, i);
}
- list_end(sratom->writer, &flags, &id, &p);
- serd_writer_end_anon(sratom->writer, &id);
+ list_end(writer, &flags, &id, &p);
+ serd_writer_end_anon(writer, &id);
} else if (type_urid == sratom->forge.Blank) {
const LV2_Atom_Object_Body* obj = (const LV2_Atom_Object_Body*)body;
- const char* otype = unmap->unmap(unmap->handle, obj->otype);
+ const char* otype = unmap->unmap(unmap->handle,
+ obj->otype);
gensym(&id, 'b', sratom->next_id++);
- start_object(sratom, flags, subject, predicate, &id, otype);
+ start_object(sratom, writer, flags, subject, predicate, &id, otype);
LV2_OBJECT_BODY_FOREACH(obj, size, i) {
const LV2_Atom_Property_Body* prop = lv2_object_iter_get(i);
const char* const key = unmap->unmap(unmap->handle, prop->key);
SerdNode pred = serd_node_from_string(SERD_URI, USTR(key));
- sratom_write(sratom, flags|SERD_ANON_CONT, &id, &pred,
+ sratom_write(sratom, writer, flags|SERD_ANON_CONT, &id, &pred,
prop->value.type, prop->value.size,
LV2_ATOM_BODY(&prop->value));
}
- serd_writer_end_anon(sratom->writer, &id);
+ serd_writer_end_anon(writer, &id);
} else if (type_urid == sratom->forge.Sequence) {
- const LV2_Atom_Sequence_Body* seq = (const LV2_Atom_Sequence_Body*)body;
+ const LV2_Atom_Sequence_Body* seq = (const LV2_Atom_Sequence_Body*)body;
gensym(&id, 'v', sratom->next_id++);
- start_object(sratom, flags, subject, predicate, &id, type);
+ start_object(sratom, writer, flags, subject, predicate, &id, type);
SerdNode p = serd_node_from_string(SERD_URI, NS_RDF "value");
flags |= SERD_LIST_O_BEGIN;
LV2_SEQUENCE_BODY_FOREACH(seq, size, i) {
LV2_Atom_Event* ev = lv2_sequence_iter_get(i);
- list_append(sratom, &flags, &id, &p, &node,
+ list_append(sratom, writer, &flags, &id, &p, &node,
sratom->atom_Event,
sizeof(LV2_Atom_Event) + ev->body.size,
ev);
}
- list_end(sratom->writer, &flags, &id, &p);
- serd_writer_end_anon(sratom->writer, &id);
+ list_end(writer, &flags, &id, &p);
+ serd_writer_end_anon(writer, &id);
} else {
object = serd_node_from_string(SERD_LITERAL, USTR("(unknown)"));
}
if (object.buf) {
- serd_writer_write_statement(sratom->writer, flags, NULL,
+ serd_writer_write_statement(writer, flags, NULL,
subject, predicate, &object,
&datatype, &language);
}
@@ -332,17 +358,237 @@ sratom_to_turtle(Sratom* sratom,
serd_env_set_prefix_from_strings(env, USTR("eg"),
USTR("http://example.org/"));
- sratom->writer = serd_writer_new(
+ SerdWriter* writer = serd_writer_new(
SERD_TURTLE,
SERD_STYLE_ABBREVIATED|SERD_STYLE_RESOLVED|SERD_STYLE_CURIED,
env, &base_uri, string_sink, &str);
- sratom_write(sratom, SERD_EMPTY_S, subject, predicate, type, size, body);
- serd_writer_finish(sratom->writer);
+ // Write @prefix directives
+ serd_env_foreach(env,
+ (SerdPrefixSink)serd_writer_set_prefix,
+ writer);
+
+ sratom_write(sratom, writer, SERD_EMPTY_S,
+ subject, predicate, type, size, body);
+ serd_writer_finish(writer);
string_sink("", 1, &str);
- serd_writer_free(sratom->writer);
+ serd_writer_free(writer);
serd_env_free(env);
- free(str.buf);
return str.buf;
}
+
+static const SordNode*
+get_object(SordModel* model,
+ const SordNode* subject,
+ const SordNode* predicate)
+{
+ const SordNode* object = NULL;
+ SordQuad q = { subject, predicate, 0, 0 };
+ SordIter* i = sord_find(model, q);
+ if (!sord_iter_end(i)) {
+ SordQuad quad;
+ sord_iter_get(i, quad);
+ object = quad[SORD_OBJECT];
+ }
+ sord_iter_free(i);
+ return object;
+}
+
+static void
+read_list_value(Sratom* sratom,
+ LV2_Atom_Forge* forge,
+ SordWorld* world,
+ SordModel* model,
+ const SordNode* node,
+ ReadMode mode)
+{
+ const SordNode* first = get_object(model, node, sratom->nodes.rdf_first);
+ const SordNode* rest = get_object(model, node, sratom->nodes.rdf_rest);
+ if (first && rest) {
+ sratom_read_internal(sratom, forge, world, model, first, mode);
+ read_list_value(sratom, forge, world, model, rest, mode);
+ }
+}
+
+static void
+sratom_read_internal(Sratom* sratom,
+ LV2_Atom_Forge* forge,
+ SordWorld* world,
+ SordModel* model,
+ const SordNode* node,
+ ReadMode mode)
+{
+ const char* str = (const char*)sord_node_get_string(node);
+ if (sord_node_get_type(node) == SORD_LITERAL) {
+ char* endptr;
+ SordNode* datatype = sord_node_get_datatype(node);
+ const char* language = sord_node_get_language(node);
+ if (datatype) {
+ const char* type_uri = (const char*)sord_node_get_string(datatype);
+ if (!strcmp(type_uri, (char*)NS_XSD "int")) {
+ lv2_atom_forge_int32(forge, strtol(str, &endptr, 10));
+ } else if (!strcmp(type_uri, (char*)NS_XSD "long")) {
+ lv2_atom_forge_int64(forge, strtol(str, &endptr, 10));
+ } else if (!strcmp(type_uri, (char*)NS_XSD "float")) {
+ lv2_atom_forge_float(forge, serd_strtod(str, &endptr));
+ } else if (!strcmp(type_uri, (char*)NS_XSD "double")) {
+ lv2_atom_forge_float(forge, serd_strtod(str, &endptr));
+ } else if (!strcmp(type_uri, (char*)NS_XSD "boolean")) {
+ lv2_atom_forge_bool(forge, !strcmp(str, "true"));
+ } else {
+ lv2_atom_forge_literal(
+ forge, (const uint8_t*)str, strlen(str),
+ sratom->map->map(sratom->map->handle, type_uri),
+ 0);
+ }
+ } else if (language) {
+ const char* prefix = "http://lexvo.org/id/iso639-3/";
+ const size_t lang_len = strlen(prefix) + strlen(language);
+ char* lang_uri = calloc(lang_len + 1, 1);
+ snprintf(lang_uri, lang_len + 1, "%s%s", prefix, language);
+ lv2_atom_forge_literal(
+ forge, (const uint8_t*)str, strlen(str), 0,
+ sratom->map->map(sratom->map->handle, lang_uri));
+ free(lang_uri);
+ } else {
+ lv2_atom_forge_string(forge, (const uint8_t*)str, strlen(str));
+ }
+ } else if (sord_node_get_type(node) == SORD_URI) {
+ lv2_atom_forge_uri(forge, (const uint8_t*)str, strlen(str));
+ } else {
+ LV2_URID_Map* map = sratom->map;
+ const SordNode* type = get_object(model, node, sratom->nodes.rdf_type);
+
+ const uint8_t* type_uri = NULL;
+ uint32_t type_urid = 0;
+ if (type) {
+ type_uri = sord_node_get_string(type);
+ type_urid = map->map(map->handle, (const char*)type_uri);
+ }
+
+ LV2_Atom_Forge_Frame frame = { 0, 0 };
+ if (mode == MODE_SEQUENCE) {
+ const SordNode* frame_time = get_object(
+ model, node, sratom->nodes.atom_frameTime);
+ const SordNode* value = get_object(
+ model, node, sratom->nodes.rdf_value);
+ const char* frame_time_str = frame_time
+ ? (const char*)sord_node_get_string(frame_time)
+ : "";
+ lv2_atom_forge_frame_time(forge, serd_strtod(frame_time_str, NULL));
+ sratom_read_internal(sratom, forge, world, model, value, MODE_NORMAL);
+ } else if (type_urid == sratom->forge.Tuple) {
+ lv2_atom_forge_tuple(forge, &frame);
+ const SordNode* value = get_object(
+ model, node, sratom->nodes.rdf_value);
+ read_list_value(sratom, forge, world, model, value, MODE_NORMAL);
+ } else if (type_urid == sratom->forge.Sequence) {
+ lv2_atom_forge_sequence_head(forge, &frame, 0);
+ const SordNode* value = get_object(
+ model, node, sratom->nodes.rdf_value);
+ read_list_value(sratom, forge, world, model, value, MODE_SEQUENCE);
+ } else {
+ lv2_atom_forge_blank(forge, &frame, 1, type_urid);
+
+ SordQuad q = { node, 0, 0, 0 };
+ for (SordIter* i = sord_find(model, q);
+ !sord_iter_end(i);
+ sord_iter_next(i)) {
+ SordQuad quad;
+ sord_iter_get(i, quad);
+ const SordNode* key = quad[SORD_PREDICATE];
+ lv2_atom_forge_property_head(
+ forge,
+ map->map(map->handle, (const char*)sord_node_get_string(key)),
+ 0);
+ sratom_read_internal(sratom, forge, world, model, quad[SORD_OBJECT], MODE_NORMAL);
+ }
+ }
+ if (frame.ref) {
+ lv2_atom_forge_pop(forge, &frame);
+ }
+ }
+}
+
+SRATOM_API
+void
+sratom_read(Sratom* sratom,
+ LV2_Atom_Forge* forge,
+ SordWorld* world,
+ SordModel* model,
+ const SordNode* node)
+{
+ sratom->nodes.atom_frameTime = sord_new_uri(world, NS_ATOM "frameTime");
+ sratom->nodes.rdf_first = sord_new_uri(world, NS_RDF "first");
+ sratom->nodes.rdf_rest = sord_new_uri(world, NS_RDF "rest");
+ sratom->nodes.rdf_type = sord_new_uri(world, NS_RDF "type");
+ sratom->nodes.rdf_value = sord_new_uri(world, NS_RDF "value");
+
+ sratom_read_internal(sratom, forge, world, model, node, MODE_NORMAL);
+
+ sord_node_free(world, sratom->nodes.rdf_value);
+ sord_node_free(world, sratom->nodes.rdf_type);
+ sord_node_free(world, sratom->nodes.rdf_rest);
+ sord_node_free(world, sratom->nodes.rdf_first);
+ sord_node_free(world, sratom->nodes.atom_frameTime);
+ memset(&sratom->nodes, 0, sizeof(sratom->nodes));
+}
+
+static LV2_Atom_Forge_Ref
+forge_sink(LV2_Atom_Forge_Sink_Handle handle,
+ const void* buf,
+ uint32_t size)
+{
+ String* string = (String*)handle;
+ const LV2_Atom_Forge_Ref ref = string->len;
+ string_sink(buf, size, string);
+ return ref;
+}
+
+static void*
+forge_deref(LV2_Atom_Forge_Sink_Handle handle, LV2_Atom_Forge_Ref ref)
+{
+ String* string = (String*)handle;
+ return string->buf + ref;
+}
+
+SRATOM_API
+LV2_Atom*
+sratom_from_turtle(Sratom* sratom,
+ const SerdNode* subject,
+ const SerdNode* predicate,
+ const char* str)
+{
+ String out = { NULL, 0 };
+
+ SerdNode base_uri_node = SERD_NODE_NULL;
+ SordWorld* world = sord_world_new();
+ SordModel* model = sord_new(world, SORD_SPO, false);
+ SerdEnv* env = serd_env_new(&base_uri_node);
+ SerdReader* reader = sord_new_reader(model, env, SERD_TURTLE, NULL);
+
+ if (!serd_reader_read_string(reader, (const uint8_t*)str)) {
+ SordNode* s = sord_node_from_serd_node(world, env, subject, 0, 0);
+ SordNode* p = sord_node_from_serd_node(world, env, predicate, 0, 0);
+ SordQuad q = { s, p, 0, 0 };
+ SordIter* i = sord_find(model, q);
+ if (!sord_iter_end(i)) {
+ SordQuad result;
+ sord_iter_get(i, result);
+ lv2_atom_forge_set_sink(&sratom->forge, forge_sink, forge_deref, &out);
+ sratom_read(sratom, &sratom->forge, world, model, result[SORD_OBJECT]);
+ } else {
+ fprintf(stderr, "Failed to find node\n");
+ }
+ } else {
+ fprintf(stderr, "Failed to read Turtle\n");
+ }
+
+ serd_reader_free(reader);
+ serd_env_free(env);
+ sord_free(model);
+ sord_world_free(world);
+
+ return (LV2_Atom*)out.buf;
+}