diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/instance.c | 2 | ||||
-rw-r--r-- | src/lilv_internal.h | 8 | ||||
-rw-r--r-- | src/node.c | 26 | ||||
-rw-r--r-- | src/state.c | 184 | ||||
-rw-r--r-- | src/world.c | 2 |
5 files changed, 176 insertions, 46 deletions
diff --git a/src/instance.c b/src/instance.c index e9d4591..4823f59 100644 --- a/src/instance.c +++ b/src/instance.c @@ -27,6 +27,8 @@ lilv_plugin_instantiate(const LilvPlugin* plugin, double sample_rate, const LV2_Feature*const* features) { + lilv_plugin_load_if_necessary(plugin); + LilvInstance* result = NULL; const LV2_Feature** local_features = NULL; diff --git a/src/lilv_internal.h b/src/lilv_internal.h index 75e21a2..9f19c1c 100644 --- a/src/lilv_internal.h +++ b/src/lilv_internal.h @@ -150,6 +150,7 @@ struct LilvWorldImpl { SordNode* rdfs_label_node; SordNode* rdfs_seealso_node; SordNode* rdfs_subclassof_node; + SordNode* xsd_base64Binary_node; SordNode* xsd_boolean_node; SordNode* xsd_decimal_node; SordNode* xsd_double_node; @@ -168,7 +169,8 @@ typedef enum { LILV_VALUE_INT, LILV_VALUE_FLOAT, LILV_VALUE_BOOL, - LILV_VALUE_BLANK + LILV_VALUE_BLANK, + LILV_VALUE_BLOB } LilvNodeType; struct LilvNodeImpl { @@ -179,6 +181,10 @@ struct LilvNodeImpl { float float_val; bool bool_val; SordNode* uri_val; + struct { + void* buf; + size_t size; + } blob_val; } val; LilvNodeType type; }; @@ -21,7 +21,7 @@ #include "lilv_internal.h" static void -lilv_node_set_numerics_from_string(LilvNode* val) +lilv_node_set_numerics_from_string(LilvNode* val, size_t len) { char* endptr; @@ -39,6 +39,9 @@ lilv_node_set_numerics_from_string(LilvNode* val) case LILV_VALUE_BOOL: val->val.bool_val = (!strcmp(val->str_val, "true")); break; + case LILV_VALUE_BLOB: + val->val.blob_val.buf = serd_base64_decode( + (const uint8_t*)val->str_val, len, &val->val.blob_val.size); } } @@ -66,6 +69,7 @@ lilv_node_new(LilvWorld* world, LilvNodeType type, const char* str) case LILV_VALUE_INT: case LILV_VALUE_FLOAT: case LILV_VALUE_BOOL: + case LILV_VALUE_BLOB: val->str_val = lilv_strdup(str); break; } @@ -80,6 +84,7 @@ lilv_node_new_from_node(LilvWorld* world, const SordNode* node) LilvNode* result = NULL; SordNode* datatype_uri = NULL; LilvNodeType type = LILV_VALUE_STRING; + size_t len = 0; switch (sord_node_get_type(node)) { case SORD_URI: @@ -106,19 +111,15 @@ lilv_node_new_from_node(LilvWorld* world, const SordNode* node) type = LILV_VALUE_FLOAT; else if (sord_node_equals(datatype_uri, world->xsd_integer_node)) type = LILV_VALUE_INT; + else if (sord_node_equals(datatype_uri, world->xsd_base64Binary_node)) + type = LILV_VALUE_BLOB; else LILV_ERRORF("Unknown datatype `%s'\n", sord_node_get_string(datatype_uri)); } - result = lilv_node_new(world, type, (const char*)sord_node_get_string(node)); - switch (result->type) { - case LILV_VALUE_INT: - case LILV_VALUE_FLOAT: - case LILV_VALUE_BOOL: - lilv_node_set_numerics_from_string(result); - default: - break; - } + result = lilv_node_new( + world, type, (const char*)sord_node_get_string_counted(node, &len)); + lilv_node_set_numerics_from_string(result, len); break; default: assert(false); @@ -237,6 +238,10 @@ lilv_node_equals(const LilvNode* value, const LilvNode* other) return (value->val.float_val == other->val.float_val); case LILV_VALUE_BOOL: return (value->val.bool_val == other->val.bool_val); + case LILV_VALUE_BLOB: + return (value->val.blob_val.size == other->val.blob_val.size) + && !memcmp(value->val.blob_val.buf, other->val.blob_val.buf, + value->val.blob_val.size); } return false; /* shouldn't get here */ @@ -263,6 +268,7 @@ lilv_node_get_turtle_token(const LilvNode* value) break; case LILV_VALUE_STRING: case LILV_VALUE_BOOL: + case LILV_VALUE_BLOB: result = lilv_strdup(value->str_val); break; case LILV_VALUE_INT: diff --git a/src/state.c b/src/state.c index aae3fab..f50557f 100644 --- a/src/state.c +++ b/src/state.c @@ -73,6 +73,14 @@ property_cmp(const void* a, const void* b) return pa->key - pb->key; } +static int +value_cmp(const void* a, const void* b) +{ + const PortValue* pa = (const PortValue*)a; + const PortValue* pb = (const PortValue*)b; + return strcmp(pa->symbol, pb->symbol); +} + LILV_API const LilvNode* lilv_state_get_plugin_uri(const LilvState* state) @@ -131,7 +139,7 @@ store_callback(void* handle, state->props = realloc(state->props, (++state->num_props) * sizeof(Property)); Property* const prop = &state->props[state->num_props - 1]; - + prop->value = malloc(size); memcpy(prop->value, value, size); @@ -183,10 +191,12 @@ lilv_state_new_from_instance(const LilvPlugin* plugin, #endif // HAVE_LV2_STATE qsort(state->props, state->num_props, sizeof(Property), property_cmp); + qsort(state->values, state->num_values, sizeof(PortValue), value_cmp); return state; } +#ifdef HAVE_LV2_STATE static const void* retrieve_callback(void* handle, uint32_t key, @@ -208,6 +218,7 @@ retrieve_callback(void* handle, } return NULL; } +#endif // HAVE_LV2_STATE LILV_API void @@ -261,9 +272,6 @@ property_from_node(LilvWorld* world, prop->type = map->map(map->handle, NS_ATOM "URID"); prop->size = sizeof(uint32_t); break; - case LILV_VALUE_BLANK: - // TODO: Hmm... - break; case LILV_VALUE_STRING: prop->size = strlen(str) + 1; prop->value = malloc(prop->size); @@ -288,8 +296,11 @@ property_from_node(LilvWorld* world, prop->type = map->map(map->handle, NS_ATOM "Float"); prop->size = sizeof(float); break; + case LILV_VALUE_BLANK: + case LILV_VALUE_BLOB: + // TODO: Blank nodes in state + break; } - prop->flags = LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE; } static LilvState* @@ -302,9 +313,9 @@ new_state_from_model(LilvWorld* world, memset(state, '\0', sizeof(LilvState)); // Get the plugin URI this state applies to - const SordQuad pat1 = { + const SordQuad upat = { node, world->lv2_appliesTo_node, NULL, NULL }; - SordIter* i = sord_find(model, pat1); + SordIter* i = sord_find(model, upat); if (i) { state->plugin_uri = lilv_node_new_from_node( world, lilv_match_object(i)); @@ -314,9 +325,19 @@ new_state_from_model(LilvWorld* world, sord_node_get_string(node)); } + // Get the state label + const SordQuad lpat = { + node, world->rdfs_label_node, NULL, NULL }; + i = sord_find(model, lpat); + if (i) { + state->label = lilv_strdup( + (const char*)sord_node_get_string(lilv_match_object(i))); + sord_iter_free(i); + } + // Get port values - const SordQuad pat2 = { node, world->lv2_port_node, NULL, NULL }; - SordIter* ports = sord_find(model, pat2); + const SordQuad ppat = { node, world->lv2_port_node, NULL, NULL }; + SordIter* ports = sord_find(model, ppat); FOREACH_MATCH(ports) { const SordNode* port = lilv_match_object(ports); const SordNode* label = get_one(model, port, world->rdfs_label_node); @@ -346,31 +367,53 @@ new_state_from_model(LilvWorld* world, SordNode* statep = sord_new_uri(world->world, USTR(NS_STATE "state")); const SordNode* state_node = get_one(model, node, statep); if (state_node) { - const SordQuad pat3 = { state_node, NULL, NULL }; - SordIter* props = sord_find(model, pat3); + const SordQuad spat = { state_node, NULL, NULL }; + SordIter* props = sord_find(model, spat); FOREACH_MATCH(props) { - const SordNode* p = lilv_match_predicate(props); - const SordNode* o = lilv_match_object(props); - LilvNode* onode = lilv_node_new_from_node(world, o); - - Property prop = { NULL, 0, 0, 0, 0 }; + const SordNode* p = lilv_match_predicate(props); + const SordNode* o = lilv_match_object(props); + + uint32_t flags = 0; +#ifdef HAVE_LV2_STATE + flags = LV2_STATE_IS_POD|LV2_STATE_IS_PORTABLE; +#endif + Property prop = { NULL, 0, 0, 0, flags }; prop.key = map->map(map->handle, (const char*)sord_node_get_string(p)); - property_from_node(world, map, onode, &prop); + + if (sord_node_get_type(o) == SORD_BLANK) { + const SordNode* type = get_one(model, o, world->rdf_a_node); + const SordNode* value = get_one(model, o, world->rdf_value_node); + if (type && value) { + size_t len; + const uint8_t* b64 = sord_node_get_string_counted(value, &len); + prop.value = serd_base64_decode(b64, len, &prop.size); + prop.type = map->map(map->handle, + (const char*)sord_node_get_string(type)); + } else { + LILV_ERRORF("Unable to parse blank node property <%p>\n", + sord_node_get_string(p)); + } + } else { + LilvNode* onode = lilv_node_new_from_node(world, o); + property_from_node(world, map, onode, &prop); + lilv_node_free(onode); + } + if (prop.value) { state->props = realloc( state->props, (++state->num_props) * sizeof(Property)); state->props[state->num_props - 1] = prop; } - lilv_node_free(onode); } sord_iter_free(props); } sord_node_free(world->world, statep); qsort(state->props, state->num_props, sizeof(Property), property_cmp); - + qsort(state->values, state->num_values, sizeof(PortValue), value_cmp); + return state; } @@ -425,10 +468,14 @@ lilv_state_new_from_file(LilvWorld* world, } static LilvNode* -node_from_property(LilvWorld* world, const char* type, void* value, size_t size) +node_from_property(LilvWorld* world, LV2_URID_Unmap* unmap, + const char* type, void* value, size_t size) { if (!strcmp(type, NS_ATOM "String")) { return lilv_new_string(world, (const char*)value); + } else if (!strcmp(type, NS_ATOM "URID")) { + const char* str = unmap->unmap(unmap->handle, *(uint32_t*)value); + return lilv_new_uri(world, str); } else if (!strcmp(type, NS_ATOM "Int32")) { if (size == sizeof(int32_t)) { return lilv_new_int(world, *(int32_t*)value); @@ -491,8 +538,8 @@ add_state_to_manifest(const LilvNode* plugin_uri, { FILE* fd = fopen((char*)manifest_path, "a"); if (!fd) { - fprintf(stderr, "error: Failed to open %s (%s)\n", - manifest_path, strerror(errno)); + LILV_ERRORF("Failed to open %s (%s)\n", + manifest_path, strerror(errno)); return 4; } @@ -508,6 +555,7 @@ add_state_to_manifest(const LilvNode* plugin_uri, SerdEnv* env = serd_env_new(NULL); serd_env_set_prefix_from_strings(env, USTR("lv2"), USTR(LILV_NS_LV2)); serd_env_set_prefix_from_strings(env, USTR("pset"), USTR(NS_PSET)); + serd_env_set_prefix_from_strings(env, USTR("rdf"), USTR(LILV_NS_RDF)); serd_env_set_prefix_from_strings(env, USTR("rdfs"), USTR(LILV_NS_RDFS)); #if defined(HAVE_LOCKF) && defined(HAVE_FILENO) @@ -607,15 +655,14 @@ lilv_state_save(LilvWorld* world, const char* const home = getenv("HOME"); if (!home) { - fprintf(stderr, "error: $HOME is undefined\n"); + LILV_ERROR("$HOME is undefined\n"); return 2; } // Create ~/.lv2/ char* const lv2dir = lilv_strjoin(home, "/.lv2/", NULL); if (mkdir(lv2dir, 0755) && errno != EEXIST) { - fprintf(stderr, "error: Unable to create %s (%s)\n", - lv2dir, strerror(errno)); + LILV_ERRORF("Unable to create %s (%s)\n", lv2dir, strerror(errno)); free(lv2dir); return 3; } @@ -623,13 +670,12 @@ lilv_state_save(LilvWorld* world, // Create ~/.lv2/presets.lv2/ char* const bundle = lilv_strjoin(lv2dir, "presets.lv2/", NULL); if (mkdir(bundle, 0755) && errno != EEXIST) { - fprintf(stderr, "error: Unable to create %s (%s)\n", - lv2dir, strerror(errno)); + LILV_ERRORF("Unable to create %s (%s)\n", lv2dir, strerror(errno)); free(lv2dir); free(bundle); return 4; } - + char* const filename = pathify(state->label); default_path = lilv_strjoin(bundle, filename, ".ttl", NULL); default_manifest_path = lilv_strjoin(bundle, "manifest.ttl", NULL); @@ -648,8 +694,7 @@ lilv_state_save(LilvWorld* world, FILE* fd = fopen(path, "w"); if (!fd) { - fprintf(stderr, "error: Failed to open %s (%s)\n", - path, strerror(errno)); + LILV_ERRORF("Failed to open %s (%s)\n", path, strerror(errno)); free(default_path); free(default_manifest_path); return 4; @@ -658,6 +703,7 @@ lilv_state_save(LilvWorld* world, SerdEnv* env = serd_env_new(NULL); serd_env_set_prefix_from_strings(env, USTR("lv2"), USTR(LILV_NS_LV2)); serd_env_set_prefix_from_strings(env, USTR("pset"), USTR(NS_PSET)); + serd_env_set_prefix_from_strings(env, USTR("rdf"), USTR(LILV_NS_RDF)); serd_env_set_prefix_from_strings(env, USTR("rdfs"), USTR(LILV_NS_RDFS)); serd_env_set_prefix_from_strings(env, USTR("state"), USTR(NS_STATE)); @@ -744,20 +790,50 @@ lilv_state_save(LilvWorld* world, LILV_WARNF("Failed to unmap property key `%d'\n", prop->key); } else if (!type) { LILV_WARNF("Failed to unmap property type `%d'\n", prop->type); - } else if (!(prop->flags & LV2_STATE_IS_PORTABLE)) { +#ifdef HAVE_LV2_STATE + } else if (!(prop->flags & LV2_STATE_IS_PORTABLE) + || !(prop->flags & LV2_STATE_IS_POD)) { LILV_WARNF("Unable to save non-portable property <%s>\n", type); +#endif } else { + SerdNode t; + p = serd_node_from_string(SERD_URI, USTR(key)); LilvNode* const node = node_from_property( - world, type, prop->value, prop->size); + world, unmap, type, prop->value, prop->size); if (node) { - p = serd_node_from_string(SERD_URI, USTR(key)); - SerdNode t; node_to_serd(node, &o, &t); serd_writer_write_statement( writer, SERD_ANON_CONT, NULL, &state_node, &p, &o, &t, NULL); } else { - LILV_WARNF("Unable to save property type <%s>\n", type); + char name[16]; + snprintf(name, sizeof(name), "b%u", i); + const SerdNode blank = serd_node_from_string( + SERD_BLANK, (const uint8_t*)name); + + // <state> <key> [ + serd_writer_write_statement( + writer, SERD_ANON_O_BEGIN, NULL, + &state_node, &p, &blank, NULL, NULL); + + // rdf:type <type> + p = serd_node_from_string(SERD_URI, USTR(LILV_NS_RDF "type")); + o = serd_node_from_string(SERD_URI, USTR(type)); + serd_writer_write_statement( + writer, SERD_ANON_CONT, NULL, + &blank, &p, &o, NULL, NULL); + + // rdf:value "string"^^<xsd:base64Binary> + SerdNode blob = serd_node_new_blob(prop->value, prop->size, true); + p = serd_node_from_string(SERD_URI, USTR(LILV_NS_RDF "value")); + t = serd_node_from_string(SERD_URI, + USTR(LILV_NS_XSD "base64Binary")); + serd_writer_write_statement( + writer, SERD_ANON_CONT, NULL, + &blank, &p, &blob, &t, NULL); + serd_node_free(&blob); + + serd_writer_end_anon(writer, &blank); // ] } } } @@ -781,6 +857,44 @@ lilv_state_save(LilvWorld* world, } LILV_API +bool +lilv_state_equals(const LilvState* a, const LilvState* b) +{ + if (!lilv_node_equals(a->plugin_uri, b->plugin_uri) + || (a->label && !b->label) + || (b->label && !a->label) + || (a->label && b->label && strcmp(a->label, b->label)) + || a->num_props != b->num_props + || a->num_values != b->num_values) { + return false; + } + + for (uint32_t i = 0; i < a->num_values; ++i) { + PortValue* const av = &a->values[i]; + PortValue* const bv = &b->values[i]; + if (strcmp(av->symbol, bv->symbol)) { + return false; + } else if (!lilv_node_equals(av->value, bv->value)) { + return false; + } + } + + for (uint32_t i = 0; i < a->num_props; ++i) { + Property* const ap = &a->props[i]; + Property* const bp = &b->props[i]; + if (ap->size != bp->size + || ap->key != bp->key + || ap->type != bp->type + || ap->flags != bp->flags + || memcmp(ap->value, bp->value, ap->size)) { + return false; + } + } + + return true; +} + +LILV_API void lilv_state_free(LilvState* state) { diff --git a/src/world.c b/src/world.c index af20bc3..2029136 100644 --- a/src/world.c +++ b/src/world.c @@ -77,6 +77,7 @@ lilv_world_new(void) world->rdfs_label_node = NEW_URI(LILV_NS_RDFS "label"); world->rdfs_seealso_node = NEW_URI(LILV_NS_RDFS "seeAlso"); world->rdfs_subclassof_node = NEW_URI(LILV_NS_RDFS "subClassOf"); + world->xsd_base64Binary_node = NEW_URI(LILV_NS_XSD "base64Binary"); world->xsd_boolean_node = NEW_URI(LILV_NS_XSD "boolean"); world->xsd_decimal_node = NEW_URI(LILV_NS_XSD "decimal"); world->xsd_double_node = NEW_URI(LILV_NS_XSD "double"); @@ -135,6 +136,7 @@ lilv_world_free(LilvWorld* world) sord_node_free(world->world, world->rdfs_label_node); sord_node_free(world->world, world->rdfs_seealso_node); sord_node_free(world->world, world->rdfs_subclassof_node); + sord_node_free(world->world, world->xsd_base64Binary_node); sord_node_free(world->world, world->xsd_boolean_node); sord_node_free(world->world, world->xsd_decimal_node); sord_node_free(world->world, world->xsd_double_node); |