summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/sratom/sratom.c69
-rw-r--r--src/sratom/sratom.h5
-rw-r--r--src/state.c99
-rw-r--r--test/lilv_test.c44
4 files changed, 135 insertions, 82 deletions
diff --git a/src/sratom/sratom.c b/src/sratom/sratom.c
index e3238e1..2117705 100644
--- a/src/sratom/sratom.c
+++ b/src/sratom/sratom.c
@@ -15,6 +15,7 @@
*/
#include <assert.h>
+#include <ctype.h>
#include <stdlib.h>
#include <string.h>
@@ -146,8 +147,16 @@ start_object(Sratom* sratom,
}
}
+static bool
+path_is_absolute(const char* path)
+{
+ return (path[0] == '/'
+ || (isalpha(path[0]) && path[1] == ':'
+ && (path[2] == '/' || path[2] == '\\')));
+}
+
SRATOM_API
-void
+int
sratom_write(Sratom* sratom,
LV2_URID_Unmap* unmap,
SerdWriter* writer,
@@ -168,7 +177,7 @@ sratom_write(Sratom* sratom,
SerdNode language = SERD_NODE_NULL;
bool new_node = false;
if (type_urid == 0 && size == 0) {
- object = serd_node_from_string(SERD_BLANK, USTR("null"));
+ object = serd_node_from_string(SERD_URI, USTR(NS_RDF "nil"));
} else if (type_urid == sratom->forge.String) {
object = serd_node_from_string(SERD_LITERAL, (const uint8_t*)body);
} else if (type_urid == sratom->forge.Literal) {
@@ -195,8 +204,25 @@ 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);
- datatype = serd_node_from_string(SERD_URI, USTR(LV2_ATOM__Path));
+ if (path_is_absolute((const char*)str)) {
+ new_node = true;
+ object = serd_node_new_uri_from_path(str, NULL, NULL);
+ } 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)) {
+ 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 {
+ new_node = true;
+ SerdNode rel = serd_node_new_uri_from_path(str, NULL, NULL);
+ object = serd_node_new_uri_from_node(&rel, &base_uri, NULL);
+ serd_node_free(&rel);
+ }
+ }
} else if (type_urid == sratom->forge.URI) {
const uint8_t* str = USTR(body);
object = serd_node_from_string(SERD_URI, str);
@@ -331,21 +357,25 @@ sratom_write(Sratom* sratom,
if (new_node) {
serd_node_free(&object);
}
+
+ return 0;
}
SRATOM_API
char*
sratom_to_turtle(Sratom* sratom,
LV2_URID_Unmap* unmap,
+ const char* base_uri,
const SerdNode* subject,
const SerdNode* predicate,
uint32_t type,
uint32_t size,
const void* body)
{
- SerdURI base_uri = SERD_URI_NULL;
- SerdEnv* env = serd_env_new(NULL);
- SerdChunk str = { NULL, 0 };
+ SerdURI buri = SERD_URI_NULL;
+ SerdNode base = serd_node_new_uri_from_string(USTR(base_uri), NULL, &buri);
+ SerdEnv* env = serd_env_new(&base);
+ SerdChunk str = { NULL, 0 };
serd_env_set_prefix_from_strings(env, USTR("midi"), NS_MIDI);
serd_env_set_prefix_from_strings(env, USTR("atom"),
@@ -358,7 +388,7 @@ sratom_to_turtle(Sratom* sratom,
SerdWriter* writer = serd_writer_new(
SERD_TURTLE,
SERD_STYLE_ABBREVIATED|SERD_STYLE_RESOLVED|SERD_STYLE_CURIED,
- env, &base_uri, serd_chunk_sink, &str);
+ env, &buri, serd_chunk_sink, &str);
// Write @prefix directives
serd_env_foreach(env,
@@ -485,10 +515,14 @@ read_node(Sratom* sratom,
lv2_atom_forge_string(forge, (const uint8_t*)str, len);
}
} else if (sord_node_get_type(node) == SORD_URI) {
- if (serd_uri_string_has_scheme((const uint8_t*)str)) {
- lv2_atom_forge_urid(forge, map->map(map->handle, str));
+ if (!strcmp(str, (const char*)NS_RDF "nil")) {
+ lv2_atom_forge_atom(forge, 0, 0);
+ } else if (!strncmp(str, "file://", 7)) {
+ uint8_t* path = serd_file_uri_parse((const uint8_t*)str, NULL);
+ lv2_atom_forge_path(forge, path, strlen((const char*)path));
+ free(path);
} else {
- lv2_atom_forge_uri(forge, (const uint8_t*)str, len);
+ lv2_atom_forge_urid(forge, map->map(map->handle, str));
}
} else {
const SordNode* type = get_object(model, node, sratom->nodes.rdf_type);
@@ -613,16 +647,17 @@ sratom_forge_deref(LV2_Atom_Forge_Sink_Handle handle, LV2_Atom_Forge_Ref ref)
SRATOM_API
LV2_Atom*
sratom_from_turtle(Sratom* sratom,
+ const char* base_uri,
const SerdNode* subject,
const SerdNode* predicate,
const char* str)
{
- SerdChunk 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);
+ SerdChunk out = { NULL, 0 };
+ SerdNode base = serd_node_new_uri_from_string(USTR(base_uri), NULL, NULL);
+ SordWorld* world = sord_world_new();
+ SordModel* model = sord_new(world, SORD_SPO, false);
+ SerdEnv* env = serd_env_new(&base);
+ 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);
diff --git a/src/sratom/sratom.h b/src/sratom/sratom.h
index 6398135..b1ef071 100644
--- a/src/sratom/sratom.h
+++ b/src/sratom/sratom.h
@@ -77,9 +77,10 @@ sratom_free(Sratom* sratom);
/**
Write an Atom to RDF.
The resulting serialised atom is written to @p writer.
+ @return 0 on success, or a non-zero error code otherwise.
*/
SRATOM_API
-void
+int
sratom_write(Sratom* sratom,
LV2_URID_Unmap* unmap,
SerdWriter* writer,
@@ -110,6 +111,7 @@ SRATOM_API
char*
sratom_to_turtle(Sratom* sratom,
LV2_URID_Unmap* unmap,
+ const char* base_uri,
const SerdNode* subject,
const SerdNode* predicate,
uint32_t type,
@@ -123,6 +125,7 @@ sratom_to_turtle(Sratom* sratom,
SRATOM_API
LV2_Atom*
sratom_from_turtle(Sratom* sratom,
+ const char* base_uri,
const SerdNode* subject,
const SerdNode* predicate,
const char* str);
diff --git a/src/state.c b/src/state.c
index 0baa76c..266f7d3 100644
--- a/src/state.c
+++ b/src/state.c
@@ -464,8 +464,7 @@ new_state_from_model(LilvWorld* world,
state->atom_Path = map->map(map->handle, LV2_ATOM__Path);
// Get the plugin URI this state applies to
- const SordQuad upat = {
- node, world->uris.lv2_appliesTo, NULL, NULL };
+ const SordQuad upat = { node, world->uris.lv2_appliesTo, NULL, NULL };
SordIter* i = sord_find(model, upat);
if (i) {
const SordNode* object = sord_iter_get_node(i, SORD_OBJECT);
@@ -561,17 +560,13 @@ new_state_from_model(LilvWorld* world,
#endif
Property prop = { NULL, 0, 0, 0, flags };
- prop.key = map->map(map->handle, (const char*)sord_node_get_string(p));
-
- prop.type = atom->type;
+ prop.key = map->map(map->handle, (const char*)sord_node_get_string(p));
+ prop.type = atom->type;
+ prop.size = atom->size;
+ prop.value = malloc(atom->size);
+ memcpy(prop.value, LV2_ATOM_BODY(atom), atom->size);
if (atom->type == forge.Path) {
prop.flags = LV2_STATE_IS_PORTABLE;
- prop.value = lilv_path_join(state->dir, LV2_ATOM_BODY(atom));
- prop.size = strlen(prop.value) + 1;
- } else {
- prop.size = atom->size;
- prop.value = malloc(atom->size);
- memcpy(prop.value, LV2_ATOM_BODY(atom), atom->size);
}
if (prop.value) {
@@ -587,6 +582,7 @@ new_state_from_model(LilvWorld* world,
sord_node_free(world->world, atom_path_node);
#endif
+ free((void*)chunk.buf);
sratom_free(sratom);
qsort(state->props, state->num_props, sizeof(Property), property_cmp);
@@ -627,17 +623,17 @@ lilv_state_new_from_file(LilvWorld* world,
return NULL;
}
- uint8_t* uri = (uint8_t*)lilv_strjoin("file://", path, NULL);
- SerdNode base = serd_node_from_string(SERD_URI, uri);
- SerdEnv* env = serd_env_new(&base);
- SordModel* model = sord_new(world->world, SORD_SPO, false);
- SerdReader* reader = sord_new_reader(model, env, SERD_TURTLE, NULL);
+ uint8_t* abs_path = (uint8_t*)lilv_path_absolute(path);
+ SerdNode node = serd_node_new_uri_from_path(abs_path, NULL, NULL);
+ SerdEnv* env = serd_env_new(&node);
+ SordModel* model = sord_new(world->world, SORD_SPO, false);
+ SerdReader* reader = sord_new_reader(model, env, SERD_TURTLE, NULL);
- serd_reader_read_file(reader, uri);
+ serd_reader_read_file(reader, node.buf);
SordNode* subject_node = (subject)
? subject->val.uri_val
- : sord_node_from_serd_node(world->world, env, &base, NULL, NULL);
+ : sord_node_from_serd_node(world->world, env, &node, NULL, NULL);
char* dirname = lilv_dirname(path);
char* real_path = lilv_realpath(dirname);
@@ -646,10 +642,11 @@ lilv_state_new_from_file(LilvWorld* world,
free(dirname);
free(real_path);
+ serd_node_free(&node);
+ free(abs_path);
serd_reader_free(reader);
sord_free(model);
serd_env_free(env);
- free(uri);
return state;
}
@@ -687,6 +684,7 @@ lilv_state_new_from_string(LilvWorld* world,
LilvState* state = new_state_from_model(world, map, model, s, NULL);
+ sord_iter_free(i);
serd_reader_free(reader);
sord_free(model);
serd_env_free(env);
@@ -695,35 +693,32 @@ lilv_state_new_from_string(LilvWorld* world,
}
static SerdWriter*
-ttl_writer(SerdSink sink, void* stream, const uint8_t* uri, SerdEnv** new_env)
+ttl_writer(SerdSink sink, void* stream, const SerdNode* base, SerdEnv** new_env)
{
- SerdURI base_uri = SERD_URI_NULL;
- SerdNode base = SERD_NODE_NULL;
- if (uri) {
- base = serd_node_new_uri_from_string(uri, NULL, &base_uri);
+ SerdURI base_uri = SERD_URI_NULL;
+ if (base) {
+ serd_uri_parse(base->buf, &base_uri);
}
-
- SerdEnv* env = serd_env_new(&base);
+
+ SerdEnv* env = serd_env_new(base);
set_prefixes(env);
SerdWriter* writer = serd_writer_new(
SERD_TURTLE,
- (SerdStyle)(SERD_STYLE_ABBREVIATED|SERD_STYLE_CURIED),
+ (SerdStyle)(SERD_STYLE_RESOLVED|SERD_STYLE_ABBREVIATED|SERD_STYLE_CURIED),
env,
&base_uri,
sink,
stream);
- serd_node_free(&base);
-
*new_env = env;
return writer;
}
static SerdWriter*
-ttl_file_writer(FILE* fd, const uint8_t* uri, SerdEnv** env)
+ttl_file_writer(FILE* fd, const SerdNode* node, SerdEnv** env)
{
- SerdWriter* writer = ttl_writer(serd_file_sink, fd, uri, env);
+ SerdWriter* writer = ttl_writer(serd_file_sink, fd, node, env);
fseek(fd, 0, SEEK_END);
if (ftell(fd) == 0) {
@@ -739,7 +734,7 @@ static int
add_state_to_manifest(const LilvNode* plugin_uri,
const char* manifest_path,
const char* state_uri,
- const char* state_file_uri)
+ const char* state_path)
{
FILE* fd = fopen((char*)manifest_path, "a");
if (!fd) {
@@ -748,29 +743,20 @@ add_state_to_manifest(const LilvNode* plugin_uri,
return 4;
}
- // Make path relative if it is in the same directory as manifest
- const char* last_slash = strrchr(state_file_uri, '/');
- if (last_slash) {
- const size_t len = last_slash - state_file_uri;
- if (!strncmp(manifest_path, state_file_uri, len)) {
- state_file_uri = last_slash + 1;
- }
- }
+ SerdNode file = serd_node_new_uri_from_path(USTR(state_path), 0, 0);
+ SerdNode manifest = serd_node_new_uri_from_path(USTR(manifest_path), 0, 0);
lilv_flock(fd, true);
- char* const manifest_uri = lilv_strjoin("file://", manifest_path, NULL);
- SerdEnv* env = NULL;
- SerdWriter* writer = ttl_file_writer(fd, USTR(manifest_uri), &env);
+ SerdEnv* env = NULL;
+ SerdWriter* writer = ttl_file_writer(fd, &manifest, &env);
if (!state_uri) {
- state_uri = state_file_uri;
+ state_uri = (const char*)file.buf;
}
- SerdNode s = serd_node_from_string(SERD_URI, USTR(state_uri));
- SerdNode file = serd_node_from_string(SERD_URI, USTR(state_file_uri));
-
// <state> a pset:Preset
+ SerdNode s = serd_node_from_string(SERD_URI, USTR(state_uri));
SerdNode p = serd_node_from_string(SERD_URI, USTR(LILV_NS_RDF "type"));
SerdNode o = serd_node_from_string(SERD_URI, USTR(NS_PSET "Preset"));
serd_writer_write_statement(writer, 0, NULL, &s, &p, &o, NULL, NULL);
@@ -785,9 +771,10 @@ add_state_to_manifest(const LilvNode* plugin_uri,
SERD_URI, USTR(lilv_node_as_string(plugin_uri)));
serd_writer_write_statement(writer, 0, NULL, &s, &p, &o, NULL, NULL);
+ serd_node_free(&file);
+ serd_node_free(&manifest);
serd_writer_free(writer);
serd_env_free(env);
- free(manifest_uri);
lilv_flock(fd, false);
fclose(fd);
@@ -885,7 +872,7 @@ lilv_state_write(LilvWorld* world,
Property* prop = &state->props[i];
const char* key = unmap->unmap(unmap->handle, prop->key);
- p = serd_node_from_string(SERD_URI, (const uint8_t*)key);
+ p = serd_node_from_string(SERD_URI, USTR(key));
if (prop->type == state->atom_Path && !dir) {
const char* abs_path = lilv_state_rel2abs(state, prop->value);
sratom_write(sratom, unmap, writer, SERD_ANON_CONT,
@@ -900,6 +887,7 @@ lilv_state_write(LilvWorld* world,
serd_writer_end_anon(writer, &state_node);
}
+ sratom_free(sratom);
return 0;
}
@@ -983,11 +971,19 @@ lilv_state_save(LilvWorld* world,
lilv_state_make_links(state, abs_dir);
// Write state to Turtle file
+ SerdNode file = serd_node_new_uri_from_path(USTR(path), NULL, NULL);
SerdEnv* env = NULL;
- SerdWriter* writer = ttl_file_writer(fd, USTR(path), &env);
+ SerdWriter* writer = ttl_file_writer(fd, &file, &env);
+
+ SerdNode node = SERD_NODE_NULL;
+ if (!uri) {
+ node = serd_node_new_uri_from_path(USTR(path), NULL, NULL);
+ uri = (const char*)node.buf;
+ }
int ret = lilv_state_write(world, map, unmap, state, writer, uri, dir);
+ serd_node_free(&file);
serd_writer_free(writer);
serd_env_free(env);
fclose(fd);
@@ -996,6 +992,7 @@ lilv_state_save(LilvWorld* world,
add_state_to_manifest(state->plugin_uri, manifest, uri, path);
}
+ serd_node_free(&node);
free(abs_dir);
free(manifest);
free(path);
@@ -1041,6 +1038,8 @@ lilv_state_free(LilvState* state)
free(state->label);
free(state->dir);
free(state->file_dir);
+ free(state->copy_dir);
+ free(state->link_dir);
free(state);
}
}
diff --git a/test/lilv_test.c b/test/lilv_test.c
index 1031685..6d5ba9d 100644
--- a/test/lilv_test.c
+++ b/test/lilv_test.c
@@ -617,6 +617,7 @@ test_plugin(void)
"http://lv2plug.in/ns/lv2core#latency");
LilvPort* latency_port = lilv_plugin_get_port_by_parameter(
plug, out_class, lv2_latency);
+ lilv_node_free(lv2_latency);
TEST_ASSERT(latency_port);
TEST_ASSERT(lilv_port_get_index(plug, latency_port) == 2);
@@ -1126,6 +1127,7 @@ map_uri(LV2_URID_Map_Handle handle,
}
}
+ assert(serd_uri_string_has_scheme((const uint8_t*)uri));
uris = (char**)realloc(uris, ++n_uris * sizeof(char*));
uris[n_uris - 1] = lilv_strdup(uri);
return n_uris;
@@ -1141,7 +1143,7 @@ unmap_uri(LV2_URID_Map_Handle handle,
return NULL;
}
-static const char* temp_dir = NULL;
+static char* temp_dir = NULL;
char*
lilv_make_path(LV2_State_Make_Path_Handle handle,
@@ -1153,11 +1155,15 @@ lilv_make_path(LV2_State_Make_Path_Handle handle,
int
test_state(void)
{
+ uint8_t* abs_bundle = (uint8_t*)lilv_path_absolute(LILV_TEST_BUNDLE);
+ SerdNode bundle = serd_node_new_uri_from_path(abs_bundle, 0, 0);
LilvWorld* world = lilv_world_new();
- LilvNode* bundle_uri = lilv_new_uri(world, LILV_TEST_BUNDLE);
+ LilvNode* bundle_uri = lilv_new_uri(world, (const char*)bundle.buf);
LilvNode* plugin_uri = lilv_new_uri(world,
"http://example.org/lilv-test-plugin");
lilv_world_load_bundle(world, bundle_uri);
+ free(abs_bundle);
+ serd_node_free(&bundle);
const LilvPlugins* plugins = lilv_world_get_all_plugins(world);
const LilvPlugin* plugin = lilv_plugins_get_by_uri(plugins, plugin_uri);
@@ -1187,9 +1193,9 @@ test_state(void)
temp_dir = lilv_realpath("temp");
const char* file_dir = NULL;
- const char* copy_dir = NULL;
- const char* link_dir = NULL;
- const char* save_dir = NULL;
+ char* copy_dir = NULL;
+ char* link_dir = NULL;
+ char* save_dir = NULL;
// Get instance state state
LilvState* state = lilv_state_new_from_instance(
@@ -1215,6 +1221,7 @@ test_state(void)
// Ensure they are equal
TEST_ASSERT(lilv_state_equals(state, from_str));
+ free(state1_str);
const LilvNode* state_plugin_uri = lilv_state_get_plugin_uri(state);
TEST_ASSERT(lilv_node_equals(state_plugin_uri, plugin_uri));
@@ -1248,35 +1255,41 @@ test_state(void)
// Save state to a directory
int ret = lilv_state_save(world, &map, &unmap, state, NULL,
- "./state.lv2", "state.ttl");
+ "state.lv2", "state.ttl");
TEST_ASSERT(!ret);
// Load state from directory
LilvState* state5 = lilv_state_new_from_file(world, &map, NULL,
- "./state.lv2/state.ttl");
+ "state.lv2/state.ttl");
TEST_ASSERT(lilv_state_equals(state, state5)); // Round trip accuracy
// Save state with URI to a directory
const char* state_uri = "http://example.org/state";
ret = lilv_state_save(world, &map, &unmap, state, state_uri,
- "./state6.lv2", "state6.ttl");
+ "state6.lv2", "state6.ttl");
TEST_ASSERT(!ret);
// Load default bundle into world and load state from it
- LilvNode* test_state_bundle = lilv_new_uri(world, "./state6.lv2/");
+ uint8_t* state6_path = (uint8_t*)lilv_path_absolute("state6.lv2/");
+ SerdNode state6_uri = serd_node_new_uri_from_path(state6_path, 0, 0);
+ LilvNode* test_state_bundle = lilv_new_uri(world, (const char*)state6_uri.buf);
LilvNode* test_state_node = lilv_new_uri(world, state_uri);
lilv_world_load_bundle(world, test_state_bundle);
lilv_world_load_resource(world, test_state_node);
+ serd_node_free(&state6_uri);
+ free(state6_path);
LilvState* state6 = lilv_state_new_from_world(world, &map, test_state_node);
TEST_ASSERT(lilv_state_equals(state, state6)); // Round trip accuracy
+ lilv_node_free(test_state_bundle);
+ lilv_node_free(test_state_node);
unsetenv("LV2_STATE_BUNDLE");
// Make directories and test files support
mkdir("temp", 0700);
- file_dir = temp_dir = lilv_realpath("temp");
+ file_dir = temp_dir;
mkdir("files", 0700);
copy_dir = lilv_realpath("files");
mkdir("links", 0700);
@@ -1342,12 +1355,12 @@ test_state(void)
// Save state to a (different) directory again
ret = lilv_state_save(world, &map, &unmap, fstate, NULL,
- "./fstate6.lv2", "fstate6.ttl");
+ "fstate6.lv2", "fstate6.ttl");
TEST_ASSERT(!ret);
// Reload it and ensure it's identical to the other loaded version
LilvState* fstate6 = lilv_state_new_from_file(world, &map, NULL,
- "./fstate6.lv2/fstate6.ttl");
+ "fstate6.lv2/fstate6.ttl");
TEST_ASSERT(lilv_state_equals(fstate4, fstate6));
// Run, changing rec file (without changing size)
@@ -1362,12 +1375,12 @@ test_state(void)
// Save the changed state to a (different) directory again
ret = lilv_state_save(world, &map, &unmap, fstate7, NULL,
- "./fstate7.lv2", "fstate7.ttl");
+ "fstate7.lv2", "fstate7.ttl");
TEST_ASSERT(!ret);
// Reload it and ensure it's changed
LilvState* fstate72 = lilv_state_new_from_file(world, &map, NULL,
- "./fstate7.lv2/fstate7.ttl");
+ "fstate7.lv2/fstate7.ttl");
TEST_ASSERT(lilv_state_equals(fstate72, fstate7));
TEST_ASSERT(!lilv_state_equals(fstate6, fstate72));
@@ -1402,6 +1415,9 @@ test_state(void)
lilv_node_free(plugin_uri);
lilv_node_free(bundle_uri);
lilv_world_free(world);
+ free(link_dir);
+ free(copy_dir);
+ free(temp_dir);
cleanup_uris();
return 1;