1 /*
2   Copyright 2008-2012 David Robillard <http://drobilla.net>
3 
4   Permission to use, copy, modify, and/or distribute this software for any
5   purpose with or without fee is hereby granted, provided that the above
6   copyright notice and this permission notice appear in all copies.
7 
8   THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16 
17 /**
18    @file event-helpers.h Helper functions for the LV2 Event extension
19    <http://lv2plug.in/ns/ext/event>.
20 */
21 
22 #ifndef LV2_EVENT_HELPERS_H
23 #define LV2_EVENT_HELPERS_H
24 
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "event.h"
30 
31 #ifdef __cplusplus
32 extern "C" {
33 #else
34 #    include <stdbool.h>
35 #endif
36 
37 /** @file
38  * Helper functions for the LV2 Event extension
39  * <http://lv2plug.in/ns/ext/event>.
40  *
41  * These functions are provided for convenience only, use of them is not
42  * required for supporting lv2ev (i.e. the events extension is defined by the
43  * raw buffer format described in lv2_event.h and NOT by this API).
44  *
45  * Note that these functions are all static inline which basically means:
46  * do not take the address of these functions. */
47 
48 
49 /** Pad a size to 64 bits (for event sizes) */
50 static inline uint16_t
lv2_event_pad_size(uint16_t size)51 lv2_event_pad_size(uint16_t size)
52 {
53 	return (uint16_t)(size + 7U) & (uint16_t)(~7U);
54 }
55 
56 
57 /** Initialize (empty, reset..) an existing event buffer.
58  * The contents of buf are ignored entirely and overwritten, except capacity
59  * which is unmodified. */
60 static inline void
lv2_event_buffer_reset(LV2_Event_Buffer * buf,uint16_t stamp_type,uint8_t * data)61 lv2_event_buffer_reset(LV2_Event_Buffer*  buf,
62                        uint16_t           stamp_type,
63                        uint8_t*           data)
64 {
65 	buf->data = data;
66 	buf->header_size = sizeof(LV2_Event_Buffer);
67 	buf->stamp_type = stamp_type;
68 	buf->event_count = 0;
69 	buf->size = 0;
70 }
71 
72 
73 /** Allocate a new, empty event buffer. */
74 static inline LV2_Event_Buffer*
lv2_event_buffer_new(uint32_t capacity,uint16_t stamp_type)75 lv2_event_buffer_new(uint32_t capacity, uint16_t stamp_type)
76 {
77 	const size_t      size = sizeof(LV2_Event_Buffer) + capacity;
78 	LV2_Event_Buffer* buf  = (LV2_Event_Buffer*)malloc(size);
79 	if (buf != NULL) {
80 		buf->capacity = capacity;
81 		lv2_event_buffer_reset(buf, stamp_type, (uint8_t *)(buf + 1));
82 		return buf;
83 	} else {
84 		return NULL;
85 	}
86 }
87 
88 
89 /** An iterator over an LV2_Event_Buffer.
90  *
91  * Multiple simultaneous read iterators over a single buffer is fine,
92  * but changing the buffer invalidates all iterators (e.g. RW Lock). */
93 typedef struct {
94 	LV2_Event_Buffer* buf;
95 	uint32_t          offset;
96 } LV2_Event_Iterator;
97 
98 
99 /** Reset an iterator to point to the start of @a buf.
100  * @return True if @a iter is valid, otherwise false (buffer is empty) */
101 static inline bool
lv2_event_begin(LV2_Event_Iterator * iter,LV2_Event_Buffer * buf)102 lv2_event_begin(LV2_Event_Iterator* iter,
103                 LV2_Event_Buffer*   buf)
104 {
105 	iter->buf = buf;
106 	iter->offset = 0;
107 	return (buf->size > 0);
108 }
109 
110 
111 /** Check if @a iter is valid.
112  * @return True if @a iter is valid, otherwise false (past end of buffer) */
113 static inline bool
lv2_event_is_valid(LV2_Event_Iterator * iter)114 lv2_event_is_valid(LV2_Event_Iterator* iter)
115 {
116 	return (iter->buf && (iter->offset < iter->buf->size));
117 }
118 
119 
120 /** Advance @a iter forward one event.
121  * @a iter must be valid.
122  * @return True if @a iter is valid, otherwise false (reached end of buffer) */
123 static inline bool
lv2_event_increment(LV2_Event_Iterator * iter)124 lv2_event_increment(LV2_Event_Iterator* iter)
125 {
126 	if (!lv2_event_is_valid(iter)) {
127 		return false;
128 	}
129 
130 	LV2_Event* const ev = (LV2_Event*)(
131 			(uint8_t*)iter->buf->data + iter->offset);
132 
133 	iter->offset += lv2_event_pad_size(
134 		(uint16_t)((uint16_t)sizeof(LV2_Event) + ev->size));
135 
136 	return true;
137 }
138 
139 
140 /** Dereference an event iterator (get the event currently pointed at).
141  * @a iter must be valid.
142  * @a data if non-NULL, will be set to point to the contents of the event
143  *         returned.
144  * @return A Pointer to the event @a iter is currently pointing at, or NULL
145  *         if the end of the buffer is reached (in which case @a data is
146  *         also set to NULL). */
147 static inline LV2_Event*
lv2_event_get(LV2_Event_Iterator * iter,uint8_t ** data)148 lv2_event_get(LV2_Event_Iterator* iter,
149               uint8_t**           data)
150 {
151 	if (!lv2_event_is_valid(iter)) {
152 		return NULL;
153 	}
154 
155 	LV2_Event* const ev = (LV2_Event*)(
156 			(uint8_t*)iter->buf->data + iter->offset);
157 
158 	if (data)
159 		*data = (uint8_t*)ev + sizeof(LV2_Event);
160 
161 	return ev;
162 }
163 
164 
165 /** Write an event at @a iter.
166  * The event (if any) pointed to by @a iter will be overwritten, and @a iter
167  * incremented to point to the following event (i.e. several calls to this
168  * function can be done in sequence without twiddling iter in-between).
169  * @return True if event was written, otherwise false (buffer is full). */
170 static inline bool
lv2_event_write(LV2_Event_Iterator * iter,uint32_t frames,uint32_t subframes,uint16_t type,uint16_t size,const uint8_t * data)171 lv2_event_write(LV2_Event_Iterator* iter,
172                 uint32_t            frames,
173                 uint32_t            subframes,
174                 uint16_t            type,
175                 uint16_t            size,
176                 const uint8_t*      data)
177 {
178 	if (!iter->buf)
179 		return false;
180 
181 	if (iter->buf->capacity - iter->buf->size < sizeof(LV2_Event) + size)
182 		return false;
183 
184 	LV2_Event* const ev = (LV2_Event*)(
185 			(uint8_t*)iter->buf->data + iter->offset);
186 
187 	ev->frames = frames;
188 	ev->subframes = subframes;
189 	ev->type = type;
190 	ev->size = size;
191 	memcpy((uint8_t*)ev + sizeof(LV2_Event), data, size);
192 	++iter->buf->event_count;
193 
194 	size = lv2_event_pad_size((uint16_t)(sizeof(LV2_Event) + size));
195 	iter->buf->size += size;
196 	iter->offset    += size;
197 
198 	return true;
199 }
200 
201 
202 /** Reserve space for an event in the buffer and return a pointer to
203     the memory where the caller can write the event data, or NULL if there
204     is not enough room in the buffer. */
205 static inline uint8_t*
lv2_event_reserve(LV2_Event_Iterator * iter,uint32_t frames,uint32_t subframes,uint16_t type,uint16_t size)206 lv2_event_reserve(LV2_Event_Iterator* iter,
207                   uint32_t frames,
208                   uint32_t subframes,
209                   uint16_t type,
210                   uint16_t size)
211 {
212 	const uint16_t total_size = (uint16_t)(sizeof(LV2_Event) + size);
213 	if (iter->buf->capacity - iter->buf->size < total_size)
214 		return NULL;
215 
216 	LV2_Event* const ev = (LV2_Event*)(
217 		(uint8_t*)iter->buf->data + iter->offset);
218 
219 	ev->frames = frames;
220 	ev->subframes = subframes;
221 	ev->type = type;
222 	ev->size = size;
223 	++iter->buf->event_count;
224 
225 	const uint16_t padded_size = lv2_event_pad_size(total_size);
226 	iter->buf->size += padded_size;
227 	iter->offset    += padded_size;
228 
229 	return (uint8_t*)ev + sizeof(LV2_Event);
230 }
231 
232 
233 /** Write an event at @a iter.
234  * The event (if any) pointed to by @a iter will be overwritten, and @a iter
235  * incremented to point to the following event (i.e. several calls to this
236  * function can be done in sequence without twiddling iter in-between).
237  * @return True if event was written, otherwise false (buffer is full). */
238 static inline bool
lv2_event_write_event(LV2_Event_Iterator * iter,const LV2_Event * ev,const uint8_t * data)239 lv2_event_write_event(LV2_Event_Iterator* iter,
240                       const LV2_Event*    ev,
241                       const uint8_t*      data)
242 {
243 	const uint16_t total_size = (uint16_t)(sizeof(LV2_Event) + ev->size);
244 	if (iter->buf->capacity - iter->buf->size < total_size)
245 		return false;
246 
247 	LV2_Event* const write_ev = (LV2_Event*)(
248 		(uint8_t*)iter->buf->data + iter->offset);
249 
250 	*write_ev = *ev;
251 	memcpy((uint8_t*)write_ev + sizeof(LV2_Event), data, ev->size);
252 	++iter->buf->event_count;
253 
254 	const uint16_t padded_size = lv2_event_pad_size(total_size);
255 	iter->buf->size += padded_size;
256 	iter->offset    += padded_size;
257 
258 	return true;
259 }
260 
261 #ifdef __cplusplus
262 }  /* extern "C" */
263 #endif
264 
265 #endif /* LV2_EVENT_HELPERS_H */
266 
267