Branch data Line data Source code
1 : : /*
2 : : Copyright 2008-2016 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 forge.h An API for constructing LV2 atoms.
19 : :
20 : : This file provides an API for constructing Atoms which makes it relatively
21 : : simple to build nested atoms of arbitrary complexity without requiring
22 : : dynamic memory allocation.
23 : :
24 : : The API is based on successively appending the appropriate pieces to build a
25 : : complete Atom. The size of containers is automatically updated. Functions
26 : : that begin a container return (via their frame argument) a stack frame which
27 : : must be popped when the container is finished.
28 : :
29 : : All output is written to a user-provided buffer or sink function. This
30 : : makes it popssible to create create atoms on the stack, on the heap, in LV2
31 : : port buffers, in a ringbuffer, or elsewhere, all using the same API.
32 : :
33 : : This entire API is realtime safe if used with a buffer or a realtime safe
34 : : sink, except lv2_atom_forge_init() which is only realtime safe if the URI
35 : : map function is.
36 : :
37 : : Note these functions are all static inline, do not take their address.
38 : :
39 : : This header is non-normative, it is provided for convenience.
40 : : */
41 : :
42 : : /**
43 : : @defgroup forge Forge
44 : : @ingroup atom
45 : : @{
46 : : */
47 : :
48 : : #ifndef LV2_ATOM_FORGE_H
49 : : #define LV2_ATOM_FORGE_H
50 : :
51 : : #include "lv2/atom/atom.h"
52 : : #include "lv2/atom/util.h"
53 : : #include "lv2/core/attributes.h"
54 : : #include "lv2/urid/urid.h"
55 : :
56 : : #include <assert.h>
57 : : #include <stdbool.h>
58 : :
59 : : #ifdef __cplusplus
60 : : extern "C" {
61 : : #endif
62 : :
63 : : // Disable deprecation warnings for Blank and Resource
64 : : LV2_DISABLE_DEPRECATION_WARNINGS
65 : :
66 : : /** Handle for LV2_Atom_Forge_Sink. */
67 : : typedef void* LV2_Atom_Forge_Sink_Handle;
68 : :
69 : : /** A reference to a chunk of written output. */
70 : : typedef intptr_t LV2_Atom_Forge_Ref;
71 : :
72 : : /** Sink function for writing output. See lv2_atom_forge_set_sink(). */
73 : : typedef LV2_Atom_Forge_Ref
74 : : (*LV2_Atom_Forge_Sink)(LV2_Atom_Forge_Sink_Handle handle,
75 : : const void* buf,
76 : : uint32_t size);
77 : :
78 : : /** Function for resolving a reference. See lv2_atom_forge_set_sink(). */
79 : : typedef LV2_Atom*
80 : : (*LV2_Atom_Forge_Deref_Func)(LV2_Atom_Forge_Sink_Handle handle,
81 : : LV2_Atom_Forge_Ref ref);
82 : :
83 : : /** A stack frame used for keeping track of nested Atom containers. */
84 : : typedef struct LV2_Atom_Forge_Frame {
85 : : struct LV2_Atom_Forge_Frame* parent;
86 : : LV2_Atom_Forge_Ref ref;
87 : : } LV2_Atom_Forge_Frame;
88 : :
89 : : /** A "forge" for creating atoms by appending to a buffer. */
90 : : typedef struct {
91 : : uint8_t* buf;
92 : : uint32_t offset;
93 : : uint32_t size;
94 : :
95 : : LV2_Atom_Forge_Sink sink;
96 : : LV2_Atom_Forge_Deref_Func deref;
97 : : LV2_Atom_Forge_Sink_Handle handle;
98 : :
99 : : LV2_Atom_Forge_Frame* stack;
100 : :
101 : : LV2_URID Blank LV2_DEPRECATED;
102 : : LV2_URID Bool;
103 : : LV2_URID Chunk;
104 : : LV2_URID Double;
105 : : LV2_URID Float;
106 : : LV2_URID Int;
107 : : LV2_URID Long;
108 : : LV2_URID Literal;
109 : : LV2_URID Object;
110 : : LV2_URID Path;
111 : : LV2_URID Property;
112 : : LV2_URID Resource LV2_DEPRECATED;
113 : : LV2_URID Sequence;
114 : : LV2_URID String;
115 : : LV2_URID Tuple;
116 : : LV2_URID URI;
117 : : LV2_URID URID;
118 : : LV2_URID Vector;
119 : : } LV2_Atom_Forge;
120 : :
121 : : static inline void
122 : : lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size);
123 : :
124 : : /**
125 : : Initialise `forge`.
126 : :
127 : : URIs will be mapped using `map` and stored, a reference to `map` itself is
128 : : not held.
129 : : */
130 : : static inline void
131 : 175 : lv2_atom_forge_init(LV2_Atom_Forge* forge, LV2_URID_Map* map)
132 : : {
133 : 175 : lv2_atom_forge_set_buffer(forge, NULL, 0);
134 : 175 : forge->Blank = map->map(map->handle, LV2_ATOM__Blank);
135 : 175 : forge->Bool = map->map(map->handle, LV2_ATOM__Bool);
136 : 175 : forge->Chunk = map->map(map->handle, LV2_ATOM__Chunk);
137 : 175 : forge->Double = map->map(map->handle, LV2_ATOM__Double);
138 : 175 : forge->Float = map->map(map->handle, LV2_ATOM__Float);
139 : 175 : forge->Int = map->map(map->handle, LV2_ATOM__Int);
140 : 175 : forge->Long = map->map(map->handle, LV2_ATOM__Long);
141 : 175 : forge->Literal = map->map(map->handle, LV2_ATOM__Literal);
142 : 175 : forge->Object = map->map(map->handle, LV2_ATOM__Object);
143 : 175 : forge->Path = map->map(map->handle, LV2_ATOM__Path);
144 : 175 : forge->Property = map->map(map->handle, LV2_ATOM__Property);
145 : 175 : forge->Resource = map->map(map->handle, LV2_ATOM__Resource);
146 : 175 : forge->Sequence = map->map(map->handle, LV2_ATOM__Sequence);
147 : 175 : forge->String = map->map(map->handle, LV2_ATOM__String);
148 : 175 : forge->Tuple = map->map(map->handle, LV2_ATOM__Tuple);
149 : 175 : forge->URI = map->map(map->handle, LV2_ATOM__URI);
150 : 175 : forge->URID = map->map(map->handle, LV2_ATOM__URID);
151 : 175 : forge->Vector = map->map(map->handle, LV2_ATOM__Vector);
152 : 175 : }
153 : :
154 : : /** Access the Atom pointed to by a reference. */
155 : : static inline LV2_Atom*
156 : 516 : lv2_atom_forge_deref(LV2_Atom_Forge* forge, LV2_Atom_Forge_Ref ref)
157 : : {
158 [ - + ]: 516 : return forge->buf ? (LV2_Atom*)ref : forge->deref(forge->handle, ref);
159 : : }
160 : :
161 : : /**
162 : : @name Object Stack
163 : : @{
164 : : */
165 : :
166 : : /**
167 : : Push a stack frame.
168 : : This is done automatically by container functions (which take a stack frame
169 : : pointer), but may be called by the user to push the top level container when
170 : : writing to an existing Atom.
171 : : */
172 : : static inline LV2_Atom_Forge_Ref
173 : 137 : lv2_atom_forge_push(LV2_Atom_Forge* forge,
174 : : LV2_Atom_Forge_Frame* frame,
175 : : LV2_Atom_Forge_Ref ref)
176 : : {
177 : 137 : frame->parent = forge->stack;
178 : 137 : frame->ref = ref;
179 : :
180 [ + + ]: 137 : if (ref) {
181 : 100 : forge->stack = frame; // Don't push, so walking the stack is always safe
182 : : }
183 : :
184 : 137 : return ref;
185 : : }
186 : :
187 : : /** Pop a stack frame. This must be called when a container is finished. */
188 : : static inline void
189 : 137 : lv2_atom_forge_pop(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame)
190 : : {
191 [ + + ]: 137 : if (frame->ref) {
192 : : // If frame has a valid ref, it must be the top of the stack
193 [ - + ]: 100 : assert(frame == forge->stack);
194 : 100 : forge->stack = frame->parent;
195 : : }
196 : : // Otherwise, frame was not pushed because of overflow, do nothing
197 : 137 : }
198 : :
199 : : /** Return true iff the top of the stack has the given type. */
200 : : static inline bool
201 : 256 : lv2_atom_forge_top_is(LV2_Atom_Forge* forge, uint32_t type)
202 : : {
203 [ + + ][ + - ]: 438 : return forge->stack && forge->stack->ref &&
204 [ + + ]: 182 : (lv2_atom_forge_deref(forge, forge->stack->ref)->type == type);
205 : : }
206 : :
207 : : /** Return true iff `type` is an atom:Object. */
208 : : static inline bool
209 : : lv2_atom_forge_is_object_type(const LV2_Atom_Forge* forge, uint32_t type)
210 : : {
211 : : return (type == forge->Object ||
212 : : type == forge->Blank ||
213 : : type == forge->Resource);
214 : : }
215 : :
216 : : /** Return true iff `type` is an atom:Object with a blank ID. */
217 : : static inline bool
218 : : lv2_atom_forge_is_blank(const LV2_Atom_Forge* forge,
219 : : uint32_t type,
220 : : const LV2_Atom_Object_Body* body)
221 : : {
222 : : return (type == forge->Blank ||
223 : : (type == forge->Object && body->id == 0));
224 : : }
225 : :
226 : : /**
227 : : @}
228 : : @name Output Configuration
229 : : @{
230 : : */
231 : :
232 : : /** Set the output buffer where `forge` will write atoms. */
233 : : static inline void
234 : 368 : lv2_atom_forge_set_buffer(LV2_Atom_Forge* forge, uint8_t* buf, size_t size)
235 : : {
236 : 368 : forge->buf = buf;
237 : 368 : forge->size = (uint32_t)size;
238 : 368 : forge->offset = 0;
239 : 368 : forge->deref = NULL;
240 : 368 : forge->sink = NULL;
241 : 368 : forge->handle = NULL;
242 : 368 : forge->stack = NULL;
243 : 368 : }
244 : :
245 : : /**
246 : : Set the sink function where `forge` will write output.
247 : :
248 : : The return value of forge functions is an LV2_Atom_Forge_Ref which is an
249 : : integer type safe to use as a pointer but is otherwise opaque. The sink
250 : : function must return a ref that can be dereferenced to access as least
251 : : sizeof(LV2_Atom) bytes of the written data, so sizes can be updated. For
252 : : ringbuffers, this should be possible as long as the size of the buffer is a
253 : : multiple of sizeof(LV2_Atom), since atoms are always aligned.
254 : :
255 : : Note that 0 is an invalid reference, so if you are using a buffer offset be
256 : : sure to offset it such that 0 is never a valid reference. You will get
257 : : confusing errors otherwise.
258 : : */
259 : : static inline void
260 : : lv2_atom_forge_set_sink(LV2_Atom_Forge* forge,
261 : : LV2_Atom_Forge_Sink sink,
262 : : LV2_Atom_Forge_Deref_Func deref,
263 : : LV2_Atom_Forge_Sink_Handle handle)
264 : : {
265 : : forge->buf = NULL;
266 : : forge->size = forge->offset = 0;
267 : : forge->deref = deref;
268 : : forge->sink = sink;
269 : : forge->handle = handle;
270 : : forge->stack = NULL;
271 : : }
272 : :
273 : : /**
274 : : @}
275 : : @name Low Level Output
276 : : @{
277 : : */
278 : :
279 : : /**
280 : : Write raw output. This is used internally, but is also useful for writing
281 : : atom types not explicitly supported by the forge API. Note the caller is
282 : : responsible for ensuring the output is approriately padded.
283 : : */
284 : : static inline LV2_Atom_Forge_Ref
285 : 922 : lv2_atom_forge_raw(LV2_Atom_Forge* forge, const void* data, uint32_t size)
286 : : {
287 : 922 : LV2_Atom_Forge_Ref out = 0;
288 [ - + ]: 922 : if (forge->sink) {
289 : 0 : out = forge->sink(forge->handle, data, size);
290 : : } else {
291 : 922 : out = (LV2_Atom_Forge_Ref)forge->buf + forge->offset;
292 : 922 : uint8_t* mem = forge->buf + forge->offset;
293 [ + + ]: 922 : if (forge->offset + size > forge->size) {
294 : 282 : return 0;
295 : : }
296 : 640 : forge->offset += size;
297 : 640 : memcpy(mem, data, size);
298 : : }
299 [ + + ]: 950 : for (LV2_Atom_Forge_Frame* f = forge->stack; f; f = f->parent) {
300 : 310 : lv2_atom_forge_deref(forge, f->ref)->size += size;
301 : : }
302 : 640 : return out;
303 : : }
304 : :
305 : : /** Pad output accordingly so next write is 64-bit aligned. */
306 : : static inline void
307 : 278 : lv2_atom_forge_pad(LV2_Atom_Forge* forge, uint32_t written)
308 : : {
309 : 278 : const uint64_t pad = 0;
310 : 278 : const uint32_t pad_size = lv2_atom_pad_size(written) - written;
311 : 278 : lv2_atom_forge_raw(forge, &pad, pad_size);
312 : 278 : }
313 : :
314 : : /** Write raw output, padding to 64-bits as necessary. */
315 : : static inline LV2_Atom_Forge_Ref
316 : 462 : lv2_atom_forge_write(LV2_Atom_Forge* forge, const void* data, uint32_t size)
317 : : {
318 : 462 : LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, data, size);
319 [ + + ]: 462 : if (out) {
320 : 257 : lv2_atom_forge_pad(forge, size);
321 : : }
322 : 462 : return out;
323 : : }
324 : :
325 : : /** Write a null-terminated string body. */
326 : : static inline LV2_Atom_Forge_Ref
327 : 27 : lv2_atom_forge_string_body(LV2_Atom_Forge* forge,
328 : : const char* str,
329 : : uint32_t len)
330 : : {
331 : 27 : LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, str, len);
332 [ + + ][ + + ]: 27 : if (out && (out = lv2_atom_forge_raw(forge, "", 1))) {
333 : 21 : lv2_atom_forge_pad(forge, len + 1);
334 : : }
335 : 27 : return out;
336 : : }
337 : :
338 : : /**
339 : : @}
340 : : @name Atom Output
341 : : @{
342 : : */
343 : :
344 : : /** Write an atom:Atom header. */
345 : : static inline LV2_Atom_Forge_Ref
346 : : lv2_atom_forge_atom(LV2_Atom_Forge* forge, uint32_t size, uint32_t type)
347 : : {
348 : : const LV2_Atom a = { size, type };
349 : : return lv2_atom_forge_raw(forge, &a, sizeof(a));
350 : : }
351 : :
352 : : /** Write a primitive (fixed-size) atom. */
353 : : static inline LV2_Atom_Forge_Ref
354 : 256 : lv2_atom_forge_primitive(LV2_Atom_Forge* forge, const LV2_Atom* a)
355 : : {
356 : 256 : return (lv2_atom_forge_top_is(forge, forge->Vector)
357 : 76 : ? lv2_atom_forge_raw(forge, LV2_ATOM_BODY_CONST(a), a->size)
358 [ + + ]: 512 : : lv2_atom_forge_write(
359 : 180 : forge, a, (uint32_t)sizeof(LV2_Atom) + a->size));
360 : : }
361 : :
362 : : /** Write an atom:Int. */
363 : : static inline LV2_Atom_Forge_Ref
364 : 218 : lv2_atom_forge_int(LV2_Atom_Forge* forge, int32_t val)
365 : : {
366 : 218 : const LV2_Atom_Int a = { { sizeof(val), forge->Int }, val };
367 : 218 : return lv2_atom_forge_primitive(forge, &a.atom);
368 : : }
369 : :
370 : : /** Write an atom:Long. */
371 : : static inline LV2_Atom_Forge_Ref
372 : 1 : lv2_atom_forge_long(LV2_Atom_Forge* forge, int64_t val)
373 : : {
374 : 1 : const LV2_Atom_Long a = { { sizeof(val), forge->Long }, val };
375 : 1 : return lv2_atom_forge_primitive(forge, &a.atom);
376 : : }
377 : :
378 : : /** Write an atom:Float. */
379 : : static inline LV2_Atom_Forge_Ref
380 : 32 : lv2_atom_forge_float(LV2_Atom_Forge* forge, float val)
381 : : {
382 : 32 : const LV2_Atom_Float a = { { sizeof(val), forge->Float }, val };
383 : 32 : return lv2_atom_forge_primitive(forge, &a.atom);
384 : : }
385 : :
386 : : /** Write an atom:Double. */
387 : : static inline LV2_Atom_Forge_Ref
388 : 1 : lv2_atom_forge_double(LV2_Atom_Forge* forge, double val)
389 : : {
390 : 1 : const LV2_Atom_Double a = { { sizeof(val), forge->Double }, val };
391 : 1 : return lv2_atom_forge_primitive(forge, &a.atom);
392 : : }
393 : :
394 : : /** Write an atom:Bool. */
395 : : static inline LV2_Atom_Forge_Ref
396 : 3 : lv2_atom_forge_bool(LV2_Atom_Forge* forge, bool val)
397 : : {
398 : 3 : const LV2_Atom_Bool a = { { sizeof(int32_t), forge->Bool }, val ? 1 : 0 };
399 : 3 : return lv2_atom_forge_primitive(forge, &a.atom);
400 : : }
401 : :
402 : : /** Write an atom:URID. */
403 : : static inline LV2_Atom_Forge_Ref
404 : 1 : lv2_atom_forge_urid(LV2_Atom_Forge* forge, LV2_URID id)
405 : : {
406 : 1 : const LV2_Atom_URID a = { { sizeof(id), forge->URID }, id };
407 : 1 : return lv2_atom_forge_primitive(forge, &a.atom);
408 : : }
409 : :
410 : : /** Write an atom compatible with atom:String. Used internally. */
411 : : static inline LV2_Atom_Forge_Ref
412 : 52 : lv2_atom_forge_typed_string(LV2_Atom_Forge* forge,
413 : : uint32_t type,
414 : : const char* str,
415 : : uint32_t len)
416 : : {
417 : 52 : const LV2_Atom_String a = { { len + 1, type } };
418 : 52 : LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, &a, sizeof(a));
419 [ + + ]: 52 : if (out) {
420 [ + + ]: 24 : if (!lv2_atom_forge_string_body(forge, str, len)) {
421 : 5 : LV2_Atom* atom = lv2_atom_forge_deref(forge, out);
422 : 5 : atom->size = atom->type = 0;
423 : 5 : out = 0;
424 : : }
425 : : }
426 : 52 : return out;
427 : : }
428 : :
429 : : /** Write an atom:String. Note that `str` need not be NULL terminated. */
430 : : static inline LV2_Atom_Forge_Ref
431 : 50 : lv2_atom_forge_string(LV2_Atom_Forge* forge, const char* str, uint32_t len)
432 : : {
433 : 50 : return lv2_atom_forge_typed_string(forge, forge->String, str, len);
434 : : }
435 : :
436 : : /**
437 : : Write an atom:URI. Note that `uri` need not be NULL terminated.
438 : : This does not map the URI, but writes the complete URI string. To write
439 : : a mapped URI, use lv2_atom_forge_urid().
440 : : */
441 : : static inline LV2_Atom_Forge_Ref
442 : 2 : lv2_atom_forge_uri(LV2_Atom_Forge* forge, const char* uri, uint32_t len)
443 : : {
444 : 2 : return lv2_atom_forge_typed_string(forge, forge->URI, uri, len);
445 : : }
446 : :
447 : : /** Write an atom:Path. Note that `path` need not be NULL terminated. */
448 : : static inline LV2_Atom_Forge_Ref
449 : : lv2_atom_forge_path(LV2_Atom_Forge* forge, const char* path, uint32_t len)
450 : : {
451 : : return lv2_atom_forge_typed_string(forge, forge->Path, path, len);
452 : : }
453 : :
454 : : /** Write an atom:Literal. */
455 : : static inline LV2_Atom_Forge_Ref
456 : 5 : lv2_atom_forge_literal(LV2_Atom_Forge* forge,
457 : : const char* str,
458 : : uint32_t len,
459 : : uint32_t datatype,
460 : : uint32_t lang)
461 : : {
462 : 10 : const LV2_Atom_Literal a = {
463 : 5 : { (uint32_t)(sizeof(LV2_Atom_Literal) - sizeof(LV2_Atom) + len + 1),
464 : 5 : forge->Literal },
465 : : { datatype,
466 : : lang }
467 : : };
468 : 5 : LV2_Atom_Forge_Ref out = lv2_atom_forge_raw(forge, &a, sizeof(a));
469 [ + + ]: 5 : if (out) {
470 [ + + ]: 3 : if (!lv2_atom_forge_string_body(forge, str, len)) {
471 : 1 : LV2_Atom* atom = lv2_atom_forge_deref(forge, out);
472 : 1 : atom->size = atom->type = 0;
473 : 1 : out = 0;
474 : : }
475 : : }
476 : 5 : return out;
477 : : }
478 : :
479 : : /** Start an atom:Vector. */
480 : : static inline LV2_Atom_Forge_Ref
481 : 40 : lv2_atom_forge_vector_head(LV2_Atom_Forge* forge,
482 : : LV2_Atom_Forge_Frame* frame,
483 : : uint32_t child_size,
484 : : uint32_t child_type)
485 : : {
486 : 80 : const LV2_Atom_Vector a = {
487 : 40 : { sizeof(LV2_Atom_Vector_Body), forge->Vector },
488 : : { child_size, child_type }
489 : : };
490 : 40 : return lv2_atom_forge_push(
491 : : forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
492 : : }
493 : :
494 : : /** Write a complete atom:Vector. */
495 : : static inline LV2_Atom_Forge_Ref
496 : 40 : lv2_atom_forge_vector(LV2_Atom_Forge* forge,
497 : : uint32_t child_size,
498 : : uint32_t child_type,
499 : : uint32_t n_elems,
500 : : const void* elems)
501 : : {
502 : 80 : const LV2_Atom_Vector a = {
503 : 40 : { (uint32_t)(sizeof(LV2_Atom_Vector_Body) + n_elems * child_size),
504 : 40 : forge->Vector },
505 : : { child_size, child_type }
506 : : };
507 : 40 : LV2_Atom_Forge_Ref out = lv2_atom_forge_write(forge, &a, sizeof(a));
508 [ + + ]: 40 : if (out) {
509 : 25 : lv2_atom_forge_write(forge, elems, child_size * n_elems);
510 : : }
511 : 40 : return out;
512 : : }
513 : :
514 : : /**
515 : : Write the header of an atom:Tuple.
516 : :
517 : : The passed frame will be initialised to represent this tuple. To complete
518 : : the tuple, write a sequence of atoms, then pop the frame with
519 : : lv2_atom_forge_pop().
520 : :
521 : : For example:
522 : : @code
523 : : // Write tuple (1, 2.0)
524 : : LV2_Atom_Forge_Frame frame;
525 : : LV2_Atom* tup = (LV2_Atom*)lv2_atom_forge_tuple(forge, &frame);
526 : : lv2_atom_forge_int32(forge, 1);
527 : : lv2_atom_forge_float(forge, 2.0);
528 : : lv2_atom_forge_pop(forge, &frame);
529 : : @endcode
530 : : */
531 : : static inline LV2_Atom_Forge_Ref
532 : 32 : lv2_atom_forge_tuple(LV2_Atom_Forge* forge, LV2_Atom_Forge_Frame* frame)
533 : : {
534 : 32 : const LV2_Atom_Tuple a = { { 0, forge->Tuple } };
535 : 32 : return lv2_atom_forge_push(
536 : : forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
537 : : }
538 : :
539 : : /**
540 : : Write the header of an atom:Object.
541 : :
542 : : The passed frame will be initialised to represent this object. To complete
543 : : the object, write a sequence of properties, then pop the frame with
544 : : lv2_atom_forge_pop().
545 : :
546 : : For example:
547 : : @code
548 : : LV2_URID eg_Cat = map("http://example.org/Cat");
549 : : LV2_URID eg_name = map("http://example.org/name");
550 : :
551 : : // Start object with type eg_Cat and blank ID
552 : : LV2_Atom_Forge_Frame frame;
553 : : lv2_atom_forge_object(forge, &frame, 0, eg_Cat);
554 : :
555 : : // Append property eg:name = "Hobbes"
556 : : lv2_atom_forge_key(forge, eg_name);
557 : : lv2_atom_forge_string(forge, "Hobbes", strlen("Hobbes"));
558 : :
559 : : // Finish object
560 : : lv2_atom_forge_pop(forge, &frame);
561 : : @endcode
562 : : */
563 : : static inline LV2_Atom_Forge_Ref
564 : 1 : lv2_atom_forge_object(LV2_Atom_Forge* forge,
565 : : LV2_Atom_Forge_Frame* frame,
566 : : LV2_URID id,
567 : : LV2_URID otype)
568 : : {
569 : 2 : const LV2_Atom_Object a = {
570 : 1 : { (uint32_t)sizeof(LV2_Atom_Object_Body), forge->Object },
571 : : { id, otype }
572 : : };
573 : 1 : return lv2_atom_forge_push(
574 : : forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
575 : : }
576 : :
577 : : /**
578 : : The same as lv2_atom_forge_object(), but for object:Resource.
579 : :
580 : : This function is deprecated and should not be used in new code.
581 : : Use lv2_atom_forge_object() directly instead.
582 : : */
583 : : LV2_DEPRECATED
584 : : static inline LV2_Atom_Forge_Ref
585 : : lv2_atom_forge_resource(LV2_Atom_Forge* forge,
586 : : LV2_Atom_Forge_Frame* frame,
587 : : LV2_URID id,
588 : : LV2_URID otype)
589 : : {
590 : : const LV2_Atom_Object a = {
591 : : { (uint32_t)sizeof(LV2_Atom_Object_Body), forge->Resource },
592 : : { id, otype }
593 : : };
594 : : return lv2_atom_forge_push(
595 : : forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
596 : : }
597 : :
598 : : /**
599 : : The same as lv2_atom_forge_object(), but for object:Blank.
600 : :
601 : : This function is deprecated and should not be used in new code.
602 : : Use lv2_atom_forge_object() directly instead.
603 : : */
604 : : LV2_DEPRECATED
605 : : static inline LV2_Atom_Forge_Ref
606 : : lv2_atom_forge_blank(LV2_Atom_Forge* forge,
607 : : LV2_Atom_Forge_Frame* frame,
608 : : uint32_t id,
609 : : LV2_URID otype)
610 : : {
611 : : const LV2_Atom_Object a = {
612 : : { (uint32_t)sizeof(LV2_Atom_Object_Body), forge->Blank },
613 : : { id, otype }
614 : : };
615 : : return lv2_atom_forge_push(
616 : : forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
617 : : }
618 : :
619 : : /**
620 : : Write a property key in an Object, to be followed by the value.
621 : :
622 : : See lv2_atom_forge_object() documentation for an example.
623 : : */
624 : : static inline LV2_Atom_Forge_Ref
625 : 15 : lv2_atom_forge_key(LV2_Atom_Forge* forge,
626 : : LV2_URID key)
627 : : {
628 : 15 : const LV2_Atom_Property_Body a = { key, 0, { 0, 0 } };
629 : 15 : return lv2_atom_forge_write(forge, &a, 2 * (uint32_t)sizeof(uint32_t));
630 : : }
631 : :
632 : : /**
633 : : Write the header for a property body in an object, with context.
634 : :
635 : : If you do not need the context, which is almost certainly the case,
636 : : use the simpler lv2_atom_forge_key() instead.
637 : : */
638 : : static inline LV2_Atom_Forge_Ref
639 : : lv2_atom_forge_property_head(LV2_Atom_Forge* forge,
640 : : LV2_URID key,
641 : : LV2_URID context)
642 : : {
643 : : const LV2_Atom_Property_Body a = { key, context, { 0, 0 } };
644 : : return lv2_atom_forge_write(forge, &a, 2 * (uint32_t)sizeof(uint32_t));
645 : : }
646 : :
647 : : /**
648 : : Write the header for a Sequence.
649 : : */
650 : : static inline LV2_Atom_Forge_Ref
651 : 64 : lv2_atom_forge_sequence_head(LV2_Atom_Forge* forge,
652 : : LV2_Atom_Forge_Frame* frame,
653 : : uint32_t unit)
654 : : {
655 : 128 : const LV2_Atom_Sequence a = {
656 : 64 : { (uint32_t)sizeof(LV2_Atom_Sequence_Body), forge->Sequence },
657 : : { unit, 0 }
658 : : };
659 : 64 : return lv2_atom_forge_push(
660 : : forge, frame, lv2_atom_forge_write(forge, &a, sizeof(a)));
661 : : }
662 : :
663 : : /**
664 : : Write the time stamp header of an Event (in a Sequence) in audio frames.
665 : : After this, call the appropriate forge method(s) to write the body. Note
666 : : the returned reference is to an LV2_Event which is NOT an Atom.
667 : : */
668 : : static inline LV2_Atom_Forge_Ref
669 : 65 : lv2_atom_forge_frame_time(LV2_Atom_Forge* forge, int64_t frames)
670 : : {
671 : 65 : return lv2_atom_forge_write(forge, &frames, sizeof(frames));
672 : : }
673 : :
674 : : /**
675 : : Write the time stamp header of an Event (in a Sequence) in beats. After
676 : : this, call the appropriate forge method(s) to write the body. Note the
677 : : returned reference is to an LV2_Event which is NOT an Atom.
678 : : */
679 : : static inline LV2_Atom_Forge_Ref
680 : : lv2_atom_forge_beat_time(LV2_Atom_Forge* forge, double beats)
681 : : {
682 : : return lv2_atom_forge_write(forge, &beats, sizeof(beats));
683 : : }
684 : :
685 : : /**
686 : : @}
687 : : @}
688 : : */
689 : :
690 : : LV2_RESTORE_WARNINGS
691 : :
692 : : #ifdef __cplusplus
693 : : } /* extern "C" */
694 : : #endif
695 : :
696 : : #endif /* LV2_ATOM_FORGE_H */
|