1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to you under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  * https://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14  * implied.  See the License for the specific language governing
15  * permissions and limitations under the License.
16  */
17 
18 #include "avro/allocation.h"
19 #include "avro/basics.h"
20 #include "avro/errors.h"
21 #include "avro/legacy.h"
22 #include "avro/refcount.h"
23 #include "avro/schema.h"
24 #include "avro_private.h"
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include "datum.h"
29 #include "schema.h"
30 #include "encoding.h"
31 
32 #define DEFAULT_TABLE_SIZE 32
33 
avro_datum_init(avro_datum_t datum,avro_type_t type)34 static void avro_datum_init(avro_datum_t datum, avro_type_t type)
35 {
36 	datum->type = type;
37 	datum->class_type = AVRO_DATUM;
38 	avro_refcount_set(&datum->refcount, 1);
39 }
40 
41 static void
avro_str_free_wrapper(void * ptr,size_t sz)42 avro_str_free_wrapper(void *ptr, size_t sz)
43 {
44 	// don't need sz, since the size is stored in the string buffer
45 	AVRO_UNUSED(sz);
46 	avro_str_free((char *)ptr);
47 }
48 
avro_string_private(char * str,int64_t size,avro_free_func_t string_free)49 static avro_datum_t avro_string_private(char *str, int64_t size,
50 					avro_free_func_t string_free)
51 {
52 	struct avro_string_datum_t *datum =
53 	    (struct avro_string_datum_t *) avro_new(struct avro_string_datum_t);
54 	if (!datum) {
55 		avro_set_error("Cannot create new string datum");
56 		return NULL;
57 	}
58 	datum->s = str;
59 	datum->size = size;
60 	datum->free = string_free;
61 
62 	avro_datum_init(&datum->obj, AVRO_STRING);
63 	return &datum->obj;
64 }
65 
avro_string(const char * str)66 avro_datum_t avro_string(const char *str)
67 {
68 	char *p = avro_strdup(str);
69 	if (!p) {
70 		avro_set_error("Cannot copy string content");
71 		return NULL;
72 	}
73 	avro_datum_t s_datum = avro_string_private(p, 0, avro_str_free_wrapper);
74 	if (!s_datum) {
75 		avro_str_free(p);
76 	}
77 
78 	return s_datum;
79 }
80 
avro_givestring(const char * str,avro_free_func_t free)81 avro_datum_t avro_givestring(const char *str,
82 			     avro_free_func_t free)
83 {
84 	int64_t  sz = strlen(str)+1;
85 	return avro_string_private((char *)str, sz, free);
86 }
87 
avro_string_get(avro_datum_t datum,char ** p)88 int avro_string_get(avro_datum_t datum, char **p)
89 {
90 	check_param(EINVAL, is_avro_datum(datum), "datum");
91 	check_param(EINVAL, is_avro_string(datum), "string datum");
92 	check_param(EINVAL, p, "string buffer");
93 
94 	*p = avro_datum_to_string(datum)->s;
95 	return 0;
96 }
97 
avro_string_set_private(avro_datum_t datum,const char * p,int64_t size,avro_free_func_t string_free)98 static int avro_string_set_private(avro_datum_t datum,
99 	       			   const char *p, int64_t size,
100 				   avro_free_func_t string_free)
101 {
102 	check_param(EINVAL, is_avro_datum(datum), "datum");
103 	check_param(EINVAL, is_avro_string(datum), "string datum");
104 	check_param(EINVAL, p, "string content");
105 
106 	struct avro_string_datum_t *string = avro_datum_to_string(datum);
107 	if (string->free) {
108 		string->free(string->s, string->size);
109 	}
110 	string->free = string_free;
111 	string->s = (char *)p;
112 	string->size = size;
113 	return 0;
114 }
115 
avro_string_set(avro_datum_t datum,const char * p)116 int avro_string_set(avro_datum_t datum, const char *p)
117 {
118 	char *string_copy = avro_strdup(p);
119 	int rval;
120 	if (!string_copy) {
121 		avro_set_error("Cannot copy string content");
122 		return ENOMEM;
123 	}
124 	rval = avro_string_set_private(datum, string_copy, 0,
125 				       avro_str_free_wrapper);
126 	if (rval) {
127 		avro_str_free(string_copy);
128 	}
129 	return rval;
130 }
131 
avro_givestring_set(avro_datum_t datum,const char * p,avro_free_func_t free)132 int avro_givestring_set(avro_datum_t datum, const char *p,
133 			avro_free_func_t free)
134 {
135 	int64_t  size = strlen(p)+1;
136 	return avro_string_set_private(datum, p, size, free);
137 }
138 
avro_bytes_private(char * bytes,int64_t size,avro_free_func_t bytes_free)139 static avro_datum_t avro_bytes_private(char *bytes, int64_t size,
140 				       avro_free_func_t bytes_free)
141 {
142 	struct avro_bytes_datum_t *datum;
143 	datum = (struct avro_bytes_datum_t *) avro_new(struct avro_bytes_datum_t);
144 	if (!datum) {
145 		avro_set_error("Cannot create new bytes datum");
146 		return NULL;
147 	}
148 	datum->bytes = bytes;
149 	datum->size = size;
150 	datum->free = bytes_free;
151 
152 	avro_datum_init(&datum->obj, AVRO_BYTES);
153 	return &datum->obj;
154 }
155 
avro_bytes(const char * bytes,int64_t size)156 avro_datum_t avro_bytes(const char *bytes, int64_t size)
157 {
158 	char *bytes_copy = (char *) avro_malloc(size);
159 	if (!bytes_copy) {
160 		avro_set_error("Cannot copy bytes content");
161 		return NULL;
162 	}
163 	memcpy(bytes_copy, bytes, size);
164 	avro_datum_t  result =
165 		avro_bytes_private(bytes_copy, size, avro_alloc_free_func);
166 	if (result == NULL) {
167 		avro_free(bytes_copy, size);
168 	}
169 	return result;
170 }
171 
avro_givebytes(const char * bytes,int64_t size,avro_free_func_t free)172 avro_datum_t avro_givebytes(const char *bytes, int64_t size,
173 			    avro_free_func_t free)
174 {
175 	return avro_bytes_private((char *)bytes, size, free);
176 }
177 
avro_bytes_set_private(avro_datum_t datum,const char * bytes,const int64_t size,avro_free_func_t bytes_free)178 static int avro_bytes_set_private(avro_datum_t datum, const char *bytes,
179 				  const int64_t size,
180 				  avro_free_func_t bytes_free)
181 {
182 	check_param(EINVAL, is_avro_datum(datum), "datum");
183 	check_param(EINVAL, is_avro_bytes(datum), "bytes datum");
184 
185 	struct avro_bytes_datum_t *b = avro_datum_to_bytes(datum);
186 	if (b->free) {
187 		b->free(b->bytes, b->size);
188 	}
189 
190 	b->free = bytes_free;
191 	b->bytes = (char *)bytes;
192 	b->size = size;
193 	return 0;
194 }
195 
avro_bytes_set(avro_datum_t datum,const char * bytes,const int64_t size)196 int avro_bytes_set(avro_datum_t datum, const char *bytes, const int64_t size)
197 {
198 	int rval;
199 	char *bytes_copy = (char *) avro_malloc(size);
200 	if (!bytes_copy) {
201 		avro_set_error("Cannot copy bytes content");
202 		return ENOMEM;
203 	}
204 	memcpy(bytes_copy, bytes, size);
205 	rval = avro_bytes_set_private(datum, bytes_copy, size, avro_alloc_free_func);
206 	if (rval) {
207 		avro_free(bytes_copy, size);
208 	}
209 	return rval;
210 }
211 
avro_givebytes_set(avro_datum_t datum,const char * bytes,const int64_t size,avro_free_func_t free)212 int avro_givebytes_set(avro_datum_t datum, const char *bytes,
213 		       const int64_t size, avro_free_func_t free)
214 {
215 	return avro_bytes_set_private(datum, bytes, size, free);
216 }
217 
avro_bytes_get(avro_datum_t datum,char ** bytes,int64_t * size)218 int avro_bytes_get(avro_datum_t datum, char **bytes, int64_t * size)
219 {
220 	check_param(EINVAL, is_avro_datum(datum), "datum");
221 	check_param(EINVAL, is_avro_bytes(datum), "bytes datum");
222 	check_param(EINVAL, bytes, "bytes");
223 	check_param(EINVAL, size, "size");
224 
225 	*bytes = avro_datum_to_bytes(datum)->bytes;
226 	*size = avro_datum_to_bytes(datum)->size;
227 	return 0;
228 }
229 
avro_int32(int32_t i)230 avro_datum_t avro_int32(int32_t i)
231 {
232 	struct avro_int32_datum_t *datum =
233 	    (struct avro_int32_datum_t *) avro_new(struct avro_int32_datum_t);
234 	if (!datum) {
235 		avro_set_error("Cannot create new int datum");
236 		return NULL;
237 	}
238 	datum->i32 = i;
239 
240 	avro_datum_init(&datum->obj, AVRO_INT32);
241 	return &datum->obj;
242 }
243 
avro_int32_get(avro_datum_t datum,int32_t * i)244 int avro_int32_get(avro_datum_t datum, int32_t * i)
245 {
246 	check_param(EINVAL, is_avro_datum(datum), "datum");
247 	check_param(EINVAL, is_avro_int32(datum), "int datum");
248 	check_param(EINVAL, i, "value pointer");
249 
250 	*i = avro_datum_to_int32(datum)->i32;
251 	return 0;
252 }
253 
avro_int32_set(avro_datum_t datum,const int32_t i)254 int avro_int32_set(avro_datum_t datum, const int32_t i)
255 {
256 	check_param(EINVAL, is_avro_datum(datum), "datum");
257 	check_param(EINVAL, is_avro_int32(datum), "int datum");
258 
259 	avro_datum_to_int32(datum)->i32 = i;
260 	return 0;
261 }
262 
avro_int64(int64_t l)263 avro_datum_t avro_int64(int64_t l)
264 {
265 	struct avro_int64_datum_t *datum =
266 	    (struct avro_int64_datum_t *) avro_new(struct avro_int64_datum_t);
267 	if (!datum) {
268 		avro_set_error("Cannot create new long datum");
269 		return NULL;
270 	}
271 	datum->i64 = l;
272 
273 	avro_datum_init(&datum->obj, AVRO_INT64);
274 	return &datum->obj;
275 }
276 
avro_int64_get(avro_datum_t datum,int64_t * l)277 int avro_int64_get(avro_datum_t datum, int64_t * l)
278 {
279 	check_param(EINVAL, is_avro_datum(datum), "datum");
280 	check_param(EINVAL, is_avro_int64(datum), "long datum");
281 	check_param(EINVAL, l, "value pointer");
282 
283 	*l = avro_datum_to_int64(datum)->i64;
284 	return 0;
285 }
286 
avro_int64_set(avro_datum_t datum,const int64_t l)287 int avro_int64_set(avro_datum_t datum, const int64_t l)
288 {
289 	check_param(EINVAL, is_avro_datum(datum), "datum");
290 	check_param(EINVAL, is_avro_int64(datum), "long datum");
291 
292 	avro_datum_to_int64(datum)->i64 = l;
293 	return 0;
294 }
295 
avro_float(float f)296 avro_datum_t avro_float(float f)
297 {
298 	struct avro_float_datum_t *datum =
299 	    (struct avro_float_datum_t *) avro_new(struct avro_float_datum_t);
300 	if (!datum) {
301 		avro_set_error("Cannot create new float datum");
302 		return NULL;
303 	}
304 	datum->f = f;
305 
306 	avro_datum_init(&datum->obj, AVRO_FLOAT);
307 	return &datum->obj;
308 }
309 
avro_float_set(avro_datum_t datum,const float f)310 int avro_float_set(avro_datum_t datum, const float f)
311 {
312 	check_param(EINVAL, is_avro_datum(datum), "datum");
313 	check_param(EINVAL, is_avro_float(datum), "float datum");
314 
315 	avro_datum_to_float(datum)->f = f;
316 	return 0;
317 }
318 
avro_float_get(avro_datum_t datum,float * f)319 int avro_float_get(avro_datum_t datum, float *f)
320 {
321 	check_param(EINVAL, is_avro_datum(datum), "datum");
322 	check_param(EINVAL, is_avro_float(datum), "float datum");
323 	check_param(EINVAL, f, "value pointer");
324 
325 	*f = avro_datum_to_float(datum)->f;
326 	return 0;
327 }
328 
avro_double(double d)329 avro_datum_t avro_double(double d)
330 {
331 	struct avro_double_datum_t *datum =
332 	    (struct avro_double_datum_t *) avro_new(struct avro_double_datum_t);
333 	if (!datum) {
334 		avro_set_error("Cannot create new double atom");
335 		return NULL;
336 	}
337 	datum->d = d;
338 
339 	avro_datum_init(&datum->obj, AVRO_DOUBLE);
340 	return &datum->obj;
341 }
342 
avro_double_set(avro_datum_t datum,const double d)343 int avro_double_set(avro_datum_t datum, const double d)
344 {
345 	check_param(EINVAL, is_avro_datum(datum), "datum");
346 	check_param(EINVAL, is_avro_double(datum), "double datum");
347 
348 	avro_datum_to_double(datum)->d = d;
349 	return 0;
350 }
351 
avro_double_get(avro_datum_t datum,double * d)352 int avro_double_get(avro_datum_t datum, double *d)
353 {
354 	check_param(EINVAL, is_avro_datum(datum), "datum");
355 	check_param(EINVAL, is_avro_double(datum), "double datum");
356 	check_param(EINVAL, d, "value pointer");
357 
358 	*d = avro_datum_to_double(datum)->d;
359 	return 0;
360 }
361 
avro_boolean(int8_t i)362 avro_datum_t avro_boolean(int8_t i)
363 {
364 	struct avro_boolean_datum_t *datum =
365 	    (struct avro_boolean_datum_t *) avro_new(struct avro_boolean_datum_t);
366 	if (!datum) {
367 		avro_set_error("Cannot create new boolean datum");
368 		return NULL;
369 	}
370 	datum->i = i;
371 	avro_datum_init(&datum->obj, AVRO_BOOLEAN);
372 	return &datum->obj;
373 }
374 
avro_boolean_set(avro_datum_t datum,const int8_t i)375 int avro_boolean_set(avro_datum_t datum, const int8_t i)
376 {
377 	check_param(EINVAL, is_avro_datum(datum), "datum");
378 	check_param(EINVAL, is_avro_boolean(datum), "boolean datum");
379 
380 	avro_datum_to_boolean(datum)->i = i;
381 	return 0;
382 }
383 
avro_boolean_get(avro_datum_t datum,int8_t * i)384 int avro_boolean_get(avro_datum_t datum, int8_t * i)
385 {
386 	check_param(EINVAL, is_avro_datum(datum), "datum");
387 	check_param(EINVAL, is_avro_boolean(datum), "boolean datum");
388 	check_param(EINVAL, i, "value pointer");
389 
390 	*i = avro_datum_to_boolean(datum)->i;
391 	return 0;
392 }
393 
avro_null(void)394 avro_datum_t avro_null(void)
395 {
396 	static struct avro_obj_t obj = {
397 		AVRO_NULL,
398 		AVRO_DATUM,
399 		1
400 	};
401 	return avro_datum_incref(&obj);
402 }
403 
avro_union(avro_schema_t schema,int64_t discriminant,avro_datum_t value)404 avro_datum_t avro_union(avro_schema_t schema,
405 			int64_t discriminant, avro_datum_t value)
406 {
407 	check_param(NULL, is_avro_schema(schema), "schema");
408 
409 	struct avro_union_datum_t *datum =
410 	    (struct avro_union_datum_t *) avro_new(struct avro_union_datum_t);
411 	if (!datum) {
412 		avro_set_error("Cannot create new union datum");
413 		return NULL;
414 	}
415 	datum->schema = avro_schema_incref(schema);
416 	datum->discriminant = discriminant;
417 	datum->value = avro_datum_incref(value);
418 
419 	avro_datum_init(&datum->obj, AVRO_UNION);
420 	return &datum->obj;
421 }
422 
avro_union_discriminant(const avro_datum_t datum)423 int64_t avro_union_discriminant(const avro_datum_t datum)
424 {
425 	return avro_datum_to_union(datum)->discriminant;
426 }
427 
avro_union_current_branch(avro_datum_t datum)428 avro_datum_t avro_union_current_branch(avro_datum_t datum)
429 {
430 	return avro_datum_to_union(datum)->value;
431 }
432 
avro_union_set_discriminant(avro_datum_t datum,int discriminant,avro_datum_t * branch)433 int avro_union_set_discriminant(avro_datum_t datum,
434 				int discriminant,
435 				avro_datum_t *branch)
436 {
437 	check_param(EINVAL, is_avro_datum(datum), "datum");
438 	check_param(EINVAL, is_avro_union(datum), "union datum");
439 
440 	struct avro_union_datum_t  *unionp = avro_datum_to_union(datum);
441 
442 	avro_schema_t  schema = unionp->schema;
443 	avro_schema_t  branch_schema =
444 	    avro_schema_union_branch(schema, discriminant);
445 
446 	if (branch_schema == NULL) {
447 		// That branch doesn't exist!
448 		avro_set_error("Branch %d doesn't exist", discriminant);
449 		return EINVAL;
450 	}
451 
452 	if (unionp->discriminant != discriminant) {
453 		// If we're changing the branch, throw away any old
454 		// branch value.
455 		if (unionp->value != NULL) {
456 			avro_datum_decref(unionp->value);
457 			unionp->value = NULL;
458 		}
459 
460 		unionp->discriminant = discriminant;
461 	}
462 
463 	// Create a new branch value, if there isn't one already.
464 	if (unionp->value == NULL) {
465 		unionp->value = avro_datum_from_schema(branch_schema);
466 	}
467 
468 	if (branch != NULL) {
469 		*branch = unionp->value;
470 	}
471 
472 	return 0;
473 }
474 
avro_record(avro_schema_t schema)475 avro_datum_t avro_record(avro_schema_t schema)
476 {
477 	check_param(NULL, is_avro_schema(schema), "schema");
478 
479 	struct avro_record_datum_t *datum =
480 	    (struct avro_record_datum_t *) avro_new(struct avro_record_datum_t);
481 	if (!datum) {
482 		avro_set_error("Cannot create new record datum");
483 		return NULL;
484 	}
485 	datum->field_order = st_init_numtable_with_size(DEFAULT_TABLE_SIZE);
486 	if (!datum->field_order) {
487 		avro_set_error("Cannot create new record datum");
488 		avro_freet(struct avro_record_datum_t, datum);
489 		return NULL;
490 	}
491 	datum->fields_byname = st_init_strtable_with_size(DEFAULT_TABLE_SIZE);
492 	if (!datum->fields_byname) {
493 		avro_set_error("Cannot create new record datum");
494 		st_free_table(datum->field_order);
495 		avro_freet(struct avro_record_datum_t, datum);
496 		return NULL;
497 	}
498 
499 	datum->schema = avro_schema_incref(schema);
500 	avro_datum_init(&datum->obj, AVRO_RECORD);
501 	return &datum->obj;
502 }
503 
504 int
avro_record_get(const avro_datum_t datum,const char * field_name,avro_datum_t * field)505 avro_record_get(const avro_datum_t datum, const char *field_name,
506 		avro_datum_t * field)
507 {
508 	union {
509 		avro_datum_t field;
510 		st_data_t data;
511 	} val;
512 	if (is_avro_datum(datum) && is_avro_record(datum) && field_name) {
513 		if (st_lookup
514 		    (avro_datum_to_record(datum)->fields_byname,
515 		     (st_data_t) field_name, &(val.data))) {
516 			*field = val.field;
517 			return 0;
518 		}
519 	}
520 	avro_set_error("No field named %s", field_name);
521 	return EINVAL;
522 }
523 
524 int
avro_record_set(avro_datum_t datum,const char * field_name,const avro_datum_t field_value)525 avro_record_set(avro_datum_t datum, const char *field_name,
526 		const avro_datum_t field_value)
527 {
528 	check_param(EINVAL, is_avro_datum(datum), "datum");
529 	check_param(EINVAL, is_avro_record(datum), "record datum");
530 	check_param(EINVAL, field_name, "field_name");
531 
532 	char *key = (char *)field_name;
533 	avro_datum_t old_field;
534 
535 	if (avro_record_get(datum, field_name, &old_field) == 0) {
536 		/* Overriding old value */
537 		avro_datum_decref(old_field);
538 	} else {
539 		/* Inserting new value */
540 		struct avro_record_datum_t *record =
541 		    avro_datum_to_record(datum);
542 		key = avro_strdup(field_name);
543 		if (!key) {
544 			avro_set_error("Cannot copy field name");
545 			return ENOMEM;
546 		}
547 		st_insert(record->field_order,
548 			  record->field_order->num_entries,
549 			  (st_data_t) key);
550 	}
551 	avro_datum_incref(field_value);
552 	st_insert(avro_datum_to_record(datum)->fields_byname,
553 		  (st_data_t) key, (st_data_t) field_value);
554 	return 0;
555 }
556 
avro_enum(avro_schema_t schema,int i)557 avro_datum_t avro_enum(avro_schema_t schema, int i)
558 {
559 	check_param(NULL, is_avro_schema(schema), "schema");
560 
561 	struct avro_enum_datum_t *datum =
562 	    (struct avro_enum_datum_t *) avro_new(struct avro_enum_datum_t);
563 	if (!datum) {
564 		avro_set_error("Cannot create new enum datum");
565 		return NULL;
566 	}
567 	datum->schema = avro_schema_incref(schema);
568 	datum->value = i;
569 
570 	avro_datum_init(&datum->obj, AVRO_ENUM);
571 	return &datum->obj;
572 }
573 
avro_enum_get(const avro_datum_t datum)574 int avro_enum_get(const avro_datum_t datum)
575 {
576 	return avro_datum_to_enum(datum)->value;
577 }
578 
avro_enum_get_name(const avro_datum_t datum)579 const char *avro_enum_get_name(const avro_datum_t datum)
580 {
581 	int  value = avro_enum_get(datum);
582 	avro_schema_t  schema = avro_datum_to_enum(datum)->schema;
583 	return avro_schema_enum_get(schema, value);
584 }
585 
avro_enum_set(avro_datum_t datum,const int symbol_value)586 int avro_enum_set(avro_datum_t datum, const int symbol_value)
587 {
588 	check_param(EINVAL, is_avro_datum(datum), "datum");
589 	check_param(EINVAL, is_avro_enum(datum), "enum datum");
590 
591 	avro_datum_to_enum(datum)->value = symbol_value;
592 	return 0;
593 }
594 
avro_enum_set_name(avro_datum_t datum,const char * symbol_name)595 int avro_enum_set_name(avro_datum_t datum, const char *symbol_name)
596 {
597 	check_param(EINVAL, is_avro_datum(datum), "datum");
598 	check_param(EINVAL, is_avro_enum(datum), "enum datum");
599 	check_param(EINVAL, symbol_name, "symbol name");
600 
601 	avro_schema_t  schema = avro_datum_to_enum(datum)->schema;
602 	int  symbol_value = avro_schema_enum_get_by_name(schema, symbol_name);
603 	if (symbol_value == -1) {
604 		avro_set_error("No symbol named %s", symbol_name);
605 		return EINVAL;
606 	}
607 	avro_datum_to_enum(datum)->value = symbol_value;
608 	return 0;
609 }
610 
avro_fixed_private(avro_schema_t schema,const char * bytes,const int64_t size,avro_free_func_t fixed_free)611 static avro_datum_t avro_fixed_private(avro_schema_t schema,
612 				       const char *bytes, const int64_t size,
613 				       avro_free_func_t fixed_free)
614 {
615 	check_param(NULL, is_avro_schema(schema), "schema");
616 	struct avro_fixed_schema_t *fschema = avro_schema_to_fixed(schema);
617 	if (size != fschema->size) {
618 		avro_free((char *) bytes, size);
619 		avro_set_error("Fixed size (%zu) doesn't match schema (%zu)",
620 			       (size_t) size, (size_t) fschema->size);
621 		return NULL;
622 	}
623 
624 	struct avro_fixed_datum_t *datum =
625 	    (struct avro_fixed_datum_t *) avro_new(struct avro_fixed_datum_t);
626 	if (!datum) {
627 		avro_free((char *) bytes, size);
628 		avro_set_error("Cannot create new fixed datum");
629 		return NULL;
630 	}
631 	datum->schema = avro_schema_incref(schema);
632 	datum->size = size;
633 	datum->bytes = (char *)bytes;
634 	datum->free = fixed_free;
635 
636 	avro_datum_init(&datum->obj, AVRO_FIXED);
637 	return &datum->obj;
638 }
639 
avro_fixed(avro_schema_t schema,const char * bytes,const int64_t size)640 avro_datum_t avro_fixed(avro_schema_t schema,
641 			const char *bytes, const int64_t size)
642 {
643 	char *bytes_copy = (char *) avro_malloc(size);
644 	if (!bytes_copy) {
645 		avro_set_error("Cannot copy fixed content");
646 		return NULL;
647 	}
648 	memcpy(bytes_copy, bytes, size);
649 	return avro_fixed_private(schema, bytes_copy, size, avro_alloc_free_func);
650 }
651 
avro_givefixed(avro_schema_t schema,const char * bytes,const int64_t size,avro_free_func_t free)652 avro_datum_t avro_givefixed(avro_schema_t schema,
653 			    const char *bytes, const int64_t size,
654 			    avro_free_func_t free)
655 {
656 	return avro_fixed_private(schema, bytes, size, free);
657 }
658 
avro_fixed_set_private(avro_datum_t datum,const char * bytes,const int64_t size,avro_free_func_t fixed_free)659 static int avro_fixed_set_private(avro_datum_t datum,
660 				  const char *bytes, const int64_t size,
661 				  avro_free_func_t fixed_free)
662 {
663 	check_param(EINVAL, is_avro_datum(datum), "datum");
664 	check_param(EINVAL, is_avro_fixed(datum), "fixed datum");
665 
666 	struct avro_fixed_datum_t *fixed = avro_datum_to_fixed(datum);
667 	struct avro_fixed_schema_t *schema = avro_schema_to_fixed(fixed->schema);
668 	if (size != schema->size) {
669 		avro_set_error("Fixed size doesn't match schema");
670 		return EINVAL;
671 	}
672 
673 	if (fixed->free) {
674 		fixed->free(fixed->bytes, fixed->size);
675 	}
676 
677 	fixed->free = fixed_free;
678 	fixed->bytes = (char *)bytes;
679 	fixed->size = size;
680 	return 0;
681 }
682 
avro_fixed_set(avro_datum_t datum,const char * bytes,const int64_t size)683 int avro_fixed_set(avro_datum_t datum, const char *bytes, const int64_t size)
684 {
685 	int rval;
686 	char *bytes_copy = (char *) avro_malloc(size);
687 	if (!bytes_copy) {
688 		avro_set_error("Cannot copy fixed content");
689 		return ENOMEM;
690 	}
691 	memcpy(bytes_copy, bytes, size);
692 	rval = avro_fixed_set_private(datum, bytes_copy, size, avro_alloc_free_func);
693 	if (rval) {
694 		avro_free(bytes_copy, size);
695 	}
696 	return rval;
697 }
698 
avro_givefixed_set(avro_datum_t datum,const char * bytes,const int64_t size,avro_free_func_t free)699 int avro_givefixed_set(avro_datum_t datum, const char *bytes,
700 		       const int64_t size, avro_free_func_t free)
701 {
702 	return avro_fixed_set_private(datum, bytes, size, free);
703 }
704 
avro_fixed_get(avro_datum_t datum,char ** bytes,int64_t * size)705 int avro_fixed_get(avro_datum_t datum, char **bytes, int64_t * size)
706 {
707 	check_param(EINVAL, is_avro_datum(datum), "datum");
708 	check_param(EINVAL, is_avro_fixed(datum), "fixed datum");
709 	check_param(EINVAL, bytes, "bytes");
710 	check_param(EINVAL, size, "size");
711 
712 	*bytes = avro_datum_to_fixed(datum)->bytes;
713 	*size = avro_datum_to_fixed(datum)->size;
714 	return 0;
715 }
716 
717 static int
avro_init_map(struct avro_map_datum_t * datum)718 avro_init_map(struct avro_map_datum_t *datum)
719 {
720 	datum->map = st_init_strtable_with_size(DEFAULT_TABLE_SIZE);
721 	if (!datum->map) {
722 		avro_set_error("Cannot create new map datum");
723 		return ENOMEM;
724 	}
725 	datum->indices_by_key = st_init_strtable_with_size(DEFAULT_TABLE_SIZE);
726 	if (!datum->indices_by_key) {
727 		avro_set_error("Cannot create new map datum");
728 		st_free_table(datum->map);
729 		return ENOMEM;
730 	}
731 	datum->keys_by_index = st_init_numtable_with_size(DEFAULT_TABLE_SIZE);
732 	if (!datum->keys_by_index) {
733 		avro_set_error("Cannot create new map datum");
734 		st_free_table(datum->indices_by_key);
735 		st_free_table(datum->map);
736 		return ENOMEM;
737 	}
738 	return 0;
739 }
740 
avro_map(avro_schema_t schema)741 avro_datum_t avro_map(avro_schema_t schema)
742 {
743 	check_param(NULL, is_avro_schema(schema), "schema");
744 
745 	struct avro_map_datum_t *datum =
746 	    (struct avro_map_datum_t *) avro_new(struct avro_map_datum_t);
747 	if (!datum) {
748 		avro_set_error("Cannot create new map datum");
749 		return NULL;
750 	}
751 
752 	if (avro_init_map(datum) != 0) {
753 		avro_freet(struct avro_map_datum_t, datum);
754 		return NULL;
755 	}
756 
757 	datum->schema = avro_schema_incref(schema);
758 	avro_datum_init(&datum->obj, AVRO_MAP);
759 	return &datum->obj;
760 }
761 
762 size_t
avro_map_size(const avro_datum_t datum)763 avro_map_size(const avro_datum_t datum)
764 {
765 	const struct avro_map_datum_t  *map = avro_datum_to_map(datum);
766 	return map->map->num_entries;
767 }
768 
769 int
avro_map_get(const avro_datum_t datum,const char * key,avro_datum_t * value)770 avro_map_get(const avro_datum_t datum, const char *key, avro_datum_t * value)
771 {
772 	check_param(EINVAL, is_avro_datum(datum), "datum");
773 	check_param(EINVAL, is_avro_map(datum), "map datum");
774 	check_param(EINVAL, key, "key");
775 	check_param(EINVAL, value, "value");
776 
777 	union {
778 		avro_datum_t datum;
779 		st_data_t data;
780 	} val;
781 
782 	struct avro_map_datum_t *map = avro_datum_to_map(datum);
783 	if (st_lookup(map->map, (st_data_t) key, &(val.data))) {
784 		*value = val.datum;
785 		return 0;
786 	}
787 
788 	avro_set_error("No map element named %s", key);
789 	return EINVAL;
790 }
791 
avro_map_get_key(const avro_datum_t datum,int index,const char ** key)792 int avro_map_get_key(const avro_datum_t datum, int index,
793 		     const char **key)
794 {
795 	check_param(EINVAL, is_avro_datum(datum), "datum");
796 	check_param(EINVAL, is_avro_map(datum), "map datum");
797 	check_param(EINVAL, index >= 0, "index");
798 	check_param(EINVAL, key, "key");
799 
800 	union {
801 		st_data_t data;
802 		char *key;
803 	} val;
804 
805 	struct avro_map_datum_t *map = avro_datum_to_map(datum);
806 	if (st_lookup(map->keys_by_index, (st_data_t) index, &val.data)) {
807 		*key = val.key;
808 		return 0;
809 	}
810 
811 	avro_set_error("No map element with index %d", index);
812 	return EINVAL;
813 }
814 
avro_map_get_index(const avro_datum_t datum,const char * key,int * index)815 int avro_map_get_index(const avro_datum_t datum, const char *key,
816 		       int *index)
817 {
818 	check_param(EINVAL, is_avro_datum(datum), "datum");
819 	check_param(EINVAL, is_avro_map(datum), "map datum");
820 	check_param(EINVAL, key, "key");
821 	check_param(EINVAL, index, "index");
822 
823 	st_data_t  data;
824 
825 	struct avro_map_datum_t *map = avro_datum_to_map(datum);
826 	if (st_lookup(map->indices_by_key, (st_data_t) key, &data)) {
827 		*index = (int) data;
828 		return 0;
829 	}
830 
831 	avro_set_error("No map element with key %s", key);
832 	return EINVAL;
833 }
834 
835 int
avro_map_set(avro_datum_t datum,const char * key,const avro_datum_t value)836 avro_map_set(avro_datum_t datum, const char *key,
837 	     const avro_datum_t value)
838 {
839 	check_param(EINVAL, is_avro_datum(datum), "datum");
840 	check_param(EINVAL, is_avro_map(datum), "map datum");
841 	check_param(EINVAL, key, "key");
842 	check_param(EINVAL, is_avro_datum(value), "value");
843 
844 	char *save_key = (char *)key;
845 	avro_datum_t old_datum;
846 
847 	struct avro_map_datum_t  *map = avro_datum_to_map(datum);
848 
849 	if (avro_map_get(datum, key, &old_datum) == 0) {
850 		/* Overwriting an old value */
851 		avro_datum_decref(old_datum);
852 	} else {
853 		/* Inserting a new value */
854 		save_key = avro_strdup(key);
855 		if (!save_key) {
856 			avro_set_error("Cannot copy map key");
857 			return ENOMEM;
858 		}
859 		int  new_index = map->map->num_entries;
860 		st_insert(map->indices_by_key, (st_data_t) save_key,
861 			  (st_data_t) new_index);
862 		st_insert(map->keys_by_index, (st_data_t) new_index,
863 			  (st_data_t) save_key);
864 	}
865 	avro_datum_incref(value);
866 	st_insert(map->map, (st_data_t) save_key, (st_data_t) value);
867 	return 0;
868 }
869 
870 static int
avro_init_array(struct avro_array_datum_t * datum)871 avro_init_array(struct avro_array_datum_t *datum)
872 {
873 	datum->els = st_init_numtable_with_size(DEFAULT_TABLE_SIZE);
874 	if (!datum->els) {
875 		avro_set_error("Cannot create new array datum");
876 		return ENOMEM;
877 	}
878 	return 0;
879 }
880 
avro_array(avro_schema_t schema)881 avro_datum_t avro_array(avro_schema_t schema)
882 {
883 	check_param(NULL, is_avro_schema(schema), "schema");
884 
885 	struct avro_array_datum_t *datum =
886 	    (struct avro_array_datum_t *) avro_new(struct avro_array_datum_t);
887 	if (!datum) {
888 		avro_set_error("Cannot create new array datum");
889 		return NULL;
890 	}
891 
892 	if (avro_init_array(datum) != 0) {
893 		avro_freet(struct avro_array_datum_t, datum);
894 		return NULL;
895 	}
896 
897 	datum->schema = avro_schema_incref(schema);
898 	avro_datum_init(&datum->obj, AVRO_ARRAY);
899 	return &datum->obj;
900 }
901 
902 int
avro_array_get(const avro_datum_t array_datum,int64_t index,avro_datum_t * value)903 avro_array_get(const avro_datum_t array_datum, int64_t index, avro_datum_t * value)
904 {
905 	check_param(EINVAL, is_avro_datum(array_datum), "datum");
906 	check_param(EINVAL, is_avro_array(array_datum), "array datum");
907 	check_param(EINVAL, value, "value pointer");
908 
909 	union {
910 		st_data_t data;
911 		avro_datum_t datum;
912 	} val;
913 
914         const struct avro_array_datum_t * array = avro_datum_to_array(array_datum);
915 	if (st_lookup(array->els, index, &val.data)) {
916 		*value = val.datum;
917 		return 0;
918 	}
919 
920 	avro_set_error("No array element with index %ld", (long) index);
921 	return EINVAL;
922 }
923 
924 size_t
avro_array_size(const avro_datum_t datum)925 avro_array_size(const avro_datum_t datum)
926 {
927 	const struct avro_array_datum_t  *array = avro_datum_to_array(datum);
928 	return array->els->num_entries;
929 }
930 
931 int
avro_array_append_datum(avro_datum_t array_datum,const avro_datum_t datum)932 avro_array_append_datum(avro_datum_t array_datum,
933 			const avro_datum_t datum)
934 {
935 	check_param(EINVAL, is_avro_datum(array_datum), "datum");
936 	check_param(EINVAL, is_avro_array(array_datum), "array datum");
937 	check_param(EINVAL, is_avro_datum(datum), "element datum");
938 
939 	struct avro_array_datum_t *array = avro_datum_to_array(array_datum);
940 	st_insert(array->els, array->els->num_entries,
941 		  (st_data_t) avro_datum_incref(datum));
942 	return 0;
943 }
944 
char_datum_free_foreach(char * key,avro_datum_t datum,void * arg)945 static int char_datum_free_foreach(char *key, avro_datum_t datum, void *arg)
946 {
947 	AVRO_UNUSED(arg);
948 
949 	avro_datum_decref(datum);
950 	avro_str_free(key);
951 	return ST_DELETE;
952 }
953 
array_free_foreach(int i,avro_datum_t datum,void * arg)954 static int array_free_foreach(int i, avro_datum_t datum, void *arg)
955 {
956 	AVRO_UNUSED(i);
957 	AVRO_UNUSED(arg);
958 
959 	avro_datum_decref(datum);
960 	return ST_DELETE;
961 }
962 
avro_datum_get_schema(const avro_datum_t datum)963 avro_schema_t avro_datum_get_schema(const avro_datum_t datum)
964 {
965 	check_param(NULL, is_avro_datum(datum), "datum");
966 
967 	switch (avro_typeof(datum)) {
968 		/*
969 		 * For the primitive types, which don't store an
970 		 * explicit reference to their schema, we decref the
971 		 * schema before returning.  This maintains the
972 		 * invariant that this function doesn't add any
973 		 * additional references to the schema.  The primitive
974 		 * schemas won't be freed, because there's always at
975 		 * least 1 reference for their initial static
976 		 * initializers.
977 		 */
978 
979 		case AVRO_STRING:
980 			{
981 				avro_schema_t  result = avro_schema_string();
982 				avro_schema_decref(result);
983 				return result;
984 			}
985 		case AVRO_BYTES:
986 			{
987 				avro_schema_t  result = avro_schema_bytes();
988 				avro_schema_decref(result);
989 				return result;
990 			}
991 		case AVRO_INT32:
992 			{
993 				avro_schema_t  result = avro_schema_int();
994 				avro_schema_decref(result);
995 				return result;
996 			}
997 		case AVRO_INT64:
998 			{
999 				avro_schema_t  result = avro_schema_long();
1000 				avro_schema_decref(result);
1001 				return result;
1002 			}
1003 		case AVRO_FLOAT:
1004 			{
1005 				avro_schema_t  result = avro_schema_float();
1006 				avro_schema_decref(result);
1007 				return result;
1008 			}
1009 		case AVRO_DOUBLE:
1010 			{
1011 				avro_schema_t  result = avro_schema_double();
1012 				avro_schema_decref(result);
1013 				return result;
1014 			}
1015 		case AVRO_BOOLEAN:
1016 			{
1017 				avro_schema_t  result = avro_schema_boolean();
1018 				avro_schema_decref(result);
1019 				return result;
1020 			}
1021 		case AVRO_NULL:
1022 			{
1023 				avro_schema_t  result = avro_schema_null();
1024 				avro_schema_decref(result);
1025 				return result;
1026 			}
1027 
1028 		case AVRO_RECORD:
1029 			return avro_datum_to_record(datum)->schema;
1030 		case AVRO_ENUM:
1031 			return avro_datum_to_enum(datum)->schema;
1032 		case AVRO_FIXED:
1033 			return avro_datum_to_fixed(datum)->schema;
1034 		case AVRO_MAP:
1035 			return avro_datum_to_map(datum)->schema;
1036 		case AVRO_ARRAY:
1037 			return avro_datum_to_array(datum)->schema;
1038 		case AVRO_UNION:
1039 			return avro_datum_to_union(datum)->schema;
1040 
1041 		default:
1042 			return NULL;
1043 	}
1044 }
1045 
avro_datum_free(avro_datum_t datum)1046 static void avro_datum_free(avro_datum_t datum)
1047 {
1048 	if (is_avro_datum(datum)) {
1049 		switch (avro_typeof(datum)) {
1050 		case AVRO_STRING:{
1051 				struct avro_string_datum_t *string;
1052 				string = avro_datum_to_string(datum);
1053 				if (string->free) {
1054 					string->free(string->s, string->size);
1055 				}
1056 				avro_freet(struct avro_string_datum_t, string);
1057 			}
1058 			break;
1059 		case AVRO_BYTES:{
1060 				struct avro_bytes_datum_t *bytes;
1061 				bytes = avro_datum_to_bytes(datum);
1062 				if (bytes->free) {
1063 					bytes->free(bytes->bytes, bytes->size);
1064 				}
1065 				avro_freet(struct avro_bytes_datum_t, bytes);
1066 			}
1067 			break;
1068 		case AVRO_INT32:{
1069 				avro_freet(struct avro_int32_datum_t, datum);
1070 			}
1071 			break;
1072 		case AVRO_INT64:{
1073 				avro_freet(struct avro_int64_datum_t, datum);
1074 			}
1075 			break;
1076 		case AVRO_FLOAT:{
1077 				avro_freet(struct avro_float_datum_t, datum);
1078 			}
1079 			break;
1080 		case AVRO_DOUBLE:{
1081 				avro_freet(struct avro_double_datum_t, datum);
1082 			}
1083 			break;
1084 		case AVRO_BOOLEAN:{
1085 				avro_freet(struct avro_boolean_datum_t, datum);
1086 			}
1087 			break;
1088 		case AVRO_NULL:
1089 			/* Nothing allocated */
1090 			break;
1091 
1092 		case AVRO_RECORD:{
1093 				struct avro_record_datum_t *record;
1094 				record = avro_datum_to_record(datum);
1095 				avro_schema_decref(record->schema);
1096 				st_foreach(record->fields_byname,
1097 					   HASH_FUNCTION_CAST char_datum_free_foreach, 0);
1098 				st_free_table(record->field_order);
1099 				st_free_table(record->fields_byname);
1100 				avro_freet(struct avro_record_datum_t, record);
1101 			}
1102 			break;
1103 		case AVRO_ENUM:{
1104 				struct avro_enum_datum_t *enump;
1105 				enump = avro_datum_to_enum(datum);
1106 				avro_schema_decref(enump->schema);
1107 				avro_freet(struct avro_enum_datum_t, enump);
1108 			}
1109 			break;
1110 		case AVRO_FIXED:{
1111 				struct avro_fixed_datum_t *fixed;
1112 				fixed = avro_datum_to_fixed(datum);
1113 				avro_schema_decref(fixed->schema);
1114 				if (fixed->free) {
1115 					fixed->free((void *)fixed->bytes,
1116 						    fixed->size);
1117 				}
1118 				avro_freet(struct avro_fixed_datum_t, fixed);
1119 			}
1120 			break;
1121 		case AVRO_MAP:{
1122 				struct avro_map_datum_t *map;
1123 				map = avro_datum_to_map(datum);
1124 				avro_schema_decref(map->schema);
1125 				st_foreach(map->map, HASH_FUNCTION_CAST char_datum_free_foreach,
1126 					   0);
1127 				st_free_table(map->map);
1128 				st_free_table(map->indices_by_key);
1129 				st_free_table(map->keys_by_index);
1130 				avro_freet(struct avro_map_datum_t, map);
1131 			}
1132 			break;
1133 		case AVRO_ARRAY:{
1134 				struct avro_array_datum_t *array;
1135 				array = avro_datum_to_array(datum);
1136 				avro_schema_decref(array->schema);
1137 				st_foreach(array->els, HASH_FUNCTION_CAST array_free_foreach, 0);
1138 				st_free_table(array->els);
1139 				avro_freet(struct avro_array_datum_t, array);
1140 			}
1141 			break;
1142 		case AVRO_UNION:{
1143 				struct avro_union_datum_t *unionp;
1144 				unionp = avro_datum_to_union(datum);
1145 				avro_schema_decref(unionp->schema);
1146 				avro_datum_decref(unionp->value);
1147 				avro_freet(struct avro_union_datum_t, unionp);
1148 			}
1149 			break;
1150 		case AVRO_LINK:{
1151 				/* TODO */
1152 			}
1153 			break;
1154 		}
1155 	}
1156 }
1157 
1158 static int
datum_reset_foreach(int i,avro_datum_t datum,void * arg)1159 datum_reset_foreach(int i, avro_datum_t datum, void *arg)
1160 {
1161 	AVRO_UNUSED(i);
1162 	int  rval;
1163 	int  *result = (int *) arg;
1164 
1165 	rval = avro_datum_reset(datum);
1166 	if (rval == 0) {
1167 		return ST_CONTINUE;
1168 	} else {
1169 		*result = rval;
1170 		return ST_STOP;
1171 	}
1172 }
1173 
1174 int
avro_datum_reset(avro_datum_t datum)1175 avro_datum_reset(avro_datum_t datum)
1176 {
1177 	check_param(EINVAL, is_avro_datum(datum), "datum");
1178 	int  rval;
1179 
1180 	switch (avro_typeof(datum)) {
1181 		case AVRO_ARRAY:
1182 		{
1183 			struct avro_array_datum_t *array;
1184 			array = avro_datum_to_array(datum);
1185 			st_foreach(array->els, HASH_FUNCTION_CAST array_free_foreach, 0);
1186 			st_free_table(array->els);
1187 
1188 			rval = avro_init_array(array);
1189 			if (rval != 0) {
1190 				avro_freet(struct avro_array_datum_t, array);
1191 				return rval;
1192 			}
1193 			return 0;
1194 		}
1195 
1196 		case AVRO_MAP:
1197 		{
1198 			struct avro_map_datum_t *map;
1199 			map = avro_datum_to_map(datum);
1200 			st_foreach(map->map, HASH_FUNCTION_CAST char_datum_free_foreach, 0);
1201 			st_free_table(map->map);
1202 			st_free_table(map->indices_by_key);
1203 			st_free_table(map->keys_by_index);
1204 
1205 			rval = avro_init_map(map);
1206 			if (rval != 0) {
1207 				avro_freet(struct avro_map_datum_t, map);
1208 				return rval;
1209 			}
1210 			return 0;
1211 		}
1212 
1213 		case AVRO_RECORD:
1214 		{
1215 			struct avro_record_datum_t *record;
1216 			record = avro_datum_to_record(datum);
1217 			rval = 0;
1218 			st_foreach(record->fields_byname,
1219 				   HASH_FUNCTION_CAST datum_reset_foreach, (st_data_t) &rval);
1220 			return rval;
1221 		}
1222 
1223 		case AVRO_UNION:
1224 		{
1225 			struct avro_union_datum_t *unionp;
1226 			unionp = avro_datum_to_union(datum);
1227 			return (unionp->value == NULL)? 0:
1228 			    avro_datum_reset(unionp->value);
1229 		}
1230 
1231 		default:
1232 			return 0;
1233 	}
1234 }
1235 
avro_datum_incref(avro_datum_t datum)1236 avro_datum_t avro_datum_incref(avro_datum_t datum)
1237 {
1238 	if (datum) {
1239 		avro_refcount_inc(&datum->refcount);
1240 	}
1241 	return datum;
1242 }
1243 
avro_datum_decref(avro_datum_t datum)1244 void avro_datum_decref(avro_datum_t datum)
1245 {
1246 	if (datum && avro_refcount_dec(&datum->refcount)) {
1247 		avro_datum_free(datum);
1248 	}
1249 }
1250 
avro_datum_print(avro_datum_t value,FILE * fp)1251 void avro_datum_print(avro_datum_t value, FILE * fp)
1252 {
1253 	AVRO_UNUSED(value);
1254 	AVRO_UNUSED(fp);
1255 }
1256