diff options
Diffstat (limited to 'lv2/atom')
-rw-r--r-- | lv2/atom/atom-test-utils.c | 73 | ||||
-rw-r--r-- | lv2/atom/atom-test.c | 366 | ||||
-rw-r--r-- | lv2/atom/atom.h | 260 | ||||
-rw-r--r-- | lv2/atom/atom.meta.ttl | 552 | ||||
-rw-r--r-- | lv2/atom/atom.ttl | 250 | ||||
-rw-r--r-- | lv2/atom/forge-overflow-test.c | 235 | ||||
-rw-r--r-- | lv2/atom/forge.h | 683 | ||||
-rw-r--r-- | lv2/atom/manifest.ttl | 9 | ||||
-rw-r--r-- | lv2/atom/meson.build | 61 | ||||
-rw-r--r-- | lv2/atom/util.h | 523 |
10 files changed, 0 insertions, 3012 deletions
diff --git a/lv2/atom/atom-test-utils.c b/lv2/atom/atom-test-utils.c deleted file mode 100644 index ae368c8..0000000 --- a/lv2/atom/atom-test-utils.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - Copyright 2012-2018 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 - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "lv2/atom/atom.h" -#include "lv2/atom/forge.h" -#include "lv2/atom/util.h" -#include "lv2/log/log.h" -#include "lv2/urid/urid.h" - -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> - -static char** uris = NULL; -static uint32_t n_uris = 0; - -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) -{ - for (uint32_t i = 0; i < n_uris; ++i) { - if (!strcmp(uris[i], uri)) { - return i + 1; - } - } - - uris = (char**)realloc(uris, ++n_uris * sizeof(char*)); - uris[n_uris - 1] = copy_string(uri); - return n_uris; -} - -static void -free_urid_map(void) -{ - for (uint32_t i = 0; i < n_uris; ++i) { - free(uris[i]); - } - - free(uris); -} - -LV2_LOG_FUNC(1, 2) -static int -test_fail(const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - fprintf(stderr, "error: "); - vfprintf(stderr, fmt, args); - va_end(args); - return 1; -} diff --git a/lv2/atom/atom-test.c b/lv2/atom/atom-test.c deleted file mode 100644 index 230a7cd..0000000 --- a/lv2/atom/atom-test.c +++ /dev/null @@ -1,366 +0,0 @@ -/* - Copyright 2012-2015 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 - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "lv2/atom/atom-test-utils.c" -#include "lv2/atom/atom.h" -#include "lv2/atom/forge.h" -#include "lv2/atom/util.h" -#include "lv2/urid/urid.h" - -#include <stdbool.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - -int -main(void) -{ - LV2_URID_Map map = {NULL, urid_map}; - LV2_Atom_Forge forge; - lv2_atom_forge_init(&forge, &map); - - LV2_URID eg_Object = urid_map(NULL, "http://example.org/Object"); - LV2_URID eg_one = urid_map(NULL, "http://example.org/one"); - LV2_URID eg_two = urid_map(NULL, "http://example.org/two"); - LV2_URID eg_three = urid_map(NULL, "http://example.org/three"); - LV2_URID eg_four = urid_map(NULL, "http://example.org/four"); - LV2_URID eg_true = urid_map(NULL, "http://example.org/true"); - LV2_URID eg_false = urid_map(NULL, "http://example.org/false"); - LV2_URID eg_path = urid_map(NULL, "http://example.org/path"); - LV2_URID eg_uri = urid_map(NULL, "http://example.org/uri"); - LV2_URID eg_urid = urid_map(NULL, "http://example.org/urid"); - LV2_URID eg_string = urid_map(NULL, "http://example.org/string"); - LV2_URID eg_literal = urid_map(NULL, "http://example.org/literal"); - LV2_URID eg_tuple = urid_map(NULL, "http://example.org/tuple"); - LV2_URID eg_vector = urid_map(NULL, "http://example.org/vector"); - LV2_URID eg_vector2 = urid_map(NULL, "http://example.org/vector2"); - LV2_URID eg_seq = urid_map(NULL, "http://example.org/seq"); - -#define BUF_SIZE 1024 -#define NUM_PROPS 15 - - uint8_t buf[BUF_SIZE]; - lv2_atom_forge_set_buffer(&forge, buf, BUF_SIZE); - - LV2_Atom_Forge_Frame obj_frame; - LV2_Atom* obj = lv2_atom_forge_deref( - &forge, lv2_atom_forge_object(&forge, &obj_frame, 0, eg_Object)); - - // eg_one = (Int)1 - lv2_atom_forge_key(&forge, eg_one); - LV2_Atom_Int* one = - (LV2_Atom_Int*)lv2_atom_forge_deref(&forge, lv2_atom_forge_int(&forge, 1)); - if (one->body != 1) { - return test_fail("%d != 1\n", one->body); - } - - // eg_two = (Long)2 - lv2_atom_forge_key(&forge, eg_two); - LV2_Atom_Long* two = (LV2_Atom_Long*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_long(&forge, 2)); - if (two->body != 2) { - return test_fail("%ld != 2\n", (long)two->body); - } - - // eg_three = (Float)3.0 - lv2_atom_forge_key(&forge, eg_three); - LV2_Atom_Float* three = (LV2_Atom_Float*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_float(&forge, 3.0f)); - if (three->body != 3) { - return test_fail("%f != 3\n", three->body); - } - - // eg_four = (Double)4.0 - lv2_atom_forge_key(&forge, eg_four); - LV2_Atom_Double* four = (LV2_Atom_Double*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_double(&forge, 4.0)); - if (four->body != 4) { - return test_fail("%f != 4\n", four->body); - } - - // eg_true = (Bool)1 - lv2_atom_forge_key(&forge, eg_true); - LV2_Atom_Bool* t = (LV2_Atom_Bool*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_bool(&forge, true)); - if (t->body != 1) { - return test_fail("%d != 1 (true)\n", t->body); - } - - // eg_false = (Bool)0 - lv2_atom_forge_key(&forge, eg_false); - LV2_Atom_Bool* f = (LV2_Atom_Bool*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_bool(&forge, false)); - if (f->body != 0) { - return test_fail("%d != 0 (false)\n", f->body); - } - - // eg_path = (Path)"/foo/bar" - const char* pstr = "/foo/bar"; - const uint32_t pstr_len = (uint32_t)strlen(pstr); - lv2_atom_forge_key(&forge, eg_path); - LV2_Atom_String* path = (LV2_Atom_String*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_uri(&forge, pstr, pstr_len)); - char* pbody = (char*)LV2_ATOM_BODY(path); - if (strcmp(pbody, pstr)) { - return test_fail("%s != \"%s\"\n", pbody, pstr); - } - - // eg_uri = (URI)"http://example.org/value" - const char* ustr = "http://example.org/value"; - const uint32_t ustr_len = (uint32_t)strlen(ustr); - lv2_atom_forge_key(&forge, eg_uri); - LV2_Atom_String* uri = (LV2_Atom_String*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_uri(&forge, ustr, ustr_len)); - char* ubody = (char*)LV2_ATOM_BODY(uri); - if (strcmp(ubody, ustr)) { - return test_fail("%s != \"%s\"\n", ubody, ustr); - } - - // eg_urid = (URID)"http://example.org/value" - LV2_URID eg_value = urid_map(NULL, "http://example.org/value"); - lv2_atom_forge_key(&forge, eg_urid); - LV2_Atom_URID* urid = (LV2_Atom_URID*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_urid(&forge, eg_value)); - if (urid->body != eg_value) { - return test_fail("%u != %u\n", urid->body, eg_value); - } - - // eg_string = (String)"hello" - lv2_atom_forge_key(&forge, eg_string); - LV2_Atom_String* string = (LV2_Atom_String*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_string(&forge, "hello", strlen("hello"))); - char* sbody = (char*)LV2_ATOM_BODY(string); - if (strcmp(sbody, "hello")) { - return test_fail("%s != \"hello\"\n", sbody); - } - - // eg_literal = (Literal)"hello"@fr - lv2_atom_forge_key(&forge, eg_literal); - LV2_Atom_Literal* literal = (LV2_Atom_Literal*)lv2_atom_forge_deref( - &forge, - lv2_atom_forge_literal(&forge, - "bonjour", - strlen("bonjour"), - 0, - urid_map(NULL, "http://lexvo.org/id/term/fr"))); - char* lbody = (char*)LV2_ATOM_CONTENTS(LV2_Atom_Literal, literal); - if (strcmp(lbody, "bonjour")) { - return test_fail("%s != \"bonjour\"\n", lbody); - } - - // eg_tuple = "foo",true - lv2_atom_forge_key(&forge, eg_tuple); - LV2_Atom_Forge_Frame tuple_frame; - LV2_Atom_Tuple* tuple = (LV2_Atom_Tuple*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_tuple(&forge, &tuple_frame)); - LV2_Atom_String* tup0 = (LV2_Atom_String*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_string(&forge, "foo", strlen("foo"))); - LV2_Atom_Bool* tup1 = (LV2_Atom_Bool*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_bool(&forge, true)); - lv2_atom_forge_pop(&forge, &tuple_frame); - LV2_Atom* i = lv2_atom_tuple_begin(tuple); - if (lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) { - return test_fail("Tuple iterator is empty\n"); - } - LV2_Atom* tup0i = i; - if (!lv2_atom_equals((LV2_Atom*)tup0, tup0i)) { - return test_fail("Corrupt tuple element 0\n"); - } - i = lv2_atom_tuple_next(i); - if (lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) { - return test_fail("Premature end of tuple iterator\n"); - } - LV2_Atom* tup1i = i; - if (!lv2_atom_equals((LV2_Atom*)tup1, tup1i)) { - return test_fail("Corrupt tuple element 1\n"); - } - i = lv2_atom_tuple_next(i); - if (!lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) { - return test_fail("Tuple iter is not at end\n"); - } - - // eg_vector = (Vector<Int>)1,2,3,4 - lv2_atom_forge_key(&forge, eg_vector); - int32_t elems[] = {1, 2, 3, 4}; - LV2_Atom_Vector* vector = (LV2_Atom_Vector*)lv2_atom_forge_deref( - &forge, - lv2_atom_forge_vector(&forge, sizeof(int32_t), forge.Int, 4, elems)); - void* vec_body = LV2_ATOM_CONTENTS(LV2_Atom_Vector, vector); - if (memcmp(elems, vec_body, sizeof(elems))) { - return test_fail("Corrupt vector\n"); - } - - // eg_vector2 = (Vector<Int>)1,2,3,4 - lv2_atom_forge_key(&forge, eg_vector2); - LV2_Atom_Forge_Frame vec_frame; - LV2_Atom_Vector* vector2 = (LV2_Atom_Vector*)lv2_atom_forge_deref( - &forge, - lv2_atom_forge_vector_head(&forge, &vec_frame, sizeof(int32_t), forge.Int)); - for (unsigned e = 0; e < sizeof(elems) / sizeof(int32_t); ++e) { - lv2_atom_forge_int(&forge, elems[e]); - } - lv2_atom_forge_pop(&forge, &vec_frame); - if (!lv2_atom_equals(&vector->atom, &vector2->atom)) { - return test_fail("Vector != Vector2\n"); - } - - // eg_seq = (Sequence)1, 2 - lv2_atom_forge_key(&forge, eg_seq); - LV2_Atom_Forge_Frame seq_frame; - LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)lv2_atom_forge_deref( - &forge, lv2_atom_forge_sequence_head(&forge, &seq_frame, 0)); - lv2_atom_forge_frame_time(&forge, 0); - lv2_atom_forge_int(&forge, 1); - lv2_atom_forge_frame_time(&forge, 1); - lv2_atom_forge_int(&forge, 2); - lv2_atom_forge_pop(&forge, &seq_frame); - - lv2_atom_forge_pop(&forge, &obj_frame); - - // Test equality - LV2_Atom_Int itwo = {{forge.Int, sizeof(int32_t)}, 2}; - if (lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)two)) { - return test_fail("1 == 2.0\n"); - } else if (lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)&itwo)) { - return test_fail("1 == 2\n"); - } else if (!lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)one)) { - return test_fail("1 != 1\n"); - } - - unsigned n_events = 0; - LV2_ATOM_SEQUENCE_FOREACH (seq, ev) { - if (ev->time.frames != n_events) { - return test_fail("Corrupt event %u has bad time\n", n_events); - } else if (ev->body.type != forge.Int) { - return test_fail("Corrupt event %u has bad type\n", n_events); - } else if (((LV2_Atom_Int*)&ev->body)->body != (int)n_events + 1) { - return test_fail("Event %u != %u\n", n_events, n_events + 1); - } - ++n_events; - } - - int n_props = 0; - LV2_ATOM_OBJECT_FOREACH ((LV2_Atom_Object*)obj, prop) { - if (!prop->key) { - return test_fail("Corrupt property %d has no key\n", n_props); - } else if (prop->context) { - return test_fail("Corrupt property %d has context\n", n_props); - } - ++n_props; - } - - if (n_props != NUM_PROPS) { - return test_fail( - "Corrupt object has %d properties != %d\n", n_props, NUM_PROPS); - } - - struct { - const LV2_Atom* one; - const LV2_Atom* two; - const LV2_Atom* three; - const LV2_Atom* four; - const LV2_Atom* affirmative; - const LV2_Atom* negative; - const LV2_Atom* path; - const LV2_Atom* uri; - const LV2_Atom* urid; - const LV2_Atom* string; - const LV2_Atom* literal; - const LV2_Atom* tuple; - const LV2_Atom* vector; - const LV2_Atom* vector2; - const LV2_Atom* seq; - } matches; - - memset(&matches, 0, sizeof(matches)); - - LV2_Atom_Object_Query q[] = {{eg_one, &matches.one}, - {eg_two, &matches.two}, - {eg_three, &matches.three}, - {eg_four, &matches.four}, - {eg_true, &matches.affirmative}, - {eg_false, &matches.negative}, - {eg_path, &matches.path}, - {eg_uri, &matches.uri}, - {eg_urid, &matches.urid}, - {eg_string, &matches.string}, - {eg_literal, &matches.literal}, - {eg_tuple, &matches.tuple}, - {eg_vector, &matches.vector}, - {eg_vector2, &matches.vector2}, - {eg_seq, &matches.seq}, - LV2_ATOM_OBJECT_QUERY_END}; - - int n_matches = lv2_atom_object_query((LV2_Atom_Object*)obj, q); - for (int n = 0; n < 2; ++n) { - if (n_matches != n_props) { - return test_fail("Query failed, %d matches != %d\n", n_matches, n_props); - } else if (!lv2_atom_equals((LV2_Atom*)one, matches.one)) { - return test_fail("Bad match one\n"); - } else if (!lv2_atom_equals((LV2_Atom*)two, matches.two)) { - return test_fail("Bad match two\n"); - } else if (!lv2_atom_equals((LV2_Atom*)three, matches.three)) { - return test_fail("Bad match three\n"); - } else if (!lv2_atom_equals((LV2_Atom*)four, matches.four)) { - return test_fail("Bad match four\n"); - } else if (!lv2_atom_equals((LV2_Atom*)t, matches.affirmative)) { - return test_fail("Bad match true\n"); - } else if (!lv2_atom_equals((LV2_Atom*)f, matches.negative)) { - return test_fail("Bad match false\n"); - } else if (!lv2_atom_equals((LV2_Atom*)path, matches.path)) { - return test_fail("Bad match path\n"); - } else if (!lv2_atom_equals((LV2_Atom*)uri, matches.uri)) { - return test_fail("Bad match URI\n"); - } else if (!lv2_atom_equals((LV2_Atom*)string, matches.string)) { - return test_fail("Bad match string\n"); - } else if (!lv2_atom_equals((LV2_Atom*)literal, matches.literal)) { - return test_fail("Bad match literal\n"); - } else if (!lv2_atom_equals((LV2_Atom*)tuple, matches.tuple)) { - return test_fail("Bad match tuple\n"); - } else if (!lv2_atom_equals((LV2_Atom*)vector, matches.vector)) { - return test_fail("Bad match vector\n"); - } else if (!lv2_atom_equals((LV2_Atom*)vector, matches.vector2)) { - return test_fail("Bad match vector2\n"); - } else if (!lv2_atom_equals((LV2_Atom*)seq, matches.seq)) { - return test_fail("Bad match sequence\n"); - } - memset(&matches, 0, sizeof(matches)); - - // clang-format off - n_matches = lv2_atom_object_get((LV2_Atom_Object*)obj, - eg_one, &matches.one, - eg_two, &matches.two, - eg_three, &matches.three, - eg_four, &matches.four, - eg_true, &matches.affirmative, - eg_false, &matches.negative, - eg_path, &matches.path, - eg_uri, &matches.uri, - eg_urid, &matches.urid, - eg_string, &matches.string, - eg_literal, &matches.literal, - eg_tuple, &matches.tuple, - eg_vector, &matches.vector, - eg_vector2, &matches.vector2, - eg_seq, &matches.seq, - 0); - // clang-format on - } - - free_urid_map(); - - return 0; -} diff --git a/lv2/atom/atom.h b/lv2/atom/atom.h deleted file mode 100644 index b090c1e..0000000 --- a/lv2/atom/atom.h +++ /dev/null @@ -1,260 +0,0 @@ -/* - Copyright 2008-2016 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 - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef LV2_ATOM_H -#define LV2_ATOM_H - -/** - @defgroup atom Atom - @ingroup lv2 - - A generic value container and several data types. - - See <http://lv2plug.in/ns/ext/atom> for details. - - @{ -*/ - -#include <stdint.h> - -// clang-format off - -#define LV2_ATOM_URI "http://lv2plug.in/ns/ext/atom" ///< http://lv2plug.in/ns/ext/atom -#define LV2_ATOM_PREFIX LV2_ATOM_URI "#" ///< http://lv2plug.in/ns/ext/atom# - -#define LV2_ATOM__Atom LV2_ATOM_PREFIX "Atom" ///< http://lv2plug.in/ns/ext/atom#Atom -#define LV2_ATOM__AtomPort LV2_ATOM_PREFIX "AtomPort" ///< http://lv2plug.in/ns/ext/atom#AtomPort -#define LV2_ATOM__Blank LV2_ATOM_PREFIX "Blank" ///< http://lv2plug.in/ns/ext/atom#Blank -#define LV2_ATOM__Bool LV2_ATOM_PREFIX "Bool" ///< http://lv2plug.in/ns/ext/atom#Bool -#define LV2_ATOM__Chunk LV2_ATOM_PREFIX "Chunk" ///< http://lv2plug.in/ns/ext/atom#Chunk -#define LV2_ATOM__Double LV2_ATOM_PREFIX "Double" ///< http://lv2plug.in/ns/ext/atom#Double -#define LV2_ATOM__Event LV2_ATOM_PREFIX "Event" ///< http://lv2plug.in/ns/ext/atom#Event -#define LV2_ATOM__Float LV2_ATOM_PREFIX "Float" ///< http://lv2plug.in/ns/ext/atom#Float -#define LV2_ATOM__Int LV2_ATOM_PREFIX "Int" ///< http://lv2plug.in/ns/ext/atom#Int -#define LV2_ATOM__Literal LV2_ATOM_PREFIX "Literal" ///< http://lv2plug.in/ns/ext/atom#Literal -#define LV2_ATOM__Long LV2_ATOM_PREFIX "Long" ///< http://lv2plug.in/ns/ext/atom#Long -#define LV2_ATOM__Number LV2_ATOM_PREFIX "Number" ///< http://lv2plug.in/ns/ext/atom#Number -#define LV2_ATOM__Object LV2_ATOM_PREFIX "Object" ///< http://lv2plug.in/ns/ext/atom#Object -#define LV2_ATOM__Path LV2_ATOM_PREFIX "Path" ///< http://lv2plug.in/ns/ext/atom#Path -#define LV2_ATOM__Property LV2_ATOM_PREFIX "Property" ///< http://lv2plug.in/ns/ext/atom#Property -#define LV2_ATOM__Resource LV2_ATOM_PREFIX "Resource" ///< http://lv2plug.in/ns/ext/atom#Resource -#define LV2_ATOM__Sequence LV2_ATOM_PREFIX "Sequence" ///< http://lv2plug.in/ns/ext/atom#Sequence -#define LV2_ATOM__Sound LV2_ATOM_PREFIX "Sound" ///< http://lv2plug.in/ns/ext/atom#Sound -#define LV2_ATOM__String LV2_ATOM_PREFIX "String" ///< http://lv2plug.in/ns/ext/atom#String -#define LV2_ATOM__Tuple LV2_ATOM_PREFIX "Tuple" ///< http://lv2plug.in/ns/ext/atom#Tuple -#define LV2_ATOM__URI LV2_ATOM_PREFIX "URI" ///< http://lv2plug.in/ns/ext/atom#URI -#define LV2_ATOM__URID LV2_ATOM_PREFIX "URID" ///< http://lv2plug.in/ns/ext/atom#URID -#define LV2_ATOM__Vector LV2_ATOM_PREFIX "Vector" ///< http://lv2plug.in/ns/ext/atom#Vector -#define LV2_ATOM__atomTransfer LV2_ATOM_PREFIX "atomTransfer" ///< http://lv2plug.in/ns/ext/atom#atomTransfer -#define LV2_ATOM__beatTime LV2_ATOM_PREFIX "beatTime" ///< http://lv2plug.in/ns/ext/atom#beatTime -#define LV2_ATOM__bufferType LV2_ATOM_PREFIX "bufferType" ///< http://lv2plug.in/ns/ext/atom#bufferType -#define LV2_ATOM__childType LV2_ATOM_PREFIX "childType" ///< http://lv2plug.in/ns/ext/atom#childType -#define LV2_ATOM__eventTransfer LV2_ATOM_PREFIX "eventTransfer" ///< http://lv2plug.in/ns/ext/atom#eventTransfer -#define LV2_ATOM__frameTime LV2_ATOM_PREFIX "frameTime" ///< http://lv2plug.in/ns/ext/atom#frameTime -#define LV2_ATOM__supports LV2_ATOM_PREFIX "supports" ///< http://lv2plug.in/ns/ext/atom#supports -#define LV2_ATOM__timeUnit LV2_ATOM_PREFIX "timeUnit" ///< http://lv2plug.in/ns/ext/atom#timeUnit - -// clang-format on - -#define LV2_ATOM_REFERENCE_TYPE 0 ///< The special type for a reference atom - -#ifdef __cplusplus -extern "C" { -#endif - -/** @cond */ -/** This expression will fail to compile if double does not fit in 64 bits. */ -typedef char lv2_atom_assert_double_fits_in_64_bits - [((sizeof(double) <= sizeof(uint64_t)) * 2) - 1]; -/** @endcond */ - -/** - Return a pointer to the contents of an Atom. The "contents" of an atom - is the data past the complete type-specific header. - @param type The type of the atom, for example LV2_Atom_String. - @param atom A variable-sized atom. -*/ -#define LV2_ATOM_CONTENTS(type, atom) ((void*)((uint8_t*)(atom) + sizeof(type))) - -/** - Const version of LV2_ATOM_CONTENTS. -*/ -#define LV2_ATOM_CONTENTS_CONST(type, atom) \ - ((const void*)((const uint8_t*)(atom) + sizeof(type))) - -/** - Return a pointer to the body of an Atom. The "body" of an atom is the - data just past the LV2_Atom head (i.e. the same offset for all types). -*/ -#define LV2_ATOM_BODY(atom) LV2_ATOM_CONTENTS(LV2_Atom, atom) - -/** - Const version of LV2_ATOM_BODY. -*/ -#define LV2_ATOM_BODY_CONST(atom) LV2_ATOM_CONTENTS_CONST(LV2_Atom, atom) - -/** The header of an atom:Atom. */ -typedef struct { - uint32_t size; /**< Size in bytes, not including type and size. */ - uint32_t type; /**< Type of this atom (mapped URI). */ -} LV2_Atom; - -/** An atom:Int or atom:Bool. May be cast to LV2_Atom. */ -typedef struct { - LV2_Atom atom; /**< Atom header. */ - int32_t body; /**< Integer value. */ -} LV2_Atom_Int; - -/** An atom:Long. May be cast to LV2_Atom. */ -typedef struct { - LV2_Atom atom; /**< Atom header. */ - int64_t body; /**< Integer value. */ -} LV2_Atom_Long; - -/** An atom:Float. May be cast to LV2_Atom. */ -typedef struct { - LV2_Atom atom; /**< Atom header. */ - float body; /**< Floating point value. */ -} LV2_Atom_Float; - -/** An atom:Double. May be cast to LV2_Atom. */ -typedef struct { - LV2_Atom atom; /**< Atom header. */ - double body; /**< Floating point value. */ -} LV2_Atom_Double; - -/** An atom:Bool. May be cast to LV2_Atom. */ -typedef LV2_Atom_Int LV2_Atom_Bool; - -/** An atom:URID. May be cast to LV2_Atom. */ -typedef struct { - LV2_Atom atom; /**< Atom header. */ - uint32_t body; /**< URID. */ -} LV2_Atom_URID; - -/** An atom:String. May be cast to LV2_Atom. */ -typedef struct { - LV2_Atom atom; /**< Atom header. */ - /* Contents (a null-terminated UTF-8 string) follow here. */ -} LV2_Atom_String; - -/** The body of an atom:Literal. */ -typedef struct { - uint32_t datatype; /**< Datatype URID. */ - uint32_t lang; /**< Language URID. */ - /* Contents (a null-terminated UTF-8 string) follow here. */ -} LV2_Atom_Literal_Body; - -/** An atom:Literal. May be cast to LV2_Atom. */ -typedef struct { - LV2_Atom atom; /**< Atom header. */ - LV2_Atom_Literal_Body body; /**< Body. */ -} LV2_Atom_Literal; - -/** An atom:Tuple. May be cast to LV2_Atom. */ -typedef struct { - LV2_Atom atom; /**< Atom header. */ - /* Contents (a series of complete atoms) follow here. */ -} LV2_Atom_Tuple; - -/** The body of an atom:Vector. */ -typedef struct { - uint32_t child_size; /**< The size of each element in the vector. */ - uint32_t child_type; /**< The type of each element in the vector. */ - /* Contents (a series of packed atom bodies) follow here. */ -} LV2_Atom_Vector_Body; - -/** An atom:Vector. May be cast to LV2_Atom. */ -typedef struct { - LV2_Atom atom; /**< Atom header. */ - LV2_Atom_Vector_Body body; /**< Body. */ -} LV2_Atom_Vector; - -/** The body of an atom:Property (typically in an atom:Object). */ -typedef struct { - uint32_t key; /**< Key (predicate) (mapped URI). */ - uint32_t context; /**< Context URID (may be, and generally is, 0). */ - LV2_Atom value; /**< Value atom header. */ - /* Value atom body follows here. */ -} LV2_Atom_Property_Body; - -/** An atom:Property. May be cast to LV2_Atom. */ -typedef struct { - LV2_Atom atom; /**< Atom header. */ - LV2_Atom_Property_Body body; /**< Body. */ -} LV2_Atom_Property; - -/** The body of an atom:Object. May be cast to LV2_Atom. */ -typedef struct { - uint32_t id; /**< URID, or 0 for blank. */ - uint32_t otype; /**< Type URID (same as rdf:type, for fast dispatch). */ - /* Contents (a series of property bodies) follow here. */ -} LV2_Atom_Object_Body; - -/** An atom:Object. May be cast to LV2_Atom. */ -typedef struct { - LV2_Atom atom; /**< Atom header. */ - LV2_Atom_Object_Body body; /**< Body. */ -} LV2_Atom_Object; - -/** The header of an atom:Event. Note this type is NOT an LV2_Atom. */ -typedef struct { - /** Time stamp. Which type is valid is determined by context. */ - union { - int64_t frames; /**< Time in audio frames. */ - double beats; /**< Time in beats. */ - } time; - LV2_Atom body; /**< Event body atom header. */ - /* Body atom contents follow here. */ -} LV2_Atom_Event; - -/** - The body of an atom:Sequence (a sequence of events). - - The unit field is either a URID that described an appropriate time stamp - type, or may be 0 where a default stamp type is known. For - LV2_Descriptor::run(), the default stamp type is audio frames. - - The contents of a sequence is a series of LV2_Atom_Event, each aligned - to 64-bits, for example: - <pre> - | Event 1 (size 6) | Event 2 - | | | | | | | | | - | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | - |FRAMES |TYPE |SIZE |DATADATADATAPAD|FRAMES |... - </pre> -*/ -typedef struct { - uint32_t unit; /**< URID of unit of event time stamps. */ - uint32_t pad; /**< Currently unused. */ - /* Contents (a series of events) follow here. */ -} LV2_Atom_Sequence_Body; - -/** An atom:Sequence. */ -typedef struct { - LV2_Atom atom; /**< Atom header. */ - LV2_Atom_Sequence_Body body; /**< Body. */ -} LV2_Atom_Sequence; - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -/** - @} -*/ - -#endif /* LV2_ATOM_H */ diff --git a/lv2/atom/atom.meta.ttl b/lv2/atom/atom.meta.ttl deleted file mode 100644 index adab5f4..0000000 --- a/lv2/atom/atom.meta.ttl +++ /dev/null @@ -1,552 +0,0 @@ -@prefix atom: <http://lv2plug.in/ns/ext/atom#> . -@prefix dcs: <http://ontologi.es/doap-changeset#> . -@prefix doap: <http://usefulinc.com/ns/doap#> . -@prefix foaf: <http://xmlns.com/foaf/0.1/> . -@prefix lv2: <http://lv2plug.in/ns/lv2core#> . -@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . - -<http://lv2plug.in/ns/ext/atom> - a doap:Project ; - doap:name "LV2 Atom" ; - doap:shortdesc "A generic value container and several data types." ; - doap:license <http://opensource.org/licenses/isc> ; - doap:created "2007-00-00" ; - doap:developer <http://drobilla.net/drobilla#me> ; - doap:release [ - doap:revision "2.4" ; - doap:created "2022-05-26" ; - doap:file-release <http://lv2plug.in/spec/lv2-1.18.4.tar.bz2> ; - dcs:blame <http://drobilla.net/drobilla#me> ; - dcs:changeset [ - dcs:item [ - rdfs:label "Fix spelling errors." - ] - ] - ] , [ - doap:revision "2.2" ; - doap:created "2019-02-03" ; - doap:file-release <http://lv2plug.in/spec/lv2-1.16.0.tar.bz2> ; - dcs:blame <http://drobilla.net/drobilla#me> ; - dcs:changeset [ - dcs:item [ - rdfs:label "Add lv2_atom_object_get_typed() for easy type-safe access to object properties." - ] - ] - ] , [ - doap:revision "2.0" ; - doap:created "2014-08-08" ; - doap:file-release <http://lv2plug.in/spec/lv2-1.10.0.tar.bz2> ; - dcs:blame <http://drobilla.net/drobilla#me> ; - dcs:changeset [ - dcs:item [ - rdfs:label "Deprecate Blank and Resource in favour of just Object." - ] , [ - rdfs:label "Add lv2_atom_forge_is_object_type() and lv2_atom_forge_is_blank() to ease backwards compatibility." - ] , [ - rdfs:label "Add lv2_atom_forge_key() for terser object writing." - ] , [ - rdfs:label "Add lv2_atom_sequence_clear() and lv2_atom_sequence_append_event() helper functions." - ] - ] - ] , [ - doap:revision "1.8" ; - doap:created "2014-01-04" ; - doap:file-release <http://lv2plug.in/spec/lv2-1.8.0.tar.bz2> ; - dcs:blame <http://drobilla.net/drobilla#me> ; - dcs:changeset [ - dcs:item [ - rdfs:label "Make lv2_atom_*_is_end() arguments const." - ] - ] - ] , [ - doap:revision "1.6" ; - doap:created "2013-05-26" ; - doap:file-release <http://lv2plug.in/spec/lv2-1.6.0.tar.bz2> ; - dcs:blame <http://drobilla.net/drobilla#me> ; - dcs:changeset [ - dcs:item [ - rdfs:label "Fix crash in forge.h when pushing atoms to a full buffer." - ] - ] - ] , [ - doap:revision "1.4" ; - doap:created "2013-01-27" ; - doap:file-release <http://lv2plug.in/spec/lv2-1.4.0.tar.bz2> ; - dcs:blame <http://drobilla.net/drobilla#me> ; - dcs:changeset [ - dcs:item [ - rdfs:label "Fix lv2_atom_sequence_end()." - ] , [ - rdfs:label "Remove atom:stringType in favour of owl:onDatatype so generic tools can understand and validate atom literals." - ] , [ - rdfs:label "Improve atom documentation." - ] - ] - ] , [ - doap:revision "1.2" ; - doap:created "2012-10-14" ; - doap:file-release <http://lv2plug.in/spec/lv2-1.2.0.tar.bz2> ; - dcs:blame <http://drobilla.net/drobilla#me> ; - dcs:changeset [ - dcs:item [ - rdfs:label "Fix implicit conversions in forge.h that are invalid in C++11." - ] , [ - rdfs:label "Fix lv2_atom_object_next() on 32-bit platforms." - ] , [ - rdfs:label "Add lv2_atom_object_body_get()." - ] , [ - rdfs:label "Fix outdated documentation in forge.h." - ] , [ - rdfs:label "Use consistent label style." - ] , [ - rdfs:label "Add LV2_ATOM_CONTENTS_CONST and LV2_ATOM_BODY_CONST." - ] - ] - ] , [ - doap:revision "1.0" ; - doap:created "2012-04-17" ; - doap:file-release <http://lv2plug.in/spec/lv2-1.0.0.tar.bz2> ; - dcs:blame <http://drobilla.net/drobilla#me> ; - dcs:changeset [ - dcs:item [ - rdfs:label "Initial release." - ] - ] - ] ; - lv2:documentation """ - -An atom:Atom is a simple generic data container for holding any type of Plain -Old Data (POD). An Atom can contain simple primitive types like integers, -floating point numbers, and strings; as well as structured data like lists and -dictionary-like <q>Objects</q>. Since Atoms are POD, they can be easily copied -(for example, with `memcpy()`) anywhere and are suitable for use in real-time -code. - -Every atom starts with an LV2_Atom header, followed by the contents. This -allows code to process atoms without requiring special code for every type of -data. For example, plugins that mutually understand a type can be used -together in a host that does not understand that type, because the host is only -required to copy atoms, not interpret their contents. Similarly, plugins (such -as routers, delays, or data structures) can meaningfully process atoms of a -type unknown to them. - -Atoms should be used anywhere values of various types must be stored or -transmitted. An atom:AtomPort can be used to transmit atoms via ports. An -atom:AtomPort that contains a atom:Sequence can be used for sample accurate -communication of events, such as MIDI. - -### Serialisation - -Each Atom type defines a binary format for use at runtime, but also a -serialisation that is natural to express in Turtle format. Thus, this -specification defines a powerful real-time appropriate data model, as well as a -portable way to serialise any data in that model. This is particularly useful -for inter-process communication, saving/restoring state, and describing values -in plugin data files. - -### Custom Atom Types - -While it is possible to define new Atom types for any binary format, the -standard types defined here are powerful enough to describe almost anything. -Implementations SHOULD build structures out of the types provided here, rather -than define new binary formats (for example, using atom:Object rather than a -new C `struct` type). Host and tool implementations have support for -serialising all standard types, so new binary formats are an implementation -burden which harms interoperabilty. In particular, plugins SHOULD NOT expect -UI communication or state saving with custom binary types to work. In general, -new Atom types should only be defined where absolutely necessary due to -performance reasons and serialisation is not a concern. - -"""^^lv2:Markdown . - -atom:Atom - lv2:documentation """ - -An LV2_Atom has a 32-bit `size` and `type`, followed by a body of `size` bytes. -Atoms MUST be 64-bit aligned. - -All concrete Atom types (subclasses of this class) MUST define a precise binary -layout for their body. - -The `type` field is the URI of an Atom type mapped to an integer. -Implementations SHOULD gracefully pass through, or ignore, atoms with unknown -types. - -All atoms are POD by definition except references, which as a special case have -`type` 0. An Atom MUST NOT contain a Reference. It is safe to copy any -non-reference Atom with a simple `memcpy`, even if the implementation does not -understand `type`. Though this extension reserves the type 0 for references, -the details of reference handling are currently unspecified. A future revision -of this extension, or a different extension, may define how to use non-POD data -and references. Implementations MUST NOT send references to another -implementation unless the receiver is explicitly known to support references -(e.g. by supporting a feature). - -The special case of a null atom with both `type` and `size` 0 is not considered -a reference. - -"""^^lv2:Markdown . - -atom:Chunk - lv2:documentation """ - -This type is used to indicate a certain amount of space is available. For -example, output ports with a variably sized type are connected to a Chunk so -the plugin knows the size of the buffer available for writing. - -The use of a Chunk should be constrained to a local scope, since -interpreting it is impossible without context. However, if serialised to RDF, -a Chunk may be represented directly as an xsd:base64Binary string, for example: - - :::turtle - [] eg:someChunk "vu/erQ=="^^xsd:base64Binary . - -"""^^lv2:Markdown . - -atom:String - lv2:documentation """ - -The body of an LV2_Atom_String is a C string in UTF-8 encoding, i.e. an array -of bytes (`uint8_t`) terminated with a NULL byte (`'\\0'`). - -This type is for free-form strings, but SHOULD NOT be used for typed data or -text in any language. Use atom:Literal unless translating the string does not -make sense and the string has no meaningful datatype. - -"""^^lv2:Markdown . - -atom:Literal - lv2:documentation """ - -This type is compatible with rdfs:Literal and is capable of expressing a -string in any language or a value of any type. A Literal has a -`datatype` and `lang` followed by string data in UTF-8 -encoding. The length of the string data in bytes is `size - -sizeof(LV2_Atom_Literal)`, including the terminating NULL character. The -`lang` field SHOULD be a URI of the form -`http://lexvo.org/id/iso639-3/LANG` or -`http://lexvo.org/id/iso639-1/LANG` where LANG is a 3-character ISO 693-3 -language code, or a 2-character ISO 693-1 language code, respectively. - -A Literal may have a `datatype` or a `lang`, but never both. - -For example, a Literal can be <q>Hello</q> in English: - - :::c - void set_to_hello_in_english(LV2_Atom_Literal* lit) { - lit->atom.type = map(expand("atom:Literal")); - lit->atom.size = 14; - lit->body.datatype = 0; - lit->body.lang = map("http://lexvo.org/id/iso639-1/en"); - memcpy(LV2_ATOM_CONTENTS(LV2_Atom_Literal, lit), - "Hello", - sizeof("Hello")); // Assumes enough space - } - -or a Turtle string: - - :::c - void set_to_turtle_string(LV2_Atom_Literal* lit, const char* ttl) { - lit->atom.type = map(expand("atom:Literal")); - lit->atom.size = 64; - lit->body.datatype = map("http://www.w3.org/2008/turtle#turtle"); - lit->body.lang = 0; - memcpy(LV2_ATOM_CONTENTS(LV2_Atom_Literal, lit), - ttl, - strlen(ttl) + 1); // Assumes enough space - } - -"""^^lv2:Markdown . - -atom:Path - lv2:documentation """ - -A Path is a URI reference with only a path component: no scheme, authority, -query, or fragment. In particular, paths to files in the same bundle may be -cleanly written in Turtle files as a relative URI. However, implementations -may assume any binary Path (e.g. in an event payload) is a valid file path -which can passed to system functions like fopen() directly, without any -character encoding or escape expansion required. - -Any implementation that creates a Path atom to transmit to another is -responsible for ensuring it is valid. A Path SHOULD always be absolute, unless -there is some mechanism in place that defines a base path. Since this is not -the case for plugin instances, effectively any Path sent to or received from a -plugin instance MUST be absolute. - -"""^^lv2:Markdown . - -atom:URI - lv2:documentation """ - -This is useful when a URI is needed but mapping is inappropriate, for example -with temporary or relative URIs. Since the ability to distinguish URIs from -plain strings is often necessary, URIs MUST NOT be transmitted as atom:String. - -This is not strictly a URI, since UTF-8 is allowed. Escaping and related -issues are the host's responsibility. - -"""^^lv2:Markdown . - -atom:URID - lv2:documentation """ - -A URID is typically generated with the LV2_URID_Map provided by the host . - -"""^^lv2:Markdown . - -atom:Vector - lv2:documentation """ - -A homogeneous series of atom bodies with equivalent type and size. - -An LV2_Atom_Vector is a 32-bit `child_size` and `child_type` followed by `size -/ child_size` atom bodies. - -For example, an atom:Vector containing 42 elements of type atom:Float: - - :::c - struct VectorOf42Floats { - uint32_t size; // sizeof(LV2_Atom_Vector_Body) + (42 * sizeof(float); - uint32_t type; // map(expand("atom:Vector")) - uint32_t child_size; // sizeof(float) - uint32_t child_type; // map(expand("atom:Float")) - float elems[42]; - }; - -Note that it is possible to construct a valid Atom for each element of the -vector, even by an implementation which does not understand `child_type`. - -If serialised to RDF, a Vector SHOULD have the form: - - :::turtle - eg:someVector - a atom:Vector ; - atom:childType atom:Int ; - rdf:value ( - "1"^^xsd:int - "2"^^xsd:int - "3"^^xsd:int - "4"^^xsd:int - ) . - -"""^^lv2:Markdown . - -atom:Tuple - lv2:documentation """ - -The body of a Tuple is simply a series of complete atoms, each aligned to -64 bits. - -If serialised to RDF, a Tuple SHOULD have the form: - - :::turtle - eg:someVector - a atom:Tuple ; - rdf:value ( - "1"^^xsd:int - "3.5"^^xsd:float - "etc" - ) . - -"""^^lv2:Markdown . - -atom:Property - lv2:documentation """ - -An LV2_Atom_Property has a URID `key` and `context`, and an Atom `value`. This -corresponds to an RDF Property, where the <q>key</q> is the <q>predicate</q> -and the <q>value</q> is the object. - -The `context` field can be used to specify a different context for each -property, where this is useful. Otherwise, it may be 0. - -Properties generally only exist as part of an atom:Object. Accordingly, -they will typically be represented directly as properties in RDF (see -atom:Object). If this is not possible, they may be expressed as partial -reified statements, for example: - - :::turtle - eg:someProperty - rdf:predicate eg:theKey ; - rdf:object eg:theValue . - -"""^^lv2:Markdown . - -atom:Object - lv2:documentation """ - -An <q>Object</q> is an atom with a set of properties. This corresponds to an -RDF Resource, and can be thought of as a dictionary with URID keys. - -An LV2_Atom_Object body has a uint32_t `id` and `type`, followed by a series of -atom:Property bodies (LV2_Atom_Property_Body). The LV2_Atom_Object_Body::otype -field is equivalent to a property with key rdf:type, but is included in the -structure to allow for fast dispatching. - -Code SHOULD check for objects using lv2_atom_forge_is_object() or -lv2_atom_forge_is_blank() if a forge is available, rather than checking the -atom type directly. This will correctly handle the deprecated atom:Resource -and atom:Blank types. - -When serialised to RDF, an Object is represented as a resource, for example: - - :::turtle - eg:someObject - eg:firstPropertyKey "first property value" ; - eg:secondPropertyKey "first loser" ; - eg:andSoOn "and so on" . - -"""^^lv2:Markdown . - -atom:Resource - lv2:documentation """ - -This class is deprecated. Use atom:Object directly instead. - -An atom:Object where the <code>id</code> field is a URID, that is, an Object -with a URI. - -"""^^lv2:Markdown . - -atom:Blank - lv2:documentation """ - -This class is deprecated. Use atom:Object with ID 0 instead. - -An atom:Object where the LV2_Atom_Object::id is a blank node ID (NOT a URI). -The ID of a Blank is valid only within the context the Blank appears in. For -ports this is the context of the associated run() call, i.e. all ports share -the same context so outputs can contain IDs that correspond to IDs of blanks in -the input. - -"""^^lv2:Markdown . - -atom:Sound - lv2:documentation """ - -The format of a atom:Sound is the same as the buffer format for lv2:AudioPort -(except the size may be arbitrary). An atom:Sound inherently depends on the -sample rate, which is assumed to be known from context. Because of this, -directly serialising an atom:Sound is probably a bad idea, use a standard -format like WAV instead. - -"""^^lv2:Markdown . - -atom:Event - lv2:documentation """ - -An Event is typically an element of an atom:Sequence. Note that this is not an Atom type since it begins with a timestamp, not an atom header. - -"""^^lv2:Markdown . - -atom:Sequence - lv2:documentation """ - -A flat sequence of atom:Event, that is, a series of time-stamped Atoms. - -LV2_Atom_Sequence_Body.unit describes the time unit for the contained atoms. -If the unit is known from context (e.g. run() stamps are always audio frames), -this field may be zero. Otherwise, it SHOULD be either units:frame or -units:beat, in which case ev.time.frames or ev.time.beats is valid, -respectively. - -If serialised to RDF, a Sequence has a similar form to atom:Vector, but for -brevity the elements may be assumed to be atom:Event, for example: - - :::turtle - eg:someSequence - a atom:Sequence ; - rdf:value ( - [ - atom:frameTime 1 ; - rdf:value "901A01"^^midi:MidiEvent - ] [ - atom:frameTime 3 ; - rdf:value "902B02"^^midi:MidiEvent - ] - ) . - -"""^^lv2:Markdown . - -atom:AtomPort - lv2:documentation """ - -Ports of this type are connected to an LV2_Atom with a type specified by -atom:bufferType. - -Output ports with a variably sized type MUST be initialised by the host before -every run() to an atom:Chunk with size set to the available space. The plugin -reads this size to know how much space is available for writing. In all cases, -the plugin MUST write a complete atom (including header) to outputs. However, -to be robust, hosts SHOULD initialise output ports to a safe sentinel (e.g. the -null Atom) before calling run(). - -"""^^lv2:Markdown . - -atom:bufferType - lv2:documentation """ - -Indicates that an AtomPort may be connected to a certain Atom type. A port MAY -support several buffer types. The host MUST NOT connect a port to an Atom with -a type not explicitly listed with this property. The value of this property -MUST be a sub-class of atom:Atom. For example, an input port that is connected -directly to an LV2_Atom_Double value is described like so: - - :::turtle - <plugin> - lv2:port [ - a lv2:InputPort , atom:AtomPort ; - atom:bufferType atom:Double ; - ] . - -This property only describes the types a port may be directly connected to. It -says nothing about the expected contents of containers. For that, use -atom:supports. - -"""^^lv2:Markdown . - -atom:supports - lv2:documentation """ - -This property is defined loosely, it may be used to indicate that anything -<q>supports</q> an Atom type, wherever that may be useful. It applies -<q>recursively</q> where collections are involved. - -In particular, this property can be used to describe which event types are -expected by a port. For example, a port that receives MIDI events is described -like so: - - :::turtle - <plugin> - lv2:port [ - a lv2:InputPort , atom:AtomPort ; - atom:bufferType atom:Sequence ; - atom:supports midi:MidiEvent ; - ] . - -"""^^lv2:Markdown . - -atom:eventTransfer - lv2:documentation """ - -Transfer of individual events in a port buffer. Useful as the `format` for a -LV2UI_Write_Function. - -This protocol applies to ports which contain events, usually in an -atom:Sequence. The host must transfer each individual event to the recipient. -The format of the received data is an LV2_Atom, there is no timestamp header. - -"""^^lv2:Markdown . - -atom:atomTransfer - lv2:documentation """ - -Transfer of the complete atom in a port buffer. Useful as the `format` for a -LV2UI_Write_Function. - -This protocol applies to atom ports. The host must transfer the complete atom -contained in the port, including header. - -"""^^lv2:Markdown . - diff --git a/lv2/atom/atom.ttl b/lv2/atom/atom.ttl deleted file mode 100644 index ef221ad..0000000 --- a/lv2/atom/atom.ttl +++ /dev/null @@ -1,250 +0,0 @@ -@prefix atom: <http://lv2plug.in/ns/ext/atom#> . -@prefix lv2: <http://lv2plug.in/ns/lv2core#> . -@prefix owl: <http://www.w3.org/2002/07/owl#> . -@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . -@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . -@prefix ui: <http://lv2plug.in/ns/extensions/ui#> . -@prefix units: <http://lv2plug.in/ns/extensions/units#> . -@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . - -<http://lv2plug.in/ns/ext/atom> - a owl:Ontology ; - rdfs:seeAlso <atom.h> , - <util.h> , - <forge.h> , - <atom.meta.ttl> ; - rdfs:label "LV2 Atom" ; - rdfs:comment "A generic value container and several data types." ; - owl:imports <http://lv2plug.in/ns/lv2core> , - <http://lv2plug.in/ns/extensions/ui> , - <http://lv2plug.in/ns/extensions/units> . - -atom:cType - a rdf:Property , - owl:DatatypeProperty , - owl:FunctionalProperty ; - rdfs:label "C type" ; - rdfs:comment "The C type that describes the binary representation of an Atom type." ; - rdfs:domain rdfs:Class ; - rdfs:range lv2:Symbol . - -atom:Atom - a rdfs:Class ; - rdfs:label "Atom" ; - rdfs:comment "Abstract base class for all atoms." ; - atom:cType "LV2_Atom" . - -atom:Chunk - a rdfs:Class , - rdfs:Datatype ; - rdfs:subClassOf atom:Atom ; - rdfs:label "Chunk" ; - rdfs:comment "A chunk of memory with undefined contents." ; - owl:onDatatype xsd:base64Binary . - -atom:Number - a rdfs:Class ; - rdfs:subClassOf atom:Atom ; - rdfs:label "Number" ; - rdfs:comment "Base class for numeric types." . - -atom:Int - a rdfs:Class , - rdfs:Datatype ; - rdfs:subClassOf atom:Number ; - rdfs:label "Int" ; - rdfs:comment "A native `int32_t`." ; - atom:cType "LV2_Atom_Int" ; - owl:onDatatype xsd:int . - -atom:Long - a rdfs:Class , - rdfs:Datatype ; - rdfs:subClassOf atom:Number ; - rdfs:label "Long" ; - rdfs:comment "A native `int64_t`." ; - atom:cType "LV2_Atom_Long" ; - owl:onDatatype xsd:long . - -atom:Float - a rdfs:Class , - rdfs:Datatype ; - rdfs:subClassOf atom:Number ; - rdfs:label "Float" ; - rdfs:comment "A native `float`." ; - atom:cType "LV2_Atom_Float" ; - owl:onDatatype xsd:float . - -atom:Double - a rdfs:Class , - rdfs:Datatype ; - rdfs:subClassOf atom:Number ; - rdfs:label "Double" ; - rdfs:comment "A native `double`." ; - atom:cType "LV2_Atom_Double" ; - owl:onDatatype xsd:double . - -atom:Bool - a rdfs:Class , - rdfs:Datatype ; - rdfs:subClassOf atom:Atom ; - rdfs:label "Bool" ; - rdfs:comment "An atom:Int where 0 is false and any other value is true." ; - atom:cType "LV2_Atom_Bool" ; - owl:onDatatype xsd:boolean . - -atom:String - a rdfs:Class , - rdfs:Datatype ; - rdfs:subClassOf atom:Atom ; - rdfs:label "String" ; - rdfs:comment "A UTF-8 string." ; - atom:cType "LV2_Atom_String" ; - owl:onDatatype xsd:string . - -atom:Literal - a rdfs:Class ; - rdfs:subClassOf atom:Atom ; - rdfs:label "Literal" ; - rdfs:comment "A UTF-8 string literal with optional datatype or language." ; - atom:cType "LV2_Atom_Literal" . - -atom:Path - a rdfs:Class , - rdfs:Datatype ; - rdfs:subClassOf atom:URI ; - owl:onDatatype atom:URI ; - rdfs:label "Path" ; - rdfs:comment "A local file path." . - -atom:URI - a rdfs:Class , - rdfs:Datatype ; - rdfs:subClassOf atom:String ; - owl:onDatatype xsd:anyURI ; - rdfs:label "URI" ; - rdfs:comment "A URI string." . - -atom:URID - a rdfs:Class ; - rdfs:subClassOf atom:Atom ; - rdfs:label "URID" ; - rdfs:comment "An unsigned 32-bit integer ID for a URI." ; - atom:cType "LV2_Atom_URID" . - -atom:Vector - a rdfs:Class ; - rdfs:subClassOf atom:Atom ; - rdfs:label "Vector" ; - rdfs:comment "A homogeneous sequence of atom bodies with equivalent type and size." ; - atom:cType "LV2_Atom_Vector" . - -atom:Tuple - a rdfs:Class ; - rdfs:subClassOf atom:Atom ; - rdfs:label "Tuple" ; - rdfs:comment "A sequence of atoms with varying type and size." . - -atom:Property - a rdfs:Class ; - rdfs:subClassOf atom:Atom ; - rdfs:label "Property" ; - rdfs:comment "A property of an atom:Object." ; - atom:cType "LV2_Atom_Property" . - -atom:Object - a rdfs:Class ; - rdfs:subClassOf atom:Atom ; - rdfs:label "Object" ; - rdfs:comment "A collection of properties." ; - atom:cType "LV2_Atom_Object" . - -atom:Resource - a rdfs:Class ; - rdfs:subClassOf atom:Object ; - rdfs:label "Resource" ; - rdfs:comment "A named collection of properties with a URI." ; - owl:deprecated "true"^^xsd:boolean ; - atom:cType "LV2_Atom_Object" . - -atom:Blank - a rdfs:Class ; - rdfs:subClassOf atom:Object ; - rdfs:label "Blank" ; - rdfs:comment "An anonymous collection of properties without a URI." ; - owl:deprecated "true"^^xsd:boolean ; - atom:cType "LV2_Atom_Object" . - -atom:Sound - a rdfs:Class ; - rdfs:subClassOf atom:Vector ; - rdfs:label "Sound" ; - rdfs:comment "A atom:Vector of atom:Float which represents an audio waveform." ; - atom:cType "LV2_Atom_Vector" . - -atom:frameTime - a rdf:Property , - owl:DatatypeProperty , - owl:FunctionalProperty ; - rdfs:range xsd:decimal ; - rdfs:label "frame time" ; - rdfs:comment "A time stamp in audio frames." . - -atom:beatTime - a rdf:Property , - owl:DatatypeProperty , - owl:FunctionalProperty ; - rdfs:range xsd:decimal ; - rdfs:label "beat time" ; - rdfs:comment "A time stamp in beats." . - -atom:Event - a rdfs:Class ; - rdfs:label "Event" ; - atom:cType "LV2_Atom_Event" ; - rdfs:comment "An atom with a time stamp prefix in a sequence." . - -atom:Sequence - a rdfs:Class ; - rdfs:subClassOf atom:Atom ; - rdfs:label "Sequence" ; - atom:cType "LV2_Atom_Sequence" ; - rdfs:comment "A sequence of events." . - -atom:AtomPort - a rdfs:Class ; - rdfs:subClassOf lv2:Port ; - rdfs:label "Atom Port" ; - rdfs:comment "A port which contains an atom:Atom." . - -atom:bufferType - a rdf:Property , - owl:ObjectProperty ; - rdfs:domain atom:AtomPort ; - rdfs:range rdfs:Class ; - rdfs:label "buffer type" ; - rdfs:comment "An atom type that a port may be connected to." . - -atom:childType - a rdf:Property , - owl:ObjectProperty ; - rdfs:label "child type" ; - rdfs:comment "The type of children in a container." . - -atom:supports - a rdf:Property , - owl:ObjectProperty ; - rdfs:label "supports" ; - rdfs:comment "A supported atom type." ; - rdfs:range rdfs:Class . - -atom:eventTransfer - a ui:PortProtocol ; - rdfs:label "event transfer" ; - rdfs:comment "A port protocol for transferring events." . - -atom:atomTransfer - a ui:PortProtocol ; - rdfs:label "atom transfer" ; - rdfs:comment "A port protocol for transferring atoms." . - diff --git a/lv2/atom/forge-overflow-test.c b/lv2/atom/forge-overflow-test.c deleted file mode 100644 index 27f3497..0000000 --- a/lv2/atom/forge-overflow-test.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - Copyright 2019 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 - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "lv2/atom/atom-test-utils.c" -#include "lv2/atom/atom.h" -#include "lv2/atom/forge.h" -#include "lv2/urid/urid.h" - -#include <assert.h> -#include <stdint.h> -#include <stdlib.h> - -static int -test_string_overflow(void) -{ -#define MAX_CHARS 15 - - static const size_t capacity = sizeof(LV2_Atom_String) + MAX_CHARS + 1; - static const char* str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - uint8_t* buf = (uint8_t*)malloc(capacity); - LV2_URID_Map map = {NULL, urid_map}; - LV2_Atom_Forge forge; - lv2_atom_forge_init(&forge, &map); - - // Check that writing increasingly long strings fails at the right point - for (unsigned count = 0; count < MAX_CHARS; ++count) { - lv2_atom_forge_set_buffer(&forge, buf, capacity); - - const LV2_Atom_Forge_Ref ref = lv2_atom_forge_string(&forge, str, count); - if (!ref) { - return test_fail("Failed to write %u byte string\n", count); - } - } - - // Failure writing to an exactly full forge - if (lv2_atom_forge_string(&forge, str, MAX_CHARS + 1)) { - return test_fail("Successfully wrote past end of buffer\n"); - } - - // Failure writing body after successfully writing header - lv2_atom_forge_set_buffer(&forge, buf, sizeof(LV2_Atom) + 1); - if (lv2_atom_forge_string(&forge, "AB", 2)) { - return test_fail("Successfully wrote atom header past end\n"); - } - - free(buf); - return 0; -} - -static int -test_literal_overflow(void) -{ - static const size_t capacity = sizeof(LV2_Atom_Literal) + 2; - - uint8_t* buf = (uint8_t*)malloc(capacity); - LV2_URID_Map map = {NULL, urid_map}; - LV2_Atom_Forge forge; - lv2_atom_forge_init(&forge, &map); - - // Failure in atom header - lv2_atom_forge_set_buffer(&forge, buf, 1); - if (lv2_atom_forge_literal(&forge, "A", 1, 0, 0)) { - return test_fail("Successfully wrote atom header past end\n"); - } - - // Failure in literal header - lv2_atom_forge_set_buffer(&forge, buf, sizeof(LV2_Atom) + 1); - if (lv2_atom_forge_literal(&forge, "A", 1, 0, 0)) { - return test_fail("Successfully wrote literal header past end\n"); - } - - // Success (only room for one character + null terminator) - lv2_atom_forge_set_buffer(&forge, buf, capacity); - if (!lv2_atom_forge_literal(&forge, "A", 1, 0, 0)) { - return test_fail("Failed to write small enough literal\n"); - } - - // Failure in body - lv2_atom_forge_set_buffer(&forge, buf, capacity); - if (lv2_atom_forge_literal(&forge, "AB", 2, 0, 0)) { - return test_fail("Successfully wrote literal body past end\n"); - } - - free(buf); - return 0; -} - -static int -test_sequence_overflow(void) -{ - static const size_t size = sizeof(LV2_Atom_Sequence) + 6 * sizeof(LV2_Atom); - LV2_URID_Map map = {NULL, urid_map}; - - // Test over a range that fails in the sequence header and event components - for (size_t capacity = 1; capacity < size; ++capacity) { - uint8_t* buf = (uint8_t*)malloc(capacity); - - LV2_Atom_Forge forge; - lv2_atom_forge_init(&forge, &map); - lv2_atom_forge_set_buffer(&forge, buf, capacity); - - LV2_Atom_Forge_Frame frame; - LV2_Atom_Forge_Ref ref = lv2_atom_forge_sequence_head(&forge, &frame, 0); - - assert(capacity >= sizeof(LV2_Atom_Sequence) || !frame.ref); - assert(capacity >= sizeof(LV2_Atom_Sequence) || !ref); - (void)ref; - - lv2_atom_forge_frame_time(&forge, 0); - lv2_atom_forge_int(&forge, 42); - lv2_atom_forge_pop(&forge, &frame); - - free(buf); - } - - return 0; -} - -static int -test_vector_head_overflow(void) -{ - static const size_t size = sizeof(LV2_Atom_Vector) + 3 * sizeof(LV2_Atom); - LV2_URID_Map map = {NULL, urid_map}; - - // Test over a range that fails in the vector header and elements - for (size_t capacity = 1; capacity < size; ++capacity) { - uint8_t* buf = (uint8_t*)malloc(capacity); - - LV2_Atom_Forge forge; - lv2_atom_forge_init(&forge, &map); - lv2_atom_forge_set_buffer(&forge, buf, capacity); - - LV2_Atom_Forge_Frame frame; - LV2_Atom_Forge_Ref ref = - lv2_atom_forge_vector_head(&forge, &frame, sizeof(int32_t), forge.Int); - - assert(capacity >= sizeof(LV2_Atom_Vector) || !frame.ref); - assert(capacity >= sizeof(LV2_Atom_Vector) || !ref); - (void)ref; - - lv2_atom_forge_int(&forge, 1); - lv2_atom_forge_int(&forge, 2); - lv2_atom_forge_int(&forge, 3); - lv2_atom_forge_pop(&forge, &frame); - - free(buf); - } - - return 0; -} - -static int -test_vector_overflow(void) -{ - static const size_t size = sizeof(LV2_Atom_Vector) + 3 * sizeof(LV2_Atom); - static const int32_t vec[] = {1, 2, 3}; - LV2_URID_Map map = {NULL, urid_map}; - - // Test over a range that fails in the vector header and elements - for (size_t capacity = 1; capacity < size; ++capacity) { - uint8_t* buf = (uint8_t*)malloc(capacity); - - LV2_Atom_Forge forge; - lv2_atom_forge_init(&forge, &map); - lv2_atom_forge_set_buffer(&forge, buf, capacity); - - LV2_Atom_Forge_Ref ref = - lv2_atom_forge_vector(&forge, sizeof(int32_t), forge.Int, 3, vec); - - assert(capacity >= sizeof(LV2_Atom_Vector) || !ref); - (void)ref; - - free(buf); - } - - return 0; -} - -static int -test_tuple_overflow(void) -{ - static const size_t size = sizeof(LV2_Atom_Tuple) + 3 * sizeof(LV2_Atom); - LV2_URID_Map map = {NULL, urid_map}; - - // Test over a range that fails in the tuple header and elements - for (size_t capacity = 1; capacity < size; ++capacity) { - uint8_t* buf = (uint8_t*)malloc(capacity); - - LV2_Atom_Forge forge; - lv2_atom_forge_init(&forge, &map); - lv2_atom_forge_set_buffer(&forge, buf, capacity); - - LV2_Atom_Forge_Frame frame; - LV2_Atom_Forge_Ref ref = lv2_atom_forge_tuple(&forge, &frame); - - assert(capacity >= sizeof(LV2_Atom_Tuple) || !frame.ref); - assert(capacity >= sizeof(LV2_Atom_Tuple) || !ref); - (void)ref; - - lv2_atom_forge_int(&forge, 1); - lv2_atom_forge_float(&forge, 2.0f); - lv2_atom_forge_string(&forge, "three", 5); - lv2_atom_forge_pop(&forge, &frame); - - free(buf); - } - - return 0; -} - -int -main(void) -{ - const int ret = test_string_overflow() || test_literal_overflow() || - test_sequence_overflow() || test_vector_head_overflow() || - test_vector_overflow() || test_tuple_overflow(); - - free_urid_map(); - - return ret; -} diff --git a/lv2/atom/forge.h b/lv2/atom/forge.h deleted file mode 100644 index 280bd53..0000000 --- a/lv2/atom/forge.h +++ /dev/null @@ -1,683 +0,0 @@ -/* - Copyright 2008-2016 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 - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -/** - @file forge.h An API for constructing LV2 atoms. - - This file provides an API for constructing Atoms which makes it relatively - simple to build nested atoms of arbitrary complexity without requiring - dynamic memory allocation. - - The API is based on successively appending the appropriate pieces to build a - complete Atom. The size of containers is automatically updated. Functions - that begin a container return (via their frame argument) a stack frame which - must be popped when the container is finished. - - All output is written to a user-provided buffer or sink function. This - makes it possible to create atoms on the stack, on the heap, in LV2 port - buffers, in a ringbuffer, or elsewhere, all using the same API. - - This entire API is realtime safe if used with a buffer or a realtime safe - sink, except lv2_atom_forge_init() which is only realtime safe if the URI - map function is. - - Note these functions are all static inline, do not take their address. - - This header is non-normative, it is provided for convenience. -*/ - -#ifndef LV2_ATOM_FORGE_H -#define LV2_ATOM_FORGE_H - -/** - @defgroup forge Forge - @ingroup atom - - An API for constructing LV2 atoms. - - @{ -*/ - -#include "lv2/atom/atom.h" -#include "lv2/atom/util.h" -#include "lv2/core/attributes.h" -#include "lv2/urid/urid.h" - -#include <assert.h> -#include <stdbool.h> -#include <stdint.h> -#include <string.h> - -#ifdef __cplusplus -extern "C" { -#endif - -// Disable deprecation warnings for Blank and Resource -LV2_DISABLE_DEPRECATION_WARNINGS - -/** Handle for LV2_Atom_Forge_Sink. */ -typedef void* LV2_Atom_Forge_Sink_Handle; - -/** A reference to a chunk of written output. */ -typedef intptr_t LV2_Atom_Forge_Ref; - -/** Sink function for writing output. See lv2_atom_forge_set_sink(). */ -typedef LV2_Atom_Forge_Ref (*LV2_Atom_Forge_Sink)( - LV2_Atom_Forge_Sink_Handle handle, - const void* buf, - uint32_t size); - -/** Function for resolving a reference. See lv2_atom_forge_set_sink(). */ -typedef LV2_Atom* (*LV2_Atom_Forge_Deref_Func)( - LV2_Atom_Forge_Sink_Handle handle, - LV2_Atom_Forge_Ref ref); - -/** A stack frame used for keeping track of nested Atom containers. */ -typedef struct LV2_Atom_Forge_Frame { - struct LV2_Atom_Forge_Frame* parent; - LV2_Atom_Forge_Ref ref; -} LV2_Atom_Forge_Frame; - -/** A "forge" for creating atoms by appending to a buffer. */ -typedef struct { - uint8_t* buf; - uint32_t offset; - uint32_t size; - - LV2_Atom_Forge_Sink sink; - LV2_Atom_Forge_Deref_Func deref; - LV2_Atom_Forge_Sink_Handle handle; - - LV2_Atom_Forge_Frame* stack; - - LV2_URID Blank LV2_DEPRECATED; - LV2_URID Bool; - LV2_URID Chunk; - LV2_URID Double; - LV2_URID Float; - LV2_URID Int; - LV2_URID Long; - LV2_URID Literal; - LV2_URID Object; - LV2_URID Path; - LV2_URID Property; - LV2_URID Resource LV2_DEPRECATED; - LV2_URID Sequence; - LV2_URID String; - LV2_URID Tuple; - LV2_URID URI; - LV2_URID URID; - LV2_URID Vector; -} LV2_Atom_Forge; - -static inline void -lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size); - -/** - Initialise `forge`. - - URIs will be mapped using `map` and stored, a reference to `map` itself is - not held. -*/ -static inline void -lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map) -{ - lv2_atom_forge_set_buffer(forge, NULL, 0); - forge->Blank = map->map(map->handle, LV2_ATOM__Blank); - forge->Bool = map->map(map->handle, LV2_ATOM__Bool); - forge->Chunk = map->map(map->handle, LV2_ATOM__Chunk); - forge->Double = map->map(map->handle, LV2_ATOM__Double); - forge->Float = map->map(map->handle, LV2_ATOM__Float); - forge->Int = map->map(map->handle, LV2_ATOM__Int); - forge->Long = map->map(map->handle, LV2_ATOM__Long); - forge->Literal = map->map(map->handle, LV2_ATOM__Literal); - forge->Object = map->map(map->handle, LV2_ATOM__Object); - forge->Path = map->map(map->handle, LV2_ATOM__Path); - forge->Property = map->map(map->handle, LV2_ATOM__Property); - forge->Resource = map->map(map->handle, LV2_ATOM__Resource); - forge->Sequence = map->map(map->handle, LV2_ATOM__Sequence); - forge->String = map->map(map->handle, LV2_ATOM__String); - forge->Tuple = map->map(map->handle, LV2_ATOM__Tuple); - forge->URI = map->map(map->handle, LV2_ATOM__URI); - forge->URID = map->map(map->handle, LV2_ATOM__URID); - forge->Vector = map->map(map->handle, LV2_ATOM__Vector); -} - -/** Access the Atom pointed to by a reference. */ -static inline LV2_Atom* -lv2_atom_forge_deref(LV2_Atom_Forge* forge, LV2_Atom_Forge_Ref ref) -{ - return forge->buf ? (LV2_Atom*)ref : forge->deref(forge->handle, ref); -} - -/** - @name Object Stack - @{ -*/ - -/** - Push a stack frame. - This is done automatically by container functions (which take a stack frame - pointer), but may be called by the user to push the top level container when - writing to an existing Atom. -*/ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_push(LV2_Atom_Forge* forge, - LV2_Atom_Forge_Frame* frame, - LV2_Atom_Forge_Ref ref) -{ - frame->parent = forge->stack; - frame->ref = ref; - - if (ref) { - forge->stack = frame; // Don't push, so walking the stack is always safe - } - - return ref; -} - -/** Pop a stack frame. This must be called when a container is finished. */ -static inline void -lv2_atom_forge_pop(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame) -{ - if (frame->ref) { - // If frame has a valid ref, it must be the top of the stack - assert(frame == forge->stack); - forge->stack = frame->parent; - } - // Otherwise, frame was not pushed because of overflow, do nothing -} - -/** Return true iff the top of the stack has the given type. */ -static inline bool -lv2_atom_forge_top_is(LV2_Atom_Forge* forge, uint32_t type) -{ - return forge->stack && forge->stack->ref && - (lv2_atom_forge_deref(forge, forge->stack->ref)->type == type); -} - -/** Return true iff `type` is an atom:Object. */ -static inline bool -lv2_atom_forge_is_object_type(const LV2_Atom_Forge* forge, uint32_t type) -{ - return (type == forge->Object || type == forge->Blank || - type == forge->Resource); -} - -/** Return true iff `type` is an atom:Object with a blank ID. */ -static inline bool -lv2_atom_forge_is_blank(const LV2_Atom_Forge* forge, - uint32_t type, - const LV2_Atom_Object_Body* body) -{ - return (type == forge->Blank || (type == forge->Object && body->id == 0)); -} - -/** - @} - @name Output Configuration - @{ -*/ - -/** Set the output buffer where `forge` will write atoms. */ -static inline void -lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size) -{ - forge->buf = buf; - forge->size = (uint32_t)size; - forge->offset = 0; - forge->deref = NULL; - forge->sink = NULL; - forge->handle = NULL; - forge->stack = NULL; -} - -/** - Set the sink function where `forge` will write output. - - The return value of forge functions is an LV2_Atom_Forge_Ref which is an - integer type safe to use as a pointer but is otherwise opaque. The sink - function must return a ref that can be dereferenced to access as least - sizeof(LV2_Atom) bytes of the written data, so sizes can be updated. For - ringbuffers, this should be possible as long as the size of the buffer is a - multiple of sizeof(LV2_Atom), since atoms are always aligned. - - Note that 0 is an invalid reference, so if you are using a buffer offset be - sure to offset it such that 0 is never a valid reference. You will get - confusing errors otherwise. -*/ -static inline void -lv2_atom_forge_set_sink(LV2_Atom_Forge* forge, - LV2_Atom_Forge_Sink sink, - LV2_Atom_Forge_Deref_Func deref, - LV2_Atom_Forge_Sink_Handle handle) -{ - forge->buf = NULL; - forge->size = forge->offset = 0; - forge->deref = deref; - forge->sink = sink; - forge->handle = handle; - forge->stack = NULL; -} - -/** - @} - @name Low Level Output - @{ -*/ - -/** - Write raw output. This is used internally, but is also useful for writing - atom types not explicitly supported by the forge API. Note the caller is - responsible for ensuring the output is appropriately padded. -*/ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_raw(LV2_Atom_Forge* forge, const void* data, uint32_t size) -{ - LV2_Atom_Forge_Ref out = 0; - if (forge->sink) { - out = forge->sink(forge->handle, data, size); - } else { - out = (LV2_Atom_Forge_Ref)forge->buf + forge->offset; - uint8_t* mem = forge->buf + forge->offset; - if (forge->offset + size > forge->size) { - return 0; - } - forge->offset += size; - memcpy(mem, data, size); - } - for (LV2_Atom_Forge_Frame* f = forge->stack; f; f = f->parent) { - lv2_atom_forge_deref(forge, f->ref)->size += size; - } - return out; -} - -/** Pad output accordingly so next write is 64-bit aligned. */ -static inline void -lv2_atom_forge_pad(LV2_Atom_Forge* forge, uint32_t written) -{ - const uint64_t pad = 0; - const uint32_t pad_size = lv2_atom_pad_size(written) - written; - lv2_atom_forge_raw(forge, &pad, pad_size); -} - -/** Write raw output, padding to 64-bits as necessary. */ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_write(LV2_Atom_Forge* forge, const void* data, uint32_t size) -{ - LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, data, size); - if (out) { - lv2_atom_forge_pad(forge, size); - } - return out; -} - -/** Write a null-terminated string body. */ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_string_body(LV2_Atom_Forge* forge, const char* str, uint32_t len) -{ - LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, str, len); - if (out && (out = lv2_atom_forge_raw(forge, "", 1))) { - lv2_atom_forge_pad(forge, len + 1); - } - return out; -} - -/** - @} - @name Atom Output - @{ -*/ - -/** Write an atom:Atom header. */ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_atom(LV2_Atom_Forge* forge, uint32_t size, uint32_t type) -{ - const LV2_Atom a = {size, type}; - return lv2_atom_forge_raw(forge, &a, sizeof(a)); -} - -/** Write a primitive (fixed-size) atom. */ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_primitive(LV2_Atom_Forge* forge, const LV2_Atom* a) -{ - return ( - lv2_atom_forge_top_is(forge, forge->Vector) - ? lv2_atom_forge_raw(forge, LV2_ATOM_BODY_CONST(a), a->size) - : lv2_atom_forge_write(forge, a, (uint32_t)sizeof(LV2_Atom) + a->size)); -} - -/** Write an atom:Int. */ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_int(LV2_Atom_Forge* forge, int32_t val) -{ - const LV2_Atom_Int a = {{sizeof(val), forge->Int}, val}; - return lv2_atom_forge_primitive(forge, (const LV2_Atom*)&a); -} - -/** Write an atom:Long. */ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_long(LV2_Atom_Forge* forge, int64_t val) -{ - const LV2_Atom_Long a = {{sizeof(val), forge->Long}, val}; - return lv2_atom_forge_primitive(forge, (const LV2_Atom*)&a); -} - -/** Write an atom:Float. */ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_float(LV2_Atom_Forge* forge, float val) -{ - const LV2_Atom_Float a = {{sizeof(val), forge->Float}, val}; - return lv2_atom_forge_primitive(forge, (const LV2_Atom*)&a); -} - -/** Write an atom:Double. */ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_double(LV2_Atom_Forge* forge, double val) -{ - const LV2_Atom_Double a = {{sizeof(val), forge->Double}, val}; - return lv2_atom_forge_primitive(forge, (const LV2_Atom*)&a); -} - -/** Write an atom:Bool. */ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_bool(LV2_Atom_Forge* forge, bool val) -{ - const LV2_Atom_Bool a = {{sizeof(int32_t), forge->Bool}, val ? 1 : 0}; - return lv2_atom_forge_primitive(forge, (const LV2_Atom*)&a); -} - -/** Write an atom:URID. */ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_urid(LV2_Atom_Forge* forge, LV2_URID id) -{ - const LV2_Atom_URID a = {{sizeof(id), forge->URID}, id}; - return lv2_atom_forge_primitive(forge, (const LV2_Atom*)&a); -} - -/** Write an atom compatible with atom:String. Used internally. */ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_typed_string(LV2_Atom_Forge* forge, - uint32_t type, - const char* str, - uint32_t len) -{ - const LV2_Atom_String a = {{len + 1, type}}; - LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, &a, sizeof(a)); - if (out) { - if (!lv2_atom_forge_string_body(forge, str, len)) { - LV2_Atom* atom = lv2_atom_forge_deref(forge, out); - atom->size = atom->type = 0; - out = 0; - } - } - return out; -} - -/** Write an atom:String. Note that `str` need not be NULL terminated. */ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_string(LV2_Atom_Forge* forge, const char* str, uint32_t len) -{ - return lv2_atom_forge_typed_string(forge, forge->String, str, len); -} - -/** - Write an atom:URI. Note that `uri` need not be NULL terminated. - This does not map the URI, but writes the complete URI string. To write - a mapped URI, use lv2_atom_forge_urid(). -*/ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_uri(LV2_Atom_Forge* forge, const char* uri, uint32_t len) -{ - return lv2_atom_forge_typed_string(forge, forge->URI, uri, len); -} - -/** Write an atom:Path. Note that `path` need not be NULL terminated. */ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_path(LV2_Atom_Forge* forge, const char* path, uint32_t len) -{ - return lv2_atom_forge_typed_string(forge, forge->Path, path, len); -} - -/** Write an atom:Literal. */ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_literal(LV2_Atom_Forge* forge, - const char* str, - uint32_t len, - uint32_t datatype, - uint32_t lang) -{ - const LV2_Atom_Literal a = { - {(uint32_t)(sizeof(LV2_Atom_Literal) - sizeof(LV2_Atom) + len + 1), - forge->Literal}, - {datatype, lang}}; - LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, &a, sizeof(a)); - if (out) { - if (!lv2_atom_forge_string_body(forge, str, len)) { - LV2_Atom* atom = lv2_atom_forge_deref(forge, out); - atom->size = atom->type = 0; - out = 0; - } - } - return out; -} - -/** Start an atom:Vector. */ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_vector_head(LV2_Atom_Forge* forge, - LV2_Atom_Forge_Frame* frame, - uint32_t child_size, - uint32_t child_type) -{ - const LV2_Atom_Vector a = {{sizeof(LV2_Atom_Vector_Body), forge->Vector}, - {child_size, child_type}}; - return lv2_atom_forge_push( - forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); -} - -/** Write a complete atom:Vector. */ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_vector(LV2_Atom_Forge* forge, - uint32_t child_size, - uint32_t child_type, - uint32_t n_elems, - const void* elems) -{ - const LV2_Atom_Vector a = { - {(uint32_t)sizeof(LV2_Atom_Vector_Body) + n_elems * child_size, - forge->Vector}, - {child_size, child_type}}; - LV2_Atom_Forge_Ref out = lv2_atom_forge_write(forge, &a, sizeof(a)); - if (out) { - lv2_atom_forge_write(forge, elems, child_size * n_elems); - } - return out; -} - -/** - Write the header of an atom:Tuple. - - The passed frame will be initialised to represent this tuple. To complete - the tuple, write a sequence of atoms, then pop the frame with - lv2_atom_forge_pop(). - - For example: - @code - // Write tuple (1, 2.0) - LV2_Atom_Forge_Frame frame; - LV2_Atom* tup = (LV2_Atom*)lv2_atom_forge_tuple(forge, &frame); - lv2_atom_forge_int(forge, 1); - lv2_atom_forge_float(forge, 2.0); - lv2_atom_forge_pop(forge, &frame); - @endcode -*/ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_tuple(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame) -{ - const LV2_Atom_Tuple a = {{0, forge->Tuple}}; - return lv2_atom_forge_push( - forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); -} - -/** - Write the header of an atom:Object. - - The passed frame will be initialised to represent this object. To complete - the object, write a sequence of properties, then pop the frame with - lv2_atom_forge_pop(). - - For example: - @code - LV2_URID eg_Cat = map("http://example.org/Cat"); - LV2_URID eg_name = map("http://example.org/name"); - - // Start object with type eg_Cat and blank ID - LV2_Atom_Forge_Frame frame; - lv2_atom_forge_object(forge, &frame, 0, eg_Cat); - - // Append property eg:name = "Hobbes" - lv2_atom_forge_key(forge, eg_name); - lv2_atom_forge_string(forge, "Hobbes", strlen("Hobbes")); - - // Finish object - lv2_atom_forge_pop(forge, &frame); - @endcode -*/ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_object(LV2_Atom_Forge* forge, - LV2_Atom_Forge_Frame* frame, - LV2_URID id, - LV2_URID otype) -{ - const LV2_Atom_Object a = { - {(uint32_t)sizeof(LV2_Atom_Object_Body), forge->Object}, {id, otype}}; - return lv2_atom_forge_push( - forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); -} - -/** - The same as lv2_atom_forge_object(), but for object:Resource. - - This function is deprecated and should not be used in new code. - Use lv2_atom_forge_object() directly instead. -*/ -LV2_DEPRECATED -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_resource(LV2_Atom_Forge* forge, - LV2_Atom_Forge_Frame* frame, - LV2_URID id, - LV2_URID otype) -{ - const LV2_Atom_Object a = { - {(uint32_t)sizeof(LV2_Atom_Object_Body), forge->Resource}, {id, otype}}; - return lv2_atom_forge_push( - forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); -} - -/** - The same as lv2_atom_forge_object(), but for object:Blank. - - This function is deprecated and should not be used in new code. - Use lv2_atom_forge_object() directly instead. -*/ -LV2_DEPRECATED -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_blank(LV2_Atom_Forge* forge, - LV2_Atom_Forge_Frame* frame, - uint32_t id, - LV2_URID otype) -{ - const LV2_Atom_Object a = { - {(uint32_t)sizeof(LV2_Atom_Object_Body), forge->Blank}, {id, otype}}; - return lv2_atom_forge_push( - forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); -} - -/** - Write a property key in an Object, to be followed by the value. - - See lv2_atom_forge_object() documentation for an example. -*/ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_key(LV2_Atom_Forge* forge, LV2_URID key) -{ - const LV2_Atom_Property_Body a = {key, 0, {0, 0}}; - return lv2_atom_forge_write(forge, &a, 2 * (uint32_t)sizeof(uint32_t)); -} - -/** - Write the header for a property body in an object, with context. - - If you do not need the context, which is almost certainly the case, - use the simpler lv2_atom_forge_key() instead. -*/ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_property_head(LV2_Atom_Forge* forge, - LV2_URID key, - LV2_URID context) -{ - const LV2_Atom_Property_Body a = {key, context, {0, 0}}; - return lv2_atom_forge_write(forge, &a, 2 * (uint32_t)sizeof(uint32_t)); -} - -/** - Write the header for a Sequence. -*/ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_sequence_head(LV2_Atom_Forge* forge, - LV2_Atom_Forge_Frame* frame, - uint32_t unit) -{ - const LV2_Atom_Sequence a = { - {(uint32_t)sizeof(LV2_Atom_Sequence_Body), forge->Sequence}, {unit, 0}}; - return lv2_atom_forge_push( - forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a))); -} - -/** - Write the time stamp header of an Event (in a Sequence) in audio frames. - After this, call the appropriate forge method(s) to write the body. Note - the returned reference is to an LV2_Event which is NOT an Atom. -*/ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_frame_time(LV2_Atom_Forge* forge, int64_t frames) -{ - return lv2_atom_forge_write(forge, &frames, sizeof(frames)); -} - -/** - Write the time stamp header of an Event (in a Sequence) in beats. After - this, call the appropriate forge method(s) to write the body. Note the - returned reference is to an LV2_Event which is NOT an Atom. -*/ -static inline LV2_Atom_Forge_Ref -lv2_atom_forge_beat_time(LV2_Atom_Forge* forge, double beats) -{ - return lv2_atom_forge_write(forge, &beats, sizeof(beats)); -} - -LV2_RESTORE_WARNINGS - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -/** - @} - @} -*/ - -#endif /* LV2_ATOM_FORGE_H */ diff --git a/lv2/atom/manifest.ttl b/lv2/atom/manifest.ttl deleted file mode 100644 index 3cb5134..0000000 --- a/lv2/atom/manifest.ttl +++ /dev/null @@ -1,9 +0,0 @@ -@prefix lv2: <http://lv2plug.in/ns/lv2core#> . -@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . - -<http://lv2plug.in/ns/ext/atom> - a lv2:Specification ; - lv2:minorVersion 2 ; - lv2:microVersion 4 ; - rdfs:seeAlso <atom.ttl> . - diff --git a/lv2/atom/meson.build b/lv2/atom/meson.build deleted file mode 100644 index 3dc43b3..0000000 --- a/lv2/atom/meson.build +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2022 David Robillard <d@drobilla.net> -# SPDX-License-Identifier: CC0-1.0 OR ISC - -name = 'atom' -path = 'ns' / 'ext' / name - -atom_data = files( - 'atom.meta.ttl', - 'atom.ttl', - 'manifest.ttl', -) - -headers = files( - 'atom.h', - 'forge.h', - 'util.h', -) - -tests = [ - 'atom-test', - 'forge-overflow-test', -] - -# Install specification bundle -install_data(atom_data, install_dir: lv2dir / name + '.lv2') -install_headers(headers, subdir: 'lv2' / name) -if get_option('old_headers') - install_headers(headers, subdir: 'lv2' / 'lv2plug.in' / path) -endif - -# Build and run tests -if not get_option('tests').disabled() - foreach test : tests - test(test, - executable( - test, - files('@0@.c'.format(test)), - c_args: c_suppressions, - include_directories: include_directories('../../'), - ), - suite: 'unit') - endforeach -endif - -# Build documentation -if build_docs - custom_target( - name + '.html', - command: lv2specgen_command_prefix + [ - '--docdir=../../html', - '--style-uri=../../aux/style.css', - '@INPUT@', - '@OUTPUT@', - ], - depends: doc_deps, - input: files('atom.ttl'), - install: true, - install_dir: lv2_docdir / 'ns' / 'ext', - output: name + '.html', - ) -endif diff --git a/lv2/atom/util.h b/lv2/atom/util.h deleted file mode 100644 index 16d2c00..0000000 --- a/lv2/atom/util.h +++ /dev/null @@ -1,523 +0,0 @@ -/* - Copyright 2008-2015 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 - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef LV2_ATOM_UTIL_H -#define LV2_ATOM_UTIL_H - -/** - @file util.h Helper functions for the LV2 Atom extension. - - Note these functions are all static inline, do not take their address. - - This header is non-normative, it is provided for convenience. -*/ - -/** - @defgroup util Utilities - @ingroup atom - - Utilities for working with atoms. - - @{ -*/ - -#include "lv2/atom/atom.h" - -#include <stdarg.h> -#include <stdbool.h> -#include <stdint.h> -#include <string.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/** Pad a size to 64 bits. */ -static inline uint32_t -lv2_atom_pad_size(uint32_t size) -{ - return (size + 7U) & (~7U); -} - -/** Return the total size of `atom`, including the header. */ -static inline uint32_t -lv2_atom_total_size(const LV2_Atom* atom) -{ - return (uint32_t)sizeof(LV2_Atom) + atom->size; -} - -/** Return true iff `atom` is null. */ -static inline bool -lv2_atom_is_null(const LV2_Atom* atom) -{ - return !atom || (atom->type == 0 && atom->size == 0); -} - -/** Return true iff `a` is equal to `b`. */ -static inline bool -lv2_atom_equals(const LV2_Atom* a, const LV2_Atom* b) -{ - return (a == b) || ((a->type == b->type) && (a->size == b->size) && - !memcmp(a + 1, b + 1, a->size)); -} - -/** - @name Sequence Iterator - @{ -*/ - -/** Get an iterator pointing to the first event in a Sequence body. */ -static inline LV2_Atom_Event* -lv2_atom_sequence_begin(const LV2_Atom_Sequence_Body* body) -{ - return (LV2_Atom_Event*)(body + 1); -} - -/** Get an iterator pointing to the end of a Sequence body. */ -static inline LV2_Atom_Event* -lv2_atom_sequence_end(const LV2_Atom_Sequence_Body* body, uint32_t size) -{ - return (LV2_Atom_Event*)((const uint8_t*)body + lv2_atom_pad_size(size)); -} - -/** Return true iff `i` has reached the end of `body`. */ -static inline bool -lv2_atom_sequence_is_end(const LV2_Atom_Sequence_Body* body, - uint32_t size, - const LV2_Atom_Event* i) -{ - return (const uint8_t*)i >= ((const uint8_t*)body + size); -} - -/** Return an iterator to the element following `i`. */ -static inline LV2_Atom_Event* -lv2_atom_sequence_next(const LV2_Atom_Event* i) -{ - return (LV2_Atom_Event*)((const uint8_t*)i + sizeof(LV2_Atom_Event) + - lv2_atom_pad_size(i->body.size)); -} - -/** - A macro for iterating over all events in a Sequence. - @param seq The sequence to iterate over - @param iter The name of the iterator - - This macro is used similarly to a for loop (which it expands to), for - example: - - @code - LV2_ATOM_SEQUENCE_FOREACH(sequence, ev) { - // Do something with ev (an LV2_Atom_Event*) here... - } - @endcode -*/ -#define LV2_ATOM_SEQUENCE_FOREACH(seq, iter) \ - for (LV2_Atom_Event * iter = lv2_atom_sequence_begin(&(seq)->body); \ - !lv2_atom_sequence_is_end(&(seq)->body, (seq)->atom.size, (iter)); \ - (iter) = lv2_atom_sequence_next(iter)) - -/** Like LV2_ATOM_SEQUENCE_FOREACH but for a headerless sequence body. */ -#define LV2_ATOM_SEQUENCE_BODY_FOREACH(body, size, iter) \ - for (LV2_Atom_Event * iter = lv2_atom_sequence_begin(body); \ - !lv2_atom_sequence_is_end(body, size, (iter)); \ - (iter) = lv2_atom_sequence_next(iter)) - -/** - @} - @name Sequence Utilities - @{ -*/ - -/** - Clear all events from `sequence`. - - This simply resets the size field, the other fields are left untouched. -*/ -static inline void -lv2_atom_sequence_clear(LV2_Atom_Sequence* seq) -{ - seq->atom.size = sizeof(LV2_Atom_Sequence_Body); -} - -/** - Append an event at the end of `sequence`. - - @param seq Sequence to append to. - @param capacity Total capacity of the sequence atom - (as set by the host for sequence output ports). - @param event Event to write. - - @return A pointer to the newly written event in `seq`, - or NULL on failure (insufficient space). -*/ -static inline LV2_Atom_Event* -lv2_atom_sequence_append_event(LV2_Atom_Sequence* seq, - uint32_t capacity, - const LV2_Atom_Event* event) -{ - const uint32_t total_size = (uint32_t)sizeof(*event) + event->body.size; - if (capacity - seq->atom.size < total_size) { - return NULL; - } - - LV2_Atom_Event* e = lv2_atom_sequence_end(&seq->body, seq->atom.size); - memcpy(e, event, total_size); - - seq->atom.size += lv2_atom_pad_size(total_size); - - return e; -} - -/** - @} - @name Tuple Iterator - @{ -*/ - -/** Get an iterator pointing to the first element in `tup`. */ -static inline LV2_Atom* -lv2_atom_tuple_begin(const LV2_Atom_Tuple* tup) -{ - return (LV2_Atom*)(LV2_ATOM_BODY(tup)); -} - -/** Return true iff `i` has reached the end of `body`. */ -static inline bool -lv2_atom_tuple_is_end(const void* body, uint32_t size, const LV2_Atom* i) -{ - return (const uint8_t*)i >= ((const uint8_t*)body + size); -} - -/** Return an iterator to the element following `i`. */ -static inline LV2_Atom* -lv2_atom_tuple_next(const LV2_Atom* i) -{ - return (LV2_Atom*)((const uint8_t*)i + sizeof(LV2_Atom) + - lv2_atom_pad_size(i->size)); -} - -/** - A macro for iterating over all properties of a Tuple. - @param tuple The tuple to iterate over - @param iter The name of the iterator - - This macro is used similarly to a for loop (which it expands to), for - example: - - @code - LV2_ATOM_TUPLE_FOREACH(tuple, elem) { - // Do something with elem (an LV2_Atom*) here... - } - @endcode -*/ -#define LV2_ATOM_TUPLE_FOREACH(tuple, iter) \ - for (LV2_Atom * iter = lv2_atom_tuple_begin(tuple); \ - !lv2_atom_tuple_is_end( \ - LV2_ATOM_BODY(tuple), (tuple)->atom.size, (iter)); \ - (iter) = lv2_atom_tuple_next(iter)) - -/** Like LV2_ATOM_TUPLE_FOREACH but for a headerless tuple body. */ -#define LV2_ATOM_TUPLE_BODY_FOREACH(body, size, iter) \ - for (LV2_Atom * iter = (LV2_Atom*)(body); \ - !lv2_atom_tuple_is_end(body, size, (iter)); \ - (iter) = lv2_atom_tuple_next(iter)) - -/** - @} - @name Object Iterator - @{ -*/ - -/** Return a pointer to the first property in `body`. */ -static inline LV2_Atom_Property_Body* -lv2_atom_object_begin(const LV2_Atom_Object_Body* body) -{ - return (LV2_Atom_Property_Body*)(body + 1); -} - -/** Return true iff `i` has reached the end of `obj`. */ -static inline bool -lv2_atom_object_is_end(const LV2_Atom_Object_Body* body, - uint32_t size, - const LV2_Atom_Property_Body* i) -{ - return (const uint8_t*)i >= ((const uint8_t*)body + size); -} - -/** Return an iterator to the property following `i`. */ -static inline LV2_Atom_Property_Body* -lv2_atom_object_next(const LV2_Atom_Property_Body* i) -{ - const LV2_Atom* const value = - (const LV2_Atom*)((const uint8_t*)i + 2 * sizeof(uint32_t)); - return (LV2_Atom_Property_Body*)((const uint8_t*)i + - lv2_atom_pad_size( - (uint32_t)sizeof(LV2_Atom_Property_Body) + - value->size)); -} - -/** - A macro for iterating over all properties of an Object. - @param obj The object to iterate over - @param iter The name of the iterator - - This macro is used similarly to a for loop (which it expands to), for - example: - - @code - LV2_ATOM_OBJECT_FOREACH(object, i) { - // Do something with i (an LV2_Atom_Property_Body*) here... - } - @endcode -*/ -#define LV2_ATOM_OBJECT_FOREACH(obj, iter) \ - for (LV2_Atom_Property_Body * iter = lv2_atom_object_begin(&(obj)->body); \ - !lv2_atom_object_is_end(&(obj)->body, (obj)->atom.size, (iter)); \ - (iter) = lv2_atom_object_next(iter)) - -/** Like LV2_ATOM_OBJECT_FOREACH but for a headerless object body. */ -#define LV2_ATOM_OBJECT_BODY_FOREACH(body, size, iter) \ - for (LV2_Atom_Property_Body * iter = lv2_atom_object_begin(body); \ - !lv2_atom_object_is_end(body, size, (iter)); \ - (iter) = lv2_atom_object_next(iter)) - -/** - @} - @name Object Query - @{ -*/ - -/** A single entry in an Object query. */ -typedef struct { - uint32_t key; /**< Key to query (input set by user) */ - const LV2_Atom** value; /**< Found value (output set by query function) */ -} LV2_Atom_Object_Query; - -/** Sentinel for lv2_atom_object_query(). */ -static const LV2_Atom_Object_Query LV2_ATOM_OBJECT_QUERY_END = {0, NULL}; - -/** - Get an object's values for various keys. - - The value pointer of each item in `query` will be set to the location of - the corresponding value in `object`. Every value pointer in `query` MUST - be initialised to NULL. This function reads `object` in a single linear - sweep. By allocating `query` on the stack, objects can be "queried" - quickly without allocating any memory. This function is realtime safe. - - This function can only do "flat" queries, it is not smart enough to match - variables in nested objects. - - For example: - @code - const LV2_Atom* name = NULL; - const LV2_Atom* age = NULL; - LV2_Atom_Object_Query q[] = { - { urids.eg_name, &name }, - { urids.eg_age, &age }, - LV2_ATOM_OBJECT_QUERY_END - }; - lv2_atom_object_query(obj, q); - // name and age are now set to the appropriate values in obj, or NULL. - @endcode -*/ -static inline int -lv2_atom_object_query(const LV2_Atom_Object* object, - LV2_Atom_Object_Query* query) -{ - int matches = 0; - int n_queries = 0; - - /* Count number of query keys so we can short-circuit when done */ - for (LV2_Atom_Object_Query* q = query; q->key; ++q) { - ++n_queries; - } - - LV2_ATOM_OBJECT_FOREACH (object, prop) { - for (LV2_Atom_Object_Query* q = query; q->key; ++q) { - if (q->key == prop->key && !*q->value) { - *q->value = &prop->value; - if (++matches == n_queries) { - return matches; - } - break; - } - } - } - return matches; -} - -/** - Body only version of lv2_atom_object_get(). -*/ -static inline int -lv2_atom_object_body_get(uint32_t size, const LV2_Atom_Object_Body* body, ...) -{ - int matches = 0; - int n_queries = 0; - - /* Count number of keys so we can short-circuit when done */ - va_list args; - va_start(args, body); - for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) { - if (!va_arg(args, const LV2_Atom**)) { - va_end(args); - return -1; - } - } - va_end(args); - - LV2_ATOM_OBJECT_BODY_FOREACH (body, size, prop) { - va_start(args, body); - for (int i = 0; i < n_queries; ++i) { - uint32_t qkey = va_arg(args, uint32_t); - const LV2_Atom** qval = va_arg(args, const LV2_Atom**); - if (qkey == prop->key && !*qval) { - *qval = &prop->value; - if (++matches == n_queries) { - va_end(args); - return matches; - } - break; - } - } - va_end(args); - } - return matches; -} - -/** - Variable argument version of lv2_atom_object_query(). - - This is nicer-looking in code, but a bit more error-prone since it is not - type safe and the argument list must be terminated. - - The arguments should be a series of uint32_t key and const LV2_Atom** value - pairs, terminated by a zero key. The value pointers MUST be initialized to - NULL. For example: - - @code - const LV2_Atom* name = NULL; - const LV2_Atom* age = NULL; - lv2_atom_object_get(obj, - uris.name_key, &name, - uris.age_key, &age, - 0); - @endcode -*/ -static inline int -lv2_atom_object_get(const LV2_Atom_Object* object, ...) -{ - int matches = 0; - int n_queries = 0; - - /* Count number of keys so we can short-circuit when done */ - va_list args; - va_start(args, object); - for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) { - if (!va_arg(args, const LV2_Atom**)) { - va_end(args); - return -1; - } - } - va_end(args); - - LV2_ATOM_OBJECT_FOREACH (object, prop) { - va_start(args, object); - for (int i = 0; i < n_queries; ++i) { - uint32_t qkey = va_arg(args, uint32_t); - const LV2_Atom** qval = va_arg(args, const LV2_Atom**); - if (qkey == prop->key && !*qval) { - *qval = &prop->value; - if (++matches == n_queries) { - va_end(args); - return matches; - } - break; - } - } - va_end(args); - } - return matches; -} - -/** - Variable argument version of lv2_atom_object_query() with types. - - This is like lv2_atom_object_get(), but each entry has an additional - parameter to specify the required type. Only atoms with a matching type - will be selected. - - The arguments should be a series of uint32_t key, const LV2_Atom**, uint32_t - type triples, terminated by a zero key. The value pointers MUST be - initialized to NULL. For example: - - @code - const LV2_Atom_String* name = NULL; - const LV2_Atom_Int* age = NULL; - lv2_atom_object_get(obj, - uris.name_key, &name, uris.atom_String, - uris.age_key, &age, uris.atom_Int - 0); - @endcode -*/ -static inline int -lv2_atom_object_get_typed(const LV2_Atom_Object* object, ...) -{ - int matches = 0; - int n_queries = 0; - - /* Count number of keys so we can short-circuit when done */ - va_list args; - va_start(args, object); - for (n_queries = 0; va_arg(args, uint32_t); ++n_queries) { - if (!va_arg(args, const LV2_Atom**) || !va_arg(args, uint32_t)) { - va_end(args); - return -1; - } - } - va_end(args); - - LV2_ATOM_OBJECT_FOREACH (object, prop) { - va_start(args, object); - for (int i = 0; i < n_queries; ++i) { - const uint32_t qkey = va_arg(args, uint32_t); - const LV2_Atom** qval = va_arg(args, const LV2_Atom**); - const uint32_t qtype = va_arg(args, uint32_t); - if (!*qval && qkey == prop->key && qtype == prop->value.type) { - *qval = &prop->value; - if (++matches == n_queries) { - va_end(args); - return matches; - } - break; - } - } - va_end(args); - } - return matches; -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -/** - @} - @} -*/ - -#endif /* LV2_ATOM_UTIL_H */ |