1 /*
2 Copyright 2012-2015 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 #include "lv2/atom/atom.h"
18 #include "lv2/atom/forge.h"
19 #include "lv2/atom/util.h"
20 #include "lv2/urid/urid.h"
21
22 #include <stdarg.h>
23 #include <stdbool.h>
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 char** uris = NULL;
30 uint32_t n_uris = 0;
31
32 static char*
copy_string(const char * str)33 copy_string(const char* str)
34 {
35 const size_t len = strlen(str);
36 char* dup = (char*)malloc(len + 1);
37 memcpy(dup, str, len + 1);
38 return dup;
39 }
40
41 static LV2_URID
urid_map(LV2_URID_Map_Handle handle,const char * uri)42 urid_map(LV2_URID_Map_Handle handle, const char* uri)
43 {
44 for (uint32_t i = 0; i < n_uris; ++i) {
45 if (!strcmp(uris[i], uri)) {
46 return i + 1;
47 }
48 }
49
50 uris = (char**)realloc(uris, ++n_uris * sizeof(char*));
51 uris[n_uris - 1] = copy_string(uri);
52 return n_uris;
53 }
54
55 static int
test_fail(const char * fmt,...)56 test_fail(const char* fmt, ...)
57 {
58 va_list args;
59 va_start(args, fmt);
60 fprintf(stderr, "error: ");
61 vfprintf(stderr, fmt, args);
62 va_end(args);
63 return 1;
64 }
65
66 int
main(void)67 main(void)
68 {
69 LV2_URID_Map map = { NULL, urid_map };
70 LV2_Atom_Forge forge;
71 lv2_atom_forge_init(&forge, &map);
72
73 LV2_URID eg_Object = urid_map(NULL, "http://example.org/Object");
74 LV2_URID eg_one = urid_map(NULL, "http://example.org/one");
75 LV2_URID eg_two = urid_map(NULL, "http://example.org/two");
76 LV2_URID eg_three = urid_map(NULL, "http://example.org/three");
77 LV2_URID eg_four = urid_map(NULL, "http://example.org/four");
78 LV2_URID eg_true = urid_map(NULL, "http://example.org/true");
79 LV2_URID eg_false = urid_map(NULL, "http://example.org/false");
80 LV2_URID eg_path = urid_map(NULL, "http://example.org/path");
81 LV2_URID eg_uri = urid_map(NULL, "http://example.org/uri");
82 LV2_URID eg_urid = urid_map(NULL, "http://example.org/urid");
83 LV2_URID eg_string = urid_map(NULL, "http://example.org/string");
84 LV2_URID eg_literal = urid_map(NULL, "http://example.org/literal");
85 LV2_URID eg_tuple = urid_map(NULL, "http://example.org/tuple");
86 LV2_URID eg_vector = urid_map(NULL, "http://example.org/vector");
87 LV2_URID eg_vector2 = urid_map(NULL, "http://example.org/vector2");
88 LV2_URID eg_seq = urid_map(NULL, "http://example.org/seq");
89
90 #define BUF_SIZE 1024
91 #define NUM_PROPS 15
92
93 uint8_t buf[BUF_SIZE];
94 lv2_atom_forge_set_buffer(&forge, buf, BUF_SIZE);
95
96 LV2_Atom_Forge_Frame obj_frame;
97 LV2_Atom* obj = lv2_atom_forge_deref(
98 &forge, lv2_atom_forge_object(&forge, &obj_frame, 0, eg_Object));
99
100 // eg_one = (Int)1
101 lv2_atom_forge_key(&forge, eg_one);
102 LV2_Atom_Int* one = (LV2_Atom_Int*)lv2_atom_forge_deref(
103 &forge, lv2_atom_forge_int(&forge, 1));
104 if (one->body != 1) {
105 return test_fail("%d != 1\n", one->body);
106 }
107
108 // eg_two = (Long)2
109 lv2_atom_forge_key(&forge, eg_two);
110 LV2_Atom_Long* two = (LV2_Atom_Long*)lv2_atom_forge_deref(
111 &forge, lv2_atom_forge_long(&forge, 2));
112 if (two->body != 2) {
113 return test_fail("%ld != 2\n", two->body);
114 }
115
116 // eg_three = (Float)3.0
117 lv2_atom_forge_key(&forge, eg_three);
118 LV2_Atom_Float* three = (LV2_Atom_Float*)lv2_atom_forge_deref(
119 &forge, lv2_atom_forge_float(&forge, 3.0f));
120 if (three->body != 3) {
121 return test_fail("%f != 3\n", three->body);
122 }
123
124 // eg_four = (Double)4.0
125 lv2_atom_forge_key(&forge, eg_four);
126 LV2_Atom_Double* four = (LV2_Atom_Double*)lv2_atom_forge_deref(
127 &forge, lv2_atom_forge_double(&forge, 4.0));
128 if (four->body != 4) {
129 return test_fail("%ld != 4\n", four->body);
130 }
131
132 // eg_true = (Bool)1
133 lv2_atom_forge_key(&forge, eg_true);
134 LV2_Atom_Bool* t = (LV2_Atom_Bool*)lv2_atom_forge_deref(
135 &forge, lv2_atom_forge_bool(&forge, true));
136 if (t->body != 1) {
137 return test_fail("%ld != 1 (true)\n", t->body);
138 }
139
140 // eg_false = (Bool)0
141 lv2_atom_forge_key(&forge, eg_false);
142 LV2_Atom_Bool* f = (LV2_Atom_Bool*)lv2_atom_forge_deref(
143 &forge, lv2_atom_forge_bool(&forge, false));
144 if (f->body != 0) {
145 return test_fail("%ld != 0 (false)\n", f->body);
146 }
147
148 // eg_path = (Path)"/foo/bar"
149 const char* pstr = "/foo/bar";
150 const uint32_t pstr_len = (uint32_t)strlen(pstr);
151 lv2_atom_forge_key(&forge, eg_path);
152 LV2_Atom_String* path = (LV2_Atom_String*)lv2_atom_forge_deref(
153 &forge, lv2_atom_forge_uri(&forge, pstr, pstr_len));
154 char* pbody = (char*)LV2_ATOM_BODY(path);
155 if (strcmp(pbody, pstr)) {
156 return test_fail("%s != \"%s\"\n", pbody, pstr);
157 }
158
159 // eg_uri = (URI)"http://example.org/value"
160 const char* ustr = "http://example.org/value";
161 const uint32_t ustr_len = (uint32_t)strlen(ustr);
162 lv2_atom_forge_key(&forge, eg_uri);
163 LV2_Atom_String* uri = (LV2_Atom_String*)lv2_atom_forge_deref(
164 &forge, lv2_atom_forge_uri(&forge, ustr, ustr_len));
165 char* ubody = (char*)LV2_ATOM_BODY(uri);
166 if (strcmp(ubody, ustr)) {
167 return test_fail("%s != \"%s\"\n", ubody, ustr);
168 }
169
170 // eg_urid = (URID)"http://example.org/value"
171 LV2_URID eg_value = urid_map(NULL, "http://example.org/value");
172 lv2_atom_forge_key(&forge, eg_urid);
173 LV2_Atom_URID* urid = (LV2_Atom_URID*)lv2_atom_forge_deref(
174 &forge, lv2_atom_forge_urid(&forge, eg_value));
175 if (urid->body != eg_value) {
176 return test_fail("%u != %u\n", urid->body, eg_value);
177 }
178
179 // eg_string = (String)"hello"
180 lv2_atom_forge_key(&forge, eg_string);
181 LV2_Atom_String* string = (LV2_Atom_String*)lv2_atom_forge_deref(
182 &forge, lv2_atom_forge_string(
183 &forge, "hello", strlen("hello")));
184 char* sbody = (char*)LV2_ATOM_BODY(string);
185 if (strcmp(sbody, "hello")) {
186 return test_fail("%s != \"hello\"\n", sbody);
187 }
188
189 // eg_literal = (Literal)"hello"@fr
190 lv2_atom_forge_key(&forge, eg_literal);
191 LV2_Atom_Literal* literal = (LV2_Atom_Literal*)lv2_atom_forge_deref(
192 &forge, lv2_atom_forge_literal(
193 &forge, "bonjour", strlen("bonjour"),
194 0, urid_map(NULL, "http://lexvo.org/id/term/fr")));
195 char* lbody = (char*)LV2_ATOM_CONTENTS(LV2_Atom_Literal, literal);
196 if (strcmp(lbody, "bonjour")) {
197 return test_fail("%s != \"bonjour\"\n", lbody);
198 }
199
200 // eg_tuple = "foo",true
201 lv2_atom_forge_key(&forge, eg_tuple);
202 LV2_Atom_Forge_Frame tuple_frame;
203 LV2_Atom_Tuple* tuple = (LV2_Atom_Tuple*)lv2_atom_forge_deref(
204 &forge, lv2_atom_forge_tuple(&forge, &tuple_frame));
205 LV2_Atom_String* tup0 = (LV2_Atom_String*)lv2_atom_forge_deref(
206 &forge, lv2_atom_forge_string(
207 &forge, "foo", strlen("foo")));
208 LV2_Atom_Bool* tup1 = (LV2_Atom_Bool*)lv2_atom_forge_deref(
209 &forge, lv2_atom_forge_bool(&forge, true));
210 lv2_atom_forge_pop(&forge, &tuple_frame);
211 LV2_Atom* i = lv2_atom_tuple_begin(tuple);
212 if (lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) {
213 return test_fail("Tuple iterator is empty\n");
214 }
215 LV2_Atom* tup0i = i;
216 if (!lv2_atom_equals((LV2_Atom*)tup0, tup0i)) {
217 return test_fail("Corrupt tuple element 0\n");
218 }
219 i = lv2_atom_tuple_next(i);
220 if (lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) {
221 return test_fail("Premature end of tuple iterator\n");
222 }
223 LV2_Atom* tup1i = i;
224 if (!lv2_atom_equals((LV2_Atom*)tup1, tup1i)) {
225 return test_fail("Corrupt tuple element 1\n");
226 }
227 i = lv2_atom_tuple_next(i);
228 if (!lv2_atom_tuple_is_end(LV2_ATOM_BODY(tuple), tuple->atom.size, i)) {
229 return test_fail("Tuple iter is not at end\n");
230 }
231
232 // eg_vector = (Vector<Int>)1,2,3,4
233 lv2_atom_forge_key(&forge, eg_vector);
234 int32_t elems[] = { 1, 2, 3, 4 };
235 LV2_Atom_Vector* vector = (LV2_Atom_Vector*)lv2_atom_forge_deref(
236 &forge, lv2_atom_forge_vector(
237 &forge, sizeof(int32_t), forge.Int, 4, elems));
238 void* vec_body = LV2_ATOM_CONTENTS(LV2_Atom_Vector, vector);
239 if (memcmp(elems, vec_body, sizeof(elems))) {
240 return test_fail("Corrupt vector\n");
241 }
242
243 // eg_vector2 = (Vector<Int>)1,2,3,4
244 lv2_atom_forge_key(&forge, eg_vector2);
245 LV2_Atom_Forge_Frame vec_frame;
246 LV2_Atom_Vector* vector2 = (LV2_Atom_Vector*)lv2_atom_forge_deref(
247 &forge, lv2_atom_forge_vector_head(
248 &forge, &vec_frame, sizeof(int32_t), forge.Int));
249 for (unsigned e = 0; e < sizeof(elems) / sizeof(int32_t); ++e) {
250 lv2_atom_forge_int(&forge, elems[e]);
251 }
252 lv2_atom_forge_pop(&forge, &vec_frame);
253 if (!lv2_atom_equals(&vector->atom, &vector2->atom)) {
254 return test_fail("Vector != Vector2\n");
255 }
256
257 // eg_seq = (Sequence)1, 2
258 lv2_atom_forge_key(&forge, eg_seq);
259 LV2_Atom_Forge_Frame seq_frame;
260 LV2_Atom_Sequence* seq = (LV2_Atom_Sequence*)lv2_atom_forge_deref(
261 &forge, lv2_atom_forge_sequence_head(&forge, &seq_frame, 0));
262 lv2_atom_forge_frame_time(&forge, 0);
263 lv2_atom_forge_int(&forge, 1);
264 lv2_atom_forge_frame_time(&forge, 1);
265 lv2_atom_forge_int(&forge, 2);
266 lv2_atom_forge_pop(&forge, &seq_frame);
267
268 lv2_atom_forge_pop(&forge, &obj_frame);
269
270 // Test equality
271 LV2_Atom_Int itwo = { { forge.Int, sizeof(int32_t) }, 2 };
272 if (lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)two)) {
273 return test_fail("1 == 2.0\n");
274 } else if (lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)&itwo)) {
275 return test_fail("1 == 2\n");
276 } else if (!lv2_atom_equals((LV2_Atom*)one, (LV2_Atom*)one)) {
277 return test_fail("1 != 1\n");
278 }
279
280 unsigned n_events = 0;
281 LV2_ATOM_SEQUENCE_FOREACH(seq, ev) {
282 if (ev->time.frames != n_events) {
283 return test_fail("Corrupt event %u has bad time\n", n_events);
284 } else if (ev->body.type != forge.Int) {
285 return test_fail("Corrupt event %u has bad type\n", n_events);
286 } else if (((LV2_Atom_Int*)&ev->body)->body != (int)n_events + 1) {
287 return test_fail("Event %u != %d\n", n_events, n_events + 1);
288 }
289 ++n_events;
290 }
291
292 int n_props = 0;
293 LV2_ATOM_OBJECT_FOREACH((LV2_Atom_Object*)obj, prop) {
294 if (!prop->key) {
295 return test_fail("Corrupt property %u has no key\n", n_props);
296 } else if (prop->context) {
297 return test_fail("Corrupt property %u has context\n", n_props);
298 }
299 ++n_props;
300 }
301
302 if (n_props != NUM_PROPS) {
303 return test_fail("Corrupt object has %u properties != %u\n",
304 n_props, NUM_PROPS);
305 }
306
307 struct {
308 const LV2_Atom* one;
309 const LV2_Atom* two;
310 const LV2_Atom* three;
311 const LV2_Atom* four;
312 const LV2_Atom* affirmative;
313 const LV2_Atom* negative;
314 const LV2_Atom* path;
315 const LV2_Atom* uri;
316 const LV2_Atom* urid;
317 const LV2_Atom* string;
318 const LV2_Atom* literal;
319 const LV2_Atom* tuple;
320 const LV2_Atom* vector;
321 const LV2_Atom* vector2;
322 const LV2_Atom* seq;
323 } matches;
324
325 memset(&matches, 0, sizeof(matches));
326
327 LV2_Atom_Object_Query q[] = {
328 { eg_one, &matches.one },
329 { eg_two, &matches.two },
330 { eg_three, &matches.three },
331 { eg_four, &matches.four },
332 { eg_true, &matches.affirmative },
333 { eg_false, &matches.negative },
334 { eg_path, &matches.path },
335 { eg_uri, &matches.uri },
336 { eg_urid, &matches.urid },
337 { eg_string, &matches.string },
338 { eg_literal, &matches.literal },
339 { eg_tuple, &matches.tuple },
340 { eg_vector, &matches.vector },
341 { eg_vector2, &matches.vector2 },
342 { eg_seq, &matches.seq },
343 LV2_ATOM_OBJECT_QUERY_END
344 };
345
346 int n_matches = lv2_atom_object_query((LV2_Atom_Object*)obj, q);
347 for (int n = 0; n < 2; ++n) {
348 if (n_matches != n_props) {
349 return test_fail("Query failed, %u matches != %u\n",
350 n_matches, n_props);
351 } else if (!lv2_atom_equals((LV2_Atom*)one, matches.one)) {
352 return test_fail("Bad match one\n");
353 } else if (!lv2_atom_equals((LV2_Atom*)two, matches.two)) {
354 return test_fail("Bad match two\n");
355 } else if (!lv2_atom_equals((LV2_Atom*)three, matches.three)) {
356 return test_fail("Bad match three\n");
357 } else if (!lv2_atom_equals((LV2_Atom*)four, matches.four)) {
358 return test_fail("Bad match four\n");
359 } else if (!lv2_atom_equals((LV2_Atom*)t, matches.affirmative)) {
360 return test_fail("Bad match true\n");
361 } else if (!lv2_atom_equals((LV2_Atom*)f, matches.negative)) {
362 return test_fail("Bad match false\n");
363 } else if (!lv2_atom_equals((LV2_Atom*)path, matches.path)) {
364 return test_fail("Bad match path\n");
365 } else if (!lv2_atom_equals((LV2_Atom*)uri, matches.uri)) {
366 return test_fail("Bad match URI\n");
367 } else if (!lv2_atom_equals((LV2_Atom*)string, matches.string)) {
368 return test_fail("Bad match string\n");
369 } else if (!lv2_atom_equals((LV2_Atom*)literal, matches.literal)) {
370 return test_fail("Bad match literal\n");
371 } else if (!lv2_atom_equals((LV2_Atom*)tuple, matches.tuple)) {
372 return test_fail("Bad match tuple\n");
373 } else if (!lv2_atom_equals((LV2_Atom*)vector, matches.vector)) {
374 return test_fail("Bad match vector\n");
375 } else if (!lv2_atom_equals((LV2_Atom*)vector, matches.vector2)) {
376 return test_fail("Bad match vector2\n");
377 } else if (!lv2_atom_equals((LV2_Atom*)seq, matches.seq)) {
378 return test_fail("Bad match sequence\n");
379 }
380 memset(&matches, 0, sizeof(matches));
381 n_matches = lv2_atom_object_get((LV2_Atom_Object*)obj,
382 eg_one, &matches.one,
383 eg_two, &matches.two,
384 eg_three, &matches.three,
385 eg_four, &matches.four,
386 eg_true, &matches.affirmative,
387 eg_false, &matches.negative,
388 eg_path, &matches.path,
389 eg_uri, &matches.uri,
390 eg_urid, &matches.urid,
391 eg_string, &matches.string,
392 eg_literal, &matches.literal,
393 eg_tuple, &matches.tuple,
394 eg_vector, &matches.vector,
395 eg_vector2, &matches.vector2,
396 eg_seq, &matches.seq,
397 0);
398 }
399
400 return 0;
401 }
402