lv2_atom.h
Walking an LV2 atom sequence a host filled in.
#include <sonore/lv2_atom.h>- 4other declarations
- Guides: Getting started, Platforms and formats
On this page
Design notes
The plugin reads one and so does the interface, and they are separate modules that must agree exactly about the layout -- so the walk lives here, where both include it, rather than being written out on each side. It depends on nothing but LV2's own atom header, which is also what lets a test drive it with hostile bytes without building a plugin around it.
The padding is the part worth centralising. An atom event is followed by its body rounded UP to eight bytes, and a reader that forgets the rounding walks into the middle of the next event and reads a size out of somebody's payload. That arithmetic appeared six times before this.
Functions 4
- fn
inline uint32_t atomPad(uint32_t size)An atom body's size, padded to the alignment the spec requires. For sizes the caller chose; a size read from a host goes through atomStep().lv2::atomPad · lv2_atom.h:25 - fn
inline uint64_t atomStep(const LV2_Atom_Event* ev)How far the next event is from this one. In 64 bits, because the size is the host's: padded in 32, anything from 0xFFFFFFF9 up wraps to a step of sixteen, which passes every bounds check and hands a reader a body four gigabytes long.lv2::atomStep · lv2_atom.h:31 - fn
template <typename Fn> inline void forEachAtomEvent(const LV2_Atom_Sequence* seq, Fn&& fn)Callfn(const LV2_Atom_Event*)for every event in a sequence whose body lies wholly inside it.lv2::forEachAtomEvent · lv2_atom.h:46More
Tolerant of rubbish on purpose: a sequence is memory a HOST filled in, and a plugin that trusts it crashes in somebody's session rather than in a test. A size that runs past the buffer is where the walk stops rather than where it reads.
seq->atom.sizeitself is the host's statement of how big the buffer is, and the one number this has to take on trust. - fn
template <typename Fn> inline void forEachAtomProperty(const LV2_Atom* obj, Fn&& fn)Callfn(const LV2_Atom_Property_Body*)for every property of an atom OBJECT whose value lies wholly inside it -- a time:Position, say.lv2::forEachAtomProperty · lv2_atom.h:75More
objis the object's atom header, as an event's body is: its size counts the object body (id, otype) and the properties after it. A property's unpadded value must fit for it to be handed over; the padding after the last one is the forge's habit, not a promise, so the step that includes it only has to keep the walk inside the object. Tolerant of rubbish for the same reason as the sequence walk.