diff options
-rw-r--r-- | .clang-tidy | 1 | ||||
-rw-r--r-- | bindings/cpp/include/sratom/sratom.hpp | 44 | ||||
-rw-r--r-- | bindings/cpp/meson.build | 16 | ||||
-rw-r--r-- | doc/c/overview.rst | 2 | ||||
-rw-r--r-- | doc/summary.rst | 2 | ||||
-rw-r--r-- | include/sratom/sratom.h | 114 | ||||
-rwxr-xr-x | scripts/dox_to_sphinx.py | 3 | ||||
-rw-r--r-- | src/dumper.c | 200 | ||||
-rw-r--r-- | src/loader.c | 384 | ||||
-rw-r--r-- | test/test_sratom.c | 49 |
10 files changed, 438 insertions, 377 deletions
diff --git a/.clang-tidy b/.clang-tidy index 40c511c..449495e 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -9,6 +9,7 @@ Checks: > -hicpp-signed-bitwise, -llvm-header-guard, -llvmlibc-*, + -misc-misplaced-const, -misc-no-recursion, WarningsAsErrors: '*' HeaderFilterRegex: '.*' diff --git a/bindings/cpp/include/sratom/sratom.hpp b/bindings/cpp/include/sratom/sratom.hpp index b12d5e1..8be6644 100644 --- a/bindings/cpp/include/sratom/sratom.hpp +++ b/bindings/cpp/include/sratom/sratom.hpp @@ -79,21 +79,21 @@ public: : BasicWrapper(sratom_dumper_new(world.cobj(), &map, &unmap)) {} - int write(const serd::Env& env, - serd::SinkView sink, - const LV2_Atom& atom, - const Flags flags) + SratomStatus write(const serd::Env& env, + serd::SinkView sink, + const LV2_Atom& atom, + const Flags flags) { return sratom_dump_atom( cobj(), env.cobj(), sink.cobj(), nullptr, nullptr, &atom, flags); } - int write(const serd::Env& env, - serd::SinkView sink, - const serd::Node& subject, - const serd::Node& predicate, - const LV2_Atom& atom, - const Flags flags) + SratomStatus write(const serd::Env& env, + serd::SinkView sink, + const serd::Node& subject, + const serd::Node& predicate, + const LV2_Atom& atom, + const Flags flags) { return sratom_dump_atom(cobj(), env.cobj(), @@ -104,14 +104,14 @@ public: flags); } - int write(const serd::Env& env, - serd::SinkView sink, - const serd::Node& subject, - const serd::Node& predicate, - LV2_URID type, - uint32_t size, - const void* body, - const Flags flags) + SratomStatus write(const serd::Env& env, + serd::SinkView sink, + const serd::Node& subject, + const serd::Node& predicate, + LV2_URID type, + uint32_t size, + const void* body, + const Flags flags) { return sratom_dump(cobj(), env.cobj(), @@ -153,10 +153,10 @@ public: : BasicWrapper(sratom_loader_new(world.cobj(), &map)) {} - int load(const serd::Optional<serd::Node>& base_uri, - LV2_Atom_Forge& forge, - const serd::Model& model, - const serd::Node& node) + SratomStatus load(const serd::Optional<serd::Node>& base_uri, + LV2_Atom_Forge& forge, + const serd::Model& model, + const serd::Node& node) { return sratom_load( cobj(), base_uri.cobj(), &forge, model.cobj(), node.cobj()); diff --git a/bindings/cpp/meson.build b/bindings/cpp/meson.build index ee1dc4f..02f4d53 100644 --- a/bindings/cpp/meson.build +++ b/bindings/cpp/meson.build @@ -67,10 +67,12 @@ install_headers(cpp_headers, subdir: versioned_cpp_name / 'sratom') cpp_test_args = cpp.get_supported_arguments(['-Wno-float-equal']) -test('bindings', - executable('test_sratom_hpp', - 'test/test_sratom_hpp.cpp', - include_directories: include_directories(['include']), - cpp_args: exess_cpp_args + cpp_test_args, - dependencies: [sratom_dep, serdpp_dep, sratompp_dep]), - suite: 'cpp') +test( + 'bindings', + executable( + 'test_sratom_hpp', + 'test/test_sratom_hpp.cpp', + include_directories: include_directories(['include', '../../test']), + cpp_args: exess_cpp_args + cpp_test_args, + dependencies: [sratom_dep, serdpp_dep, sratompp_dep]), + suite: 'cpp') diff --git a/doc/c/overview.rst b/doc/c/overview.rst index 3b26a5b..b5d75c1 100644 --- a/doc/c/overview.rst +++ b/doc/c/overview.rst @@ -5,7 +5,7 @@ Overview .. default-domain:: c .. highlight:: c -The complete API is declared in ``sratom.h``: +The entire API is declared in ``sratom.h``: .. code-block:: c diff --git a/doc/summary.rst b/doc/summary.rst index 7e28f6e..715e82e 100644 --- a/doc/summary.rst +++ b/doc/summary.rst @@ -1,6 +1,6 @@ Sratom is a small library for reading and writing `LV2 atoms`_ in RDF, for representing them as strings or storing them in a data model. Sratom is useful for representing LV2 atoms in a portable and human-readable form, -in, for example, saved files, network protocols, or logs. +for example in save files, network protocols, or logs. .. _LV2 atoms: http://lv2plug.in/ns/ext/atom diff --git a/include/sratom/sratom.h b/include/sratom/sratom.h index 68bff33..6934fb8 100644 --- a/include/sratom/sratom.h +++ b/include/sratom/sratom.h @@ -43,10 +43,17 @@ extern "C" { /** @defgroup sratom Sratom C API - This is the complete public C API of sratom. @{ */ +/// Return status code +typedef enum { + SRATOM_SUCCESS, ///< No error + SRATOM_BAD_FILE_URI, ///< Invalid file URI encountered + SRATOM_BAD_VECTOR, ///< Invalid vector (missing atom:childType) + SRATOM_BAD_FORGE, ///< Error forging output atom (likely overflow) +} SratomStatus; + /// Free memory allocated in the sratom library SRATOM_API void @@ -71,16 +78,23 @@ typedef enum { /** Write pretty numeric literals in Turtle or TriG. - If set, numbers may be written as pretty literals instead of string - literals with explicit data types. Note that enabling this means that - types will not survive a round trip. + If set, numbers may be written as "pretty" xsd:integer or xsd:decimal + literals (without quoting or an explicit datatype) instead of string + literals with explicit data types. It is best to leave this off in + contexts where human readability doesn't matter very much, since the + explicit form is more consistent and likely to survive storage, + transmission, and transformation with perfect fidelity. */ SRATOM_PRETTY_NUMBERS = 1u << 2u, /** Write terse output without newlines. - If set, top level atoms will be written as a single long line. + If set when writing to a string, top-level atoms will be written as a + single long line. From a machine perspective, the output is identical, + but this can be convenient in contexts where taking up less space for the + representation of atoms is desirable, such as developer logs or + transmission over a network. */ SRATOM_TERSE = 1u << 3u, } SratomDumperFlag; @@ -117,30 +131,40 @@ sratom_dumper_free(SratomDumper* dumper); series of statements. It can be used with any sink, such as a Turtle writer, model inserter, or a custom sink provided by the application. - This function takes the `type`, `size`, and `body` separately to allow - writing atoms from data in memory that does not have an atom header. For - true atom pointers, the simpler sratom_dump_atom() can be used instead. - - Since all statements must be triples, a subject and predicate can be - provided to serialise literals like `subject predicate "literal"`. If - `subject` and `predicate` are null, resources will be written as the - subject, but literals will be written as the only element of an anonymous - list. A subject and predicate should always be given for lossless - round-tripping. This corresponds to using atoms as property values. - - @param dumper Dumper instance - @param env Environment defining the base URI and any prefixes - @param sink Sink which receives the serialised statements - @param subject Subject of first statement, or NULL - @param predicate Predicate of first statement, or NULL - @param type Type of the atom - @param size Size of the atom body in bytes - @param body Atom body - @param flags Option flags - @return Zero on success + This function takes the `type`, `size`, and `body` separately to enable + writing values that are not a contiguous `LV2_Atom` in memory. For writing + existing atoms, the simpler sratom_dump_atom() can be used instead. + + A subject and predicate can be provided so that writing simple atoms will + produce a statement like `subject predicate "literal"`. If either `subject` + or `predicate` are null, objects will be written as the subject, and + literals will be written as the only element of an anonymous list. For + example: + + @verbatim + my:object some:property 42 . + [ some:property 42 ] . + ( "literal" ) . + @endverbatim + + Generally, this function is intended for writing the value of some property + (for example, the current value of a plugin parameter in a preset), and the + appropriate subject and predicate for the context should always be provided. + This avoids any ambiguities and guarantees lossless round-tripping. + + @param dumper Dumper instance. + @param env Environment defining the base URI and any prefixes. + @param sink Sink which receives the statements describing the atom. + @param subject Subject of first statement, or NULL. + @param predicate Predicate of first statement, or NULL. + @param type Type of the atom. + @param size Size of the atom body in bytes. + @param body Atom body. + @param flags Option flags. + @return Zero on success. */ SRATOM_API -int +SratomStatus sratom_dump(SratomDumper* dumper, const SerdEnv* env, const SerdSink* sink, @@ -157,17 +181,17 @@ sratom_dump(SratomDumper* dumper, Convenience wrapper that takes a pointer to a complete atom, see the sratom_dump() documentation for details. - @param dumper Dumper instance - @param env Environment defining the base URI and any prefixes - @param sink Sink which receives the serialised statements - @param subject Subject of first statement, or NULL - @param predicate Predicate of first statement, or NULL - @param atom Atom to serialise - @param flags Option flags - @return Zero on success + @param dumper Dumper instance. + @param env Environment defining the base URI and any prefixes. + @param sink Sink which receives the statements describing the atom. + @param subject Subject of first statement, or NULL. + @param predicate Predicate of first statement, or NULL. + @param atom Atom to write. + @param flags Option flags. + @return Zero on success. */ SRATOM_API -int +SratomStatus sratom_dump_atom(SratomDumper* dumper, const SerdEnv* env, const SerdSink* sink, @@ -182,10 +206,10 @@ sratom_dump_atom(SratomDumper* dumper, The returned string can be forged back into an atom using sratom_from_string(). - @param dumper Dumper instance - @param env Environment for namespaces and relative URIs - @param atom Atom to serialise - @param flags Option flags + @param dumper Dumper instance. + @param env Environment for namespaces and relative URIs. + @param atom Atom to write. + @param flags Option flags. @return A string that must be freed using sratom_free(), or NULL on error. */ SRATOM_API @@ -207,9 +231,9 @@ typedef struct SratomLoaderImpl SratomLoader; /** Create a new loader for forging atoms from a document. - @param world RDF world - @param map URID mapper - @return A new object that must be freed with sratom_loader_free() + @param world RDF world. + @param map URID mapper. + @return A new object that must be freed with sratom_loader_free(). */ SRATOM_API SratomLoader* @@ -243,10 +267,10 @@ sratom_loader_free(SratomLoader* loader); primitive atoms, or the subject resource for more complex structures like objects and vectors. - @return Zero on success. + @return A status code which is zero on success. */ SRATOM_API -int +SratomStatus sratom_load(SratomLoader* loader, const SerdNode* base_uri, LV2_Atom_Forge* forge, diff --git a/scripts/dox_to_sphinx.py b/scripts/dox_to_sphinx.py index c9d401c..f0dcd2c 100755 --- a/scripts/dox_to_sphinx.py +++ b/scripts/dox_to_sphinx.py @@ -322,6 +322,9 @@ def dox_to_rst(index, lang, node): if node.tag == "ulink": return "`%s <%s>`_" % (node.text, node.get("url")) + if node.tag == "verbatim": + return "::\n\n" + indent(plain_text(node), 1) + raise RuntimeError("Unknown documentation command: %s" % node.tag) diff --git a/src/dumper.c b/src/dumper.c index b2bb852..b6cd08e 100644 --- a/src/dumper.c +++ b/src/dumper.c @@ -33,12 +33,12 @@ #define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#" #define NS_XSD "http://www.w3.org/2001/XMLSchema#" -#define STREAM_WARN(msg) \ - serd_world_logf( \ +#define DUMP_WARN(msg) \ + serd_world_logf( \ writer->world, "sratom", SERD_LOG_LEVEL_WARNING, 0, NULL, msg); -#define STREAM_ERRORF(msg, ...) \ - serd_world_logf( \ +#define DUMP_ERRORF(msg, ...) \ + serd_world_logf( \ writer->world, "sratom", SERD_LOG_LEVEL_ERROR, 0, NULL, msg, __VA_ARGS__); struct SratomDumperImpl { @@ -92,53 +92,53 @@ sratom_dumper_new(SerdWorld* const world, LV2_URID_Map* const map, LV2_URID_Unmap* const unmap) { - SratomDumper* writer = (SratomDumper*)calloc(1, sizeof(SratomDumper)); - if (!writer) { + SratomDumper* const dumper = (SratomDumper*)calloc(1, sizeof(SratomDumper)); + if (!dumper) { return NULL; } - writer->world = world; - writer->unmap = unmap; - writer->atom_Event = map->map(map->handle, LV2_ATOM__Event); - writer->atom_beatTime = map->map(map->handle, LV2_ATOM__beatTime); - writer->midi_MidiEvent = map->map(map->handle, LV2_MIDI__MidiEvent); - lv2_atom_forge_init(&writer->forge, map); + dumper->world = world; + dumper->unmap = unmap; + dumper->atom_Event = map->map(map->handle, LV2_ATOM__Event); + dumper->atom_beatTime = map->map(map->handle, LV2_ATOM__beatTime); + dumper->midi_MidiEvent = map->map(map->handle, LV2_MIDI__MidiEvent); + lv2_atom_forge_init(&dumper->forge, map); #define MANAGE_URI(uri) \ serd_nodes_manage(serd_world_nodes(world), \ serd_new_uri(SERD_STATIC_STRING(uri))) - writer->nodes.atom_Path = MANAGE_URI(LV2_ATOM__Path); - writer->nodes.atom_beatTime = MANAGE_URI(LV2_ATOM__beatTime); - writer->nodes.atom_childType = MANAGE_URI(LV2_ATOM__childType); - writer->nodes.atom_frameTime = MANAGE_URI(LV2_ATOM__frameTime); - writer->nodes.midi_MidiEvent = MANAGE_URI(LV2_MIDI__MidiEvent); - writer->nodes.rdf_first = MANAGE_URI(NS_RDF "first"); - writer->nodes.rdf_nil = MANAGE_URI(NS_RDF "nil"); - writer->nodes.rdf_rest = MANAGE_URI(NS_RDF "rest"); - writer->nodes.rdf_type = MANAGE_URI(NS_RDF "type"); - writer->nodes.rdf_value = MANAGE_URI(NS_RDF "value"); - writer->nodes.xsd_base64Binary = MANAGE_URI(NS_XSD "base64Binary"); - writer->nodes.xsd_boolean = MANAGE_URI(NS_XSD "boolean"); - writer->nodes.xsd_decimal = MANAGE_URI(NS_XSD "decimal"); - writer->nodes.xsd_double = MANAGE_URI(NS_XSD "double"); - writer->nodes.xsd_float = MANAGE_URI(NS_XSD "float"); - writer->nodes.xsd_int = MANAGE_URI(NS_XSD "int"); - writer->nodes.xsd_integer = MANAGE_URI(NS_XSD "integer"); - writer->nodes.xsd_long = MANAGE_URI(NS_XSD "long"); + dumper->nodes.atom_Path = MANAGE_URI(LV2_ATOM__Path); + dumper->nodes.atom_beatTime = MANAGE_URI(LV2_ATOM__beatTime); + dumper->nodes.atom_childType = MANAGE_URI(LV2_ATOM__childType); + dumper->nodes.atom_frameTime = MANAGE_URI(LV2_ATOM__frameTime); + dumper->nodes.midi_MidiEvent = MANAGE_URI(LV2_MIDI__MidiEvent); + dumper->nodes.rdf_first = MANAGE_URI(NS_RDF "first"); + dumper->nodes.rdf_nil = MANAGE_URI(NS_RDF "nil"); + dumper->nodes.rdf_rest = MANAGE_URI(NS_RDF "rest"); + dumper->nodes.rdf_type = MANAGE_URI(NS_RDF "type"); + dumper->nodes.rdf_value = MANAGE_URI(NS_RDF "value"); + dumper->nodes.xsd_base64Binary = MANAGE_URI(NS_XSD "base64Binary"); + dumper->nodes.xsd_boolean = MANAGE_URI(NS_XSD "boolean"); + dumper->nodes.xsd_decimal = MANAGE_URI(NS_XSD "decimal"); + dumper->nodes.xsd_double = MANAGE_URI(NS_XSD "double"); + dumper->nodes.xsd_float = MANAGE_URI(NS_XSD "float"); + dumper->nodes.xsd_int = MANAGE_URI(NS_XSD "int"); + dumper->nodes.xsd_integer = MANAGE_URI(NS_XSD "integer"); + dumper->nodes.xsd_long = MANAGE_URI(NS_XSD "long"); #undef MANAGE_URI - return writer; + return dumper; } void -sratom_dumper_free(SratomDumper* writer) +sratom_dumper_free(SratomDumper* const writer) { free(writer); } -static int +static SratomStatus write_atom(StreamContext* ctx, const SerdNode* subject, const SerdNode* predicate, @@ -147,15 +147,16 @@ write_atom(StreamContext* ctx, const void* body); static void -list_append(StreamContext* ctx, - SerdNode** s, - const SerdNode** p, - uint32_t size, - uint32_t type, - const void* body) +list_append(StreamContext* const ctx, + SerdNode** const s, + const SerdNode** const p, + const uint32_t size, + const uint32_t type, + const void* const body) { // Generate a list node - SerdNode* node = serd_node_copy(serd_world_get_blank(ctx->writer->world)); + SerdNode* const node = + serd_node_copy(serd_world_get_blank(ctx->writer->world)); serd_sink_write(ctx->sink, ctx->sflags, *s, *p, node, NULL); // _:node rdf:first value @@ -170,19 +171,20 @@ list_append(StreamContext* ctx, } static void -list_end(StreamContext* ctx, const SerdNode* s, const SerdNode* p) +list_end(const StreamContext* const ctx, + const SerdNode* const s, + const SerdNode* const p) { // _:node rdf:rest rdf:nil - serd_sink_write( - ctx->sink, ctx->sflags, s, p, ctx->writer->nodes.rdf_nil, NULL); + serd_sink_write(ctx->sink, 0, s, p, ctx->writer->nodes.rdf_nil, NULL); } static void -start_object(StreamContext* ctx, - const SerdNode* subject, - const SerdNode* predicate, - const SerdNode* node, - const char* type) +start_object(StreamContext* const ctx, + const SerdNode* const subject, + const SerdNode* const predicate, + const SerdNode* const node, + const char* const type) { if (subject && predicate) { serd_sink_write( @@ -192,7 +194,7 @@ start_object(StreamContext* ctx, } if (type) { - SerdNode* o = serd_new_uri(SERD_MEASURE_STRING(type)); + SerdNode* const o = serd_new_uri(SERD_MEASURE_STRING(type)); serd_sink_write( ctx->sink, ctx->sflags, node, ctx->writer->nodes.rdf_type, o, NULL); @@ -202,10 +204,10 @@ start_object(StreamContext* ctx, } static void -end_object(StreamContext* ctx, - const SerdNode* subject, - const SerdNode* predicate, - const SerdNode* node) +end_object(const StreamContext* const ctx, + const SerdNode* const subject, + const SerdNode* const predicate, + const SerdNode* const node) { if (subject && predicate) { serd_sink_write_end(ctx->sink, node); @@ -213,30 +215,33 @@ end_object(StreamContext* ctx, } static bool -path_is_absolute(const char* path) +path_is_absolute(const char* const path) { return (path[0] == '/' || (isalpha(path[0]) && path[1] == ':' && (path[2] == '/' || path[2] == '\\'))); } static const SerdNode* -number_type(StreamContext* ctx, const SerdNode* type) +number_type(const StreamContext* const ctx, const SerdNode* const type) { SratomDumper* const writer = ctx->writer; const bool pretty = (ctx->flags & SRATOM_PRETTY_NUMBERS); + if (pretty) { if (type == writer->nodes.xsd_int || type == writer->nodes.xsd_long) { return writer->nodes.xsd_integer; - } else if (type == writer->nodes.xsd_float || - type == writer->nodes.xsd_double) { + } + + if (type == writer->nodes.xsd_float || type == writer->nodes.xsd_double) { return writer->nodes.xsd_decimal; } } + return type; } static bool -is_primitive_type(StreamContext* ctx, const LV2_URID type) +is_primitive_type(const StreamContext* const ctx, const LV2_URID type) { SratomDumper* const writer = ctx->writer; return (!type || type == writer->forge.Bool || type == writer->forge.Double || @@ -246,20 +251,22 @@ is_primitive_type(StreamContext* ctx, const LV2_URID type) type == writer->forge.URI || type == writer->forge.URID); } -static int -write_atom(StreamContext* const ctx, - const SerdNode* subject, - const SerdNode* predicate, - const LV2_URID type, - const uint32_t size, - const void* const body) +static SratomStatus +write_atom(StreamContext* const ctx, + const SerdNode* const subject, + const SerdNode* const predicate, + const LV2_URID type, + const uint32_t size, + const void* const body) { - SratomDumper* writer = ctx->writer; - LV2_URID_Unmap* unmap = writer->unmap; - const SerdSink* sink = ctx->sink; - const SerdEnv* env = ctx->env; - const char* const type_uri = unmap->unmap(unmap->handle, type); - SerdNode* object = NULL; + SratomDumper* const writer = ctx->writer; + LV2_URID_Unmap* const unmap = writer->unmap; + const SerdSink* const sink = ctx->sink; + const SerdEnv* const env = ctx->env; + const char* const type_uri = unmap->unmap(unmap->handle, type); + SerdNode* object = NULL; + SratomStatus st = SRATOM_SUCCESS; + if (type == 0 && size == 0) { object = serd_node_copy(writer->nodes.rdf_nil); } else if (type == writer->forge.String) { @@ -281,7 +288,7 @@ write_atom(StreamContext* const ctx, object = serd_new_plain_literal(SERD_MEASURE_STRING(str), SERD_MEASURE_STRING(lang + prefix_len)); } else { - STREAM_ERRORF("Unknown language URID %u\n", lit->lang); + DUMP_ERRORF("Unknown language URID %u\n", lit->lang); } } } else if (type == writer->forge.URID) { @@ -296,8 +303,8 @@ write_atom(StreamContext* const ctx, } else { const SerdNode* base_uri = serd_env_base_uri(env); if (!base_uri || strncmp(serd_node_string(base_uri), "file://", 7)) { - STREAM_WARN("Relative path but base is not a file URI.\n"); - STREAM_WARN("Writing ambiguous atom:Path literal.\n"); + DUMP_WARN("Relative path but base is not a file URI.\n"); + DUMP_WARN("Writing ambiguous atom:Path literal.\n"); object = serd_new_typed_literal( str, serd_node_string_view(writer->nodes.atom_Path)); } else { @@ -341,8 +348,8 @@ write_atom(StreamContext* const ctx, free(str); } else if (type == writer->atom_Event) { - const LV2_Atom_Event* ev = (const LV2_Atom_Event*)body; - const SerdNode* id = serd_world_get_blank(writer->world); + const LV2_Atom_Event* const ev = (const LV2_Atom_Event*)body; + const SerdNode* const id = serd_world_get_blank(writer->world); start_object(ctx, subject, predicate, id, NULL); SerdNode* time = NULL; const SerdNode* p = NULL; @@ -362,28 +369,34 @@ write_atom(StreamContext* const ctx, ctx, id, p, ev->body.type, ev->body.size, LV2_ATOM_BODY_CONST(&ev->body)); end_object(ctx, subject, predicate, id); } else if (type == writer->forge.Tuple) { - SerdNode* id = serd_node_copy(serd_world_get_blank(writer->world)); + SerdNode* id = serd_node_copy(serd_world_get_blank(writer->world)); + const SerdNode* p = writer->nodes.rdf_value; start_object(ctx, subject, predicate, id, type_uri); - const SerdNode* p = writer->nodes.rdf_value; + ctx->sflags |= SERD_LIST_O | SERD_TERSE_O; LV2_ATOM_TUPLE_BODY_FOREACH (body, size, i) { if (!is_primitive_type(ctx, i->type)) { ctx->sflags &= ~SERD_TERSE_O; } } + LV2_ATOM_TUPLE_BODY_FOREACH (body, size, i) { list_append(ctx, &id, &p, i->size, i->type, LV2_ATOM_BODY(i)); } - list_end(ctx, id, p); + + serd_sink_write(ctx->sink, 0, id, p, ctx->writer->nodes.rdf_nil, NULL); end_object(ctx, subject, predicate, id); serd_node_free(id); } else if (type == writer->forge.Vector) { - const LV2_Atom_Vector_Body* vec = (const LV2_Atom_Vector_Body*)body; + const LV2_Atom_Vector_Body* const vec = (const LV2_Atom_Vector_Body*)body; + SerdNode* id = serd_node_copy(serd_world_get_blank(writer->world)); start_object(ctx, subject, predicate, id, type_uri); + const SerdNode* p = writer->nodes.atom_childType; - SerdNode* child_type = serd_new_uri( + SerdNode* const child_type = serd_new_uri( SERD_MEASURE_STRING(unmap->unmap(unmap->handle, vec->child_type))); + serd_sink_write(sink, ctx->sflags, id, p, child_type, NULL); p = writer->nodes.rdf_value; serd_node_free(child_type); @@ -391,16 +404,18 @@ write_atom(StreamContext* const ctx, if (is_primitive_type(ctx, vec->child_type)) { ctx->sflags |= SERD_TERSE_O; } + for (const char* i = (const char*)(vec + 1); i < (const char*)vec + size; i += vec->child_size) { list_append(ctx, &id, &p, vec->child_size, vec->child_type, i); } - list_end(ctx, id, p); + + serd_sink_write(ctx->sink, 0, id, p, ctx->writer->nodes.rdf_nil, NULL); end_object(ctx, subject, predicate, id); serd_node_free(id); } else if (lv2_atom_forge_is_object_type(&writer->forge, type)) { const LV2_Atom_Object_Body* obj = (const LV2_Atom_Object_Body*)body; - const char* otype = unmap->unmap(unmap->handle, obj->otype); + const char* const otype = unmap->unmap(unmap->handle, obj->otype); SerdNode* id = NULL; if (lv2_atom_forge_is_blank(&writer->forge, type, obj)) { @@ -414,7 +429,7 @@ write_atom(StreamContext* const ctx, } LV2_ATOM_OBJECT_BODY_FOREACH (obj, size, prop) { const char* const key = unmap->unmap(unmap->handle, prop->key); - SerdNode* pred = serd_new_uri(SERD_MEASURE_STRING(key)); + SerdNode* const pred = serd_new_uri(SERD_MEASURE_STRING(key)); write_atom(ctx, id, pred, @@ -454,18 +469,17 @@ write_atom(StreamContext* const ctx, } if (object) { - if (!subject && !predicate) { - subject = serd_world_get_blank(writer->world); - predicate = writer->nodes.rdf_first; + if (!subject || !predicate) { + const SerdNode* const blank = serd_world_get_blank(writer->world); serd_sink_write(sink, ctx->sflags | SERD_LIST_S | SERD_TERSE_S, - subject, - predicate, + blank, + writer->nodes.rdf_first, object, NULL); serd_sink_write(sink, SERD_TERSE_S, - subject, + blank, writer->nodes.rdf_rest, writer->nodes.rdf_nil, NULL); @@ -476,10 +490,10 @@ write_atom(StreamContext* const ctx, serd_node_free(object); - return 0; + return st; } -int +SratomStatus sratom_dump(SratomDumper* const writer, const SerdEnv* const env, const SerdSink* const sink, @@ -500,7 +514,7 @@ sratom_dump(SratomDumper* const writer, return write_atom(&ctx, subject, predicate, type, size, body); } -int +SratomStatus sratom_dump_atom(SratomDumper* const writer, const SerdEnv* const env, const SerdSink* const sink, diff --git a/src/loader.c b/src/loader.c index 46e7c51..46a23f3 100644 --- a/src/loader.c +++ b/src/loader.c @@ -23,7 +23,6 @@ #include "serd/serd.h" #include <assert.h> -#include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -37,6 +36,17 @@ typedef enum { MODE_SUBJECT, MODE_BODY, MODE_SEQUENCE } ReadMode; +typedef struct { + const SerdNode* atom_beatTime; + const SerdNode* atom_childType; + const SerdNode* atom_frameTime; + const SerdNode* rdf_first; + const SerdNode* rdf_rest; + const SerdNode* rdf_type; + const SerdNode* rdf_value; + const SerdNode* xsd_base64Binary; +} LoaderNodes; + struct SratomLoaderImpl { LV2_URID_Map* map; LV2_Atom_Forge forge; @@ -44,25 +54,16 @@ struct SratomLoaderImpl { LV2_URID atom_frameTime; LV2_URID atom_beatTime; LV2_URID midi_MidiEvent; - struct { - const SerdNode* atom_beatTime; - const SerdNode* atom_childType; - const SerdNode* atom_frameTime; - const SerdNode* rdf_first; - const SerdNode* rdf_rest; - const SerdNode* rdf_type; - const SerdNode* rdf_value; - const SerdNode* xsd_base64Binary; - } nodes; + LoaderNodes nodes; }; typedef struct { - SratomLoader* loader; - const SerdNode* base_uri; - LV2_URID seq_unit; + SratomLoader* SERD_NONNULL loader; + const SerdNode* SERD_NONNULL base_uri; + LV2_URID seq_unit; } LoadContext; -static void +static SratomStatus read_node(LoadContext* ctx, LV2_Atom_Forge* forge, const SerdModel* model, @@ -70,55 +71,58 @@ read_node(LoadContext* ctx, ReadMode mode); SratomLoader* -sratom_loader_new(SerdWorld* world, LV2_URID_Map* map) +sratom_loader_new(SerdWorld* const world, LV2_URID_Map* const map) { - SratomLoader* sratom = (SratomLoader*)calloc(1, sizeof(SratomLoader)); - if (!sratom) { + SratomLoader* const loader = (SratomLoader*)calloc(1, sizeof(SratomLoader)); + if (!loader) { return NULL; } - sratom->world = world; - sratom->map = map; - sratom->atom_frameTime = map->map(map->handle, LV2_ATOM__frameTime); - sratom->atom_beatTime = map->map(map->handle, LV2_ATOM__beatTime); - sratom->midi_MidiEvent = map->map(map->handle, LV2_MIDI__MidiEvent); - lv2_atom_forge_init(&sratom->forge, map); + loader->world = world; + loader->map = map; + loader->atom_frameTime = map->map(map->handle, LV2_ATOM__frameTime); + loader->atom_beatTime = map->map(map->handle, LV2_ATOM__beatTime); + loader->midi_MidiEvent = map->map(map->handle, LV2_MIDI__MidiEvent); + + lv2_atom_forge_init(&loader->forge, map); #define MANAGE_URI(uri) \ serd_nodes_manage(serd_world_nodes(world), \ serd_new_uri(SERD_STATIC_STRING(uri))) - sratom->nodes.atom_beatTime = MANAGE_URI(LV2_ATOM__beatTime); - sratom->nodes.atom_childType = MANAGE_URI(LV2_ATOM__childType); - sratom->nodes.atom_frameTime = MANAGE_URI(LV2_ATOM__frameTime); - sratom->nodes.rdf_first = MANAGE_URI(NS_RDF "first"); - sratom->nodes.rdf_rest = MANAGE_URI(NS_RDF "rest"); - sratom->nodes.rdf_type = MANAGE_URI(NS_RDF "type"); - sratom->nodes.rdf_value = MANAGE_URI(NS_RDF "value"); - sratom->nodes.xsd_base64Binary = MANAGE_URI(NS_XSD "base64Binary"); + loader->nodes.atom_beatTime = MANAGE_URI(LV2_ATOM__beatTime); + loader->nodes.atom_childType = MANAGE_URI(LV2_ATOM__childType); + loader->nodes.atom_frameTime = MANAGE_URI(LV2_ATOM__frameTime); + loader->nodes.rdf_first = MANAGE_URI(NS_RDF "first"); + loader->nodes.rdf_rest = MANAGE_URI(NS_RDF "rest"); + loader->nodes.rdf_type = MANAGE_URI(NS_RDF "type"); + loader->nodes.rdf_value = MANAGE_URI(NS_RDF "value"); + loader->nodes.xsd_base64Binary = MANAGE_URI(NS_XSD "base64Binary"); -#undef INTERN_URI +#undef MANAGE_URI - return sratom; + return loader; } void -sratom_loader_free(SratomLoader* loader) +sratom_loader_free(SratomLoader* const loader) { free(loader); } static void -read_list_value(LoadContext* ctx, - LV2_Atom_Forge* forge, - const SerdModel* model, - const SerdNode* node, - ReadMode mode) +read_list_value(LoadContext* const ctx, + LV2_Atom_Forge* const forge, + const SerdModel* const model, + const SerdNode* const node, + const ReadMode mode) { - const SerdNode* fst = + const SerdNode* const fst = serd_model_get(model, node, ctx->loader->nodes.rdf_first, NULL, NULL); - const SerdNode* rst = + + const SerdNode* const rst = serd_model_get(model, node, ctx->loader->nodes.rdf_rest, NULL, NULL); + if (fst && rst) { read_node(ctx, forge, model, fst, mode); read_list_value(ctx, forge, model, rst, mode); @@ -126,21 +130,21 @@ read_list_value(LoadContext* ctx, } static void -read_resource(LoadContext* ctx, - LV2_Atom_Forge* forge, - const SerdModel* model, - const SerdNode* node, - LV2_URID otype) +read_resource(LoadContext* const ctx, + LV2_Atom_Forge* const forge, + const SerdModel* const model, + const SerdNode* const node, + const LV2_URID otype) { - LV2_URID_Map* map = ctx->loader->map; - SerdRange* r = serd_model_range(model, node, NULL, NULL, NULL); + LV2_URID_Map* const map = ctx->loader->map; + SerdRange* const r = serd_model_range(model, node, NULL, NULL, NULL); for (; !serd_range_empty(r); serd_range_next(r)) { const SerdStatement* match = serd_range_front(r); - const SerdNode* p = serd_statement_predicate(match); - const SerdNode* o = serd_statement_object(match); - if (p) { - const char* p_uri = serd_node_string(p); - uint32_t p_urid = map->map(map->handle, p_uri); + if (match) { + const SerdNode* const p = serd_statement_predicate(match); + const SerdNode* const o = serd_statement_object(match); + const char* const p_uri = serd_node_string(p); + const uint32_t p_urid = map->map(map->handle, p_uri); if (!(serd_node_equals(p, ctx->loader->nodes.rdf_type) && serd_node_type(o) == SERD_URI && map->map(map->handle, serd_node_string(o)) == otype)) { @@ -153,146 +157,184 @@ read_resource(LoadContext* ctx, } static uint32_t -atom_size(SratomLoader* loader, uint32_t type_urid) +atom_size(SratomLoader* const loader, const uint32_t type_urid) { - if (type_urid == loader->forge.Int) { + if (type_urid == loader->forge.Int || type_urid == loader->forge.Bool) { return sizeof(int32_t); - } else if (type_urid == loader->forge.Long) { + } + + if (type_urid == loader->forge.URID) { + return sizeof(uint32_t); + } + + if (type_urid == loader->forge.Long) { return sizeof(int64_t); - } else if (type_urid == loader->forge.Float) { + } + + if (type_urid == loader->forge.Float) { return sizeof(float); - } else if (type_urid == loader->forge.Double) { + } + + if (type_urid == loader->forge.Double) { return sizeof(double); - } else if (type_urid == loader->forge.Bool) { - return sizeof(int32_t); - } else if (type_urid == loader->forge.URID) { - return sizeof(uint32_t); } + return 0; } -static void -read_uri(LoadContext* ctx, LV2_Atom_Forge* forge, const SerdNode* node) +static SratomStatus +read_uri(LoadContext* const ctx, + LV2_Atom_Forge* const forge, + const SerdNode* const node) { SratomLoader* const loader = ctx->loader; LV2_URID_Map* const map = loader->map; const char* const str = serd_node_string(node); + LV2_Atom_Forge_Ref ref = 0; if (!strcmp(str, NS_RDF "nil")) { - lv2_atom_forge_atom(forge, 0, 0); + ref = lv2_atom_forge_atom(forge, 0, 0); } else if (!strncmp(str, "file://", 7)) { - const SerdURIView base_uri = serd_node_uri_view(ctx->base_uri); - const SerdURIView uri = serd_parse_uri(str); - if (serd_uri_is_within(uri, base_uri)) { + const SerdURIView uri = serd_parse_uri(str); + if (ctx->base_uri && + serd_uri_is_within(uri, serd_node_uri_view(ctx->base_uri))) { SerdNode* const rel = serd_new_parsed_uri(serd_relative_uri( serd_parse_uri(str), serd_node_uri_view(ctx->base_uri))); - char* path = serd_parse_file_uri(serd_node_string(rel), NULL); - lv2_atom_forge_path(forge, path, strlen(path)); + char* const path = serd_parse_file_uri(serd_node_string(rel), NULL); + if (!path) { + return SRATOM_BAD_FILE_URI; + } + + ref = lv2_atom_forge_path(forge, path, strlen(path)); serd_free(path); serd_node_free(rel); } else { char* const path = serd_parse_file_uri(str, NULL); - lv2_atom_forge_path(forge, path, strlen(path)); + if (!path) { + return SRATOM_BAD_FILE_URI; + } + + ref = lv2_atom_forge_path(forge, path, strlen(path)); serd_free(path); } } else { - lv2_atom_forge_urid(forge, map->map(map->handle, str)); + ref = lv2_atom_forge_urid(forge, map->map(map->handle, str)); } + + return ref ? SRATOM_SUCCESS : SRATOM_BAD_FORGE; } -static void +static SratomStatus read_typed_literal(SratomLoader* const loader, LV2_Atom_Forge* const forge, const SerdNode* const node, const SerdNode* const datatype) { - const char* const str = serd_node_string(node); - const size_t len = serd_node_length(node); - const char* const type_uri = serd_node_string(datatype); + const char* const str = serd_node_string(node); + const size_t len = serd_node_length(node); + const char* const type_uri = serd_node_string(datatype); + LV2_Atom_Forge_Ref ref = 0; if (!strcmp(type_uri, NS_XSD "int") || !strcmp(type_uri, NS_XSD "integer")) { - lv2_atom_forge_int(forge, strtol(str, NULL, 10)); + ref = lv2_atom_forge_int(forge, strtol(str, NULL, 10)); } else if (!strcmp(type_uri, NS_XSD "long")) { - lv2_atom_forge_long(forge, strtol(str, NULL, 10)); - } else if (!strcmp(type_uri, NS_XSD "float") || - !strcmp(type_uri, NS_XSD "decimal")) { - lv2_atom_forge_float(forge, serd_get_float(node)); - } else if (!strcmp(type_uri, NS_XSD "double")) { - lv2_atom_forge_double(forge, serd_get_double(node)); + ref = lv2_atom_forge_long(forge, strtol(str, NULL, 10)); + } else if (!strcmp(type_uri, NS_XSD "decimal") || + !strcmp(type_uri, NS_XSD "double")) { + ref = lv2_atom_forge_double(forge, serd_get_double(node)); + } else if (!strcmp(type_uri, NS_XSD "float")) { + ref = lv2_atom_forge_float(forge, serd_get_float(node)); } else if (!strcmp(type_uri, NS_XSD "boolean")) { - lv2_atom_forge_bool(forge, serd_get_boolean(node)); + ref = lv2_atom_forge_bool(forge, serd_get_boolean(node)); } else if (!strcmp(type_uri, NS_XSD "base64Binary")) { - size_t size = 0; - void* body = serd_base64_decode(str, len, &size); - lv2_atom_forge_atom(forge, size, forge->Chunk); - lv2_atom_forge_write(forge, body, size); + size_t size = 0; + void* const body = serd_base64_decode(str, len, &size); + if ((ref = lv2_atom_forge_atom(forge, size, forge->Chunk))) { + ref = lv2_atom_forge_write(forge, body, size); + } free(body); } else if (!strcmp(type_uri, LV2_ATOM__Path)) { - lv2_atom_forge_path(forge, str, len); + ref = lv2_atom_forge_path(forge, str, len); } else if (!strcmp(type_uri, LV2_MIDI__MidiEvent)) { - lv2_atom_forge_atom(forge, len / 2, loader->midi_MidiEvent); - for (const char* s = str; s < str + len; s += 2) { - unsigned num; - sscanf(s, "%2X", &num); - const uint8_t c = num; - lv2_atom_forge_raw(forge, &c, 1); + if ((ref = lv2_atom_forge_atom(forge, len / 2, loader->midi_MidiEvent))) { + for (const char* s = str; s < str + len; s += 2) { + unsigned num = 0u; + sscanf(s, "%2X", &num); + const uint8_t c = num; + if (!(ref = lv2_atom_forge_raw(forge, &c, 1))) { + return SRATOM_BAD_FORGE; + } + } + lv2_atom_forge_pad(forge, len / 2); } - lv2_atom_forge_pad(forge, len / 2); } else { - lv2_atom_forge_literal( + ref = lv2_atom_forge_literal( forge, str, len, loader->map->map(loader->map->handle, type_uri), 0); } + + return ref ? SRATOM_SUCCESS : SRATOM_BAD_FORGE; } -static void +static SratomStatus read_plain_literal(SratomLoader* const loader, LV2_Atom_Forge* const forge, const SerdNode* const node, const SerdNode* const language) { - const char* const str = serd_node_string(node); - const size_t len = serd_node_length(node); - const char* lang_str = serd_node_string(language); - const char* prefix = "http://lexvo.org/id/iso639-3/"; - const size_t lang_len = strlen(prefix) + strlen(lang_str); - char* const lang_uri = (char*)calloc(lang_len + 1, 1); + static const char* const prefix = "http://lexvo.org/id/iso639-3/"; + + const char* const str = serd_node_string(node); + const size_t len = serd_node_length(node); + const char* lang_str = serd_node_string(language); + const size_t prefix_len = strlen(prefix); + const size_t lang_len = prefix_len + strlen(lang_str); + char* const lang_uri = (char*)calloc(lang_len + 1, 1); snprintf(lang_uri, lang_len + 1, "%s%s", prefix, lang_str); - lv2_atom_forge_literal( + const LV2_Atom_Forge_Ref ref = lv2_atom_forge_literal( forge, str, len, 0, loader->map->map(loader->map->handle, lang_uri)); free(lang_uri); + + return ref ? SRATOM_SUCCESS : SRATOM_BAD_FORGE; } -static void -read_literal(SratomLoader* loader, LV2_Atom_Forge* forge, const SerdNode* node) +static SratomStatus +read_literal(SratomLoader* const loader, + LV2_Atom_Forge* const forge, + const SerdNode* const node) { assert(serd_node_type(node) == SERD_LITERAL); const SerdNode* const datatype = serd_node_datatype(node); - const SerdNode* const language = serd_node_language(node); if (datatype) { - read_typed_literal(loader, forge, node, datatype); - } else if (language) { - read_plain_literal(loader, forge, node, language); - } else { - lv2_atom_forge_string( - forge, serd_node_string(node), serd_node_length(node)); + return read_typed_literal(loader, forge, node, datatype); + } + + const SerdNode* const language = serd_node_language(node); + if (language) { + return read_plain_literal(loader, forge, node, language); } + + const LV2_Atom_Forge_Ref ref = lv2_atom_forge_string( + forge, serd_node_string(node), serd_node_length(node)); + + return ref ? SRATOM_SUCCESS : SRATOM_BAD_FORGE; } -static void -read_object(LoadContext* ctx, - LV2_Atom_Forge* forge, - const SerdModel* model, - const SerdNode* node, - ReadMode mode) +static SratomStatus +read_object(LoadContext* const ctx, + LV2_Atom_Forge* const forge, + const SerdModel* const model, + const SerdNode* const node, + const ReadMode mode) { SratomLoader* const loader = ctx->loader; LV2_URID_Map* const map = loader->map; const char* const str = serd_node_string(node); + SratomStatus st = SRATOM_SUCCESS; const SerdNode* const type = serd_model_get(model, node, loader->nodes.rdf_type, NULL, NULL); @@ -336,7 +378,7 @@ read_object(LoadContext* ctx, ctx->seq_unit = 0; read_list_value(ctx, forge, model, value, MODE_SEQUENCE); - LV2_Atom_Sequence* seq = + LV2_Atom_Sequence* const seq = (LV2_Atom_Sequence*)lv2_atom_forge_deref(forge, ref); seq->body.unit = ((ctx->seq_unit == loader->atom_frameTime) ? 0 : ctx->seq_unit); @@ -344,9 +386,13 @@ read_object(LoadContext* ctx, } else if (type_urid == loader->forge.Vector) { const SerdNode* child_type_node = serd_model_get(model, node, loader->nodes.atom_childType, NULL, NULL); - uint32_t child_type = + if (!child_type_node) { + return SRATOM_BAD_VECTOR; + } + + const uint32_t child_type = map->map(map->handle, serd_node_string(child_type_node)); - uint32_t child_size = atom_size(loader, child_type); + const uint32_t child_size = atom_size(loader, child_type); if (child_size > 0) { LV2_Atom_Forge_Ref ref = lv2_atom_forge_vector_head(forge, &frame, child_size, child_type); @@ -358,10 +404,10 @@ read_object(LoadContext* ctx, } else if (value && serd_node_equals(serd_node_datatype(value), loader->nodes.xsd_base64Binary)) { - const char* vstr = serd_node_string(value); - const size_t vlen = serd_node_length(value); - size_t size = 0; - void* body = serd_base64_decode(vstr, vlen, &size); + const char* const vstr = serd_node_string(value); + const size_t vlen = serd_node_length(value); + size_t size = 0; + void* body = serd_base64_decode(vstr, vlen, &size); lv2_atom_forge_atom(forge, size, type_urid); lv2_atom_forge_write(forge, body, size); free(body); @@ -372,7 +418,7 @@ read_object(LoadContext* ctx, lv2_atom_forge_object(forge, &frame, urid, type_urid); read_resource(ctx, forge, model, node, type_urid); } else { - read_uri(ctx, forge, node); + st = read_uri(ctx, forge, node); } } else { @@ -383,41 +429,46 @@ read_object(LoadContext* ctx, if (frame.ref) { lv2_atom_forge_pop(forge, &frame); } + + return st; } -static void -read_node(LoadContext* ctx, - LV2_Atom_Forge* forge, - const SerdModel* model, - const SerdNode* node, - ReadMode mode) +static SratomStatus +read_node(LoadContext* const ctx, + LV2_Atom_Forge* const forge, + const SerdModel* const model, + const SerdNode* const node, + const ReadMode mode) { if (serd_node_type(node) == SERD_LITERAL) { - read_literal(ctx->loader, forge, node); - } else if (serd_node_type(node) == SERD_URI && mode != MODE_SUBJECT) { - read_uri(ctx, forge, node); - } else { - read_object(ctx, forge, model, node, mode); + return read_literal(ctx->loader, forge, node); } + + if (serd_node_type(node) == SERD_URI && mode != MODE_SUBJECT) { + return read_uri(ctx, forge, node); + } + + return read_object(ctx, forge, model, node, mode); } -int -sratom_load(SratomLoader* loader, - const SerdNode* base_uri, - LV2_Atom_Forge* forge, - const SerdModel* model, - const SerdNode* node) +SratomStatus +sratom_load(SratomLoader* const loader, + const SerdNode* const base_uri, + LV2_Atom_Forge* const forge, + const SerdModel* const model, + const SerdNode* const node) { LoadContext ctx = {loader, base_uri, 0}; - read_node(&ctx, forge, model, node, MODE_SUBJECT); - return 0; + return read_node(&ctx, forge, model, node, MODE_SUBJECT); } static SerdModel* -model_from_string(SratomLoader* loader, SerdEnv* env, const char* str) +model_from_string(SratomLoader* const loader, + SerdEnv* const env, + const char* const str) { SerdModel* const model = serd_model_new(loader->world, SERD_INDEX_SPO); - SerdSink* const inserter = serd_inserter_new(model, env, NULL); + SerdSink* const inserter = serd_inserter_new(model, NULL); SerdNode* const name = serd_new_string(SERD_STATIC_STRING("string")); SerdByteSource* const source = serd_byte_source_new_string(str, name); @@ -446,15 +497,17 @@ sratom_from_string(SratomLoader* const loader, SerdEnv* const env, const char* const str) { - SerdModel* model = model_from_string(loader, env, str); + SerdModel* const model = model_from_string(loader, env, str); if (!model || serd_model_empty(model)) { LOAD_ERROR("Failed to read string into model"); return NULL; } - const SerdNode* node = NULL; - SerdIter* begin = serd_model_begin(model); - const SerdStatement* s = serd_iter_get(begin); + const SerdNode* node = NULL; + SerdIter* const begin = serd_model_begin(model); + const SerdStatement* const s = serd_iter_get(begin); + + assert(s); if (serd_model_size(model) == 2 && serd_node_type(serd_statement_subject(s)) == SERD_BLANK && serd_node_equals(serd_statement_predicate(s), loader->nodes.rdf_first)) { @@ -478,28 +531,31 @@ sratom_from_string(SratomLoader* const loader, } static LV2_Atom_Forge_Ref -sratom_forge_sink(LV2_Atom_Forge_Sink_Handle handle, - const void* buf, - uint32_t size) +sratom_forge_sink(const LV2_Atom_Forge_Sink_Handle handle, + const void* const buf, + const uint32_t size) { - SerdBuffer* chunk = (SerdBuffer*)handle; + SerdBuffer* const chunk = (SerdBuffer*)handle; const LV2_Atom_Forge_Ref ref = chunk->len + 1; + serd_buffer_sink(buf, 1, size, chunk); return ref; } static LV2_Atom* -sratom_forge_deref(LV2_Atom_Forge_Sink_Handle handle, LV2_Atom_Forge_Ref ref) +sratom_forge_deref(const LV2_Atom_Forge_Sink_Handle handle, + const LV2_Atom_Forge_Ref ref) { - SerdBuffer* chunk = (SerdBuffer*)handle; + SerdBuffer* const chunk = (SerdBuffer*)handle; + return (LV2_Atom*)((char*)chunk->buf + ref - 1); } LV2_Atom* -sratom_from_model(SratomLoader* loader, - const SerdNode* base_uri, - const SerdModel* model, - const SerdNode* subject) +sratom_from_model(SratomLoader* const loader, + const SerdNode* const base_uri, + const SerdModel* const model, + const SerdNode* const subject) { if (!subject) { return NULL; diff --git a/test/test_sratom.c b/test/test_sratom.c index 12daea3..11154d4 100644 --- a/test/test_sratom.c +++ b/test/test_sratom.c @@ -1,5 +1,5 @@ /* - Copyright 2012-2016 David Robillard <http://drobilla.net> + Copyright 2012-2021 David Robillard <d@drobilla.net> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above @@ -14,16 +14,20 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "test_utils.h" + #include "sratom/sratom.h" #include "lv2/atom/atom.h" #include "lv2/atom/forge.h" +#include "lv2/atom/util.h" #include "lv2/midi/midi.h" #include "lv2/urid/urid.h" #include "serd/serd.h" #include <assert.h> #include <stdbool.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -32,49 +36,6 @@ #define NS_RDF "http://www.w3.org/1999/02/22-rdf-syntax-ns#" #define NS_XSD "http://www.w3.org/2001/XMLSchema#" -/// Simple O(n) URI map -typedef struct { - char** uris; - uint32_t n_uris; -} Uris; - -static char* -copy_string(const char* str) -{ - const size_t len = strlen(str); - char* dup = (char*)malloc(len + 1); - memcpy(dup, str, len + 1); - return dup; -} - -static LV2_URID -urid_map(LV2_URID_Map_Handle handle, const char* uri) -{ - Uris* const uris = (Uris*)handle; - - for (uint32_t i = 0; i < uris->n_uris; ++i) { - if (!strcmp(uris->uris[i], uri)) { - return i + 1; - } - } - - uris->uris = (char**)realloc(uris->uris, ++uris->n_uris * sizeof(char*)); - uris->uris[uris->n_uris - 1] = copy_string(uri); - return uris->n_uris; -} - -static const char* -urid_unmap(LV2_URID_Unmap_Handle handle, LV2_URID urid) -{ - Uris* const uris = (Uris*)handle; - - if (urid > 0 && urid <= uris->n_uris) { - return uris->uris[urid - 1]; - } - - return NULL; -} - static int check_round_trip(Uris* uris, SerdEnv* env, |