fix crash when copy'ing latent plugins
[ardour.git] / libs / ardour / lv2_evbuf.c
index 7877e07950844435f08b7a0e753b4b45f7a55d87..ae6d869b5fac0a87726d453086cbb66b5b56cced 100644 (file)
@@ -14,8 +14,7 @@
   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
 
-#include <stdint.h>
-#include <stdbool.h>
+#include <assert.h>
 #include <string.h>
 #include <stdlib.h>
 
 struct LV2_Evbuf_Impl {
        LV2_Evbuf_Type type;
        uint32_t       capacity;
+       uint32_t       atom_Chunk;
+       uint32_t       atom_Sequence;
        union {
-               LV2_Event_Buffer     event;
-               LV2_Atom_Port_Buffer atom;
+               LV2_Event_Buffer  event;
+               LV2_Atom_Sequence atom;
        } buf;
 };
 
@@ -40,14 +41,19 @@ lv2_evbuf_pad_size(uint32_t size)
 }
 
 LV2_Evbuf*
-lv2_evbuf_new(uint32_t capacity, LV2_Evbuf_Type type, uint32_t atom_type)
+lv2_evbuf_new(uint32_t       capacity,
+              LV2_Evbuf_Type type,
+              uint32_t       atom_Chunk,
+              uint32_t       atom_Sequence)
 {
        // FIXME: memory must be 64-bit aligned
        LV2_Evbuf* evbuf = (LV2_Evbuf*)malloc(
                sizeof(LV2_Evbuf) + sizeof(LV2_Atom_Sequence) + capacity);
-       evbuf->capacity = capacity;
-       lv2_evbuf_set_type(evbuf, type, atom_type);
-       lv2_evbuf_reset(evbuf);
+       evbuf->capacity      = capacity;
+       evbuf->atom_Chunk    = atom_Chunk;
+       evbuf->atom_Sequence = atom_Sequence;
+       lv2_evbuf_set_type(evbuf, type);
+       lv2_evbuf_reset(evbuf, true);
        return evbuf;
 }
 
@@ -58,7 +64,7 @@ lv2_evbuf_free(LV2_Evbuf* evbuf)
 }
 
 void
-lv2_evbuf_set_type(LV2_Evbuf* evbuf, LV2_Evbuf_Type type, uint32_t atom_type)
+lv2_evbuf_set_type(LV2_Evbuf* evbuf, LV2_Evbuf_Type type)
 {
        evbuf->type = type;
        switch (type) {
@@ -67,18 +73,13 @@ lv2_evbuf_set_type(LV2_Evbuf* evbuf, LV2_Evbuf_Type type, uint32_t atom_type)
                evbuf->buf.event.capacity = evbuf->capacity;
                break;
        case LV2_EVBUF_ATOM:
-               evbuf->buf.atom.data       = (LV2_Atom*)(evbuf + 1);
-               evbuf->buf.atom.size       = sizeof(LV2_Atom_Port_Buffer);
-               evbuf->buf.atom.capacity   = evbuf->capacity;
-               evbuf->buf.atom.data->type = atom_type;
-               evbuf->buf.atom.data->size = 0;
                break;
        }
-       lv2_evbuf_reset(evbuf);
+       lv2_evbuf_reset(evbuf, true);
 }
 
 void
-lv2_evbuf_reset(LV2_Evbuf* evbuf)
+lv2_evbuf_reset(LV2_Evbuf* evbuf, bool input)
 {
        switch (evbuf->type) {
        case LV2_EVBUF_EVENT:
@@ -88,7 +89,13 @@ lv2_evbuf_reset(LV2_Evbuf* evbuf)
                evbuf->buf.event.size        = 0;
                break;
        case LV2_EVBUF_ATOM:
-               evbuf->buf.atom.data->size = 0;
+               if (input) {
+                       evbuf->buf.atom.atom.size = sizeof(LV2_Atom_Sequence_Body);
+                       evbuf->buf.atom.atom.type = evbuf->atom_Sequence;
+               } else {
+                       evbuf->buf.atom.atom.size = evbuf->capacity;
+                       evbuf->buf.atom.atom.type = evbuf->atom_Chunk;
+               }
        }
 }
 
@@ -99,11 +106,21 @@ lv2_evbuf_get_size(LV2_Evbuf* evbuf)
        case LV2_EVBUF_EVENT:
                return evbuf->buf.event.size;
        case LV2_EVBUF_ATOM:
-               return evbuf->buf.atom.data->size;
+               assert(evbuf->buf.atom.atom.type != evbuf->atom_Sequence
+                      || evbuf->buf.atom.atom.size >= sizeof(LV2_Atom_Sequence_Body));
+               return evbuf->buf.atom.atom.type == evbuf->atom_Sequence
+                       ? evbuf->buf.atom.atom.size - sizeof(LV2_Atom_Sequence_Body)
+                       : 0;
        }
        return 0;
 }
 
