diff options
author | David Robillard <d@drobilla.net> | 2012-02-18 06:55:00 +0000 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2012-02-18 06:55:00 +0000 |
commit | d0b752f49f0af4aa64c92d49d8e6ec1e6b545c5b (patch) | |
tree | c87f129e3613c0d96d82813bfb97efdcb4d687f2 /lv2 | |
parent | 9c2c83e11d161442f3064b1ae7bc8b778b57542d (diff) | |
download | lv2-d0b752f49f0af4aa64c92d49d8e6ec1e6b545c5b.tar.xz |
Make forge API more fool-proof and automatically update container sizes to any depth.
Diffstat (limited to 'lv2')
-rw-r--r-- | lv2/lv2plug.in/ns/ext/atom/atom-test.c | 79 | ||||
-rw-r--r-- | lv2/lv2plug.in/ns/ext/atom/forge.h | 202 |
2 files changed, 154 insertions, 127 deletions
diff --git a/lv2/lv2plug.in/ns/ext/atom/atom-test.c b/lv2/lv2plug.in/ns/ext/atom/atom-test.c index 55d453c..2cc0da9 100644 --- a/lv2/lv2plug.in/ns/ext/atom/atom-test.c +++ b/lv2/lv2plug.in/ns/ext/atom/atom-test.c @@ -86,47 +86,48 @@ main() 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*)lv2_atom_forge_resource( - &forge, NULL, 0, eg_Object); + &forge, &obj_frame, 0, eg_Object); // eg_one = (Int32)1 - lv2_atom_forge_property_head(&forge, obj, eg_one, 0); - LV2_Atom_Int32* one = lv2_atom_forge_int32(&forge, obj, 1); + lv2_atom_forge_property_head(&forge, eg_one, 0); + LV2_Atom_Int32* one = lv2_atom_forge_int32(&forge, 1); if (one->value != 1) { return test_fail("%d != 1\n", one->value); } // eg_two = (Int64)2 - lv2_atom_forge_property_head(&forge, obj, eg_two, 0); - LV2_Atom_Int64* two = lv2_atom_forge_int64(&forge, obj, 2); + lv2_atom_forge_property_head(&forge, eg_two, 0); + LV2_Atom_Int64* two = lv2_atom_forge_int64(&forge, 2); if (two->value != 2) { return test_fail("%ld != 2\n", two->value); } // eg_three = (Float)3.0 - lv2_atom_forge_property_head(&forge, obj, eg_three, 0); - LV2_Atom_Float* three = lv2_atom_forge_float(&forge, obj, 3.0f); + lv2_atom_forge_property_head(&forge, eg_three, 0); + LV2_Atom_Float* three = lv2_atom_forge_float(&forge, 3.0f); if (three->value != 3) { return test_fail("%f != 3\n", three->value); } // eg_four = (Double)4.0 - lv2_atom_forge_property_head(&forge, obj, eg_four, 0); - LV2_Atom_Double* four = lv2_atom_forge_double(&forge, obj, 4.0); + lv2_atom_forge_property_head(&forge, eg_four, 0); + LV2_Atom_Double* four = lv2_atom_forge_double(&forge, 4.0); if (four->value != 4) { return test_fail("%ld != 4\n", four->value); } // eg_true = (Bool)1 - lv2_atom_forge_property_head(&forge, obj, eg_true, 0); - LV2_Atom_Bool* t = lv2_atom_forge_bool(&forge, obj, true); + lv2_atom_forge_property_head(&forge, eg_true, 0); + LV2_Atom_Bool* t = lv2_atom_forge_bool(&forge, true); if (t->value != 1) { return test_fail("%ld != 1 (true)\n", t->value); } // eg_false = (Bool)0 - lv2_atom_forge_property_head(&forge, obj, eg_false, 0); - LV2_Atom_Bool* f = lv2_atom_forge_bool(&forge, obj, false); + lv2_atom_forge_property_head(&forge, eg_false, 0); + LV2_Atom_Bool* f = lv2_atom_forge_bool(&forge, false); if (f->value != 0) { return test_fail("%ld != 0 (false)\n", f->value); } @@ -134,8 +135,8 @@ main() // eg_uri = (URI)"http://example.org/value" const uint8_t* ustr = (const uint8_t*)"http://example.org/value"; const size_t ustr_len = strlen((const char*)ustr); - lv2_atom_forge_property_head(&forge, obj, eg_uri, 0); - LV2_Atom_String* uri = lv2_atom_forge_uri(&forge, obj, ustr, ustr_len); + lv2_atom_forge_property_head(&forge, eg_uri, 0); + LV2_Atom_String* uri = lv2_atom_forge_uri(&forge, ustr, ustr_len); uint8_t* body = (uint8_t*)LV2_ATOM_BODY(uri); if (strcmp((const char*)body, (const char*)ustr)) { return test_fail("%s != \"%s\"\n", @@ -144,25 +145,25 @@ main() // eg_urid = (URID)"http://example.org/value" LV2_URID eg_value = urid_map(NULL, "http://example.org/value"); - lv2_atom_forge_property_head(&forge, obj, eg_urid, 0); - LV2_Atom_URID* urid = lv2_atom_forge_urid(&forge, obj, eg_value); + lv2_atom_forge_property_head(&forge, eg_urid, 0); + LV2_Atom_URID* urid = lv2_atom_forge_urid(&forge, eg_value); if (urid->id != eg_value) { return test_fail("%u != %u\n", urid->id, eg_value); } // eg_string = (String)"hello" - lv2_atom_forge_property_head(&forge, obj, eg_string, 0); + lv2_atom_forge_property_head(&forge, eg_string, 0); LV2_Atom_String* string = lv2_atom_forge_string( - &forge, obj, (const uint8_t*)"hello", strlen("hello")); + &forge, (const uint8_t*)"hello", strlen("hello")); uint8_t* sbody = (uint8_t*)LV2_ATOM_BODY(string); if (strcmp((const char*)sbody, "hello")) { return test_fail("%s != \"hello\"\n", (const char*)body); } // eg_literal = (Literal)"hello"@fr - lv2_atom_forge_property_head(&forge, obj, eg_literal, 0); + lv2_atom_forge_property_head(&forge, eg_literal, 0); LV2_Atom_Literal* literal = lv2_atom_forge_literal( - &forge, obj, (const uint8_t*)"bonjour", strlen("bonjour"), + &forge, (const uint8_t*)"bonjour", strlen("bonjour"), 0, urid_map(NULL, "http://lexvo.org/id/term/fr")); body = (uint8_t*)LV2_ATOM_CONTENTS(LV2_Atom_Literal, literal); if (strcmp((const char*)body, "bonjour")) { @@ -170,12 +171,14 @@ main() } // eg_tuple = "foo",true - lv2_atom_forge_property_head(&forge, obj, eg_tuple, 0); - LV2_Atom_Tuple* tuple = lv2_atom_forge_tuple(&forge, obj); - LV2_Atom_String* tup0 = lv2_atom_forge_string( - &forge, (LV2_Atom*)tuple, (const uint8_t*)"foo", strlen("foo")); - LV2_Atom_Bool* tup1 = lv2_atom_forge_bool(&forge, (LV2_Atom*)tuple, true); - obj->size += ((LV2_Atom*)tuple)->size; + lv2_atom_forge_property_head(&forge, eg_tuple, 0); + LV2_Atom_Forge_Frame tuple_frame; + LV2_Atom_Tuple* tuple = (LV2_Atom_Tuple*)lv2_atom_forge_tuple( + &forge, &tuple_frame); + LV2_Atom_String* tup0 = lv2_atom_forge_string( + &forge, (const uint8_t*)"foo", strlen("foo")); + LV2_Atom_Bool* tup1 = lv2_atom_forge_bool(&forge, true); + lv2_atom_forge_pop(&forge, &tuple_frame); LV2_Atom_Tuple_Iter i = lv2_tuple_begin(tuple); if (lv2_tuple_is_end(tuple, i)) { return test_fail("Tuple iterator is empty\n"); @@ -198,23 +201,26 @@ main() } // eg_vector = (Vector<Int32>)1,2,3,4 - lv2_atom_forge_property_head(&forge, obj, eg_vector, 0); + lv2_atom_forge_property_head(&forge, eg_vector, 0); int32_t elems[] = { 1, 2, 3, 4 }; LV2_Atom_Vector* vector = lv2_atom_forge_vector( - &forge, obj, 4, forge.Int32, sizeof(int32_t), elems); + &forge, 4, forge.Int32, sizeof(int32_t), 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_seq = (Sequence)1, 2 - lv2_atom_forge_property_head(&forge, obj, eg_seq, 0); - LV2_Atom_Sequence* seq = lv2_atom_forge_sequence_head(&forge, obj, 0, 0); - lv2_atom_forge_audio_time(&forge, (LV2_Atom*)seq, 0, 0); - lv2_atom_forge_int32(&forge, (LV2_Atom*)seq, 1); - lv2_atom_forge_audio_time(&forge, (LV2_Atom*)seq, 1, 0); - lv2_atom_forge_int32(&forge, (LV2_Atom*)seq, 2); - obj->size += seq->atom.size - sizeof(LV2_Atom); + lv2_atom_forge_property_head(&forge, eg_seq, 0); + LV2_Atom_Forge_Frame seq_frame; + LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)lv2_atom_forge_sequence_head(&forge, &seq_frame, 0); + lv2_atom_forge_audio_time(&forge, 0, 0); + lv2_atom_forge_int32(&forge, 1); + lv2_atom_forge_audio_time(&forge, 1, 0); + lv2_atom_forge_int32(&forge, 2); + lv2_atom_forge_pop(&forge, &seq_frame); + + lv2_atom_forge_pop(&forge, &obj_frame); // Test equality LV2_Atom_Int32 itwo = { { forge.Int32, sizeof(int32_t) }, 2 }; @@ -279,6 +285,7 @@ main() { eg_four, &matches.four }, { eg_true, &matches.affirmative }, { eg_false, &matches.negative }, + { eg_uri, &matches.uri }, { eg_urid, &matches.urid }, { eg_string, &matches.string }, { eg_literal, &matches.literal }, diff --git a/lv2/lv2plug.in/ns/ext/atom/forge.h b/lv2/lv2plug.in/ns/ext/atom/forge.h index 9735302..0f32db3 100644 --- a/lv2/lv2plug.in/ns/ext/atom/forge.h +++ b/lv2/lv2plug.in/ns/ext/atom/forge.h @@ -19,8 +19,7 @@ This file provides a simple API which can be used to create complex nested atoms by calling the provided functions to append atoms (or atom headers) in - the correct order. The size of the parent atom is automatically updated, - but the caller must handle this situation if atoms are more deeply nested. + the correct order. All output is written to a user-provided buffer. This entire API is realtime safe and suitable for writing to output port buffers in the run @@ -53,9 +52,13 @@ typedef uint32_t (*LV2_Atom_Forge_Sink)(LV2_Atom_Forge_Sink_Handle handle, const void* buf, uint32_t size); -/** - A "forge" for creating atoms by appending to a buffer. -*/ +/** 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* atom; +} LV2_Atom_Forge_Frame; + +/** A "forge" for creating atoms by appending to a buffer. */ typedef struct { uint8_t* buf; uint32_t offset; @@ -64,6 +67,8 @@ typedef struct { LV2_Atom_Forge_Sink sink; LV2_Atom_Forge_Sink_Handle handle; + LV2_Atom_Forge_Frame* stack; + LV2_URID Blank; LV2_URID Bool; LV2_URID Double; @@ -81,7 +86,25 @@ typedef struct { LV2_URID Vector; } LV2_Atom_Forge; -/** Set the output buffer where @c forge will write atoms. */ +static inline LV2_Atom* +lv2_atom_forge_push(LV2_Atom_Forge* forge, + LV2_Atom_Forge_Frame* frame, + LV2_Atom* atom) +{ + frame->parent = forge->stack; + frame->atom = atom; + forge->stack = frame; + return atom; +} + +static inline void +lv2_atom_forge_pop(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame) +{ + assert(frame == forge->stack); + forge->stack = frame->parent; +} + +/** Set the output buffer where @p forge will write atoms. */ static inline void lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size) { @@ -90,6 +113,7 @@ lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size) forge->offset = 0; } +/** Set the sink function where @p forge will write output. */ static inline void lv2_atom_forge_set_sink(LV2_Atom_Forge* forge, LV2_Atom_Forge_Sink sink, @@ -102,15 +126,16 @@ lv2_atom_forge_set_sink(LV2_Atom_Forge* forge, } /** - Initialise @c forge. + Initialise @p forge. - URIs will be mapped using @c map and stored, a reference to @c map itself is + URIs will be mapped using @p map and stored, a reference to @p 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->stack = NULL; forge->Blank = map->map(map->handle, LV2_ATOM_URI "#Blank"); forge->Bool = map->map(map->handle, LV2_ATOM_URI "#Bool"); forge->Double = map->map(map->handle, LV2_ATOM_URI "#Double"); @@ -130,7 +155,6 @@ lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map) static inline void* lv2_atom_forge_write_nopad(LV2_Atom_Forge* forge, - LV2_Atom* parent, const void* data, uint32_t size) { @@ -138,97 +162,94 @@ lv2_atom_forge_write_nopad(LV2_Atom_Forge* forge, if (forge->offset + size > forge->size) { return NULL; } - if (parent) { - parent->size += size; - } forge->offset += size; memcpy(out, data, size); + for (LV2_Atom_Forge_Frame* f = forge->stack; f; f = f->parent) { + f->atom->size += size; + } return out; } static inline void lv2_atom_forge_pad(LV2_Atom_Forge* forge, - LV2_Atom* parent, uint32_t written) { const uint64_t pad = 0; const uint32_t pad_size = lv2_atom_pad_size(written) - written; - lv2_atom_forge_write_nopad(forge, parent, &pad, pad_size); + lv2_atom_forge_write_nopad(forge, &pad, pad_size); } static inline void* lv2_atom_forge_write(LV2_Atom_Forge* forge, - LV2_Atom* parent, const void* data, uint32_t size) { - void* out = lv2_atom_forge_write_nopad(forge, parent, data, size); + void* out = lv2_atom_forge_write_nopad(forge, data, size); if (out) { - lv2_atom_forge_pad(forge, parent, size); + lv2_atom_forge_pad(forge, size); } return out; } /** Write an atom:Int32. */ static inline LV2_Atom_Int32* -lv2_atom_forge_int32(LV2_Atom_Forge* forge, LV2_Atom* parent, int32_t val) +lv2_atom_forge_int32(LV2_Atom_Forge* forge, int32_t val) { const LV2_Atom_Int32 a = { { forge->Int32, sizeof(val) }, val }; - return (LV2_Atom_Int32*)lv2_atom_forge_write(forge, parent, &a, sizeof(a)); + return (LV2_Atom_Int32*)lv2_atom_forge_write(forge, &a, sizeof(a)); } /** Write an atom:Int64. */ static inline LV2_Atom_Int64* -lv2_atom_forge_int64(LV2_Atom_Forge* forge, LV2_Atom* parent, int64_t val) +lv2_atom_forge_int64(LV2_Atom_Forge* forge, int64_t val) { const LV2_Atom_Int64 a = { { forge->Int64, sizeof(val) }, val }; - return (LV2_Atom_Int64*)lv2_atom_forge_write(forge, parent, &a, sizeof(a)); + return (LV2_Atom_Int64*)lv2_atom_forge_write(forge, &a, sizeof(a)); } /** Write an atom:Float. */ static inline LV2_Atom_Float* -lv2_atom_forge_float(LV2_Atom_Forge* forge, LV2_Atom* parent, float val) +lv2_atom_forge_float(LV2_Atom_Forge* forge, float val) { const LV2_Atom_Float a = { { forge->Float, sizeof(val) }, val }; - return (LV2_Atom_Float*)lv2_atom_forge_write(forge, parent, &a, sizeof(a)); + return (LV2_Atom_Float*)lv2_atom_forge_write(forge, &a, sizeof(a)); } /** Write an atom:Double. */ static inline LV2_Atom_Double* -lv2_atom_forge_double(LV2_Atom_Forge* forge, LV2_Atom* parent, double val) +lv2_atom_forge_double(LV2_Atom_Forge* forge, double val) { const LV2_Atom_Double a = { { forge->Double, sizeof(val) }, val }; return (LV2_Atom_Double*)lv2_atom_forge_write( - forge, parent, &a, sizeof(a)); + forge, &a, sizeof(a)); } /** Write an atom:Bool. */ static inline LV2_Atom_Bool* -lv2_atom_forge_bool(LV2_Atom_Forge* forge, LV2_Atom* parent, bool val) +lv2_atom_forge_bool(LV2_Atom_Forge* forge, bool val) { const LV2_Atom_Bool a = { { forge->Bool, sizeof(val) }, val }; - return (LV2_Atom_Bool*)lv2_atom_forge_write(forge, parent, &a, sizeof(a)); + return (LV2_Atom_Bool*)lv2_atom_forge_write(forge, &a, sizeof(a)); } /** Write an atom:URID. */ static inline LV2_Atom_URID* -lv2_atom_forge_urid(LV2_Atom_Forge* forge, LV2_Atom* parent, LV2_URID id) +lv2_atom_forge_urid(LV2_Atom_Forge* forge, LV2_URID id) { const LV2_Atom_URID a = { { forge->Int32, sizeof(id) }, id }; - return (LV2_Atom_URID*)lv2_atom_forge_write(forge, parent, &a, sizeof(a)); + return (LV2_Atom_URID*)lv2_atom_forge_write(forge, &a, sizeof(a)); } /** Write a string body. Used internally. */ static inline uint8_t* lv2_atom_forge_string_body(LV2_Atom_Forge* forge, - LV2_Atom* parent, const uint8_t* str, size_t len) { uint8_t* out = NULL; - if ((out = lv2_atom_forge_write_nopad(forge, parent, str, len)) - && (out = lv2_atom_forge_write_nopad(forge, parent, "", 1))) { - lv2_atom_forge_pad(forge, parent, len + 1); + if ((out = lv2_atom_forge_write_nopad(forge, str, len)) + && (out = lv2_atom_forge_write_nopad(forge, "", 1))) { + lv2_atom_forge_pad(forge, len + 1); } return out; } @@ -236,15 +257,14 @@ lv2_atom_forge_string_body(LV2_Atom_Forge* forge, /** Write an atom:String. Note that @p str need not be NULL terminated. */ static inline LV2_Atom_String* lv2_atom_forge_string(LV2_Atom_Forge* forge, - LV2_Atom* parent, const uint8_t* str, size_t len) { const LV2_Atom_String a = { { forge->String, len + 1 } }; LV2_Atom_String* out = (LV2_Atom_String*) - lv2_atom_forge_write_nopad(forge, parent, &a, sizeof(a)); + lv2_atom_forge_write_nopad(forge, &a, sizeof(a)); if (out) { - if (!lv2_atom_forge_string_body(forge, parent, str, len)) { + if (!lv2_atom_forge_string_body(forge, str, len)) { out->atom.type = 0; out->atom.size = 0; out = NULL; @@ -260,17 +280,16 @@ lv2_atom_forge_string(LV2_Atom_Forge* forge, */ static inline LV2_Atom_String* lv2_atom_forge_uri(LV2_Atom_Forge* forge, - LV2_Atom* parent, const uint8_t* uri, size_t len) { const LV2_Atom_String a = { { forge->URI, len + 1 } }; LV2_Atom_String* out = (LV2_Atom_String*) - lv2_atom_forge_write_nopad(forge, parent, &a, sizeof(a)); + lv2_atom_forge_write_nopad(forge, &a, sizeof(a)); if (!out) { return NULL; } - if (!lv2_atom_forge_string_body(forge, parent, uri, len)) { + if (!lv2_atom_forge_string_body(forge, uri, len)) { out->atom.type = 0; out->atom.size = 0; return NULL; @@ -281,7 +300,6 @@ lv2_atom_forge_uri(LV2_Atom_Forge* forge, /** Write an atom:Literal. */ static inline LV2_Atom_Literal* lv2_atom_forge_literal(LV2_Atom_Forge* forge, - LV2_Atom* parent, const uint8_t* str, size_t len, uint32_t datatype, @@ -294,9 +312,9 @@ lv2_atom_forge_literal(LV2_Atom_Forge* forge, lang }; LV2_Atom_Literal* out = (LV2_Atom_Literal*) - lv2_atom_forge_write_nopad(forge, parent, &a, sizeof(a)); + lv2_atom_forge_write_nopad(forge, &a, sizeof(a)); if (out) { - if (!lv2_atom_forge_string_body(forge, parent, str, len)) { + if (!lv2_atom_forge_string_body(forge, str, len)) { out->atom.type = 0; out->atom.size = 0; out = NULL; @@ -308,7 +326,6 @@ lv2_atom_forge_literal(LV2_Atom_Forge* forge, /** Write an atom:Vector header, but not the vector body. */ static inline LV2_Atom_Vector* lv2_atom_forge_vector_head(LV2_Atom_Forge* forge, - LV2_Atom* parent, uint32_t elem_count, uint32_t elem_type, uint32_t elem_size) @@ -320,22 +337,21 @@ lv2_atom_forge_vector_head(LV2_Atom_Forge* forge, elem_type }; return (LV2_Atom_Vector*)lv2_atom_forge_write( - forge, parent, &a, sizeof(a)); + forge, &a, sizeof(a)); } /** Write a complete atom:Vector. */ static inline LV2_Atom_Vector* lv2_atom_forge_vector(LV2_Atom_Forge* forge, - LV2_Atom* parent, uint32_t elem_count, uint32_t elem_type, uint32_t elem_size, void* elems) { LV2_Atom_Vector* out = lv2_atom_forge_vector_head( - forge, parent, elem_count, elem_type, elem_size); + forge, elem_count, elem_type, elem_size); if (out) { - lv2_atom_forge_write(forge, parent, elems, elem_size * elem_count); + lv2_atom_forge_write(forge, elems, elem_size * elem_count); } return out; } @@ -343,32 +359,34 @@ lv2_atom_forge_vector(LV2_Atom_Forge* forge, /** Write the header of an atom:Tuple. - To complete the tuple, write a sequence of atoms, always passing the - returned tuple as the @c parent parameter (or otherwise ensuring the size is - updated correctly). + 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* tup = (LV2_Atom*)lv2_atom_forge_tuple(forge, NULL); - lv2_atom_forge_int32(forge, tup, 1); - lv2_atom_forge_float(forge, tup, 2.0); + LV2_Atom_Forge_Frame frame; + LV2_Atom* tup = (LV2_Atom*)lv2_atom_forge_tuple(forge, &frame); + lv2_atom_forge_int32(forge, 1); + lv2_atom_forge_float(forge, 2.0); + lv2_atom_forge_pop(forge, &frame); @endcode */ -static inline LV2_Atom_Tuple* -lv2_atom_forge_tuple(LV2_Atom_Forge* forge, - LV2_Atom* parent) +static inline LV2_Atom* +lv2_atom_forge_tuple(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame) { - const LV2_Atom_Tuple a = { { forge->Tuple, 0 } }; - return (LV2_Atom_Tuple*)lv2_atom_forge_write(forge, parent, &a, sizeof(a)); + const LV2_Atom_Tuple a = { { forge->Tuple, 0 } }; + LV2_Atom* atom = lv2_atom_forge_write(forge, &a, sizeof(a)); + return lv2_atom_forge_push(forge, frame, atom); } /** Write the header of an atom:Resource. - To complete the object, write a sequence of properties, always passing the - object as the @c parent parameter (or otherwise ensuring the size is updated - correctly). + 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 @@ -376,42 +394,48 @@ lv2_atom_forge_tuple(LV2_Atom_Forge* forge, LV2_URID eg_name = map("http://example.org/name"); // Write object header - LV2_Atom* obj = (LV2_Atom*)lv2_atom_forge_resource(forge, NULL, 0, eg_Cat); + LV2_Atom_Forge_Frame frame; + LV2_Atom* obj = (LV2_Atom*)lv2_atom_forge_resource(forge, &frame, 1, eg_Cat); // Write property: eg:name = "Hobbes" - lv2_atom_forge_property_head(forge, obj, eg_name, 0); - lv2_atom_forge_string(forge, obj, "Hobbes", strlen("Hobbes")); + lv2_atom_forge_property_head(forge, eg_name, 0); + lv2_atom_forge_string(forge, "Hobbes", strlen("Hobbes")); + + // Finish object + lv2_atom_forge_pop(forge, &frame); @endcode */ -static inline LV2_Atom_Object* -lv2_atom_forge_resource(LV2_Atom_Forge* forge, - LV2_Atom* parent, - LV2_URID id, - LV2_URID otype) +static inline LV2_Atom* +lv2_atom_forge_resource(LV2_Atom_Forge* forge, + LV2_Atom_Forge_Frame* frame, + LV2_URID id, + LV2_URID otype) { const LV2_Atom_Object a = { { forge->Resource, sizeof(LV2_Atom_Object) - sizeof(LV2_Atom) }, id, otype }; - return (LV2_Atom_Object*)lv2_atom_forge_write(forge, parent, &a, sizeof(a)); + LV2_Atom* atom = (LV2_Atom*)lv2_atom_forge_write(forge, &a, sizeof(a)); + return lv2_atom_forge_push(forge, frame, atom); } /** The same as lv2_atom_forge_resource(), but for object:Blank. */ -static inline LV2_Atom_Object* -lv2_atom_forge_blank(LV2_Atom_Forge* forge, - LV2_Atom* parent, - uint32_t id, - LV2_URID otype) +static inline LV2_Atom* +lv2_atom_forge_blank(LV2_Atom_Forge* forge, + LV2_Atom_Forge_Frame* frame, + uint32_t id, + LV2_URID otype) { const LV2_Atom_Object a = { { forge->Blank, sizeof(LV2_Atom_Object) - sizeof(LV2_Atom) }, id, otype }; - return (LV2_Atom_Object*)lv2_atom_forge_write(forge, parent, &a, sizeof(a)); + LV2_Atom* atom = (LV2_Atom*)lv2_atom_forge_write(forge, &a, sizeof(a)); + return lv2_atom_forge_push(forge, frame, atom); } /** @@ -420,13 +444,12 @@ lv2_atom_forge_blank(LV2_Atom_Forge* forge, */ static inline LV2_Atom_Property_Body* lv2_atom_forge_property_head(LV2_Atom_Forge* forge, - LV2_Atom* parent, LV2_URID key, LV2_URID context) { const LV2_Atom_Property_Body a = { key, context, { 0, 0 } }; return (LV2_Atom_Property_Body*)lv2_atom_forge_write( - forge, parent, &a, 2 * sizeof(uint32_t)); + forge, &a, 2 * sizeof(uint32_t)); } /** @@ -434,48 +457,45 @@ lv2_atom_forge_property_head(LV2_Atom_Forge* forge, The size of the returned sequence will be 0, so passing it as the parent parameter to other forge methods will do the right thing. */ -static inline LV2_Atom_Sequence* -lv2_atom_forge_sequence_head(LV2_Atom_Forge* forge, - LV2_Atom* parent, - uint32_t capacity, - uint32_t unit) +static inline LV2_Atom* +lv2_atom_forge_sequence_head(LV2_Atom_Forge* forge, + LV2_Atom_Forge_Frame* frame, + uint32_t unit) { const LV2_Atom_Sequence a = { { forge->Sequence, sizeof(LV2_Atom_Sequence) - sizeof(LV2_Atom) }, unit, 0 }; - return (LV2_Atom_Sequence*)lv2_atom_forge_write( - forge, parent, &a, sizeof(a)); + LV2_Atom* atom = (LV2_Atom*)lv2_atom_forge_write(forge, &a, sizeof(a)); + return lv2_atom_forge_push(forge, frame, atom); } /** 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, passing - the same @c parent parameter. Note the returned LV2_Event is NOT an Atom. + the same @p parent parameter. Note the returned LV2_Event is NOT an Atom. */ static inline LV2_Atom_Event* lv2_atom_forge_audio_time(LV2_Atom_Forge* forge, - LV2_Atom* parent, uint32_t frames, uint32_t subframes) { const LV2_Atom_Audio_Time a = { frames, subframes }; - return (LV2_Atom_Event*)lv2_atom_forge_write(forge, parent, &a, sizeof(a)); + return (LV2_Atom_Event*)lv2_atom_forge_write(forge, &a, sizeof(a)); } /** 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, passing - the same @c parent parameter. Note the returned LV2_Event is NOT an Atom. + the same @p parent parameter. Note the returned LV2_Event is NOT an Atom. */ static inline LV2_Atom_Event* lv2_atom_forge_beat_time(LV2_Atom_Forge* forge, - LV2_Atom* parent, double beats) { return (LV2_Atom_Event*)lv2_atom_forge_write( - forge, parent, &beats, sizeof(beats)); + forge, &beats, sizeof(beats)); } #ifdef __cplusplus |