From d0b752f49f0af4aa64c92d49d8e6ec1e6b545c5b Mon Sep 17 00:00:00 2001 From: David Robillard Date: Sat, 18 Feb 2012 06:55:00 +0000 Subject: Make forge API more fool-proof and automatically update container sizes to any depth. --- lv2/lv2plug.in/ns/ext/atom/forge.h | 202 ++++++++++++++++++++----------------- 1 file changed, 111 insertions(+), 91 deletions(-) (limited to 'lv2/lv2plug.in/ns/ext/atom/forge.h') 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 -- cgit v1.2.1