LCOV - code coverage report
Current view: top level - atom - forge.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 148 149 99.3 %
Date: 2020-09-30 14:18:52 Functions: 28 28 100.0 %
Branches: 34 38 89.5 %

           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 */

Generated by: LCOV version 1.13