From bfb5d3ad83b17c8a14211c637baf8fe321ba466b Mon Sep 17 00:00:00 2001 From: David Robillard Date: Tue, 20 Mar 2012 00:08:43 +0000 Subject: Support writing to a statement sink (particularly for writing to a model). Support writing pretty numeric literals in Turtle. git-svn-id: http://svn.drobilla.net/lad/trunk/sratom@4080 a436a847-0d15-0410-975c-d299462d15a1 --- sratom/sratom.h | 23 +++++- src/sratom.c | 204 ++++++++++++++++++++++++++++++++-------------------- tests/sratom_test.c | 4 +- 3 files changed, 147 insertions(+), 84 deletions(-) diff --git a/sratom/sratom.h b/sratom/sratom.h index b1ef071..bd4a572 100644 --- a/sratom/sratom.h +++ b/sratom/sratom.h @@ -25,6 +25,7 @@ #include "lv2/lv2plug.in/ns/ext/urid/urid.h" #include "lv2/lv2plug.in/ns/ext/atom/atom.h" +#include "lv2/lv2plug.in/ns/ext/atom/forge.h" #include "serd/serd.h" #include "sord/sord.h" @@ -74,16 +75,32 @@ SRATOM_API void sratom_free(Sratom* sratom); +/** + Set the sink(s) where sratom will write its output. + + This must be called before calling sratom_write(). If @p pretty_numbers is + true, numbers will be written as pretty Turtle literals, rather than string + literals with precise types. The cost of this is the types might get + fudged on a round-trip to RDF and back. +*/ +SRATOM_API +void +sratom_set_sink(Sratom* sratom, + const char* base_uri, + SerdStatementSink sink, + SerdEndSink end_sink, + void* handle, + bool pretty_numbers); + /** Write an Atom to RDF. - The resulting serialised atom is written to @p writer. + The serialised atom is written to the sink set by sratom_set_sink(). @return 0 on success, or a non-zero error code otherwise. */ SRATOM_API int sratom_write(Sratom* sratom, LV2_URID_Unmap* unmap, - SerdWriter* writer, uint32_t flags, const SerdNode* subject, const SerdNode* predicate, @@ -131,7 +148,7 @@ sratom_from_turtle(Sratom* sratom, const char* str); /** - A convenient resizing string sink for LV2_Atom_Forge. + A convenient resizing sink for LV2_Atom_Forge. The handle must point to an initialized SerdChunk. */ SRATOM_API diff --git a/src/sratom.c b/src/sratom.c index 7c88db0..646d462 100644 --- a/src/sratom.c +++ b/src/sratom.c @@ -36,11 +36,16 @@ typedef enum { } ReadMode; struct SratomImpl { - LV2_URID_Map* map; - LV2_Atom_Forge forge; - LV2_URID atom_Event; - LV2_URID midi_MidiEvent; - unsigned next_id; + LV2_URID_Map* map; + LV2_Atom_Forge forge; + LV2_URID atom_Event; + LV2_URID midi_MidiEvent; + unsigned next_id; + SerdNode base_uri; + SerdStatementSink write_statement; + SerdEndSink end_anon; + void* handle; + bool pretty_numbers; struct { SordNode* atom_childType; SordNode* atom_frameTime; @@ -70,6 +75,8 @@ sratom_new(LV2_URID_Map* map) sratom->midi_MidiEvent = map->map(map->handle, (const char*)NS_MIDI "MidiEvent"); sratom->next_id = 0; + sratom->base_uri = SERD_NODE_NULL; + sratom->pretty_numbers = false; memset(&sratom->nodes, 0, sizeof(sratom->nodes)); lv2_atom_forge_init(&sratom->forge, map); return sratom; @@ -82,6 +89,26 @@ sratom_free(Sratom* sratom) free(sratom); } +SRATOM_API +void +sratom_set_sink(Sratom* sratom, + const char* base_uri, + SerdStatementSink write_statement, + SerdEndSink end_anon, + void* handle, + bool pretty_numbers) +{ + if (base_uri) { + serd_node_free(&sratom->base_uri); + sratom->base_uri = serd_node_new_uri_from_string( + USTR(base_uri), NULL, NULL); + } + sratom->write_statement = write_statement; + sratom->end_anon = end_anon; + sratom->handle = handle; + sratom->pretty_numbers = pretty_numbers; +} + static void gensym(SerdNode* out, char c, unsigned num) { @@ -90,25 +117,25 @@ gensym(SerdNode* out, char c, unsigned num) } static void -list_append(Sratom* sratom, - LV2_URID_Unmap* unmap, - SerdWriter* writer, - unsigned* flags, - SerdNode* s, - SerdNode* p, - SerdNode* node, - uint32_t size, - uint32_t type, - void* body) +list_append(Sratom* sratom, + LV2_URID_Unmap* unmap, + unsigned* flags, + SerdNode* s, + SerdNode* p, + SerdNode* node, + uint32_t size, + uint32_t type, + void* body) { // Generate a list node gensym(node, 'l', sratom->next_id); - serd_writer_write_statement(writer, *flags, NULL, s, p, node, NULL, NULL); + sratom->write_statement(sratom->handle, *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, unmap, writer, SERD_LIST_CONT, node, p, type, size, body); + sratom_write(sratom, unmap, *flags, node, p, type, size, body); // Set subject to node and predicate to rdf:rest for next time gensym(node, 'l', ++sratom->next_id); @@ -117,31 +144,32 @@ list_append(Sratom* sratom, } static void -list_end(SerdWriter* writer, unsigned* flags, SerdNode* s, SerdNode* p) +list_end(SerdStatementSink sink, + void* handle, + unsigned* flags, + SerdNode* s, + SerdNode* p) { // _:node rdf:rest rdf:nil const SerdNode nil = serd_node_from_string(SERD_URI, NS_RDF "nil"); - serd_writer_write_statement(writer, *flags, NULL, - s, p, &nil, NULL, NULL); + sink(handle, *flags, NULL, s, p, &nil, NULL, NULL); } static void -start_object(Sratom* sratom, - SerdWriter* writer, - uint32_t flags, - const SerdNode* subject, - const SerdNode* predicate, - const SerdNode* node, - const char* type) +start_object(Sratom* sratom, + uint32_t flags, + const SerdNode* subject, + const SerdNode* predicate, + const SerdNode* node, + const char* type) { - serd_writer_write_statement(writer, flags|SERD_ANON_O_BEGIN, NULL, - subject, predicate, node, NULL, NULL); + sratom->write_statement(sratom->handle, 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( - writer, SERD_ANON_CONT, NULL, - node, &p, &o, NULL, NULL); + sratom->write_statement(sratom->handle, SERD_ANON_CONT, NULL, + node, &p, &o, NULL, NULL); } } @@ -157,7 +185,6 @@ SRATOM_API int sratom_write(Sratom* sratom, LV2_URID_Unmap* unmap, - SerdWriter* writer, uint32_t flags, const SerdNode* subject, const SerdNode* predicate, @@ -206,15 +233,17 @@ sratom_write(Sratom* sratom, new_node = true; object = serd_node_new_file_uri(str, NULL, NULL, false); } else { - SerdEnv* env = serd_writer_get_env(writer); - SerdURI base_uri = SERD_URI_NULL; - const SerdNode* base = serd_env_get_base_uri(env, &base_uri); - if (strncmp((const char*)base->buf, "file://", 7)) { + SerdURI base_uri = SERD_URI_NULL; + if (!sratom->base_uri.buf || + strncmp((const char*)sratom->base_uri.buf, "file://", 7)) { fprintf(stderr, "warning: Relative path but base is not a file URI.\n"); fprintf(stderr, "warning: Writing ambiguous atom:Path literal.\n"); object = serd_node_from_string(SERD_LITERAL, str); datatype = serd_node_from_string(SERD_URI, USTR(LV2_ATOM__Path)); } else { + if (sratom->base_uri.buf) { + serd_uri_parse(sratom->base_uri.buf, &base_uri); + } new_node = true; SerdNode rel = serd_node_new_file_uri(str, NULL, NULL, false); object = serd_node_new_uri_from_node(&rel, &base_uri, NULL); @@ -227,19 +256,23 @@ sratom_write(Sratom* sratom, } else if (type_urid == sratom->forge.Int) { new_node = true; object = serd_node_new_integer(*(int32_t*)body); - datatype = serd_node_from_string(SERD_URI, NS_XSD "int"); + datatype = serd_node_from_string(SERD_URI, (sratom->pretty_numbers) + ? NS_XSD "integer" : NS_XSD "int"); } else if (type_urid == sratom->forge.Long) { new_node = true; object = serd_node_new_integer(*(int64_t*)body); - datatype = serd_node_from_string(SERD_URI, NS_XSD "long"); + datatype = serd_node_from_string(SERD_URI, (sratom->pretty_numbers) + ? NS_XSD "integer" : NS_XSD "long"); } else if (type_urid == sratom->forge.Float) { new_node = true; object = serd_node_new_decimal(*(float*)body, 8); - datatype = serd_node_from_string(SERD_URI, NS_XSD "float"); + datatype = serd_node_from_string(SERD_URI, (sratom->pretty_numbers) + ? NS_XSD "decimal" : NS_XSD "float"); } else if (type_urid == sratom->forge.Double) { new_node = true; object = serd_node_new_decimal(*(double*)body, 16); - datatype = serd_node_from_string(SERD_URI, NS_XSD "double"); + datatype = serd_node_from_string(SERD_URI, (sratom->pretty_numbers) + ? NS_XSD "decimal" : NS_XSD "double"); } else if (type_urid == sratom->forge.Bool) { const int32_t val = *(const int32_t*)body; datatype = serd_node_from_string(SERD_URI, NS_XSD "boolean"); @@ -257,99 +290,105 @@ sratom_write(Sratom* sratom, } 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, writer, flags, subject, predicate, &id, NULL); + start_object(sratom, flags, subject, predicate, &id, NULL); // TODO: beat time 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(writer, SERD_ANON_CONT, NULL, - &id, &p, &time, - &datatype, &language); + sratom->write_statement(sratom->handle, 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, unmap, writer, SERD_ANON_CONT, &id, &p, - ev->body.type, ev->body.size, - LV2_ATOM_BODY(&ev->body)); - serd_writer_end_anon(writer, &id); + sratom_write(sratom, unmap, SERD_ANON_CONT, &id, &p, + ev->body.type, ev->body.size, LV2_ATOM_BODY(&ev->body)); + if (sratom->end_anon) { + sratom->end_anon(sratom->handle, &id); + } } else if (type_urid == sratom->forge.Tuple) { gensym(&id, 't', sratom->next_id++); - start_object(sratom, writer, flags, subject, predicate, &id, type); + start_object(sratom, 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, unmap, writer, &flags, &id, &p, &node, + list_append(sratom, unmap, &flags, &id, &p, &node, i->size, i->type, LV2_ATOM_BODY(i)); } - list_end(writer, &flags, &id, &p); - serd_writer_end_anon(writer, &id); + list_end(sratom->write_statement, sratom->handle, &flags, &id, &p); + if (sratom->end_anon) { + sratom->end_anon(sratom->handle, &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, writer, flags, subject, predicate, &id, type); + start_object(sratom, flags, subject, predicate, &id, type); SerdNode p = serd_node_from_string(SERD_URI, (const uint8_t*)LV2_ATOM__childType); SerdNode child_type = serd_node_from_string( SERD_URI, (const uint8_t*)unmap->unmap(unmap->handle, vec->child_type)); - serd_writer_write_statement( - writer, flags, NULL, &id, &p, &child_type, NULL, NULL); + sratom->write_statement(sratom->handle, flags, NULL, &id, &p, &child_type, NULL, NULL); p = serd_node_from_string(SERD_URI, NS_RDF "value"); flags |= SERD_LIST_O_BEGIN; for (char* i = (char*)(vec + 1); i < (char*)vec + size; i += vec->child_size) { - list_append(sratom, unmap, writer, &flags, &id, &p, &node, + list_append(sratom, unmap, &flags, &id, &p, &node, vec->child_size, vec->child_type, i); } - list_end(writer, &flags, &id, &p); - serd_writer_end_anon(writer, &id); + list_end(sratom->write_statement, sratom->handle, &flags, &id, &p); + if (sratom->end_anon) { + sratom->end_anon(sratom->handle, &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); gensym(&id, 'b', sratom->next_id++); - start_object(sratom, writer, flags, subject, predicate, &id, otype); + start_object(sratom, 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, unmap, writer, - flags|SERD_ANON_CONT, &id, &pred, + sratom_write(sratom, unmap, flags|SERD_ANON_CONT, &id, &pred, prop->value.type, prop->value.size, LV2_ATOM_BODY(&prop->value)); } - serd_writer_end_anon(writer, &id); + if (sratom->end_anon) { + sratom->end_anon(sratom->handle, &id); + } } else if (type_urid == sratom->forge.Sequence) { const LV2_Atom_Sequence_Body* seq = (const LV2_Atom_Sequence_Body*)body; gensym(&id, 'v', sratom->next_id++); - start_object(sratom, writer, flags, subject, predicate, &id, type); + start_object(sratom, 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, unmap, writer, &flags, &id, &p, &node, + list_append(sratom, unmap, &flags, &id, &p, &node, sizeof(LV2_Atom_Event) + ev->body.size, sratom->atom_Event, ev); } - list_end(writer, &flags, &id, &p); - serd_writer_end_anon(writer, &id); + list_end(sratom->write_statement, sratom->handle, &flags, &id, &p); + if (sratom->end_anon) { + sratom->end_anon(sratom->handle, &id); + } } else { gensym(&id, 'b', sratom->next_id++); - start_object(sratom, writer, flags, subject, predicate, &id, type); + start_object(sratom, flags, subject, predicate, &id, type); SerdNode p = serd_node_from_string(SERD_URI, NS_RDF "value"); SerdNode o = serd_node_new_blob(body, size, true); datatype = serd_node_from_string(SERD_URI, NS_XSD "base64Binary"); - serd_writer_write_statement(writer, flags, NULL, - &id, &p, &o, &datatype, NULL); - serd_writer_end_anon(writer, &id); + sratom->write_statement(sratom->handle, flags, NULL, &id, &p, &o, &datatype, NULL); + if (sratom->end_anon) { + sratom->end_anon(sratom->handle, &id); + } serd_node_free(&o); } if (object.buf) { - serd_writer_write_statement(writer, flags, NULL, - subject, predicate, &object, - &datatype, &language); + sratom->write_statement(sratom->handle, flags, NULL, + subject, predicate, &object, &datatype, &language); } if (new_node) { @@ -393,7 +432,12 @@ sratom_to_turtle(Sratom* sratom, (SerdPrefixSink)serd_writer_set_prefix, writer); - sratom_write(sratom, unmap, writer, SERD_EMPTY_S, + sratom_set_sink(sratom, base_uri, + (SerdStatementSink)serd_writer_write_statement, + (SerdEndSink)serd_writer_end_anon, + writer, + false); + sratom_write(sratom, unmap, SERD_EMPTY_S, subject, predicate, type, size, body); serd_writer_finish(writer); @@ -472,11 +516,13 @@ read_node(Sratom* sratom, 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)); + if (!strcmp(type_uri, (char*)NS_XSD "int") || + !strcmp(type_uri, (char*)NS_XSD "integer")) { + lv2_atom_forge_int(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_long(forge, strtol(str, &endptr, 10)); + } else if (!strcmp(type_uri, (char*)NS_XSD "float") || + !strcmp(type_uri, (char*)NS_XSD "decimal")) { lv2_atom_forge_float(forge, serd_strtod(str, &endptr)); } else if (!strcmp(type_uri, (char*)NS_XSD "double")) { lv2_atom_forge_double(forge, serd_strtod(str, &endptr)); diff --git a/tests/sratom_test.c b/tests/sratom_test.c index b13def9..e8745fa 100644 --- a/tests/sratom_test.c +++ b/tests/sratom_test.c @@ -112,11 +112,11 @@ main() // eg_one = (Int32)1 lv2_atom_forge_property_head(&forge, eg_one, 0); - lv2_atom_forge_int32(&forge, 1); + lv2_atom_forge_int(&forge, 1); // eg_two = (Int64)2 lv2_atom_forge_property_head(&forge, eg_two, 0); - lv2_atom_forge_int64(&forge, 2); + lv2_atom_forge_long(&forge, 2); // eg_three = (Float)3.0 lv2_atom_forge_property_head(&forge, eg_three, 0); -- cgit v1.2.1