+uint32_t
+lv2_evbuf_get_capacity(LV2_Evbuf* evbuf)
+{
+       return evbuf->capacity;
+}
+
 void*
 lv2_evbuf_get_buffer(LV2_Evbuf* evbuf)
 {
@@ -126,7 +143,7 @@ lv2_evbuf_begin(LV2_Evbuf* evbuf)
 LV2_Evbuf_Iterator
 lv2_evbuf_end(LV2_Evbuf* evbuf)
 {
-       const size_t             size = lv2_evbuf_get_size(evbuf);
+       const uint32_t           size = lv2_evbuf_get_size(evbuf);
        const LV2_Evbuf_Iterator iter = { evbuf, lv2_evbuf_pad_size(size) };
        return iter;
 }
@@ -149,13 +166,13 @@ lv2_evbuf_next(LV2_Evbuf_Iterator iter)
        uint32_t   size;
        switch (evbuf->type) {
        case LV2_EVBUF_EVENT:
-               size    = ((LV2_Event*)(evbuf->buf.event.data + offset))->size;
+               size    = ((LV2_Event*)((uintptr_t)(evbuf->buf.event.data + offset)))->size;
                offset += lv2_evbuf_pad_size(sizeof(LV2_Event) + size);
                break;
        case LV2_EVBUF_ATOM:
-               size = ((LV2_Atom_Event*)
-                       ((char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, evbuf->buf.atom.data)
-                        + offset))->body.size;
+               size = ((LV2_Atom_Event*)((uintptr_t)
+                       ((char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, &evbuf->buf.atom)
+                        + offset)))->body.size;
                offset += lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size);
                break;
        }
@@ -179,14 +196,14 @@ lv2_evbuf_get(LV2_Evbuf_Iterator iter,
                return false;
        }
 
-       LV2_Event_Buffer*     ebuf;
-       LV2_Event*            ev;
-       LV2_Atom_Port_Buffer* abuf;
-       LV2_Atom_Event*       aev;
+       LV2_Event_Buffer*  ebuf;
+       LV2_Event*         ev;
+       LV2_Atom_Sequence* aseq;
+       LV2_Atom_Event*    aev;
        switch (iter.evbuf->type) {
        case LV2_EVBUF_EVENT:
                ebuf = &iter.evbuf->buf.event;
-               ev = (LV2_Event*)ebuf->data + iter.offset;
+               ev = (LV2_Event*)((uintptr_t)((char*)ebuf->data + iter.offset));
                *frames    = ev->frames;
                *subframes = ev->subframes;
                *type      = ev->type;
@@ -194,15 +211,15 @@ lv2_evbuf_get(LV2_Evbuf_Iterator iter,
                *data      = (uint8_t*)ev + sizeof(LV2_Event);
                break;
        case LV2_EVBUF_ATOM:
-               abuf = &iter.evbuf->buf.atom;
-               aev = (LV2_Atom_Event*)(
-                       (char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, abuf->data)
-                       + iter.offset);
+               aseq = (LV2_Atom_Sequence*)&iter.evbuf->buf.atom;
+               aev = (LV2_Atom_Event*)((uintptr_t)(
+                       (char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, aseq)
+                       + iter.offset));
                *frames    = aev->time.frames;
                *subframes = 0;
                *type      = aev->body.type;
                *size      = aev->body.size;
-               *data      = LV2_ATOM_BODY(&aev->body);
+               *data      = (uint8_t*)LV2_ATOM_BODY(&aev->body);
                break;
        }
 
@@ -217,10 +234,10 @@ lv2_evbuf_write(LV2_Evbuf_Iterator* iter,
                 uint32_t            size,
                 const uint8_t*      data)
 {
-       LV2_Event_Buffer*     ebuf;
-       LV2_Event*            ev;
-       LV2_Atom_Port_Buffer* abuf;
-       LV2_Atom_Event*       aev;
+       LV2_Event_Buffer*  ebuf;
+       LV2_Event*         ev;
+       LV2_Atom_Sequence* aseq;
+       LV2_Atom_Event*    aev;
        switch (iter->evbuf->type) {
        case LV2_EVBUF_EVENT:
                ebuf = &iter->evbuf->buf.event;
@@ -228,7 +245,7 @@ lv2_evbuf_write(LV2_Evbuf_Iterator* iter,
                        return false;
                }
 
-               ev = (LV2_Event*)(ebuf->data + iter->offset);
+               ev = (LV2_Event*)((uintptr_t)(ebuf->data + iter->offset));
                ev->frames    = frames;
                ev->subframes = subframes;
                ev->type      = type;
@@ -241,23 +258,26 @@ lv2_evbuf_write(LV2_Evbuf_Iterator* iter,
                iter->offset      += size;
                break;
        case LV2_EVBUF_ATOM:
-               abuf = &iter->evbuf->buf.atom;
-               if (abuf->capacity - abuf->data->size < sizeof(LV2_Atom_Event) + size) {
+               aseq = (LV2_Atom_Sequence*)&iter->evbuf->buf.atom;
+               if (iter->evbuf->capacity - sizeof(LV2_Atom) - aseq->atom.size
+                   < sizeof(LV2_Atom_Event) + size) {
                        return false;
                }
 
-               aev = (LV2_Atom_Event*)(
-                       (char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, abuf->data)
-                       + iter->offset);
+               aev = (LV2_Atom_Event*)((uintptr_t)(
+                       (char*)LV2_ATOM_CONTENTS(LV2_Atom_Sequence, aseq)
+                       + iter->offset));
                aev->time.frames = frames;
                aev->body.type   = type;
                aev->body.size   = size;
                memcpy(LV2_ATOM_BODY(&aev->body), data, size);
 
-               size              = lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size);
-               abuf->data->size += size;
-               iter->offset     += size;
+               size             = lv2_evbuf_pad_size(sizeof(LV2_Atom_Event) + size);
+               aseq->atom.size += size;
+               iter->offset    += size;
                break;
+       default:
+               return false;
        }
 
        return true;