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