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