summaryrefslogtreecommitdiffstats
path: root/fluent-bit/lib/avro/src
diff options
context:
space:
mode:
Diffstat (limited to 'fluent-bit/lib/avro/src')
-rw-r--r--fluent-bit/lib/avro/src/.gitignore2
-rw-r--r--fluent-bit/lib/avro/src/CMakeLists.txt158
-rw-r--r--fluent-bit/lib/avro/src/allocation.c116
-rw-r--r--fluent-bit/lib/avro/src/array.c118
-rw-r--r--fluent-bit/lib/avro/src/avro-c.pc.in7
-rw-r--r--fluent-bit/lib/avro/src/avro.h40
-rw-r--r--fluent-bit/lib/avro/src/avro/allocation.h89
-rw-r--r--fluent-bit/lib/avro/src/avro/basics.h95
-rw-r--r--fluent-bit/lib/avro/src/avro/consumer.h317
-rw-r--r--fluent-bit/lib/avro/src/avro/data.h526
-rw-r--r--fluent-bit/lib/avro/src/avro/errors.h41
-rw-r--r--fluent-bit/lib/avro/src/avro/generic.h88
-rw-r--r--fluent-bit/lib/avro/src/avro/io.h156
-rw-r--r--fluent-bit/lib/avro/src/avro/legacy.h264
-rw-r--r--fluent-bit/lib/avro/src/avro/msinttypes.h315
-rw-r--r--fluent-bit/lib/avro/src/avro/msstdint.h247
-rw-r--r--fluent-bit/lib/avro/src/avro/platform.h45
-rw-r--r--fluent-bit/lib/avro/src/avro/refcount.h306
-rw-r--r--fluent-bit/lib/avro/src/avro/resolver.h130
-rw-r--r--fluent-bit/lib/avro/src/avro/schema.h122
-rw-r--r--fluent-bit/lib/avro/src/avro/value.h498
-rw-r--r--fluent-bit/lib/avro/src/avro_generic_internal.h73
-rw-r--r--fluent-bit/lib/avro/src/avro_private.h99
-rw-r--r--fluent-bit/lib/avro/src/avroappend.c169
-rw-r--r--fluent-bit/lib/avro/src/avrocat.c127
-rw-r--r--fluent-bit/lib/avro/src/avromod.c168
-rw-r--r--fluent-bit/lib/avro/src/avropipe.c432
-rw-r--r--fluent-bit/lib/avro/src/codec.c620
-rw-r--r--fluent-bit/lib/avro/src/codec.h53
-rw-r--r--fluent-bit/lib/avro/src/consume-binary.c328
-rw-r--r--fluent-bit/lib/avro/src/consumer.c23
-rw-r--r--fluent-bit/lib/avro/src/datafile.c766
-rw-r--r--fluent-bit/lib/avro/src/datum.c1255
-rw-r--r--fluent-bit/lib/avro/src/datum.h123
-rw-r--r--fluent-bit/lib/avro/src/datum_equal.c186
-rw-r--r--fluent-bit/lib/avro/src/datum_read.c99
-rw-r--r--fluent-bit/lib/avro/src/datum_size.c292
-rw-r--r--fluent-bit/lib/avro/src/datum_skip.c202
-rw-r--r--fluent-bit/lib/avro/src/datum_validate.c193
-rw-r--r--fluent-bit/lib/avro/src/datum_value.c784
-rw-r--r--fluent-bit/lib/avro/src/datum_write.c91
-rw-r--r--fluent-bit/lib/avro/src/dump.c56
-rw-r--r--fluent-bit/lib/avro/src/dump.h34
-rw-r--r--fluent-bit/lib/avro/src/encoding.h106
-rw-r--r--fluent-bit/lib/avro/src/encoding_binary.c446
-rw-r--r--fluent-bit/lib/avro/src/errors.c160
-rw-r--r--fluent-bit/lib/avro/src/generic.c3707
-rw-r--r--fluent-bit/lib/avro/src/io.c447
-rw-r--r--fluent-bit/lib/avro/src/map.c130
-rw-r--r--fluent-bit/lib/avro/src/memoize.c165
-rw-r--r--fluent-bit/lib/avro/src/resolved-reader.c3377
-rw-r--r--fluent-bit/lib/avro/src/resolved-writer.c2911
-rw-r--r--fluent-bit/lib/avro/src/resolver.c1338
-rw-r--r--fluent-bit/lib/avro/src/schema.c1897
-rw-r--r--fluent-bit/lib/avro/src/schema.h87
-rw-r--r--fluent-bit/lib/avro/src/schema_equal.c204
-rw-r--r--fluent-bit/lib/avro/src/schema_specific.c232
-rw-r--r--fluent-bit/lib/avro/src/st.c543
-rw-r--r--fluent-bit/lib/avro/src/st.h87
-rw-r--r--fluent-bit/lib/avro/src/string.c304
-rw-r--r--fluent-bit/lib/avro/src/value-hash.c294
-rw-r--r--fluent-bit/lib/avro/src/value-json.c417
-rw-r--r--fluent-bit/lib/avro/src/value-read.c392
-rw-r--r--fluent-bit/lib/avro/src/value-sizeof.c230
-rw-r--r--fluent-bit/lib/avro/src/value-write.c209
-rw-r--r--fluent-bit/lib/avro/src/value.c690
-rw-r--r--fluent-bit/lib/avro/src/wrapped-buffer.c145
67 files changed, 28371 insertions, 0 deletions
diff --git a/fluent-bit/lib/avro/src/.gitignore b/fluent-bit/lib/avro/src/.gitignore
new file mode 100644
index 000000000..e278a8b91
--- /dev/null
+++ b/fluent-bit/lib/avro/src/.gitignore
@@ -0,0 +1,2 @@
+avro-c.pc
+avropipe
diff --git a/fluent-bit/lib/avro/src/CMakeLists.txt b/fluent-bit/lib/avro/src/CMakeLists.txt
new file mode 100644
index 000000000..a911115f6
--- /dev/null
+++ b/fluent-bit/lib/avro/src/CMakeLists.txt
@@ -0,0 +1,158 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+set(AVRO_SRC
+ allocation.c
+ array.c
+ avro.h
+ avro/allocation.h
+ avro/basics.h
+ avro/consumer.h
+ avro/data.h
+ avro/errors.h
+ avro/generic.h
+ avro/io.h
+ avro/legacy.h
+ avro/refcount.h
+ avro/resolver.h
+ avro/schema.h
+ avro/value.h
+ avro_generic_internal.h
+ avro_private.h
+ codec.c
+ codec.h
+ consumer.c
+ consume-binary.c
+ datafile.c
+ datum.c
+ datum.h
+ datum_equal.c
+ datum_read.c
+ datum_size.c
+ datum_skip.c
+ datum_validate.c
+ datum_value.c
+ datum_write.c
+ dump.c
+ dump.h
+ encoding.h
+ encoding_binary.c
+ errors.c
+ generic.c
+ io.c
+ map.c
+ memoize.c
+ resolved-reader.c
+ resolved-writer.c
+ resolver.c
+ schema.c
+ schema.h
+ schema_equal.c
+ st.c
+ st.h
+ string.c
+ value.c
+ value-hash.c
+ value-json.c
+ value-read.c
+ value-sizeof.c
+ value-write.c
+ wrapped-buffer.c
+)
+
+
+source_group(Avro FILES ${AVRO_SRC})
+
+# The version.sh script gives us a VERSION that uses colon as a
+# separator; we need periods.
+
+string(REPLACE ":" "." LIBAVRO_DOT_VERSION ${LIBAVRO_VERSION})
+
+add_library(avro-static STATIC ${AVRO_SRC})
+target_link_libraries(avro-static ${JANSSON_LIBRARIES} ${CODEC_LIBRARIES} ${THREADS_LIBRARIES})
+set_target_properties(avro-static PROPERTIES OUTPUT_NAME avro)
+
+if (NOT WIN32)
+# TODO: Create Windows DLLs. See https://www.cmake.org/Wiki/BuildingWinDLL
+add_library(avro-shared SHARED ${AVRO_SRC})
+target_link_libraries(avro-shared ${JANSSON_LIBRARIES} ${CODEC_LIBRARIES} ${THREADS_LIBRARIES})
+set_target_properties(avro-shared PROPERTIES
+ OUTPUT_NAME avro
+ VERSION ${LIBAVRO_DOT_VERSION}
+ SOVERSION ${LIBAVRO_SOVERSION})
+endif(NOT WIN32)
+
+install(FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/avro.h
+ DESTINATION include)
+install(DIRECTORY
+ ${CMAKE_CURRENT_SOURCE_DIR}/avro
+ DESTINATION include
+ FILES_MATCHING PATTERN "*.h")
+
+# updated by edsiper, avro version 77692d8c1
+# added by mcqueen to get the headers into the fluent-bit build root 07OCT2020
+file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/avro.h
+ DESTINATION ${CMAKE_BINARY_DIR}/include/)
+file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/avro
+ DESTINATION ${CMAKE_BINARY_DIR}/include/
+ FILES_MATCHING PATTERN "*.h")
+
+include(GNUInstallDirs)
+
+if (WIN32)
+install(TARGETS avro-static
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ )
+else(WIN32)
+install(TARGETS avro-static avro-shared
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ )
+endif(WIN32)
+
+# Install pkg-config file
+
+set(prefix ${CMAKE_INSTALL_PREFIX})
+set(VERSION ${AVRO_VERSION})
+configure_file(avro-c.pc.in avro-c.pc)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/avro-c.pc
+ DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
+
+add_executable(avrocat avrocat.c)
+target_link_libraries(avrocat avro-static)
+install(TARGETS avrocat RUNTIME DESTINATION bin)
+
+add_executable(avroappend avroappend.c)
+target_link_libraries(avroappend avro-static)
+install(TARGETS avroappend RUNTIME DESTINATION bin)
+
+if (NOT WIN32)
+#TODO: Port getopt() to Windows to compile avropipe.c and avromod.c
+add_executable(avropipe avropipe.c)
+target_link_libraries(avropipe avro-static)
+install(TARGETS avropipe RUNTIME DESTINATION bin)
+
+add_executable(avromod avromod.c)
+target_link_libraries(avromod avro-static)
+install(TARGETS avromod RUNTIME DESTINATION bin)
+endif(NOT WIN32)
diff --git a/fluent-bit/lib/avro/src/allocation.c b/fluent-bit/lib/avro/src/allocation.c
new file mode 100644
index 000000000..2059f92a9
--- /dev/null
+++ b/fluent-bit/lib/avro/src/allocation.c
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro_private.h"
+#include "avro/allocation.h"
+#include "avro/data.h"
+#include "avro/legacy.h"
+
+static void *
+avro_default_allocator(void *ud, void *ptr, size_t osize, size_t nsize)
+{
+ AVRO_UNUSED(ud);
+ AVRO_UNUSED(osize);
+
+ if (nsize == 0) {
+ free(ptr);
+ return NULL;
+ } else {
+ return realloc(ptr, nsize);
+ }
+}
+
+struct avro_allocator_state AVRO_CURRENT_ALLOCATOR = {
+ avro_default_allocator,
+ NULL
+};
+
+void avro_set_allocator(avro_allocator_t alloc, void *user_data)
+{
+ AVRO_CURRENT_ALLOCATOR.alloc = alloc;
+ AVRO_CURRENT_ALLOCATOR.user_data = user_data;
+}
+
+void *avro_calloc(size_t count, size_t size)
+{
+ void *ptr = avro_malloc(count * size);
+ if (ptr != NULL) {
+ memset(ptr, 0, count * size);
+ }
+ return ptr;
+}
+
+char *avro_str_alloc(size_t str_size)
+{
+ size_t buf_size = str_size + sizeof(size_t);
+
+ void *buf = avro_malloc(buf_size);
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ size_t *size = (size_t *) buf;
+ char *new_str = (char *) (size + 1);
+
+ *size = buf_size;
+
+ return new_str;
+}
+
+char *avro_strdup(const char *str)
+{
+ if (str == NULL) {
+ return NULL;
+ }
+
+ size_t str_size = strlen(str)+1;
+ char *new_str = avro_str_alloc(str_size);
+ memcpy(new_str, str, str_size);
+
+ //fprintf(stderr, "--- new %" PRIsz " %p %s\n", *size, new_str, new_str);
+ return new_str;
+}
+
+char *avro_strndup(const char *str, size_t size)
+{
+ if (str == NULL) {
+ return NULL;
+ }
+
+ char *new_str = avro_str_alloc(size + 1);
+ memcpy(new_str, str, size);
+ new_str[size] = '\0';
+
+ return new_str;
+}
+
+void avro_str_free(char *str)
+{
+ size_t *size = ((size_t *) str) - 1;
+ //fprintf(stderr, "--- free %" PRIsz " %p %s\n", *size, str, str);
+ avro_free(size, *size);
+}
+
+
+void
+avro_alloc_free_func(void *ptr, size_t sz)
+{
+ avro_free(ptr, sz);
+}
diff --git a/fluent-bit/lib/avro/src/array.c b/fluent-bit/lib/avro/src/array.c
new file mode 100644
index 000000000..94dce295c
--- /dev/null
+++ b/fluent-bit/lib/avro/src/array.c
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro/allocation.h"
+#include "avro/data.h"
+#include "avro/errors.h"
+#include "avro_private.h"
+
+
+void avro_raw_array_init(avro_raw_array_t *array, size_t element_size)
+{
+ memset(array, 0, sizeof(avro_raw_array_t));
+ array->element_size = element_size;
+}
+
+
+void avro_raw_array_done(avro_raw_array_t *array)
+{
+ if (array->data) {
+ avro_free(array->data, array->allocated_size);
+ }
+ memset(array, 0, sizeof(avro_raw_array_t));
+}
+
+
+void avro_raw_array_clear(avro_raw_array_t *array)
+{
+ array->element_count = 0;
+}
+
+
+int
+avro_raw_array_ensure_size(avro_raw_array_t *array, size_t desired_count)
+{
+ size_t required_size = array->element_size * desired_count;
+ if (array->allocated_size >= required_size) {
+ return 0;
+ }
+
+ /*
+ * Double the old size when reallocating.
+ */
+
+ size_t new_size;
+ if (array->allocated_size == 0) {
+ /*
+ * Start with an arbitrary 10 items.
+ */
+
+ new_size = 10 * array->element_size;
+ } else {
+ new_size = array->allocated_size * 2;
+ }
+
+ if (required_size > new_size) {
+ new_size = required_size;
+ }
+
+ array->data = avro_realloc(array->data, array->allocated_size, new_size);
+ if (array->data == NULL) {
+ avro_set_error("Cannot allocate space in array for %" PRIsz " elements",
+ desired_count);
+ return ENOMEM;
+ }
+ array->allocated_size = new_size;
+
+ return 0;
+}
+
+
+int
+avro_raw_array_ensure_size0(avro_raw_array_t *array, size_t desired_count)
+{
+ int rval;
+ size_t old_allocated_size = array->allocated_size;
+ check(rval, avro_raw_array_ensure_size(array, desired_count));
+
+ if (array->allocated_size > old_allocated_size) {
+ size_t extra_space = array->allocated_size - old_allocated_size;
+ void *buf = array->data;
+ memset((char *)buf + old_allocated_size, 0, extra_space);
+ }
+
+ return 0;
+}
+
+
+void *avro_raw_array_append(avro_raw_array_t *array)
+{
+ int rval;
+
+ rval = avro_raw_array_ensure_size(array, array->element_count + 1);
+ if (rval) {
+ return NULL;
+ }
+
+ size_t offset = array->element_size * array->element_count;
+ array->element_count++;
+ return (char *)array->data + offset;
+}
diff --git a/fluent-bit/lib/avro/src/avro-c.pc.in b/fluent-bit/lib/avro/src/avro-c.pc.in
new file mode 100644
index 000000000..013afe4d1
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro-c.pc.in
@@ -0,0 +1,7 @@
+Name: avro-c
+Description: C library for parsing Avro data
+Version: @VERSION@
+URL: https://avro.apache.org/
+Libs: -L@prefix@/lib -lavro
+Cflags: -I@prefix@/include
+Requires: @CODEC_PKG@
diff --git a/fluent-bit/lib/avro/src/avro.h b/fluent-bit/lib/avro/src/avro.h
new file mode 100644
index 000000000..af32a32db
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro.h
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+#ifndef AVRO_H
+#define AVRO_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+#include <avro/allocation.h>
+#include <avro/basics.h>
+#include <avro/consumer.h>
+#include <avro/data.h>
+#include <avro/errors.h>
+#include <avro/generic.h>
+#include <avro/io.h>
+#include <avro/legacy.h>
+#include <avro/platform.h>
+#include <avro/resolver.h>
+#include <avro/schema.h>
+#include <avro/value.h>
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/avro/allocation.h b/fluent-bit/lib/avro/src/avro/allocation.h
new file mode 100644
index 000000000..0ed412b94
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro/allocation.h
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef AVRO_ALLOCATION_H
+#define AVRO_ALLOCATION_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+#include <stdlib.h>
+
+/*
+ * Allocation interface. You can provide a custom allocator for the
+ * library, should you wish. The allocator is provided as a single
+ * generic function, which can emulate the standard malloc, realloc, and
+ * free functions. The design of this allocation interface is inspired
+ * by the implementation of the Lua interpreter.
+ *
+ * The ptr parameter will be the location of any existing memory
+ * buffer. The osize parameter will be the size of this existing
+ * buffer. If ptr is NULL, then osize will be 0. The nsize parameter
+ * will be the size of the new buffer, or 0 if the new buffer should be
+ * freed.
+ *
+ * If nsize is 0, then the allocation function must return NULL. If
+ * nsize is not 0, then it should return NULL if the allocation fails.
+ */
+
+typedef void *
+(*avro_allocator_t)(void *user_data, void *ptr, size_t osize, size_t nsize);
+
+void avro_set_allocator(avro_allocator_t alloc, void *user_data);
+
+struct avro_allocator_state {
+ avro_allocator_t alloc;
+ void *user_data;
+};
+
+extern struct avro_allocator_state AVRO_CURRENT_ALLOCATOR;
+
+#define avro_realloc(ptr, osz, nsz) \
+ (AVRO_CURRENT_ALLOCATOR.alloc \
+ (AVRO_CURRENT_ALLOCATOR.user_data, \
+ (ptr), (osz), (nsz)))
+
+#define avro_malloc(sz) (avro_realloc(NULL, 0, (sz)))
+#define avro_free(ptr, osz) (avro_realloc((ptr), (osz), 0))
+
+#define avro_new(type) (avro_realloc(NULL, 0, sizeof(type)))
+#define avro_freet(type, ptr) (avro_realloc((ptr), sizeof(type), 0))
+
+void *avro_calloc(size_t count, size_t size);
+
+/*
+ * This is probably too clever for our own good, but when we duplicate a
+ * string, we actually store its size in the same allocated memory
+ * buffer. That lets us free the string later, without having to call
+ * strlen to get its size, and without the containing struct having to
+ * manually store the strings length.
+ *
+ * This means that any string return by avro_strdup MUST be freed using
+ * avro_str_free, and the only thing that can be passed into
+ * avro_str_free is a string created via avro_strdup.
+ */
+
+char *avro_str_alloc(size_t str_size);
+char *avro_strdup(const char *str);
+char *avro_strndup(const char *str, size_t size);
+void avro_str_free(char *str);
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/avro/basics.h b/fluent-bit/lib/avro/src/avro/basics.h
new file mode 100644
index 000000000..368509b90
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro/basics.h
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef AVRO_BASICS_H
+#define AVRO_BASICS_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+
+enum avro_type_t {
+ AVRO_STRING,
+ AVRO_BYTES,
+ AVRO_INT32,
+ AVRO_INT64,
+ AVRO_FLOAT,
+ AVRO_DOUBLE,
+ AVRO_BOOLEAN,
+ AVRO_NULL,
+ AVRO_RECORD,
+ AVRO_ENUM,
+ AVRO_FIXED,
+ AVRO_MAP,
+ AVRO_ARRAY,
+ AVRO_UNION,
+ AVRO_LINK
+};
+typedef enum avro_type_t avro_type_t;
+
+enum avro_class_t {
+ AVRO_SCHEMA,
+ AVRO_DATUM
+};
+typedef enum avro_class_t avro_class_t;
+
+struct avro_obj_t {
+ avro_type_t type;
+ avro_class_t class_type;
+ volatile int refcount;
+};
+
+#define avro_classof(obj) ((obj)->class_type)
+#define is_avro_schema(obj) (obj && avro_classof(obj) == AVRO_SCHEMA)
+#define is_avro_datum(obj) (obj && avro_classof(obj) == AVRO_DATUM)
+
+#define avro_typeof(obj) ((obj)->type)
+#define is_avro_string(obj) (obj && avro_typeof(obj) == AVRO_STRING)
+#define is_avro_bytes(obj) (obj && avro_typeof(obj) == AVRO_BYTES)
+#define is_avro_int32(obj) (obj && avro_typeof(obj) == AVRO_INT32)
+#define is_avro_int64(obj) (obj && avro_typeof(obj) == AVRO_INT64)
+#define is_avro_float(obj) (obj && avro_typeof(obj) == AVRO_FLOAT)
+#define is_avro_double(obj) (obj && avro_typeof(obj) == AVRO_DOUBLE)
+#define is_avro_boolean(obj) (obj && avro_typeof(obj) == AVRO_BOOLEAN)
+#define is_avro_null(obj) (obj && avro_typeof(obj) == AVRO_NULL)
+#define is_avro_primitive(obj)(is_avro_string(obj) \
+ ||is_avro_bytes(obj) \
+ ||is_avro_int32(obj) \
+ ||is_avro_int64(obj) \
+ ||is_avro_float(obj) \
+ ||is_avro_double(obj) \
+ ||is_avro_boolean(obj) \
+ ||is_avro_null(obj))
+#define is_avro_record(obj) (obj && avro_typeof(obj) == AVRO_RECORD)
+#define is_avro_enum(obj) (obj && avro_typeof(obj) == AVRO_ENUM)
+#define is_avro_fixed(obj) (obj && avro_typeof(obj) == AVRO_FIXED)
+#define is_avro_named_type(obj)(is_avro_record(obj) \
+ ||is_avro_enum(obj) \
+ ||is_avro_fixed(obj))
+#define is_avro_map(obj) (obj && avro_typeof(obj) == AVRO_MAP)
+#define is_avro_array(obj) (obj && avro_typeof(obj) == AVRO_ARRAY)
+#define is_avro_union(obj) (obj && avro_typeof(obj) == AVRO_UNION)
+#define is_avro_complex_type(obj) (!(is_avro_primitive(obj))
+#define is_avro_link(obj) (obj && avro_typeof(obj) == AVRO_LINK)
+
+
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/avro/consumer.h b/fluent-bit/lib/avro/src/avro/consumer.h
new file mode 100644
index 000000000..4128eef1a
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro/consumer.h
@@ -0,0 +1,317 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef AVRO_CONSUMER_H
+#define AVRO_CONSUMER_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+#include <avro/platform.h>
+#include <stdlib.h>
+
+#include <avro/io.h>
+#include <avro/schema.h>
+
+
+/*---------------------------------------------------------------------
+ * Consumers
+ */
+
+/**
+ * A <i>consumer</i> is an object that knows how to process Avro data.
+ * There are consumer methods for each type of Avro data. The
+ * <code>avro_consumer_t</code> struct is an abstract superclass, which
+ * you don't instantiate directly. Later in this file, we define
+ * several consumer classes that know how to process Avro data in
+ * specific ways.
+ *
+ * For compound Avro values (records, arrays, maps, and unions), the
+ * consumer callbacks provide a nested consumer that should be used to
+ * process subvalues. Each consumer instance, including these
+ * "subconsumers", contains a reference to the schema of the data that
+ * it expects to process. This means that the functions that produce
+ * Avro data (such as avro_consume_binary) don't need to maintain their
+ * own references to any schemas, since they'll be encapsulated in the
+ * consumer that they pass their data off to.
+ */
+
+typedef struct avro_consumer_t avro_consumer_t;
+
+struct avro_consumer_t {
+ /**
+ * The schema of the data that this consumer expects to process.
+ */
+
+ avro_schema_t schema;
+
+ /**
+ * Called when this consumer is freed. This function should
+ * free any additional resources acquired by a consumer
+ * subclass.
+ */
+
+ void (*free)(avro_consumer_t *consumer);
+
+ /* PRIMITIVE VALUES */
+
+ /**
+ * Called when a boolean value is encountered.
+ */
+
+ int (*boolean_value)(avro_consumer_t *consumer,
+ int value,
+ void *user_data);
+
+ /**
+ * Called when a bytes value is encountered. The @ref value
+ * pointer is only guaranteed to be valid for the duration of
+ * the callback function. If you need to save the data for
+ * processing later, you must copy it into another buffer.
+ */
+
+ int (*bytes_value)(avro_consumer_t *consumer,
+ const void *value, size_t value_len,
+ void *user_data);
+
+ /**
+ * Called when a double value is encountered.
+ */
+
+ int (*double_value)(avro_consumer_t *consumer,
+ double value,
+ void *user_data);
+
+ /**
+ * Called when a float value is encountered.
+ */
+
+ int (*float_value)(avro_consumer_t *consumer,
+ float value,
+ void *user_data);
+
+ /**
+ * Called when an int value is encountered.
+ */
+
+ int (*int_value)(avro_consumer_t *consumer,
+ int32_t value,
+ void *user_data);
+
+ /**
+ * Called when a long value is encountered.
+ */
+
+ int (*long_value)(avro_consumer_t *consumer,
+ int64_t value,
+ void *user_data);
+
+ /**
+ * Called when a null value is encountered.
+ */
+
+ int (*null_value)(avro_consumer_t *consumer, void *user_data);
+
+ /**
+ * Called when a string value is encountered. The @ref value
+ * pointer will point at UTF-8 encoded data. (If the data
+ * you're representing isn't a UTF-8 Unicode string, you
+ * should use the bytes type.) The @ref value_len parameter
+ * gives the length of the data in bytes, not in Unicode
+ * characters. The @ref value pointer is only guaranteed to
+ * be valid for the duration of the callback function. If you
+ * need to save the data for processing later, you must copy
+ * it into another buffer.
+ */
+
+ int (*string_value)(avro_consumer_t *consumer,
+ const void *value, size_t value_len,
+ void *user_data);
+
+ /* COMPOUND VALUES */
+
+ /**
+ * Called when the beginning of an array block is encountered.
+ * The @ref block_count parameter will contain the number of
+ * elements in this block.
+ */
+
+ int (*array_start_block)(avro_consumer_t *consumer,
+ int is_first_block,
+ unsigned int block_count,
+ void *user_data);
+
+ /**
+ * Called before each individual element of an array is
+ * processed. The index of the current element is passed into
+ * the callback. The callback should fill in @ref
+ * element_consumer and @ref element_user_data with the consumer
+ * and <code>user_data</code> pointer to use to process the
+ * element.
+ */
+
+ int (*array_element)(avro_consumer_t *consumer,
+ unsigned int index,
+ avro_consumer_t **element_consumer,
+ void **element_user_data,
+ void *user_data);
+
+ /**
+ * Called when an enum value is encountered.
+ */
+
+ int (*enum_value)(avro_consumer_t *consumer, int value,
+ void *user_data);
+
+ /**
+ * Called when a fixed value is encountered. The @ref value
+ * pointer is only guaranteed to be valid for the duration of
+ * the callback function. If you need to save the data for
+ * processing later, you must copy it into another buffer.
+ */
+
+ int (*fixed_value)(avro_consumer_t *consumer,
+ const void *value, size_t value_len,
+ void *user_data);
+
+ /**
+ * Called when the beginning of a map block is encountered.
+ * The @ref block_count parameter will contain the number of
+ * elements in this block.
+ */
+
+ int (*map_start_block)(avro_consumer_t *consumer,
+ int is_first_block,
+ unsigned int block_count,
+ void *user_data);
+
+ /**
+ * Called before each individual element of a map is
+ * processed. The index and key of the current element is
+ * passed into the callback. The key is only guaranteed to be
+ * valid for the duration of the map_element_start callback,
+ * and the map's subschema callback. If you need to save it for
+ * later use, you must copy the key into another memory
+ * location. The callback should fill in @ref value_consumer
+ * and @ref value_user_data with the consumer and
+ * <code>user_data</code> pointer to use to process the value.
+ */
+
+ int (*map_element)(avro_consumer_t *consumer,
+ unsigned int index,
+ const char *key,
+ avro_consumer_t **value_consumer,
+ void **value_user_data,
+ void *user_data);
+
+ /**
+ * Called when the beginning of a record is encountered.
+ */
+
+ int (*record_start)(avro_consumer_t *consumer,
+ void *user_data);
+
+ /**
+ * Called before each individual field of a record is
+ * processed. The index and name of the current field is
+ * passed into the callback. The name is only guaranteed to
+ * be valid for the duration of the record_field_start
+ * callback, and the field's subschema callback. If you need to
+ * save it for later use, you must copy the key into another
+ * memory location. The callback should fill in @ref
+ * field_consumer and @ref field_user_data with the consumer
+ * <code>user_data</code> pointer to use to process the field.
+ */
+
+ int (*record_field)(avro_consumer_t *consumer,
+ unsigned int index,
+ avro_consumer_t **field_consumer,
+ void **field_user_data,
+ void *user_data);
+
+ /**
+ * Called when a union value is encountered. The callback
+ * should fill in @ref branch_consumer and @ref branch_user_data
+ * with the consumer <code>user_data</code> pointer to use to
+ * process the branch.
+ */
+
+ int (*union_branch)(avro_consumer_t *consumer,
+ unsigned int discriminant,
+ avro_consumer_t **branch_consumer,
+ void **branch_user_data,
+ void *user_data);
+};
+
+
+/**
+ * Calls the given callback in consumer, if it's present. If the
+ * callback is NULL, it just returns a success code.
+ */
+
+#define avro_consumer_call(consumer, callback, ...) \
+ (((consumer)->callback == NULL)? 0: \
+ (consumer)->callback((consumer), __VA_ARGS__))
+
+
+/**
+ * Frees an @ref avro_consumer_t instance. (This function works on
+ * consumer subclasses, too.)
+ */
+
+void avro_consumer_free(avro_consumer_t *consumer);
+
+
+/*---------------------------------------------------------------------
+ * Resolvers
+ */
+
+/**
+ * A <i>resolver</i> is a special kind of consumer that knows how to
+ * implement Avro's schema resolution rules to translate between a
+ * writer schema and a reader schema. The consumer callbacks line up
+ * with the writer schema; as each element of the datum is produced, the
+ * resolver fills in the contents of an @ref avro_datum_t instance.
+ * (The datum is provided as the user_data when you use the consumer.)
+ */
+
+avro_consumer_t *
+avro_resolver_new(avro_schema_t writer_schema,
+ avro_schema_t reader_schema);
+
+
+/*---------------------------------------------------------------------
+ * Binary encoding
+ */
+
+/**
+ * Reads an Avro datum from the given @ref avro_reader_t. As the
+ * datum is read, each portion of it is passed off to the appropriate
+ * callback in @ref consumer.
+ */
+
+int
+avro_consume_binary(avro_reader_t reader,
+ avro_consumer_t *consumer,
+ void *ud);
+
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/avro/data.h b/fluent-bit/lib/avro/src/avro/data.h
new file mode 100644
index 000000000..5b1d429b3
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro/data.h
@@ -0,0 +1,526 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef AVRO_DATA_H
+#define AVRO_DATA_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+/*
+ * This file defines some helper data structures that are used within
+ * Avro, and in the schema-specific types created by avrocc.
+ */
+
+
+/*---------------------------------------------------------------------
+ * Arrays
+ */
+
+/**
+ * A resizeable array of fixed-size elements.
+ */
+
+typedef struct avro_raw_array {
+ size_t element_size;
+ size_t element_count;
+ size_t allocated_size;
+ void *data;
+} avro_raw_array_t;
+
+/**
+ * Initializes a new avro_raw_array_t that you've allocated yourself.
+ */
+
+void avro_raw_array_init(avro_raw_array_t *array, size_t element_size);
+
+/**
+ * Finalizes an avro_raw_array_t.
+ */
+
+void avro_raw_array_done(avro_raw_array_t *array);
+
+/**
+ * Clears an avro_raw_array_t. This does not deallocate any space; this
+ * allows us to reuse the underlying array buffer as we start to re-add
+ * elements to the array.
+ */
+
+void avro_raw_array_clear(avro_raw_array_t *array);
+
+/**
+ * Ensures that there is enough allocated space to store the given
+ * number of elements in an avro_raw_array_t. If we can't allocate that
+ * much space, we return ENOMEM.
+ */
+
+int
+avro_raw_array_ensure_size(avro_raw_array_t *array, size_t desired_count);
+
+/**
+ * Ensures that there is enough allocated space to store the given
+ * number of elements in an avro_raw_array_t. If the array grows as a
+ * result of this operation, we will fill in any newly allocated space
+ * with 0 bytes. If we can't allocate that much space, we return
+ * ENOMEM.
+ */
+
+int
+avro_raw_array_ensure_size0(avro_raw_array_t *array, size_t desired_count);
+
+/**
+ * Returns the number of elements in an avro_raw_array_t.
+ */
+
+#define avro_raw_array_size(array) ((array)->element_count)
+
+/**
+ * Returns the given element of an avro_raw_array_t as a <code>void
+ * *</code>.
+ */
+
+#define avro_raw_array_get_raw(array, index) \
+ ((char *) (array)->data + (array)->element_size * index)
+
+/**
+ * Returns the given element of an avro_raw_array_t, using element_type
+ * as the type of the elements. The result is *not* a pointer to the
+ * element; you get the element itself.
+ */
+
+#define avro_raw_array_get(array, element_type, index) \
+ (((element_type *) (array)->data)[index])
+
+/**
+ * Appends a new element to an avro_raw_array_t, expanding it if
+ * necessary. Returns a pointer to the new element, or NULL if we
+ * needed to reallocate the array and couldn't.
+ */
+
+void *avro_raw_array_append(avro_raw_array_t *array);
+
+
+/*---------------------------------------------------------------------
+ * Maps
+ */
+
+/**
+ * The type of the elements in a map's elements array.
+ */
+
+typedef struct avro_raw_map_entry {
+ const char *key;
+} avro_raw_map_entry_t;
+
+/**
+ * A string-indexed map of fixed-size elements.
+ */
+
+typedef struct avro_raw_map {
+ avro_raw_array_t elements;
+ void *indices_by_key;
+} avro_raw_map_t;
+
+/**
+ * Initializes a new avro_raw_map_t that you've allocated yourself.
+ */
+
+void avro_raw_map_init(avro_raw_map_t *map, size_t element_size);
+
+/**
+ * Finalizes an avro_raw_map_t.
+ */
+
+void avro_raw_map_done(avro_raw_map_t *map);
+
+/**
+ * Clears an avro_raw_map_t.
+ */
+
+void avro_raw_map_clear(avro_raw_map_t *map);
+
+/**
+ * Ensures that there is enough allocated space to store the given
+ * number of elements in an avro_raw_map_t. If we can't allocate that
+ * much space, we return ENOMEM.
+ */
+
+int
+avro_raw_map_ensure_size(avro_raw_map_t *map, size_t desired_count);
+
+/**
+ * Returns the number of elements in an avro_raw_map_t.
+ */
+
+#define avro_raw_map_size(map) avro_raw_array_size(&((map)->elements))
+
+/**
+ * Returns the avro_raw_map_entry_t for a given index.
+ */
+
+#define avro_raw_get_entry(map, index) \
+ ((avro_raw_map_entry_t *) \
+ avro_raw_array_get_raw(&(map)->elements, index))
+
+/**
+ * Returns the given element of an avro_raw_array_t as a <code>void
+ * *</code>. The indexes are assigned based on the order that the
+ * elements are added to the map.
+ */
+
+#define avro_raw_map_get_raw(map, index) \
+ (avro_raw_array_get_raw(&(map)->elements, index) + \
+ sizeof(avro_raw_map_entry_t))
+
+/**
+ * Returns the element of an avro_raw_map_t with the given numeric
+ * index. The indexes are assigned based on the order that the elements
+ * are added to the map.
+ */
+
+#define avro_raw_map_get_by_index(map, element_type, index) \
+ (*((element_type *) avro_raw_map_get_raw(map, index)))
+
+/**
+ * Returns the key of the element with the given numeric index.
+ */
+
+#define avro_raw_map_get_key(map, index) \
+ (avro_raw_get_entry(map, index)->key)
+
+/**
+ * Returns the element of an avro_raw_map_t with the given string key.
+ * If the given element doesn't exist, returns NULL. If @ref index
+ * isn't NULL, it will be filled in with the index of the element.
+ */
+
+void *avro_raw_map_get(const avro_raw_map_t *map, const char *key,
+ size_t *index);
+
+/**
+ * Retrieves the element of an avro_raw_map_t with the given string key,
+ * creating it if necessary. A pointer to the element is placed into
+ * @ref element. If @ref index isn't NULL, it will be filled in with
+ * the index of the element. We return 1 if the element is new; 0 if
+ * it's not, and a negative error code if there was some problem.
+ */
+
+int avro_raw_map_get_or_create(avro_raw_map_t *map, const char *key,
+ void **element, size_t *index);
+
+
+/*---------------------------------------------------------------------
+ * Wrapped buffers
+ */
+
+/**
+ * A pointer to an unmodifiable external memory region, along with
+ * functions for freeing that buffer when it's no longer needed, and
+ * copying it.
+ */
+
+typedef struct avro_wrapped_buffer avro_wrapped_buffer_t;
+
+struct avro_wrapped_buffer {
+ /** A pointer to the memory region */
+ const void *buf;
+
+ /** The size of the memory region */
+ size_t size;
+
+ /** Additional data needed by the methods below */
+ void *user_data;
+
+ /**
+ * A function that will be called when the memory region is no
+ * longer needed. This pointer can be NULL if nothing special
+ * needs to be done to free the buffer.
+ */
+ void
+ (*free)(avro_wrapped_buffer_t *self);
+
+ /**
+ * A function that makes a copy of a portion of a wrapped
+ * buffer. This doesn't have to involve duplicating the memory
+ * region, but it should ensure that the free method can be
+ * safely called on both copies without producing any errors or
+ * memory corruption. If this function is NULL, then we'll use
+ * a default implementation that calls @ref
+ * avro_wrapped_buffer_new_copy.
+ */
+ int
+ (*copy)(avro_wrapped_buffer_t *dest, const avro_wrapped_buffer_t *src,
+ size_t offset, size_t length);
+
+ /**
+ * A function that "slices" a wrapped buffer, causing it to
+ * point at a subset of the existing buffer. Usually, this just
+ * requires * updating the @ref buf and @ref size fields. If
+ * you don't need to do anything other than this, this function
+ * pointer can be left @c NULL. The function can assume that
+ * the @a offset and @a length parameters point to a valid
+ * subset of the existing wrapped buffer.
+ */
+ int
+ (*slice)(avro_wrapped_buffer_t *self, size_t offset, size_t length);
+};
+
+/**
+ * Free a wrapped buffer.
+ */
+
+#define avro_wrapped_buffer_free(self) \
+ do { \
+ if ((self)->free != NULL) { \
+ (self)->free((self)); \
+ } \
+ } while (0)
+
+/**
+ * A static initializer for an empty wrapped buffer.
+ */
+
+#define AVRO_WRAPPED_BUFFER_EMPTY { NULL, 0, NULL, NULL, NULL, NULL }
+
+/**
+ * Moves a wrapped buffer. After returning, @a dest will wrap the
+ * buffer that @a src used to point at, and @a src will be empty.
+ */
+
+void
+avro_wrapped_buffer_move(avro_wrapped_buffer_t *dest,
+ avro_wrapped_buffer_t *src);
+
+/**
+ * Copies a buffer.
+ */
+
+int
+avro_wrapped_buffer_copy(avro_wrapped_buffer_t *dest,
+ const avro_wrapped_buffer_t *src,
+ size_t offset, size_t length);
+
+/**
+ * Slices a buffer.
+ */
+
+int
+avro_wrapped_buffer_slice(avro_wrapped_buffer_t *self,
+ size_t offset, size_t length);
+
+/**
+ * Creates a new wrapped buffer wrapping the given memory region. You
+ * have to ensure that buf stays around for as long as you need to new
+ * wrapped buffer. If you copy the wrapped buffer (using
+ * avro_wrapped_buffer_copy), this will create a copy of the data.
+ * Additional copies will reuse this new copy.
+ */
+
+int
+avro_wrapped_buffer_new(avro_wrapped_buffer_t *dest,
+ const void *buf, size_t length);
+
+/**
+ * Creates a new wrapped buffer wrapping the given C string.
+ */
+
+#define avro_wrapped_buffer_new_string(dest, str) \
+ (avro_wrapped_buffer_new((dest), (str), strlen((str))+1))
+
+/**
+ * Creates a new wrapped buffer containing a copy of the given memory
+ * region. This new copy will be reference counted; if you copy it
+ * further (using avro_wrapped_buffer_copy), the new copies will share a
+ * single underlying buffer.
+ */
+
+int
+avro_wrapped_buffer_new_copy(avro_wrapped_buffer_t *dest,
+ const void *buf, size_t length);
+
+/**
+ * Creates a new wrapped buffer containing a copy of the given C string.
+ */
+
+#define avro_wrapped_buffer_new_string_copy(dest, str) \
+ (avro_wrapped_buffer_new_copy((dest), (str), strlen((str))+1))
+
+
+/*---------------------------------------------------------------------
+ * Strings
+ */
+
+/**
+ * A resizable buffer for storing strings and bytes values.
+ */
+
+typedef struct avro_raw_string {
+ avro_wrapped_buffer_t wrapped;
+} avro_raw_string_t;
+
+/**
+ * Initializes an avro_raw_string_t that you've allocated yourself.
+ */
+
+void avro_raw_string_init(avro_raw_string_t *str);
+
+/**
+ * Finalizes an avro_raw_string_t.
+ */
+
+void avro_raw_string_done(avro_raw_string_t *str);
+
+/**
+ * Returns the length of the data stored in an avro_raw_string_t. If
+ * the buffer contains a C string, this length includes the NUL
+ * terminator.
+ */
+
+#define avro_raw_string_length(str) ((str)->wrapped.size)
+
+/**
+ * Returns a pointer to the data stored in an avro_raw_string_t.
+ */
+
+#define avro_raw_string_get(str) ((str)->wrapped.buf)
+
+/**
+ * Fills an avro_raw_string_t with a copy of the given buffer.
+ */
+
+void avro_raw_string_set_length(avro_raw_string_t *str,
+ const void *src,
+ size_t length);
+
+/**
+ * Fills an avro_raw_string_t with a copy of the given C string.
+ */
+
+void avro_raw_string_set(avro_raw_string_t *str, const char *src);
+
+/**
+ * Appends the given C string to an avro_raw_string_t.
+ */
+
+void avro_raw_string_append(avro_raw_string_t *str, const char *src);
+
+/**
+ * Appends the given C string to an avro_raw_string_t, using the
+ * provided length instead of calling strlen(src).
+ */
+
+void avro_raw_string_append_length(avro_raw_string_t *str,
+ const void *src,
+ size_t length);
+/**
+ * Gives control of a buffer to an avro_raw_string_t.
+ */
+
+void
+avro_raw_string_give(avro_raw_string_t *str,
+ avro_wrapped_buffer_t *src);
+
+/**
+ * Returns an avro_wrapped_buffer_t for the content of the string,
+ * ideally without copying it.
+ */
+
+int
+avro_raw_string_grab(const avro_raw_string_t *str,
+ avro_wrapped_buffer_t *dest);
+
+/**
+ * Clears an avro_raw_string_t.
+ */
+
+void avro_raw_string_clear(avro_raw_string_t *str);
+
+
+/**
+ * Tests two avro_raw_string_t instances for equality.
+ */
+
+int avro_raw_string_equals(const avro_raw_string_t *str1,
+ const avro_raw_string_t *str2);
+
+
+/*---------------------------------------------------------------------
+ * Memoization
+ */
+
+/**
+ * A specialized map that can be used to memoize the results of a
+ * function. The API allows you to use two keys as the memoization
+ * keys; if you only need one key, just use NULL for the second key.
+ * The result of the function should be a single pointer, or an integer
+ * that can be cast into a pointer (i.e., an intptr_t).
+ */
+
+typedef struct avro_memoize {
+ void *cache;
+} avro_memoize_t;
+
+/**
+ * Initialize an avro_memoize_t that you've allocated for yourself.
+ */
+
+void
+avro_memoize_init(avro_memoize_t *mem);
+
+/**
+ * Finalizes an avro_memoize_t.
+ */
+
+void
+avro_memoize_done(avro_memoize_t *mem);
+
+/**
+ * Search for a cached value in an avro_memoize_t. Returns a boolean
+ * indicating whether there's a value in the cache for the given keys.
+ * If there is, the cached result is placed into @ref result.
+ */
+
+int
+avro_memoize_get(avro_memoize_t *mem,
+ void *key1, void *key2,
+ void **result);
+
+/**
+ * Stores a new cached value into an avro_memoize_t, overwriting it if
+ * necessary.
+ */
+
+void
+avro_memoize_set(avro_memoize_t *mem,
+ void *key1, void *key2,
+ void *result);
+
+/**
+ * Removes any cached value for the given key from an avro_memoize_t.
+ */
+
+void
+avro_memoize_delete(avro_memoize_t *mem, void *key1, void *key2);
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/avro/errors.h b/fluent-bit/lib/avro/src/avro/errors.h
new file mode 100644
index 000000000..c7991344b
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro/errors.h
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef AVRO_ERRORS_H
+#define AVRO_ERRORS_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+/*
+ * Returns a textual description of the last error condition returned by
+ * an Avro function.
+ */
+
+const char *avro_strerror(void);
+
+void
+avro_set_error(const char *fmt, ...);
+
+void
+avro_prefix_error(const char *fmt, ...);
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/avro/generic.h b/fluent-bit/lib/avro/src/avro/generic.h
new file mode 100644
index 000000000..5e6047fb7
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro/generic.h
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef AVRO_GENERIC_H
+#define AVRO_GENERIC_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+#include <avro/platform.h>
+#include <stdlib.h>
+
+#include <avro/schema.h>
+#include <avro/value.h>
+
+/*
+ * This file contains an avro_value_t implementation that can store
+ * values of any Avro schema. It replaces the old avro_datum_t class.
+ */
+
+
+/**
+ * Return a generic avro_value_iface_t implementation for the given
+ * schema, regardless of what type it is.
+ */
+
+avro_value_iface_t *
+avro_generic_class_from_schema(avro_schema_t schema);
+
+/**
+ * Allocate a new instance of the given generic value class. @a iface
+ * must have been created by @ref avro_generic_class_from_schema.
+ */
+
+int
+avro_generic_value_new(avro_value_iface_t *iface, avro_value_t *dest);
+
+
+/*
+ * These functions return an avro_value_iface_t implementation for each
+ * primitive schema type. (For enum, fixed, and the compound types, you
+ * must use the @ref avro_generic_class_from_schema function.)
+ */
+
+avro_value_iface_t *avro_generic_boolean_class(void);
+avro_value_iface_t *avro_generic_bytes_class(void);
+avro_value_iface_t *avro_generic_double_class(void);
+avro_value_iface_t *avro_generic_float_class(void);
+avro_value_iface_t *avro_generic_int_class(void);
+avro_value_iface_t *avro_generic_long_class(void);
+avro_value_iface_t *avro_generic_null_class(void);
+avro_value_iface_t *avro_generic_string_class(void);
+
+
+/*
+ * These functions instantiate a new generic primitive value.
+ */
+
+int avro_generic_boolean_new(avro_value_t *value, int val);
+int avro_generic_bytes_new(avro_value_t *value, void *buf, size_t size);
+int avro_generic_double_new(avro_value_t *value, double val);
+int avro_generic_float_new(avro_value_t *value, float val);
+int avro_generic_int_new(avro_value_t *value, int32_t val);
+int avro_generic_long_new(avro_value_t *value, int64_t val);
+int avro_generic_null_new(avro_value_t *value);
+int avro_generic_string_new(avro_value_t *value, const char *val);
+int avro_generic_string_new_length(avro_value_t *value, const char *val, size_t size);
+
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/avro/io.h b/fluent-bit/lib/avro/src/avro/io.h
new file mode 100644
index 000000000..ffbb68dc5
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro/io.h
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef AVRO_IO_H
+#define AVRO_IO_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+#include <avro/platform.h>
+#include <stdio.h>
+
+#include <avro/basics.h>
+#include <avro/legacy.h>
+#include <avro/schema.h>
+#include <avro/value.h>
+
+typedef struct avro_reader_t_ *avro_reader_t;
+typedef struct avro_writer_t_ *avro_writer_t;
+
+/*
+ * io
+ */
+
+avro_reader_t avro_reader_file(FILE * fp);
+avro_reader_t avro_reader_file_fp(FILE * fp, int should_close);
+avro_writer_t avro_writer_file(FILE * fp);
+avro_writer_t avro_writer_file_fp(FILE * fp, int should_close);
+avro_reader_t avro_reader_memory(const char *buf, int64_t len);
+avro_writer_t avro_writer_memory(const char *buf, int64_t len);
+
+void
+avro_reader_memory_set_source(avro_reader_t reader, const char *buf, int64_t len);
+
+void
+avro_writer_memory_set_dest(avro_writer_t writer, const char *buf, int64_t len);
+
+int avro_read(avro_reader_t reader, void *buf, int64_t len);
+int avro_skip(avro_reader_t reader, int64_t len);
+int avro_write(avro_writer_t writer, void *buf, int64_t len);
+
+void avro_reader_reset(avro_reader_t reader);
+
+void avro_writer_reset(avro_writer_t writer);
+int64_t avro_writer_tell(avro_writer_t writer);
+void avro_writer_flush(avro_writer_t writer);
+
+void avro_writer_dump(avro_writer_t writer, FILE * fp);
+void avro_reader_dump(avro_reader_t reader, FILE * fp);
+
+int avro_reader_is_eof(avro_reader_t reader);
+
+void avro_reader_free(avro_reader_t reader);
+void avro_writer_free(avro_writer_t writer);
+
+int avro_schema_to_json(const avro_schema_t schema, avro_writer_t out);
+
+/*
+ * Reads a binary-encoded Avro value from the given reader object,
+ * storing the result into dest.
+ */
+
+int
+avro_value_read(avro_reader_t reader, avro_value_t *dest);
+
+/*
+ * Writes a binary-encoded Avro value to the given writer object.
+ */
+
+int
+avro_value_write(avro_writer_t writer, avro_value_t *src);
+
+/*
+ * Returns the size of the binary encoding of the given Avro value.
+ */
+
+int
+avro_value_sizeof(avro_value_t *src, size_t *size);
+
+
+/* File object container */
+typedef struct avro_file_reader_t_ *avro_file_reader_t;
+typedef struct avro_file_writer_t_ *avro_file_writer_t;
+
+int avro_file_writer_create(const char *path, avro_schema_t schema,
+ avro_file_writer_t * writer);
+int avro_file_writer_create_fp(FILE *fp, const char *path, int should_close,
+ avro_schema_t schema, avro_file_writer_t * writer);
+int avro_file_writer_create_with_codec(const char *path,
+ avro_schema_t schema, avro_file_writer_t * writer,
+ const char *codec, size_t block_size);
+int avro_file_writer_create_with_codec_fp(FILE *fp, const char *path, int should_close,
+ avro_schema_t schema, avro_file_writer_t * writer,
+ const char *codec, size_t block_size);
+int avro_file_writer_open(const char *path, avro_file_writer_t * writer);
+int avro_file_writer_open_bs(const char *path, avro_file_writer_t * writer, size_t block_size);
+int avro_file_reader(const char *path, avro_file_reader_t * reader);
+int avro_file_reader_fp(FILE *fp, const char *path, int should_close,
+ avro_file_reader_t * reader);
+
+avro_schema_t
+avro_file_reader_get_writer_schema(avro_file_reader_t reader);
+
+int avro_file_writer_sync(avro_file_writer_t writer);
+int avro_file_writer_flush(avro_file_writer_t writer);
+int avro_file_writer_close(avro_file_writer_t writer);
+
+int avro_file_reader_close(avro_file_reader_t reader);
+
+int
+avro_file_reader_read_value(avro_file_reader_t reader, avro_value_t *dest);
+
+int
+avro_file_writer_append_value(avro_file_writer_t writer, avro_value_t *src);
+
+int
+avro_file_writer_append_encoded(avro_file_writer_t writer,
+ const void *buf, int64_t len);
+
+/*
+ * Legacy avro_datum_t API
+ */
+
+int avro_read_data(avro_reader_t reader,
+ avro_schema_t writer_schema,
+ avro_schema_t reader_schema, avro_datum_t * datum);
+int avro_skip_data(avro_reader_t reader, avro_schema_t writer_schema);
+int avro_write_data(avro_writer_t writer,
+ avro_schema_t writer_schema, avro_datum_t datum);
+int64_t avro_size_data(avro_writer_t writer,
+ avro_schema_t writer_schema, avro_datum_t datum);
+
+int avro_file_writer_append(avro_file_writer_t writer, avro_datum_t datum);
+
+int avro_file_reader_read(avro_file_reader_t reader,
+ avro_schema_t readers_schema, avro_datum_t * datum);
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/avro/legacy.h b/fluent-bit/lib/avro/src/avro/legacy.h
new file mode 100644
index 000000000..ba8f29bab
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro/legacy.h
@@ -0,0 +1,264 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef AVRO_LEGACY_H
+#define AVRO_LEGACY_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+#include <avro/platform.h>
+#include <stdio.h>
+
+#include <avro/basics.h>
+#include <avro/data.h>
+#include <avro/schema.h>
+#include <avro/value.h>
+
+/*
+ * This file defines the deprecated interface for handling Avro values.
+ * It's here solely for backwards compatibility. New code should use
+ * the avro_value_t interface (defined in avro/value.h). The
+ * avro_datum_t type has been replaced by the “generic” implementation
+ * of the value interface, which is defined in avro/generic.h. You can
+ * also use your own application-specific types as Avro values by
+ * defining your own avro_value_t implementation for them.
+ */
+
+/**
+ * A function used to free a bytes, string, or fixed buffer once it is
+ * no longer needed by the datum that wraps it.
+ */
+
+typedef void
+(*avro_free_func_t)(void *ptr, size_t sz);
+
+/**
+ * An avro_free_func_t that frees the buffer using the custom allocator
+ * provided to avro_set_allocator.
+ */
+
+void
+avro_alloc_free_func(void *ptr, size_t sz);
+
+/*
+ * Datum constructors. Each datum stores a reference to the schema that
+ * the datum is an instance of. The primitive datum constructors don't
+ * need to take in an explicit avro_schema_t parameter, since there's
+ * only one schema that they could be an instance of. The complex
+ * constructors do need an explicit schema parameter.
+ */
+
+typedef struct avro_obj_t *avro_datum_t;
+avro_datum_t avro_string(const char *str);
+avro_datum_t avro_givestring(const char *str,
+ avro_free_func_t free);
+avro_datum_t avro_bytes(const char *buf, int64_t len);
+avro_datum_t avro_givebytes(const char *buf, int64_t len,
+ avro_free_func_t free);
+avro_datum_t avro_int32(int32_t i);
+avro_datum_t avro_int64(int64_t l);
+avro_datum_t avro_float(float f);
+avro_datum_t avro_double(double d);
+avro_datum_t avro_boolean(int8_t i);
+avro_datum_t avro_null(void);
+avro_datum_t avro_record(avro_schema_t schema);
+avro_datum_t avro_enum(avro_schema_t schema, int i);
+avro_datum_t avro_fixed(avro_schema_t schema,
+ const char *bytes, const int64_t size);
+avro_datum_t avro_givefixed(avro_schema_t schema,
+ const char *bytes, const int64_t size,
+ avro_free_func_t free);
+avro_datum_t avro_map(avro_schema_t schema);
+avro_datum_t avro_array(avro_schema_t schema);
+avro_datum_t avro_union(avro_schema_t schema,
+ int64_t discriminant, const avro_datum_t datum);
+
+/**
+ * Returns the schema that the datum is an instance of.
+ */
+
+avro_schema_t avro_datum_get_schema(const avro_datum_t datum);
+
+/*
+ * Constructs a new avro_datum_t instance that's appropriate for holding
+ * values of the given schema.
+ */
+
+avro_datum_t avro_datum_from_schema(const avro_schema_t schema);
+
+/* getters */
+int avro_string_get(avro_datum_t datum, char **p);
+int avro_bytes_get(avro_datum_t datum, char **bytes, int64_t * size);
+int avro_int32_get(avro_datum_t datum, int32_t * i);
+int avro_int64_get(avro_datum_t datum, int64_t * l);
+int avro_float_get(avro_datum_t datum, float *f);
+int avro_double_get(avro_datum_t datum, double *d);
+int avro_boolean_get(avro_datum_t datum, int8_t * i);
+
+int avro_enum_get(const avro_datum_t datum);
+const char *avro_enum_get_name(const avro_datum_t datum);
+int avro_fixed_get(avro_datum_t datum, char **bytes, int64_t * size);
+int avro_record_get(const avro_datum_t record, const char *field_name,
+ avro_datum_t * value);
+
+/*
+ * A helper macro that extracts the value of the given field of a
+ * record.
+ */
+
+#define avro_record_get_field_value(rc, rec, typ, fname, ...) \
+ do { \
+ avro_datum_t field = NULL; \
+ (rc) = avro_record_get((rec), (fname), &field); \
+ if (rc) break; \
+ (rc) = avro_##typ##_get(field, __VA_ARGS__); \
+ } while (0)
+
+
+int avro_map_get(const avro_datum_t datum, const char *key,
+ avro_datum_t * value);
+/*
+ * For maps, the "index" for each entry is based on the order that they
+ * were added to the map.
+ */
+int avro_map_get_key(const avro_datum_t datum, int index,
+ const char **key);
+int avro_map_get_index(const avro_datum_t datum, const char *key,
+ int *index);
+size_t avro_map_size(const avro_datum_t datum);
+int avro_array_get(const avro_datum_t datum, int64_t index, avro_datum_t * value);
+size_t avro_array_size(const avro_datum_t datum);
+
+/*
+ * These accessors allow you to query the current branch of a union
+ * value, returning either the branch's discriminant value or the
+ * avro_datum_t of the branch. A union value can be uninitialized, in
+ * which case the discriminant will be -1 and the datum NULL.
+ */
+
+int64_t avro_union_discriminant(const avro_datum_t datum);
+avro_datum_t avro_union_current_branch(avro_datum_t datum);
+
+/* setters */
+int avro_string_set(avro_datum_t datum, const char *p);
+int avro_givestring_set(avro_datum_t datum, const char *p,
+ avro_free_func_t free);
+
+int avro_bytes_set(avro_datum_t datum, const char *bytes, const int64_t size);
+int avro_givebytes_set(avro_datum_t datum, const char *bytes,
+ const int64_t size,
+ avro_free_func_t free);
+
+int avro_int32_set(avro_datum_t datum, const int32_t i);
+int avro_int64_set(avro_datum_t datum, const int64_t l);
+int avro_float_set(avro_datum_t datum, const float f);
+int avro_double_set(avro_datum_t datum, const double d);
+int avro_boolean_set(avro_datum_t datum, const int8_t i);
+
+int avro_enum_set(avro_datum_t datum, const int symbol_value);
+int avro_enum_set_name(avro_datum_t datum, const char *symbol_name);
+int avro_fixed_set(avro_datum_t datum, const char *bytes, const int64_t size);
+int avro_givefixed_set(avro_datum_t datum, const char *bytes,
+ const int64_t size,
+ avro_free_func_t free);
+
+int avro_record_set(avro_datum_t record, const char *field_name,
+ avro_datum_t value);
+
+/*
+ * A helper macro that sets the value of the given field of a record.
+ */
+
+#define avro_record_set_field_value(rc, rec, typ, fname, ...) \
+ do { \
+ avro_datum_t field = NULL; \
+ (rc) = avro_record_get((rec), (fname), &field); \
+ if (rc) break; \
+ (rc) = avro_##typ##_set(field, __VA_ARGS__); \
+ } while (0)
+
+int avro_map_set(avro_datum_t map, const char *key,
+ avro_datum_t value);
+int avro_array_append_datum(avro_datum_t array_datum,
+ avro_datum_t datum);
+
+/*
+ * This function selects the active branch of a union value, and can be
+ * safely called on an existing union to change the current branch. If
+ * the branch changes, we'll automatically construct a new avro_datum_t
+ * for the new branch's schema type. If the desired branch is already
+ * the active branch of the union, we'll leave the existing datum
+ * instance as-is. The branch datum will be placed into the "branch"
+ * parameter, regardless of whether we have to create a new datum
+ * instance or not.
+ */
+
+int avro_union_set_discriminant(avro_datum_t unionp,
+ int discriminant,
+ avro_datum_t *branch);
+
+/**
+ * Resets a datum instance. For arrays and maps, this frees all
+ * elements and clears the container. For records and unions, this
+ * recursively resets any child datum instances.
+ */
+
+int
+avro_datum_reset(avro_datum_t value);
+
+/* reference counting */
+avro_datum_t avro_datum_incref(avro_datum_t value);
+void avro_datum_decref(avro_datum_t value);
+
+void avro_datum_print(avro_datum_t value, FILE * fp);
+
+int avro_datum_equal(avro_datum_t a, avro_datum_t b);
+
+/*
+ * Returns a string containing the JSON encoding of an Avro value. You
+ * must free this string when you're done with it, using the standard
+ * free() function. (*Not* using the custom Avro allocator.)
+ */
+
+int avro_datum_to_json(const avro_datum_t datum,
+ int one_line, char **json_str);
+
+
+int avro_schema_datum_validate(avro_schema_t
+ expected_schema, avro_datum_t datum);
+
+/*
+ * An avro_value_t implementation for avro_datum_t objects.
+ */
+
+avro_value_iface_t *
+avro_datum_class(void);
+
+/*
+ * Creates a new avro_value_t instance for the given datum.
+ */
+
+int
+avro_datum_as_value(avro_value_t *value, avro_datum_t src);
+
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/avro/msinttypes.h b/fluent-bit/lib/avro/src/avro/msinttypes.h
new file mode 100644
index 000000000..29be14b95
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro/msinttypes.h
@@ -0,0 +1,315 @@
+// ISO C9x compliant inttypes.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_INTTYPES_H_ // [
+#define _MSC_INTTYPES_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+//////////////////////////////////////
+// Start AVRO specific modifications
+//////////////////////////////////////
+#include "msstdint.h"
+
+// Modification for AVRO of inttypes.h
+#define __STDC_FORMAT_MACROS (1)
+
+//////////////////////////////////////
+// End AVRO specific modifications
+//////////////////////////////////////
+
+// 7.8 Format conversion of integer types
+
+typedef struct {
+ intmax_t quot;
+ intmax_t rem;
+} imaxdiv_t;
+
+// 7.8.1 Macros for format specifiers
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
+
+// The fprintf macros for signed integers are:
+#define PRId8 "d"
+#define PRIi8 "i"
+#define PRIdLEAST8 "d"
+#define PRIiLEAST8 "i"
+#define PRIdFAST8 "d"
+#define PRIiFAST8 "i"
+
+#define PRId16 "hd"
+#define PRIi16 "hi"
+#define PRIdLEAST16 "hd"
+#define PRIiLEAST16 "hi"
+#define PRIdFAST16 "hd"
+#define PRIiFAST16 "hi"
+
+#define PRId32 "I32d"
+#define PRIi32 "I32i"
+#define PRIdLEAST32 "I32d"
+#define PRIiLEAST32 "I32i"
+#define PRIdFAST32 "I32d"
+#define PRIiFAST32 "I32i"
+
+#define PRId64 "I64d"
+#define PRIi64 "I64i"
+#define PRIdLEAST64 "I64d"
+#define PRIiLEAST64 "I64i"
+#define PRIdFAST64 "I64d"
+#define PRIiFAST64 "I64i"
+
+#define PRIdMAX "I64d"
+#define PRIiMAX "I64i"
+
+#define PRIdPTR "Id"
+#define PRIiPTR "Ii"
+
+// The fprintf macros for unsigned integers are:
+#define PRIo8 "o"
+#define PRIu8 "u"
+#define PRIx8 "x"
+#define PRIX8 "X"
+#define PRIoLEAST8 "o"
+#define PRIuLEAST8 "u"
+#define PRIxLEAST8 "x"
+#define PRIXLEAST8 "X"
+#define PRIoFAST8 "o"
+#define PRIuFAST8 "u"
+#define PRIxFAST8 "x"
+#define PRIXFAST8 "X"
+
+#define PRIo16 "ho"
+#define PRIu16 "hu"
+#define PRIx16 "hx"
+#define PRIX16 "hX"
+#define PRIoLEAST16 "ho"
+#define PRIuLEAST16 "hu"
+#define PRIxLEAST16 "hx"
+#define PRIXLEAST16 "hX"
+#define PRIoFAST16 "ho"
+#define PRIuFAST16 "hu"
+#define PRIxFAST16 "hx"
+#define PRIXFAST16 "hX"
+
+#define PRIo32 "I32o"
+#define PRIu32 "I32u"
+#define PRIx32 "I32x"
+#define PRIX32 "I32X"
+#define PRIoLEAST32 "I32o"
+#define PRIuLEAST32 "I32u"
+#define PRIxLEAST32 "I32x"
+#define PRIXLEAST32 "I32X"
+#define PRIoFAST32 "I32o"
+#define PRIuFAST32 "I32u"
+#define PRIxFAST32 "I32x"
+#define PRIXFAST32 "I32X"
+
+#define PRIo64 "I64o"
+#define PRIu64 "I64u"
+#define PRIx64 "I64x"
+#define PRIX64 "I64X"
+#define PRIoLEAST64 "I64o"
+#define PRIuLEAST64 "I64u"
+#define PRIxLEAST64 "I64x"
+#define PRIXLEAST64 "I64X"
+#define PRIoFAST64 "I64o"
+#define PRIuFAST64 "I64u"
+#define PRIxFAST64 "I64x"
+#define PRIXFAST64 "I64X"
+
+#define PRIoMAX "I64o"
+#define PRIuMAX "I64u"
+#define PRIxMAX "I64x"
+#define PRIXMAX "I64X"
+
+#define PRIoPTR "Io"
+#define PRIuPTR "Iu"
+#define PRIxPTR "Ix"
+#define PRIXPTR "IX"
+
+// The fscanf macros for signed integers are:
+#define SCNd8 "d"
+#define SCNi8 "i"
+#define SCNdLEAST8 "d"
+#define SCNiLEAST8 "i"
+#define SCNdFAST8 "d"
+#define SCNiFAST8 "i"
+
+#define SCNd16 "hd"
+#define SCNi16 "hi"
+#define SCNdLEAST16 "hd"
+#define SCNiLEAST16 "hi"
+#define SCNdFAST16 "hd"
+#define SCNiFAST16 "hi"
+
+#define SCNd32 "ld"
+#define SCNi32 "li"
+#define SCNdLEAST32 "ld"
+#define SCNiLEAST32 "li"
+#define SCNdFAST32 "ld"
+#define SCNiFAST32 "li"
+
+#define SCNd64 "I64d"
+#define SCNi64 "I64i"
+#define SCNdLEAST64 "I64d"
+#define SCNiLEAST64 "I64i"
+#define SCNdFAST64 "I64d"
+#define SCNiFAST64 "I64i"
+
+#define SCNdMAX "I64d"
+#define SCNiMAX "I64i"
+
+#ifdef _WIN64 // [
+# define SCNdPTR "I64d"
+# define SCNiPTR "I64i"
+#else // _WIN64 ][
+# define SCNdPTR "ld"
+# define SCNiPTR "li"
+#endif // _WIN64 ]
+
+// The fscanf macros for unsigned integers are:
+#define SCNo8 "o"
+#define SCNu8 "u"
+#define SCNx8 "x"
+#define SCNX8 "X"
+#define SCNoLEAST8 "o"
+#define SCNuLEAST8 "u"
+#define SCNxLEAST8 "x"
+#define SCNXLEAST8 "X"
+#define SCNoFAST8 "o"
+#define SCNuFAST8 "u"
+#define SCNxFAST8 "x"
+#define SCNXFAST8 "X"
+
+#define SCNo16 "ho"
+#define SCNu16 "hu"
+#define SCNx16 "hx"
+#define SCNX16 "hX"
+#define SCNoLEAST16 "ho"
+#define SCNuLEAST16 "hu"
+#define SCNxLEAST16 "hx"
+#define SCNXLEAST16 "hX"
+#define SCNoFAST16 "ho"
+#define SCNuFAST16 "hu"
+#define SCNxFAST16 "hx"
+#define SCNXFAST16 "hX"
+
+#define SCNo32 "lo"
+#define SCNu32 "lu"
+#define SCNx32 "lx"
+#define SCNX32 "lX"
+#define SCNoLEAST32 "lo"
+#define SCNuLEAST32 "lu"
+#define SCNxLEAST32 "lx"
+#define SCNXLEAST32 "lX"
+#define SCNoFAST32 "lo"
+#define SCNuFAST32 "lu"
+#define SCNxFAST32 "lx"
+#define SCNXFAST32 "lX"
+
+#define SCNo64 "I64o"
+#define SCNu64 "I64u"
+#define SCNx64 "I64x"
+#define SCNX64 "I64X"
+#define SCNoLEAST64 "I64o"
+#define SCNuLEAST64 "I64u"
+#define SCNxLEAST64 "I64x"
+#define SCNXLEAST64 "I64X"
+#define SCNoFAST64 "I64o"
+#define SCNuFAST64 "I64u"
+#define SCNxFAST64 "I64x"
+#define SCNXFAST64 "I64X"
+
+#define SCNoMAX "I64o"
+#define SCNuMAX "I64u"
+#define SCNxMAX "I64x"
+#define SCNXMAX "I64X"
+
+#ifdef _WIN64 // [
+# define SCNoPTR "I64o"
+# define SCNuPTR "I64u"
+# define SCNxPTR "I64x"
+# define SCNXPTR "I64X"
+#else // _WIN64 ][
+# define SCNoPTR "lo"
+# define SCNuPTR "lu"
+# define SCNxPTR "lx"
+# define SCNXPTR "lX"
+#endif // _WIN64 ]
+
+#endif // __STDC_FORMAT_MACROS ]
+
+// 7.8.2 Functions for greatest-width integer types
+
+// 7.8.2.1 The imaxabs function
+#define imaxabs _abs64
+
+// 7.8.2.2 The imaxdiv function
+
+// This is modified version of div() function from Microsoft's div.c found
+// in %MSVC.NET%\crt\src\div.c
+#ifdef STATIC_IMAXDIV // [
+static
+#else // STATIC_IMAXDIV ][
+_inline
+#endif // STATIC_IMAXDIV ]
+imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
+{
+ imaxdiv_t result;
+
+ result.quot = numer / denom;
+ result.rem = numer % denom;
+
+ if (numer < 0 && result.rem > 0) {
+ // did division wrong; must fix up
+ ++result.quot;
+ result.rem -= denom;
+ }
+
+ return result;
+}
+
+// 7.8.2.3 The strtoimax and strtoumax functions
+#define strtoimax _strtoi64
+#define strtoumax _strtoui64
+
+// 7.8.2.4 The wcstoimax and wcstoumax functions
+#define wcstoimax _wcstoi64
+#define wcstoumax _wcstoui64
+
+
+#endif // _MSC_INTTYPES_H_ ]
diff --git a/fluent-bit/lib/avro/src/avro/msstdint.h b/fluent-bit/lib/avro/src/avro/msstdint.h
new file mode 100644
index 000000000..d02608a59
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro/msstdint.h
@@ -0,0 +1,247 @@
+// ISO C9x compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2008 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler give many errors like this:
+// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#ifdef __cplusplus
+extern "C" {
+#endif
+# include <wchar.h>
+#ifdef __cplusplus
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+# define _W64 __w64
+# else
+# define _W64
+# endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+ typedef signed char int8_t;
+ typedef signed short int16_t;
+ typedef signed int int32_t;
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+#else
+ typedef signed __int8 int8_t;
+ typedef signed __int16 int16_t;
+ typedef signed __int32 int32_t;
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int32 uint32_t;
+#endif
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+ typedef signed __int64 intptr_t;
+ typedef unsigned __int64 uintptr_t;
+#else // _WIN64 ][
+ typedef _W64 signed int intptr_t;
+ typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN ((int8_t)_I8_MIN)
+#define INT8_MAX _I8_MAX
+#define INT16_MIN ((int16_t)_I16_MIN)
+#define INT16_MAX _I16_MAX
+#define INT32_MIN ((int32_t)_I32_MIN)
+#define INT32_MAX _I32_MAX
+#define INT64_MIN ((int64_t)_I64_MIN)
+#define INT64_MAX _I64_MAX
+#define UINT8_MAX _UI8_MAX
+#define UINT16_MAX _UI16_MAX
+#define UINT32_MAX _UI32_MAX
+#define UINT64_MAX _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+# define INTPTR_MIN INT64_MIN
+# define INTPTR_MAX INT64_MAX
+# define UINTPTR_MAX UINT64_MAX
+#else // _WIN64 ][
+# define INTPTR_MIN INT32_MIN
+# define INTPTR_MAX INT32_MAX
+# define UINTPTR_MAX UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+# define PTRDIFF_MIN _I64_MIN
+# define PTRDIFF_MAX _I64_MAX
+#else // _WIN64 ][
+# define PTRDIFF_MIN _I32_MIN
+# define PTRDIFF_MAX _I32_MAX
+#endif // _WIN64 ]
+
+#define SIG_ATOMIC_MIN INT_MIN
+#define SIG_ATOMIC_MAX INT_MAX
+
+#ifndef SIZE_MAX // [
+# ifdef _WIN64 // [
+# define SIZE_MAX _UI64_MAX
+# else // _WIN64 ][
+# define SIZE_MAX _UI32_MAX
+# endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+# define WCHAR_MIN 0
+#endif // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+# define WCHAR_MAX _UI16_MAX
+#endif // WCHAR_MAX ]
+
+#define WINT_MIN 0
+#define WINT_MAX _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+#define INTMAX_C INT64_C
+#define UINTMAX_C UINT64_C
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/fluent-bit/lib/avro/src/avro/platform.h b/fluent-bit/lib/avro/src/avro/platform.h
new file mode 100644
index 000000000..929305505
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro/platform.h
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef AVRO_PLATFORM_H
+#define AVRO_PLATFORM_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+/* Use this header file to include platform specific definitions */
+
+#ifdef _WIN32
+ #include <avro/msinttypes.h>
+#else
+ #include <inttypes.h>
+#endif
+
+// Defines for printing size_t.
+#if defined(_WIN64)
+ #define PRIsz PRIu64
+#elif defined(_WIN32)
+ #define PRIsz PRIu32
+#else // GCC
+ #define PRIsz "zu"
+#endif
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/avro/refcount.h b/fluent-bit/lib/avro/src/avro/refcount.h
new file mode 100644
index 000000000..27369900a
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro/refcount.h
@@ -0,0 +1,306 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef AVRO_REFCOUNT_H
+#define AVRO_REFCOUNT_H
+
+#if defined(_WIN32) && defined(__cplusplus)
+/* Include the C++ file <intrin.h> outside the scope of extern "C" */
+#include <intrin.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+/**
+ * Atomically sets the value of a reference count.
+ */
+
+static inline void
+avro_refcount_set(volatile int *refcount, int value);
+
+/**
+ * Increments a reference count, ensuring that its value doesn't
+ * overflow.
+ */
+
+static inline void
+avro_refcount_inc(volatile int *refcount);
+
+/**
+ * Decrements a reference count, and returns whether the resulting
+ * (decremented) value is 0.
+ */
+
+static inline int
+avro_refcount_dec(volatile int *refcount);
+
+
+/*-----------------------------------------------------------------------
+ * Non-Atomic Reference Count
+ */
+#if defined(AVRO_NON_ATOMIC_REFCOUNT)
+static inline void
+avro_refcount_set(volatile int *refcount, int value)
+{
+ *refcount = value;
+}
+
+static inline void
+avro_refcount_inc(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ *refcount += 1;
+ }
+}
+
+static inline int
+avro_refcount_dec(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ *refcount -= 1;
+ return (*refcount == 0);
+ }
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Mac OS X
+ */
+
+#elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
+
+#include <libkern/OSAtomic.h>
+
+static inline void
+avro_refcount_set(volatile int *refcount, int value)
+{
+ *refcount = value;
+}
+
+static inline void
+avro_refcount_inc(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ OSAtomicIncrement32(refcount);
+ }
+}
+
+static inline int
+avro_refcount_dec(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ return (OSAtomicDecrement32(refcount) == 0);
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * GCC intrinsics
+ */
+
+#elif (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40500 \
+|| defined(__clang__)
+
+static inline void
+avro_refcount_set(volatile int *refcount, int value)
+{
+ *refcount = value;
+}
+
+static inline void
+avro_refcount_inc(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ __sync_add_and_fetch(refcount, 1);
+ }
+}
+
+static inline int
+avro_refcount_dec(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ return (__sync_sub_and_fetch(refcount, 1) == 0);
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * Raw x86 assembly
+ */
+
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+
+/* determine the size of int */
+
+#include <limits.h>
+#include <avro/platform.h>
+#if INT_MAX == INT32_MAX
+#define REFCOUNT_SS "l"
+#elif INT_MAX == INT64_MAX
+#define REFCOUNT_SS "q"
+#else
+#error "Unknown int size"
+#endif
+
+static inline void
+avro_refcount_set(volatile int *refcount, int value)
+{
+ *refcount = value;
+}
+
+static inline void
+avro_refcount_inc(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ __asm__ __volatile__ ("lock ; inc"REFCOUNT_SS" %0"
+ :"=m" (*refcount)
+ :"m" (*refcount));
+ }
+}
+
+static inline int
+avro_refcount_dec(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ char result;
+ __asm__ __volatile__ ("lock ; dec"REFCOUNT_SS" %0; setz %1"
+ :"=m" (*refcount), "=q" (result)
+ :"m" (*refcount));
+ return result;
+ }
+ return 0;
+}
+
+#undef REFCOUNT_SS
+
+
+/*-----------------------------------------------------------------------
+ * Raw PPC assembly
+ */
+
+#elif defined(__GNUC__) && defined(__ppc__)
+
+static inline int
+avro_refcount_LL_int(volatile int *ptr)
+{
+ int val;
+ __asm__ __volatile__ ("lwarx %[val],0,%[ptr]"
+ : [val] "=r" (val)
+ : [ptr] "r" (&ptr)
+ : "cc");
+
+ return val;
+}
+
+/* Returns non-zero if the store was successful, zero otherwise. */
+static inline int
+avro_refcount_SC_int(volatile int *ptr, int val)
+{
+ int ret = 1; /* init to non-zero, will be reset to 0 if SC was successful */
+ __asm__ __volatile__ ("stwcx. %[val],0,%[ptr];\n"
+ "beq 1f;\n"
+ "li %[ret], 0;\n"
+ "1: ;\n"
+ : [ret] "=r" (ret)
+ : [ptr] "r" (&ptr), [val] "r" (val), "0" (ret)
+ : "cc", "memory");
+ return ret;
+}
+
+static inline void
+avro_refcount_set(volatile int *refcount, int value)
+{
+ *refcount = value;
+}
+
+static inline void
+avro_refcount_inc(volatile int *refcount)
+{
+ int prev;
+ do {
+ prev = avro_refcount_LL_int(refcount);
+ if (prev == (int) -1) {
+ return;
+ }
+ } while (!avro_refcount_SC_int(refcount, prev + 1));
+}
+
+static inline int
+avro_refcount_dec(volatile int *refcount)
+{
+ int prev;
+ do {
+ prev = avro_refcount_LL_int(refcount);
+ if (prev == (int) -1) {
+ return 0;
+ }
+ } while (!avro_refcount_SC_int(refcount, prev - 1));
+ return prev == 1;
+}
+
+
+/*-----------------------------------------------------------------------
+ * Windows intrinsics
+ */
+#elif defined(_WIN32)
+
+#ifdef __cplusplus
+// Note: <intrin.h> included outside the extern "C" wrappers above
+#else
+#include <windows.h>
+#include <intrin.h>
+#endif // __cplusplus
+
+static inline void
+avro_refcount_set(volatile int *refcount, int value)
+{
+ *refcount = value;
+}
+
+static inline void
+avro_refcount_inc(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ _InterlockedIncrement((volatile long *) refcount);
+ }
+}
+
+static inline int
+avro_refcount_dec(volatile int *refcount)
+{
+ if (*refcount != (int) -1) {
+ return (_InterlockedDecrement((volatile long *) refcount) == 0);
+ }
+ return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Fallback
+ */
+#else
+#error "No atomic implementation!"
+#endif
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/avro/resolver.h b/fluent-bit/lib/avro/src/avro/resolver.h
new file mode 100644
index 000000000..472e0f95d
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro/resolver.h
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef AVRO_RESOLVER_H
+#define AVRO_RESOLVER_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+#include <avro/schema.h>
+#include <avro/value.h>
+
+/*
+ * A <i>resolved value</i> is a special kind of value that knows how to
+ * implement Avro's schema resolution rules to translate between a
+ * writer schema and a reader schema. A resolved value doesn't store or
+ * process data itself; instead, it wraps an existing value instance.
+ *
+ * There are two resolved value classes. In the first (@ref
+ * avro_resolved_writer_t), the resolved value is an instance of the
+ * writer schema, and wraps an instance of the reader schema. This is
+ * used, for instance, when reading from an Avro data file; you want the
+ * end result to be a reader schema value, and the resolved value allows
+ * the file reader to ignore the schema resolution and simply fill in
+ * the values of the writer schema. You can only set the values of a
+ * resolved writer; you must use the original wrapped value to read.
+ *
+ * With other class (@ref avro_resolved_reader_t), the resolved value is
+ * an instance of the reader schema, and wraps an instance of the writer
+ * schema. This is used when resolving an existing Avro value to
+ * another schema; you've already got the value in the original (writer)
+ * schema, and want to transparently treat it as if it were an instance
+ * of the new (reader) schema. You can only read the values of a
+ * resolved reader; you must use the original wrapped value to write.
+ *
+ * For both classes, the “self” pointer of the resolved value is an
+ * avro_value_t pointer, which points at the wrapped value.
+ */
+
+
+/**
+ * Create a new resolved writer implementation for the given writer and
+ * reader schemas.
+ */
+
+avro_value_iface_t *
+avro_resolved_writer_new(avro_schema_t writer_schema,
+ avro_schema_t reader_schema);
+
+/**
+ * Creates a new resolved writer value.
+ */
+
+int
+avro_resolved_writer_new_value(avro_value_iface_t *iface,
+ avro_value_t *value);
+
+/**
+ * Sets the wrapped value for a resolved writer. This must be an
+ * instance of the reader schema. We create our own reference to the
+ * destination value.
+ */
+
+void
+avro_resolved_writer_set_dest(avro_value_t *resolved,
+ avro_value_t *dest);
+
+
+/**
+ * Clears the wrapped value for a resolved writer.
+ */
+
+void
+avro_resolved_writer_clear_dest(avro_value_t *resolved);
+
+
+/**
+ * Create a new resolved reader implementation for the given writer and
+ * reader schemas.
+ */
+
+avro_value_iface_t *
+avro_resolved_reader_new(avro_schema_t writer_schema,
+ avro_schema_t reader_schema);
+
+/**
+ * Creates a new resolved reader value.
+ */
+
+int
+avro_resolved_reader_new_value(avro_value_iface_t *iface,
+ avro_value_t *value);
+
+/**
+ * Sets the wrapped value for a resolved reader. This must be an
+ * instance of the reader schema. We create our own reference to the
+ * source value.
+ */
+
+void
+avro_resolved_reader_set_source(avro_value_t *resolved,
+ avro_value_t *dest);
+
+
+/**
+ * Clears the wrapped value for a resolved reader.
+ */
+
+void
+avro_resolved_reader_clear_source(avro_value_t *resolved);
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/avro/schema.h b/fluent-bit/lib/avro/src/avro/schema.h
new file mode 100644
index 000000000..51d456155
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro/schema.h
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef AVRO_SCHEMA_H
+#define AVRO_SCHEMA_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+#include <avro/platform.h>
+#include <stdlib.h>
+
+#include <avro/basics.h>
+
+typedef struct avro_obj_t *avro_schema_t;
+
+avro_schema_t avro_schema_string(void);
+avro_schema_t avro_schema_bytes(void);
+avro_schema_t avro_schema_int(void);
+avro_schema_t avro_schema_long(void);
+avro_schema_t avro_schema_float(void);
+avro_schema_t avro_schema_double(void);
+avro_schema_t avro_schema_boolean(void);
+avro_schema_t avro_schema_null(void);
+
+avro_schema_t avro_schema_record(const char *name, const char *space);
+avro_schema_t avro_schema_record_field_get(const avro_schema_t
+ record, const char *field_name);
+const char *avro_schema_record_field_name(const avro_schema_t schema, int index);
+int avro_schema_record_field_get_index(const avro_schema_t schema,
+ const char *field_name);
+avro_schema_t avro_schema_record_field_get_by_index
+(const avro_schema_t record, int index);
+int avro_schema_record_field_append(const avro_schema_t record,
+ const char *field_name,
+ const avro_schema_t type);
+size_t avro_schema_record_size(const avro_schema_t record);
+
+avro_schema_t avro_schema_enum(const char *name);
+avro_schema_t avro_schema_enum_ns(const char *name, const char *space);
+const char *avro_schema_enum_get(const avro_schema_t enump,
+ int index);
+int avro_schema_enum_get_by_name(const avro_schema_t enump,
+ const char *symbol_name);
+int avro_schema_enum_symbol_append(const avro_schema_t
+ enump, const char *symbol);
+int avro_schema_enum_number_of_symbols(const avro_schema_t enump);
+
+avro_schema_t avro_schema_fixed(const char *name, const int64_t len);
+avro_schema_t avro_schema_fixed_ns(const char *name, const char *space,
+ const int64_t len);
+int64_t avro_schema_fixed_size(const avro_schema_t fixed);
+
+avro_schema_t avro_schema_map(const avro_schema_t values);
+avro_schema_t avro_schema_map_values(avro_schema_t map);
+
+avro_schema_t avro_schema_array(const avro_schema_t items);
+avro_schema_t avro_schema_array_items(avro_schema_t array);
+
+avro_schema_t avro_schema_union(void);
+size_t avro_schema_union_size(const avro_schema_t union_schema);
+int avro_schema_union_append(const avro_schema_t
+ union_schema, const avro_schema_t schema);
+avro_schema_t avro_schema_union_branch(avro_schema_t union_schema,
+ int branch_index);
+avro_schema_t avro_schema_union_branch_by_name
+(avro_schema_t union_schema, int *branch_index, const char *name);
+
+avro_schema_t avro_schema_link(avro_schema_t schema);
+avro_schema_t avro_schema_link_target(avro_schema_t schema);
+
+typedef struct avro_schema_error_t_ *avro_schema_error_t;
+
+int avro_schema_from_json(const char *jsontext, int32_t unused1,
+ avro_schema_t *schema, avro_schema_error_t *unused2);
+
+/* jsontext does not need to be NUL terminated. length must *NOT*
+ * include the NUL terminator, if one is present. */
+int avro_schema_from_json_length(const char *jsontext, size_t length,
+ avro_schema_t *schema);
+
+/* A helper macro for loading a schema from a string literal. The
+ * literal must be declared as a char[], not a char *, since we use the
+ * sizeof operator to determine its length. */
+#define avro_schema_from_json_literal(json, schema) \
+ (avro_schema_from_json_length((json), sizeof((json))-1, (schema)))
+
+int avro_schema_to_specific(avro_schema_t schema, const char *prefix);
+
+avro_schema_t avro_schema_get_subschema(const avro_schema_t schema,
+ const char *name);
+const char *avro_schema_name(const avro_schema_t schema);
+const char *avro_schema_namespace(const avro_schema_t schema);
+const char *avro_schema_type_name(const avro_schema_t schema);
+avro_schema_t avro_schema_copy(avro_schema_t schema);
+int avro_schema_equal(avro_schema_t a, avro_schema_t b);
+
+avro_schema_t avro_schema_incref(avro_schema_t schema);
+int avro_schema_decref(avro_schema_t schema);
+
+int avro_schema_match(avro_schema_t writers_schema,
+ avro_schema_t readers_schema);
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/avro/value.h b/fluent-bit/lib/avro/src/avro/value.h
new file mode 100644
index 000000000..c5619e7bf
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro/value.h
@@ -0,0 +1,498 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef AVRO_VALUE_H
+#define AVRO_VALUE_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+#include <errno.h>
+#include <avro/platform.h>
+#include <stdlib.h>
+
+#include <avro/data.h>
+#include <avro/schema.h>
+
+/*
+ * This file defines an interface struct for Avro data. Most of the
+ * interesting parts of this library will work with Avro data values
+ * that are expressed in whatever C type you want, as long as you can
+ * provide an implementation of this interface for that type.
+ */
+
+typedef struct avro_value_iface avro_value_iface_t;
+
+typedef struct avro_value {
+ avro_value_iface_t *iface;
+ void *self;
+} avro_value_t;
+
+struct avro_value_iface {
+ /*-------------------------------------------------------------
+ * "class" methods
+ */
+
+ /**
+ * Increment the reference count of the interface struct. This
+ * should be a no-op for static structs, since they don't need
+ * reference counts.
+ */
+ avro_value_iface_t *
+ (*incref_iface)(avro_value_iface_t *iface);
+
+ /**
+ * Decrement the reference count of the interface struct. If
+ * the count falls to 0, free the struct. This should be a
+ * no-op for static structs, since they don't need reference
+ * counts.
+ */
+ void
+ (*decref_iface)(avro_value_iface_t *iface);
+
+ /*-------------------------------------------------------------
+ * General "instance" methods
+ */
+
+ /**
+ * Increments the reference count of a value.
+ */
+
+ void
+ (*incref)(avro_value_t *value);
+
+ /**
+ * Decrements the reference count of a value, and frees the
+ * value if the reference count drops to 0. After calling this
+ * method, your value instance is undefined, and cannot be used
+ * anymore.
+ */
+
+ void
+ (*decref)(avro_value_t *value);
+
+ /**
+ * Reset the instance to its "empty", default value. You don't
+ * have to free the underlying storage, if you want to keep it
+ * around for later values.
+ */
+ int
+ (*reset)(const avro_value_iface_t *iface, void *self);
+
+ /**
+ * Return the general Avro type of a value instance.
+ */
+ avro_type_t
+ (*get_type)(const avro_value_iface_t *iface, const void *self);
+
+ /**
+ * Return the Avro schema that a value is an instance of.
+ */
+ avro_schema_t
+ (*get_schema)(const avro_value_iface_t *iface, const void *self);
+
+ /*-------------------------------------------------------------
+ * Primitive value getters
+ */
+ int (*get_boolean)(const avro_value_iface_t *iface,
+ const void *self, int *out);
+ int (*get_bytes)(const avro_value_iface_t *iface,
+ const void *self, const void **buf, size_t *size);
+ int (*grab_bytes)(const avro_value_iface_t *iface,
+ const void *self, avro_wrapped_buffer_t *dest);
+ int (*get_double)(const avro_value_iface_t *iface,
+ const void *self, double *out);
+ int (*get_float)(const avro_value_iface_t *iface,
+ const void *self, float *out);
+ int (*get_int)(const avro_value_iface_t *iface,
+ const void *self, int32_t *out);
+ int (*get_long)(const avro_value_iface_t *iface,
+ const void *self, int64_t *out);
+ int (*get_null)(const avro_value_iface_t *iface,
+ const void *self);
+ /* The result will be NUL-terminated; the size will INCLUDE the
+ * NUL terminator. str will never be NULL unless there's an
+ * error. */
+ int (*get_string)(const avro_value_iface_t *iface,
+ const void *self, const char **str, size_t *size);
+ int (*grab_string)(const avro_value_iface_t *iface,
+ const void *self, avro_wrapped_buffer_t *dest);
+
+ int (*get_enum)(const avro_value_iface_t *iface,
+ const void *self, int *out);
+ int (*get_fixed)(const avro_value_iface_t *iface,
+ const void *self, const void **buf, size_t *size);
+ int (*grab_fixed)(const avro_value_iface_t *iface,
+ const void *self, avro_wrapped_buffer_t *dest);
+
+ /*-------------------------------------------------------------
+ * Primitive value setters
+ */
+
+ /*
+ * The "give" setters can be used to give control of an existing
+ * buffer to a bytes, fixed, or string value. The free function
+ * will be called when the buffer is no longer needed. (It's
+ * okay for free to be NULL; that just means that nothing
+ * special needs to be done to free the buffer. That's useful
+ * for a static string, for instance.)
+ *
+ * If your class can't take control of an existing buffer, then
+ * your give functions should pass the buffer into the
+ * corresponding "set" method and then immediately free the
+ * buffer.
+ *
+ * Note that for strings, the free function will be called with
+ * a size that *includes* the NUL terminator, even though you
+ * provide a size that does *not*.
+ */
+
+ int (*set_boolean)(const avro_value_iface_t *iface,
+ void *self, int val);
+ int (*set_bytes)(const avro_value_iface_t *iface,
+ void *self, void *buf, size_t size);
+ int (*give_bytes)(const avro_value_iface_t *iface,
+ void *self, avro_wrapped_buffer_t *buf);
+ int (*set_double)(const avro_value_iface_t *iface,
+ void *self, double val);
+ int (*set_float)(const avro_value_iface_t *iface,
+ void *self, float val);
+ int (*set_int)(const avro_value_iface_t *iface,
+ void *self, int32_t val);
+ int (*set_long)(const avro_value_iface_t *iface,
+ void *self, int64_t val);
+ int (*set_null)(const avro_value_iface_t *iface, void *self);
+ /* The input must be NUL-terminated */
+ int (*set_string)(const avro_value_iface_t *iface,
+ void *self, const char *str);
+ /* and size must INCLUDE the NUL terminator */
+ int (*set_string_len)(const avro_value_iface_t *iface,
+ void *self, const char *str, size_t size);
+ int (*give_string_len)(const avro_value_iface_t *iface,
+ void *self, avro_wrapped_buffer_t *buf);
+
+ int (*set_enum)(const avro_value_iface_t *iface,
+ void *self, int val);
+ int (*set_fixed)(const avro_value_iface_t *iface,
+ void *self, void *buf, size_t size);
+ int (*give_fixed)(const avro_value_iface_t *iface,
+ void *self, avro_wrapped_buffer_t *buf);
+
+ /*-------------------------------------------------------------
+ * Compound value getters
+ */
+
+ /* Number of elements in array/map, or the number of fields in a
+ * record. */
+ int (*get_size)(const avro_value_iface_t *iface,
+ const void *self, size_t *size);
+
+ /*
+ * For arrays and maps, returns the element with the given
+ * index. (For maps, the "index" is based on the order that the
+ * keys were added to the map.) For records, returns the field
+ * with that index in the schema.
+ *
+ * For maps and records, the name parameter (if given) will be
+ * filled in with the key or field name of the returned value.
+ * For arrays, the name parameter will always be ignored.
+ */
+ int (*get_by_index)(const avro_value_iface_t *iface,
+ const void *self, size_t index,
+ avro_value_t *child, const char **name);
+
+ /*
+ * For maps, returns the element with the given key. For
+ * records, returns the element with the given field name. If
+ * index is given, it will be filled in with the numeric index
+ * of the returned value.
+ */
+ int (*get_by_name)(const avro_value_iface_t *iface,
+ const void *self, const char *name,
+ avro_value_t *child, size_t *index);
+
+ /* Discriminant of current union value */
+ int (*get_discriminant)(const avro_value_iface_t *iface,
+ const void *self, int *out);
+ /* Current union value */
+ int (*get_current_branch)(const avro_value_iface_t *iface,
+ const void *self, avro_value_t *branch);
+
+ /*-------------------------------------------------------------
+ * Compound value setters
+ */
+
+ /*
+ * For all of these, the value class should know which class to
+ * use for its children.
+ */
+
+ /* Creates a new array element. */
+ int (*append)(const avro_value_iface_t *iface,
+ void *self, avro_value_t *child_out, size_t *new_index);
+
+ /* Creates a new map element, or returns an existing one. */
+ int (*add)(const avro_value_iface_t *iface,
+ void *self, const char *key,
+ avro_value_t *child, size_t *index, int *is_new);
+
+ /* Select a union branch. */
+ int (*set_branch)(const avro_value_iface_t *iface,
+ void *self, int discriminant,
+ avro_value_t *branch);
+};
+
+
+/**
+ * Increments the reference count of a value instance. Normally you
+ * don't need to call this directly; you'll have a reference whenever
+ * you create the value, and @ref avro_value_copy and @ref
+ * avro_value_move update the reference counts correctly for you.
+ */
+
+void
+avro_value_incref(avro_value_t *value);
+
+/**
+ * Decremenets the reference count of a value instance, freeing it if
+ * its reference count drops to 0.
+ */
+
+void
+avro_value_decref(avro_value_t *value);
+
+/**
+ * Copies a reference to a value. This does not copy any of the data
+ * in the value; you get two avro_value_t references that point at the
+ * same underlying value instance.
+ */
+
+void
+avro_value_copy_ref(avro_value_t *dest, const avro_value_t *src);
+
+/**
+ * Moves a reference to a value. This does not copy any of the data in
+ * the value. The @ref src value is invalidated by this function; its
+ * equivalent to the following:
+ *
+ * <code>
+ * avro_value_copy_ref(dest, src);
+ * avro_value_decref(src);
+ * </code>
+ */
+
+void
+avro_value_move_ref(avro_value_t *dest, avro_value_t *src);
+
+/**
+ * Compares two values for equality. The two values don't need to have
+ * the same implementation of the value interface, but they do need to
+ * represent Avro values of the same schema. This function ensures that
+ * the schemas match; if you want to skip this check, use
+ * avro_value_equal_fast.
+ */
+
+int
+avro_value_equal(avro_value_t *val1, avro_value_t *val2);
+
+/**
+ * Compares two values for equality. The two values don't need to have
+ * the same implementation of the value interface, but they do need to
+ * represent Avro values of the same schema. This function assumes that
+ * the schemas match; if you can't guarantee this, you should use
+ * avro_value_equal, which compares the schemas before comparing the
+ * values.
+ */
+
+int
+avro_value_equal_fast(avro_value_t *val1, avro_value_t *val2);
+
+/**
+ * Compares two values using the sort order defined in the Avro
+ * specification. The two values don't need to have the same
+ * implementation of the value interface, but they do need to represent
+ * Avro values of the same schema. This function ensures that the
+ * schemas match; if you want to skip this check, use
+ * avro_value_cmp_fast.
+ */
+
+int
+avro_value_cmp(avro_value_t *val1, avro_value_t *val2);
+
+/**
+ * Compares two values using the sort order defined in the Avro
+ * specification. The two values don't need to have the same
+ * implementation of the value interface, but they do need to represent
+ * Avro values of the same schema. This function assumes that the
+ * schemas match; if you can't guarantee this, you should use
+ * avro_value_cmp, which compares the schemas before comparing the
+ * values.
+ */
+
+int
+avro_value_cmp_fast(avro_value_t *val1, avro_value_t *val2);
+
+
+
+/**
+ * Copies the contents of src into dest. The two values don't need to
+ * have the same implementation of the value interface, but they do need
+ * to represent Avro values of the same schema. This function ensures
+ * that the schemas match; if you want to skip this check, use
+ * avro_value_copy_fast.
+ */
+
+int
+avro_value_copy(avro_value_t *dest, const avro_value_t *src);
+
+/**
+ * Copies the contents of src into dest. The two values don't need to
+ * have the same implementation of the value interface, but they do need
+ * to represent Avro values of the same schema. This function assumes
+ * that the schemas match; if you can't guarantee this, you should use
+ * avro_value_copy, which compares the schemas before comparing the
+ * values.
+ */
+
+int
+avro_value_copy_fast(avro_value_t *dest, const avro_value_t *src);
+
+/**
+ * Returns a hash value for a given Avro value.
+ */
+
+uint32_t
+avro_value_hash(avro_value_t *value);
+
+/*
+ * Returns a string containing the JSON encoding of an Avro value. You
+ * must free this string when you're done with it, using the standard
+ * free() function. (*Not* using the custom Avro allocator.)
+ */
+
+int
+avro_value_to_json(const avro_value_t *value,
+ int one_line, char **json_str);
+
+
+/**
+ * A helper macro for calling a given method in a value instance, if
+ * it's present. If the value's class doesn't implement the given
+ * method, we return dflt. You usually won't call this directly; it's
+ * just here to implement the macros below.
+ */
+
+#define avro_value_call0(value, method, dflt) \
+ ((value)->iface->method == NULL? (dflt): \
+ (value)->iface->method((value)->iface, (value)->self))
+
+#define avro_value_call(value, method, dflt, ...) \
+ ((value)->iface->method == NULL? (dflt): \
+ (value)->iface->method((value)->iface, (value)->self, __VA_ARGS__))
+
+
+#define avro_value_iface_incref(cls) \
+ ((cls)->incref_iface == NULL? (cls): (cls)->incref_iface((cls)))
+#define avro_value_iface_decref(cls) \
+ ((cls)->decref_iface == NULL? (void) 0: (cls)->decref_iface((cls)))
+
+#define avro_value_reset(value) \
+ avro_value_call0(value, reset, EINVAL)
+#define avro_value_get_type(value) \
+ avro_value_call0(value, get_type, (avro_type_t) -1)
+#define avro_value_get_schema(value) \
+ avro_value_call0(value, get_schema, NULL)
+
+#define avro_value_get_boolean(value, out) \
+ avro_value_call(value, get_boolean, EINVAL, out)
+#define avro_value_get_bytes(value, buf, size) \
+ avro_value_call(value, get_bytes, EINVAL, buf, size)
+#define avro_value_grab_bytes(value, dest) \
+ avro_value_call(value, grab_bytes, EINVAL, dest)
+#define avro_value_get_double(value, out) \
+ avro_value_call(value, get_double, EINVAL, out)
+#define avro_value_get_float(value, out) \
+ avro_value_call(value, get_float, EINVAL, out)
+#define avro_value_get_int(value, out) \
+ avro_value_call(value, get_int, EINVAL, out)
+#define avro_value_get_long(value, out) \
+ avro_value_call(value, get_long, EINVAL, out)
+#define avro_value_get_null(value) \
+ avro_value_call0(value, get_null, EINVAL)
+#define avro_value_get_string(value, str, size) \
+ avro_value_call(value, get_string, EINVAL, str, size)
+#define avro_value_grab_string(value, dest) \
+ avro_value_call(value, grab_string, EINVAL, dest)
+#define avro_value_get_enum(value, out) \
+ avro_value_call(value, get_enum, EINVAL, out)
+#define avro_value_get_fixed(value, buf, size) \
+ avro_value_call(value, get_fixed, EINVAL, buf, size)
+#define avro_value_grab_fixed(value, dest) \
+ avro_value_call(value, grab_fixed, EINVAL, dest)
+
+#define avro_value_set_boolean(value, val) \
+ avro_value_call(value, set_boolean, EINVAL, val)
+#define avro_value_set_bytes(value, buf, size) \
+ avro_value_call(value, set_bytes, EINVAL, buf, size)
+#define avro_value_give_bytes(value, buf) \
+ avro_value_call(value, give_bytes, EINVAL, buf)
+#define avro_value_set_double(value, val) \
+ avro_value_call(value, set_double, EINVAL, val)
+#define avro_value_set_float(value, val) \
+ avro_value_call(value, set_float, EINVAL, val)
+#define avro_value_set_int(value, val) \
+ avro_value_call(value, set_int, EINVAL, val)
+#define avro_value_set_long(value, val) \
+ avro_value_call(value, set_long, EINVAL, val)
+#define avro_value_set_null(value) \
+ avro_value_call0(value, set_null, EINVAL)
+#define avro_value_set_string(value, str) \
+ avro_value_call(value, set_string, EINVAL, str)
+#define avro_value_set_string_len(value, str, size) \
+ avro_value_call(value, set_string_len, EINVAL, str, size)
+#define avro_value_give_string_len(value, buf) \
+ avro_value_call(value, give_string_len, EINVAL, buf)
+#define avro_value_set_enum(value, val) \
+ avro_value_call(value, set_enum, EINVAL, val)
+#define avro_value_set_fixed(value, buf, size) \
+ avro_value_call(value, set_fixed, EINVAL, buf, size)
+#define avro_value_give_fixed(value, buf) \
+ avro_value_call(value, give_fixed, EINVAL, buf)
+
+#define avro_value_get_size(value, size) \
+ avro_value_call(value, get_size, EINVAL, size)
+#define avro_value_get_by_index(value, idx, child, name) \
+ avro_value_call(value, get_by_index, EINVAL, idx, child, name)
+#define avro_value_get_by_name(value, name, child, index) \
+ avro_value_call(value, get_by_name, EINVAL, name, child, index)
+#define avro_value_get_discriminant(value, out) \
+ avro_value_call(value, get_discriminant, EINVAL, out)
+#define avro_value_get_current_branch(value, branch) \
+ avro_value_call(value, get_current_branch, EINVAL, branch)
+
+#define avro_value_append(value, child, new_index) \
+ avro_value_call(value, append, EINVAL, child, new_index)
+#define avro_value_add(value, key, child, index, is_new) \
+ avro_value_call(value, add, EINVAL, key, child, index, is_new)
+#define avro_value_set_branch(value, discriminant, branch) \
+ avro_value_call(value, set_branch, EINVAL, discriminant, branch)
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/avro_generic_internal.h b/fluent-bit/lib/avro/src/avro_generic_internal.h
new file mode 100644
index 000000000..9843ed652
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro_generic_internal.h
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef AVRO_GENERIC_INTERNAL_H
+#define AVRO_GENERIC_INTERNAL_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+#include <sys/types.h>
+
+#include "avro/generic.h"
+#include "avro/schema.h"
+#include "avro/value.h"
+
+/*
+ * Each generic value implementation struct defines a couple of extra
+ * methods that we use to control the lifecycle of the value objects.
+ */
+
+typedef struct avro_generic_value_iface {
+ avro_value_iface_t parent;
+
+ /**
+ * Return the size of an instance of this value type. If this
+ * returns 0, then this value type can't be used with any
+ * function or type (like avro_value_new) that expects to
+ * allocate space for the value itself.
+ */
+ size_t
+ (*instance_size)(const avro_value_iface_t *iface);
+
+ /**
+ * Initialize a new value instance.
+ */
+ int
+ (*init)(const avro_value_iface_t *iface, void *self);
+
+ /**
+ * Finalize a value instance.
+ */
+ void
+ (*done)(const avro_value_iface_t *iface, void *self);
+} avro_generic_value_iface_t;
+
+
+#define avro_value_instance_size(gcls) \
+ ((gcls)->instance_size == NULL ? (ssize_t)-1 : (ssize_t)(gcls)->instance_size(&(gcls)->parent))
+#define avro_value_init(gcls, self) \
+ ((gcls)->init == NULL? EINVAL: (gcls)->init(&(gcls)->parent, (self)))
+#define avro_value_done(gcls, self) \
+ ((gcls)->done == NULL? (void) 0: (gcls)->done(&(gcls)->parent, (self)))
+
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/avro_private.h b/fluent-bit/lib/avro/src/avro_private.h
new file mode 100644
index 000000000..f97ef6b5a
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avro_private.h
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+#ifndef AVRO_PRIVATE_H
+#define AVRO_PRIVATE_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+#include <errno.h>
+
+#include "avro/errors.h"
+#include "avro/platform.h"
+
+#ifdef HAVE_CONFIG_H
+/* This is only true for now in the autotools build */
+#include "config.h"
+#endif
+
+#ifdef _WIN32
+#define snprintf _snprintf
+#endif
+
+/* Note that AVRO_PLATFORM_IS_BIG_ENDIAN is *always* defined. It is
+ * either TRUE (1) or FALSE (0).
+ */
+#ifdef _WIN32
+ #define AVRO_PLATFORM_IS_BIG_ENDIAN (0)
+#else // UNIX
+ #include <sys/param.h>
+ #if BYTE_ORDER == BIG_ENDIAN
+ #define AVRO_PLATFORM_IS_BIG_ENDIAN (1)
+ #else
+ #define AVRO_PLATFORM_IS_BIG_ENDIAN (0)
+ #endif
+#endif
+
+/* Add definition of EILSEQ if it is not defined in errno.h. */
+#include <errno.h>
+#ifndef EILSEQ
+#define EILSEQ 138
+#endif
+
+
+#define check(rval, call) { rval = call; if(rval) return rval; }
+
+#define check_set(rval, call, ...) \
+ { \
+ rval = call; \
+ if (rval) { \
+ avro_set_error(__VA_ARGS__); \
+ return rval; \
+ } \
+ }
+
+#define check_prefix(rval, call, ...) \
+ { \
+ rval = call; \
+ if (rval) { \
+ avro_prefix_error(__VA_ARGS__); \
+ return rval; \
+ } \
+ }
+
+#define check_param(result, test, name) \
+ { \
+ if (!(test)) { \
+ avro_set_error("Invalid " name " in %s", \
+ __FUNCTION__); \
+ return result; \
+ } \
+ }
+
+#define AVRO_UNUSED(var) (void)var;
+
+#define container_of(ptr_, type_, member_) \
+ ((type_ *)((char *)ptr_ - (size_t)&((type_ *)0)->member_))
+
+#define nullstrcmp(s1, s2) \
+ (((s1) && (s2)) ? strcmp(s1, s2) : ((s1) || (s2)))
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/avroappend.c b/fluent-bit/lib/avro/src/avroappend.c
new file mode 100644
index 000000000..7243c6009
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avroappend.c
@@ -0,0 +1,169 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef _WIN32
+#include <unistd.h>
+#endif
+
+#include "avro.h"
+
+int process_file(const char *in_filename, const char *out_filename)
+{
+ avro_file_reader_t reader;
+ avro_file_writer_t writer;
+
+ if (in_filename == NULL) {
+ if (avro_file_reader_fp(stdin, "<stdin>", 0, &reader)) {
+ fprintf(stderr, "Error opening <stdin>:\n %s\n",
+ avro_strerror());
+ return 1;
+ }
+ } else {
+ if (avro_file_reader(in_filename, &reader)) {
+ fprintf(stderr, "Error opening %s:\n %s\n",
+ in_filename, avro_strerror());
+ return 1;
+ }
+ }
+
+ avro_schema_t wschema;
+ wschema = avro_file_reader_get_writer_schema(reader);
+
+ /* Check that the reader schema is the same as the writer schema */
+ {
+ avro_schema_t oschema;
+ avro_file_reader_t oreader;
+
+ if (avro_file_reader(out_filename, &oreader)) {
+ fprintf(stderr, "Error opening %s:\n %s\n",
+ out_filename, avro_strerror());
+ avro_file_reader_close(reader);
+ return 1;
+ }
+
+ oschema = avro_file_reader_get_writer_schema(oreader);
+
+ if (avro_schema_equal(oschema, wschema) == 0) {
+ fprintf(stderr, "Error: reader and writer schema are not equal.\n");
+ avro_file_reader_close(oreader);
+ avro_file_reader_close(reader);
+ return 1;
+ }
+
+ avro_file_reader_close(oreader);
+ avro_schema_decref(oschema);
+ }
+
+ if (avro_file_writer_open(out_filename, &writer)) {
+ fprintf(stderr, "Error opening %s:\n %s\n",
+ out_filename, avro_strerror());
+ avro_file_reader_close(reader);
+ return 1;
+ }
+
+ avro_value_iface_t *iface;
+ avro_value_t value;
+
+ iface = avro_generic_class_from_schema(wschema);
+ avro_generic_value_new(iface, &value);
+
+ while (avro_file_reader_read_value(reader, &value) == 0) {
+ if (avro_file_writer_append_value(writer, &value)) {
+ fprintf(stderr, "Error writing to %s:\n %s\n",
+ out_filename, avro_strerror());
+ return 1;
+ }
+ avro_value_reset(&value);
+ }
+
+ avro_file_reader_close(reader);
+ avro_file_writer_close(writer);
+ avro_value_decref(&value);
+ avro_value_iface_decref(iface);
+ avro_schema_decref(wschema);
+
+ return 0;
+}
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "Usage: avroappend [<input avro file>] <output avro file>\n");
+}
+
+static int check_filenames(const char *in_filename, const char *out_filename)
+{
+ if (in_filename == NULL) {
+ return 0;
+ }
+
+ struct stat in_stat;
+ struct stat out_stat;
+
+ if (stat(in_filename, &in_stat) == -1) {
+ fprintf(stderr, "stat error on %s: %s\n", in_filename, strerror(errno));
+ return 2;
+ }
+
+ if (stat(out_filename, &out_stat) == -1) {
+ fprintf(stderr, "stat error on %s: %s\n", out_filename, strerror(errno));
+ return 2;
+ }
+
+ if (in_stat.st_dev == out_stat.st_dev && in_stat.st_ino == out_stat.st_ino) {
+ return 1;
+ }
+
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ char *in_filename;
+ char *out_filename;
+
+ argc--;
+ argv++;
+
+ if (argc == 2) {
+ in_filename = argv[0];
+ out_filename = argv[1];
+ } else if (argc == 1) {
+ in_filename = NULL;
+ out_filename = argv[0];
+ } else {
+ fprintf(stderr, "Not enough arguments\n\n");
+ usage();
+ exit(1);
+ }
+
+ int ret = check_filenames(in_filename, out_filename);
+
+ if (ret == 1) {
+ fprintf(stderr, "Files are the same.\n");
+ }
+
+ if (ret > 0) {
+ exit(1);
+ }
+
+ exit(process_file(in_filename, out_filename));
+}
diff --git a/fluent-bit/lib/avro/src/avrocat.c b/fluent-bit/lib/avro/src/avrocat.c
new file mode 100644
index 000000000..134ea8e64
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avrocat.c
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro.h"
+#include "avro_private.h"
+
+
+/*-- PROCESSING A FILE --*/
+
+static void
+process_file(const char *filename)
+{
+ avro_file_reader_t reader;
+ FILE *fp;
+ int should_close;
+
+ if (filename == NULL) {
+ fp = stdin;
+ filename = "<stdin>";
+ should_close = 0;
+ } else {
+ fp = fopen(filename, "rb");
+ should_close = 1;
+
+ if (fp == NULL) {
+ fprintf(stderr, "Error opening %s:\n %s\n",
+ filename, strerror(errno));
+ exit(1);
+ }
+ }
+
+ if (avro_file_reader_fp(fp, filename, 0, &reader)) {
+ fprintf(stderr, "Error opening %s:\n %s\n",
+ filename, avro_strerror());
+ if (should_close) {
+ fclose(fp);
+ }
+ exit(1);
+ }
+
+ avro_schema_t wschema;
+ avro_value_iface_t *iface;
+ avro_value_t value;
+
+ wschema = avro_file_reader_get_writer_schema(reader);
+ iface = avro_generic_class_from_schema(wschema);
+ avro_generic_value_new(iface, &value);
+
+ int rval;
+
+ while ((rval = avro_file_reader_read_value(reader, &value)) == 0) {
+ char *json;
+
+ if (avro_value_to_json(&value, 1, &json)) {
+ fprintf(stderr, "Error converting value to JSON: %s\n",
+ avro_strerror());
+ } else {
+ printf("%s\n", json);
+ free(json);
+ }
+
+ avro_value_reset(&value);
+ }
+
+ // If it was not an EOF that caused it to fail,
+ // print the error.
+ if (rval != EOF) {
+ fprintf(stderr, "Error: %s\n", avro_strerror());
+ }
+
+ avro_file_reader_close(reader);
+ avro_value_decref(&value);
+ avro_value_iface_decref(iface);
+ avro_schema_decref(wschema);
+
+ if (should_close) {
+ fclose(fp);
+ }
+}
+
+
+/*-- MAIN PROGRAM --*/
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "Usage: avrocat <avro data file>\n");
+}
+
+
+int main(int argc, char **argv)
+{
+ char *data_filename;
+
+ if (argc == 2) {
+ data_filename = argv[1];
+ } else if (argc == 1) {
+ data_filename = NULL;
+ } else {
+ fprintf(stderr, "Can't read from multiple input files.\n");
+ usage();
+ exit(1);
+ }
+
+ /* Process the data file */
+ process_file(data_filename);
+ return 0;
+}
diff --git a/fluent-bit/lib/avro/src/avromod.c b/fluent-bit/lib/avro/src/avromod.c
new file mode 100644
index 000000000..7415d6e2f
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avromod.c
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro.h"
+#include "avro_private.h"
+
+
+/* The compression codec to use. */
+static const char *codec = "null";
+
+/* The block size to use. */
+static size_t block_size = 0;
+
+/*-- PROCESSING A FILE --*/
+
+static void
+process_file(const char *in_filename, const char *out_filename)
+{
+ avro_file_reader_t reader;
+ avro_file_writer_t writer;
+
+ if (in_filename == NULL) {
+ if (avro_file_reader_fp(stdin, "<stdin>", 0, &reader)) {
+ fprintf(stderr, "Error opening <stdin>:\n %s\n",
+ avro_strerror());
+ exit(1);
+ }
+ } else {
+ if (avro_file_reader(in_filename, &reader)) {
+ fprintf(stderr, "Error opening %s:\n %s\n",
+ in_filename, avro_strerror());
+ exit(1);
+ }
+ }
+
+ avro_schema_t wschema;
+ avro_value_iface_t *iface;
+ avro_value_t value;
+ int rval;
+
+ wschema = avro_file_reader_get_writer_schema(reader);
+ iface = avro_generic_class_from_schema(wschema);
+ avro_generic_value_new(iface, &value);
+
+ if (avro_file_writer_create_with_codec
+ (out_filename, wschema, &writer, codec, block_size)) {
+ fprintf(stderr, "Error creating %s:\n %s\n",
+ out_filename, avro_strerror());
+ exit(1);
+ }
+
+ while ((rval = avro_file_reader_read_value(reader, &value)) == 0) {
+ if (avro_file_writer_append_value(writer, &value)) {
+ fprintf(stderr, "Error writing to %s:\n %s\n",
+ out_filename, avro_strerror());
+ exit(1);
+ }
+ avro_value_reset(&value);
+ }
+
+ if (rval != EOF) {
+ fprintf(stderr, "Error reading value: %s", avro_strerror());
+ }
+
+ avro_file_reader_close(reader);
+ avro_file_writer_close(writer);
+ avro_value_decref(&value);
+ avro_value_iface_decref(iface);
+ avro_schema_decref(wschema);
+}
+
+
+/*-- MAIN PROGRAM --*/
+
+static struct option longopts[] = {
+ { "block-size", required_argument, NULL, 'b' },
+ { "codec", required_argument, NULL, 'c' },
+ { NULL, 0, NULL, 0 }
+};
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "Usage: avromod [--codec=<compression codec>]\n"
+ " [--block-size=<block size>]\n"
+ " [<input avro file>]\n"
+ " <output avro file>\n");
+}
+
+static void
+parse_block_size(const char *optarg)
+{
+ unsigned long ul;
+ char *end;
+
+ ul = strtoul(optarg, &end, 10);
+ if ((ul == 0 && end == optarg) ||
+ (ul == ULONG_MAX && errno == ERANGE)) {
+ fprintf(stderr, "Invalid block size: %s\n\n", optarg);
+ usage();
+ exit(1);
+ }
+ block_size = ul;
+}
+
+
+int main(int argc, char **argv)
+{
+ char *in_filename;
+ char *out_filename;
+
+ int ch;
+ while ((ch = getopt_long(argc, argv, "b:c:", longopts, NULL)) != -1) {
+ switch (ch) {
+ case 'b':
+ parse_block_size(optarg);
+ break;
+
+ case 'c':
+ codec = optarg;
+ break;
+
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 2) {
+ in_filename = argv[0];
+ out_filename = argv[1];
+ } else if (argc == 1) {
+ in_filename = NULL;
+ out_filename = argv[0];
+ } else {
+ fprintf(stderr, "Can't read from multiple input files.\n");
+ usage();
+ exit(1);
+ }
+
+ /* Process the data file */
+ process_file(in_filename, out_filename);
+ return 0;
+}
diff --git a/fluent-bit/lib/avro/src/avropipe.c b/fluent-bit/lib/avro/src/avropipe.c
new file mode 100644
index 000000000..7bda12534
--- /dev/null
+++ b/fluent-bit/lib/avro/src/avropipe.c
@@ -0,0 +1,432 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <getopt.h>
+#include <avro/platform.h>
+#include <avro/platform.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro.h"
+#include "avro_private.h"
+
+
+/* The path separator to use in the JSON output. */
+
+static const char *separator = "/";
+
+
+/*-- PROCESSING A FILE --*/
+
+/**
+ * Fills in a raw string with the path to an element of an array.
+ */
+
+static void
+create_array_prefix(avro_raw_string_t *dest, const char *prefix, size_t index)
+{
+ static char buf[100];
+ snprintf(buf, sizeof(buf), "%" PRIsz, index);
+ avro_raw_string_set(dest, prefix);
+ avro_raw_string_append(dest, separator);
+ avro_raw_string_append(dest, buf);
+}
+
+static void
+create_object_prefix(avro_raw_string_t *dest, const char *prefix, const char *key)
+{
+ /*
+ * Make sure that the key doesn't contain the separator
+ * character.
+ */
+
+ if (strstr(key, separator) != NULL) {
+ fprintf(stderr,
+ "Error: Element \"%s\" in object %s "
+ "contains the separator character.\n"
+ "Please use the --separator option to choose another.\n",
+ key, prefix);
+ exit(1);
+ }
+
+ avro_raw_string_set(dest, prefix);
+ avro_raw_string_append(dest, separator);
+ avro_raw_string_append(dest, key);
+}
+
+static void
+print_bytes_value(const char *buf, size_t size)
+{
+ size_t i;
+ printf("\"");
+ for (i = 0; i < size; i++)
+ {
+ if (buf[i] == '"') {
+ printf("\\\"");
+ } else if (buf[i] == '\\') {
+ printf("\\\\");
+ } else if (buf[i] == '\b') {
+ printf("\\b");
+ } else if (buf[i] == '\f') {
+ printf("\\f");
+ } else if (buf[i] == '\n') {
+ printf("\\n");
+ } else if (buf[i] == '\r') {
+ printf("\\r");
+ } else if (buf[i] == '\t') {
+ printf("\\t");
+ } else if (isprint(buf[i])) {
+ printf("%c", (int) buf[i]);
+ } else {
+ printf("\\u00%02x", (unsigned int) (unsigned char) buf[i]);
+ }
+ }
+ printf("\"");
+}
+
+static void
+process_value(const char *prefix, avro_value_t *value);
+
+static void
+process_array(const char *prefix, avro_value_t *value)
+{
+ printf("%s\t[]\n", prefix);
+ size_t element_count;
+ avro_value_get_size(value, &element_count);
+
+ avro_raw_string_t element_prefix;
+ avro_raw_string_init(&element_prefix);
+
+ size_t i;
+ for (i = 0; i < element_count; i++) {
+ avro_value_t element_value;
+ avro_value_get_by_index(value, i, &element_value, NULL);
+
+ create_array_prefix(&element_prefix, prefix, i);
+ process_value((const char *) avro_raw_string_get(&element_prefix), &element_value);
+ }
+
+ avro_raw_string_done(&element_prefix);
+}
+
+static void
+process_enum(const char *prefix, avro_value_t *value)
+{
+ int val;
+ const char *symbol_name;
+
+ avro_schema_t schema = avro_value_get_schema(value);
+ avro_value_get_enum(value, &val);
+ symbol_name = avro_schema_enum_get(schema, val);
+ printf("%s\t", prefix);
+ print_bytes_value(symbol_name, strlen(symbol_name));
+ printf("\n");
+}
+
+static void
+process_map(const char *prefix, avro_value_t *value)
+{
+ printf("%s\t{}\n", prefix);
+ size_t element_count;
+ avro_value_get_size(value, &element_count);
+
+ avro_raw_string_t element_prefix;
+ avro_raw_string_init(&element_prefix);
+
+ size_t i;
+ for (i = 0; i < element_count; i++) {
+ const char *key;
+ avro_value_t element_value;
+ avro_value_get_by_index(value, i, &element_value, &key);
+
+ create_object_prefix(&element_prefix, prefix, key);
+ process_value((const char *) avro_raw_string_get(&element_prefix), &element_value);
+ }
+
+ avro_raw_string_done(&element_prefix);
+}
+
+static void
+process_record(const char *prefix, avro_value_t *value)
+{
+ printf("%s\t{}\n", prefix);
+ size_t field_count;
+ avro_value_get_size(value, &field_count);
+
+ avro_raw_string_t field_prefix;
+ avro_raw_string_init(&field_prefix);
+
+ size_t i;
+ for (i = 0; i < field_count; i++) {
+ avro_value_t field_value;
+ const char *field_name;
+ avro_value_get_by_index(value, i, &field_value, &field_name);
+
+ create_object_prefix(&field_prefix, prefix, field_name);
+ process_value((const char *) avro_raw_string_get(&field_prefix), &field_value);
+ }
+
+ avro_raw_string_done(&field_prefix);
+}
+
+static void
+process_union(const char *prefix, avro_value_t *value)
+{
+ avro_value_t branch_value;
+ avro_value_get_current_branch(value, &branch_value);
+
+ /* nulls in a union aren't wrapped in a JSON object */
+ if (avro_value_get_type(&branch_value) == AVRO_NULL) {
+ printf("%s\tnull\n", prefix);
+ return;
+ }
+
+ int discriminant;
+ avro_value_get_discriminant(value, &discriminant);
+
+ avro_schema_t schema = avro_value_get_schema(value);
+ avro_schema_t branch_schema = avro_schema_union_branch(schema, discriminant);
+ const char *branch_name = avro_schema_type_name(branch_schema);
+
+ avro_raw_string_t branch_prefix;
+ avro_raw_string_init(&branch_prefix);
+ create_object_prefix(&branch_prefix, prefix, branch_name);
+
+ printf("%s\t{}\n", prefix);
+ process_value((const char *) avro_raw_string_get(&branch_prefix), &branch_value);
+
+ avro_raw_string_done(&branch_prefix);
+}
+
+static void
+process_value(const char *prefix, avro_value_t *value)
+{
+ avro_type_t type = avro_value_get_type(value);
+ switch (type) {
+ case AVRO_BOOLEAN:
+ {
+ int val;
+ avro_value_get_boolean(value, &val);
+ printf("%s\t%s\n", prefix, val? "true": "false");
+ return;
+ }
+
+ case AVRO_BYTES:
+ {
+ const void *buf;
+ size_t size;
+ avro_value_get_bytes(value, &buf, &size);
+ printf("%s\t", prefix);
+ print_bytes_value((const char *) buf, size);
+ printf("\n");
+ return;
+ }
+
+ case AVRO_DOUBLE:
+ {
+ double val;
+ avro_value_get_double(value, &val);
+ printf("%s\t%lf\n", prefix, val);
+ return;
+ }
+
+ case AVRO_FLOAT:
+ {
+ float val;
+ avro_value_get_float(value, &val);
+ printf("%s\t%f\n", prefix, val);
+ return;
+ }
+
+ case AVRO_INT32:
+ {
+ int32_t val;
+ avro_value_get_int(value, &val);
+ printf("%s\t%" PRId32 "\n", prefix, val);
+ return;
+ }
+
+ case AVRO_INT64:
+ {
+ int64_t val;
+ avro_value_get_long(value, &val);
+ printf("%s\t%" PRId64 "\n", prefix, val);
+ return;
+ }
+
+ case AVRO_NULL:
+ {
+ avro_value_get_null(value);
+ printf("%s\tnull\n", prefix);
+ return;
+ }
+
+ case AVRO_STRING:
+ {
+ /* TODO: Convert the UTF-8 to the current
+ * locale's character set */
+ const char *buf;
+ size_t size;
+ avro_value_get_string(value, &buf, &size);
+ printf("%s\t", prefix);
+ /* For strings, size includes the NUL terminator. */
+ print_bytes_value(buf, size-1);
+ printf("\n");
+ return;
+ }
+
+ case AVRO_ARRAY:
+ process_array(prefix, value);
+ return;
+
+ case AVRO_ENUM:
+ process_enum(prefix, value);
+ return;
+
+ case AVRO_FIXED:
+ {
+ const void *buf;
+ size_t size;
+ avro_value_get_fixed(value, &buf, &size);
+ printf("%s\t", prefix);
+ print_bytes_value((const char *) buf, size);
+ printf("\n");
+ return;
+ }
+
+ case AVRO_MAP:
+ process_map(prefix, value);
+ return;
+
+ case AVRO_RECORD:
+ process_record(prefix, value);
+ return;
+
+ case AVRO_UNION:
+ process_union(prefix, value);
+ return;
+
+ default:
+ {
+ fprintf(stderr, "Unknown schema type\n");
+ exit(1);
+ }
+ }
+}
+
+static void
+process_file(const char *filename)
+{
+ avro_file_reader_t reader;
+
+ if (filename == NULL) {
+ if (avro_file_reader_fp(stdin, "<stdin>", 0, &reader)) {
+ fprintf(stderr, "Error opening <stdin>:\n %s\n",
+ avro_strerror());
+ exit(1);
+ }
+ } else {
+ if (avro_file_reader(filename, &reader)) {
+ fprintf(stderr, "Error opening %s:\n %s\n",
+ filename, avro_strerror());
+ exit(1);
+ }
+ }
+
+ /* The JSON root is an array */
+ printf("%s\t[]\n", separator);
+
+ avro_raw_string_t prefix;
+ avro_raw_string_init(&prefix);
+
+ avro_schema_t wschema = avro_file_reader_get_writer_schema(reader);
+ avro_value_iface_t *iface = avro_generic_class_from_schema(wschema);
+ avro_value_t value;
+ avro_generic_value_new(iface, &value);
+
+ size_t record_number = 0;
+ int rval;
+
+ for (; (rval = avro_file_reader_read_value(reader, &value)) == 0; record_number++) {
+ create_array_prefix(&prefix, "", record_number);
+ process_value((const char *) avro_raw_string_get(&prefix), &value);
+ avro_value_reset(&value);
+ }
+
+ if (rval != EOF) {
+ fprintf(stderr, "Error reading value: %s", avro_strerror());
+ }
+
+ avro_raw_string_done(&prefix);
+ avro_value_decref(&value);
+ avro_value_iface_decref(iface);
+ avro_file_reader_close(reader);
+ avro_schema_decref(wschema);
+}
+
+
+/*-- MAIN PROGRAM --*/
+static struct option longopts[] = {
+ { "separator", required_argument, NULL, 's' },
+ { NULL, 0, NULL, 0 }
+};
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "Usage: avropipe [--separator=<separator>]\n"
+ " <avro data file>\n");
+}
+
+
+int main(int argc, char **argv)
+{
+ char *data_filename;
+
+ int ch;
+ while ((ch = getopt_long(argc, argv, "s:", longopts, NULL) ) != -1) {
+ switch (ch) {
+ case 's':
+ separator = optarg;
+ break;
+
+ default:
+ usage();
+ exit(1);
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 1) {
+ data_filename = argv[0];
+ } else if (argc == 0) {
+ data_filename = NULL;
+ } else {
+ fprintf(stderr, "Can't read from multiple input files.\n");
+ usage();
+ exit(1);
+ }
+
+ /* Process the data file */
+ process_file(data_filename);
+ return 0;
+}
diff --git a/fluent-bit/lib/avro/src/codec.c b/fluent-bit/lib/avro/src/codec.c
new file mode 100644
index 000000000..613a91437
--- /dev/null
+++ b/fluent-bit/lib/avro/src/codec.c
@@ -0,0 +1,620 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <string.h>
+#ifdef SNAPPY_CODEC
+#include <snappy-c.h>
+# if defined(__APPLE__)
+# include <libkern/OSByteOrder.h>
+# define __bswap_32 OSSwapInt32
+# elif defined(__FreeBSD__)
+# include <sys/endian.h>
+# define __bswap_32 bswap32
+# elif defined(_WIN32)
+# include <stdlib.h>
+# define __bswap_32 _byteswap_ulong
+# else
+# include <byteswap.h>
+# endif
+#endif
+#ifdef DEFLATE_CODEC
+#include <zlib.h>
+#endif
+#ifdef LZMA_CODEC
+#include <lzma.h>
+#endif
+#include "avro/errors.h"
+#include "avro/allocation.h"
+#include "codec.h"
+
+#define DEFAULT_BLOCK_SIZE (16 * 1024)
+
+/* NULL codec */
+
+static int
+codec_null(avro_codec_t codec)
+{
+ codec->name = "null";
+ codec->type = AVRO_CODEC_NULL;
+ codec->block_size = 0;
+ codec->used_size = 0;
+ codec->block_data = NULL;
+ codec->codec_data = NULL;
+
+ return 0;
+}
+
+static int encode_null(avro_codec_t c, void * data, int64_t len)
+{
+ c->block_data = data;
+ c->block_size = len;
+ c->used_size = len;
+
+ return 0;
+}
+
+static int decode_null(avro_codec_t c, void * data, int64_t len)
+{
+ c->block_data = data;
+ c->block_size = len;
+ c->used_size = len;
+
+ return 0;
+}
+
+static int reset_null(avro_codec_t c)
+{
+ c->block_data = NULL;
+ c->block_size = 0;
+ c->used_size = 0;
+ c->codec_data = NULL;
+
+ return 0;
+}
+
+/* Snappy codec */
+
+#ifdef SNAPPY_CODEC
+
+static int
+codec_snappy(avro_codec_t codec)
+{
+ codec->name = "snappy";
+ codec->type = AVRO_CODEC_SNAPPY;
+ codec->block_size = 0;
+ codec->used_size = 0;
+ codec->block_data = NULL;
+ codec->codec_data = NULL;
+
+ return 0;
+}
+
+static int encode_snappy(avro_codec_t c, void * data, int64_t len)
+{
+ uint32_t crc;
+ size_t outlen = snappy_max_compressed_length(len);
+
+ if (!c->block_data) {
+ c->block_data = avro_malloc(outlen+4);
+ c->block_size = outlen+4;
+ } else if (c->block_size < (int64_t) (outlen+4)) {
+ c->block_data = avro_realloc(c->block_data, c->block_size, (outlen+4));
+ c->block_size = outlen+4;
+ }
+
+ if (!c->block_data) {
+ avro_set_error("Cannot allocate memory for snappy");
+ return 1;
+ }
+
+ if (snappy_compress((const char *)data, len, (char*)c->block_data, &outlen) != SNAPPY_OK)
+ {
+ avro_set_error("Error compressing block with Snappy");
+ return 1;
+ }
+
+ crc = __bswap_32(crc32(0, (const Bytef *)data, len));
+ memcpy((char*)c->block_data+outlen, &crc, 4);
+ c->used_size = outlen+4;
+
+ return 0;
+}
+
+static int decode_snappy(avro_codec_t c, void * data, int64_t len)
+{
+ uint32_t crc;
+ size_t outlen;
+
+ if (snappy_uncompressed_length((const char*)data, len-4, &outlen) != SNAPPY_OK) {
+ avro_set_error("Uncompressed length error in snappy");
+ return 1;
+ }
+
+ if (!c->block_data) {
+ c->block_data = avro_malloc(outlen);
+ c->block_size = outlen;
+ } else if ( (size_t)c->block_size < outlen) {
+ c->block_data = avro_realloc(c->block_data, c->block_size, outlen);
+ c->block_size = outlen;
+ }
+
+ if (!c->block_data)
+ {
+ avro_set_error("Cannot allocate memory for snappy");
+ return 1;
+ }
+
+ if (snappy_uncompress((const char*)data, len-4, (char*)c->block_data, &outlen) != SNAPPY_OK)
+ {
+ avro_set_error("Error uncompressing block with Snappy");
+ return 1;
+ }
+
+ crc = __bswap_32(crc32(0, (const Bytef *)c->block_data, outlen));
+ if (memcmp(&crc, (char*)data+len-4, 4))
+ {
+ avro_set_error("CRC32 check failure uncompressing block with Snappy");
+ return 1;
+ }
+
+ c->used_size = outlen;
+
+ return 0;
+}
+
+static int reset_snappy(avro_codec_t c)
+{
+ if (c->block_data) {
+ avro_free(c->block_data, c->block_size);
+ }
+
+ c->block_data = NULL;
+ c->block_size = 0;
+ c->used_size = 0;
+ c->codec_data = NULL;
+
+ return 0;
+}
+
+#endif // SNAPPY_CODEC
+
+/* Deflate codec */
+
+#ifdef DEFLATE_CODEC
+
+struct codec_data_deflate {
+ z_stream deflate;
+ z_stream inflate;
+};
+#define codec_data_deflate_stream(cd) &((struct codec_data_deflate *)cd)->deflate
+#define codec_data_inflate_stream(cd) &((struct codec_data_deflate *)cd)->inflate
+
+
+static int
+codec_deflate(avro_codec_t codec)
+{
+ codec->name = "deflate";
+ codec->type = AVRO_CODEC_DEFLATE;
+ codec->block_size = 0;
+ codec->used_size = 0;
+ codec->block_data = NULL;
+ codec->codec_data = avro_new(struct codec_data_deflate);
+
+ if (!codec->codec_data) {
+ avro_set_error("Cannot allocate memory for zlib");
+ return 1;
+ }
+
+ z_stream *ds = codec_data_deflate_stream(codec->codec_data);
+ z_stream *is = codec_data_inflate_stream(codec->codec_data);
+
+ memset(ds, 0, sizeof(z_stream));
+ memset(is, 0, sizeof(z_stream));
+
+ ds->zalloc = is->zalloc = Z_NULL;
+ ds->zfree = is->zfree = Z_NULL;
+ ds->opaque = is->opaque = Z_NULL;
+
+ if (deflateInit2(ds, Z_BEST_COMPRESSION, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
+ avro_freet(struct codec_data_deflate, codec->codec_data);
+ codec->codec_data = NULL;
+ avro_set_error("Cannot initialize zlib deflate");
+ return 1;
+ }
+
+ if (inflateInit2(is, -15) != Z_OK) {
+ avro_freet(struct codec_data_deflate, codec->codec_data);
+ codec->codec_data = NULL;
+ avro_set_error("Cannot initialize zlib inflate");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int encode_deflate(avro_codec_t c, void * data, int64_t len)
+{
+ int err;
+ int64_t defl_len = compressBound((uLong)len * 1.2);
+
+ if (!c->block_data) {
+ c->block_data = avro_malloc(defl_len);
+ c->block_size = defl_len;
+ } else if ( c->block_size < defl_len) {
+ c->block_data = avro_realloc(c->block_data, c->block_size, defl_len);
+ c->block_size = defl_len;
+ }
+
+ if (!c->block_data)
+ {
+ avro_set_error("Cannot allocate memory for deflate");
+ return 1;
+ }
+
+ c->used_size = 0;
+
+ z_stream *s = codec_data_deflate_stream(c->codec_data);
+
+ s->next_in = (Bytef*)data;
+ s->avail_in = (uInt)len;
+
+ s->next_out = c->block_data;
+ s->avail_out = (uInt)c->block_size;
+
+ s->total_out = 0;
+
+ err = deflate(s, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(s);
+ if (err != Z_OK) {
+ avro_set_error("Error compressing block with deflate (%i)", err);
+ return 1;
+ }
+ return 0;
+ }
+
+ // zlib resizes the buffer?
+ c->block_size = s->total_out;
+ c->used_size = s->total_out;
+
+ if (deflateReset(s) != Z_OK) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static int decode_deflate(avro_codec_t c, void * data, int64_t len)
+{
+ int err;
+ z_stream *s = codec_data_inflate_stream(c->codec_data);
+
+ if (!c->block_data) {
+ c->block_data = avro_malloc(DEFAULT_BLOCK_SIZE);
+ c->block_size = DEFAULT_BLOCK_SIZE;
+ }
+
+ if (!c->block_data)
+ {
+ avro_set_error("Cannot allocate memory for deflate");
+ return 1;
+ }
+
+ c->used_size = 0;
+
+ s->next_in = data;
+ s->avail_in = len;
+
+ s->next_out = c->block_data;
+ s->avail_out = c->block_size;
+
+ s->total_out = 0;
+
+ do
+ {
+ err = inflate(s, Z_FINISH);
+
+ // Apparently if there is yet available space in the output then something
+ // has gone wrong in decompressing the data (according to cpython zlibmodule.c)
+ if (err == Z_BUF_ERROR && s->avail_out > 0) {
+ inflateEnd(s);
+ avro_set_error("Error decompressing block with deflate, possible data error");
+ return 1;
+ }
+
+ // The buffer was not big enough. resize it.
+ if (err == Z_BUF_ERROR)
+ {
+ c->block_data = avro_realloc(c->block_data, c->block_size, c->block_size * 2);
+ s->next_out = c->block_data + s->total_out;
+ s->avail_out += c->block_size;
+ c->block_size = c->block_size * 2;
+ }
+ } while (err == Z_BUF_ERROR);
+
+ if (err != Z_STREAM_END) {
+ inflateEnd(s);
+ if (err != Z_OK) {
+ avro_set_error("Error decompressing block with deflate (%i)", err);
+ return 1;
+ }
+ return 0;
+ }
+
+ c->used_size = s->total_out;
+
+ if (inflateReset(s) != Z_OK) {
+ avro_set_error("Error resetting deflate decompression");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int reset_deflate(avro_codec_t c)
+{
+ if (c->block_data) {
+ avro_free(c->block_data, c->block_size);
+ }
+ if (c->codec_data) {
+ deflateEnd(codec_data_deflate_stream(c->codec_data));
+ inflateEnd(codec_data_inflate_stream(c->codec_data));
+ avro_freet(struct codec_data_deflate, c->codec_data);
+ }
+
+ c->block_data = NULL;
+ c->block_size = 0;
+ c->used_size = 0;
+ c->codec_data = NULL;
+
+ return 0;
+}
+
+#endif // DEFLATE_CODEC
+
+/* LZMA codec */
+
+#ifdef LZMA_CODEC
+
+struct codec_data_lzma {
+ lzma_filter filters[2];
+ lzma_options_lzma options;
+};
+#define codec_data_lzma_filters(cd) ((struct codec_data_lzma *)cd)->filters
+#define codec_data_lzma_options(cd) &((struct codec_data_lzma *)cd)->options
+
+static int
+codec_lzma(avro_codec_t codec)
+{
+ codec->name = "lzma";
+ codec->type = AVRO_CODEC_LZMA;
+ codec->block_size = 0;
+ codec->used_size = 0;
+ codec->block_data = NULL;
+ codec->codec_data = avro_new(struct codec_data_lzma);
+
+ if (!codec->codec_data) {
+ avro_set_error("Cannot allocate memory for lzma");
+ return 1;
+ }
+
+ lzma_options_lzma* opt = codec_data_lzma_options(codec->codec_data);
+ lzma_lzma_preset(opt, LZMA_PRESET_DEFAULT);
+
+ lzma_filter* filters = codec_data_lzma_filters(codec->codec_data);
+ filters[0].id = LZMA_FILTER_LZMA2;
+ filters[0].options = opt;
+ filters[1].id = LZMA_VLI_UNKNOWN;
+ filters[1].options = NULL;
+
+ return 0;
+}
+
+static int encode_lzma(avro_codec_t codec, void * data, int64_t len)
+{
+ lzma_ret ret;
+ size_t written = 0;
+ lzma_filter* filters = codec_data_lzma_filters(codec->codec_data);
+
+ int64_t buff_len = len + lzma_raw_encoder_memusage(filters);
+
+ if (!codec->block_data) {
+ codec->block_data = avro_malloc(buff_len);
+ codec->block_size = buff_len;
+ }
+
+ if (!codec->block_data)
+ {
+ avro_set_error("Cannot allocate memory for lzma encoder");
+ return 1;
+ }
+
+ ret = lzma_raw_buffer_encode(filters, NULL, data, len, codec->block_data, &written, codec->block_size);
+
+ codec->used_size = written;
+
+ if (ret != LZMA_OK) {
+ avro_set_error("Error in lzma encoder");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int decode_lzma(avro_codec_t codec, void * data, int64_t len)
+{
+ size_t read_pos = 0;
+ size_t write_pos = 0;
+ lzma_ret ret;
+ lzma_filter* filters = codec_data_lzma_filters(codec->codec_data);
+
+ if (!codec->block_data) {
+ codec->block_data = avro_malloc(DEFAULT_BLOCK_SIZE);
+ codec->block_size = DEFAULT_BLOCK_SIZE;
+ }
+
+ if (!codec->block_data) {
+ avro_set_error("Cannot allocate memory for lzma decoder");
+ return 1;
+ }
+
+ do
+ {
+ ret = lzma_raw_buffer_decode(filters, NULL, data,
+ &read_pos, len, codec->block_data, &write_pos,
+ codec->block_size);
+
+ codec->used_size = write_pos;
+
+ // If it ran out of space to decode, give it more!!
+ // It will continue where it left off because of read_pos and write_pos.
+ if (ret == LZMA_BUF_ERROR) {
+ codec->block_data = avro_realloc(codec->block_data, codec->block_size, codec->block_size * 2);
+ codec->block_size = codec->block_size * 2;
+ }
+
+ } while (ret == LZMA_BUF_ERROR);
+
+ if (ret != LZMA_OK) {
+ avro_set_error("Error in lzma decoder");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int reset_lzma(avro_codec_t c)
+{
+ if (c->block_data) {
+ avro_free(c->block_data, c->block_size);
+ }
+ if (c->codec_data) {
+ avro_freet(struct codec_data_lzma, c->codec_data);
+ }
+
+ c->block_data = NULL;
+ c->block_size = 0;
+ c->used_size = 0;
+ c->codec_data = NULL;
+
+ return 0;
+}
+
+#endif // LZMA_CODEC
+
+/* Common interface */
+
+int avro_codec(avro_codec_t codec, const char *type)
+{
+ if (type == NULL) {
+ return codec_null(codec);
+ }
+
+#ifdef SNAPPY_CODEC
+ if (strcmp("snappy", type) == 0) {
+ return codec_snappy(codec);
+ }
+#endif
+
+#ifdef DEFLATE_CODEC
+ if (strcmp("deflate", type) == 0) {
+ return codec_deflate(codec);
+ }
+#endif
+
+#ifdef LZMA_CODEC
+ if (strcmp("lzma", type) == 0) {
+ return codec_lzma(codec);
+ }
+#endif
+
+ if (strcmp("null", type) == 0) {
+ return codec_null(codec);
+ }
+
+ avro_set_error("Unknown codec %s", type);
+ return 1;
+}
+
+int avro_codec_encode(avro_codec_t c, void * data, int64_t len)
+{
+ switch(c->type)
+ {
+ case AVRO_CODEC_NULL:
+ return encode_null(c, data, len);
+#ifdef SNAPPY_CODEC
+ case AVRO_CODEC_SNAPPY:
+ return encode_snappy(c, data, len);
+#endif
+#ifdef DEFLATE_CODEC
+ case AVRO_CODEC_DEFLATE:
+ return encode_deflate(c, data, len);
+#endif
+#ifdef LZMA_CODEC
+ case AVRO_CODEC_LZMA:
+ return encode_lzma(c, data, len);
+#endif
+ default:
+ return 1;
+ }
+}
+
+int avro_codec_decode(avro_codec_t c, void * data, int64_t len)
+{
+ switch(c->type)
+ {
+ case AVRO_CODEC_NULL:
+ return decode_null(c, data, len);
+#ifdef SNAPPY_CODEC
+ case AVRO_CODEC_SNAPPY:
+ return decode_snappy(c, data, len);
+#endif
+#ifdef DEFLATE_CODEC
+ case AVRO_CODEC_DEFLATE:
+ return decode_deflate(c, data, len);
+#endif
+#ifdef LZMA_CODEC
+ case AVRO_CODEC_LZMA:
+ return decode_lzma(c, data, len);
+#endif
+ default:
+ return 1;
+ }
+}
+
+int avro_codec_reset(avro_codec_t c)
+{
+ switch(c->type)
+ {
+ case AVRO_CODEC_NULL:
+ return reset_null(c);
+#ifdef SNAPPY_CODEC
+ case AVRO_CODEC_SNAPPY:
+ return reset_snappy(c);
+#endif
+#ifdef DEFLATE_CODEC
+ case AVRO_CODEC_DEFLATE:
+ return reset_deflate(c);
+#endif
+#ifdef LZMA_CODEC
+ case AVRO_CODEC_LZMA:
+ return reset_lzma(c);
+#endif
+ default:
+ return 1;
+ }
+}
diff --git a/fluent-bit/lib/avro/src/codec.h b/fluent-bit/lib/avro/src/codec.h
new file mode 100644
index 000000000..689122430
--- /dev/null
+++ b/fluent-bit/lib/avro/src/codec.h
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef AVRO_CODEC_H
+#define AVRO_CODEC_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+#include <avro/platform.h>
+
+enum avro_codec_type_t {
+ AVRO_CODEC_NULL,
+ AVRO_CODEC_DEFLATE,
+ AVRO_CODEC_LZMA,
+ AVRO_CODEC_SNAPPY
+};
+typedef enum avro_codec_type_t avro_codec_type_t;
+
+struct avro_codec_t_ {
+ const char * name;
+ avro_codec_type_t type;
+ int64_t block_size;
+ int64_t used_size;
+ void * block_data;
+ void * codec_data;
+};
+typedef struct avro_codec_t_* avro_codec_t;
+
+int avro_codec(avro_codec_t c, const char *type);
+int avro_codec_reset(avro_codec_t c);
+int avro_codec_encode(avro_codec_t c, void * data, int64_t len);
+int avro_codec_decode(avro_codec_t c, void * data, int64_t len);
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/consume-binary.c b/fluent-bit/lib/avro/src/consume-binary.c
new file mode 100644
index 000000000..9f92799d8
--- /dev/null
+++ b/fluent-bit/lib/avro/src/consume-binary.c
@@ -0,0 +1,328 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include "avro_private.h"
+#include "avro/allocation.h"
+#include "avro/consumer.h"
+#include "avro/errors.h"
+#include "avro/resolver.h"
+#include "avro/value.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include "encoding.h"
+#include "schema.h"
+#include "datum.h"
+
+
+static int
+read_enum(avro_reader_t reader, const avro_encoding_t * enc,
+ avro_consumer_t *consumer, void *ud)
+{
+ int rval;
+ int64_t index;
+
+ check_prefix(rval, enc->read_long(reader, &index),
+ "Cannot read enum value: ");
+ return avro_consumer_call(consumer, enum_value, index, ud);
+}
+
+static int
+read_array(avro_reader_t reader, const avro_encoding_t * enc,
+ avro_consumer_t *consumer, void *ud)
+{
+ int rval;
+ int64_t i; /* index within the current block */
+ int64_t index = 0; /* index within the entire array */
+ int64_t block_count;
+ int64_t block_size;
+
+ check_prefix(rval, enc->read_long(reader, &block_count),
+ "Cannot read array block count: ");
+ check(rval, avro_consumer_call(consumer, array_start_block,
+ 1, block_count, ud));
+
+ while (block_count != 0) {
+ if (block_count < 0) {
+ block_count = block_count * -1;
+ check_prefix(rval, enc->read_long(reader, &block_size),
+ "Cannot read array block size: ");
+ }
+
+ for (i = 0; i < block_count; i++, index++) {
+ avro_consumer_t *element_consumer = NULL;
+ void *element_ud = NULL;
+
+ check(rval,
+ avro_consumer_call(consumer, array_element,
+ index, &element_consumer, &element_ud,
+ ud));
+
+ check(rval, avro_consume_binary(reader, element_consumer, element_ud));
+ }
+
+ check_prefix(rval, enc->read_long(reader, &block_count),
+ "Cannot read array block count: ");
+ check(rval, avro_consumer_call(consumer, array_start_block,
+ 0, block_count, ud));
+ }
+
+ return 0;
+}
+
+static int
+read_map(avro_reader_t reader, const avro_encoding_t * enc,
+ avro_consumer_t *consumer, void *ud)
+{
+ int rval;
+ int64_t i; /* index within the current block */
+ int64_t index = 0; /* index within the entire array */
+ int64_t block_count;
+ int64_t block_size;
+
+ check_prefix(rval, enc->read_long(reader, &block_count),
+ "Cannot read map block count: ");
+ check(rval, avro_consumer_call(consumer, map_start_block,
+ 1, block_count, ud));
+
+ while (block_count != 0) {
+ if (block_count < 0) {
+ block_count = block_count * -1;
+ check_prefix(rval, enc->read_long(reader, &block_size),
+ "Cannot read map block size: ");
+ }
+
+ for (i = 0; i < block_count; i++, index++) {
+ char *key;
+ int64_t key_size;
+ avro_consumer_t *element_consumer = NULL;
+ void *element_ud = NULL;
+
+ check_prefix(rval, enc->read_string(reader, &key, &key_size),
+ "Cannot read map key: ");
+
+ rval = avro_consumer_call(consumer, map_element,
+ index, key,
+ &element_consumer, &element_ud,
+ ud);
+ if (rval) {
+ avro_free(key, key_size);
+ return rval;
+ }
+
+ rval = avro_consume_binary(reader, element_consumer, element_ud);
+ if (rval) {
+ avro_free(key, key_size);
+ return rval;
+ }
+
+ avro_free(key, key_size);
+ }
+
+ check_prefix(rval, enc->read_long(reader, &block_count),
+ "Cannot read map block count: ");
+ check(rval, avro_consumer_call(consumer, map_start_block,
+ 0, block_count, ud));
+ }
+
+ return 0;
+}
+
+static int
+read_union(avro_reader_t reader, const avro_encoding_t * enc,
+ avro_consumer_t *consumer, void *ud)
+{
+ int rval;
+ int64_t discriminant;
+ avro_consumer_t *branch_consumer = NULL;
+ void *branch_ud = NULL;
+
+ check_prefix(rval, enc->read_long(reader, &discriminant),
+ "Cannot read union discriminant: ");
+ check(rval, avro_consumer_call(consumer, union_branch,
+ discriminant,
+ &branch_consumer, &branch_ud, ud));
+ return avro_consume_binary(reader, branch_consumer, branch_ud);
+}
+
+static int
+read_record(avro_reader_t reader, const avro_encoding_t * enc,
+ avro_consumer_t *consumer, void *ud)
+{
+ int rval;
+ size_t num_fields;
+ unsigned int i;
+
+ AVRO_UNUSED(enc);
+
+ check(rval, avro_consumer_call(consumer, record_start, ud));
+
+ num_fields = avro_schema_record_size(consumer->schema);
+ for (i = 0; i < num_fields; i++) {
+ avro_consumer_t *field_consumer = NULL;
+ void *field_ud = NULL;
+
+ check(rval, avro_consumer_call(consumer, record_field,
+ i, &field_consumer, &field_ud,
+ ud));
+
+ if (field_consumer) {
+ check(rval, avro_consume_binary(reader, field_consumer, field_ud));
+ } else {
+ avro_schema_t field_schema =
+ avro_schema_record_field_get_by_index(consumer->schema, i);
+ check(rval, avro_skip_data(reader, field_schema));
+ }
+ }
+
+ return 0;
+}
+
+int
+avro_consume_binary(avro_reader_t reader, avro_consumer_t *consumer, void *ud)
+{
+ int rval;
+ const avro_encoding_t *enc = &avro_binary_encoding;
+
+ check_param(EINVAL, reader, "reader");
+ check_param(EINVAL, consumer, "consumer");
+
+ switch (avro_typeof(consumer->schema)) {
+ case AVRO_NULL:
+ check_prefix(rval, enc->read_null(reader),
+ "Cannot read null value: ");
+ check(rval, avro_consumer_call(consumer, null_value, ud));
+ break;
+
+ case AVRO_BOOLEAN:
+ {
+ int8_t b;
+ check_prefix(rval, enc->read_boolean(reader, &b),
+ "Cannot read boolean value: ");
+ check(rval, avro_consumer_call(consumer, boolean_value, b, ud));
+ }
+ break;
+
+ case AVRO_STRING:
+ {
+ int64_t len;
+ char *s;
+ check_prefix(rval, enc->read_string(reader, &s, &len),
+ "Cannot read string value: ");
+ check(rval, avro_consumer_call(consumer, string_value, s, len, ud));
+ }
+ break;
+
+ case AVRO_INT32:
+ {
+ int32_t i;
+ check_prefix(rval, enc->read_int(reader, &i),
+ "Cannot read int value: ");
+ check(rval, avro_consumer_call(consumer, int_value, i, ud));
+ }
+ break;
+
+ case AVRO_INT64:
+ {
+ int64_t l;
+ check_prefix(rval, enc->read_long(reader, &l),
+ "Cannot read long value: ");
+ check(rval, avro_consumer_call(consumer, long_value, l, ud));
+ }
+ break;
+
+ case AVRO_FLOAT:
+ {
+ float f;
+ check_prefix(rval, enc->read_float(reader, &f),
+ "Cannot read float value: ");
+ check(rval, avro_consumer_call(consumer, float_value, f, ud));
+ }
+ break;
+
+ case AVRO_DOUBLE:
+ {
+ double d;
+ check_prefix(rval, enc->read_double(reader, &d),
+ "Cannot read double value: ");
+ check(rval, avro_consumer_call(consumer, double_value, d, ud));
+ }
+ break;
+
+ case AVRO_BYTES:
+ {
+ char *bytes;
+ int64_t len;
+ check_prefix(rval, enc->read_bytes(reader, &bytes, &len),
+ "Cannot read bytes value: ");
+ check(rval, avro_consumer_call(consumer, bytes_value, bytes, len, ud));
+ }
+ break;
+
+ case AVRO_FIXED:
+ {
+ char *bytes;
+ int64_t size =
+ avro_schema_to_fixed(consumer->schema)->size;
+
+ bytes = (char *) avro_malloc(size);
+ if (!bytes) {
+ avro_prefix_error("Cannot allocate new fixed value");
+ return ENOMEM;
+ }
+ rval = avro_read(reader, bytes, size);
+ if (rval) {
+ avro_prefix_error("Cannot read fixed value: ");
+ avro_free(bytes, size);
+ return rval;
+ }
+
+ rval = avro_consumer_call(consumer, fixed_value, bytes, size, ud);
+ if (rval) {
+ avro_free(bytes, size);
+ return rval;
+ }
+ }
+ break;
+
+ case AVRO_ENUM:
+ check(rval, read_enum(reader, enc, consumer, ud));
+ break;
+
+ case AVRO_ARRAY:
+ check(rval, read_array(reader, enc, consumer, ud));
+ break;
+
+ case AVRO_MAP:
+ check(rval, read_map(reader, enc, consumer, ud));
+ break;
+
+ case AVRO_UNION:
+ check(rval, read_union(reader, enc, consumer, ud));
+ break;
+
+ case AVRO_RECORD:
+ check(rval, read_record(reader, enc, consumer, ud));
+ break;
+
+ case AVRO_LINK:
+ avro_set_error("Consumer can't consume a link schema directly");
+ return EINVAL;
+ }
+
+ return 0;
+}
diff --git a/fluent-bit/lib/avro/src/consumer.c b/fluent-bit/lib/avro/src/consumer.c
new file mode 100644
index 000000000..e01958c8b
--- /dev/null
+++ b/fluent-bit/lib/avro/src/consumer.c
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include "avro/consumer.h"
+
+void avro_consumer_free(avro_consumer_t *consumer)
+{
+ consumer->free(consumer);
+}
diff --git a/fluent-bit/lib/avro/src/datafile.c b/fluent-bit/lib/avro/src/datafile.c
new file mode 100644
index 000000000..c9d4dfeb6
--- /dev/null
+++ b/fluent-bit/lib/avro/src/datafile.c
@@ -0,0 +1,766 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include "avro_private.h"
+#include "avro/allocation.h"
+#include "avro/generic.h"
+#include "avro/errors.h"
+#include "avro/value.h"
+#include "encoding.h"
+#include "codec.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include <string.h>
+
+struct avro_file_reader_t_ {
+ avro_schema_t writers_schema;
+ avro_reader_t reader;
+ avro_reader_t block_reader;
+ avro_codec_t codec;
+ char sync[16];
+ int64_t blocks_read;
+ int64_t blocks_total;
+ int64_t current_blocklen;
+ char * current_blockdata;
+};
+
+struct avro_file_writer_t_ {
+ avro_schema_t writers_schema;
+ avro_writer_t writer;
+ avro_codec_t codec;
+ char sync[16];
+ int block_count;
+ size_t block_size;
+ avro_writer_t datum_writer;
+ char* datum_buffer;
+ size_t datum_buffer_size;
+ char schema_buf[64 * 1024];
+};
+
+#define DEFAULT_BLOCK_SIZE 16 * 1024
+
+/* Note: We should not just read /dev/random here, because it may not
+ * exist on all platforms e.g. Win32.
+ */
+static void generate_sync(avro_file_writer_t w)
+{
+ unsigned int i;
+ srand(time(NULL));
+ for (i = 0; i < sizeof(w->sync); i++) {
+ w->sync[i] = ((double)rand() / (RAND_MAX + 1.0)) * 255;
+ }
+}
+
+static int write_sync(avro_file_writer_t w)
+{
+ return avro_write(w->writer, w->sync, sizeof(w->sync));
+}
+
+static int write_header(avro_file_writer_t w)
+{
+ int rval;
+ uint8_t version = 1;
+ /* TODO: remove this static buffer */
+ avro_writer_t schema_writer;
+ const avro_encoding_t *enc = &avro_binary_encoding;
+ int64_t schema_len;
+
+ /* Generate random sync */
+ generate_sync(w);
+
+ check(rval, avro_write(w->writer, "Obj", 3));
+ check(rval, avro_write(w->writer, &version, 1));
+
+ check(rval, enc->write_long(w->writer, 2));
+ check(rval, enc->write_string(w->writer, "avro.codec"));
+ check(rval, enc->write_bytes(w->writer, w->codec->name, strlen(w->codec->name)));
+ check(rval, enc->write_string(w->writer, "avro.schema"));
+ schema_writer =
+ avro_writer_memory(&w->schema_buf[0], sizeof(w->schema_buf));
+ rval = avro_schema_to_json(w->writers_schema, schema_writer);
+ if (rval) {
+ avro_writer_free(schema_writer);
+ return rval;
+ }
+ schema_len = avro_writer_tell(schema_writer);
+ avro_writer_free(schema_writer);
+ check(rval,
+ enc->write_bytes(w->writer, w->schema_buf, schema_len));
+ check(rval, enc->write_long(w->writer, 0));
+ return write_sync(w);
+}
+
+static int
+file_writer_init_fp(FILE *fp, const char *path, int should_close, const char *mode, avro_file_writer_t w)
+{
+ if (!fp) {
+ fp = fopen(path, mode);
+ }
+
+ if (!fp) {
+ avro_set_error("Cannot open file for %s", path);
+ return ENOMEM;
+ }
+ w->writer = avro_writer_file_fp(fp, should_close);
+ if (!w->writer) {
+ if (should_close) {
+ fclose(fp);
+ }
+ avro_set_error("Cannot create file writer for %s", path);
+ return ENOMEM;
+ }
+ return 0;
+}
+
+/* Exclusive file writing is supported by GCC using the mode
+ * "wx". Win32 does not support exclusive file writing, so for win32
+ * fall back to the non-exclusive file writing.
+ */
+#ifdef _WIN32
+ #define EXCLUSIVE_WRITE_MODE "wb"
+#else
+ #define EXCLUSIVE_WRITE_MODE "wbx"
+#endif
+
+static int
+file_writer_create(FILE *fp, const char *path, int should_close, avro_schema_t schema, avro_file_writer_t w, size_t block_size)
+{
+ int rval;
+
+ w->block_count = 0;
+ rval = file_writer_init_fp(fp, path, should_close, EXCLUSIVE_WRITE_MODE, w);
+ if (rval) {
+ check(rval, file_writer_init_fp(fp, path, should_close, "wb", w));
+ }
+
+ w->datum_buffer_size = block_size;
+ w->datum_buffer = (char *) avro_malloc(w->datum_buffer_size);
+
+ if(!w->datum_buffer) {
+ avro_set_error("Could not allocate datum buffer\n");
+ avro_writer_free(w->writer);
+ return ENOMEM;
+ }
+
+ w->datum_writer =
+ avro_writer_memory(w->datum_buffer, w->datum_buffer_size);
+ if (!w->datum_writer) {
+ avro_set_error("Cannot create datum writer for file %s", path);
+ avro_writer_free(w->writer);
+ avro_free(w->datum_buffer, w->datum_buffer_size);
+ return ENOMEM;
+ }
+
+ w->writers_schema = avro_schema_incref(schema);
+ return write_header(w);
+}
+
+int
+avro_file_writer_create(const char *path, avro_schema_t schema,
+ avro_file_writer_t * writer)
+{
+ return avro_file_writer_create_with_codec_fp(NULL, path, 1, schema, writer, "null", 0);
+}
+
+int
+avro_file_writer_create_fp(FILE *fp, const char *path, int should_close, avro_schema_t schema,
+ avro_file_writer_t * writer)
+{
+ return avro_file_writer_create_with_codec_fp(fp, path, should_close, schema, writer, "null", 0);
+}
+
+int avro_file_writer_create_with_codec(const char *path,
+ avro_schema_t schema, avro_file_writer_t * writer,
+ const char *codec, size_t block_size)
+{
+ return avro_file_writer_create_with_codec_fp(NULL, path, 1, schema, writer, codec, block_size);
+}
+
+int avro_file_writer_create_with_codec_fp(FILE *fp, const char *path, int should_close,
+ avro_schema_t schema, avro_file_writer_t * writer,
+ const char *codec, size_t block_size)
+{
+ avro_file_writer_t w;
+ int rval;
+ check_param(EINVAL, path, "path");
+ check_param(EINVAL, is_avro_schema(schema), "schema");
+ check_param(EINVAL, writer, "writer");
+ check_param(EINVAL, codec, "codec");
+
+ if (block_size == 0) {
+ block_size = DEFAULT_BLOCK_SIZE;
+ }
+
+ w = (avro_file_writer_t) avro_new(struct avro_file_writer_t_);
+ if (!w) {
+ avro_set_error("Cannot allocate new file writer");
+ return ENOMEM;
+ }
+ w->codec = (avro_codec_t) avro_new(struct avro_codec_t_);
+ if (!w->codec) {
+ avro_set_error("Cannot allocate new codec");
+ avro_freet(struct avro_file_writer_t_, w);
+ return ENOMEM;
+ }
+ rval = avro_codec(w->codec, codec);
+ if (rval) {
+ avro_codec_reset(w->codec);
+ avro_freet(struct avro_codec_t_, w->codec);
+ avro_freet(struct avro_file_writer_t_, w);
+ return rval;
+ }
+ rval = file_writer_create(fp, path, should_close, schema, w, block_size);
+ if (rval) {
+ avro_codec_reset(w->codec);
+ avro_freet(struct avro_codec_t_, w->codec);
+ avro_freet(struct avro_file_writer_t_, w);
+ return rval;
+ }
+ *writer = w;
+
+ return 0;
+}
+
+static int file_read_header(avro_reader_t reader,
+ avro_schema_t * writers_schema, avro_codec_t codec,
+ char *sync, int synclen)
+{
+ int rval;
+ avro_schema_t meta_schema;
+ avro_schema_t meta_values_schema;
+ avro_value_iface_t *meta_iface;
+ avro_value_t meta;
+ char magic[4];
+ avro_value_t codec_val;
+ avro_value_t schema_bytes;
+ const void *p;
+ size_t len;
+
+ check(rval, avro_read(reader, magic, sizeof(magic)));
+ if (magic[0] != 'O' || magic[1] != 'b' || magic[2] != 'j'
+ || magic[3] != 1) {
+ avro_set_error("Incorrect Avro container file magic number");
+ return EILSEQ;
+ }
+
+ meta_values_schema = avro_schema_bytes();
+ meta_schema = avro_schema_map(meta_values_schema);
+ meta_iface = avro_generic_class_from_schema(meta_schema);
+ if (meta_iface == NULL) {
+ return EILSEQ;
+ }
+ check(rval, avro_generic_value_new(meta_iface, &meta));
+ rval = avro_value_read(reader, &meta);
+ if (rval) {
+ avro_prefix_error("Cannot read file header: ");
+ return EILSEQ;
+ }
+ avro_schema_decref(meta_schema);
+
+ rval = avro_value_get_by_name(&meta, "avro.codec", &codec_val, NULL);
+ if (rval) {
+ if (avro_codec(codec, NULL) != 0) {
+ avro_set_error("Codec not specified in header and unable to set 'null' codec");
+ avro_value_decref(&meta);
+ return EILSEQ;
+ }
+ } else {
+ const void *buf;
+ size_t size;
+ char codec_name[11];
+
+ avro_type_t type = avro_value_get_type(&codec_val);
+
+ if (type != AVRO_BYTES) {
+ avro_set_error("Value type of codec is unexpected");
+ avro_value_decref(&meta);
+ return EILSEQ;
+ }
+
+ avro_value_get_bytes(&codec_val, &buf, &size);
+ memset(codec_name, 0, sizeof(codec_name));
+ strncpy(codec_name, (const char *) buf, size < 10 ? size : 10);
+
+ if (avro_codec(codec, codec_name) != 0) {
+ avro_set_error("File header contains an unknown codec");
+ avro_value_decref(&meta);
+ return EILSEQ;
+ }
+ }
+
+ rval = avro_value_get_by_name(&meta, "avro.schema", &schema_bytes, NULL);
+ if (rval) {
+ avro_set_error("File header doesn't contain a schema");
+ avro_value_decref(&meta);
+ return EILSEQ;
+ }
+
+ avro_value_get_bytes(&schema_bytes, &p, &len);
+ rval = avro_schema_from_json_length((const char *) p, len, writers_schema);
+ if (rval) {
+ avro_prefix_error("Cannot parse file header: ");
+ avro_value_decref(&meta);
+ return rval;
+ }
+
+ avro_value_decref(&meta);
+ avro_value_iface_decref(meta_iface);
+ return avro_read(reader, sync, synclen);
+}
+
+static int
+file_writer_open(const char *path, avro_file_writer_t w, size_t block_size)
+{
+ int rval;
+ FILE *fp;
+ avro_reader_t reader;
+
+ /* Open for read AND write */
+ fp = fopen(path, "r+b");
+ if (!fp) {
+ avro_set_error("Error opening file: %s",
+ strerror(errno));
+ return errno;
+ }
+
+ /* Don`t close the underlying file descriptor, logrotate can
+ * vanish it from sight. */
+ reader = avro_reader_file_fp(fp, 0);
+ if (!reader) {
+ fclose(fp);
+ avro_set_error("Cannot create file reader for %s", path);
+ return ENOMEM;
+ }
+ rval =
+ file_read_header(reader, &w->writers_schema, w->codec, w->sync,
+ sizeof(w->sync));
+
+ avro_reader_free(reader);
+ if (rval) {
+ fclose(fp);
+ return rval;
+ }
+
+ w->block_count = 0;
+
+ /* Position to end of file and get ready to write */
+ fseek(fp, 0, SEEK_END);
+
+ w->writer = avro_writer_file(fp);
+ if (!w->writer) {
+ fclose(fp);
+ avro_set_error("Cannot create file writer for %s", path);
+ return ENOMEM;
+ }
+
+ if (block_size == 0) {
+ block_size = DEFAULT_BLOCK_SIZE;
+ }
+
+ w->datum_buffer_size = block_size;
+ w->datum_buffer = (char *) avro_malloc(w->datum_buffer_size);
+
+ if(!w->datum_buffer) {
+ avro_set_error("Could not allocate datum buffer\n");
+ avro_writer_free(w->writer);
+ return ENOMEM;
+ }
+
+ w->datum_writer =
+ avro_writer_memory(w->datum_buffer, w->datum_buffer_size);
+ if (!w->datum_writer) {
+ avro_set_error("Cannot create datum writer for file %s", path);
+ avro_writer_free(w->writer);
+ avro_free(w->datum_buffer, w->datum_buffer_size);
+ return ENOMEM;
+ }
+
+ return 0;
+}
+
+int
+avro_file_writer_open_bs(const char *path, avro_file_writer_t * writer,
+ size_t block_size)
+{
+ avro_file_writer_t w;
+ int rval;
+ check_param(EINVAL, path, "path");
+ check_param(EINVAL, writer, "writer");
+
+ w = (avro_file_writer_t) avro_new(struct avro_file_writer_t_);
+ if (!w) {
+ avro_set_error("Cannot create new file writer for %s", path);
+ return ENOMEM;
+ }
+ w->codec = (avro_codec_t) avro_new(struct avro_codec_t_);
+ if (!w->codec) {
+ avro_set_error("Cannot allocate new codec");
+ avro_freet(struct avro_file_writer_t_, w);
+ return ENOMEM;
+ }
+ avro_codec(w->codec, NULL);
+ rval = file_writer_open(path, w, block_size);
+ if (rval) {
+ avro_codec_reset(w->codec);
+ avro_freet(struct avro_codec_t_, w->codec);
+ avro_freet(struct avro_file_writer_t_, w);
+ return rval;
+ }
+
+ *writer = w;
+ return 0;
+}
+
+int
+avro_file_writer_open(const char *path, avro_file_writer_t * writer)
+{
+ return avro_file_writer_open_bs(path, writer, 0);
+}
+
+static int file_read_block_count(avro_file_reader_t r)
+{
+ int rval;
+ int64_t len;
+ const avro_encoding_t *enc = &avro_binary_encoding;
+
+ /* For a correctly formatted file, EOF will occur here */
+ rval = enc->read_long(r->reader, &r->blocks_total);
+
+ if (rval == EILSEQ && avro_reader_is_eof(r->reader)) {
+ return EOF;
+ }
+
+ check_prefix(rval, rval,
+ "Cannot read file block count: ");
+ check_prefix(rval, enc->read_long(r->reader, &len),
+ "Cannot read file block size: ");
+
+ if (r->current_blockdata && len > r->current_blocklen) {
+ r->current_blockdata = (char *) avro_realloc(r->current_blockdata, r->current_blocklen, len);
+ r->current_blocklen = len;
+ } else if (!r->current_blockdata) {
+ r->current_blockdata = (char *) avro_malloc(len);
+ r->current_blocklen = len;
+ }
+
+ if (len > 0) {
+ check_prefix(rval, avro_read(r->reader, r->current_blockdata, len),
+ "Cannot read file block: ");
+
+ check_prefix(rval, avro_codec_decode(r->codec, r->current_blockdata, len),
+ "Cannot decode file block: ");
+ }
+
+ avro_reader_memory_set_source(r->block_reader, (const char *) r->codec->block_data, r->codec->used_size);
+
+ r->blocks_read = 0;
+ return 0;
+}
+
+int avro_file_reader_fp(FILE *fp, const char *path, int should_close,
+ avro_file_reader_t * reader)
+{
+ int rval;
+ avro_file_reader_t r = (avro_file_reader_t) avro_new(struct avro_file_reader_t_);
+ if (!r) {
+ if (should_close) {
+ fclose(fp);
+ }
+ avro_set_error("Cannot allocate file reader for %s", path);
+ return ENOMEM;
+ }
+
+ r->reader = avro_reader_file_fp(fp, should_close);
+ if (!r->reader) {
+ if (should_close) {
+ fclose(fp);
+ }
+ avro_set_error("Cannot allocate reader for file %s", path);
+ avro_freet(struct avro_file_reader_t_, r);
+ return ENOMEM;
+ }
+ r->block_reader = avro_reader_memory(0, 0);
+ if (!r->block_reader) {
+ avro_set_error("Cannot allocate block reader for file %s", path);
+ avro_reader_free(r->reader);
+ avro_freet(struct avro_file_reader_t_, r);
+ return ENOMEM;
+ }
+
+ r->codec = (avro_codec_t) avro_new(struct avro_codec_t_);
+ if (!r->codec) {
+ avro_set_error("Could not allocate codec for file %s", path);
+ avro_reader_free(r->reader);
+ avro_freet(struct avro_file_reader_t_, r);
+ return ENOMEM;
+ }
+ avro_codec(r->codec, NULL);
+
+ rval = file_read_header(r->reader, &r->writers_schema, r->codec,
+ r->sync, sizeof(r->sync));
+ if (rval) {
+ avro_reader_free(r->reader);
+ avro_codec_reset(r->codec);
+ avro_freet(struct avro_codec_t_, r->codec);
+ avro_freet(struct avro_file_reader_t_, r);
+ return rval;
+ }
+
+ r->current_blockdata = NULL;
+ r->current_blocklen = 0;
+
+ rval = file_read_block_count(r);
+ if (rval == EOF) {
+ r->blocks_total = 0;
+ } else if (rval) {
+ avro_reader_free(r->reader);
+ avro_codec_reset(r->codec);
+ avro_freet(struct avro_codec_t_, r->codec);
+ avro_freet(struct avro_file_reader_t_, r);
+ return rval;
+ }
+
+ *reader = r;
+ return 0;
+}
+
+int avro_file_reader(const char *path, avro_file_reader_t * reader)
+{
+ FILE *fp;
+
+ fp = fopen(path, "rb");
+ if (!fp) {
+ return errno;
+ }
+
+ return avro_file_reader_fp(fp, path, 1, reader);
+}
+
+avro_schema_t
+avro_file_reader_get_writer_schema(avro_file_reader_t r)
+{
+ check_param(NULL, r, "reader");
+ return avro_schema_incref(r->writers_schema);
+}
+
+static int file_write_block(avro_file_writer_t w)
+{
+ const avro_encoding_t *enc = &avro_binary_encoding;
+ int rval;
+
+ if (w->block_count) {
+ /* Write the block count */
+ check_prefix(rval, enc->write_long(w->writer, w->block_count),
+ "Cannot write file block count: ");
+ /* Encode the block */
+ check_prefix(rval, avro_codec_encode(w->codec, w->datum_buffer, w->block_size),
+ "Cannot encode file block: ");
+ /* Write the block length */
+ check_prefix(rval, enc->write_long(w->writer, w->codec->used_size),
+ "Cannot write file block size: ");
+ /* Write the block */
+ check_prefix(rval, avro_write(w->writer, w->codec->block_data, w->codec->used_size),
+ "Cannot write file block: ");
+ /* Write the sync marker */
+ check_prefix(rval, write_sync(w),
+ "Cannot write sync marker: ");
+ /* Reset the datum writer */
+ avro_writer_reset(w->datum_writer);
+ w->block_count = 0;
+ w->block_size = 0;
+ }
+ return 0;
+}
+
+int avro_file_writer_append(avro_file_writer_t w, avro_datum_t datum)
+{
+ int rval;
+ check_param(EINVAL, w, "writer");
+ check_param(EINVAL, datum, "datum");
+
+ rval = avro_write_data(w->datum_writer, w->writers_schema, datum);
+ if (rval) {
+ check(rval, file_write_block(w));
+ rval =
+ avro_write_data(w->datum_writer, w->writers_schema, datum);
+ if (rval) {
+ avro_set_error("Datum too large for file block size");
+ /* TODO: if the datum encoder larger than our buffer,
+ just write a single large datum */
+ return rval;
+ }
+ }
+ w->block_count++;
+ w->block_size = avro_writer_tell(w->datum_writer);
+ return 0;
+}
+
+int
+avro_file_writer_append_value(avro_file_writer_t w, avro_value_t *value)
+{
+ int rval;
+ check_param(EINVAL, w, "writer");
+ check_param(EINVAL, value, "value");
+
+ rval = avro_value_write(w->datum_writer, value);
+ if (rval) {
+ check(rval, file_write_block(w));
+ rval = avro_value_write(w->datum_writer, value);
+ if (rval) {
+ avro_set_error("Value too large for file block size");
+ /* TODO: if the value encoder larger than our buffer,
+ just write a single large datum */
+ return rval;
+ }
+ }
+ w->block_count++;
+ w->block_size = avro_writer_tell(w->datum_writer);
+ return 0;
+}
+
+int
+avro_file_writer_append_encoded(avro_file_writer_t w,
+ const void *buf, int64_t len)
+{
+ int rval;
+ check_param(EINVAL, w, "writer");
+
+ rval = avro_write(w->datum_writer, (void *) buf, len);
+ if (rval) {
+ check(rval, file_write_block(w));
+ rval = avro_write(w->datum_writer, (void *) buf, len);
+ if (rval) {
+ avro_set_error("Value too large for file block size");
+ /* TODO: if the value encoder larger than our buffer,
+ just write a single large datum */
+ return rval;
+ }
+ }
+ w->block_count++;
+ w->block_size = avro_writer_tell(w->datum_writer);
+ return 0;
+}
+
+int avro_file_writer_sync(avro_file_writer_t w)
+{
+ return file_write_block(w);
+}
+
+int avro_file_writer_flush(avro_file_writer_t w)
+{
+ int rval;
+ check(rval, file_write_block(w));
+ avro_writer_flush(w->writer);
+ return 0;
+}
+
+int avro_file_writer_close(avro_file_writer_t w)
+{
+ int rval;
+ check(rval, avro_file_writer_flush(w));
+ avro_schema_decref(w->writers_schema);
+ avro_writer_free(w->datum_writer);
+ avro_writer_free(w->writer);
+ avro_free(w->datum_buffer, w->datum_buffer_size);
+ avro_codec_reset(w->codec);
+ avro_freet(struct avro_codec_t_, w->codec);
+ avro_freet(struct avro_file_writer_t_, w);
+ return 0;
+}
+
+int avro_file_reader_read(avro_file_reader_t r, avro_schema_t readers_schema,
+ avro_datum_t * datum)
+{
+ int rval;
+ char sync[16];
+
+ check_param(EINVAL, r, "reader");
+ check_param(EINVAL, datum, "datum");
+
+ /* This will be set to zero when an empty file is opened.
+ * Return EOF here when the user attempts to read. */
+ if (r->blocks_total == 0) {
+ return EOF;
+ }
+
+ if (r->blocks_read == r->blocks_total) {
+ check(rval, avro_read(r->reader, sync, sizeof(sync)));
+ if (memcmp(r->sync, sync, sizeof(r->sync)) != 0) {
+ /* wrong sync bytes */
+ avro_set_error("Incorrect sync bytes");
+ return EILSEQ;
+ }
+ check(rval, file_read_block_count(r));
+ }
+
+ check(rval,
+ avro_read_data(r->block_reader, r->writers_schema, readers_schema,
+ datum));
+ r->blocks_read++;
+
+ return 0;
+}
+
+int
+avro_file_reader_read_value(avro_file_reader_t r, avro_value_t *value)
+{
+ int rval;
+ char sync[16];
+
+ check_param(EINVAL, r, "reader");
+ check_param(EINVAL, value, "value");
+
+ /* This will be set to zero when an empty file is opened.
+ * Return EOF here when the user attempts to read. */
+ if (r->blocks_total == 0) {
+ return EOF;
+ }
+
+ if (r->blocks_read == r->blocks_total) {
+ /* reads sync bytes and buffers further bytes */
+ check(rval, avro_read(r->reader, sync, sizeof(sync)));
+ if (memcmp(r->sync, sync, sizeof(r->sync)) != 0) {
+ /* wrong sync bytes */
+ avro_set_error("Incorrect sync bytes");
+ return EILSEQ;
+ }
+
+ check(rval, file_read_block_count(r));
+ }
+
+ check(rval, avro_value_read(r->block_reader, value));
+ r->blocks_read++;
+
+ return 0;
+}
+
+int avro_file_reader_close(avro_file_reader_t reader)
+{
+ avro_schema_decref(reader->writers_schema);
+ avro_reader_free(reader->reader);
+ avro_reader_free(reader->block_reader);
+ avro_codec_reset(reader->codec);
+ avro_freet(struct avro_codec_t_, reader->codec);
+ if (reader->current_blockdata) {
+ avro_free(reader->current_blockdata, reader->current_blocklen);
+ }
+ avro_freet(struct avro_file_reader_t_, reader);
+ return 0;
+}
diff --git a/fluent-bit/lib/avro/src/datum.c b/fluent-bit/lib/avro/src/datum.c
new file mode 100644
index 000000000..2c4278090
--- /dev/null
+++ b/fluent-bit/lib/avro/src/datum.c
@@ -0,0 +1,1255 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include "avro/allocation.h"
+#include "avro/basics.h"
+#include "avro/errors.h"
+#include "avro/legacy.h"
+#include "avro/refcount.h"
+#include "avro/schema.h"
+#include "avro_private.h"
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "datum.h"
+#include "schema.h"
+#include "encoding.h"
+
+#define DEFAULT_TABLE_SIZE 32
+
+static void avro_datum_init(avro_datum_t datum, avro_type_t type)
+{
+ datum->type = type;
+ datum->class_type = AVRO_DATUM;
+ avro_refcount_set(&datum->refcount, 1);
+}
+
+static void
+avro_str_free_wrapper(void *ptr, size_t sz)
+{
+ // don't need sz, since the size is stored in the string buffer
+ AVRO_UNUSED(sz);
+ avro_str_free((char *)ptr);
+}
+
+static avro_datum_t avro_string_private(char *str, int64_t size,
+ avro_free_func_t string_free)
+{
+ struct avro_string_datum_t *datum =
+ (struct avro_string_datum_t *) avro_new(struct avro_string_datum_t);
+ if (!datum) {
+ avro_set_error("Cannot create new string datum");
+ return NULL;
+ }
+ datum->s = str;
+ datum->size = size;
+ datum->free = string_free;
+
+ avro_datum_init(&datum->obj, AVRO_STRING);
+ return &datum->obj;
+}
+
+avro_datum_t avro_string(const char *str)
+{
+ char *p = avro_strdup(str);
+ if (!p) {
+ avro_set_error("Cannot copy string content");
+ return NULL;
+ }
+ avro_datum_t s_datum = avro_string_private(p, 0, avro_str_free_wrapper);
+ if (!s_datum) {
+ avro_str_free(p);
+ }
+
+ return s_datum;
+}
+
+avro_datum_t avro_givestring(const char *str,
+ avro_free_func_t free)
+{
+ int64_t sz = strlen(str)+1;
+ return avro_string_private((char *)str, sz, free);
+}
+
+int avro_string_get(avro_datum_t datum, char **p)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_string(datum), "string datum");
+ check_param(EINVAL, p, "string buffer");
+
+ *p = avro_datum_to_string(datum)->s;
+ return 0;
+}
+
+static int avro_string_set_private(avro_datum_t datum,
+ const char *p, int64_t size,
+ avro_free_func_t string_free)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_string(datum), "string datum");
+ check_param(EINVAL, p, "string content");
+
+ struct avro_string_datum_t *string = avro_datum_to_string(datum);
+ if (string->free) {
+ string->free(string->s, string->size);
+ }
+ string->free = string_free;
+ string->s = (char *)p;
+ string->size = size;
+ return 0;
+}
+
+int avro_string_set(avro_datum_t datum, const char *p)
+{
+ char *string_copy = avro_strdup(p);
+ int rval;
+ if (!string_copy) {
+ avro_set_error("Cannot copy string content");
+ return ENOMEM;
+ }
+ rval = avro_string_set_private(datum, string_copy, 0,
+ avro_str_free_wrapper);
+ if (rval) {
+ avro_str_free(string_copy);
+ }
+ return rval;
+}
+
+int avro_givestring_set(avro_datum_t datum, const char *p,
+ avro_free_func_t free)
+{
+ int64_t size = strlen(p)+1;
+ return avro_string_set_private(datum, p, size, free);
+}
+
+static avro_datum_t avro_bytes_private(char *bytes, int64_t size,
+ avro_free_func_t bytes_free)
+{
+ struct avro_bytes_datum_t *datum;
+ datum = (struct avro_bytes_datum_t *) avro_new(struct avro_bytes_datum_t);
+ if (!datum) {
+ avro_set_error("Cannot create new bytes datum");
+ return NULL;
+ }
+ datum->bytes = bytes;
+ datum->size = size;
+ datum->free = bytes_free;
+
+ avro_datum_init(&datum->obj, AVRO_BYTES);
+ return &datum->obj;
+}
+
+avro_datum_t avro_bytes(const char *bytes, int64_t size)
+{
+ char *bytes_copy = (char *) avro_malloc(size);
+ if (!bytes_copy) {
+ avro_set_error("Cannot copy bytes content");
+ return NULL;
+ }
+ memcpy(bytes_copy, bytes, size);
+ avro_datum_t result =
+ avro_bytes_private(bytes_copy, size, avro_alloc_free_func);
+ if (result == NULL) {
+ avro_free(bytes_copy, size);
+ }
+ return result;
+}
+
+avro_datum_t avro_givebytes(const char *bytes, int64_t size,
+ avro_free_func_t free)
+{
+ return avro_bytes_private((char *)bytes, size, free);
+}
+
+static int avro_bytes_set_private(avro_datum_t datum, const char *bytes,
+ const int64_t size,
+ avro_free_func_t bytes_free)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_bytes(datum), "bytes datum");
+
+ struct avro_bytes_datum_t *b = avro_datum_to_bytes(datum);
+ if (b->free) {
+ b->free(b->bytes, b->size);
+ }
+
+ b->free = bytes_free;
+ b->bytes = (char *)bytes;
+ b->size = size;
+ return 0;
+}
+
+int avro_bytes_set(avro_datum_t datum, const char *bytes, const int64_t size)
+{
+ int rval;
+ char *bytes_copy = (char *) avro_malloc(size);
+ if (!bytes_copy) {
+ avro_set_error("Cannot copy bytes content");
+ return ENOMEM;
+ }
+ memcpy(bytes_copy, bytes, size);
+ rval = avro_bytes_set_private(datum, bytes_copy, size, avro_alloc_free_func);
+ if (rval) {
+ avro_free(bytes_copy, size);
+ }
+ return rval;
+}
+
+int avro_givebytes_set(avro_datum_t datum, const char *bytes,
+ const int64_t size, avro_free_func_t free)
+{
+ return avro_bytes_set_private(datum, bytes, size, free);
+}
+
+int avro_bytes_get(avro_datum_t datum, char **bytes, int64_t * size)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_bytes(datum), "bytes datum");
+ check_param(EINVAL, bytes, "bytes");
+ check_param(EINVAL, size, "size");
+
+ *bytes = avro_datum_to_bytes(datum)->bytes;
+ *size = avro_datum_to_bytes(datum)->size;
+ return 0;
+}
+
+avro_datum_t avro_int32(int32_t i)
+{
+ struct avro_int32_datum_t *datum =
+ (struct avro_int32_datum_t *) avro_new(struct avro_int32_datum_t);
+ if (!datum) {
+ avro_set_error("Cannot create new int datum");
+ return NULL;
+ }
+ datum->i32 = i;
+
+ avro_datum_init(&datum->obj, AVRO_INT32);
+ return &datum->obj;
+}
+
+int avro_int32_get(avro_datum_t datum, int32_t * i)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_int32(datum), "int datum");
+ check_param(EINVAL, i, "value pointer");
+
+ *i = avro_datum_to_int32(datum)->i32;
+ return 0;
+}
+
+int avro_int32_set(avro_datum_t datum, const int32_t i)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_int32(datum), "int datum");
+
+ avro_datum_to_int32(datum)->i32 = i;
+ return 0;
+}
+
+avro_datum_t avro_int64(int64_t l)
+{
+ struct avro_int64_datum_t *datum =
+ (struct avro_int64_datum_t *) avro_new(struct avro_int64_datum_t);
+ if (!datum) {
+ avro_set_error("Cannot create new long datum");
+ return NULL;
+ }
+ datum->i64 = l;
+
+ avro_datum_init(&datum->obj, AVRO_INT64);
+ return &datum->obj;
+}
+
+int avro_int64_get(avro_datum_t datum, int64_t * l)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_int64(datum), "long datum");
+ check_param(EINVAL, l, "value pointer");
+
+ *l = avro_datum_to_int64(datum)->i64;
+ return 0;
+}
+
+int avro_int64_set(avro_datum_t datum, const int64_t l)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_int64(datum), "long datum");
+
+ avro_datum_to_int64(datum)->i64 = l;
+ return 0;
+}
+
+avro_datum_t avro_float(float f)
+{
+ struct avro_float_datum_t *datum =
+ (struct avro_float_datum_t *) avro_new(struct avro_float_datum_t);
+ if (!datum) {
+ avro_set_error("Cannot create new float datum");
+ return NULL;
+ }
+ datum->f = f;
+
+ avro_datum_init(&datum->obj, AVRO_FLOAT);
+ return &datum->obj;
+}
+
+int avro_float_set(avro_datum_t datum, const float f)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_float(datum), "float datum");
+
+ avro_datum_to_float(datum)->f = f;
+ return 0;
+}
+
+int avro_float_get(avro_datum_t datum, float *f)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_float(datum), "float datum");
+ check_param(EINVAL, f, "value pointer");
+
+ *f = avro_datum_to_float(datum)->f;
+ return 0;
+}
+
+avro_datum_t avro_double(double d)
+{
+ struct avro_double_datum_t *datum =
+ (struct avro_double_datum_t *) avro_new(struct avro_double_datum_t);
+ if (!datum) {
+ avro_set_error("Cannot create new double atom");
+ return NULL;
+ }
+ datum->d = d;
+
+ avro_datum_init(&datum->obj, AVRO_DOUBLE);
+ return &datum->obj;
+}
+
+int avro_double_set(avro_datum_t datum, const double d)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_double(datum), "double datum");
+
+ avro_datum_to_double(datum)->d = d;
+ return 0;
+}
+
+int avro_double_get(avro_datum_t datum, double *d)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_double(datum), "double datum");
+ check_param(EINVAL, d, "value pointer");
+
+ *d = avro_datum_to_double(datum)->d;
+ return 0;
+}
+
+avro_datum_t avro_boolean(int8_t i)
+{
+ struct avro_boolean_datum_t *datum =
+ (struct avro_boolean_datum_t *) avro_new(struct avro_boolean_datum_t);
+ if (!datum) {
+ avro_set_error("Cannot create new boolean datum");
+ return NULL;
+ }
+ datum->i = i;
+ avro_datum_init(&datum->obj, AVRO_BOOLEAN);
+ return &datum->obj;
+}
+
+int avro_boolean_set(avro_datum_t datum, const int8_t i)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_boolean(datum), "boolean datum");
+
+ avro_datum_to_boolean(datum)->i = i;
+ return 0;
+}
+
+int avro_boolean_get(avro_datum_t datum, int8_t * i)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_boolean(datum), "boolean datum");
+ check_param(EINVAL, i, "value pointer");
+
+ *i = avro_datum_to_boolean(datum)->i;
+ return 0;
+}
+
+avro_datum_t avro_null(void)
+{
+ static struct avro_obj_t obj = {
+ AVRO_NULL,
+ AVRO_DATUM,
+ 1
+ };
+ return avro_datum_incref(&obj);
+}
+
+avro_datum_t avro_union(avro_schema_t schema,
+ int64_t discriminant, avro_datum_t value)
+{
+ check_param(NULL, is_avro_schema(schema), "schema");
+
+ struct avro_union_datum_t *datum =
+ (struct avro_union_datum_t *) avro_new(struct avro_union_datum_t);
+ if (!datum) {
+ avro_set_error("Cannot create new union datum");
+ return NULL;
+ }
+ datum->schema = avro_schema_incref(schema);
+ datum->discriminant = discriminant;
+ datum->value = avro_datum_incref(value);
+
+ avro_datum_init(&datum->obj, AVRO_UNION);
+ return &datum->obj;
+}
+
+int64_t avro_union_discriminant(const avro_datum_t datum)
+{
+ return avro_datum_to_union(datum)->discriminant;
+}
+
+avro_datum_t avro_union_current_branch(avro_datum_t datum)
+{
+ return avro_datum_to_union(datum)->value;
+}
+
+int avro_union_set_discriminant(avro_datum_t datum,
+ int discriminant,
+ avro_datum_t *branch)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_union(datum), "union datum");
+
+ struct avro_union_datum_t *unionp = avro_datum_to_union(datum);
+
+ avro_schema_t schema = unionp->schema;
+ avro_schema_t branch_schema =
+ avro_schema_union_branch(schema, discriminant);
+
+ if (branch_schema == NULL) {
+ // That branch doesn't exist!
+ avro_set_error("Branch %d doesn't exist", discriminant);
+ return EINVAL;
+ }
+
+ if (unionp->discriminant != discriminant) {
+ // If we're changing the branch, throw away any old
+ // branch value.
+ if (unionp->value != NULL) {
+ avro_datum_decref(unionp->value);
+ unionp->value = NULL;
+ }
+
+ unionp->discriminant = discriminant;
+ }
+
+ // Create a new branch value, if there isn't one already.
+ if (unionp->value == NULL) {
+ unionp->value = avro_datum_from_schema(branch_schema);
+ }
+
+ if (branch != NULL) {
+ *branch = unionp->value;
+ }
+
+ return 0;
+}
+
+avro_datum_t avro_record(avro_schema_t schema)
+{
+ check_param(NULL, is_avro_schema(schema), "schema");
+
+ struct avro_record_datum_t *datum =
+ (struct avro_record_datum_t *) avro_new(struct avro_record_datum_t);
+ if (!datum) {
+ avro_set_error("Cannot create new record datum");
+ return NULL;
+ }
+ datum->field_order = st_init_numtable_with_size(DEFAULT_TABLE_SIZE);
+ if (!datum->field_order) {
+ avro_set_error("Cannot create new record datum");
+ avro_freet(struct avro_record_datum_t, datum);
+ return NULL;
+ }
+ datum->fields_byname = st_init_strtable_with_size(DEFAULT_TABLE_SIZE);
+ if (!datum->fields_byname) {
+ avro_set_error("Cannot create new record datum");
+ st_free_table(datum->field_order);
+ avro_freet(struct avro_record_datum_t, datum);
+ return NULL;
+ }
+
+ datum->schema = avro_schema_incref(schema);
+ avro_datum_init(&datum->obj, AVRO_RECORD);
+ return &datum->obj;
+}
+
+int
+avro_record_get(const avro_datum_t datum, const char *field_name,
+ avro_datum_t * field)
+{
+ union {
+ avro_datum_t field;
+ st_data_t data;
+ } val;
+ if (is_avro_datum(datum) && is_avro_record(datum) && field_name) {
+ if (st_lookup
+ (avro_datum_to_record(datum)->fields_byname,
+ (st_data_t) field_name, &(val.data))) {
+ *field = val.field;
+ return 0;
+ }
+ }
+ avro_set_error("No field named %s", field_name);
+ return EINVAL;
+}
+
+int
+avro_record_set(avro_datum_t datum, const char *field_name,
+ const avro_datum_t field_value)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_record(datum), "record datum");
+ check_param(EINVAL, field_name, "field_name");
+
+ char *key = (char *)field_name;
+ avro_datum_t old_field;
+
+ if (avro_record_get(datum, field_name, &old_field) == 0) {
+ /* Overriding old value */
+ avro_datum_decref(old_field);
+ } else {
+ /* Inserting new value */
+ struct avro_record_datum_t *record =
+ avro_datum_to_record(datum);
+ key = avro_strdup(field_name);
+ if (!key) {
+ avro_set_error("Cannot copy field name");
+ return ENOMEM;
+ }
+ st_insert(record->field_order,
+ record->field_order->num_entries,
+ (st_data_t) key);
+ }
+ avro_datum_incref(field_value);
+ st_insert(avro_datum_to_record(datum)->fields_byname,
+ (st_data_t) key, (st_data_t) field_value);
+ return 0;
+}
+
+avro_datum_t avro_enum(avro_schema_t schema, int i)
+{
+ check_param(NULL, is_avro_schema(schema), "schema");
+
+ struct avro_enum_datum_t *datum =
+ (struct avro_enum_datum_t *) avro_new(struct avro_enum_datum_t);
+ if (!datum) {
+ avro_set_error("Cannot create new enum datum");
+ return NULL;
+ }
+ datum->schema = avro_schema_incref(schema);
+ datum->value = i;
+
+ avro_datum_init(&datum->obj, AVRO_ENUM);
+ return &datum->obj;
+}
+
+int avro_enum_get(const avro_datum_t datum)
+{
+ return avro_datum_to_enum(datum)->value;
+}
+
+const char *avro_enum_get_name(const avro_datum_t datum)
+{
+ int value = avro_enum_get(datum);
+ avro_schema_t schema = avro_datum_to_enum(datum)->schema;
+ return avro_schema_enum_get(schema, value);
+}
+
+int avro_enum_set(avro_datum_t datum, const int symbol_value)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_enum(datum), "enum datum");
+
+ avro_datum_to_enum(datum)->value = symbol_value;
+ return 0;
+}
+
+int avro_enum_set_name(avro_datum_t datum, const char *symbol_name)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_enum(datum), "enum datum");
+ check_param(EINVAL, symbol_name, "symbol name");
+
+ avro_schema_t schema = avro_datum_to_enum(datum)->schema;
+ int symbol_value = avro_schema_enum_get_by_name(schema, symbol_name);
+ if (symbol_value == -1) {
+ avro_set_error("No symbol named %s", symbol_name);
+ return EINVAL;
+ }
+ avro_datum_to_enum(datum)->value = symbol_value;
+ return 0;
+}
+
+static avro_datum_t avro_fixed_private(avro_schema_t schema,
+ const char *bytes, const int64_t size,
+ avro_free_func_t fixed_free)
+{
+ check_param(NULL, is_avro_schema(schema), "schema");
+ struct avro_fixed_schema_t *fschema = avro_schema_to_fixed(schema);
+ if (size != fschema->size) {
+ avro_free((char *) bytes, size);
+ avro_set_error("Fixed size (%zu) doesn't match schema (%zu)",
+ (size_t) size, (size_t) fschema->size);
+ return NULL;
+ }
+
+ struct avro_fixed_datum_t *datum =
+ (struct avro_fixed_datum_t *) avro_new(struct avro_fixed_datum_t);
+ if (!datum) {
+ avro_free((char *) bytes, size);
+ avro_set_error("Cannot create new fixed datum");
+ return NULL;
+ }
+ datum->schema = avro_schema_incref(schema);
+ datum->size = size;
+ datum->bytes = (char *)bytes;
+ datum->free = fixed_free;
+
+ avro_datum_init(&datum->obj, AVRO_FIXED);
+ return &datum->obj;
+}
+
+avro_datum_t avro_fixed(avro_schema_t schema,
+ const char *bytes, const int64_t size)
+{
+ char *bytes_copy = (char *) avro_malloc(size);
+ if (!bytes_copy) {
+ avro_set_error("Cannot copy fixed content");
+ return NULL;
+ }
+ memcpy(bytes_copy, bytes, size);
+ return avro_fixed_private(schema, bytes_copy, size, avro_alloc_free_func);
+}
+
+avro_datum_t avro_givefixed(avro_schema_t schema,
+ const char *bytes, const int64_t size,
+ avro_free_func_t free)
+{
+ return avro_fixed_private(schema, bytes, size, free);
+}
+
+static int avro_fixed_set_private(avro_datum_t datum,
+ const char *bytes, const int64_t size,
+ avro_free_func_t fixed_free)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_fixed(datum), "fixed datum");
+
+ struct avro_fixed_datum_t *fixed = avro_datum_to_fixed(datum);
+ struct avro_fixed_schema_t *schema = avro_schema_to_fixed(fixed->schema);
+ if (size != schema->size) {
+ avro_set_error("Fixed size doesn't match schema");
+ return EINVAL;
+ }
+
+ if (fixed->free) {
+ fixed->free(fixed->bytes, fixed->size);
+ }
+
+ fixed->free = fixed_free;
+ fixed->bytes = (char *)bytes;
+ fixed->size = size;
+ return 0;
+}
+
+int avro_fixed_set(avro_datum_t datum, const char *bytes, const int64_t size)
+{
+ int rval;
+ char *bytes_copy = (char *) avro_malloc(size);
+ if (!bytes_copy) {
+ avro_set_error("Cannot copy fixed content");
+ return ENOMEM;
+ }
+ memcpy(bytes_copy, bytes, size);
+ rval = avro_fixed_set_private(datum, bytes_copy, size, avro_alloc_free_func);
+ if (rval) {
+ avro_free(bytes_copy, size);
+ }
+ return rval;
+}
+
+int avro_givefixed_set(avro_datum_t datum, const char *bytes,
+ const int64_t size, avro_free_func_t free)
+{
+ return avro_fixed_set_private(datum, bytes, size, free);
+}
+
+int avro_fixed_get(avro_datum_t datum, char **bytes, int64_t * size)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_fixed(datum), "fixed datum");
+ check_param(EINVAL, bytes, "bytes");
+ check_param(EINVAL, size, "size");
+
+ *bytes = avro_datum_to_fixed(datum)->bytes;
+ *size = avro_datum_to_fixed(datum)->size;
+ return 0;
+}
+
+static int
+avro_init_map(struct avro_map_datum_t *datum)
+{
+ datum->map = st_init_strtable_with_size(DEFAULT_TABLE_SIZE);
+ if (!datum->map) {
+ avro_set_error("Cannot create new map datum");
+ return ENOMEM;
+ }
+ datum->indices_by_key = st_init_strtable_with_size(DEFAULT_TABLE_SIZE);
+ if (!datum->indices_by_key) {
+ avro_set_error("Cannot create new map datum");
+ st_free_table(datum->map);
+ return ENOMEM;
+ }
+ datum->keys_by_index = st_init_numtable_with_size(DEFAULT_TABLE_SIZE);
+ if (!datum->keys_by_index) {
+ avro_set_error("Cannot create new map datum");
+ st_free_table(datum->indices_by_key);
+ st_free_table(datum->map);
+ return ENOMEM;
+ }
+ return 0;
+}
+
+avro_datum_t avro_map(avro_schema_t schema)
+{
+ check_param(NULL, is_avro_schema(schema), "schema");
+
+ struct avro_map_datum_t *datum =
+ (struct avro_map_datum_t *) avro_new(struct avro_map_datum_t);
+ if (!datum) {
+ avro_set_error("Cannot create new map datum");
+ return NULL;
+ }
+
+ if (avro_init_map(datum) != 0) {
+ avro_freet(struct avro_map_datum_t, datum);
+ return NULL;
+ }
+
+ datum->schema = avro_schema_incref(schema);
+ avro_datum_init(&datum->obj, AVRO_MAP);
+ return &datum->obj;
+}
+
+size_t
+avro_map_size(const avro_datum_t datum)
+{
+ const struct avro_map_datum_t *map = avro_datum_to_map(datum);
+ return map->map->num_entries;
+}
+
+int
+avro_map_get(const avro_datum_t datum, const char *key, avro_datum_t * value)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_map(datum), "map datum");
+ check_param(EINVAL, key, "key");
+ check_param(EINVAL, value, "value");
+
+ union {
+ avro_datum_t datum;
+ st_data_t data;
+ } val;
+
+ struct avro_map_datum_t *map = avro_datum_to_map(datum);
+ if (st_lookup(map->map, (st_data_t) key, &(val.data))) {
+ *value = val.datum;
+ return 0;
+ }
+
+ avro_set_error("No map element named %s", key);
+ return EINVAL;
+}
+
+int avro_map_get_key(const avro_datum_t datum, int index,
+ const char **key)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_map(datum), "map datum");
+ check_param(EINVAL, index >= 0, "index");
+ check_param(EINVAL, key, "key");
+
+ union {
+ st_data_t data;
+ char *key;
+ } val;
+
+ struct avro_map_datum_t *map = avro_datum_to_map(datum);
+ if (st_lookup(map->keys_by_index, (st_data_t) index, &val.data)) {
+ *key = val.key;
+ return 0;
+ }
+
+ avro_set_error("No map element with index %d", index);
+ return EINVAL;
+}
+
+int avro_map_get_index(const avro_datum_t datum, const char *key,
+ int *index)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_map(datum), "map datum");
+ check_param(EINVAL, key, "key");
+ check_param(EINVAL, index, "index");
+
+ st_data_t data;
+
+ struct avro_map_datum_t *map = avro_datum_to_map(datum);
+ if (st_lookup(map->indices_by_key, (st_data_t) key, &data)) {
+ *index = (int) data;
+ return 0;
+ }
+
+ avro_set_error("No map element with key %s", key);
+ return EINVAL;
+}
+
+int
+avro_map_set(avro_datum_t datum, const char *key,
+ const avro_datum_t value)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ check_param(EINVAL, is_avro_map(datum), "map datum");
+ check_param(EINVAL, key, "key");
+ check_param(EINVAL, is_avro_datum(value), "value");
+
+ char *save_key = (char *)key;
+ avro_datum_t old_datum;
+
+ struct avro_map_datum_t *map = avro_datum_to_map(datum);
+
+ if (avro_map_get(datum, key, &old_datum) == 0) {
+ /* Overwriting an old value */
+ avro_datum_decref(old_datum);
+ } else {
+ /* Inserting a new value */
+ save_key = avro_strdup(key);
+ if (!save_key) {
+ avro_set_error("Cannot copy map key");
+ return ENOMEM;
+ }
+ int new_index = map->map->num_entries;
+ st_insert(map->indices_by_key, (st_data_t) save_key,
+ (st_data_t) new_index);
+ st_insert(map->keys_by_index, (st_data_t) new_index,
+ (st_data_t) save_key);
+ }
+ avro_datum_incref(value);
+ st_insert(map->map, (st_data_t) save_key, (st_data_t) value);
+ return 0;
+}
+
+static int
+avro_init_array(struct avro_array_datum_t *datum)
+{
+ datum->els = st_init_numtable_with_size(DEFAULT_TABLE_SIZE);
+ if (!datum->els) {
+ avro_set_error("Cannot create new array datum");
+ return ENOMEM;
+ }
+ return 0;
+}
+
+avro_datum_t avro_array(avro_schema_t schema)
+{
+ check_param(NULL, is_avro_schema(schema), "schema");
+
+ struct avro_array_datum_t *datum =
+ (struct avro_array_datum_t *) avro_new(struct avro_array_datum_t);
+ if (!datum) {
+ avro_set_error("Cannot create new array datum");
+ return NULL;
+ }
+
+ if (avro_init_array(datum) != 0) {
+ avro_freet(struct avro_array_datum_t, datum);
+ return NULL;
+ }
+
+ datum->schema = avro_schema_incref(schema);
+ avro_datum_init(&datum->obj, AVRO_ARRAY);
+ return &datum->obj;
+}
+
+int
+avro_array_get(const avro_datum_t array_datum, int64_t index, avro_datum_t * value)
+{
+ check_param(EINVAL, is_avro_datum(array_datum), "datum");
+ check_param(EINVAL, is_avro_array(array_datum), "array datum");
+ check_param(EINVAL, value, "value pointer");
+
+ union {
+ st_data_t data;
+ avro_datum_t datum;
+ } val;
+
+ const struct avro_array_datum_t * array = avro_datum_to_array(array_datum);
+ if (st_lookup(array->els, index, &val.data)) {
+ *value = val.datum;
+ return 0;
+ }
+
+ avro_set_error("No array element with index %ld", (long) index);
+ return EINVAL;
+}
+
+size_t
+avro_array_size(const avro_datum_t datum)
+{
+ const struct avro_array_datum_t *array = avro_datum_to_array(datum);
+ return array->els->num_entries;
+}
+
+int
+avro_array_append_datum(avro_datum_t array_datum,
+ const avro_datum_t datum)
+{
+ check_param(EINVAL, is_avro_datum(array_datum), "datum");
+ check_param(EINVAL, is_avro_array(array_datum), "array datum");
+ check_param(EINVAL, is_avro_datum(datum), "element datum");
+
+ struct avro_array_datum_t *array = avro_datum_to_array(array_datum);
+ st_insert(array->els, array->els->num_entries,
+ (st_data_t) avro_datum_incref(datum));
+ return 0;
+}
+
+static int char_datum_free_foreach(char *key, avro_datum_t datum, void *arg)
+{
+ AVRO_UNUSED(arg);
+
+ avro_datum_decref(datum);
+ avro_str_free(key);
+ return ST_DELETE;
+}
+
+static int array_free_foreach(int i, avro_datum_t datum, void *arg)
+{
+ AVRO_UNUSED(i);
+ AVRO_UNUSED(arg);
+
+ avro_datum_decref(datum);
+ return ST_DELETE;
+}
+
+avro_schema_t avro_datum_get_schema(const avro_datum_t datum)
+{
+ check_param(NULL, is_avro_datum(datum), "datum");
+
+ switch (avro_typeof(datum)) {
+ /*
+ * For the primitive types, which don't store an
+ * explicit reference to their schema, we decref the
+ * schema before returning. This maintains the
+ * invariant that this function doesn't add any
+ * additional references to the schema. The primitive
+ * schemas won't be freed, because there's always at
+ * least 1 reference for their initial static
+ * initializers.
+ */
+
+ case AVRO_STRING:
+ {
+ avro_schema_t result = avro_schema_string();
+ avro_schema_decref(result);
+ return result;
+ }
+ case AVRO_BYTES:
+ {
+ avro_schema_t result = avro_schema_bytes();
+ avro_schema_decref(result);
+ return result;
+ }
+ case AVRO_INT32:
+ {
+ avro_schema_t result = avro_schema_int();
+ avro_schema_decref(result);
+ return result;
+ }
+ case AVRO_INT64:
+ {
+ avro_schema_t result = avro_schema_long();
+ avro_schema_decref(result);
+ return result;
+ }
+ case AVRO_FLOAT:
+ {
+ avro_schema_t result = avro_schema_float();
+ avro_schema_decref(result);
+ return result;
+ }
+ case AVRO_DOUBLE:
+ {
+ avro_schema_t result = avro_schema_double();
+ avro_schema_decref(result);
+ return result;
+ }
+ case AVRO_BOOLEAN:
+ {
+ avro_schema_t result = avro_schema_boolean();
+ avro_schema_decref(result);
+ return result;
+ }
+ case AVRO_NULL:
+ {
+ avro_schema_t result = avro_schema_null();
+ avro_schema_decref(result);
+ return result;
+ }
+
+ case AVRO_RECORD:
+ return avro_datum_to_record(datum)->schema;
+ case AVRO_ENUM:
+ return avro_datum_to_enum(datum)->schema;
+ case AVRO_FIXED:
+ return avro_datum_to_fixed(datum)->schema;
+ case AVRO_MAP:
+ return avro_datum_to_map(datum)->schema;
+ case AVRO_ARRAY:
+ return avro_datum_to_array(datum)->schema;
+ case AVRO_UNION:
+ return avro_datum_to_union(datum)->schema;
+
+ default:
+ return NULL;
+ }
+}
+
+static void avro_datum_free(avro_datum_t datum)
+{
+ if (is_avro_datum(datum)) {
+ switch (avro_typeof(datum)) {
+ case AVRO_STRING:{
+ struct avro_string_datum_t *string;
+ string = avro_datum_to_string(datum);
+ if (string->free) {
+ string->free(string->s, string->size);
+ }
+ avro_freet(struct avro_string_datum_t, string);
+ }
+ break;
+ case AVRO_BYTES:{
+ struct avro_bytes_datum_t *bytes;
+ bytes = avro_datum_to_bytes(datum);
+ if (bytes->free) {
+ bytes->free(bytes->bytes, bytes->size);
+ }
+ avro_freet(struct avro_bytes_datum_t, bytes);
+ }
+ break;
+ case AVRO_INT32:{
+ avro_freet(struct avro_int32_datum_t, datum);
+ }
+ break;
+ case AVRO_INT64:{
+ avro_freet(struct avro_int64_datum_t, datum);
+ }
+ break;
+ case AVRO_FLOAT:{
+ avro_freet(struct avro_float_datum_t, datum);
+ }
+ break;
+ case AVRO_DOUBLE:{
+ avro_freet(struct avro_double_datum_t, datum);
+ }
+ break;
+ case AVRO_BOOLEAN:{
+ avro_freet(struct avro_boolean_datum_t, datum);
+ }
+ break;
+ case AVRO_NULL:
+ /* Nothing allocated */
+ break;
+
+ case AVRO_RECORD:{
+ struct avro_record_datum_t *record;
+ record = avro_datum_to_record(datum);
+ avro_schema_decref(record->schema);
+ st_foreach(record->fields_byname,
+ HASH_FUNCTION_CAST char_datum_free_foreach, 0);
+ st_free_table(record->field_order);
+ st_free_table(record->fields_byname);
+ avro_freet(struct avro_record_datum_t, record);
+ }
+ break;
+ case AVRO_ENUM:{
+ struct avro_enum_datum_t *enump;
+ enump = avro_datum_to_enum(datum);
+ avro_schema_decref(enump->schema);
+ avro_freet(struct avro_enum_datum_t, enump);
+ }
+ break;
+ case AVRO_FIXED:{
+ struct avro_fixed_datum_t *fixed;
+ fixed = avro_datum_to_fixed(datum);
+ avro_schema_decref(fixed->schema);
+ if (fixed->free) {
+ fixed->free((void *)fixed->bytes,
+ fixed->size);
+ }
+ avro_freet(struct avro_fixed_datum_t, fixed);
+ }
+ break;
+ case AVRO_MAP:{
+ struct avro_map_datum_t *map;
+ map = avro_datum_to_map(datum);
+ avro_schema_decref(map->schema);
+ st_foreach(map->map, HASH_FUNCTION_CAST char_datum_free_foreach,
+ 0);
+ st_free_table(map->map);
+ st_free_table(map->indices_by_key);
+ st_free_table(map->keys_by_index);
+ avro_freet(struct avro_map_datum_t, map);
+ }
+ break;
+ case AVRO_ARRAY:{
+ struct avro_array_datum_t *array;
+ array = avro_datum_to_array(datum);
+ avro_schema_decref(array->schema);
+ st_foreach(array->els, HASH_FUNCTION_CAST array_free_foreach, 0);
+ st_free_table(array->els);
+ avro_freet(struct avro_array_datum_t, array);
+ }
+ break;
+ case AVRO_UNION:{
+ struct avro_union_datum_t *unionp;
+ unionp = avro_datum_to_union(datum);
+ avro_schema_decref(unionp->schema);
+ avro_datum_decref(unionp->value);
+ avro_freet(struct avro_union_datum_t, unionp);
+ }
+ break;
+ case AVRO_LINK:{
+ /* TODO */
+ }
+ break;
+ }
+ }
+}
+
+static int
+datum_reset_foreach(int i, avro_datum_t datum, void *arg)
+{
+ AVRO_UNUSED(i);
+ int rval;
+ int *result = (int *) arg;
+
+ rval = avro_datum_reset(datum);
+ if (rval == 0) {
+ return ST_CONTINUE;
+ } else {
+ *result = rval;
+ return ST_STOP;
+ }
+}
+
+int
+avro_datum_reset(avro_datum_t datum)
+{
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+ int rval;
+
+ switch (avro_typeof(datum)) {
+ case AVRO_ARRAY:
+ {
+ struct avro_array_datum_t *array;
+ array = avro_datum_to_array(datum);
+ st_foreach(array->els, HASH_FUNCTION_CAST array_free_foreach, 0);
+ st_free_table(array->els);
+
+ rval = avro_init_array(array);
+ if (rval != 0) {
+ avro_freet(struct avro_array_datum_t, array);
+ return rval;
+ }
+ return 0;
+ }
+
+ case AVRO_MAP:
+ {
+ struct avro_map_datum_t *map;
+ map = avro_datum_to_map(datum);
+ st_foreach(map->map, HASH_FUNCTION_CAST char_datum_free_foreach, 0);
+ st_free_table(map->map);
+ st_free_table(map->indices_by_key);
+ st_free_table(map->keys_by_index);
+
+ rval = avro_init_map(map);
+ if (rval != 0) {
+ avro_freet(struct avro_map_datum_t, map);
+ return rval;
+ }
+ return 0;
+ }
+
+ case AVRO_RECORD:
+ {
+ struct avro_record_datum_t *record;
+ record = avro_datum_to_record(datum);
+ rval = 0;
+ st_foreach(record->fields_byname,
+ HASH_FUNCTION_CAST datum_reset_foreach, (st_data_t) &rval);
+ return rval;
+ }
+
+ case AVRO_UNION:
+ {
+ struct avro_union_datum_t *unionp;
+ unionp = avro_datum_to_union(datum);
+ return (unionp->value == NULL)? 0:
+ avro_datum_reset(unionp->value);
+ }
+
+ default:
+ return 0;
+ }
+}
+
+avro_datum_t avro_datum_incref(avro_datum_t datum)
+{
+ if (datum) {
+ avro_refcount_inc(&datum->refcount);
+ }
+ return datum;
+}
+
+void avro_datum_decref(avro_datum_t datum)
+{
+ if (datum && avro_refcount_dec(&datum->refcount)) {
+ avro_datum_free(datum);
+ }
+}
+
+void avro_datum_print(avro_datum_t value, FILE * fp)
+{
+ AVRO_UNUSED(value);
+ AVRO_UNUSED(fp);
+}
diff --git a/fluent-bit/lib/avro/src/datum.h b/fluent-bit/lib/avro/src/datum.h
new file mode 100644
index 000000000..c09542b3f
--- /dev/null
+++ b/fluent-bit/lib/avro/src/datum.h
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef AVRO_DATUM_H
+#define AVRO_DATUM_H
+#include <avro/platform.h>
+#include "avro/basics.h"
+#include "avro/data.h"
+#include "avro/legacy.h"
+#include "avro/schema.h"
+#include "avro_private.h"
+#include "st.h"
+
+struct avro_string_datum_t {
+ struct avro_obj_t obj;
+ char *s;
+ int64_t size;
+ avro_free_func_t free;
+};
+
+struct avro_bytes_datum_t {
+ struct avro_obj_t obj;
+ char *bytes;
+ int64_t size;
+ avro_free_func_t free;
+};
+
+struct avro_int32_datum_t {
+ struct avro_obj_t obj;
+ int32_t i32;
+};
+
+struct avro_int64_datum_t {
+ struct avro_obj_t obj;
+ int64_t i64;
+};
+
+struct avro_float_datum_t {
+ struct avro_obj_t obj;
+ float f;
+};
+
+struct avro_double_datum_t {
+ struct avro_obj_t obj;
+ double d;
+};
+
+struct avro_boolean_datum_t {
+ struct avro_obj_t obj;
+ int8_t i;
+};
+
+struct avro_fixed_datum_t {
+ struct avro_obj_t obj;
+ avro_schema_t schema;
+ char *bytes;
+ int64_t size;
+ avro_free_func_t free;
+};
+
+struct avro_map_datum_t {
+ struct avro_obj_t obj;
+ avro_schema_t schema;
+ st_table *map;
+ st_table *indices_by_key;
+ st_table *keys_by_index;
+};
+
+struct avro_record_datum_t {
+ struct avro_obj_t obj;
+ avro_schema_t schema;
+ st_table *field_order;
+ st_table *fields_byname;
+};
+
+struct avro_enum_datum_t {
+ struct avro_obj_t obj;
+ avro_schema_t schema;
+ int value;
+};
+
+struct avro_array_datum_t {
+ struct avro_obj_t obj;
+ avro_schema_t schema;
+ st_table *els;
+};
+
+struct avro_union_datum_t {
+ struct avro_obj_t obj;
+ avro_schema_t schema;
+ int64_t discriminant;
+ avro_datum_t value;
+};
+
+#define avro_datum_to_string(datum_) (container_of(datum_, struct avro_string_datum_t, obj))
+#define avro_datum_to_bytes(datum_) (container_of(datum_, struct avro_bytes_datum_t, obj))
+#define avro_datum_to_int32(datum_) (container_of(datum_, struct avro_int32_datum_t, obj))
+#define avro_datum_to_int64(datum_) (container_of(datum_, struct avro_int64_datum_t, obj))
+#define avro_datum_to_float(datum_) (container_of(datum_, struct avro_float_datum_t, obj))
+#define avro_datum_to_double(datum_) (container_of(datum_, struct avro_double_datum_t, obj))
+#define avro_datum_to_boolean(datum_) (container_of(datum_, struct avro_boolean_datum_t, obj))
+#define avro_datum_to_fixed(datum_) (container_of(datum_, struct avro_fixed_datum_t, obj))
+#define avro_datum_to_map(datum_) (container_of(datum_, struct avro_map_datum_t, obj))
+#define avro_datum_to_record(datum_) (container_of(datum_, struct avro_record_datum_t, obj))
+#define avro_datum_to_enum(datum_) (container_of(datum_, struct avro_enum_datum_t, obj))
+#define avro_datum_to_array(datum_) (container_of(datum_, struct avro_array_datum_t, obj))
+#define avro_datum_to_union(datum_) (container_of(datum_, struct avro_union_datum_t, obj))
+
+#endif
diff --git a/fluent-bit/lib/avro/src/datum_equal.c b/fluent-bit/lib/avro/src/datum_equal.c
new file mode 100644
index 000000000..2ef750f9b
--- /dev/null
+++ b/fluent-bit/lib/avro/src/datum_equal.c
@@ -0,0 +1,186 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include "avro_private.h"
+#include <string.h>
+#include "datum.h"
+
+static int
+array_equal(struct avro_array_datum_t *a, struct avro_array_datum_t *b)
+{
+ if (!avro_schema_equal(a->schema, b->schema)) {
+ return 0;
+ }
+
+ long i;
+
+ if (a->els->num_entries != b->els->num_entries) {
+ return 0;
+ }
+ for (i = 0; i < a->els->num_entries; i++) {
+ union {
+ st_data_t data;
+ avro_datum_t datum;
+ } ael, bel;
+ st_lookup(a->els, i, &ael.data);
+ st_lookup(b->els, i, &bel.data);
+ if (!avro_datum_equal(ael.datum, bel.datum)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+struct st_equal_args {
+ int rval;
+ st_table *st;
+};
+
+static int
+st_equal_foreach(char *key, avro_datum_t datum, struct st_equal_args *args)
+{
+ union {
+ avro_datum_t datum_other;
+ st_data_t data;
+ } val;
+ if (!st_lookup(args->st, (st_data_t) key, &(val.data))) {
+ args->rval = 0;
+ return ST_STOP;
+ }
+ if (!avro_datum_equal(datum, val.datum_other)) {
+ args->rval = 0;
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
+static int map_equal(struct avro_map_datum_t *a, struct avro_map_datum_t *b)
+{
+ if (!avro_schema_equal(a->schema, b->schema)) {
+ return 0;
+ }
+
+ struct st_equal_args args = { 1, b->map };
+ if (a->map->num_entries != b->map->num_entries) {
+ return 0;
+ }
+ st_foreach(a->map, HASH_FUNCTION_CAST st_equal_foreach, (st_data_t) & args);
+ return args.rval;
+}
+
+static int record_equal(struct avro_record_datum_t *a,
+ struct avro_record_datum_t *b)
+{
+ if (!avro_schema_equal(a->schema, b->schema)) {
+ return 0;
+ }
+
+ struct st_equal_args args = { 1, b->fields_byname };
+ if (a->fields_byname->num_entries != b->fields_byname->num_entries) {
+ return 0;
+ }
+ st_foreach(a->fields_byname, HASH_FUNCTION_CAST st_equal_foreach, (st_data_t) & args);
+ return args.rval;
+}
+
+static int enum_equal(struct avro_enum_datum_t *a, struct avro_enum_datum_t *b)
+{
+ return avro_schema_equal(a->schema, b->schema) && a->value == b->value;
+}
+
+static int fixed_equal(struct avro_fixed_datum_t *a,
+ struct avro_fixed_datum_t *b)
+{
+ if (!avro_schema_equal(a->schema, b->schema)) {
+ return 0;
+ }
+
+ return a->size == b->size && memcmp(a->bytes, b->bytes, a->size) == 0;
+}
+
+static int union_equal(struct avro_union_datum_t *a,
+ struct avro_union_datum_t *b)
+{
+ if (!avro_schema_equal(a->schema, b->schema)) {
+ return 0;
+ }
+
+ return a->discriminant == b->discriminant && avro_datum_equal(a->value, b->value);
+}
+
+int avro_datum_equal(const avro_datum_t a, const avro_datum_t b)
+{
+ if (!(is_avro_datum(a) && is_avro_datum(b))) {
+ return 0;
+ }
+ if (avro_typeof(a) != avro_typeof(b)) {
+ return 0;
+ }
+ switch (avro_typeof(a)) {
+ case AVRO_STRING:
+ return strcmp(avro_datum_to_string(a)->s,
+ avro_datum_to_string(b)->s) == 0;
+ case AVRO_BYTES:
+ return (avro_datum_to_bytes(a)->size ==
+ avro_datum_to_bytes(b)->size)
+ && memcmp(avro_datum_to_bytes(a)->bytes,
+ avro_datum_to_bytes(b)->bytes,
+ avro_datum_to_bytes(a)->size) == 0;
+ case AVRO_INT32:
+ return avro_datum_to_int32(a)->i32 ==
+ avro_datum_to_int32(b)->i32;
+ case AVRO_INT64:
+ return avro_datum_to_int64(a)->i64 ==
+ avro_datum_to_int64(b)->i64;
+ case AVRO_FLOAT:
+ return avro_datum_to_float(a)->f == avro_datum_to_float(b)->f;
+ case AVRO_DOUBLE:
+ return avro_datum_to_double(a)->d == avro_datum_to_double(b)->d;
+ case AVRO_BOOLEAN:
+ return avro_datum_to_boolean(a)->i ==
+ avro_datum_to_boolean(b)->i;
+ case AVRO_NULL:
+ return 1;
+ case AVRO_ARRAY:
+ return array_equal(avro_datum_to_array(a),
+ avro_datum_to_array(b));
+ case AVRO_MAP:
+ return map_equal(avro_datum_to_map(a), avro_datum_to_map(b));
+
+ case AVRO_RECORD:
+ return record_equal(avro_datum_to_record(a),
+ avro_datum_to_record(b));
+
+ case AVRO_ENUM:
+ return enum_equal(avro_datum_to_enum(a), avro_datum_to_enum(b));
+
+ case AVRO_FIXED:
+ return fixed_equal(avro_datum_to_fixed(a),
+ avro_datum_to_fixed(b));
+
+ case AVRO_UNION:
+ return union_equal(avro_datum_to_union(a),
+ avro_datum_to_union(b));
+
+ case AVRO_LINK:
+ /*
+ * TODO
+ */
+ return 0;
+ }
+ return 0;
+}
diff --git a/fluent-bit/lib/avro/src/datum_read.c b/fluent-bit/lib/avro/src/datum_read.c
new file mode 100644
index 000000000..97bdd54f9
--- /dev/null
+++ b/fluent-bit/lib/avro/src/datum_read.c
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+
+#include "avro/errors.h"
+#include "avro/io.h"
+#include "avro/legacy.h"
+#include "avro/resolver.h"
+#include "avro/schema.h"
+#include "avro/value.h"
+#include "avro_private.h"
+
+int
+avro_schema_match(avro_schema_t wschema, avro_schema_t rschema)
+{
+ check_param(0, is_avro_schema(wschema), "writer schema");
+ check_param(0, is_avro_schema(rschema), "reader schema");
+
+ avro_value_iface_t *resolver =
+ avro_resolved_writer_new(wschema, rschema);
+ if (resolver != NULL) {
+ avro_value_iface_decref(resolver);
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+avro_read_data(avro_reader_t reader, avro_schema_t writers_schema,
+ avro_schema_t readers_schema, avro_datum_t * datum)
+{
+ int rval;
+
+ check_param(EINVAL, reader, "reader");
+ check_param(EINVAL, is_avro_schema(writers_schema), "writer schema");
+ check_param(EINVAL, datum, "datum pointer");
+
+ if (!readers_schema) {
+ readers_schema = writers_schema;
+ }
+
+ avro_datum_t result = avro_datum_from_schema(readers_schema);
+ if (!result) {
+ return EINVAL;
+ }
+
+ avro_value_t value;
+ check(rval, avro_datum_as_value(&value, result));
+
+ avro_value_iface_t *resolver =
+ avro_resolved_writer_new(writers_schema, readers_schema);
+ if (!resolver) {
+ avro_value_decref(&value);
+ avro_datum_decref(result);
+ return EINVAL;
+ }
+
+ avro_value_t resolved_value;
+ rval = avro_resolved_writer_new_value(resolver, &resolved_value);
+ if (rval) {
+ avro_value_iface_decref(resolver);
+ avro_value_decref(&value);
+ avro_datum_decref(result);
+ return rval;
+ }
+
+ avro_resolved_writer_set_dest(&resolved_value, &value);
+ rval = avro_value_read(reader, &resolved_value);
+ if (rval) {
+ avro_value_decref(&resolved_value);
+ avro_value_iface_decref(resolver);
+ avro_value_decref(&value);
+ avro_datum_decref(result);
+ return rval;
+ }
+
+ avro_value_decref(&resolved_value);
+ avro_value_iface_decref(resolver);
+ avro_value_decref(&value);
+ *datum = result;
+ return 0;
+}
diff --git a/fluent-bit/lib/avro/src/datum_size.c b/fluent-bit/lib/avro/src/datum_size.c
new file mode 100644
index 000000000..770cb655f
--- /dev/null
+++ b/fluent-bit/lib/avro/src/datum_size.c
@@ -0,0 +1,292 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include "avro_private.h"
+#include "avro/errors.h"
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include "schema.h"
+#include "datum.h"
+#include "encoding.h"
+
+#define size_check(rval, call) { rval = call; if(rval) return rval; }
+#define size_accum(rval, size, call) { rval = call; if (rval < 0) return rval; else size += rval; }
+
+static int64_t size_datum(avro_writer_t writer, const avro_encoding_t * enc,
+ avro_schema_t writers_schema, avro_datum_t datum);
+
+static int64_t
+size_record(avro_writer_t writer, const avro_encoding_t * enc,
+ struct avro_record_schema_t *schema, avro_datum_t datum)
+{
+ int rval;
+ long i;
+ int64_t size;
+ avro_datum_t field_datum;
+
+ size = 0;
+ if (schema) {
+ for (i = 0; i < schema->fields->num_entries; i++) {
+ union {
+ st_data_t data;
+ struct avro_record_field_t *field;
+ } val;
+ st_lookup(schema->fields, i, &val.data);
+ size_check(rval,
+ avro_record_get(datum, val.field->name,
+ &field_datum));
+ size_accum(rval, size,
+ size_datum(writer, enc, val.field->type,
+ field_datum));
+ }
+ } else {
+ /* No schema. Just write the record datum */
+ struct avro_record_datum_t *record =
+ avro_datum_to_record(datum);
+ for (i = 0; i < record->field_order->num_entries; i++) {
+ union {
+ st_data_t data;
+ char *name;
+ } val;
+ st_lookup(record->field_order, i, &val.data);
+ size_check(rval,
+ avro_record_get(datum, val.name,
+ &field_datum));
+ size_accum(rval, size,
+ size_datum(writer, enc, NULL, field_datum));
+ }
+ }
+ return size;
+}
+
+static int64_t
+size_enum(avro_writer_t writer, const avro_encoding_t * enc,
+ struct avro_enum_schema_t *enump, struct avro_enum_datum_t *datum)
+{
+ AVRO_UNUSED(enump);
+
+ return enc->size_long(writer, datum->value);
+}
+
+struct size_map_args {
+ int rval;
+ int64_t size;
+ avro_writer_t writer;
+ const avro_encoding_t *enc;
+ avro_schema_t values_schema;
+};
+
+static int
+size_map_foreach(char *key, avro_datum_t datum, struct size_map_args *args)
+{
+ int rval = args->enc->size_string(args->writer, key);
+ if (rval < 0) {
+ args->rval = rval;
+ return ST_STOP;
+ } else {
+ args->size += rval;
+ }
+ rval = size_datum(args->writer, args->enc, args->values_schema, datum);
+ if (rval < 0) {
+ args->rval = rval;
+ return ST_STOP;
+ } else {
+ args->size += rval;
+ }
+ return ST_CONTINUE;
+}
+
+static int64_t
+size_map(avro_writer_t writer, const avro_encoding_t * enc,
+ struct avro_map_schema_t *writers_schema,
+ struct avro_map_datum_t *datum)
+{
+ int rval;
+ int64_t size;
+ struct size_map_args args = { 0, 0, writer, enc,
+ writers_schema ? writers_schema->values : NULL
+ };
+
+ size = 0;
+ if (datum->map->num_entries) {
+ size_accum(rval, size,
+ enc->size_long(writer, datum->map->num_entries));
+ st_foreach(datum->map, HASH_FUNCTION_CAST size_map_foreach, (st_data_t) & args);
+ size += args.size;
+ }
+ if (!args.rval) {
+ size_accum(rval, size, enc->size_long(writer, 0));
+ }
+ return size;
+}
+
+static int64_t
+size_array(avro_writer_t writer, const avro_encoding_t * enc,
+ struct avro_array_schema_t *schema, struct avro_array_datum_t *array)
+{
+ int rval;
+ long i;
+ int64_t size;
+
+ size = 0;
+ if (array->els->num_entries) {
+ size_accum(rval, size,
+ enc->size_long(writer, array->els->num_entries));
+ for (i = 0; i < array->els->num_entries; i++) {
+ union {
+ st_data_t data;
+ avro_datum_t datum;
+ } val;
+ st_lookup(array->els, i, &val.data);
+ size_accum(rval, size,
+ size_datum(writer, enc,
+ schema ? schema->items : NULL,
+ val.datum));
+ }
+ }
+ size_accum(rval, size, enc->size_long(writer, 0));
+ return size;
+}
+
+static int64_t
+size_union(avro_writer_t writer, const avro_encoding_t * enc,
+ struct avro_union_schema_t *schema,
+ struct avro_union_datum_t *unionp)
+{
+ int rval;
+ int64_t size;
+ avro_schema_t write_schema = NULL;
+
+ size = 0;
+ size_accum(rval, size, enc->size_long(writer, unionp->discriminant));
+ if (schema) {
+ write_schema =
+ avro_schema_union_branch(&schema->obj, unionp->discriminant);
+ if (!write_schema) {
+ return -EINVAL;
+ }
+ }
+ size_accum(rval, size,
+ size_datum(writer, enc, write_schema, unionp->value));
+ return size;
+}
+
+static int64_t size_datum(avro_writer_t writer, const avro_encoding_t * enc,
+ avro_schema_t writers_schema, avro_datum_t datum)
+{
+ if (is_avro_schema(writers_schema) && is_avro_link(writers_schema)) {
+ return size_datum(writer, enc,
+ (avro_schema_to_link(writers_schema))->to,
+ datum);
+ }
+
+ switch (avro_typeof(datum)) {
+ case AVRO_NULL:
+ return enc->size_null(writer);
+
+ case AVRO_BOOLEAN:
+ return enc->size_boolean(writer,
+ avro_datum_to_boolean(datum)->i);
+
+ case AVRO_STRING:
+ return enc->size_string(writer, avro_datum_to_string(datum)->s);
+
+ case AVRO_BYTES:
+ return enc->size_bytes(writer,
+ avro_datum_to_bytes(datum)->bytes,
+ avro_datum_to_bytes(datum)->size);
+
+ case AVRO_INT32:
+ case AVRO_INT64:{
+ int64_t val = avro_typeof(datum) == AVRO_INT32 ?
+ avro_datum_to_int32(datum)->i32 :
+ avro_datum_to_int64(datum)->i64;
+ if (is_avro_schema(writers_schema)) {
+ /* handle promotion */
+ if (is_avro_float(writers_schema)) {
+ return enc->size_float(writer,
+ (float)val);
+ } else if (is_avro_double(writers_schema)) {
+ return enc->size_double(writer,
+ (double)val);
+ }
+ }
+ return enc->size_long(writer, val);
+ }
+
+ case AVRO_FLOAT:{
+ float val = avro_datum_to_float(datum)->f;
+ if (is_avro_schema(writers_schema)
+ && is_avro_double(writers_schema)) {
+ /* handle promotion */
+ return enc->size_double(writer, (double)val);
+ }
+ return enc->size_float(writer, val);
+ }
+
+ case AVRO_DOUBLE:
+ return enc->size_double(writer, avro_datum_to_double(datum)->d);
+
+ case AVRO_RECORD:
+ return size_record(writer, enc,
+ avro_schema_to_record(writers_schema),
+ datum);
+
+ case AVRO_ENUM:
+ return size_enum(writer, enc,
+ avro_schema_to_enum(writers_schema),
+ avro_datum_to_enum(datum));
+
+ case AVRO_FIXED:
+ return avro_datum_to_fixed(datum)->size;
+
+ case AVRO_MAP:
+ return size_map(writer, enc,
+ avro_schema_to_map(writers_schema),
+ avro_datum_to_map(datum));
+
+ case AVRO_ARRAY:
+ return size_array(writer, enc,
+ avro_schema_to_array(writers_schema),
+ avro_datum_to_array(datum));
+
+ case AVRO_UNION:
+ return size_union(writer, enc,
+ avro_schema_to_union(writers_schema),
+ avro_datum_to_union(datum));
+
+ case AVRO_LINK:
+ break;
+ }
+
+ return 0;
+}
+
+int64_t avro_size_data(avro_writer_t writer, avro_schema_t writers_schema,
+ avro_datum_t datum)
+{
+ check_param(-EINVAL, writer, "writer");
+ check_param(-EINVAL, is_avro_datum(datum), "datum");
+ /* Only validate datum if a writer's schema is provided */
+ if (is_avro_schema(writers_schema)
+ && !avro_schema_datum_validate(writers_schema, datum)) {
+ avro_set_error("Datum doesn't validate against schema");
+ return -EINVAL;
+ }
+ return size_datum(writer, &avro_binary_encoding, writers_schema, datum);
+}
diff --git a/fluent-bit/lib/avro/src/datum_skip.c b/fluent-bit/lib/avro/src/datum_skip.c
new file mode 100644
index 000000000..aa51d7934
--- /dev/null
+++ b/fluent-bit/lib/avro/src/datum_skip.c
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include "avro_private.h"
+#include "avro/errors.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include "encoding.h"
+#include "schema.h"
+
+static int skip_array(avro_reader_t reader, const avro_encoding_t * enc,
+ struct avro_array_schema_t *writers_schema)
+{
+ int rval;
+ int64_t i;
+ int64_t block_count;
+ int64_t block_size;
+
+ check_prefix(rval, enc->read_long(reader, &block_count),
+ "Cannot read array block count: ");
+
+ while (block_count != 0) {
+ if (block_count < 0) {
+ block_count = block_count * -1;
+ check_prefix(rval, enc->read_long(reader, &block_size),
+ "Cannot read array block size: ");
+ }
+
+ for (i = 0; i < block_count; i++) {
+ check_prefix(rval, avro_skip_data(reader, writers_schema->items),
+ "Cannot skip array element: ");
+ }
+
+ check_prefix(rval, enc->read_long(reader, &block_count),
+ "Cannot read array block count: ");
+ }
+ return 0;
+}
+
+static int skip_map(avro_reader_t reader, const avro_encoding_t * enc,
+ struct avro_map_schema_t *writers_schema)
+{
+ int rval;
+ int64_t i, block_count;
+
+ check_prefix(rval, enc->read_long(reader, &block_count),
+ "Cannot read map block count: ");
+ while (block_count != 0) {
+ int64_t block_size;
+ if (block_count < 0) {
+ block_count = block_count * -1;
+ check_prefix(rval, enc->read_long(reader, &block_size),
+ "Cannot read map block size: ");
+ }
+ for (i = 0; i < block_count; i++) {
+ check_prefix(rval, enc->skip_string(reader),
+ "Cannot skip map key: ");
+ check_prefix(rval,
+ avro_skip_data(reader,
+ avro_schema_to_map(writers_schema)->
+ values),
+ "Cannot skip map value: ");
+ }
+ check_prefix(rval, enc->read_long(reader, &block_count),
+ "Cannot read map block count: ");
+ }
+ return 0;
+}
+
+static int skip_union(avro_reader_t reader, const avro_encoding_t * enc,
+ struct avro_union_schema_t *writers_schema)
+{
+ int rval;
+ int64_t index;
+ avro_schema_t branch_schema;
+
+ check_prefix(rval, enc->read_long(reader, &index),
+ "Cannot read union discriminant: ");
+ branch_schema = avro_schema_union_branch(&writers_schema->obj, index);
+ if (!branch_schema) {
+ return EILSEQ;
+ }
+ return avro_skip_data(reader, branch_schema);
+}
+
+static int skip_record(avro_reader_t reader, const avro_encoding_t * enc,
+ struct avro_record_schema_t *writers_schema)
+{
+ int rval;
+ long i;
+
+ AVRO_UNUSED(enc);
+
+ for (i = 0; i < writers_schema->fields->num_entries; i++) {
+ avro_schema_t field_schema;
+
+ field_schema = avro_schema_record_field_get_by_index
+ (&writers_schema->obj, i);
+ check_prefix(rval, avro_skip_data(reader, field_schema),
+ "Cannot skip record field: ");
+ }
+ return 0;
+}
+
+int avro_skip_data(avro_reader_t reader, avro_schema_t writers_schema)
+{
+ check_param(EINVAL, reader, "reader");
+ check_param(EINVAL, is_avro_schema(writers_schema), "writer schema");
+
+ int rval = EINVAL;
+ const avro_encoding_t *enc = &avro_binary_encoding;
+
+ switch (avro_typeof(writers_schema)) {
+ case AVRO_NULL:
+ rval = enc->skip_null(reader);
+ break;
+
+ case AVRO_BOOLEAN:
+ rval = enc->skip_boolean(reader);
+ break;
+
+ case AVRO_STRING:
+ rval = enc->skip_string(reader);
+ break;
+
+ case AVRO_INT32:
+ rval = enc->skip_int(reader);
+ break;
+
+ case AVRO_INT64:
+ rval = enc->skip_long(reader);
+ break;
+
+ case AVRO_FLOAT:
+ rval = enc->skip_float(reader);
+ break;
+
+ case AVRO_DOUBLE:
+ rval = enc->skip_double(reader);
+ break;
+
+ case AVRO_BYTES:
+ rval = enc->skip_bytes(reader);
+ break;
+
+ case AVRO_FIXED:
+ rval =
+ avro_skip(reader,
+ avro_schema_to_fixed(writers_schema)->size);
+ break;
+
+ case AVRO_ENUM:
+ rval = enc->skip_long(reader);
+ break;
+
+ case AVRO_ARRAY:
+ rval =
+ skip_array(reader, enc,
+ avro_schema_to_array(writers_schema));
+ break;
+
+ case AVRO_MAP:
+ rval =
+ skip_map(reader, enc, avro_schema_to_map(writers_schema));
+ break;
+
+ case AVRO_UNION:
+ rval =
+ skip_union(reader, enc,
+ avro_schema_to_union(writers_schema));
+ break;
+
+ case AVRO_RECORD:
+ rval =
+ skip_record(reader, enc,
+ avro_schema_to_record(writers_schema));
+ break;
+
+ case AVRO_LINK:
+ rval =
+ avro_skip_data(reader,
+ (avro_schema_to_link(writers_schema))->to);
+ break;
+ }
+
+ return rval;
+}
diff --git a/fluent-bit/lib/avro/src/datum_validate.c b/fluent-bit/lib/avro/src/datum_validate.c
new file mode 100644
index 000000000..d15ebddda
--- /dev/null
+++ b/fluent-bit/lib/avro/src/datum_validate.c
@@ -0,0 +1,193 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include "avro_private.h"
+#include "avro/errors.h"
+#include <limits.h>
+#include <errno.h>
+#include <string.h>
+#include "schema.h"
+#include "datum.h"
+#include "st.h"
+
+struct validate_st {
+ avro_schema_t expected_schema;
+ int rval;
+};
+
+static int
+schema_map_validate_foreach(char *key, avro_datum_t datum,
+ struct validate_st *vst)
+{
+ AVRO_UNUSED(key);
+
+ if (!avro_schema_datum_validate(vst->expected_schema, datum)) {
+ vst->rval = 0;
+ return ST_STOP;
+ }
+ return ST_CONTINUE;
+}
+
+int
+avro_schema_datum_validate(avro_schema_t expected_schema, avro_datum_t datum)
+{
+ check_param(EINVAL, expected_schema, "expected schema");
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+
+ int rval;
+ long i;
+
+ switch (avro_typeof(expected_schema)) {
+ case AVRO_NULL:
+ return is_avro_null(datum);
+
+ case AVRO_BOOLEAN:
+ return is_avro_boolean(datum);
+
+ case AVRO_STRING:
+ return is_avro_string(datum);
+
+ case AVRO_BYTES:
+ return is_avro_bytes(datum);
+
+ case AVRO_INT32:
+ return is_avro_int32(datum)
+ || (is_avro_int64(datum)
+ && (INT_MIN <= avro_datum_to_int64(datum)->i64
+ && avro_datum_to_int64(datum)->i64 <= INT_MAX));
+
+ case AVRO_INT64:
+ return is_avro_int32(datum) || is_avro_int64(datum);
+
+ case AVRO_FLOAT:
+ return is_avro_int32(datum) || is_avro_int64(datum)
+ || is_avro_float(datum);
+
+ case AVRO_DOUBLE:
+ return is_avro_int32(datum) || is_avro_int64(datum)
+ || is_avro_float(datum) || is_avro_double(datum);
+
+ case AVRO_FIXED:
+ return (is_avro_fixed(datum)
+ && (avro_schema_to_fixed(expected_schema)->size ==
+ avro_datum_to_fixed(datum)->size));
+
+ case AVRO_ENUM:
+ if (is_avro_enum(datum)) {
+ long value = avro_datum_to_enum(datum)->value;
+ long max_value =
+ avro_schema_to_enum(expected_schema)->symbols->
+ num_entries;
+ return 0 <= value && value <= max_value;
+ }
+ return 0;
+
+ case AVRO_ARRAY:
+ if (is_avro_array(datum)) {
+ struct avro_array_datum_t *array =
+ avro_datum_to_array(datum);
+
+ for (i = 0; i < array->els->num_entries; i++) {
+ union {
+ st_data_t data;
+ avro_datum_t datum;
+ } val;
+ st_lookup(array->els, i, &val.data);
+ if (!avro_schema_datum_validate
+ ((avro_schema_to_array
+ (expected_schema))->items, val.datum)) {
+ return 0;
+ }
+ }
+ return 1;
+ }
+ return 0;
+
+ case AVRO_MAP:
+ if (is_avro_map(datum)) {
+ struct validate_st vst =
+ { avro_schema_to_map(expected_schema)->values, 1
+ };
+ st_foreach(avro_datum_to_map(datum)->map,
+ HASH_FUNCTION_CAST schema_map_validate_foreach,
+ (st_data_t) & vst);
+ return vst.rval;
+ }
+ break;
+
+ case AVRO_UNION:
+ if (is_avro_union(datum)) {
+ struct avro_union_schema_t *union_schema =
+ avro_schema_to_union(expected_schema);
+ struct avro_union_datum_t *union_datum =
+ avro_datum_to_union(datum);
+ union {
+ st_data_t data;
+ avro_schema_t schema;
+ } val;
+
+ if (!st_lookup
+ (union_schema->branches, union_datum->discriminant,
+ &val.data)) {
+ return 0;
+ }
+ return avro_schema_datum_validate(val.schema,
+ union_datum->value);
+ }
+ break;
+
+ case AVRO_RECORD:
+ if (is_avro_record(datum)) {
+ struct avro_record_schema_t *record_schema =
+ avro_schema_to_record(expected_schema);
+ for (i = 0; i < record_schema->fields->num_entries; i++) {
+ avro_datum_t field_datum;
+ union {
+ st_data_t data;
+ struct avro_record_field_t *field;
+ } val;
+ st_lookup(record_schema->fields, i, &val.data);
+
+ rval =
+ avro_record_get(datum, val.field->name,
+ &field_datum);
+ if (rval) {
+ /*
+ * TODO: check for default values
+ */
+ return rval;
+ }
+ if (!avro_schema_datum_validate
+ (val.field->type, field_datum)) {
+ return 0;
+ }
+ }
+ return 1;
+ }
+ break;
+
+ case AVRO_LINK:
+ {
+ return
+ avro_schema_datum_validate((avro_schema_to_link
+ (expected_schema))->to,
+ datum);
+ }
+ break;
+ }
+ return 0;
+}
diff --git a/fluent-bit/lib/avro/src/datum_value.c b/fluent-bit/lib/avro/src/datum_value.c
new file mode 100644
index 000000000..a4fa55a0c
--- /dev/null
+++ b/fluent-bit/lib/avro/src/datum_value.c
@@ -0,0 +1,784 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <avro/platform.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro/allocation.h"
+#include "avro/basics.h"
+#include "avro/errors.h"
+#include "avro/legacy.h"
+#include "avro/refcount.h"
+#include "avro/schema.h"
+#include "avro/value.h"
+#include "avro_private.h"
+
+extern avro_value_iface_t AVRO_DATUM_VALUE_CLASS;
+
+avro_value_iface_t *
+avro_datum_class(void)
+{
+ return &AVRO_DATUM_VALUE_CLASS;
+}
+
+int
+avro_datum_as_value(avro_value_t *value, avro_datum_t src)
+{
+ value->iface = &AVRO_DATUM_VALUE_CLASS;
+ value->self = avro_datum_incref(src);
+ return 0;
+}
+
+static int
+avro_datum_as_child_value(avro_value_t *value, avro_datum_t src)
+{
+ value->iface = &AVRO_DATUM_VALUE_CLASS;
+ value->self = src;
+ return 0;
+}
+
+static void
+avro_datum_value_incref(avro_value_t *value)
+{
+ avro_datum_t self = (avro_datum_t) value->self;
+ avro_datum_incref(self);
+}
+
+static void
+avro_datum_value_decref(avro_value_t *value)
+{
+ avro_datum_t self = (avro_datum_t) value->self;
+ avro_datum_decref(self);
+}
+
+static int
+avro_datum_value_reset(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ avro_datum_t self = (avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+ return avro_datum_reset(self);
+}
+
+static avro_type_t
+avro_datum_value_get_type(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+#ifdef _WIN32
+#pragma message("#warning: Bug: EINVAL is not of type avro_type_t.")
+#else
+#warning "Bug: EINVAL is not of type avro_type_t."
+#endif
+ /* We shouldn't use EINVAL as the return value to
+ * check_param(), because EINVAL (= 22) is not a valid enum
+ * avro_type_t. This is a structural issue -- we would need a
+ * different interface on all the get_type functions to fix
+ * this. For now, suppressing the error by casting EINVAL to
+ * (avro_type_t) so the code compiles under C++.
+ */
+ check_param((avro_type_t) EINVAL, self, "datum instance");
+ return avro_typeof(self);
+}
+
+static avro_schema_t
+avro_datum_value_get_schema(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(NULL, self, "datum instance");
+ return avro_datum_get_schema(self);
+}
+
+
+static int
+avro_datum_value_get_boolean(const avro_value_iface_t *iface,
+ const void *vself, int *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ int rval;
+ int8_t value;
+ check(rval, avro_boolean_get(self, &value));
+ *out = value;
+ return 0;
+}
+
+static int
+avro_datum_value_get_bytes(const avro_value_iface_t *iface,
+ const void *vself, const void **buf, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ int rval;
+ char *bytes;
+ int64_t sz;
+ check(rval, avro_bytes_get(self, &bytes, &sz));
+ if (buf != NULL) {
+ *buf = (const void *) bytes;
+ }
+ if (size != NULL) {
+ *size = sz;
+ }
+ return 0;
+}
+
+static int
+avro_datum_value_grab_bytes(const avro_value_iface_t *iface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ int rval;
+ char *bytes;
+ int64_t sz;
+ check(rval, avro_bytes_get(self, &bytes, &sz));
+
+ /* nothing clever, just make a copy */
+ return avro_wrapped_buffer_new_copy(dest, bytes, sz);
+}
+
+static int
+avro_datum_value_get_double(const avro_value_iface_t *iface,
+ const void *vself, double *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ int rval;
+ double value;
+ check(rval, avro_double_get(self, &value));
+ *out = value;
+ return 0;
+}
+
+static int
+avro_datum_value_get_float(const avro_value_iface_t *iface,
+ const void *vself, float *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ int rval;
+ float value;
+ check(rval, avro_float_get(self, &value));
+ *out = value;
+ return 0;
+}
+
+static int
+avro_datum_value_get_int(const avro_value_iface_t *iface,
+ const void *vself, int32_t *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ int rval;
+ int32_t value;
+ check(rval, avro_int32_get(self, &value));
+ *out = value;
+ return 0;
+}
+
+static int
+avro_datum_value_get_long(const avro_value_iface_t *iface,
+ const void *vself, int64_t *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ int rval;
+ int64_t value;
+ check(rval, avro_int64_get(self, &value));
+ *out = value;
+ return 0;
+}
+
+static int
+avro_datum_value_get_null(const avro_value_iface_t *iface,
+ const void *vself)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, is_avro_null(self), "datum instance");
+ return 0;
+}
+
+static int
+avro_datum_value_get_string(const avro_value_iface_t *iface,
+ const void *vself, const char **str, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ int rval;
+ char *value;
+ check(rval, avro_string_get(self, &value));
+ if (str != NULL) {
+ *str = (const char *) value;
+ }
+ if (size != NULL) {
+ *size = strlen(value)+1;
+ }
+ return 0;
+}
+
+static int
+avro_datum_value_grab_string(const avro_value_iface_t *iface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ int rval;
+ char *str;
+ size_t sz;
+ check(rval, avro_string_get(self, &str));
+ sz = strlen(str);
+
+ /* nothing clever, just make a copy */
+ /* sz doesn't contain NUL terminator */
+ return avro_wrapped_buffer_new_copy(dest, str, sz+1);
+}
+
+static int
+avro_datum_value_get_enum(const avro_value_iface_t *iface,
+ const void *vself, int *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, is_avro_enum(self), "datum instance");
+ *out = avro_enum_get(self);
+ return 0;
+}
+
+static int
+avro_datum_value_get_fixed(const avro_value_iface_t *iface,
+ const void *vself, const void **buf, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ int rval;
+ char *bytes;
+ int64_t sz;
+ check(rval, avro_fixed_get(self, &bytes, &sz));
+ if (buf != NULL) {
+ *buf = (const void *) bytes;
+ }
+ if (size != NULL) {
+ *size = sz;
+ }
+ return 0;
+}
+
+static int
+avro_datum_value_grab_fixed(const avro_value_iface_t *iface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ int rval;
+ char *bytes;
+ int64_t sz;
+ check(rval, avro_fixed_get(self, &bytes, &sz));
+
+ /* nothing clever, just make a copy */
+ return avro_wrapped_buffer_new_copy(dest, bytes, sz);
+}
+
+
+static int
+avro_datum_value_set_boolean(const avro_value_iface_t *iface,
+ void *vself, int val)
+{
+ AVRO_UNUSED(iface);
+ avro_datum_t self = (avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+ return avro_boolean_set(self, val);
+}
+
+static int
+avro_datum_value_set_bytes(const avro_value_iface_t *iface,
+ void *vself, void *buf, size_t size)
+{
+ AVRO_UNUSED(iface);
+ avro_datum_t self = (avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+ return avro_bytes_set(self, (const char *) buf, size);
+}
+
+static int
+avro_datum_value_give_bytes(const avro_value_iface_t *iface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ /*
+ * We actually can't use avro_givebytes_set, since it can't
+ * handle the extra free_ud parameter. Ah well, this is
+ * deprecated, so go ahead and make a copy.
+ */
+
+ int rval = avro_datum_value_set_bytes
+ (iface, vself, (void *) buf->buf, buf->size);
+ avro_wrapped_buffer_free(buf);
+ return rval;
+}
+
+static int
+avro_datum_value_set_double(const avro_value_iface_t *iface,
+ void *vself, double val)
+{
+ AVRO_UNUSED(iface);
+ avro_datum_t self = (avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+ return avro_double_set(self, val);
+}
+
+static int
+avro_datum_value_set_float(const avro_value_iface_t *iface,
+ void *vself, float val)
+{
+ AVRO_UNUSED(iface);
+ avro_datum_t self = (avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+ return avro_float_set(self, val);
+}
+
+static int
+avro_datum_value_set_int(const avro_value_iface_t *iface,
+ void *vself, int32_t val)
+{
+ AVRO_UNUSED(iface);
+ avro_datum_t self = (avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+ return avro_int32_set(self, val);
+}
+
+static int
+avro_datum_value_set_long(const avro_value_iface_t *iface,
+ void *vself, int64_t val)
+{
+ AVRO_UNUSED(iface);
+ avro_datum_t self = (avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+ return avro_int64_set(self, val);
+}
+
+static int
+avro_datum_value_set_null(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ avro_datum_t self = (avro_datum_t) vself;
+ check_param(EINVAL, is_avro_null(self), "datum instance");
+ return 0;
+}
+
+static int
+avro_datum_value_set_string(const avro_value_iface_t *iface,
+ void *vself, const char *str)
+{
+ AVRO_UNUSED(iface);
+ avro_datum_t self = (avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+ return avro_string_set(self, str);
+}
+
+static int
+avro_datum_value_set_string_len(const avro_value_iface_t *iface,
+ void *vself, const char *str, size_t size)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(size);
+ avro_datum_t self = (avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+ return avro_string_set(self, str);
+}
+
+static int
+avro_datum_value_give_string_len(const avro_value_iface_t *iface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ /*
+ * We actually can't use avro_givestring_set, since it can't
+ * handle the extra free_ud parameter. Ah well, this is
+ * deprecated, so go ahead and make a copy.
+ */
+
+ int rval = avro_datum_value_set_string_len
+ (iface, vself, (char *) buf->buf, buf->size-1);
+ avro_wrapped_buffer_free(buf);
+ return rval;
+}
+
+static int
+avro_datum_value_set_enum(const avro_value_iface_t *iface,
+ void *vself, int val)
+{
+ AVRO_UNUSED(iface);
+ avro_datum_t self = (avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+ return avro_enum_set(self, val);
+}
+
+static int
+avro_datum_value_set_fixed(const avro_value_iface_t *iface,
+ void *vself, void *buf, size_t size)
+{
+ AVRO_UNUSED(iface);
+ avro_datum_t self = (avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+ return avro_fixed_set(self, (const char *) buf, size);
+}
+
+static int
+avro_datum_value_give_fixed(const avro_value_iface_t *iface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ /*
+ * We actually can't use avro_givefixed_set, since it can't
+ * handle the extra free_ud parameter. Ah well, this is
+ * deprecated, so go ahead and make a copy.
+ */
+
+ int rval = avro_datum_value_set_fixed
+ (iface, vself, (void *) buf->buf, buf->size);
+ avro_wrapped_buffer_free(buf);
+ return rval;
+}
+
+
+static int
+avro_datum_value_get_size(const avro_value_iface_t *iface,
+ const void *vself, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ if (is_avro_array(self)) {
+ *size = avro_array_size(self);
+ return 0;
+ }
+
+ if (is_avro_map(self)) {
+ *size = avro_map_size(self);
+ return 0;
+ }
+
+ if (is_avro_record(self)) {
+ avro_schema_t schema = avro_datum_get_schema(self);
+ *size = avro_schema_record_size(schema);
+ return 0;
+ }
+
+ avro_set_error("Can only get size of array, map, or record, %d", avro_typeof(self));
+ return EINVAL;
+}
+
+static int
+avro_datum_value_get_by_index(const avro_value_iface_t *iface,
+ const void *vself, size_t index,
+ avro_value_t *child, const char **name)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ int rval;
+ avro_datum_t child_datum;
+
+ if (is_avro_array(self)) {
+ check(rval, avro_array_get(self, index, &child_datum));
+ return avro_datum_as_child_value(child, child_datum);
+ }
+
+ if (is_avro_map(self)) {
+ const char *real_key;
+ check(rval, avro_map_get_key(self, index, &real_key));
+ if (name != NULL) {
+ *name = real_key;
+ }
+ check(rval, avro_map_get(self, real_key, &child_datum));
+ return avro_datum_as_child_value(child, child_datum);
+ }
+
+ if (is_avro_record(self)) {
+ avro_schema_t schema = avro_datum_get_schema(self);
+ const char *field_name =
+ avro_schema_record_field_name(schema, index);
+ if (field_name == NULL) {
+ return EINVAL;
+ }
+ if (name != NULL) {
+ *name = field_name;
+ }
+ check(rval, avro_record_get(self, field_name, &child_datum));
+ return avro_datum_as_child_value(child, child_datum);
+ }
+
+ avro_set_error("Can only get by index from array, map, or record");
+ return EINVAL;
+}
+
+static int
+avro_datum_value_get_by_name(const avro_value_iface_t *iface,
+ const void *vself, const char *name,
+ avro_value_t *child, size_t *index)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ int rval;
+ avro_datum_t child_datum;
+
+ if (is_avro_map(self)) {
+ if (index != NULL) {
+ int real_index;
+ check(rval, avro_map_get_index(self, name, &real_index));
+ *index = real_index;
+ }
+
+ check(rval, avro_map_get(self, name, &child_datum));
+ return avro_datum_as_child_value(child, child_datum);
+ }
+
+ if (is_avro_record(self)) {
+ if (index != NULL) {
+ avro_schema_t schema = avro_datum_get_schema(self);
+ *index = avro_schema_record_field_get_index(schema, name);
+ }
+
+ check(rval, avro_record_get(self, name, &child_datum));
+ return avro_datum_as_child_value(child, child_datum);
+ }
+
+ avro_set_error("Can only get by name from map or record");
+ return EINVAL;
+}
+
+static int
+avro_datum_value_get_discriminant(const avro_value_iface_t *iface,
+ const void *vself, int *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ if (!is_avro_union(self)) {
+ avro_set_error("Can only get discriminant of union");
+ return EINVAL;
+ }
+
+ *out = avro_union_discriminant(self);
+ return 0;
+}
+
+static int
+avro_datum_value_get_current_branch(const avro_value_iface_t *iface,
+ const void *vself, avro_value_t *branch)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ if (!is_avro_union(self)) {
+ avro_set_error("Can only get current branch of union");
+ return EINVAL;
+ }
+
+ avro_datum_t child_datum = avro_union_current_branch(self);
+ return avro_datum_as_child_value(branch, child_datum);
+}
+
+
+static int
+avro_datum_value_append(const avro_value_iface_t *iface,
+ void *vself, avro_value_t *child_out, size_t *new_index)
+{
+ AVRO_UNUSED(iface);
+ avro_datum_t self = (avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ if (!is_avro_array(self)) {
+ avro_set_error("Can only append to array");
+ return EINVAL;
+ }
+
+ int rval;
+
+ avro_schema_t array_schema = avro_datum_get_schema(self);
+ avro_schema_t child_schema = avro_schema_array_items(array_schema);
+ avro_datum_t child_datum = avro_datum_from_schema(child_schema);
+ if (child_datum == NULL) {
+ return ENOMEM;
+ }
+
+ rval = avro_array_append_datum(self, child_datum);
+ avro_datum_decref(child_datum);
+ if (rval != 0) {
+ return rval;
+ }
+
+ if (new_index != NULL) {
+ *new_index = avro_array_size(self) - 1;
+ }
+ return avro_datum_as_child_value(child_out, child_datum);
+}
+
+static int
+avro_datum_value_add(const avro_value_iface_t *iface,
+ void *vself, const char *key,
+ avro_value_t *child, size_t *index, int *is_new)
+{
+ AVRO_UNUSED(iface);
+ avro_datum_t self = (avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ if (!is_avro_map(self)) {
+ avro_set_error("Can only add to map");
+ return EINVAL;
+ }
+
+ int rval;
+ avro_datum_t child_datum;
+
+ if (avro_map_get(self, key, &child_datum) == 0) {
+ /* key already exists */
+ if (is_new != NULL) {
+ *is_new = 0;
+ }
+ if (index != NULL) {
+ int real_index;
+ avro_map_get_index(self, key, &real_index);
+ *index = real_index;
+ }
+ return avro_datum_as_child_value(child, child_datum);
+ }
+
+ /* key is new */
+ avro_schema_t map_schema = avro_datum_get_schema(self);
+ avro_schema_t child_schema = avro_schema_map_values(map_schema);
+ child_datum = avro_datum_from_schema(child_schema);
+ if (child_datum == NULL) {
+ return ENOMEM;
+ }
+
+ rval = avro_map_set(self, key, child_datum);
+ avro_datum_decref(child_datum);
+ if (rval != 0) {
+ return rval;
+ }
+
+ if (is_new != NULL) {
+ *is_new = 1;
+ }
+ if (index != NULL) {
+ *index = avro_map_size(self) - 1;
+ }
+
+ return avro_datum_as_child_value(child, child_datum);
+}
+
+static int
+avro_datum_value_set_branch(const avro_value_iface_t *iface,
+ void *vself, int discriminant,
+ avro_value_t *branch)
+{
+ AVRO_UNUSED(iface);
+ const avro_datum_t self = (const avro_datum_t) vself;
+ check_param(EINVAL, self, "datum instance");
+
+ if (!is_avro_union(self)) {
+ avro_set_error("Can only set branch of union");
+ return EINVAL;
+ }
+
+ int rval;
+ avro_datum_t child_datum;
+ check(rval, avro_union_set_discriminant(self, discriminant, &child_datum));
+ return avro_datum_as_child_value(branch, child_datum);
+}
+
+
+avro_value_iface_t AVRO_DATUM_VALUE_CLASS =
+{
+ /* "class" methods */
+ NULL, /* incref */
+ NULL, /* decref */
+ /* general "instance" methods */
+ avro_datum_value_incref,
+ avro_datum_value_decref,
+ avro_datum_value_reset,
+ avro_datum_value_get_type,
+ avro_datum_value_get_schema,
+ /* primitive getters */
+ avro_datum_value_get_boolean,
+ avro_datum_value_get_bytes,
+ avro_datum_value_grab_bytes,
+ avro_datum_value_get_double,
+ avro_datum_value_get_float,
+ avro_datum_value_get_int,
+ avro_datum_value_get_long,
+ avro_datum_value_get_null,
+ avro_datum_value_get_string,
+ avro_datum_value_grab_string,
+ avro_datum_value_get_enum,
+ avro_datum_value_get_fixed,
+ avro_datum_value_grab_fixed,
+ /* primitive setters */
+ avro_datum_value_set_boolean,
+ avro_datum_value_set_bytes,
+ avro_datum_value_give_bytes,
+ avro_datum_value_set_double,
+ avro_datum_value_set_float,
+ avro_datum_value_set_int,
+ avro_datum_value_set_long,
+ avro_datum_value_set_null,
+ avro_datum_value_set_string,
+ avro_datum_value_set_string_len,
+ avro_datum_value_give_string_len,
+ avro_datum_value_set_enum,
+ avro_datum_value_set_fixed,
+ avro_datum_value_give_fixed,
+ /* compound getters */
+ avro_datum_value_get_size,
+ avro_datum_value_get_by_index,
+ avro_datum_value_get_by_name,
+ avro_datum_value_get_discriminant,
+ avro_datum_value_get_current_branch,
+ /* compound setters */
+ avro_datum_value_append,
+ avro_datum_value_add,
+ avro_datum_value_set_branch
+};
diff --git a/fluent-bit/lib/avro/src/datum_write.c b/fluent-bit/lib/avro/src/datum_write.c
new file mode 100644
index 000000000..f3714ab84
--- /dev/null
+++ b/fluent-bit/lib/avro/src/datum_write.c
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include "avro/basics.h"
+#include "avro/errors.h"
+#include "avro/io.h"
+#include "avro/legacy.h"
+#include "avro/resolver.h"
+#include "avro/schema.h"
+#include "avro/value.h"
+#include "avro_private.h"
+
+int avro_write_data(avro_writer_t writer, avro_schema_t writers_schema,
+ avro_datum_t datum)
+{
+ int rval;
+
+ check_param(EINVAL, writer, "writer");
+ check_param(EINVAL, is_avro_datum(datum), "datum");
+
+ /* Only validate datum if a writer's schema is provided */
+ if (is_avro_schema(writers_schema)) {
+ if (!avro_schema_datum_validate(writers_schema, datum)) {
+ avro_set_error("Datum doesn't validate against schema");
+ return EINVAL;
+ }
+
+ /*
+ * Some confusing terminology here. The "writers_schema"
+ * parameter is the schema we want to use to write the data
+ * into the "writer" buffer. Before doing that, we need to
+ * resolve the datum from its actual schema into this
+ * "writer" schema. For the purposes of that resolution,
+ * the writer schema is the datum's actual schema, and the
+ * reader schema is our eventual (when writing to the
+ * buffer) "writer" schema.
+ */
+
+ avro_schema_t datum_schema = avro_datum_get_schema(datum);
+ avro_value_iface_t *resolver =
+ avro_resolved_reader_new(datum_schema, writers_schema);
+ if (resolver == NULL) {
+ return EINVAL;
+ }
+
+ avro_value_t value;
+ check(rval, avro_datum_as_value(&value, datum));
+
+ avro_value_t resolved;
+ rval = avro_resolved_reader_new_value(resolver, &resolved);
+ if (rval != 0) {
+ avro_value_decref(&value);
+ avro_value_iface_decref(resolver);
+ return rval;
+ }
+
+ avro_resolved_reader_set_source(&resolved, &value);
+ rval = avro_value_write(writer, &resolved);
+ avro_value_decref(&resolved);
+ avro_value_decref(&value);
+ avro_value_iface_decref(resolver);
+ return rval;
+ }
+
+ /* If we're writing using the datum's actual schema, we don't
+ * need a resolver. */
+
+ avro_value_t value;
+ check(rval, avro_datum_as_value(&value, datum));
+ check(rval, avro_value_write(writer, &value));
+ avro_value_decref(&value);
+ return 0;
+}
diff --git a/fluent-bit/lib/avro/src/dump.c b/fluent-bit/lib/avro/src/dump.c
new file mode 100644
index 000000000..5b8f1c99b
--- /dev/null
+++ b/fluent-bit/lib/avro/src/dump.c
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include "avro_private.h"
+#include "dump.h"
+
+static void dump_line(FILE * out, const char *addr, const long len)
+{
+ int i;
+ fprintf(out, "|");
+ for (i = 0; i < 16; i++) {
+ if (i < len) {
+ fprintf(out, " %02X", ((uint8_t *) addr)[i]);
+ } else {
+ fprintf(out, " ..");
+ }
+ if (!((i + 1) % 8)) {
+ fprintf(out, " |");
+ }
+ }
+ fprintf(out, "\t");
+ for (i = 0; i < 16; i++) {
+ char c = 0x7f & ((uint8_t *) addr)[i];
+ if (i < len && isprint(c)) {
+ fprintf(out, "%c", c);
+ } else {
+ fprintf(out, ".");
+ }
+ }
+}
+
+void dump(FILE * out, const char *addr, const long len)
+{
+ int i;
+ for (i = 0; i < len; i += 16) {
+ dump_line(out, addr + i, (len - i) < 16 ? (len - i) : 16);
+ fprintf(out, "\n");
+ }
+ fflush(out);
+}
diff --git a/fluent-bit/lib/avro/src/dump.h b/fluent-bit/lib/avro/src/dump.h
new file mode 100644
index 000000000..23e806672
--- /dev/null
+++ b/fluent-bit/lib/avro/src/dump.h
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#ifndef DUMP_H
+#define DUMP_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+#include <stdio.h>
+
+#pragma GCC visibility push(hidden)
+void dump(FILE * out, const char *addr, const long len);
+#pragma GCC visibility pop
+
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/encoding.h b/fluent-bit/lib/avro/src/encoding.h
new file mode 100644
index 000000000..6333d588d
--- /dev/null
+++ b/fluent-bit/lib/avro/src/encoding.h
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+#ifndef AVRO_ENCODING_H
+#define AVRO_ENCODING_H
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+#include <avro/platform.h>
+#include "avro/io.h"
+
+/*
+ * TODO: this will need more functions when JSON encoding is added
+ */
+struct avro_encoding_t {
+ const char *description;
+ /*
+ * string
+ */
+ int (*read_string) (avro_reader_t reader, char **s, int64_t *len);
+ int (*skip_string) (avro_reader_t reader);
+ int (*write_string) (avro_writer_t writer, const char *s);
+ int64_t(*size_string) (avro_writer_t writer, const char *s);
+ /*
+ * bytes
+ */
+ int (*read_bytes) (avro_reader_t reader, char **bytes, int64_t * len);
+ int (*skip_bytes) (avro_reader_t reader);
+ int (*write_bytes) (avro_writer_t writer,
+ const char *bytes, const int64_t len);
+ int64_t(*size_bytes) (avro_writer_t writer,
+ const char *bytes, const int64_t len);
+ /*
+ * int
+ */
+ int (*read_int) (avro_reader_t reader, int32_t * i);
+ int (*skip_int) (avro_reader_t reader);
+ int (*write_int) (avro_writer_t writer, const int32_t i);
+ int64_t(*size_int) (avro_writer_t writer, const int32_t i);
+ /*
+ * long
+ */
+ int (*read_long) (avro_reader_t reader, int64_t * l);
+ int (*skip_long) (avro_reader_t reader);
+ int (*write_long) (avro_writer_t writer, const int64_t l);
+ int64_t(*size_long) (avro_writer_t writer, const int64_t l);
+ /*
+ * float
+ */
+ int (*read_float) (avro_reader_t reader, float *f);
+ int (*skip_float) (avro_reader_t reader);
+ int (*write_float) (avro_writer_t writer, const float f);
+ int64_t(*size_float) (avro_writer_t writer, const float f);
+ /*
+ * double
+ */
+ int (*read_double) (avro_reader_t reader, double *d);
+ int (*skip_double) (avro_reader_t reader);
+ int (*write_double) (avro_writer_t writer, const double d);
+ int64_t(*size_double) (avro_writer_t writer, const double d);
+ /*
+ * boolean
+ */
+ int (*read_boolean) (avro_reader_t reader, int8_t * b);
+ int (*skip_boolean) (avro_reader_t reader);
+ int (*write_boolean) (avro_writer_t writer, const int8_t b);
+ int64_t(*size_boolean) (avro_writer_t writer, const int8_t b);
+ /*
+ * null
+ */
+ int (*read_null) (avro_reader_t reader);
+ int (*skip_null) (avro_reader_t reader);
+ int (*write_null) (avro_writer_t writer);
+ int64_t(*size_null) (avro_writer_t writer);
+};
+typedef struct avro_encoding_t avro_encoding_t;
+
+#define AVRO_WRITE(writer, buf, len) \
+{ int rval = avro_write( writer, buf, len ); if(rval) return rval; }
+#define AVRO_READ(reader, buf, len) \
+{ int rval = avro_read( reader, buf, len ); if(rval) return rval; }
+#define AVRO_SKIP(reader, len) \
+{ int rval = avro_skip( reader, len); if (rval) return rval; }
+
+extern const avro_encoding_t avro_binary_encoding; /* in
+ * encoding_binary
+ */
+CLOSE_EXTERN
+#endif
diff --git a/fluent-bit/lib/avro/src/encoding_binary.c b/fluent-bit/lib/avro/src/encoding_binary.c
new file mode 100644
index 000000000..1fc5f0c9a
--- /dev/null
+++ b/fluent-bit/lib/avro/src/encoding_binary.c
@@ -0,0 +1,446 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include "avro_private.h"
+#include "avro/allocation.h"
+#include "avro/errors.h"
+#include "encoding.h"
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <string.h>
+
+#define MAX_VARINT_BUF_SIZE 10
+
+static int read_long(avro_reader_t reader, int64_t * l)
+{
+ uint64_t value = 0;
+ uint8_t b;
+ int offset = 0;
+ do {
+ if (offset == MAX_VARINT_BUF_SIZE) {
+ /*
+ * illegal byte sequence
+ */
+ avro_set_error("Varint too long");
+ return EILSEQ;
+ }
+ AVRO_READ(reader, &b, 1);
+ value |= (int64_t) (b & 0x7F) << (7 * offset);
+ ++offset;
+ }
+ while (b & 0x80);
+ *l = ((value >> 1) ^ -(value & 1));
+ return 0;
+}
+
+static int skip_long(avro_reader_t reader)
+{
+ uint8_t b;
+ int offset = 0;
+ do {
+ if (offset == MAX_VARINT_BUF_SIZE) {
+ avro_set_error("Varint too long");
+ return EILSEQ;
+ }
+ AVRO_READ(reader, &b, 1);
+ ++offset;
+ }
+ while (b & 0x80);
+ return 0;
+}
+
+static int write_long(avro_writer_t writer, int64_t l)
+{
+ char buf[MAX_VARINT_BUF_SIZE];
+ uint8_t bytes_written = 0;
+ uint64_t n = (l << 1) ^ (l >> 63);
+ while (n & ~0x7F) {
+ buf[bytes_written++] = (char)((((uint8_t) n) & 0x7F) | 0x80);
+ n >>= 7;
+ }
+ buf[bytes_written++] = (char)n;
+ AVRO_WRITE(writer, buf, bytes_written);
+ return 0;
+}
+
+static int64_t size_long(avro_writer_t writer, int64_t l)
+{
+ AVRO_UNUSED(writer);
+
+ int64_t len = 0;
+ uint64_t n = (l << 1) ^ (l >> 63);
+ while (n & ~0x7F) {
+ len++;
+ n >>= 7;
+ }
+ len++;
+ return len;
+}
+
+static int read_int(avro_reader_t reader, int32_t * i)
+{
+ int64_t l;
+ int rval;
+ check(rval, read_long(reader, &l));
+ if (!(INT_MIN <= l && l <= INT_MAX)) {
+ avro_set_error("Varint out of range for int type");
+ return ERANGE;
+ }
+ *i = l;
+ return 0;
+}
+
+static int skip_int(avro_reader_t reader)
+{
+ return skip_long(reader);
+}
+
+static int write_int(avro_writer_t writer, const int32_t i)
+{
+ int64_t l = i;
+ return write_long(writer, l);
+}
+
+static int64_t size_int(avro_writer_t writer, const int32_t i)
+{
+ int64_t l = i;
+ return size_long(writer, l);
+}
+
+static int read_bytes(avro_reader_t reader, char **bytes, int64_t * len)
+{
+ int rval;
+ check_prefix(rval, read_long(reader, len),
+ "Cannot read bytes length: ");
+ *bytes = (char *) avro_malloc(*len + 1);
+ if (!*bytes) {
+ avro_set_error("Cannot allocate buffer for bytes value");
+ return ENOMEM;
+ }
+ AVRO_READ(reader, *bytes, *len);
+ (*bytes)[*len] = '\0';
+ return 0;
+}
+
+static int skip_bytes(avro_reader_t reader)
+{
+ int64_t len = 0;
+ int rval;
+ check_prefix(rval, read_long(reader, &len),
+ "Cannot read bytes length: ");
+ AVRO_SKIP(reader, len);
+ return 0;
+}
+
+static int
+write_bytes(avro_writer_t writer, const char *bytes, const int64_t len)
+{
+ int rval;
+ if (len < 0) {
+ avro_set_error("Invalid bytes value length");
+ return EINVAL;
+ }
+ check_prefix(rval, write_long(writer, len),
+ "Cannot write bytes length: ");
+ AVRO_WRITE(writer, (char *)bytes, len);
+ return 0;
+}
+
+static int64_t
+size_bytes(avro_writer_t writer, const char *bytes, const int64_t len)
+{
+ AVRO_UNUSED(bytes);
+
+ return size_long(writer, len) + len;
+}
+
+static int read_string(avro_reader_t reader, char **s, int64_t *len)
+{
+ int64_t str_len = 0;
+ int rval;
+ check_prefix(rval, read_long(reader, &str_len),
+ "Cannot read string length: ");
+ *len = str_len + 1;
+ *s = (char *) avro_malloc(*len);
+ if (!*s) {
+ avro_set_error("Cannot allocate buffer for string value");
+ return ENOMEM;
+ }
+ (*s)[str_len] = '\0';
+ AVRO_READ(reader, *s, str_len);
+ return 0;
+}
+
+static int skip_string(avro_reader_t reader)
+{
+ return skip_bytes(reader);
+}
+
+static int write_string(avro_writer_t writer, const char *s)
+{
+ int64_t len = strlen(s);
+ return write_bytes(writer, s, len);
+}
+
+static int64_t size_string(avro_writer_t writer, const char *s)
+{
+ int64_t len = strlen(s);
+ return size_bytes(writer, s, len);
+}
+
+static int read_float(avro_reader_t reader, float *f)
+{
+#if AVRO_PLATFORM_IS_BIG_ENDIAN
+ uint8_t buf[4];
+#endif
+ union {
+ float f;
+ int32_t i;
+ } v;
+#if AVRO_PLATFORM_IS_BIG_ENDIAN
+ AVRO_READ(reader, buf, 4);
+ v.i = ((int32_t) buf[0] << 0)
+ | ((int32_t) buf[1] << 8)
+ | ((int32_t) buf[2] << 16) | ((int32_t) buf[3] << 24);
+#else
+ AVRO_READ(reader, (void *)&v.i, 4);
+#endif
+ *f = v.f;
+ return 0;
+}
+
+static int skip_float(avro_reader_t reader)
+{
+ AVRO_SKIP(reader, 4);
+ return 0;
+}
+
+static int write_float(avro_writer_t writer, const float f)
+{
+#if AVRO_PLATFORM_IS_BIG_ENDIAN
+ uint8_t buf[4];
+#endif
+ union {
+ float f;
+ int32_t i;
+ } v;
+
+ v.f = f;
+#if AVRO_PLATFORM_IS_BIG_ENDIAN
+ buf[0] = (uint8_t) (v.i >> 0);
+ buf[1] = (uint8_t) (v.i >> 8);
+ buf[2] = (uint8_t) (v.i >> 16);
+ buf[3] = (uint8_t) (v.i >> 24);
+ AVRO_WRITE(writer, buf, 4);
+#else
+ AVRO_WRITE(writer, (void *)&v.i, 4);
+#endif
+ return 0;
+}
+
+static int64_t size_float(avro_writer_t writer, const float f)
+{
+ AVRO_UNUSED(writer);
+ AVRO_UNUSED(f);
+
+ return 4;
+}
+
+static int read_double(avro_reader_t reader, double *d)
+{
+#if AVRO_PLATFORM_IS_BIG_ENDIAN
+ uint8_t buf[8];
+#endif
+ union {
+ double d;
+ int64_t l;
+ } v;
+
+#if AVRO_PLATFORM_IS_BIG_ENDIAN
+ AVRO_READ(reader, buf, 8);
+ v.l = ((int64_t) buf[0] << 0)
+ | ((int64_t) buf[1] << 8)
+ | ((int64_t) buf[2] << 16)
+ | ((int64_t) buf[3] << 24)
+ | ((int64_t) buf[4] << 32)
+ | ((int64_t) buf[5] << 40)
+ | ((int64_t) buf[6] << 48) | ((int64_t) buf[7] << 56);
+#else
+ AVRO_READ(reader, (void *)&v.l, 8);
+#endif
+ *d = v.d;
+ return 0;
+}
+
+static int skip_double(avro_reader_t reader)
+{
+ AVRO_SKIP(reader, 8);
+ return 0;
+}
+
+static int write_double(avro_writer_t writer, const double d)
+{
+#if AVRO_PLATFORM_IS_BIG_ENDIAN
+ uint8_t buf[8];
+#endif
+ union {
+ double d;
+ int64_t l;
+ } v;
+
+ v.d = d;
+#if AVRO_PLATFORM_IS_BIG_ENDIAN
+ buf[0] = (uint8_t) (v.l >> 0);
+ buf[1] = (uint8_t) (v.l >> 8);
+ buf[2] = (uint8_t) (v.l >> 16);
+ buf[3] = (uint8_t) (v.l >> 24);
+ buf[4] = (uint8_t) (v.l >> 32);
+ buf[5] = (uint8_t) (v.l >> 40);
+ buf[6] = (uint8_t) (v.l >> 48);
+ buf[7] = (uint8_t) (v.l >> 56);
+ AVRO_WRITE(writer, buf, 8);
+#else
+ AVRO_WRITE(writer, (void *)&v.l, 8);
+#endif
+ return 0;
+}
+
+static int64_t size_double(avro_writer_t writer, const double d)
+{
+ AVRO_UNUSED(writer);
+ AVRO_UNUSED(d);
+
+ return 8;
+}
+
+static int read_boolean(avro_reader_t reader, int8_t * b)
+{
+ AVRO_READ(reader, b, 1);
+ return 0;
+}
+
+static int skip_boolean(avro_reader_t reader)
+{
+ AVRO_SKIP(reader, 1);
+ return 0;
+}
+
+static int write_boolean(avro_writer_t writer, const int8_t b)
+{
+ AVRO_WRITE(writer, (char *)&b, 1);
+ return 0;
+}
+
+static int64_t size_boolean(avro_writer_t writer, const int8_t b)
+{
+ AVRO_UNUSED(writer);
+ AVRO_UNUSED(b);
+
+ return 1;
+}
+
+static int read_skip_null(avro_reader_t reader)
+{
+ /*
+ * no-op
+ */
+ AVRO_UNUSED(reader);
+
+ return 0;
+}
+
+static int write_null(avro_writer_t writer)
+{
+ /*
+ * no-op
+ */
+ AVRO_UNUSED(writer);
+
+ return 0;
+}
+
+static int64_t size_null(avro_writer_t writer)
+{
+ AVRO_UNUSED(writer);
+
+ return 0;
+}
+
+/* Win32 doesn't support the C99 method of initializing named elements
+ * in a struct declaration. So hide the named parameters for Win32,
+ * and initialize in the order the code was written.
+ */
+const avro_encoding_t avro_binary_encoding = {
+ /* .description = */ "BINARY FORMAT",
+ /*
+ * string
+ */
+ /* .read_string = */ read_string,
+ /* .skip_string = */ skip_string,
+ /* .write_string = */ write_string,
+ /* .size_string = */ size_string,
+ /*
+ * bytes
+ */
+ /* .read_bytes = */ read_bytes,
+ /* .skip_bytes = */ skip_bytes,
+ /* .write_bytes = */ write_bytes,
+ /* .size_bytes = */ size_bytes,
+ /*
+ * int
+ */
+ /* .read_int = */ read_int,
+ /* .skip_int = */ skip_int,
+ /* .write_int = */ write_int,
+ /* .size_int = */ size_int,
+ /*
+ * long
+ */
+ /* .read_long = */ read_long,
+ /* .skip_long = */ skip_long,
+ /* .write_long = */ write_long,
+ /* .size_long = */ size_long,
+ /*
+ * float
+ */
+ /* .read_float = */ read_float,
+ /* .skip_float = */ skip_float,
+ /* .write_float = */ write_float,
+ /* .size_float = */ size_float,
+ /*
+ * double
+ */
+ /* .read_double = */ read_double,
+ /* .skip_double = */ skip_double,
+ /* .write_double = */ write_double,
+ /* .size_double = */ size_double,
+ /*
+ * boolean
+ */
+ /* .read_boolean = */ read_boolean,
+ /* .skip_boolean = */ skip_boolean,
+ /* .write_boolean = */ write_boolean,
+ /* .size_boolean = */ size_boolean,
+ /*
+ * null
+ */
+ /* .read_null = */ read_skip_null,
+ /* .skip_null = */ read_skip_null,
+ /* .write_null = */ write_null,
+ /* .size_null = */ size_null
+};
diff --git a/fluent-bit/lib/avro/src/errors.c b/fluent-bit/lib/avro/src/errors.c
new file mode 100644
index 000000000..8abd8c832
--- /dev/null
+++ b/fluent-bit/lib/avro/src/errors.c
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "avro/errors.h"
+
+/* 4K should be enough, right? */
+#define AVRO_ERROR_SIZE 4096
+
+/*
+ * To support the avro_prefix_error function, we keep two string buffers
+ * around. The AVRO_CURRENT_ERROR points at the buffer that's holding
+ * the current error message. avro_prefix error writes into the other
+ * buffer, and then swaps them.
+ */
+
+struct avro_error_data_t {
+ char AVRO_ERROR1[AVRO_ERROR_SIZE];
+ char AVRO_ERROR2[AVRO_ERROR_SIZE];
+
+ char *AVRO_CURRENT_ERROR;
+ char *AVRO_OTHER_ERROR;
+};
+
+
+#if defined THREADSAFE
+#if ( defined __unix__ || defined __unix )
+#include <pthread.h>
+static pthread_key_t error_data_key;
+static pthread_once_t error_data_key_once = PTHREAD_ONCE_INIT;
+
+static void make_error_data_key()
+{
+ pthread_key_create(&error_data_key, free);
+}
+#elif defined _WIN32
+#include <Windows.h>
+
+static __declspec( thread ) struct avro_error_data_t TLS_ERROR_DATA = { "", "", NULL, NULL };
+
+#endif /* unix||_unix||_WIN32 */
+#endif /* THREADSAFE */
+
+static struct avro_error_data_t *
+avro_get_error_data(void)
+{
+#if defined THREADSAFE
+#if defined __unix__ || defined __unix
+
+ pthread_once(&error_data_key_once, make_error_data_key);
+
+ struct avro_error_data_t *ERROR_DATA =
+ (struct avro_error_data_t*) pthread_getspecific(error_data_key);
+
+ if (!ERROR_DATA) {
+ ERROR_DATA = (struct avro_error_data_t*) malloc(sizeof(struct avro_error_data_t));
+ pthread_setspecific(error_data_key, ERROR_DATA);
+
+ ERROR_DATA->AVRO_ERROR1[0] = '\0';
+ ERROR_DATA->AVRO_ERROR2[0] = '\0';
+ ERROR_DATA->AVRO_CURRENT_ERROR = ERROR_DATA->AVRO_ERROR1;
+ ERROR_DATA->AVRO_OTHER_ERROR = ERROR_DATA->AVRO_ERROR2;
+ }
+
+ return ERROR_DATA;
+
+#elif defined _WIN32
+
+ if ( TLS_ERROR_DATA.AVRO_CURRENT_ERROR == NULL )
+ {
+ //first usage of the ERROR_DATA, initialize 'current' and 'other' pointers.
+ TLS_ERROR_DATA.AVRO_CURRENT_ERROR = TLS_ERROR_DATA.AVRO_ERROR1;
+ TLS_ERROR_DATA.AVRO_OTHER_ERROR = TLS_ERROR_DATA.AVRO_ERROR2;
+ }
+ return &TLS_ERROR_DATA;
+
+ #endif /* UNIX and WIN32 threadsafe handling */
+
+#else /* not thread-safe */
+ static struct avro_error_data_t ERROR_DATA = {
+ /* .AVRO_ERROR1 = */ {'\0'},
+ /* .AVRO_ERROR2 = */ {'\0'},
+ /* .AVRO_CURRENT_ERROR = */ ERROR_DATA.AVRO_ERROR1,
+ /* .AVRO_OTHER_ERROR = */ ERROR_DATA.AVRO_ERROR2,
+ };
+
+ return &ERROR_DATA;
+#endif
+}
+
+
+void
+avro_set_error(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(avro_get_error_data()->AVRO_CURRENT_ERROR, AVRO_ERROR_SIZE, fmt, args);
+ va_end(args);
+ //fprintf(stderr, "--- %s\n", AVRO_CURRENT_ERROR);
+}
+
+
+void
+avro_prefix_error(const char *fmt, ...)
+{
+ struct avro_error_data_t *ERROR_DATA = avro_get_error_data();
+
+ /*
+ * First render the prefix into OTHER_ERROR.
+ */
+
+ va_list args;
+ va_start(args, fmt);
+ int bytes_written = vsnprintf(ERROR_DATA->AVRO_OTHER_ERROR, AVRO_ERROR_SIZE, fmt, args);
+ va_end(args);
+
+ /*
+ * Then concatenate the existing error onto the end.
+ */
+
+ if (bytes_written < AVRO_ERROR_SIZE) {
+ strncpy(&ERROR_DATA->AVRO_OTHER_ERROR[bytes_written], ERROR_DATA->AVRO_CURRENT_ERROR,
+ AVRO_ERROR_SIZE - bytes_written);
+ ERROR_DATA->AVRO_OTHER_ERROR[AVRO_ERROR_SIZE-1] = '\0';
+ }
+
+ /*
+ * Swap the two error pointers.
+ */
+
+ char *tmp;
+ tmp = ERROR_DATA->AVRO_OTHER_ERROR;
+ ERROR_DATA->AVRO_OTHER_ERROR = ERROR_DATA->AVRO_CURRENT_ERROR;
+ ERROR_DATA->AVRO_CURRENT_ERROR = tmp;
+ //fprintf(stderr, "+++ %s\n", AVRO_CURRENT_ERROR);
+}
+
+
+const char *avro_strerror(void)
+{
+ return avro_get_error_data()->AVRO_CURRENT_ERROR;
+}
diff --git a/fluent-bit/lib/avro/src/generic.c b/fluent-bit/lib/avro/src/generic.c
new file mode 100644
index 000000000..e614eb3f8
--- /dev/null
+++ b/fluent-bit/lib/avro/src/generic.c
@@ -0,0 +1,3707 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <avro/platform.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro/allocation.h"
+#include "avro/data.h"
+#include "avro/errors.h"
+#include "avro/generic.h"
+#include "avro/refcount.h"
+#include "avro/schema.h"
+#include "avro/value.h"
+#include "avro_generic_internal.h"
+#include "avro_private.h"
+
+
+/*-----------------------------------------------------------------------
+ * Forward definitions
+ */
+
+typedef struct avro_generic_link_value_iface avro_generic_link_value_iface_t;
+
+typedef struct memoize_state_t {
+ avro_memoize_t mem;
+ avro_generic_link_value_iface_t *links;
+} memoize_state_t;
+
+static avro_generic_value_iface_t *
+avro_generic_class_from_schema_memoized(avro_schema_t schema,
+ memoize_state_t *state);
+
+
+/*-----------------------------------------------------------------------
+ * Generic support functions
+ */
+
+int
+avro_generic_value_new(avro_value_iface_t *iface, avro_value_t *dest)
+{
+ int rval;
+ avro_generic_value_iface_t *giface =
+ container_of(iface, avro_generic_value_iface_t, parent);
+ size_t instance_size = avro_value_instance_size(giface);
+ void *self = avro_malloc(instance_size + sizeof(volatile int));
+ if (self == NULL) {
+ avro_set_error(strerror(ENOMEM));
+ dest->iface = NULL;
+ dest->self = NULL;
+ return ENOMEM;
+ }
+
+ volatile int *refcount = (volatile int *) self;
+ self = (char *) self + sizeof(volatile int);
+
+ *refcount = 1;
+ rval = avro_value_init(giface, self);
+ if (rval != 0) {
+ avro_free(self, instance_size);
+ dest->iface = NULL;
+ dest->self = NULL;
+ return rval;
+ }
+
+ dest->iface = avro_value_iface_incref(&giface->parent);
+ dest->self = self;
+ return 0;
+}
+
+static void
+avro_generic_value_free(const avro_value_iface_t *iface, void *self)
+{
+ if (self != NULL) {
+ const avro_generic_value_iface_t *giface =
+ container_of(iface, avro_generic_value_iface_t, parent);
+ size_t instance_size = avro_value_instance_size(giface);
+ avro_value_done(giface, self);
+ self = (char *) self - sizeof(volatile int);
+ avro_free(self, instance_size + sizeof(volatile int));
+ }
+}
+
+static void
+avro_generic_value_incref(avro_value_t *value)
+{
+ /*
+ * This only works if you pass in the top-level value.
+ */
+
+ volatile int *refcount = (volatile int *) ((char *) value->self - sizeof(volatile int));
+ avro_refcount_inc(refcount);
+}
+
+static void
+avro_generic_value_decref(avro_value_t *value)
+{
+ /*
+ * This only works if you pass in the top-level value.
+ */
+
+ volatile int *refcount = (volatile int *) ((char *) value->self - sizeof(volatile int));
+ if (avro_refcount_dec(refcount)) {
+ avro_generic_value_free(value->iface, value->self);
+ }
+}
+
+
+/*-----------------------------------------------------------------------
+ * Recursive schemas
+ */
+
+/*
+ * Recursive schemas are handled specially; the value implementation for
+ * an AVRO_LINK schema is simply a wrapper around the value
+ * implementation for the link's target schema. The value methods all
+ * delegate to the wrapped implementation.
+ *
+ * We don't set the target_iface pointer when the link implementation is
+ * first created, since we might not have finished creating the
+ * implementation for the target schema. (We create the implementations
+ * for child schemas depth-first, so the target schema's implementation
+ * won't be done until all of its descendants — including the link
+ * schema — have been instantiated.)
+ *
+ * So anyway, we set the target_iface pointer to NULL at first. And
+ * then in a fix-up stage, once all of the non-link schemas have been
+ * instantiated, we go through and set the target_iface pointers for any
+ * link schemas we encountered.
+ */
+
+struct avro_generic_link_value_iface {
+ avro_generic_value_iface_t parent;
+
+ /** The reference count for this interface. */
+ volatile int refcount;
+
+ /** The schema for this interface. */
+ avro_schema_t schema;
+
+ /** The target's implementation. */
+ avro_generic_value_iface_t *target_giface;
+
+ /**
+ * A pointer to the “next” link interface that we've had to
+ * create. We use this as we're creating the overall top-level
+ * value interface to keep track of which ones we have to fix up
+ * afterwards.
+ */
+ avro_generic_link_value_iface_t *next;
+};
+
+
+static avro_value_iface_t *
+avro_generic_link_incref_iface(avro_value_iface_t *viface)
+{
+ avro_generic_link_value_iface_t *iface =
+ container_of(viface, avro_generic_link_value_iface_t, parent);
+ avro_refcount_inc(&iface->refcount);
+ return viface;
+}
+
+static void
+avro_generic_link_decref_iface(avro_value_iface_t *viface)
+{
+ avro_generic_link_value_iface_t *iface =
+ container_of(viface, avro_generic_link_value_iface_t, parent.parent);
+
+ if (avro_refcount_dec(&iface->refcount)) {
+ /* We don't keep a reference to the target
+ * implementation, since that would give us a reference
+ * cycle. */
+ /* We do however keep a reference to the target
+ * schema, which we need to decrement before freeing
+ * the link */
+ avro_schema_decref(iface->schema);
+ avro_freet(avro_generic_link_value_iface_t, iface);
+ }
+}
+
+
+static int
+avro_generic_link_reset(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_reset(self);
+}
+
+static avro_type_t
+avro_generic_link_get_type(const avro_value_iface_t *viface, const void *vself)
+{
+ AVRO_UNUSED(viface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_type(self);
+}
+
+static avro_schema_t
+avro_generic_link_get_schema(const avro_value_iface_t *viface, const void *vself)
+{
+ AVRO_UNUSED(viface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_schema(self);
+}
+
+static int
+avro_generic_link_get_boolean(const avro_value_iface_t *iface,
+ const void *vself, int *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_boolean(self, out);
+}
+
+static int
+avro_generic_link_get_bytes(const avro_value_iface_t *iface,
+ const void *vself, const void **buf, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_bytes(self, buf, size);
+}
+
+static int
+avro_generic_link_grab_bytes(const avro_value_iface_t *iface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_grab_bytes(self, dest);
+}
+
+static int
+avro_generic_link_get_double(const avro_value_iface_t *iface,
+ const void *vself, double *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_double(self, out);
+}
+
+static int
+avro_generic_link_get_float(const avro_value_iface_t *iface,
+ const void *vself, float *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_float(self, out);
+}
+
+static int
+avro_generic_link_get_int(const avro_value_iface_t *iface,
+ const void *vself, int32_t *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_int(self, out);
+}
+
+static int
+avro_generic_link_get_long(const avro_value_iface_t *iface,
+ const void *vself, int64_t *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_long(self, out);
+}
+
+static int
+avro_generic_link_get_null(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_null(self);
+}
+
+static int
+avro_generic_link_get_string(const avro_value_iface_t *iface,
+ const void *vself, const char **str, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_string(self, str, size);
+}
+
+static int
+avro_generic_link_grab_string(const avro_value_iface_t *iface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_grab_string(self, dest);
+}
+
+static int
+avro_generic_link_get_enum(const avro_value_iface_t *iface,
+ const void *vself, int *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_enum(self, out);
+}
+
+static int
+avro_generic_link_get_fixed(const avro_value_iface_t *iface,
+ const void *vself, const void **buf, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_fixed(self, buf, size);
+}
+
+static int
+avro_generic_link_grab_fixed(const avro_value_iface_t *iface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_grab_fixed(self, dest);
+}
+
+static int
+avro_generic_link_set_boolean(const avro_value_iface_t *iface,
+ void *vself, int val)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_set_boolean(self, val);
+}
+
+static int
+avro_generic_link_set_bytes(const avro_value_iface_t *iface,
+ void *vself, void *buf, size_t size)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_set_bytes(self, buf, size);
+}
+
+static int
+avro_generic_link_give_bytes(const avro_value_iface_t *iface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_give_bytes(self, buf);
+}
+
+static int
+avro_generic_link_set_double(const avro_value_iface_t *iface,
+ void *vself, double val)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_set_double(self, val);
+}
+
+static int
+avro_generic_link_set_float(const avro_value_iface_t *iface,
+ void *vself, float val)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_set_float(self, val);
+}
+
+static int
+avro_generic_link_set_int(const avro_value_iface_t *iface,
+ void *vself, int32_t val)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_set_int(self, val);
+}
+
+static int
+avro_generic_link_set_long(const avro_value_iface_t *iface,
+ void *vself, int64_t val)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_set_long(self, val);
+}
+
+static int
+avro_generic_link_set_null(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_set_null(self);
+}
+
+static int
+avro_generic_link_set_string(const avro_value_iface_t *iface,
+ void *vself, const char *str)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_set_string(self, str);
+}
+
+static int
+avro_generic_link_set_string_len(const avro_value_iface_t *iface,
+ void *vself, const char *str, size_t size)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_set_string_len(self, str, size);
+}
+
+static int
+avro_generic_link_give_string_len(const avro_value_iface_t *iface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_give_string_len(self, buf);
+}
+
+static int
+avro_generic_link_set_enum(const avro_value_iface_t *iface,
+ void *vself, int val)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_set_enum(self, val);
+}
+
+static int
+avro_generic_link_set_fixed(const avro_value_iface_t *iface,
+ void *vself, void *buf, size_t size)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_set_fixed(self, buf, size);
+}
+
+static int
+avro_generic_link_give_fixed(const avro_value_iface_t *iface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_give_fixed(self, buf);
+}
+
+static int
+avro_generic_link_get_size(const avro_value_iface_t *iface,
+ const void *vself, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_size(self, size);
+}
+
+static int
+avro_generic_link_get_by_index(const avro_value_iface_t *iface,
+ const void *vself, size_t index,
+ avro_value_t *child, const char **name)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_by_index(self, index, child, name);
+}
+
+static int
+avro_generic_link_get_by_name(const avro_value_iface_t *iface,
+ const void *vself, const char *name,
+ avro_value_t *child, size_t *index)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_by_name(self, name, child, index);
+}
+
+static int
+avro_generic_link_get_discriminant(const avro_value_iface_t *iface,
+ const void *vself, int *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_discriminant(self, out);
+}
+
+static int
+avro_generic_link_get_current_branch(const avro_value_iface_t *iface,
+ const void *vself, avro_value_t *branch)
+{
+ AVRO_UNUSED(iface);
+ const avro_value_t *self = (const avro_value_t *) vself;
+ return avro_value_get_current_branch(self, branch);
+}
+
+static int
+avro_generic_link_append(const avro_value_iface_t *iface,
+ void *vself, avro_value_t *child_out,
+ size_t *new_index)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_append(self, child_out, new_index);
+}
+
+static int
+avro_generic_link_add(const avro_value_iface_t *iface,
+ void *vself, const char *key,
+ avro_value_t *child, size_t *index, int *is_new)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_add(self, key, child, index, is_new);
+}
+
+static int
+avro_generic_link_set_branch(const avro_value_iface_t *iface,
+ void *vself, int discriminant,
+ avro_value_t *branch)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ return avro_value_set_branch(self, discriminant, branch);
+}
+
+static size_t
+avro_generic_link_instance_size(const avro_value_iface_t *viface)
+{
+ AVRO_UNUSED(viface);
+ return sizeof(avro_value_t);
+}
+
+static int
+avro_generic_link_init(const avro_value_iface_t *viface, void *vself)
+{
+ int rval;
+
+ avro_generic_link_value_iface_t *iface =
+ container_of(viface, avro_generic_link_value_iface_t, parent.parent);
+
+ avro_value_t *self = (avro_value_t *) vself;
+ ssize_t target_instance_size =
+ avro_value_instance_size(iface->target_giface);
+ if (target_instance_size < 0) {
+ return EINVAL;
+ }
+
+ self->iface = &iface->target_giface->parent;
+
+ if (target_instance_size == 0) {
+ self->self = NULL;
+ } else {
+ self->self = avro_malloc(target_instance_size);
+ if (self->self == NULL) {
+ return ENOMEM;
+ }
+ }
+
+ rval = avro_value_init(iface->target_giface, self->self);
+ if (rval != 0) {
+ avro_free(self->self, target_instance_size);
+ }
+ return rval;
+}
+
+static void
+avro_generic_link_done(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_generic_value_iface_t *target_giface =
+ container_of(self->iface, avro_generic_value_iface_t, parent);
+ size_t target_instance_size = avro_value_instance_size(target_giface);
+ avro_value_done(target_giface, self->self);
+ avro_free(self->self, target_instance_size);
+ self->iface = NULL;
+ self->self = NULL;
+}
+
+static avro_generic_value_iface_t AVRO_GENERIC_LINK_CLASS =
+{
+ {
+ /* "class" methods */
+ avro_generic_link_incref_iface,
+ avro_generic_link_decref_iface,
+ /* general "instance" methods */
+ avro_generic_value_incref,
+ avro_generic_value_decref,
+ avro_generic_link_reset,
+ avro_generic_link_get_type,
+ avro_generic_link_get_schema,
+ /* primitive getters */
+ avro_generic_link_get_boolean,
+ avro_generic_link_get_bytes,
+ avro_generic_link_grab_bytes,
+ avro_generic_link_get_double,
+ avro_generic_link_get_float,
+ avro_generic_link_get_int,
+ avro_generic_link_get_long,
+ avro_generic_link_get_null,
+ avro_generic_link_get_string,
+ avro_generic_link_grab_string,
+ avro_generic_link_get_enum,
+ avro_generic_link_get_fixed,
+ avro_generic_link_grab_fixed,
+ /* primitive setters */
+ avro_generic_link_set_boolean,
+ avro_generic_link_set_bytes,
+ avro_generic_link_give_bytes,
+ avro_generic_link_set_double,
+ avro_generic_link_set_float,
+ avro_generic_link_set_int,
+ avro_generic_link_set_long,
+ avro_generic_link_set_null,
+ avro_generic_link_set_string,
+ avro_generic_link_set_string_len,
+ avro_generic_link_give_string_len,
+ avro_generic_link_set_enum,
+ avro_generic_link_set_fixed,
+ avro_generic_link_give_fixed,
+ /* compound getters */
+ avro_generic_link_get_size,
+ avro_generic_link_get_by_index,
+ avro_generic_link_get_by_name,
+ avro_generic_link_get_discriminant,
+ avro_generic_link_get_current_branch,
+ /* compound setters */
+ avro_generic_link_append,
+ avro_generic_link_add,
+ avro_generic_link_set_branch
+ },
+ avro_generic_link_instance_size,
+ avro_generic_link_init,
+ avro_generic_link_done
+};
+
+static avro_generic_link_value_iface_t *
+avro_generic_link_class(avro_schema_t schema)
+{
+ if (!is_avro_link(schema)) {
+ avro_set_error("Expected link schema");
+ return NULL;
+ }
+
+ avro_generic_link_value_iface_t *iface =
+ (avro_generic_link_value_iface_t *) avro_new(avro_generic_link_value_iface_t);
+ if (iface == NULL) {
+ return NULL;
+ }
+
+ iface->parent = AVRO_GENERIC_LINK_CLASS;
+ iface->refcount = 1;
+ iface->schema = avro_schema_incref(schema);
+ iface->next = NULL;
+ return iface;
+}
+
+
+/*-----------------------------------------------------------------------
+ * boolean
+ */
+
+static int
+avro_generic_boolean_reset(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ int *self = (int *) vself;
+ *self = 0;
+ return 0;
+}
+
+static avro_type_t
+avro_generic_boolean_get_type(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return AVRO_BOOLEAN;
+}
+
+static avro_schema_t
+avro_generic_boolean_get_schema(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return avro_schema_boolean();
+}
+
+static int
+avro_generic_boolean_get(const avro_value_iface_t *iface,
+ const void *vself, int *out)
+{
+ AVRO_UNUSED(iface);
+ const int *self = (const int *) vself;
+ *out = *self;
+ return 0;
+}
+
+static int
+avro_generic_boolean_set(const avro_value_iface_t *iface,
+ void *vself, int val)
+{
+ AVRO_UNUSED(iface);
+ int *self = (int *) vself;
+ *self = val;
+ return 0;
+}
+
+static size_t
+avro_generic_boolean_instance_size(const avro_value_iface_t *iface)
+{
+ AVRO_UNUSED(iface);
+ return sizeof(int);
+}
+
+static int
+avro_generic_boolean_init(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ int *self = (int *) vself;
+ *self = 0;
+ return 0;
+}
+
+static void
+avro_generic_boolean_done(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+}
+
+static avro_generic_value_iface_t AVRO_GENERIC_BOOLEAN_CLASS =
+{
+ {
+ /* "class" methods */
+ NULL, /* incref_iface */
+ NULL, /* decref_iface */
+ /* general "instance" methods */
+ avro_generic_value_incref,
+ avro_generic_value_decref,
+ avro_generic_boolean_reset,
+ avro_generic_boolean_get_type,
+ avro_generic_boolean_get_schema,
+ /* primitive getters */
+ avro_generic_boolean_get,
+ NULL, /* get_bytes */
+ NULL, /* grab_bytes */
+ NULL, /* get_double */
+ NULL, /* get_float */
+ NULL, /* get_int */
+ NULL, /* get_long */
+ NULL, /* get_null */
+ NULL, /* get_string */
+ NULL, /* grab_string */
+ NULL, /* get_enum */
+ NULL, /* get_fixed */
+ NULL, /* grab_fixed */
+ /* primitive setters */
+ avro_generic_boolean_set,
+ NULL, /* set_bytes */
+ NULL, /* give_bytes */
+ NULL, /* set_double */
+ NULL, /* set_float */
+ NULL, /* set_int */
+ NULL, /* set_long */
+ NULL, /* set_null */
+ NULL, /* set_string */
+ NULL, /* set_string_length */
+ NULL, /* give_string_length */
+ NULL, /* set_enum */
+ NULL, /* set_fixed */
+ NULL, /* give_fixed */
+ /* compound getters */
+ NULL, /* get_size */
+ NULL, /* get_by_index */
+ NULL, /* get_by_name */
+ NULL, /* get_discriminant */
+ NULL, /* get_current_branch */
+ /* compound setters */
+ NULL, /* append */
+ NULL, /* add */
+ NULL /* set_branch */
+ },
+ avro_generic_boolean_instance_size,
+ avro_generic_boolean_init,
+ avro_generic_boolean_done
+};
+
+avro_value_iface_t *
+avro_generic_boolean_class(void)
+{
+ return &AVRO_GENERIC_BOOLEAN_CLASS.parent;
+}
+
+int
+avro_generic_boolean_new(avro_value_t *value, int val)
+{
+ int rval;
+ check(rval, avro_generic_value_new(&AVRO_GENERIC_BOOLEAN_CLASS.parent, value));
+ return avro_generic_boolean_set(value->iface, value->self, val);
+}
+
+/*-----------------------------------------------------------------------
+ * bytes
+ */
+
+static int
+avro_generic_bytes_reset(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ avro_raw_string_t *self = (avro_raw_string_t *) vself;
+ avro_raw_string_clear(self);
+ return 0;
+}
+
+static avro_type_t
+avro_generic_bytes_get_type(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return AVRO_BYTES;
+}
+
+static avro_schema_t
+avro_generic_bytes_get_schema(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return avro_schema_bytes();
+}
+
+static int
+avro_generic_bytes_get(const avro_value_iface_t *iface,
+ const void *vself, const void **buf, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_raw_string_t *self = (const avro_raw_string_t *) vself;
+ if (buf != NULL) {
+ *buf = avro_raw_string_get(self);
+ }
+ if (size != NULL) {
+ *size = avro_raw_string_length(self);
+ }
+ return 0;
+}
+
+static int
+avro_generic_bytes_grab(const avro_value_iface_t *iface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(iface);
+ const avro_raw_string_t *self = (const avro_raw_string_t *) vself;
+ return avro_raw_string_grab(self, dest);
+}
+
+static int
+avro_generic_bytes_set(const avro_value_iface_t *iface,
+ void *vself, void *buf, size_t size)
+{
+ AVRO_UNUSED(iface);
+ check_param(EINVAL, buf != NULL, "bytes contents");
+ avro_raw_string_t *self = (avro_raw_string_t *) vself;
+ avro_raw_string_set_length(self, buf, size);
+ return 0;
+}
+
+static int
+avro_generic_bytes_give(const avro_value_iface_t *iface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ AVRO_UNUSED(iface);
+ avro_raw_string_t *self = (avro_raw_string_t *) vself;
+ avro_raw_string_give(self, buf);
+ return 0;
+}
+
+static size_t
+avro_generic_bytes_instance_size(const avro_value_iface_t *iface)
+{
+ AVRO_UNUSED(iface);
+ return sizeof(avro_raw_string_t);
+}
+
+static int
+avro_generic_bytes_init(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ avro_raw_string_t *self = (avro_raw_string_t *) vself;
+ avro_raw_string_init(self);
+ return 0;
+}
+
+static void
+avro_generic_bytes_done(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ avro_raw_string_t *self = (avro_raw_string_t *) vself;
+ avro_raw_string_done(self);
+}
+
+static avro_generic_value_iface_t AVRO_GENERIC_BYTES_CLASS =
+{
+ {
+ /* "class" methods */
+ NULL, /* incref_iface */
+ NULL, /* decref_iface */
+ /* general "instance" methods */
+ avro_generic_value_incref,
+ avro_generic_value_decref,
+ avro_generic_bytes_reset,
+ avro_generic_bytes_get_type,
+ avro_generic_bytes_get_schema,
+ /* primitive getters */
+ NULL, /* get_boolean */
+ avro_generic_bytes_get,
+ avro_generic_bytes_grab,
+ NULL, /* get_double */
+ NULL, /* get_float */
+ NULL, /* get_int */
+ NULL, /* get_long */
+ NULL, /* get_null */
+ NULL, /* get_string */
+ NULL, /* grab_string */
+ NULL, /* get_enum */
+ NULL, /* get_fixed */
+ NULL, /* grab_fixed */
+ /* primitive setters */
+ NULL, /* set_boolean */
+ avro_generic_bytes_set,
+ avro_generic_bytes_give,
+ NULL, /* set_double */
+ NULL, /* set_float */
+ NULL, /* set_int */
+ NULL, /* set_long */
+ NULL, /* set_null */
+ NULL, /* set_string */
+ NULL, /* set_string_length */
+ NULL, /* give_string_length */
+ NULL, /* set_enum */
+ NULL, /* set_fixed */
+ NULL, /* give_fixed */
+ /* compound getters */
+ NULL, /* get_size */
+ NULL, /* get_by_index */
+ NULL, /* get_by_name */
+ NULL, /* get_discriminant */
+ NULL, /* get_current_branch */
+ /* compound setters */
+ NULL, /* append */
+ NULL, /* add */
+ NULL /* set_branch */
+ },
+ avro_generic_bytes_instance_size,
+ avro_generic_bytes_init,
+ avro_generic_bytes_done
+};
+
+avro_value_iface_t *
+avro_generic_bytes_class(void)
+{
+ return &AVRO_GENERIC_BYTES_CLASS.parent;
+}
+
+int
+avro_generic_bytes_new(avro_value_t *value, void *buf, size_t size)
+{
+ int rval;
+ check(rval, avro_generic_value_new(&AVRO_GENERIC_BYTES_CLASS.parent, value));
+ return avro_generic_bytes_set(value->iface, value->self, buf, size);
+}
+
+/*-----------------------------------------------------------------------
+ * double
+ */
+
+static int
+avro_generic_double_reset(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ double *self = (double *) vself;
+ *self = 0.0;
+ return 0;
+}
+
+static avro_type_t
+avro_generic_double_get_type(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return AVRO_DOUBLE;
+}
+
+static avro_schema_t
+avro_generic_double_get_schema(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return avro_schema_double();
+}
+
+static int
+avro_generic_double_get(const avro_value_iface_t *iface,
+ const void *vself, double *out)
+{
+ AVRO_UNUSED(iface);
+ const double *self = (const double *) vself;
+ *out = *self;
+ return 0;
+}
+
+static int
+avro_generic_double_set(const avro_value_iface_t *iface,
+ void *vself, double val)
+{
+ AVRO_UNUSED(iface);
+ double *self = (double *) vself;
+ *self = val;
+ return 0;
+}
+
+static size_t
+avro_generic_double_instance_size(const avro_value_iface_t *iface)
+{
+ AVRO_UNUSED(iface);
+ return sizeof(double);
+}
+
+static int
+avro_generic_double_init(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ double *self = (double *) vself;
+ *self = 0.0;
+ return 0;
+}
+
+static void
+avro_generic_double_done(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+}
+
+static avro_generic_value_iface_t AVRO_GENERIC_DOUBLE_CLASS =
+{
+ {
+ /* "class" methods */
+ NULL, /* incref_iface */
+ NULL, /* decref_iface */
+ /* general "instance" methods */
+ avro_generic_value_incref,
+ avro_generic_value_decref,
+ avro_generic_double_reset,
+ avro_generic_double_get_type,
+ avro_generic_double_get_schema,
+ /* primitive getters */
+ NULL, /* get_boolean */
+ NULL, /* get_bytes */
+ NULL, /* grab_bytes */
+ avro_generic_double_get,
+ NULL, /* get_float */
+ NULL, /* get_int */
+ NULL, /* get_long */
+ NULL, /* get_null */
+ NULL, /* get_string */
+ NULL, /* grab_string */
+ NULL, /* get_enum */
+ NULL, /* get_fixed */
+ NULL, /* grab_fixed */
+ /* primitive setters */
+ NULL, /* set_boolean */
+ NULL, /* set_bytes */
+ NULL, /* give_bytes */
+ avro_generic_double_set,
+ NULL, /* set_float */
+ NULL, /* set_int */
+ NULL, /* set_long */
+ NULL, /* set_null */
+ NULL, /* set_string */
+ NULL, /* set_string_length */
+ NULL, /* give_string_length */
+ NULL, /* set_enum */
+ NULL, /* set_fixed */
+ NULL, /* give_fixed */
+ /* compound getters */
+ NULL, /* get_size */
+ NULL, /* get_by_index */
+ NULL, /* get_by_name */
+ NULL, /* get_discriminant */
+ NULL, /* get_current_branch */
+ /* compound setters */
+ NULL, /* append */
+ NULL, /* add */
+ NULL /* set_branch */
+ },
+ avro_generic_double_instance_size,
+ avro_generic_double_init,
+ avro_generic_double_done
+};
+
+avro_value_iface_t *
+avro_generic_double_class(void)
+{
+ return &AVRO_GENERIC_DOUBLE_CLASS.parent;
+}
+
+int
+avro_generic_double_new(avro_value_t *value, double val)
+{
+ int rval;
+ check(rval, avro_generic_value_new(&AVRO_GENERIC_DOUBLE_CLASS.parent, value));
+ return avro_generic_double_set(value->iface, value->self, val);
+}
+
+/*-----------------------------------------------------------------------
+ * float
+ */
+
+static int
+avro_generic_float_reset(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ float *self = (float *) vself;
+ *self = 0.0f;
+ return 0;
+}
+
+static avro_type_t
+avro_generic_float_get_type(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return AVRO_FLOAT;
+}
+
+static avro_schema_t
+avro_generic_float_get_schema(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return avro_schema_float();
+}
+
+static int
+avro_generic_float_get(const avro_value_iface_t *iface,
+ const void *vself, float *out)
+{
+ AVRO_UNUSED(iface);
+ const float *self = (const float *) vself;
+ *out = *self;
+ return 0;
+}
+
+static int
+avro_generic_float_set(const avro_value_iface_t *iface,
+ void *vself, float val)
+{
+ AVRO_UNUSED(iface);
+ float *self = (float *) vself;
+ *self = val;
+ return 0;
+}
+
+static size_t
+avro_generic_float_instance_size(const avro_value_iface_t *iface)
+{
+ AVRO_UNUSED(iface);
+ return sizeof(float);
+}
+
+static int
+avro_generic_float_init(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ float *self = (float *) vself;
+ *self = 0.0f;
+ return 0;
+}
+
+static void
+avro_generic_float_done(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+}
+
+static avro_generic_value_iface_t AVRO_GENERIC_FLOAT_CLASS =
+{
+ {
+ /* "class" methods */
+ NULL, /* incref_iface */
+ NULL, /* decref_iface */
+ /* general "instance" methods */
+ avro_generic_value_incref,
+ avro_generic_value_decref,
+ avro_generic_float_reset,
+ avro_generic_float_get_type,
+ avro_generic_float_get_schema,
+ /* primitive getters */
+ NULL, /* get_boolean */
+ NULL, /* get_bytes */
+ NULL, /* grab_bytes */
+ NULL, /* get_double */
+ avro_generic_float_get,
+ NULL, /* get_int */
+ NULL, /* get_long */
+ NULL, /* get_null */
+ NULL, /* get_string */
+ NULL, /* grab_string */
+ NULL, /* get_enum */
+ NULL, /* get_fixed */
+ NULL, /* grab_fixed */
+ /* primitive setters */
+ NULL, /* set_boolean */
+ NULL, /* set_bytes */
+ NULL, /* give_bytes */
+ NULL, /* set_double */
+ avro_generic_float_set,
+ NULL, /* set_int */
+ NULL, /* set_long */
+ NULL, /* set_null */
+ NULL, /* set_string */
+ NULL, /* set_string_length */
+ NULL, /* give_string_length */
+ NULL, /* set_enum */
+ NULL, /* set_fixed */
+ NULL, /* give_fixed */
+ /* compound getters */
+ NULL, /* get_size */
+ NULL, /* get_by_index */
+ NULL, /* get_by_name */
+ NULL, /* get_discriminant */
+ NULL, /* get_current_branch */
+ /* compound setters */
+ NULL, /* append */
+ NULL, /* add */
+ NULL /* set_branch */
+ },
+ avro_generic_float_instance_size,
+ avro_generic_float_init,
+ avro_generic_float_done
+};
+
+avro_value_iface_t *
+avro_generic_float_class(void)
+{
+ return &AVRO_GENERIC_FLOAT_CLASS.parent;
+}
+
+int
+avro_generic_float_new(avro_value_t *value, float val)
+{
+ int rval;
+ check(rval, avro_generic_value_new(&AVRO_GENERIC_FLOAT_CLASS.parent, value));
+ return avro_generic_float_set(value->iface, value->self, val);
+}
+
+/*-----------------------------------------------------------------------
+ * int
+ */
+
+static int
+avro_generic_int_reset(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ int32_t *self = (int32_t *) vself;
+ *self = 0;
+ return 0;
+}
+
+static avro_type_t
+avro_generic_int_get_type(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return AVRO_INT32;
+}
+
+static avro_schema_t
+avro_generic_int_get_schema(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return avro_schema_int();
+}
+
+static int
+avro_generic_int_get(const avro_value_iface_t *iface,
+ const void *vself, int32_t *out)
+{
+ AVRO_UNUSED(iface);
+ const int32_t *self = (const int32_t *) vself;
+ *out = *self;
+ return 0;
+}
+
+static int
+avro_generic_int_set(const avro_value_iface_t *iface,
+ void *vself, int32_t val)
+{
+ AVRO_UNUSED(iface);
+ int32_t *self = (int32_t *) vself;
+ *self = val;
+ return 0;
+}
+
+static size_t
+avro_generic_int_instance_size(const avro_value_iface_t *iface)
+{
+ AVRO_UNUSED(iface);
+ return sizeof(int32_t);
+}
+
+static int
+avro_generic_int_init(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ int32_t *self = (int32_t *) vself;
+ *self = 0;
+ return 0;
+}
+
+static void
+avro_generic_int_done(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+}
+
+static avro_generic_value_iface_t AVRO_GENERIC_INT_CLASS =
+{
+ {
+ /* "class" methods */
+ NULL, /* incref_iface */
+ NULL, /* decref_iface */
+ /* general "instance" methods */
+ avro_generic_value_incref,
+ avro_generic_value_decref,
+ avro_generic_int_reset,
+ avro_generic_int_get_type,
+ avro_generic_int_get_schema,
+ /* primitive getters */
+ NULL, /* get_boolean */
+ NULL, /* get_bytes */
+ NULL, /* grab_bytes */
+ NULL, /* get_double */
+ NULL, /* get_float */
+ avro_generic_int_get,
+ NULL, /* get_long */
+ NULL, /* get_null */
+ NULL, /* get_string */
+ NULL, /* grab_string */
+ NULL, /* get_enum */
+ NULL, /* get_fixed */
+ NULL, /* grab_fixed */
+ /* primitive setters */
+ NULL, /* set_boolean */
+ NULL, /* set_bytes */
+ NULL, /* give_bytes */
+ NULL, /* set_double */
+ NULL, /* set_float */
+ avro_generic_int_set,
+ NULL, /* set_long */
+ NULL, /* set_null */
+ NULL, /* set_string */
+ NULL, /* set_string_length */
+ NULL, /* give_string_length */
+ NULL, /* set_enum */
+ NULL, /* set_fixed */
+ NULL, /* give_fixed */
+ /* compound getters */
+ NULL, /* get_size */
+ NULL, /* get_by_index */
+ NULL, /* get_by_name */
+ NULL, /* get_discriminant */
+ NULL, /* get_current_branch */
+ /* compound setters */
+ NULL, /* append */
+ NULL, /* add */
+ NULL /* set_branch */
+ },
+ avro_generic_int_instance_size,
+ avro_generic_int_init,
+ avro_generic_int_done
+};
+
+avro_value_iface_t *
+avro_generic_int_class(void)
+{
+ return &AVRO_GENERIC_INT_CLASS.parent;
+}
+
+int
+avro_generic_int_new(avro_value_t *value, int32_t val)
+{
+ int rval;
+ check(rval, avro_generic_value_new(&AVRO_GENERIC_INT_CLASS.parent, value));
+ return avro_generic_int_set(value->iface, value->self, val);
+}
+
+/*-----------------------------------------------------------------------
+ * long
+ */
+
+static int
+avro_generic_long_reset(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ int64_t *self = (int64_t *) vself;
+ *self = 0;
+ return 0;
+}
+
+static avro_type_t
+avro_generic_long_get_type(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return AVRO_INT64;
+}
+
+static avro_schema_t
+avro_generic_long_get_schema(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return avro_schema_long();
+}
+
+static int
+avro_generic_long_get(const avro_value_iface_t *iface,
+ const void *vself, int64_t *out)
+{
+ AVRO_UNUSED(iface);
+ const int64_t *self = (const int64_t *) vself;
+ *out = *self;
+ return 0;
+}
+
+static int
+avro_generic_long_set(const avro_value_iface_t *iface,
+ void *vself, int64_t val)
+{
+ AVRO_UNUSED(iface);
+ int64_t *self = (int64_t *) vself;
+ *self = val;
+ return 0;
+}
+
+static size_t
+avro_generic_long_instance_size(const avro_value_iface_t *iface)
+{
+ AVRO_UNUSED(iface);
+ return sizeof(int64_t);
+}
+
+static int
+avro_generic_long_init(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ int64_t *self = (int64_t *) vself;
+ *self = 0;
+ return 0;
+}
+
+static void
+avro_generic_long_done(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+}
+
+static avro_generic_value_iface_t AVRO_GENERIC_LONG_CLASS =
+{
+ {
+ /* "class" methods */
+ NULL, /* incref_iface */
+ NULL, /* decref_iface */
+ /* general "instance" methods */
+ avro_generic_value_incref,
+ avro_generic_value_decref,
+ avro_generic_long_reset,
+ avro_generic_long_get_type,
+ avro_generic_long_get_schema,
+ /* primitive getters */
+ NULL, /* get_boolean */
+ NULL, /* get_bytes */
+ NULL, /* grab_bytes */
+ NULL, /* get_double */
+ NULL, /* get_float */
+ NULL, /* get_int */
+ avro_generic_long_get,
+ NULL, /* get_null */
+ NULL, /* get_string */
+ NULL, /* grab_string */
+ NULL, /* get_enum */
+ NULL, /* get_fixed */
+ NULL, /* grab_fixed */
+ /* primitive setters */
+ NULL, /* set_boolean */
+ NULL, /* set_bytes */
+ NULL, /* give_bytes */
+ NULL, /* set_double */
+ NULL, /* set_float */
+ NULL, /* set_int */
+ avro_generic_long_set,
+ NULL, /* set_null */
+ NULL, /* set_string */
+ NULL, /* set_string_length */
+ NULL, /* give_string_length */
+ NULL, /* set_enum */
+ NULL, /* set_fixed */
+ NULL, /* give_fixed */
+ /* compound getters */
+ NULL, /* get_size */
+ NULL, /* get_by_index */
+ NULL, /* get_by_name */
+ NULL, /* get_discriminant */
+ NULL, /* get_current_branch */
+ /* compound setters */
+ NULL, /* append */
+ NULL, /* add */
+ NULL /* set_branch */
+ },
+ avro_generic_long_instance_size,
+ avro_generic_long_init,
+ avro_generic_long_done
+};
+
+avro_value_iface_t *
+avro_generic_long_class(void)
+{
+ return &AVRO_GENERIC_LONG_CLASS.parent;
+}
+
+int
+avro_generic_long_new(avro_value_t *value, int64_t val)
+{
+ int rval;
+ check(rval, avro_generic_value_new(&AVRO_GENERIC_LONG_CLASS.parent, value));
+ return avro_generic_long_set(value->iface, value->self, val);
+}
+
+/*-----------------------------------------------------------------------
+ * null
+ */
+
+static int
+avro_generic_null_reset(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ int *self = (int *) vself;
+ *self = 0;
+ return 0;
+}
+
+static avro_type_t
+avro_generic_null_get_type(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return AVRO_NULL;
+}
+
+static avro_schema_t
+avro_generic_null_get_schema(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return avro_schema_null();
+}
+
+static int
+avro_generic_null_get(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return 0;
+}
+
+static int
+avro_generic_null_set(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return 0;
+}
+
+static size_t
+avro_generic_null_instance_size(const avro_value_iface_t *iface)
+{
+ AVRO_UNUSED(iface);
+ return sizeof(int);
+}
+
+static int
+avro_generic_null_init(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ int *self = (int *) vself;
+ *self = 0;
+ return 0;
+}
+
+static void
+avro_generic_null_done(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+}
+
+static avro_generic_value_iface_t AVRO_GENERIC_NULL_CLASS =
+{
+ {
+ /* "class" methods */
+ NULL, /* incref_iface */
+ NULL, /* decref_iface */
+ /* general "instance" methods */
+ avro_generic_value_incref,
+ avro_generic_value_decref,
+ avro_generic_null_reset,
+ avro_generic_null_get_type,
+ avro_generic_null_get_schema,
+ /* primitive getters */
+ NULL, /* get_boolean */
+ NULL, /* get_bytes */
+ NULL, /* grab_bytes */
+ NULL, /* get_double */
+ NULL, /* get_float */
+ NULL, /* get_int */
+ NULL, /* get_long */
+ avro_generic_null_get,
+ NULL, /* get_string */
+ NULL, /* grab_string */
+ NULL, /* get_enum */
+ NULL, /* get_fixed */
+ NULL, /* grab_fixed */
+ /* primitive setters */
+ NULL, /* set_boolean */
+ NULL, /* set_bytes */
+ NULL, /* give_bytes */
+ NULL, /* set_double */
+ NULL, /* set_float */
+ NULL, /* set_int */
+ NULL, /* set_long */
+ avro_generic_null_set,
+ NULL, /* set_string */
+ NULL, /* set_string_length */
+ NULL, /* give_string_length */
+ NULL, /* set_enum */
+ NULL, /* set_fixed */
+ NULL, /* give_fixed */
+ /* compound getters */
+ NULL, /* get_size */
+ NULL, /* get_by_index */
+ NULL, /* get_by_name */
+ NULL, /* get_discriminant */
+ NULL, /* get_current_branch */
+ /* compound setters */
+ NULL, /* append */
+ NULL, /* add */
+ NULL /* set_branch */
+ },
+ avro_generic_null_instance_size,
+ avro_generic_null_init,
+ avro_generic_null_done
+};
+
+avro_value_iface_t *
+avro_generic_null_class(void)
+{
+ return &AVRO_GENERIC_NULL_CLASS.parent;
+}
+
+int
+avro_generic_null_new(avro_value_t *value)
+{
+ return avro_generic_value_new(&AVRO_GENERIC_NULL_CLASS.parent, value);
+}
+
+/*-----------------------------------------------------------------------
+ * string
+ */
+
+static int
+avro_generic_string_reset(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ avro_raw_string_t *self = (avro_raw_string_t *) vself;
+ avro_raw_string_clear(self);
+ return 0;
+}
+
+static avro_type_t
+avro_generic_string_get_type(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return AVRO_STRING;
+}
+
+static avro_schema_t
+avro_generic_string_get_schema(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return avro_schema_string();
+}
+
+static int
+avro_generic_string_get(const avro_value_iface_t *iface,
+ const void *vself, const char **str, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_raw_string_t *self = (const avro_raw_string_t *) vself;
+ const char *contents = (const char *) avro_raw_string_get(self);
+
+ if (str != NULL) {
+ /*
+ * We can't return a NULL string, we have to return an
+ * *empty* string
+ */
+
+ *str = (contents == NULL)? "": contents;
+ }
+ if (size != NULL) {
+ /* raw_string's length includes the NUL terminator,
+ * unless it's empty */
+ *size = (contents == NULL)? 1: avro_raw_string_length(self);
+ }
+ return 0;
+}
+
+static int
+avro_generic_string_grab(const avro_value_iface_t *iface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(iface);
+ const avro_raw_string_t *self = (const avro_raw_string_t *) vself;
+ const char *contents = (const char *) avro_raw_string_get(self);
+
+ if (contents == NULL) {
+ return avro_wrapped_buffer_new(dest, "", 1);
+ } else {
+ return avro_raw_string_grab(self, dest);
+ }
+}
+
+static int
+avro_generic_string_set(const avro_value_iface_t *iface,
+ void *vself, const char *val)
+{
+ AVRO_UNUSED(iface);
+ check_param(EINVAL, val != NULL, "string contents");
+
+ /*
+ * This raw_string method ensures that we copy the NUL
+ * terminator from val, and will include the NUL terminator in
+ * the raw_string's length, which is what we want.
+ */
+ avro_raw_string_t *self = (avro_raw_string_t *) vself;
+ avro_raw_string_set(self, val);
+ return 0;
+}
+
+static int
+avro_generic_string_set_length(const avro_value_iface_t *iface,
+ void *vself, const char *val, size_t size)
+{
+ AVRO_UNUSED(iface);
+ check_param(EINVAL, val != NULL, "string contents");
+ avro_raw_string_t *self = (avro_raw_string_t *) vself;
+ avro_raw_string_set_length(self, val, size);
+ return 0;
+}
+
+static int
+avro_generic_string_give_length(const avro_value_iface_t *iface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ AVRO_UNUSED(iface);
+ avro_raw_string_t *self = (avro_raw_string_t *) vself;
+ avro_raw_string_give(self, buf);
+ return 0;
+}
+
+static size_t
+avro_generic_string_instance_size(const avro_value_iface_t *iface)
+{
+ AVRO_UNUSED(iface);
+ return sizeof(avro_raw_string_t);
+}
+
+static int
+avro_generic_string_init(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ avro_raw_string_t *self = (avro_raw_string_t *) vself;
+ avro_raw_string_init(self);
+ return 0;
+}
+
+static void
+avro_generic_string_done(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ avro_raw_string_t *self = (avro_raw_string_t *) vself;
+ avro_raw_string_done(self);
+}
+
+static avro_generic_value_iface_t AVRO_GENERIC_STRING_CLASS =
+{
+ {
+ /* "class" methods */
+ NULL, /* incref_iface */
+ NULL, /* decref_iface */
+ /* general "instance" methods */
+ avro_generic_value_incref,
+ avro_generic_value_decref,
+ avro_generic_string_reset,
+ avro_generic_string_get_type,
+ avro_generic_string_get_schema,
+ /* primitive getters */
+ NULL, /* get_boolean */
+ NULL, /* get_bytes */
+ NULL, /* grab_bytes */
+ NULL, /* get_double */
+ NULL, /* get_float */
+ NULL, /* get_int */
+ NULL, /* get_long */
+ NULL, /* get_null */
+ avro_generic_string_get,
+ avro_generic_string_grab,
+ NULL, /* get_enum */
+ NULL, /* get_fixed */
+ NULL, /* grab_fixed */
+ /* primitive setters */
+ NULL, /* set_boolean */
+ NULL, /* set_bytes */
+ NULL, /* give_bytes */
+ NULL, /* set_double */
+ NULL, /* set_float */
+ NULL, /* set_int */
+ NULL, /* set_long */
+ NULL, /* set_null */
+ avro_generic_string_set,
+ avro_generic_string_set_length,
+ avro_generic_string_give_length,
+ NULL, /* set_enum */
+ NULL, /* set_fixed */
+ NULL, /* give_fixed */
+ /* compound getters */
+ NULL, /* get_size */
+ NULL, /* get_by_index */
+ NULL, /* get_by_name */
+ NULL, /* get_discriminant */
+ NULL, /* get_current_branch */
+ /* compound setters */
+ NULL, /* append */
+ NULL, /* add */
+ NULL /* set_branch */
+ },
+ avro_generic_string_instance_size,
+ avro_generic_string_init,
+ avro_generic_string_done
+};
+
+avro_value_iface_t *
+avro_generic_string_class(void)
+{
+ return &AVRO_GENERIC_STRING_CLASS.parent;
+}
+
+int
+avro_generic_string_new(avro_value_t *value, const char *str)
+{
+ int rval;
+ check(rval, avro_generic_value_new(&AVRO_GENERIC_STRING_CLASS.parent, value));
+ return avro_generic_string_set(value->iface, value->self, str);
+}
+
+int
+avro_generic_string_new_length(avro_value_t *value, const char *str, size_t size)
+{
+ int rval;
+ check(rval, avro_generic_value_new(&AVRO_GENERIC_STRING_CLASS.parent, value));
+ return avro_generic_string_set_length(value->iface, value->self, str, size);
+}
+
+
+/*-----------------------------------------------------------------------
+ * array
+ */
+
+/*
+ * For generic arrays, we need to store the value implementation for the
+ * array's elements.
+ */
+
+typedef struct avro_generic_array_value_iface {
+ avro_generic_value_iface_t parent;
+ volatile int refcount;
+ avro_schema_t schema;
+ avro_generic_value_iface_t *child_giface;
+} avro_generic_array_value_iface_t;
+
+typedef struct avro_generic_array {
+ avro_raw_array_t array;
+} avro_generic_array_t;
+
+
+static avro_value_iface_t *
+avro_generic_array_incref_iface(avro_value_iface_t *viface)
+{
+ avro_generic_array_value_iface_t *iface =
+ container_of(viface, avro_generic_array_value_iface_t, parent);
+ avro_refcount_inc(&iface->refcount);
+ return viface;
+}
+
+static void
+avro_generic_array_decref_iface(avro_value_iface_t *viface)
+{
+ avro_generic_array_value_iface_t *iface =
+ container_of(viface, avro_generic_array_value_iface_t, parent);
+ if (avro_refcount_dec(&iface->refcount)) {
+ avro_schema_decref(iface->schema);
+ avro_value_iface_decref(&iface->child_giface->parent);
+ avro_freet(avro_generic_array_value_iface_t, iface);
+ }
+}
+
+
+static void
+avro_generic_array_free_elements(const avro_generic_value_iface_t *child_giface,
+ avro_generic_array_t *self)
+{
+ size_t i;
+ for (i = 0; i < avro_raw_array_size(&self->array); i++) {
+ void *child_self = avro_raw_array_get_raw(&self->array, i);
+ avro_value_done(child_giface, child_self);
+ }
+}
+
+static int
+avro_generic_array_reset(const avro_value_iface_t *viface, void *vself)
+{
+ const avro_generic_array_value_iface_t *iface =
+ container_of(viface, avro_generic_array_value_iface_t, parent);
+ avro_generic_array_t *self = (avro_generic_array_t *) vself;
+ avro_generic_array_free_elements(iface->child_giface, self);
+ avro_raw_array_clear(&self->array);
+ return 0;
+}
+
+static avro_type_t
+avro_generic_array_get_type(const avro_value_iface_t *viface, const void *vself)
+{
+ AVRO_UNUSED(viface);
+ AVRO_UNUSED(vself);
+ return AVRO_ARRAY;
+}
+
+static avro_schema_t
+avro_generic_array_get_schema(const avro_value_iface_t *viface, const void *vself)
+{
+ const avro_generic_array_value_iface_t *iface =
+ container_of(viface, avro_generic_array_value_iface_t, parent);
+ AVRO_UNUSED(vself);
+ return iface->schema;
+}
+
+static int
+avro_generic_array_get_size(const avro_value_iface_t *viface,
+ const void *vself, size_t *size)
+{
+ AVRO_UNUSED(viface);
+ const avro_generic_array_t *self = (const avro_generic_array_t *) vself;
+ if (size != NULL) {
+ *size = avro_raw_array_size(&self->array);
+ }
+ return 0;
+}
+
+static int
+avro_generic_array_get_by_index(const avro_value_iface_t *viface,
+ const void *vself, size_t index,
+ avro_value_t *child, const char **name)
+{
+ const avro_generic_array_value_iface_t *iface =
+ container_of(viface, avro_generic_array_value_iface_t, parent);
+ AVRO_UNUSED(name);
+ const avro_generic_array_t *self = (avro_generic_array_t *) vself;
+ if (index >= avro_raw_array_size(&self->array)) {
+ avro_set_error("Array index %" PRIsz " out of range", index);
+ return EINVAL;
+ }
+ child->iface = &iface->child_giface->parent;
+ child->self = avro_raw_array_get_raw(&self->array, index);
+ return 0;
+}
+
+static int
+avro_generic_array_append(const avro_value_iface_t *viface,
+ void *vself, avro_value_t *child,
+ size_t *new_index)
+{
+ int rval;
+ const avro_generic_array_value_iface_t *iface =
+ container_of(viface, avro_generic_array_value_iface_t, parent);
+ avro_generic_array_t *self = (avro_generic_array_t *) vself;
+ child->iface = &iface->child_giface->parent;
+ child->self = avro_raw_array_append(&self->array);
+ if (child->self == NULL) {
+ avro_set_error("Couldn't expand array");
+ return ENOMEM;
+ }
+ check(rval, avro_value_init(iface->child_giface, child->self));
+ if (new_index != NULL) {
+ *new_index = avro_raw_array_size(&self->array) - 1;
+ }
+ return 0;
+}
+
+static size_t
+avro_generic_array_instance_size(const avro_value_iface_t *viface)
+{
+ AVRO_UNUSED(viface);
+ return sizeof(avro_generic_array_t);
+}
+
+static int
+avro_generic_array_init(const avro_value_iface_t *viface, void *vself)
+{
+ const avro_generic_array_value_iface_t *iface =
+ container_of(viface, avro_generic_array_value_iface_t, parent);
+ avro_generic_array_t *self = (avro_generic_array_t *) vself;
+
+ size_t child_size = avro_value_instance_size(iface->child_giface);
+ avro_raw_array_init(&self->array, child_size);
+ return 0;
+}
+
+static void
+avro_generic_array_done(const avro_value_iface_t *viface, void *vself)
+{
+ const avro_generic_array_value_iface_t *iface =
+ container_of(viface, avro_generic_array_value_iface_t, parent);
+ avro_generic_array_t *self = (avro_generic_array_t *) vself;
+ avro_generic_array_free_elements(iface->child_giface, self);
+ avro_raw_array_done(&self->array);
+}
+
+static avro_generic_value_iface_t AVRO_GENERIC_ARRAY_CLASS =
+{
+{
+ /* "class" methods */
+ avro_generic_array_incref_iface,
+ avro_generic_array_decref_iface,
+ /* general "instance" methods */
+ avro_generic_value_incref,
+ avro_generic_value_decref,
+ avro_generic_array_reset,
+ avro_generic_array_get_type,
+ avro_generic_array_get_schema,
+ /* primitive getters */
+ NULL, /* get_boolean */
+ NULL, /* get_bytes */
+ NULL, /* grab_bytes */
+ NULL, /* get_double */
+ NULL, /* get_float */
+ NULL, /* get_int */
+ NULL, /* get_long */
+ NULL, /* get_null */
+ NULL, /* get_string */
+ NULL, /* grab_string */
+ NULL, /* get_enum */
+ NULL, /* get_fixed */
+ NULL, /* grab_fixed */
+ /* primitive setters */
+ NULL, /* set_boolean */
+ NULL, /* set_bytes */
+ NULL, /* give_bytes */
+ NULL, /* set_double */
+ NULL, /* set_float */
+ NULL, /* set_int */
+ NULL, /* set_long */
+ NULL, /* set_null */
+ NULL, /* set_string */
+ NULL, /* set_string_length */
+ NULL, /* give_string_length */
+ NULL, /* set_enum */
+ NULL, /* set_fixed */
+ NULL, /* give_fixed */
+ /* compound getters */
+ avro_generic_array_get_size,
+ avro_generic_array_get_by_index,
+ NULL, /* get_by_name */
+ NULL, /* get_discriminant */
+ NULL, /* get_current_branch */
+ /* compound setters */
+ avro_generic_array_append,
+ NULL, /* add */
+ NULL /* set_branch */
+},
+ avro_generic_array_instance_size,
+ avro_generic_array_init,
+ avro_generic_array_done
+};
+
+static avro_generic_value_iface_t *
+avro_generic_array_class(avro_schema_t schema, memoize_state_t *state)
+{
+ avro_schema_t child_schema = avro_schema_array_items(schema);
+ avro_generic_value_iface_t *child_giface =
+ avro_generic_class_from_schema_memoized(child_schema, state);
+ if (child_giface == NULL) {
+ return NULL;
+ }
+
+ ssize_t child_size = avro_value_instance_size(child_giface);
+ if (child_size < 0) {
+ avro_set_error("Array item class must provide instance_size");
+ avro_value_iface_decref(&child_giface->parent);
+ return NULL;
+ }
+
+ avro_generic_array_value_iface_t *iface =
+ (avro_generic_array_value_iface_t *) avro_new(avro_generic_array_value_iface_t);
+ if (iface == NULL) {
+ avro_value_iface_decref(&child_giface->parent);
+ return NULL;
+ }
+
+ /*
+ * TODO: Maybe check that schema.items matches
+ * child_iface.get_schema?
+ */
+
+ iface->parent = AVRO_GENERIC_ARRAY_CLASS;
+ iface->refcount = 1;
+ iface->schema = avro_schema_incref(schema);
+ iface->child_giface = child_giface;
+ return &iface->parent;
+}
+
+
+/*-----------------------------------------------------------------------
+ * enum
+ */
+
+typedef struct avro_generic_enum_value_iface {
+ avro_generic_value_iface_t parent;
+ volatile int refcount;
+ avro_schema_t schema;
+} avro_generic_enum_value_iface_t;
+
+
+static avro_value_iface_t *
+avro_generic_enum_incref_iface(avro_value_iface_t *viface)
+{
+ avro_generic_enum_value_iface_t *iface =
+ (avro_generic_enum_value_iface_t *) viface;
+ avro_refcount_inc(&iface->refcount);
+ return viface;
+}
+
+static void
+avro_generic_enum_decref_iface(avro_value_iface_t *viface)
+{
+ avro_generic_enum_value_iface_t *iface =
+ (avro_generic_enum_value_iface_t *) viface;
+ if (avro_refcount_dec(&iface->refcount)) {
+ avro_schema_decref(iface->schema);
+ avro_freet(avro_generic_enum_value_iface_t, iface);
+ }
+}
+
+static int
+avro_generic_enum_reset(const avro_value_iface_t *viface, void *vself)
+{
+ AVRO_UNUSED(viface);
+ int *self = (int *) vself;
+ *self = 0;
+ return 0;
+}
+
+static avro_type_t
+avro_generic_enum_get_type(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return AVRO_ENUM;
+}
+
+static avro_schema_t
+avro_generic_enum_get_schema(const avro_value_iface_t *viface, const void *vself)
+{
+ const avro_generic_enum_value_iface_t *iface =
+ container_of(viface, avro_generic_enum_value_iface_t, parent);
+ AVRO_UNUSED(vself);
+ return iface->schema;
+}
+
+static int
+avro_generic_enum_get(const avro_value_iface_t *viface,
+ const void *vself, int *out)
+{
+ AVRO_UNUSED(viface);
+ const int *self = (const int *) vself;
+ *out = *self;
+ return 0;
+}
+
+static int
+avro_generic_enum_set(const avro_value_iface_t *viface,
+ void *vself, int val)
+{
+ AVRO_UNUSED(viface);
+ int *self = (int *) vself;
+ *self = val;
+ return 0;
+}
+
+static size_t
+avro_generic_enum_instance_size(const avro_value_iface_t *viface)
+{
+ AVRO_UNUSED(viface);
+ return sizeof(int);
+}
+
+static int
+avro_generic_enum_init(const avro_value_iface_t *viface, void *vself)
+{
+ AVRO_UNUSED(viface);
+ int *self = (int *) vself;
+ *self = 0;
+ return 0;
+}
+
+static void
+avro_generic_enum_done(const avro_value_iface_t *viface, void *vself)
+{
+ AVRO_UNUSED(viface);
+ AVRO_UNUSED(vself);
+}
+
+static avro_generic_value_iface_t AVRO_GENERIC_ENUM_CLASS =
+{
+ {
+ /* "class" methods */
+ avro_generic_enum_incref_iface,
+ avro_generic_enum_decref_iface,
+ /* general "instance" methods */
+ avro_generic_value_incref,
+ avro_generic_value_decref,
+ avro_generic_enum_reset,
+ avro_generic_enum_get_type,
+ avro_generic_enum_get_schema,
+ /* primitive getters */
+ NULL, /* get_boolean */
+ NULL, /* get_bytes */
+ NULL, /* grab_bytes */
+ NULL, /* get_double */
+ NULL, /* get_float */
+ NULL, /* get_int */
+ NULL, /* get_long */
+ NULL, /* get_null */
+ NULL, /* get_string */
+ NULL, /* grab_string */
+ avro_generic_enum_get,
+ NULL, /* get_fixed */
+ NULL, /* grab_fixed */
+ /* primitive setters */
+ NULL, /* set_boolean */
+ NULL, /* set_bytes */
+ NULL, /* give_bytes */
+ NULL, /* set_double */
+ NULL, /* set_float */
+ NULL, /* set_int */
+ NULL, /* set_long */
+ NULL, /* set_null */
+ NULL, /* set_string */
+ NULL, /* set_string_length */
+ NULL, /* give_string_length */
+ avro_generic_enum_set,
+ NULL, /* set_fixed */
+ NULL, /* give_fixed */
+ /* compound getters */
+ NULL, /* get_size */
+ NULL, /* get_by_index */
+ NULL, /* get_by_name */
+ NULL, /* get_discriminant */
+ NULL, /* get_current_branch */
+ /* compound setters */
+ NULL, /* append */
+ NULL, /* add */
+ NULL /* set_branch */
+ },
+ avro_generic_enum_instance_size,
+ avro_generic_enum_init,
+ avro_generic_enum_done
+};
+
+static avro_generic_value_iface_t *
+avro_generic_enum_class(avro_schema_t schema)
+{
+ avro_generic_enum_value_iface_t *iface =
+ (avro_generic_enum_value_iface_t *) avro_new(avro_generic_enum_value_iface_t);
+ if (iface == NULL) {
+ return NULL;
+ }
+
+ iface->parent = AVRO_GENERIC_ENUM_CLASS;
+ iface->refcount = 1;
+ iface->schema = avro_schema_incref(schema);
+ return &iface->parent;
+}
+
+
+/*-----------------------------------------------------------------------
+ * fixed
+ */
+
+typedef struct avro_generic_fixed_value_iface {
+ avro_generic_value_iface_t parent;
+ volatile int refcount;
+ avro_schema_t schema;
+ size_t data_size;
+} avro_generic_fixed_value_iface_t;
+
+
+static avro_value_iface_t *
+avro_generic_fixed_incref_iface(avro_value_iface_t *viface)
+{
+ avro_generic_fixed_value_iface_t *iface =
+ container_of(viface, avro_generic_fixed_value_iface_t, parent);
+ avro_refcount_inc(&iface->refcount);
+ return viface;
+}
+
+static void
+avro_generic_fixed_decref_iface(avro_value_iface_t *viface)
+{
+ avro_generic_fixed_value_iface_t *iface =
+ container_of(viface, avro_generic_fixed_value_iface_t, parent);
+ if (avro_refcount_dec(&iface->refcount)) {
+ avro_schema_decref(iface->schema);
+ avro_freet(avro_generic_fixed_value_iface_t, iface);
+ }
+}
+
+static int
+avro_generic_fixed_reset(const avro_value_iface_t *viface, void *vself)
+{
+ const avro_generic_fixed_value_iface_t *iface =
+ container_of(viface, avro_generic_fixed_value_iface_t, parent);
+ memset(vself, 0, iface->data_size);
+ return 0;
+}
+
+static avro_type_t
+avro_generic_fixed_get_type(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ AVRO_UNUSED(vself);
+ return AVRO_FIXED;
+}
+
+static avro_schema_t
+avro_generic_fixed_get_schema(const avro_value_iface_t *viface, const void *vself)
+{
+ const avro_generic_fixed_value_iface_t *iface =
+ container_of(viface, avro_generic_fixed_value_iface_t, parent);
+ AVRO_UNUSED(vself);
+ return iface->schema;
+}
+
+static int
+avro_generic_fixed_get(const avro_value_iface_t *viface,
+ const void *vself, const void **buf, size_t *size)
+{
+ const avro_generic_fixed_value_iface_t *iface =
+ container_of(viface, avro_generic_fixed_value_iface_t, parent);
+ if (buf != NULL) {
+ *buf = vself;
+ }
+ if (size != NULL) {
+ *size = iface->data_size;
+ }
+ return 0;
+}
+
+static int
+avro_generic_fixed_grab(const avro_value_iface_t *viface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ const avro_generic_fixed_value_iface_t *iface =
+ container_of(viface, avro_generic_fixed_value_iface_t, parent);
+ return avro_wrapped_buffer_new(dest, vself, iface->data_size);
+}
+
+static int
+avro_generic_fixed_set(const avro_value_iface_t *viface,
+ void *vself, void *buf, size_t size)
+{
+ check_param(EINVAL, buf != NULL, "fixed contents");
+ const avro_generic_fixed_value_iface_t *iface =
+ container_of(viface, avro_generic_fixed_value_iface_t, parent);
+ if (size != iface->data_size) {
+ avro_set_error("Invalid data size in set_fixed");
+ return EINVAL;
+ }
+ memcpy(vself, buf, size);
+ return 0;
+}
+
+static int
+avro_generic_fixed_give(const avro_value_iface_t *viface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ int rval = avro_generic_fixed_set
+ (viface, vself, (void *) buf->buf, buf->size);
+ avro_wrapped_buffer_free(buf);
+ return rval;
+}
+
+static size_t
+avro_generic_fixed_instance_size(const avro_value_iface_t *viface)
+{
+ const avro_generic_fixed_value_iface_t *iface =
+ container_of(viface, avro_generic_fixed_value_iface_t, parent);
+ return iface->data_size;
+}
+
+static int
+avro_generic_fixed_init(const avro_value_iface_t *viface, void *vself)
+{
+ const avro_generic_fixed_value_iface_t *iface =
+ container_of(viface, avro_generic_fixed_value_iface_t, parent);
+ memset(vself, 0, iface->data_size);
+ return 0;
+}
+
+static void
+avro_generic_fixed_done(const avro_value_iface_t *viface, void *vself)
+{
+ AVRO_UNUSED(viface);
+ AVRO_UNUSED(vself);
+}
+
+static avro_generic_value_iface_t AVRO_GENERIC_FIXED_CLASS =
+{
+ {
+ /* "class" methods */
+ avro_generic_fixed_incref_iface,
+ avro_generic_fixed_decref_iface,
+ /* general "instance" methods */
+ avro_generic_value_incref,
+ avro_generic_value_decref,
+ avro_generic_fixed_reset,
+ avro_generic_fixed_get_type,
+ avro_generic_fixed_get_schema,
+ /* primitive getters */
+ NULL, /* get_boolean */
+ NULL, /* get_bytes */
+ NULL, /* grab_bytes */
+ NULL, /* get_double */
+ NULL, /* get_float */
+ NULL, /* get_int */
+ NULL, /* get_long */
+ NULL, /* get_null */
+ NULL, /* get_string */
+ NULL, /* grab_string */
+ NULL, /* get_enum */
+ avro_generic_fixed_get,
+ avro_generic_fixed_grab,
+ /* primitive setters */
+ NULL, /* set_boolean */
+ NULL, /* set_bytes */
+ NULL, /* give_bytes */
+ NULL, /* set_double */
+ NULL, /* set_float */
+ NULL, /* set_int */
+ NULL, /* set_long */
+ NULL, /* set_null */
+ NULL, /* set_string */
+ NULL, /* set_string_length */
+ NULL, /* give_string_length */
+ NULL, /* set_enum */
+ avro_generic_fixed_set,
+ avro_generic_fixed_give,
+ /* compound getters */
+ NULL, /* get_size */
+ NULL, /* get_by_index */
+ NULL, /* get_by_name */
+ NULL, /* get_discriminant */
+ NULL, /* get_current_branch */
+ /* compound setters */
+ NULL, /* append */
+ NULL, /* add */
+ NULL /* set_branch */
+ },
+ avro_generic_fixed_instance_size,
+ avro_generic_fixed_init,
+ avro_generic_fixed_done
+};
+
+static avro_generic_value_iface_t *
+avro_generic_fixed_class(avro_schema_t schema)
+{
+ avro_generic_fixed_value_iface_t *iface =
+ (avro_generic_fixed_value_iface_t *) avro_new(avro_generic_fixed_value_iface_t);
+ if (iface == NULL) {
+ return NULL;
+ }
+
+ iface->parent = AVRO_GENERIC_FIXED_CLASS;
+ iface->refcount = 1;
+ iface->schema = avro_schema_incref(schema);
+ iface->data_size = avro_schema_fixed_size(schema);
+ return &iface->parent;
+}
+
+
+/*-----------------------------------------------------------------------
+ * map
+ */
+
+/*
+ * For generic maps, we need to store the value implementation for the
+ * map's elements.
+ */
+
+typedef struct avro_generic_map_value_iface {
+ avro_generic_value_iface_t parent;
+ volatile int refcount;
+ avro_schema_t schema;
+ avro_generic_value_iface_t *child_giface;
+} avro_generic_map_value_iface_t;
+
+typedef struct avro_generic_map {
+ avro_raw_map_t map;
+} avro_generic_map_t;
+
+
+static avro_value_iface_t *
+avro_generic_map_incref_iface(avro_value_iface_t *viface)
+{
+ avro_generic_map_value_iface_t *iface =
+ container_of(viface, avro_generic_map_value_iface_t, parent);
+ avro_refcount_inc(&iface->refcount);
+ return viface;
+}
+
+static void
+avro_generic_map_decref_iface(avro_value_iface_t *viface)
+{
+ avro_generic_map_value_iface_t *iface =
+ container_of(viface, avro_generic_map_value_iface_t, parent);
+ if (avro_refcount_dec(&iface->refcount)) {
+ avro_schema_decref(iface->schema);
+ avro_value_iface_decref(&iface->child_giface->parent);
+ avro_freet(avro_generic_map_value_iface_t, iface);
+ }
+}
+
+
+static void
+avro_generic_map_free_elements(const avro_generic_value_iface_t *child_giface,
+ avro_generic_map_t *self)
+{
+ size_t i;
+ for (i = 0; i < avro_raw_map_size(&self->map); i++) {
+ void *child_self = avro_raw_map_get_raw(&self->map, i);
+ avro_value_done(child_giface, child_self);
+ }
+}
+
+static int
+avro_generic_map_reset(const avro_value_iface_t *viface, void *vself)
+{
+ const avro_generic_map_value_iface_t *iface =
+ container_of(viface, avro_generic_map_value_iface_t, parent);
+ avro_generic_map_t *self = (avro_generic_map_t *) vself;
+ avro_generic_map_free_elements(iface->child_giface, self);
+ avro_raw_map_clear(&self->map);
+ return 0;
+}
+
+static avro_type_t
+avro_generic_map_get_type(const avro_value_iface_t *viface, const void *vself)
+{
+ AVRO_UNUSED(viface);
+ AVRO_UNUSED(vself);
+ return AVRO_MAP;
+}
+
+static avro_schema_t
+avro_generic_map_get_schema(const avro_value_iface_t *viface, const void *vself)
+{
+ const avro_generic_map_value_iface_t *iface =
+ container_of(viface, avro_generic_map_value_iface_t, parent);
+ AVRO_UNUSED(vself);
+ return iface->schema;
+}
+
+static int
+avro_generic_map_get_size(const avro_value_iface_t *viface,
+ const void *vself, size_t *size)
+{
+ AVRO_UNUSED(viface);
+ const avro_generic_map_t *self = (const avro_generic_map_t *) vself;
+ if (size != NULL) {
+ *size = avro_raw_map_size(&self->map);
+ }
+ return 0;
+}
+
+static int
+avro_generic_map_get_by_index(const avro_value_iface_t *viface,
+ const void *vself, size_t index,
+ avro_value_t *child, const char **name)
+{
+ const avro_generic_map_value_iface_t *iface =
+ container_of(viface, avro_generic_map_value_iface_t, parent);
+ const avro_generic_map_t *self = (const avro_generic_map_t *) vself;
+ if (index >= avro_raw_map_size(&self->map)) {
+ avro_set_error("Map index %" PRIsz " out of range", index);
+ return EINVAL;
+ }
+ child->iface = &iface->child_giface->parent;
+ child->self = avro_raw_map_get_raw(&self->map, index);
+ if (name != NULL) {
+ *name = avro_raw_map_get_key(&self->map, index);
+ }
+ return 0;
+}
+
+static int
+avro_generic_map_get_by_name(const avro_value_iface_t *viface,
+ const void *vself, const char *name,
+ avro_value_t *child, size_t *index)
+{
+ const avro_generic_map_value_iface_t *iface =
+ container_of(viface, avro_generic_map_value_iface_t, parent);
+ const avro_generic_map_t *self = (const avro_generic_map_t *) vself;
+ child->iface = &iface->child_giface->parent;
+ child->self = avro_raw_map_get(&self->map, name, index);
+ if (child->self == NULL) {
+ avro_set_error("No map element named %s", name);
+ return EINVAL;
+ }
+ return 0;
+}
+
+static int
+avro_generic_map_add(const avro_value_iface_t *viface,
+ void *vself, const char *key,
+ avro_value_t *child, size_t *index, int *is_new)
+{
+ const avro_generic_map_value_iface_t *iface =
+ container_of(viface, avro_generic_map_value_iface_t, parent);
+ int rval;
+ avro_generic_map_t *self = (avro_generic_map_t *) vself;
+ child->iface = &iface->child_giface->parent;
+ rval = avro_raw_map_get_or_create(&self->map, key,
+ &child->self, index);
+ if (rval < 0) {
+ return -rval;
+ }
+ if (is_new != NULL) {
+ *is_new = rval;
+ }
+ if (rval) {
+ check(rval, avro_value_init(iface->child_giface, child->self));
+ }
+ return 0;
+}
+
+static size_t
+avro_generic_map_instance_size(const avro_value_iface_t *viface)
+{
+ AVRO_UNUSED(viface);
+ return sizeof(avro_generic_map_t);
+}
+
+static int
+avro_generic_map_init(const avro_value_iface_t *viface, void *vself)
+{
+ const avro_generic_map_value_iface_t *iface =
+ container_of(viface, avro_generic_map_value_iface_t, parent);
+ avro_generic_map_t *self = (avro_generic_map_t *) vself;
+
+ size_t child_size = avro_value_instance_size(iface->child_giface);
+ avro_raw_map_init(&self->map, child_size);
+ return 0;
+}
+
+static void
+avro_generic_map_done(const avro_value_iface_t *viface, void *vself)
+{
+ const avro_generic_map_value_iface_t *iface =
+ container_of(viface, avro_generic_map_value_iface_t, parent);
+ avro_generic_map_t *self = (avro_generic_map_t *) vself;
+ avro_generic_map_free_elements(iface->child_giface, self);
+ avro_raw_map_done(&self->map);
+}
+
+static avro_generic_value_iface_t AVRO_GENERIC_MAP_CLASS =
+{
+ {
+ /* "class" methods */
+ avro_generic_map_incref_iface,
+ avro_generic_map_decref_iface,
+ /* general "instance" methods */
+ avro_generic_value_incref,
+ avro_generic_value_decref,
+ avro_generic_map_reset,
+ avro_generic_map_get_type,
+ avro_generic_map_get_schema,
+ /* primitive getters */
+ NULL, /* get_boolean */
+ NULL, /* get_bytes */
+ NULL, /* grab_bytes */
+ NULL, /* get_double */
+ NULL, /* get_float */
+ NULL, /* get_int */
+ NULL, /* get_long */
+ NULL, /* get_null */
+ NULL, /* get_string */
+ NULL, /* grab_string */
+ NULL, /* get_enum */
+ NULL, /* get_fixed */
+ NULL, /* grab_fixed */
+ /* primitive setters */
+ NULL, /* set_boolean */
+ NULL, /* set_bytes */
+ NULL, /* give_bytes */
+ NULL, /* set_double */
+ NULL, /* set_float */
+ NULL, /* set_int */
+ NULL, /* set_long */
+ NULL, /* set_null */
+ NULL, /* set_string */
+ NULL, /* set_string_length */
+ NULL, /* give_string_length */
+ NULL, /* set_enum */
+ NULL, /* set_fixed */
+ NULL, /* give_fixed */
+ /* compound getters */
+ avro_generic_map_get_size,
+ avro_generic_map_get_by_index,
+ avro_generic_map_get_by_name,
+ NULL, /* get_discriminant */
+ NULL, /* get_current_branch */
+ /* compound setters */
+ NULL, /* append */
+ avro_generic_map_add,
+ NULL /* set_branch */
+ },
+ avro_generic_map_instance_size,
+ avro_generic_map_init,
+ avro_generic_map_done
+};
+
+static avro_generic_value_iface_t *
+avro_generic_map_class(avro_schema_t schema, memoize_state_t *state)
+{
+ avro_schema_t child_schema = avro_schema_array_items(schema);
+ avro_generic_value_iface_t *child_giface =
+ avro_generic_class_from_schema_memoized(child_schema, state);
+ if (child_giface == NULL) {
+ return NULL;
+ }
+
+ ssize_t child_size = avro_value_instance_size(child_giface);
+ if (child_size < 0) {
+ avro_set_error("Map value class must provide instance_size");
+ avro_value_iface_decref(&child_giface->parent);
+ return NULL;
+ }
+
+ avro_generic_map_value_iface_t *iface =
+ (avro_generic_map_value_iface_t *) avro_new(avro_generic_map_value_iface_t);
+ if (iface == NULL) {
+ avro_value_iface_decref(&child_giface->parent);
+ return NULL;
+ }
+
+ /*
+ * TODO: Maybe check that schema.items matches
+ * child_iface.get_schema?
+ */
+
+ iface->parent = AVRO_GENERIC_MAP_CLASS;
+ iface->refcount = 1;
+ iface->schema = avro_schema_incref(schema);
+ iface->child_giface = child_giface;
+ return &iface->parent;
+}
+
+
+/*-----------------------------------------------------------------------
+ * record
+ */
+
+#ifndef DEBUG_FIELD_OFFSETS
+#define DEBUG_FIELD_OFFSETS 0
+#endif
+
+#if DEBUG_FIELD_OFFSETS
+#include <stdio.h>
+#endif
+
+/*
+ * For generic records, we need to store the value implementation for
+ * each field. We also need to store an offset for each field, since
+ * we're going to store the contents of each field directly in the
+ * record, rather than via pointers.
+ */
+
+typedef struct avro_generic_record_value_iface {
+ avro_generic_value_iface_t parent;
+ volatile int refcount;
+ avro_schema_t schema;
+
+ /** The total size of each value struct for this record. */
+ size_t instance_size;
+
+ /** The number of fields in this record. Yes, we could get this
+ * from schema, but this is easier. */
+ size_t field_count;
+
+ /** The offset of each field within the record struct. */
+ size_t *field_offsets;
+
+ /** The value implementation for each field. */
+ avro_generic_value_iface_t **field_ifaces;
+} avro_generic_record_value_iface_t;
+
+typedef struct avro_generic_record {
+ /* The rest of the struct is taken up by the inline storage
+ * needed for each field. */
+} avro_generic_record_t;
+
+
+/** Return a pointer to the given field within a record struct. */
+#define avro_generic_record_field(iface, rec, index) \
+ (((char *) (rec)) + (iface)->field_offsets[(index)])
+
+
+static avro_value_iface_t *
+avro_generic_record_incref_iface(avro_value_iface_t *viface)
+{
+ avro_generic_record_value_iface_t *iface =
+ container_of(viface, avro_generic_record_value_iface_t, parent);
+ avro_refcount_inc(&iface->refcount);
+ return viface;
+}
+
+static void
+avro_generic_record_decref_iface(avro_value_iface_t *viface)
+{
+ avro_generic_record_value_iface_t *iface =
+ container_of(viface, avro_generic_record_value_iface_t, parent);
+
+ if (avro_refcount_dec(&iface->refcount)) {
+ size_t i;
+ for (i = 0; i < iface->field_count; i++) {
+ avro_value_iface_decref(&iface->field_ifaces[i]->parent);
+ }
+
+ avro_schema_decref(iface->schema);
+ avro_free(iface->field_offsets,
+ sizeof(size_t) * iface->field_count);
+ avro_free(iface->field_ifaces,
+ sizeof(avro_generic_value_iface_t *) * iface->field_count);
+
+ avro_freet(avro_generic_record_value_iface_t, iface);
+ }
+}
+
+
+static int
+avro_generic_record_reset(const avro_value_iface_t *viface, void *vself)
+{
+ const avro_generic_record_value_iface_t *iface =
+ container_of(viface, avro_generic_record_value_iface_t, parent);
+ int rval;
+ avro_generic_record_t *self = (avro_generic_record_t *) vself;
+ size_t i;
+ for (i = 0; i < iface->field_count; i++) {
+ avro_value_t value = {
+ &iface->field_ifaces[i]->parent,
+ avro_generic_record_field(iface, self, i)
+ };
+ check(rval, avro_value_reset(&value));
+ }
+ return 0;
+}
+
+static avro_type_t
+avro_generic_record_get_type(const avro_value_iface_t *viface, const void *vself)
+{
+ AVRO_UNUSED(viface);
+ AVRO_UNUSED(vself);
+ return AVRO_RECORD;
+}
+
+static avro_schema_t
+avro_generic_record_get_schema(const avro_value_iface_t *viface, const void *vself)
+{
+ const avro_generic_record_value_iface_t *iface =
+ container_of(viface, avro_generic_record_value_iface_t, parent);
+ AVRO_UNUSED(vself);
+ return iface->schema;
+}
+
+static int
+avro_generic_record_get_size(const avro_value_iface_t *viface,
+ const void *vself, size_t *size)
+{
+ const avro_generic_record_value_iface_t *iface =
+ container_of(viface, avro_generic_record_value_iface_t, parent);
+ AVRO_UNUSED(vself);
+ if (size != NULL) {
+ *size = iface->field_count;
+ }
+ return 0;
+}
+
+static int
+avro_generic_record_get_by_index(const avro_value_iface_t *viface,
+ const void *vself, size_t index,
+ avro_value_t *child, const char **name)
+{
+ const avro_generic_record_value_iface_t *iface =
+ container_of(viface, avro_generic_record_value_iface_t, parent);
+ const avro_generic_record_t *self = (const avro_generic_record_t *) vself;
+ if (index >= iface->field_count) {
+ avro_set_error("Field index %" PRIsz " out of range", index);
+ return EINVAL;
+ }
+ child->iface = &iface->field_ifaces[index]->parent;
+ child->self = avro_generic_record_field(iface, self, index);
+
+ /*
+ * Grab the field name from the schema if asked for.
+ */
+ if (name != NULL) {
+ avro_schema_t schema = iface->schema;
+ *name = avro_schema_record_field_name(schema, index);
+ }
+
+ return 0;
+}
+
+static int
+avro_generic_record_get_by_name(const avro_value_iface_t *viface,
+ const void *vself, const char *name,
+ avro_value_t *child, size_t *index_out)
+{
+ const avro_generic_record_value_iface_t *iface =
+ container_of(viface, avro_generic_record_value_iface_t, parent);
+ const avro_generic_record_t *self = (const avro_generic_record_t *) vself;
+
+ avro_schema_t schema = iface->schema;
+ int index = avro_schema_record_field_get_index(schema, name);
+ if (index < 0) {
+ avro_set_error("Unknown record field %s", name);
+ return EINVAL;
+ }
+
+ child->iface = &iface->field_ifaces[index]->parent;
+ child->self = avro_generic_record_field(iface, self, index);
+ if (index_out != NULL) {
+ *index_out = index;
+ }
+ return 0;
+}
+
+static size_t
+avro_generic_record_instance_size(const avro_value_iface_t *viface)
+{
+ const avro_generic_record_value_iface_t *iface =
+ container_of(viface, avro_generic_record_value_iface_t, parent);
+ return iface->instance_size;
+}
+
+static int
+avro_generic_record_init(const avro_value_iface_t *viface, void *vself)
+{
+ int rval;
+ const avro_generic_record_value_iface_t *iface =
+ container_of(viface, avro_generic_record_value_iface_t, parent);
+ avro_generic_record_t *self = (avro_generic_record_t *) vself;
+
+ /* Initialize each field */
+ size_t i;
+ for (i = 0; i < iface->field_count; i++) {
+ check(rval, avro_value_init
+ (iface->field_ifaces[i],
+ avro_generic_record_field(iface, self, i)));
+ }
+
+ return 0;
+}
+
+static void
+avro_generic_record_done(const avro_value_iface_t *viface, void *vself)
+{
+ const avro_generic_record_value_iface_t *iface =
+ container_of(viface, avro_generic_record_value_iface_t, parent);
+ avro_generic_record_t *self = (avro_generic_record_t *) vself;
+ size_t i;
+ for (i = 0; i < iface->field_count; i++) {
+ avro_value_done(iface->field_ifaces[i],
+ avro_generic_record_field(iface, self, i));
+ }
+}
+
+static avro_generic_value_iface_t AVRO_GENERIC_RECORD_CLASS =
+{
+ {
+ /* "class" methods */
+ avro_generic_record_incref_iface,
+ avro_generic_record_decref_iface,
+ /* general "instance" methods */
+ avro_generic_value_incref,
+ avro_generic_value_decref,
+ avro_generic_record_reset,
+ avro_generic_record_get_type,
+ avro_generic_record_get_schema,
+ /* primitive getters */
+ NULL, /* get_boolean */
+ NULL, /* get_bytes */
+ NULL, /* grab_bytes */
+ NULL, /* get_double */
+ NULL, /* get_float */
+ NULL, /* get_int */
+ NULL, /* get_long */
+ NULL, /* get_null */
+ NULL, /* get_string */
+ NULL, /* grab_string */
+ NULL, /* get_enum */
+ NULL, /* get_fixed */
+ NULL, /* grab_fixed */
+ /* primitive setters */
+ NULL, /* set_boolean */
+ NULL, /* set_bytes */
+ NULL, /* give_bytes */
+ NULL, /* set_double */
+ NULL, /* set_float */
+ NULL, /* set_int */
+ NULL, /* set_long */
+ NULL, /* set_null */
+ NULL, /* set_string */
+ NULL, /* set_string_length */
+ NULL, /* give_string_length */
+ NULL, /* set_enum */
+ NULL, /* set_fixed */
+ NULL, /* give_fixed */
+ /* compound getters */
+ avro_generic_record_get_size,
+ avro_generic_record_get_by_index,
+ avro_generic_record_get_by_name,
+ NULL, /* get_discriminant */
+ NULL, /* get_current_branch */
+ /* compound setters */
+ NULL, /* append */
+ NULL, /* add */
+ NULL /* set_branch */
+ },
+ avro_generic_record_instance_size,
+ avro_generic_record_init,
+ avro_generic_record_done
+};
+
+static avro_generic_value_iface_t *
+avro_generic_record_class(avro_schema_t schema, memoize_state_t *state)
+{
+ avro_generic_record_value_iface_t *iface =
+ (avro_generic_record_value_iface_t *) avro_new(avro_generic_record_value_iface_t);
+ if (iface == NULL) {
+ return NULL;
+ }
+
+ memset(iface, 0, sizeof(avro_generic_record_value_iface_t));
+ iface->parent = AVRO_GENERIC_RECORD_CLASS;
+ iface->refcount = 1;
+ iface->schema = avro_schema_incref(schema);
+
+ iface->field_count = avro_schema_record_size(schema);
+ size_t field_offsets_size =
+ sizeof(size_t) * iface->field_count;
+ size_t field_ifaces_size =
+ sizeof(avro_generic_value_iface_t *) * iface->field_count;
+
+ if (iface->field_count == 0) {
+ iface->field_offsets = NULL;
+ iface->field_ifaces = NULL;
+ } else {
+ iface->field_offsets = (size_t *) avro_malloc(field_offsets_size);
+ if (iface->field_offsets == NULL) {
+ goto error;
+ }
+
+ iface->field_ifaces = (avro_generic_value_iface_t **) avro_malloc(field_ifaces_size);
+ if (iface->field_ifaces == NULL) {
+ goto error;
+ }
+ }
+
+ size_t next_offset = sizeof(avro_generic_record_t);
+#if DEBUG_FIELD_OFFSETS
+ fprintf(stderr, " Record %s\n Header: Offset 0, size %" PRIsz "\n",
+ avro_schema_type_name(schema),
+ sizeof(avro_generic_record_t));
+#endif
+ size_t i;
+ for (i = 0; i < iface->field_count; i++) {
+#if DEBUG_FIELD_OFFSETS
+ fprintf(stderr, " Field %" PRIsz ":\n", i);
+#endif
+ avro_schema_t field_schema =
+ avro_schema_record_field_get_by_index(schema, i);
+#if DEBUG_FIELD_OFFSETS
+ fprintf(stderr, " Schema %s\n",
+ avro_schema_type_name(field_schema));
+#endif
+
+ iface->field_offsets[i] = next_offset;
+
+ iface->field_ifaces[i] =
+ avro_generic_class_from_schema_memoized(field_schema, state);
+ if (iface->field_ifaces[i] == NULL) {
+ goto error;
+ }
+
+ ssize_t field_size =
+ avro_value_instance_size(iface->field_ifaces[i]);
+ if (field_size < 0) {
+ avro_set_error("Record field class must provide instance_size");
+ goto error;
+ }
+
+#if DEBUG_FIELD_OFFSETS
+ fprintf(stderr, " Offset %" PRIsz ", size %" PRIsz "\n",
+ next_offset, field_size);
+#endif
+ next_offset += field_size;
+ }
+
+ iface->instance_size = next_offset;
+#if DEBUG_FIELD_OFFSETS
+ fprintf(stderr, " TOTAL SIZE: %" PRIsz "\n", next_offset);
+#endif
+
+ return &iface->parent;
+
+error:
+ avro_schema_decref(iface->schema);
+ if (iface->field_offsets != NULL) {
+ avro_free(iface->field_offsets, field_offsets_size);
+ }
+ if (iface->field_ifaces != NULL) {
+ for (i = 0; i < iface->field_count; i++) {
+ if (iface->field_ifaces[i] != NULL) {
+ avro_value_iface_decref(&iface->field_ifaces[i]->parent);
+ }
+ }
+ avro_free(iface->field_ifaces, field_ifaces_size);
+ }
+ avro_freet(avro_generic_record_value_iface_t, iface);
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * union
+ */
+
+#ifndef DEBUG_BRANCHES_OFFSETS
+#define DEBUG_BRANCHES_OFFSETS 0
+#endif
+
+#if DEBUG_BRANCHES_OFFSETS
+#include <stdio.h>
+#endif
+
+/*
+ * For generic unions, we need to store the value implementation for
+ * each branch, just like for generic records. However, for unions, we
+ * can only have one branch active at a time, so we can reuse the space
+ * in the union struct, just like is done with C unions.
+ */
+
+typedef struct avro_generic_union_value_iface {
+ avro_generic_value_iface_t parent;
+ volatile int refcount;
+ avro_schema_t schema;
+
+ /** The total size of each value struct for this union. */
+ size_t instance_size;
+
+ /** The number of branches in this union. Yes, we could get
+ * this from schema, but this is easier. */
+ size_t branch_count;
+
+ /** The value implementation for each branch. */
+ avro_generic_value_iface_t **branch_ifaces;
+} avro_generic_union_value_iface_t;
+
+typedef struct avro_generic_union {
+ /** The currently active branch of the union. -1 if no branch
+ * is selected. */
+ int discriminant;
+
+ /* The rest of the struct is taken up by the inline storage
+ * needed for the active branch. */
+} avro_generic_union_t;
+
+
+/** Return the child interface for the active branch. */
+#define avro_generic_union_branch_giface(iface, _union) \
+ ((iface)->branch_ifaces[(_union)->discriminant])
+#define avro_generic_union_branch_iface(iface, _union) \
+ (&(avro_generic_union_branch_giface((iface), (_union)))->parent)
+
+/** Return a pointer to the active branch within a union struct. */
+#define avro_generic_union_branch(_union) \
+ (((char *) (_union)) + sizeof(avro_generic_union_t))
+
+
+static avro_value_iface_t *
+avro_generic_union_incref_iface(avro_value_iface_t *viface)
+{
+ avro_generic_union_value_iface_t *iface =
+ container_of(viface, avro_generic_union_value_iface_t, parent);
+ avro_refcount_inc(&iface->refcount);
+ return viface;
+}
+
+static void
+avro_generic_union_decref_iface(avro_value_iface_t *viface)
+{
+ avro_generic_union_value_iface_t *iface =
+ container_of(viface, avro_generic_union_value_iface_t, parent);
+
+ if (avro_refcount_dec(&iface->refcount)) {
+ size_t i;
+ for (i = 0; i < iface->branch_count; i++) {
+ avro_value_iface_decref(&iface->branch_ifaces[i]->parent);
+ }
+
+ avro_schema_decref(iface->schema);
+ avro_free(iface->branch_ifaces,
+ sizeof(avro_generic_value_iface_t *) * iface->branch_count);
+
+ avro_freet(avro_generic_union_value_iface_t, iface);
+ }
+}
+
+
+static int
+avro_generic_union_reset(const avro_value_iface_t *viface, void *vself)
+{
+ const avro_generic_union_value_iface_t *iface =
+ container_of(viface, avro_generic_union_value_iface_t, parent);
+ avro_generic_union_t *self = (avro_generic_union_t *) vself;
+ /* Keep the same branch selected, for the common case that we're
+ * about to reuse it. */
+ if (self->discriminant >= 0) {
+#if DEBUG_BRANCHES
+ fprintf(stderr, "Resetting branch %d\n",
+ self->discriminant);
+#endif
+ avro_value_t value = {
+ avro_generic_union_branch_iface(iface, self),
+ avro_generic_union_branch(self)
+ };
+ return avro_value_reset(&value);
+ }
+ return 0;
+}
+
+static avro_type_t
+avro_generic_union_get_type(const avro_value_iface_t *viface, const void *vself)
+{
+ AVRO_UNUSED(viface);
+ AVRO_UNUSED(vself);
+ return AVRO_UNION;
+}
+
+static avro_schema_t
+avro_generic_union_get_schema(const avro_value_iface_t *viface, const void *vself)
+{
+ const avro_generic_union_value_iface_t *iface =
+ container_of(viface, avro_generic_union_value_iface_t, parent);
+ AVRO_UNUSED(vself);
+ return iface->schema;
+}
+
+static int
+avro_generic_union_get_discriminant(const avro_value_iface_t *viface,
+ const void *vself, int *out)
+{
+ AVRO_UNUSED(viface);
+ const avro_generic_union_t *self = (const avro_generic_union_t *) vself;
+ *out = self->discriminant;
+ return 0;
+}
+
+static int
+avro_generic_union_get_current_branch(const avro_value_iface_t *viface,
+ const void *vself, avro_value_t *branch)
+{
+ const avro_generic_union_value_iface_t *iface =
+ container_of(viface, avro_generic_union_value_iface_t, parent);
+ const avro_generic_union_t *self = (const avro_generic_union_t *) vself;
+ if (self->discriminant < 0) {
+ avro_set_error("Union has no selected branch");
+ return EINVAL;
+ }
+ branch->iface = avro_generic_union_branch_iface(iface, self);
+ branch->self = avro_generic_union_branch(self);
+ return 0;
+}
+
+static int
+avro_generic_union_set_branch(const avro_value_iface_t *viface,
+ void *vself, int discriminant,
+ avro_value_t *branch)
+{
+ const avro_generic_union_value_iface_t *iface =
+ container_of(viface, avro_generic_union_value_iface_t, parent);
+ int rval;
+ avro_generic_union_t *self = (avro_generic_union_t *) vself;
+
+#if DEBUG_BRANCHES
+ fprintf(stderr, "Selecting branch %d (was %d)\n",
+ discriminant, self->discriminant);
+#endif
+
+ /*
+ * If the new desired branch is different than the currently
+ * active one, then finalize the old branch and initialize the
+ * new one.
+ */
+ if (self->discriminant != discriminant) {
+ if (self->discriminant >= 0) {
+#if DEBUG_BRANCHES
+ fprintf(stderr, "Finalizing branch %d\n",
+ self->discriminant);
+#endif
+ avro_value_done
+ (avro_generic_union_branch_giface(iface, self),
+ avro_generic_union_branch(self));
+ }
+ self->discriminant = discriminant;
+ if (discriminant >= 0) {
+#if DEBUG_BRANCHES
+ fprintf(stderr, "Initializing branch %d\n",
+ self->discriminant);
+#endif
+ check(rval, avro_value_init
+ (avro_generic_union_branch_giface(iface, self),
+ avro_generic_union_branch(self)));
+ }
+ }
+
+ if (branch != NULL) {
+ branch->iface = avro_generic_union_branch_iface(iface, self);
+ branch->self = avro_generic_union_branch(self);
+ }
+
+ return 0;
+}
+
+static size_t
+avro_generic_union_instance_size(const avro_value_iface_t *viface)
+{
+ const avro_generic_union_value_iface_t *iface =
+ container_of(viface, avro_generic_union_value_iface_t, parent);
+ return iface->instance_size;
+}
+
+static int
+avro_generic_union_init(const avro_value_iface_t *viface, void *vself)
+{
+ AVRO_UNUSED(viface);
+ avro_generic_union_t *self = (avro_generic_union_t *) vself;
+ self->discriminant = -1;
+ return 0;
+}
+
+static void
+avro_generic_union_done(const avro_value_iface_t *viface, void *vself)
+{
+ const avro_generic_union_value_iface_t *iface =
+ container_of(viface, avro_generic_union_value_iface_t, parent);
+ avro_generic_union_t *self = (avro_generic_union_t *) vself;
+ if (self->discriminant >= 0) {
+#if DEBUG_BRANCHES
+ fprintf(stderr, "Finalizing branch %d\n",
+ self->discriminant);
+#endif
+ avro_value_done
+ (avro_generic_union_branch_giface(iface, self),
+ avro_generic_union_branch(self));
+ self->discriminant = -1;
+ }
+}
+
+static avro_generic_value_iface_t AVRO_GENERIC_UNION_CLASS =
+{
+ {
+ /* "class" methods */
+ avro_generic_union_incref_iface,
+ avro_generic_union_decref_iface,
+ /* general "instance" methods */
+ avro_generic_value_incref,
+ avro_generic_value_decref,
+ avro_generic_union_reset,
+ avro_generic_union_get_type,
+ avro_generic_union_get_schema,
+ /* primitive getters */
+ NULL, /* get_boolean */
+ NULL, /* get_bytes */
+ NULL, /* grab_bytes */
+ NULL, /* get_double */
+ NULL, /* get_float */
+ NULL, /* get_int */
+ NULL, /* get_long */
+ NULL, /* get_null */
+ NULL, /* get_string */
+ NULL, /* grab_string */
+ NULL, /* get_enum */
+ NULL, /* get_fixed */
+ NULL, /* grab_fixed */
+ /* primitive setters */
+ NULL, /* set_boolean */
+ NULL, /* set_bytes */
+ NULL, /* give_bytes */
+ NULL, /* set_double */
+ NULL, /* set_float */
+ NULL, /* set_int */
+ NULL, /* set_long */
+ NULL, /* set_null */
+ NULL, /* set_string */
+ NULL, /* set_string_length */
+ NULL, /* give_string_length */
+ NULL, /* set_enum */
+ NULL, /* set_fixed */
+ NULL, /* give_fixed */
+ /* compound getters */
+ NULL, /* get_size */
+ NULL, /* get_by_index */
+ NULL, /* get_by_name */
+ avro_generic_union_get_discriminant,
+ avro_generic_union_get_current_branch,
+ /* compound setters */
+ NULL, /* append */
+ NULL, /* add */
+ avro_generic_union_set_branch
+ },
+ avro_generic_union_instance_size,
+ avro_generic_union_init,
+ avro_generic_union_done
+};
+
+static avro_generic_value_iface_t *
+avro_generic_union_class(avro_schema_t schema, memoize_state_t *state)
+{
+ avro_generic_union_value_iface_t *iface =
+ (avro_generic_union_value_iface_t *) avro_new(avro_generic_union_value_iface_t);
+ if (iface == NULL) {
+ return NULL;
+ }
+
+ memset(iface, 0, sizeof(avro_generic_union_value_iface_t));
+ iface->parent = AVRO_GENERIC_UNION_CLASS;
+ iface->refcount = 1;
+ iface->schema = avro_schema_incref(schema);
+
+ iface->branch_count = avro_schema_union_size(schema);
+ size_t branch_ifaces_size =
+ sizeof(avro_generic_value_iface_t *) * iface->branch_count;
+
+ iface->branch_ifaces = (avro_generic_value_iface_t **) avro_malloc(branch_ifaces_size);
+ if (iface->branch_ifaces == NULL) {
+ goto error;
+ }
+
+ size_t max_branch_size = 0;
+ size_t i;
+ for (i = 0; i < iface->branch_count; i++) {
+ avro_schema_t branch_schema =
+ avro_schema_union_branch(schema, i);
+
+ iface->branch_ifaces[i] =
+ avro_generic_class_from_schema_memoized(branch_schema, state);
+ if (iface->branch_ifaces[i] == NULL) {
+ goto error;
+ }
+
+ ssize_t branch_size =
+ avro_value_instance_size(iface->branch_ifaces[i]);
+ if (branch_size < 0) {
+ avro_set_error("Union branch class must provide instance_size");
+ goto error;
+ }
+
+#if DEBUG_BRANCHES
+ fprintf(stderr, "Branch %" PRIsz ", size %" PRIsz "\n",
+ i, branch_size);
+#endif
+
+ if ((size_t)branch_size > max_branch_size) {
+ max_branch_size = (size_t)branch_size;
+ }
+ }
+
+ iface->instance_size =
+ sizeof(avro_generic_union_t) + max_branch_size;
+#if DEBUG_BRANCHES
+ fprintf(stderr, "MAX BRANCH SIZE: %" PRIsz "\n", max_branch_size);
+#endif
+
+ return &iface->parent;
+
+error:
+ avro_schema_decref(iface->schema);
+ if (iface->branch_ifaces != NULL) {
+ for (i = 0; i < iface->branch_count; i++) {
+ if (iface->branch_ifaces[i] != NULL) {
+ avro_value_iface_decref(&iface->branch_ifaces[i]->parent);
+ }
+ }
+ avro_free(iface->branch_ifaces, branch_ifaces_size);
+ }
+ avro_freet(avro_generic_union_value_iface_t, iface);
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * Schema type dispatcher
+ */
+
+static avro_generic_value_iface_t *
+avro_generic_class_from_schema_memoized(avro_schema_t schema,
+ memoize_state_t *state)
+{
+ /*
+ * If we've already instantiated a value class for this schema,
+ * just return it.
+ */
+
+ avro_generic_value_iface_t *result = NULL;
+ if (avro_memoize_get(&state->mem, schema, NULL, (void **) &result)) {
+ avro_value_iface_incref(&result->parent);
+ return result;
+ }
+
+ /*
+ * Otherwise instantiate the value class based on the schema
+ * type.
+ */
+
+ switch (schema->type) {
+ case AVRO_BOOLEAN:
+ result = &AVRO_GENERIC_BOOLEAN_CLASS;
+ break;
+ case AVRO_BYTES:
+ result = &AVRO_GENERIC_BYTES_CLASS;
+ break;
+ case AVRO_DOUBLE:
+ result = &AVRO_GENERIC_DOUBLE_CLASS;
+ break;
+ case AVRO_FLOAT:
+ result = &AVRO_GENERIC_FLOAT_CLASS;
+ break;
+ case AVRO_INT32:
+ result = &AVRO_GENERIC_INT_CLASS;
+ break;
+ case AVRO_INT64:
+ result = &AVRO_GENERIC_LONG_CLASS;
+ break;
+ case AVRO_NULL:
+ result = &AVRO_GENERIC_NULL_CLASS;
+ break;
+ case AVRO_STRING:
+ result = &AVRO_GENERIC_STRING_CLASS;
+ break;
+
+ case AVRO_ARRAY:
+ result = avro_generic_array_class(schema, state);
+ break;
+ case AVRO_ENUM:
+ result = avro_generic_enum_class(schema);
+ break;
+ case AVRO_FIXED:
+ result = avro_generic_fixed_class(schema);
+ break;
+ case AVRO_MAP:
+ result = avro_generic_map_class(schema, state);
+ break;
+ case AVRO_RECORD:
+ result = avro_generic_record_class(schema, state);
+ break;
+ case AVRO_UNION:
+ result = avro_generic_union_class(schema, state);
+ break;
+
+ case AVRO_LINK:
+ {
+ avro_generic_link_value_iface_t *lresult =
+ avro_generic_link_class(schema);
+ lresult->next = state->links;
+ state->links = lresult;
+ result = &lresult->parent;
+ break;
+ }
+
+ default:
+ avro_set_error("Unknown schema type");
+ return NULL;
+ }
+
+ /*
+ * Add the new value implementation to the memoized state before
+ * we return.
+ */
+
+ avro_memoize_set(&state->mem, schema, NULL, result);
+ return result;
+}
+
+avro_value_iface_t *
+avro_generic_class_from_schema(avro_schema_t schema)
+{
+ /*
+ * Create a state to keep track of the value implementations
+ * that we create for each subschema.
+ */
+
+ memoize_state_t state;
+ avro_memoize_init(&state.mem);
+ state.links = NULL;
+
+ /*
+ * Create the value implementations.
+ */
+
+ avro_generic_value_iface_t *result =
+ avro_generic_class_from_schema_memoized(schema, &state);
+ if (result == NULL) {
+ avro_memoize_done(&state.mem);
+ return NULL;
+ }
+
+ /*
+ * Fix up any link schemas so that their value implementations
+ * point to their target schemas' implementations.
+ */
+
+ while (state.links != NULL) {
+ avro_generic_link_value_iface_t *link_iface = state.links;
+ avro_schema_t target_schema =
+ avro_schema_link_target(link_iface->schema);
+
+ avro_generic_value_iface_t *target_iface = NULL;
+ if (!avro_memoize_get(&state.mem, target_schema, NULL,
+ (void **) &target_iface)) {
+ avro_set_error("Never created a value implementation for %s",
+ avro_schema_type_name(target_schema));
+ return NULL;
+ }
+
+ /* We don't keep a reference to the target
+ * implementation, since that would give us a reference
+ * cycle. */
+ link_iface->target_giface = target_iface;
+ state.links = link_iface->next;
+ link_iface->next = NULL;
+ }
+
+ /*
+ * And now we can return.
+ */
+
+ avro_memoize_done(&state.mem);
+ return &result->parent;
+}
diff --git a/fluent-bit/lib/avro/src/io.c b/fluent-bit/lib/avro/src/io.c
new file mode 100644
index 000000000..c1e2f5dc9
--- /dev/null
+++ b/fluent-bit/lib/avro/src/io.c
@@ -0,0 +1,447 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include "avro/allocation.h"
+#include "avro/refcount.h"
+#include "avro/errors.h"
+#include "avro/io.h"
+#include "avro_private.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include "dump.h"
+
+enum avro_io_type_t {
+ AVRO_FILE_IO,
+ AVRO_MEMORY_IO
+};
+typedef enum avro_io_type_t avro_io_type_t;
+
+struct avro_reader_t_ {
+ avro_io_type_t type;
+ volatile int refcount;
+};
+
+struct avro_writer_t_ {
+ avro_io_type_t type;
+ volatile int refcount;
+};
+
+struct _avro_reader_file_t {
+ struct avro_reader_t_ reader;
+ FILE *fp;
+ int should_close;
+ char *cur;
+ char *end;
+ char buffer[4096];
+};
+
+struct _avro_writer_file_t {
+ struct avro_writer_t_ writer;
+ FILE *fp;
+ int should_close;
+};
+
+struct _avro_reader_memory_t {
+ struct avro_reader_t_ reader;
+ const char *buf;
+ int64_t len;
+ int64_t read;
+};
+
+struct _avro_writer_memory_t {
+ struct avro_writer_t_ writer;
+ const char *buf;
+ int64_t len;
+ int64_t written;
+};
+
+#define avro_io_typeof(obj) ((obj)->type)
+#define is_memory_io(obj) (obj && avro_io_typeof(obj) == AVRO_MEMORY_IO)
+#define is_file_io(obj) (obj && avro_io_typeof(obj) == AVRO_FILE_IO)
+
+#define avro_reader_to_memory(reader_) container_of(reader_, struct _avro_reader_memory_t, reader)
+#define avro_reader_to_file(reader_) container_of(reader_, struct _avro_reader_file_t, reader)
+#define avro_writer_to_memory(writer_) container_of(writer_, struct _avro_writer_memory_t, writer)
+#define avro_writer_to_file(writer_) container_of(writer_, struct _avro_writer_file_t, writer)
+
+static void reader_init(avro_reader_t reader, avro_io_type_t type)
+{
+ reader->type = type;
+ avro_refcount_set(&reader->refcount, 1);
+}
+
+static void writer_init(avro_writer_t writer, avro_io_type_t type)
+{
+ writer->type = type;
+ avro_refcount_set(&writer->refcount, 1);
+}
+
+avro_reader_t avro_reader_file_fp(FILE * fp, int should_close)
+{
+ struct _avro_reader_file_t *file_reader =
+ (struct _avro_reader_file_t *) avro_new(struct _avro_reader_file_t);
+ if (!file_reader) {
+ avro_set_error("Cannot allocate new file reader");
+ return NULL;
+ }
+ memset(file_reader, 0, sizeof(struct _avro_reader_file_t));
+ file_reader->fp = fp;
+ file_reader->should_close = should_close;
+ reader_init(&file_reader->reader, AVRO_FILE_IO);
+ return &file_reader->reader;
+}
+
+avro_reader_t avro_reader_file(FILE * fp)
+{
+ return avro_reader_file_fp(fp, 1);
+}
+
+avro_writer_t avro_writer_file_fp(FILE * fp, int should_close)
+{
+ struct _avro_writer_file_t *file_writer =
+ (struct _avro_writer_file_t *) avro_new(struct _avro_writer_file_t);
+ if (!file_writer) {
+ avro_set_error("Cannot allocate new file writer");
+ return NULL;
+ }
+ file_writer->fp = fp;
+ file_writer->should_close = should_close;
+ writer_init(&file_writer->writer, AVRO_FILE_IO);
+ return &file_writer->writer;
+}
+
+avro_writer_t avro_writer_file(FILE * fp)
+{
+ return avro_writer_file_fp(fp, 1);
+}
+
+avro_reader_t avro_reader_memory(const char *buf, int64_t len)
+{
+ struct _avro_reader_memory_t *mem_reader =
+ (struct _avro_reader_memory_t *) avro_new(struct _avro_reader_memory_t);
+ if (!mem_reader) {
+ avro_set_error("Cannot allocate new memory reader");
+ return NULL;
+ }
+ mem_reader->buf = buf;
+ mem_reader->len = len;
+ mem_reader->read = 0;
+ reader_init(&mem_reader->reader, AVRO_MEMORY_IO);
+ return &mem_reader->reader;
+}
+
+void
+avro_reader_memory_set_source(avro_reader_t reader, const char *buf, int64_t len)
+{
+ if (is_memory_io(reader)) {
+ struct _avro_reader_memory_t *mem_reader = avro_reader_to_memory(reader);
+ mem_reader->buf = buf;
+ mem_reader->len = len;
+ mem_reader->read = 0;
+ }
+}
+
+avro_writer_t avro_writer_memory(const char *buf, int64_t len)
+{
+ struct _avro_writer_memory_t *mem_writer =
+ (struct _avro_writer_memory_t *) avro_new(struct _avro_writer_memory_t);
+ if (!mem_writer) {
+ avro_set_error("Cannot allocate new memory writer");
+ return NULL;
+ }
+ mem_writer->buf = buf;
+ mem_writer->len = len;
+ mem_writer->written = 0;
+ writer_init(&mem_writer->writer, AVRO_MEMORY_IO);
+ return &mem_writer->writer;
+}
+
+void
+avro_writer_memory_set_dest(avro_writer_t writer, const char *buf, int64_t len)
+{
+ if (is_memory_io(writer)) {
+ struct _avro_writer_memory_t *mem_writer = avro_writer_to_memory(writer);
+ mem_writer->buf = buf;
+ mem_writer->len = len;
+ mem_writer->written = 0;
+ }
+}
+
+static int
+avro_read_memory(struct _avro_reader_memory_t *reader, void *buf, int64_t len)
+{
+ if (len > 0) {
+ if ((reader->len - reader->read) < len) {
+ avro_prefix_error("Cannot read %" PRIsz " bytes from memory buffer",
+ (size_t) len);
+ return ENOSPC;
+ }
+ memcpy(buf, reader->buf + reader->read, len);
+ reader->read += len;
+ }
+ return 0;
+}
+
+#define bytes_available(reader) (reader->end - reader->cur)
+#define buffer_reset(reader) {reader->cur = reader->end = reader->buffer;}
+
+static int
+avro_read_file(struct _avro_reader_file_t *reader, void *buf, int64_t len)
+{
+ int64_t needed = len;
+ char *p = (char *) buf;
+ int rval;
+
+ if (len == 0) {
+ return 0;
+ }
+
+ if (needed > (int64_t) sizeof(reader->buffer)) {
+ if (bytes_available(reader) > 0) {
+ memcpy(p, reader->cur, bytes_available(reader));
+ p += bytes_available(reader);
+ needed -= bytes_available(reader);
+ buffer_reset(reader);
+ }
+ rval = fread(p, 1, needed, reader->fp);
+ if (rval != needed) {
+ avro_set_error("Cannot read %" PRIsz " bytes from file",
+ (size_t) needed);
+ return EILSEQ;
+ }
+ return 0;
+ } else if (needed <= bytes_available(reader)) {
+ memcpy(p, reader->cur, needed);
+ reader->cur += needed;
+ return 0;
+ } else {
+ memcpy(p, reader->cur, bytes_available(reader));
+ p += bytes_available(reader);
+ needed -= bytes_available(reader);
+
+ rval =
+ fread(reader->buffer, 1, sizeof(reader->buffer),
+ reader->fp);
+ if (rval == 0) {
+ avro_set_error("Cannot read %" PRIsz " bytes from file",
+ (size_t) needed);
+ return EILSEQ;
+ }
+ reader->cur = reader->buffer;
+ reader->end = reader->cur + rval;
+
+ if (bytes_available(reader) < needed) {
+ avro_set_error("Cannot read %" PRIsz " bytes from file",
+ (size_t) needed);
+ return EILSEQ;
+ }
+ memcpy(p, reader->cur, needed);
+ reader->cur += needed;
+ return 0;
+ }
+ avro_set_error("Cannot read %" PRIsz " bytes from file",
+ (size_t) needed);
+ return EILSEQ;
+}
+
+int avro_read(avro_reader_t reader, void *buf, int64_t len)
+{
+ if (buf && len >= 0) {
+ if (is_memory_io(reader)) {
+ return avro_read_memory(avro_reader_to_memory(reader),
+ buf, len);
+ } else if (is_file_io(reader)) {
+ return avro_read_file(avro_reader_to_file(reader), buf,
+ len);
+ }
+ }
+ return EINVAL;
+}
+
+static int avro_skip_memory(struct _avro_reader_memory_t *reader, int64_t len)
+{
+ if (len > 0) {
+ if ((reader->len - reader->read) < len) {
+ avro_set_error("Cannot skip %" PRIsz " bytes in memory buffer",
+ (size_t) len);
+ return ENOSPC;
+ }
+ reader->read += len;
+ }
+ return 0;
+}
+
+static int avro_skip_file(struct _avro_reader_file_t *reader, int64_t len)
+{
+ int rval;
+ int64_t needed = len;
+
+ if (len == 0) {
+ return 0;
+ }
+ if (needed <= bytes_available(reader)) {
+ reader->cur += needed;
+ } else {
+ needed -= bytes_available(reader);
+ buffer_reset(reader);
+ rval = fseek(reader->fp, needed, SEEK_CUR);
+ if (rval < 0) {
+ avro_set_error("Cannot skip %" PRIsz " bytes in file",
+ (size_t) len);
+ return rval;
+ }
+ }
+ return 0;
+}
+
+int avro_skip(avro_reader_t reader, int64_t len)
+{
+ if (len >= 0) {
+ if (is_memory_io(reader)) {
+ return avro_skip_memory(avro_reader_to_memory(reader),
+ len);
+ } else if (is_file_io(reader)) {
+ return avro_skip_file(avro_reader_to_file(reader), len);
+ }
+ }
+ return 0;
+}
+
+static int
+avro_write_memory(struct _avro_writer_memory_t *writer, void *buf, int64_t len)
+{
+ if (len) {
+ if ((writer->len - writer->written) < len) {
+ avro_set_error("Cannot write %" PRIsz " bytes in memory buffer",
+ (size_t) len);
+ return ENOSPC;
+ }
+ memcpy((void *)(writer->buf + writer->written), buf, len);
+ writer->written += len;
+ }
+ return 0;
+}
+
+static int
+avro_write_file(struct _avro_writer_file_t *writer, void *buf, int64_t len)
+{
+ int rval;
+ if (len > 0) {
+ rval = fwrite(buf, len, 1, writer->fp);
+ if (rval == 0) {
+ return EIO;
+ }
+ }
+ return 0;
+}
+
+int avro_write(avro_writer_t writer, void *buf, int64_t len)
+{
+ if (buf && len >= 0) {
+ if (is_memory_io(writer)) {
+ return avro_write_memory(avro_writer_to_memory(writer),
+ buf, len);
+ } else if (is_file_io(writer)) {
+ return avro_write_file(avro_writer_to_file(writer), buf,
+ len);
+ }
+ }
+ return EINVAL;
+}
+
+void
+avro_reader_reset(avro_reader_t reader)
+{
+ if (is_memory_io(reader)) {
+ avro_reader_to_memory(reader)->read = 0;
+ }
+}
+
+void avro_writer_reset(avro_writer_t writer)
+{
+ if (is_memory_io(writer)) {
+ avro_writer_to_memory(writer)->written = 0;
+ }
+}
+
+int64_t avro_writer_tell(avro_writer_t writer)
+{
+ if (is_memory_io(writer)) {
+ return avro_writer_to_memory(writer)->written;
+ }
+ return EINVAL;
+}
+
+void avro_writer_flush(avro_writer_t writer)
+{
+ if (is_file_io(writer)) {
+ fflush(avro_writer_to_file(writer)->fp);
+ }
+}
+
+void avro_writer_dump(avro_writer_t writer, FILE * fp)
+{
+ if (is_memory_io(writer)) {
+ dump(fp, (char *)avro_writer_to_memory(writer)->buf,
+ avro_writer_to_memory(writer)->written);
+ }
+}
+
+void avro_reader_dump(avro_reader_t reader, FILE * fp)
+{
+ if (is_memory_io(reader)) {
+ dump(fp, (char *)avro_reader_to_memory(reader)->buf,
+ avro_reader_to_memory(reader)->read);
+ }
+}
+
+void avro_reader_free(avro_reader_t reader)
+{
+ if (is_memory_io(reader)) {
+ avro_freet(struct _avro_reader_memory_t, reader);
+ } else if (is_file_io(reader)) {
+ if (avro_reader_to_file(reader)->should_close) {
+ fclose(avro_reader_to_file(reader)->fp);
+ }
+ avro_freet(struct _avro_reader_file_t, reader);
+ }
+}
+
+void avro_writer_free(avro_writer_t writer)
+{
+ if (is_memory_io(writer)) {
+ avro_freet(struct _avro_writer_memory_t, writer);
+ } else if (is_file_io(writer)) {
+ if (avro_writer_to_file(writer)->should_close) {
+ fclose(avro_writer_to_file(writer)->fp);
+ }
+ avro_freet(struct _avro_writer_file_t, writer);
+ }
+}
+
+int avro_reader_is_eof(avro_reader_t reader)
+{
+ if (is_file_io(reader)) {
+ struct _avro_reader_file_t *file = avro_reader_to_file(reader);
+ if (feof(file->fp)) {
+ return file->cur == file->end;
+ }
+ }
+ return 0;
+}
diff --git a/fluent-bit/lib/avro/src/map.c b/fluent-bit/lib/avro/src/map.c
new file mode 100644
index 000000000..c85ffbd84
--- /dev/null
+++ b/fluent-bit/lib/avro/src/map.c
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "avro/data.h"
+#include "avro/allocation.h"
+#include "avro/errors.h"
+#include "st.h"
+
+
+#define raw_entry_size(element_size) \
+ (sizeof(avro_raw_map_entry_t) + element_size)
+
+void avro_raw_map_init(avro_raw_map_t *map, size_t element_size)
+{
+ memset(map, 0, sizeof(avro_raw_map_t));
+ avro_raw_array_init(&map->elements, raw_entry_size(element_size));
+ map->indices_by_key = st_init_strtable();
+}
+
+
+static void
+avro_raw_map_free_keys(avro_raw_map_t *map)
+{
+ unsigned int i;
+ for (i = 0; i < avro_raw_map_size(map); i++) {
+ void *ventry =
+ ((char *) map->elements.data + map->elements.element_size * i);
+ avro_raw_map_entry_t *entry = (avro_raw_map_entry_t *) ventry;
+ avro_str_free((char *) entry->key);
+ }
+}
+
+
+void avro_raw_map_done(avro_raw_map_t *map)
+{
+ avro_raw_map_free_keys(map);
+ avro_raw_array_done(&map->elements);
+ st_free_table((st_table *) map->indices_by_key);
+ memset(map, 0, sizeof(avro_raw_map_t));
+}
+
+
+void avro_raw_map_clear(avro_raw_map_t *map)
+{
+ avro_raw_map_free_keys(map);
+ avro_raw_array_clear(&map->elements);
+ st_free_table((st_table *) map->indices_by_key);
+ map->indices_by_key = st_init_strtable();
+}
+
+
+int
+avro_raw_map_ensure_size(avro_raw_map_t *map, size_t desired_count)
+{
+ return avro_raw_array_ensure_size(&map->elements, desired_count);
+}
+
+
+void *avro_raw_map_get(const avro_raw_map_t *map, const char *key,
+ size_t *index)
+{
+ st_data_t data;
+ if (st_lookup((st_table *) map->indices_by_key, (st_data_t) key, &data)) {
+ unsigned int i = (unsigned int) data;
+ if (index) {
+ *index = i;
+ }
+ void *raw_entry =
+ ((char *) map->elements.data + map->elements.element_size * i);
+ return (char *) raw_entry + sizeof(avro_raw_map_entry_t);
+ } else {
+ return NULL;
+ }
+}
+
+
+int avro_raw_map_get_or_create(avro_raw_map_t *map, const char *key,
+ void **element, size_t *index)
+{
+ st_data_t data;
+ void *el;
+ unsigned int i;
+ int is_new;
+
+ if (st_lookup((st_table *) map->indices_by_key, (st_data_t) key, &data)) {
+ i = (unsigned int) data;
+ void *raw_entry =
+ ((char *) map->elements.data + map->elements.element_size * i);
+ el = (char *) raw_entry + sizeof(avro_raw_map_entry_t);
+ is_new = 0;
+ } else {
+ i = map->elements.element_count;
+ avro_raw_map_entry_t *raw_entry =
+ (avro_raw_map_entry_t *) avro_raw_array_append(&map->elements);
+ raw_entry->key = avro_strdup(key);
+ st_insert((st_table *) map->indices_by_key,
+ (st_data_t) raw_entry->key, (st_data_t) i);
+ if (!raw_entry) {
+ avro_str_free((char*)raw_entry->key);
+ return -ENOMEM;
+ }
+ el = ((char *) raw_entry) + sizeof(avro_raw_map_entry_t);
+ is_new = 1;
+ }
+
+ if (element) {
+ *element = el;
+ }
+ if (index) {
+ *index = i;
+ }
+ return is_new;
+}
diff --git a/fluent-bit/lib/avro/src/memoize.c b/fluent-bit/lib/avro/src/memoize.c
new file mode 100644
index 000000000..933fecbd0
--- /dev/null
+++ b/fluent-bit/lib/avro/src/memoize.c
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include "avro/data.h"
+#include "avro/allocation.h"
+#include "avro/errors.h"
+#include "avro_private.h"
+#include "st.h"
+
+
+typedef struct avro_memoize_key {
+ void *key1;
+ void *key2;
+} avro_memoize_key_t;
+
+
+static int
+avro_memoize_key_cmp(avro_memoize_key_t *a, avro_memoize_key_t *b)
+{
+ /*
+ * This isn't a proper cmp operation, since it always returns 1
+ * if the keys are different. But that's okay for the hash
+ * table implementation we're using.
+ */
+
+ return (a->key1 != b->key1) || (a->key2 != b->key2);
+}
+
+
+static int
+avro_memoize_key_hash(avro_memoize_key_t *a)
+{
+ return ((uintptr_t) a->key1) ^ ((uintptr_t) a->key2);
+}
+
+
+static struct st_hash_type avro_memoize_hash_type = {
+ HASH_FUNCTION_CAST avro_memoize_key_cmp,
+ HASH_FUNCTION_CAST avro_memoize_key_hash
+};
+
+
+void
+avro_memoize_init(avro_memoize_t *mem)
+{
+ memset(mem, 0, sizeof(avro_memoize_t));
+ mem->cache = st_init_table(&avro_memoize_hash_type);
+}
+
+
+static int
+avro_memoize_free_key(avro_memoize_key_t *key, void *result, void *dummy)
+{
+ AVRO_UNUSED(result);
+ AVRO_UNUSED(dummy);
+ avro_freet(avro_memoize_key_t, key);
+ return ST_CONTINUE;
+}
+
+
+void
+avro_memoize_done(avro_memoize_t *mem)
+{
+ st_foreach((st_table *) mem->cache, HASH_FUNCTION_CAST avro_memoize_free_key, 0);
+ st_free_table((st_table *) mem->cache);
+ memset(mem, 0, sizeof(avro_memoize_t));
+}
+
+
+int
+avro_memoize_get(avro_memoize_t *mem,
+ void *key1, void *key2,
+ void **result)
+{
+ avro_memoize_key_t key;
+ key.key1 = key1;
+ key.key2 = key2;
+
+ union {
+ st_data_t data;
+ void *value;
+ } val;
+
+ if (st_lookup((st_table *) mem->cache, (st_data_t) &key, &val.data)) {
+ if (result) {
+ *result = val.value;
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+void
+avro_memoize_set(avro_memoize_t *mem,
+ void *key1, void *key2,
+ void *result)
+{
+ /*
+ * First see if there's already a cached value for this key. If
+ * so, we don't want to allocate a new avro_memoize_key_t
+ * instance.
+ */
+
+ avro_memoize_key_t key;
+ key.key1 = key1;
+ key.key2 = key2;
+
+ union {
+ st_data_t data;
+ void *value;
+ } val;
+
+ if (st_lookup((st_table *) mem->cache, (st_data_t) &key, &val.data)) {
+ st_insert((st_table *) mem->cache, (st_data_t) &key, (st_data_t) result);
+ return;
+ }
+
+ /*
+ * If it's a new key pair, then we do need to allocate.
+ */
+
+ avro_memoize_key_t *real_key = (avro_memoize_key_t *) avro_new(avro_memoize_key_t);
+ real_key->key1 = key1;
+ real_key->key2 = key2;
+
+ st_insert((st_table *) mem->cache, (st_data_t) real_key, (st_data_t) result);
+}
+
+
+void
+avro_memoize_delete(avro_memoize_t *mem, void *key1, void *key2)
+{
+ avro_memoize_key_t key;
+ key.key1 = key1;
+ key.key2 = key2;
+
+ union {
+ st_data_t data;
+ avro_memoize_key_t *key;
+ } real_key;
+
+ real_key.key = &key;
+ if (st_delete((st_table *) mem->cache, &real_key.data, NULL)) {
+ avro_freet(avro_memoize_key_t, real_key.key);
+ }
+}
diff --git a/fluent-bit/lib/avro/src/resolved-reader.c b/fluent-bit/lib/avro/src/resolved-reader.c
new file mode 100644
index 000000000..30d7b8c97
--- /dev/null
+++ b/fluent-bit/lib/avro/src/resolved-reader.c
@@ -0,0 +1,3377 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <avro/platform.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro_private.h"
+#include "avro/allocation.h"
+#include "avro/basics.h"
+#include "avro/data.h"
+#include "avro/errors.h"
+#include "avro/refcount.h"
+#include "avro/resolver.h"
+#include "avro/schema.h"
+#include "avro/value.h"
+#include "st.h"
+
+#ifndef AVRO_RESOLVER_DEBUG
+#define AVRO_RESOLVER_DEBUG 0
+#endif
+
+#if AVRO_RESOLVER_DEBUG
+#include <stdio.h>
+#define DEBUG(...) \
+ do { \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ } while (0)
+#else
+#define DEBUG(...) /* don't print messages */
+#endif
+
+
+typedef struct avro_resolved_reader avro_resolved_reader_t;
+
+struct avro_resolved_reader {
+ avro_value_iface_t parent;
+
+ /** The reference count for this interface. */
+ volatile int refcount;
+
+ /** The writer schema. */
+ avro_schema_t wschema;
+
+ /** The reader schema. */
+ avro_schema_t rschema;
+
+ /* The size of the value instances for this resolver. */
+ size_t instance_size;
+
+ /* A function to calculate the instance size once the overall
+ * top-level resolver (and all of its children) have been
+ * constructed. */
+ void
+ (*calculate_size)(avro_resolved_reader_t *iface);
+
+ /* A free function for this resolver */
+ void
+ (*free_iface)(avro_resolved_reader_t *iface, st_table *freeing);
+
+ /* An initialization function for instances of this resolver. */
+ int
+ (*init)(const avro_resolved_reader_t *iface, void *self);
+
+ /* A finalization function for instances of this resolver. */
+ void
+ (*done)(const avro_resolved_reader_t *iface, void *self);
+
+ /* Clear out any existing wrappers, if any */
+ int
+ (*reset_wrappers)(const avro_resolved_reader_t *iface, void *self);
+};
+
+#define avro_resolved_reader_calculate_size(iface) \
+ do { \
+ if ((iface)->calculate_size != NULL) { \
+ (iface)->calculate_size((iface)); \
+ } \
+ } while (0)
+#define avro_resolved_reader_init(iface, self) \
+ ((iface)->init == NULL? 0: (iface)->init((iface), (self)))
+#define avro_resolved_reader_done(iface, self) \
+ ((iface)->done == NULL? (void) 0: (iface)->done((iface), (self)))
+#define avro_resolved_reader_reset_wrappers(iface, self) \
+ ((iface)->reset_wrappers == NULL? 0: \
+ (iface)->reset_wrappers((iface), (self)))
+
+
+/*
+ * We assume that each instance type in this value contains an an
+ * avro_value_t as its first element, which is the current wrapped
+ * value.
+ */
+
+void
+avro_resolved_reader_set_source(avro_value_t *resolved,
+ avro_value_t *dest)
+{
+ avro_value_t *self = (avro_value_t *) resolved->self;
+ if (self->self != NULL) {
+ avro_value_decref(self);
+ }
+ avro_value_copy_ref(self, dest);
+}
+
+void
+avro_resolved_reader_clear_source(avro_value_t *resolved)
+{
+ avro_value_t *self = (avro_value_t *) resolved->self;
+ if (self->self != NULL) {
+ avro_value_decref(self);
+ }
+ self->iface = NULL;
+ self->self = NULL;
+}
+
+int
+avro_resolved_reader_new_value(avro_value_iface_t *viface,
+ avro_value_t *value)
+{
+ int rval;
+ avro_resolved_reader_t *iface =
+ container_of(viface, avro_resolved_reader_t, parent);
+ void *self = avro_malloc(iface->instance_size + sizeof(volatile int));
+ if (self == NULL) {
+ value->iface = NULL;
+ value->self = NULL;
+ return ENOMEM;
+ }
+
+ memset(self, 0, iface->instance_size + sizeof(volatile int));
+ volatile int *refcount = (volatile int *) self;
+ self = (char *) self + sizeof(volatile int);
+
+ rval = avro_resolved_reader_init(iface, self);
+ if (rval != 0) {
+ avro_free(self, iface->instance_size + sizeof(volatile int));
+ value->iface = NULL;
+ value->self = NULL;
+ return rval;
+ }
+
+ *refcount = 1;
+ value->iface = avro_value_iface_incref(viface);
+ value->self = self;
+ return 0;
+}
+
+static void
+avro_resolved_reader_free_value(const avro_value_iface_t *viface, void *vself)
+{
+ avro_resolved_reader_t *iface =
+ container_of(viface, avro_resolved_reader_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+
+ avro_resolved_reader_done(iface, vself);
+ if (self->self != NULL) {
+ avro_value_decref(self);
+ }
+
+ vself = (char *) vself - sizeof(volatile int);
+ avro_free(vself, iface->instance_size + sizeof(volatile int));
+}
+
+static void
+avro_resolved_reader_incref(avro_value_t *value)
+{
+ /*
+ * This only works if you pass in the top-level value.
+ */
+
+ volatile int *refcount = (volatile int *) ((char *) value->self - sizeof(volatile int));
+ avro_refcount_inc(refcount);
+}
+
+static void
+avro_resolved_reader_decref(avro_value_t *value)
+{
+ /*
+ * This only works if you pass in the top-level value.
+ */
+
+ volatile int *refcount = (volatile int *) ((char *) value->self - sizeof(volatile int));
+ if (avro_refcount_dec(refcount)) {
+ avro_resolved_reader_free_value(value->iface, value->self);
+ }
+}
+
+
+static avro_value_iface_t *
+avro_resolved_reader_incref_iface(avro_value_iface_t *viface)
+{
+ avro_resolved_reader_t *iface =
+ container_of(viface, avro_resolved_reader_t, parent);
+ avro_refcount_inc(&iface->refcount);
+ return viface;
+}
+
+static void
+free_resolver(avro_resolved_reader_t *iface, st_table *freeing)
+{
+ /* First check if we've already started freeing this resolver. */
+ if (st_lookup(freeing, (st_data_t) iface, NULL)) {
+ DEBUG("Already freed %p", iface);
+ return;
+ }
+
+ /* Otherwise add this resolver to the freeing set, then free it. */
+ st_insert(freeing, (st_data_t) iface, (st_data_t) NULL);
+ DEBUG("Freeing resolver %p (%s->%s)", iface,
+ avro_schema_type_name(iface->wschema),
+ avro_schema_type_name(iface->rschema));
+
+ iface->free_iface(iface, freeing);
+}
+
+static void
+avro_resolved_reader_calculate_size_(avro_resolved_reader_t *iface)
+{
+ /* Only calculate the size for any resolver once */
+ iface->calculate_size = NULL;
+
+ DEBUG("Calculating size for %s->%s",
+ avro_schema_type_name((iface)->wschema),
+ avro_schema_type_name((iface)->rschema));
+ iface->instance_size = sizeof(avro_value_t);
+}
+
+static void
+avro_resolved_reader_free_iface(avro_resolved_reader_t *iface, st_table *freeing)
+{
+ AVRO_UNUSED(freeing);
+ avro_schema_decref(iface->wschema);
+ avro_schema_decref(iface->rschema);
+ avro_freet(avro_resolved_reader_t, iface);
+}
+
+static void
+avro_resolved_reader_decref_iface(avro_value_iface_t *viface)
+{
+ avro_resolved_reader_t *iface =
+ container_of(viface, avro_resolved_reader_t, parent);
+ DEBUG("Decref resolver %p (before=%d)", iface, iface->refcount);
+ if (avro_refcount_dec(&iface->refcount)) {
+ st_table *freeing = st_init_numtable();
+ free_resolver(iface, freeing);
+ st_free_table(freeing);
+ }
+}
+
+static int
+avro_resolved_reader_reset(const avro_value_iface_t *viface, void *vself)
+{
+ /*
+ * To reset a wrapped value, we first clear out any wrappers,
+ * and then have the wrapped value reset itself.
+ */
+
+ int rval;
+ avro_resolved_reader_t *iface =
+ container_of(viface, avro_resolved_reader_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ check(rval, avro_resolved_reader_reset_wrappers(iface, vself));
+ return avro_value_reset(self);
+}
+
+static avro_type_t
+avro_resolved_reader_get_type(const avro_value_iface_t *viface, const void *vself)
+{
+ AVRO_UNUSED(vself);
+ const avro_resolved_reader_t *iface =
+ container_of(viface, avro_resolved_reader_t, parent);
+ return avro_typeof(iface->rschema);
+}
+
+static avro_schema_t
+avro_resolved_reader_get_schema(const avro_value_iface_t *viface, const void *vself)
+{
+ AVRO_UNUSED(vself);
+ avro_resolved_reader_t *iface =
+ container_of(viface, avro_resolved_reader_t, parent);
+ return iface->rschema;
+}
+
+
+static avro_resolved_reader_t *
+avro_resolved_reader_create(avro_schema_t wschema, avro_schema_t rschema)
+{
+ avro_resolved_reader_t *self = (avro_resolved_reader_t *) avro_new(avro_resolved_reader_t);
+ memset(self, 0, sizeof(avro_resolved_reader_t));
+
+ self->parent.incref_iface = avro_resolved_reader_incref_iface;
+ self->parent.decref_iface = avro_resolved_reader_decref_iface;
+ self->parent.incref = avro_resolved_reader_incref;
+ self->parent.decref = avro_resolved_reader_decref;
+ self->parent.reset = avro_resolved_reader_reset;
+ self->parent.get_type = avro_resolved_reader_get_type;
+ self->parent.get_schema = avro_resolved_reader_get_schema;
+
+ self->refcount = 1;
+ self->wschema = avro_schema_incref(wschema);
+ self->rschema = avro_schema_incref(rschema);
+ self->calculate_size = avro_resolved_reader_calculate_size_;
+ self->free_iface = avro_resolved_reader_free_iface;
+ self->reset_wrappers = NULL;
+ return self;
+}
+
+
+/*-----------------------------------------------------------------------
+ * Memoized resolvers
+ */
+
+typedef struct avro_resolved_link_reader avro_resolved_link_reader_t;
+
+typedef struct memoize_state_t {
+ avro_memoize_t mem;
+ avro_resolved_link_reader_t *links;
+} memoize_state_t;
+
+static avro_resolved_reader_t *
+avro_resolved_reader_new_memoized(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema);
+
+
+/*-----------------------------------------------------------------------
+ * Recursive schemas
+ */
+
+/*
+ * Recursive schemas are handled specially; the value implementation for
+ * an AVRO_LINK schema is simply a wrapper around the value
+ * implementation for the link's target schema. The value methods all
+ * delegate to the wrapped implementation.
+ *
+ * Complicating the links here is that we might be linking to the writer
+ * schema or the reader schema. This only matters for a couple of
+ * methods, so instead of keeping a boolean flag in the value interface,
+ * we just have separate method implementations that we slot in
+ * appropriately.
+ */
+
+struct avro_resolved_link_reader {
+ avro_resolved_reader_t parent;
+
+ /**
+ * A pointer to the “next” link resolver that we've had to
+ * create. We use this as we're creating the overall top-level
+ * resolver to keep track of which ones we have to fix up
+ * afterwards.
+ */
+ avro_resolved_link_reader_t *next;
+
+ /** The target's implementation. */
+ avro_resolved_reader_t *target_resolver;
+};
+
+typedef struct avro_resolved_link_value {
+ avro_value_t wrapped;
+ avro_value_t target;
+} avro_resolved_link_value_t;
+
+static void
+avro_resolved_wlink_reader_calculate_size(avro_resolved_reader_t *iface)
+{
+ /* Only calculate the size for any resolver once */
+ iface->calculate_size = NULL;
+
+ DEBUG("Calculating size for [%s]->%s",
+ avro_schema_type_name((iface)->wschema),
+ avro_schema_type_name((iface)->rschema));
+ iface->instance_size = sizeof(avro_resolved_link_value_t);
+}
+
+static void
+avro_resolved_rlink_reader_calculate_size(avro_resolved_reader_t *iface)
+{
+ /* Only calculate the size for any resolver once */
+ iface->calculate_size = NULL;
+
+ DEBUG("Calculating size for %s->[%s]",
+ avro_schema_type_name((iface)->wschema),
+ avro_schema_type_name((iface)->rschema));
+ iface->instance_size = sizeof(avro_resolved_link_value_t);
+}
+
+static void
+avro_resolved_link_reader_free_iface(avro_resolved_reader_t *iface, st_table *freeing)
+{
+ avro_resolved_link_reader_t *liface =
+ container_of(iface, avro_resolved_link_reader_t, parent);
+ if (liface->target_resolver != NULL) {
+ free_resolver(liface->target_resolver, freeing);
+ }
+ avro_schema_decref(iface->wschema);
+ avro_schema_decref(iface->rschema);
+ avro_freet(avro_resolved_link_reader_t, iface);
+}
+
+static int
+avro_resolved_link_reader_init(const avro_resolved_reader_t *iface, void *vself)
+{
+ int rval;
+ const avro_resolved_link_reader_t *liface =
+ container_of(iface, avro_resolved_link_reader_t, parent);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ size_t target_instance_size = liface->target_resolver->instance_size;
+
+ self->target.iface = &liface->target_resolver->parent;
+ self->target.self = avro_malloc(target_instance_size);
+ if (self->target.self == NULL) {
+ return ENOMEM;
+ }
+ DEBUG("Allocated <%p:%" PRIsz "> for link", self->target.self, target_instance_size);
+
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+
+ rval = avro_resolved_reader_init(liface->target_resolver, self->target.self);
+ if (rval != 0) {
+ avro_free(self->target.self, target_instance_size);
+ }
+ return rval;
+}
+
+static void
+avro_resolved_link_reader_done(const avro_resolved_reader_t *iface, void *vself)
+{
+ const avro_resolved_link_reader_t *liface =
+ container_of(iface, avro_resolved_link_reader_t, parent);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ size_t target_instance_size = liface->target_resolver->instance_size;
+ DEBUG("Freeing <%p:%" PRIsz "> for link", self->target.self, target_instance_size);
+ avro_resolved_reader_done(liface->target_resolver, self->target.self);
+ avro_free(self->target.self, target_instance_size);
+ self->target.iface = NULL;
+ self->target.self = NULL;
+}
+
+static int
+avro_resolved_link_reader_reset(const avro_resolved_reader_t *iface, void *vself)
+{
+ const avro_resolved_link_reader_t *liface =
+ container_of(iface, avro_resolved_link_reader_t, parent);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ return avro_resolved_reader_reset_wrappers
+ (liface->target_resolver, self->target.self);
+}
+
+static avro_type_t
+avro_resolved_link_reader_get_type(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_type(&self->target);
+}
+
+static avro_schema_t
+avro_resolved_link_reader_get_schema(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_schema(&self->target);
+}
+
+static int
+avro_resolved_link_reader_get_boolean(const avro_value_iface_t *iface,
+ const void *vself, int *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_boolean(&self->target, out);
+}
+
+static int
+avro_resolved_link_reader_get_bytes(const avro_value_iface_t *iface,
+ const void *vself, const void **buf, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_bytes(&self->target, buf, size);
+}
+
+static int
+avro_resolved_link_reader_grab_bytes(const avro_value_iface_t *iface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_grab_bytes(&self->target, dest);
+}
+
+static int
+avro_resolved_link_reader_get_double(const avro_value_iface_t *iface,
+ const void *vself, double *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_double(&self->target, out);
+}
+
+static int
+avro_resolved_link_reader_get_float(const avro_value_iface_t *iface,
+ const void *vself, float *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_float(&self->target, out);
+}
+
+static int
+avro_resolved_link_reader_get_int(const avro_value_iface_t *iface,
+ const void *vself, int32_t *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_int(&self->target, out);
+}
+
+static int
+avro_resolved_link_reader_get_long(const avro_value_iface_t *iface,
+ const void *vself, int64_t *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_long(&self->target, out);
+}
+
+static int
+avro_resolved_link_reader_get_null(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_null(&self->target);
+}
+
+static int
+avro_resolved_link_reader_get_string(const avro_value_iface_t *iface,
+ const void *vself, const char **str, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_string(&self->target, str, size);
+}
+
+static int
+avro_resolved_link_reader_grab_string(const avro_value_iface_t *iface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_grab_string(&self->target, dest);
+}
+
+static int
+avro_resolved_link_reader_get_enum(const avro_value_iface_t *iface,
+ const void *vself, int *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_enum(&self->target, out);
+}
+
+static int
+avro_resolved_link_reader_get_fixed(const avro_value_iface_t *iface,
+ const void *vself, const void **buf, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_fixed(&self->target, buf, size);
+}
+
+static int
+avro_resolved_link_reader_grab_fixed(const avro_value_iface_t *iface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_grab_fixed(&self->target, dest);
+}
+
+static int
+avro_resolved_link_reader_set_boolean(const avro_value_iface_t *iface,
+ void *vself, int val)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_boolean(&self->target, val);
+}
+
+static int
+avro_resolved_link_reader_set_bytes(const avro_value_iface_t *iface,
+ void *vself, void *buf, size_t size)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_bytes(&self->target, buf, size);
+}
+
+static int
+avro_resolved_link_reader_give_bytes(const avro_value_iface_t *iface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_give_bytes(&self->target, buf);
+}
+
+static int
+avro_resolved_link_reader_set_double(const avro_value_iface_t *iface,
+ void *vself, double val)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_double(&self->target, val);
+}
+
+static int
+avro_resolved_link_reader_set_float(const avro_value_iface_t *iface,
+ void *vself, float val)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_float(&self->target, val);
+}
+
+static int
+avro_resolved_link_reader_set_int(const avro_value_iface_t *iface,
+ void *vself, int32_t val)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_int(&self->target, val);
+}
+
+static int
+avro_resolved_link_reader_set_long(const avro_value_iface_t *iface,
+ void *vself, int64_t val)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_long(&self->target, val);
+}
+
+static int
+avro_resolved_link_reader_set_null(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_null(&self->target);
+}
+
+static int
+avro_resolved_link_reader_set_string(const avro_value_iface_t *iface,
+ void *vself, const char *str)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_string(&self->target, str);
+}
+
+static int
+avro_resolved_link_reader_set_string_len(const avro_value_iface_t *iface,
+ void *vself, const char *str, size_t size)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_string_len(&self->target, str, size);
+}
+
+static int
+avro_resolved_link_reader_give_string_len(const avro_value_iface_t *iface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_give_string_len(&self->target, buf);
+}
+
+static int
+avro_resolved_link_reader_set_enum(const avro_value_iface_t *iface,
+ void *vself, int val)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_enum(&self->target, val);
+}
+
+static int
+avro_resolved_link_reader_set_fixed(const avro_value_iface_t *iface,
+ void *vself, void *buf, size_t size)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_fixed(&self->target, buf, size);
+}
+
+static int
+avro_resolved_link_reader_give_fixed(const avro_value_iface_t *iface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_give_fixed(&self->target, buf);
+}
+
+static int
+avro_resolved_link_reader_get_size(const avro_value_iface_t *iface,
+ const void *vself, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_size(&self->target, size);
+}
+
+static int
+avro_resolved_link_reader_get_by_index(const avro_value_iface_t *iface,
+ const void *vself, size_t index,
+ avro_value_t *child, const char **name)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_by_index(&self->target, index, child, name);
+}
+
+static int
+avro_resolved_link_reader_get_by_name(const avro_value_iface_t *iface,
+ const void *vself, const char *name,
+ avro_value_t *child, size_t *index)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_by_name(&self->target, name, child, index);
+}
+
+static int
+avro_resolved_link_reader_get_discriminant(const avro_value_iface_t *iface,
+ const void *vself, int *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_discriminant(&self->target, out);
+}
+
+static int
+avro_resolved_link_reader_get_current_branch(const avro_value_iface_t *iface,
+ const void *vself, avro_value_t *branch)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_current_branch(&self->target, branch);
+}
+
+static int
+avro_resolved_link_reader_append(const avro_value_iface_t *iface,
+ void *vself, avro_value_t *child_out,
+ size_t *new_index)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_append(&self->target, child_out, new_index);
+}
+
+static int
+avro_resolved_link_reader_add(const avro_value_iface_t *iface,
+ void *vself, const char *key,
+ avro_value_t *child, size_t *index, int *is_new)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_add(&self->target, key, child, index, is_new);
+}
+
+static int
+avro_resolved_link_reader_set_branch(const avro_value_iface_t *iface,
+ void *vself, int discriminant,
+ avro_value_t *branch)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_branch(&self->target, discriminant, branch);
+}
+
+static avro_resolved_link_reader_t *
+avro_resolved_link_reader_create(avro_schema_t wschema, avro_schema_t rschema)
+{
+ avro_resolved_reader_t *self = (avro_resolved_reader_t *) avro_new(avro_resolved_link_reader_t);
+ memset(self, 0, sizeof(avro_resolved_link_reader_t));
+
+ self->parent.incref_iface = avro_resolved_reader_incref_iface;
+ self->parent.decref_iface = avro_resolved_reader_decref_iface;
+ self->parent.incref = avro_resolved_reader_incref;
+ self->parent.decref = avro_resolved_reader_decref;
+ self->parent.reset = avro_resolved_reader_reset;
+ self->parent.get_type = avro_resolved_link_reader_get_type;
+ self->parent.get_schema = avro_resolved_link_reader_get_schema;
+ self->parent.get_size = avro_resolved_link_reader_get_size;
+ self->parent.get_by_index = avro_resolved_link_reader_get_by_index;
+ self->parent.get_by_name = avro_resolved_link_reader_get_by_name;
+
+ self->refcount = 1;
+ self->wschema = avro_schema_incref(wschema);
+ self->rschema = avro_schema_incref(rschema);
+ self->free_iface = avro_resolved_link_reader_free_iface;
+ self->init = avro_resolved_link_reader_init;
+ self->done = avro_resolved_link_reader_done;
+ self->reset_wrappers = avro_resolved_link_reader_reset;
+
+ self->parent.get_boolean = avro_resolved_link_reader_get_boolean;
+ self->parent.get_bytes = avro_resolved_link_reader_get_bytes;
+ self->parent.grab_bytes = avro_resolved_link_reader_grab_bytes;
+ self->parent.get_double = avro_resolved_link_reader_get_double;
+ self->parent.get_float = avro_resolved_link_reader_get_float;
+ self->parent.get_int = avro_resolved_link_reader_get_int;
+ self->parent.get_long = avro_resolved_link_reader_get_long;
+ self->parent.get_null = avro_resolved_link_reader_get_null;
+ self->parent.get_string = avro_resolved_link_reader_get_string;
+ self->parent.grab_string = avro_resolved_link_reader_grab_string;
+ self->parent.get_enum = avro_resolved_link_reader_get_enum;
+ self->parent.get_fixed = avro_resolved_link_reader_get_fixed;
+ self->parent.grab_fixed = avro_resolved_link_reader_grab_fixed;
+
+ self->parent.set_boolean = avro_resolved_link_reader_set_boolean;
+ self->parent.set_bytes = avro_resolved_link_reader_set_bytes;
+ self->parent.give_bytes = avro_resolved_link_reader_give_bytes;
+ self->parent.set_double = avro_resolved_link_reader_set_double;
+ self->parent.set_float = avro_resolved_link_reader_set_float;
+ self->parent.set_int = avro_resolved_link_reader_set_int;
+ self->parent.set_long = avro_resolved_link_reader_set_long;
+ self->parent.set_null = avro_resolved_link_reader_set_null;
+ self->parent.set_string = avro_resolved_link_reader_set_string;
+ self->parent.set_string_len = avro_resolved_link_reader_set_string_len;
+ self->parent.give_string_len = avro_resolved_link_reader_give_string_len;
+ self->parent.set_enum = avro_resolved_link_reader_set_enum;
+ self->parent.set_fixed = avro_resolved_link_reader_set_fixed;
+ self->parent.give_fixed = avro_resolved_link_reader_give_fixed;
+
+ self->parent.get_size = avro_resolved_link_reader_get_size;
+ self->parent.get_by_index = avro_resolved_link_reader_get_by_index;
+ self->parent.get_by_name = avro_resolved_link_reader_get_by_name;
+ self->parent.get_discriminant = avro_resolved_link_reader_get_discriminant;
+ self->parent.get_current_branch = avro_resolved_link_reader_get_current_branch;
+
+ self->parent.append = avro_resolved_link_reader_append;
+ self->parent.add = avro_resolved_link_reader_add;
+ self->parent.set_branch = avro_resolved_link_reader_set_branch;
+
+ return container_of(self, avro_resolved_link_reader_t, parent);
+}
+
+static avro_resolved_reader_t *
+try_wlink(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ AVRO_UNUSED(rschema);
+
+ /*
+ * For link schemas, we create a special value implementation
+ * that allocates space for its wrapped value at runtime. This
+ * lets us handle recursive types without having to instantiate
+ * in infinite-size value.
+ */
+
+ avro_schema_t wtarget = avro_schema_link_target(wschema);
+ avro_resolved_link_reader_t *lself =
+ avro_resolved_link_reader_create(wtarget, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, lself);
+
+ avro_resolved_reader_t *target_resolver =
+ avro_resolved_reader_new_memoized(state, wtarget, rschema);
+ if (target_resolver == NULL) {
+ avro_memoize_delete(&state->mem, wschema, rschema);
+ avro_value_iface_decref(&lself->parent.parent);
+ avro_prefix_error("Link target isn't compatible: ");
+ DEBUG("%s", avro_strerror());
+ return NULL;
+ }
+
+ lself->parent.calculate_size = avro_resolved_wlink_reader_calculate_size;
+ lself->target_resolver = target_resolver;
+ lself->next = state->links;
+ state->links = lself;
+
+ return &lself->parent;
+}
+
+static avro_resolved_reader_t *
+try_rlink(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ AVRO_UNUSED(rschema);
+
+ /*
+ * For link schemas, we create a special value implementation
+ * that allocates space for its wrapped value at runtime. This
+ * lets us handle recursive types without having to instantiate
+ * in infinite-size value.
+ */
+
+ avro_schema_t rtarget = avro_schema_link_target(rschema);
+ avro_resolved_link_reader_t *lself =
+ avro_resolved_link_reader_create(wschema, rtarget);
+ avro_memoize_set(&state->mem, wschema, rschema, lself);
+
+ avro_resolved_reader_t *target_resolver =
+ avro_resolved_reader_new_memoized(state, wschema, rtarget);
+ if (target_resolver == NULL) {
+ avro_memoize_delete(&state->mem, wschema, rschema);
+ avro_value_iface_decref(&lself->parent.parent);
+ avro_prefix_error("Link target isn't compatible: ");
+ DEBUG("%s", avro_strerror());
+ return NULL;
+ }
+
+ lself->parent.calculate_size = avro_resolved_rlink_reader_calculate_size;
+ lself->target_resolver = target_resolver;
+ lself->next = state->links;
+ state->links = lself;
+
+ return &lself->parent;
+}
+
+
+/*-----------------------------------------------------------------------
+ * boolean
+ */
+
+static int
+avro_resolved_reader_get_boolean(const avro_value_iface_t *viface,
+ const void *vself, int *val)
+{
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Getting boolean from %p", src->self);
+ return avro_value_get_boolean(src, val);
+}
+
+static avro_resolved_reader_t *
+try_boolean(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ if (is_avro_boolean(wschema)) {
+ avro_resolved_reader_t *self =
+ avro_resolved_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, self);
+ self->parent.get_boolean = avro_resolved_reader_get_boolean;
+ return self;
+ }
+ avro_set_error("Writer %s not compatible with reader boolean",
+ avro_schema_type_name(wschema));
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * bytes
+ */
+
+static int
+avro_resolved_reader_get_bytes(const avro_value_iface_t *viface,
+ const void *vself, const void **buf, size_t *size)
+{
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Getting bytes from %p", src->self);
+ return avro_value_get_bytes(src, buf, size);
+}
+
+static int
+avro_resolved_reader_grab_bytes(const avro_value_iface_t *viface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Grabbing bytes from %p", src->self);
+ return avro_value_grab_bytes(src, dest);
+}
+
+static avro_resolved_reader_t *
+try_bytes(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ if (is_avro_bytes(wschema)) {
+ avro_resolved_reader_t *self =
+ avro_resolved_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, self);
+ self->parent.get_bytes = avro_resolved_reader_get_bytes;
+ self->parent.grab_bytes = avro_resolved_reader_grab_bytes;
+ return self;
+ }
+ avro_set_error("Writer %s not compatible with reader bytes",
+ avro_schema_type_name(wschema));
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * double
+ */
+
+static int
+avro_resolved_reader_get_double(const avro_value_iface_t *viface,
+ const void *vself, double *val)
+{
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Getting double from %p", src->self);
+ return avro_value_get_double(src, val);
+}
+
+static int
+avro_resolved_reader_get_double_float(const avro_value_iface_t *viface,
+ const void *vself, double *val)
+{
+ int rval;
+ float real_val;
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Promoting double from float %p", src->self);
+ check(rval, avro_value_get_float(src, &real_val));
+ *val = real_val;
+ return 0;
+}
+
+static int
+avro_resolved_reader_get_double_int(const avro_value_iface_t *viface,
+ const void *vself, double *val)
+{
+ int rval;
+ int32_t real_val;
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Promoting double from int %p", src->self);
+ check(rval, avro_value_get_int(src, &real_val));
+ *val = real_val;
+ return 0;
+}
+
+static int
+avro_resolved_reader_get_double_long(const avro_value_iface_t *viface,
+ const void *vself, double *val)
+{
+ int rval;
+ int64_t real_val;
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Promoting double from long %p", src->self);
+ check(rval, avro_value_get_long(src, &real_val));
+ *val = (double) real_val;
+ return 0;
+}
+
+static avro_resolved_reader_t *
+try_double(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ if (is_avro_double(wschema)) {
+ avro_resolved_reader_t *self =
+ avro_resolved_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, self);
+ self->parent.get_double = avro_resolved_reader_get_double;
+ return self;
+ }
+
+ else if (is_avro_float(wschema)) {
+ avro_resolved_reader_t *self =
+ avro_resolved_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, self);
+ self->parent.get_double = avro_resolved_reader_get_double_float;
+ return self;
+ }
+
+ else if (is_avro_int32(wschema)) {
+ avro_resolved_reader_t *self =
+ avro_resolved_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, self);
+ self->parent.get_double = avro_resolved_reader_get_double_int;
+ return self;
+ }
+
+ else if (is_avro_int64(wschema)) {
+ avro_resolved_reader_t *self =
+ avro_resolved_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, self);
+ self->parent.get_double = avro_resolved_reader_get_double_long;
+ return self;
+ }
+
+ avro_set_error("Writer %s not compatible with reader double",
+ avro_schema_type_name(wschema));
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * float
+ */
+
+static int
+avro_resolved_reader_get_float(const avro_value_iface_t *viface,
+ const void *vself, float *val)
+{
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Getting float from %p", src->self);
+ return avro_value_get_float(src, val);
+}
+
+static int
+avro_resolved_reader_get_float_int(const avro_value_iface_t *viface,
+ const void *vself, float *val)
+{
+ int rval;
+ int32_t real_val;
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Promoting float from int %p", src->self);
+ check(rval, avro_value_get_int(src, &real_val));
+ *val = (float) real_val;
+ return 0;
+}
+
+static int
+avro_resolved_reader_get_float_long(const avro_value_iface_t *viface,
+ const void *vself, float *val)
+{
+ int rval;
+ int64_t real_val;
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Promoting float from long %p", src->self);
+ check(rval, avro_value_get_long(src, &real_val));
+ *val = (float) real_val;
+ return 0;
+}
+
+static avro_resolved_reader_t *
+try_float(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ if (is_avro_float(wschema)) {
+ avro_resolved_reader_t *self =
+ avro_resolved_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, self);
+ self->parent.get_float = avro_resolved_reader_get_float;
+ return self;
+ }
+
+ else if (is_avro_int32(wschema)) {
+ avro_resolved_reader_t *self =
+ avro_resolved_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, self);
+ self->parent.get_float = avro_resolved_reader_get_float_int;
+ return self;
+ }
+
+ else if (is_avro_int64(wschema)) {
+ avro_resolved_reader_t *self =
+ avro_resolved_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, self);
+ self->parent.get_float = avro_resolved_reader_get_float_long;
+ return self;
+ }
+
+ avro_set_error("Writer %s not compatible with reader float",
+ avro_schema_type_name(wschema));
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * int
+ */
+
+static int
+avro_resolved_reader_get_int(const avro_value_iface_t *viface,
+ const void *vself, int32_t *val)
+{
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Getting int from %p", src->self);
+ return avro_value_get_int(src, val);
+}
+
+static avro_resolved_reader_t *
+try_int(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ if (is_avro_int32(wschema)) {
+ avro_resolved_reader_t *self =
+ avro_resolved_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, self);
+ self->parent.get_int = avro_resolved_reader_get_int;
+ return self;
+ }
+ avro_set_error("Writer %s not compatible with reader int",
+ avro_schema_type_name(wschema));
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * long
+ */
+
+static int
+avro_resolved_reader_get_long(const avro_value_iface_t *viface,
+ const void *vself, int64_t *val)
+{
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Getting long from %p", src->self);
+ return avro_value_get_long(src, val);
+}
+
+static int
+avro_resolved_reader_get_long_int(const avro_value_iface_t *viface,
+ const void *vself, int64_t *val)
+{
+ int rval;
+ int32_t real_val;
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Promoting long from int %p", src->self);
+ check(rval, avro_value_get_int(src, &real_val));
+ *val = real_val;
+ return 0;
+}
+
+static avro_resolved_reader_t *
+try_long(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ if (is_avro_int64(wschema)) {
+ avro_resolved_reader_t *self =
+ avro_resolved_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, self);
+ self->parent.get_long = avro_resolved_reader_get_long;
+ return self;
+ }
+
+ else if (is_avro_int32(wschema)) {
+ avro_resolved_reader_t *self =
+ avro_resolved_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, self);
+ self->parent.get_long = avro_resolved_reader_get_long_int;
+ return self;
+ }
+
+ avro_set_error("Writer %s not compatible with reader long",
+ avro_schema_type_name(wschema));
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * null
+ */
+
+static int
+avro_resolved_reader_get_null(const avro_value_iface_t *viface,
+ const void *vself)
+{
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Getting null from %p", src->self);
+ return avro_value_get_null(src);
+}
+
+static avro_resolved_reader_t *
+try_null(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ if (is_avro_null(wschema)) {
+ avro_resolved_reader_t *self =
+ avro_resolved_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, self);
+ self->parent.get_null = avro_resolved_reader_get_null;
+ return self;
+ }
+ avro_set_error("Writer %s not compatible with reader null",
+ avro_schema_type_name(wschema));
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * string
+ */
+
+static int
+avro_resolved_reader_get_string(const avro_value_iface_t *viface,
+ const void *vself, const char **str, size_t *size)
+{
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Getting string from %p", src->self);
+ return avro_value_get_string(src, str, size);
+}
+
+static int
+avro_resolved_reader_grab_string(const avro_value_iface_t *viface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Grabbing string from %p", src->self);
+ return avro_value_grab_string(src, dest);
+}
+
+static avro_resolved_reader_t *
+try_string(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ if (is_avro_string(wschema)) {
+ avro_resolved_reader_t *self =
+ avro_resolved_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, self);
+ self->parent.get_string = avro_resolved_reader_get_string;
+ self->parent.grab_string = avro_resolved_reader_grab_string;
+ return self;
+ }
+ avro_set_error("Writer %s not compatible with reader string",
+ avro_schema_type_name(wschema));
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * array
+ */
+
+typedef struct avro_resolved_array_reader {
+ avro_resolved_reader_t parent;
+ avro_resolved_reader_t *child_resolver;
+} avro_resolved_array_reader_t;
+
+typedef struct avro_resolved_array_value {
+ avro_value_t wrapped;
+ avro_raw_array_t children;
+} avro_resolved_array_value_t;
+
+static void
+avro_resolved_array_reader_calculate_size(avro_resolved_reader_t *iface)
+{
+ avro_resolved_array_reader_t *aiface =
+ container_of(iface, avro_resolved_array_reader_t, parent);
+
+ /* Only calculate the size for any resolver once */
+ iface->calculate_size = NULL;
+
+ DEBUG("Calculating size for %s->%s",
+ avro_schema_type_name((iface)->wschema),
+ avro_schema_type_name((iface)->rschema));
+ iface->instance_size = sizeof(avro_resolved_array_value_t);
+
+ avro_resolved_reader_calculate_size(aiface->child_resolver);
+}
+
+static void
+avro_resolved_array_reader_free_iface(avro_resolved_reader_t *iface, st_table *freeing)
+{
+ avro_resolved_array_reader_t *aiface =
+ container_of(iface, avro_resolved_array_reader_t, parent);
+ free_resolver(aiface->child_resolver, freeing);
+ avro_schema_decref(iface->wschema);
+ avro_schema_decref(iface->rschema);
+ avro_freet(avro_resolved_array_reader_t, iface);
+}
+
+static int
+avro_resolved_array_reader_init(const avro_resolved_reader_t *iface, void *vself)
+{
+ const avro_resolved_array_reader_t *aiface =
+ container_of(iface, avro_resolved_array_reader_t, parent);
+ avro_resolved_array_value_t *self = (avro_resolved_array_value_t *) vself;
+ size_t child_instance_size = aiface->child_resolver->instance_size;
+ DEBUG("Initializing child array (child_size=%" PRIsz ")", child_instance_size);
+ avro_raw_array_init(&self->children, child_instance_size);
+ return 0;
+}
+
+static void
+avro_resolved_array_reader_free_elements(const avro_resolved_reader_t *child_iface,
+ avro_resolved_array_value_t *self)
+{
+ size_t i;
+ for (i = 0; i < avro_raw_array_size(&self->children); i++) {
+ void *child_self = avro_raw_array_get_raw(&self->children, i);
+ avro_resolved_reader_done(child_iface, child_self);
+ }
+}
+
+static void
+avro_resolved_array_reader_done(const avro_resolved_reader_t *iface, void *vself)
+{
+ const avro_resolved_array_reader_t *aiface =
+ container_of(iface, avro_resolved_array_reader_t, parent);
+ avro_resolved_array_value_t *self = (avro_resolved_array_value_t *) vself;
+ avro_resolved_array_reader_free_elements(aiface->child_resolver, self);
+ avro_raw_array_done(&self->children);
+}
+
+static int
+avro_resolved_array_reader_reset(const avro_resolved_reader_t *iface, void *vself)
+{
+ const avro_resolved_array_reader_t *aiface =
+ container_of(iface, avro_resolved_array_reader_t, parent);
+ avro_resolved_array_value_t *self = (avro_resolved_array_value_t *) vself;
+
+ /* Clear out our cache of wrapped children */
+ avro_resolved_array_reader_free_elements(aiface->child_resolver, self);
+ avro_raw_array_clear(&self->children);
+ return 0;
+}
+
+static int
+avro_resolved_array_reader_get_size(const avro_value_iface_t *viface,
+ const void *vself, size_t *size)
+{
+ AVRO_UNUSED(viface);
+ const avro_resolved_array_value_t *self = (const avro_resolved_array_value_t *) vself;
+ return avro_value_get_size(&self->wrapped, size);
+}
+
+static int
+avro_resolved_array_reader_get_by_index(const avro_value_iface_t *viface,
+ const void *vself, size_t index,
+ avro_value_t *child, const char **name)
+{
+ int rval;
+ size_t old_size;
+ size_t new_size;
+ const avro_resolved_reader_t *iface =
+ container_of(viface, avro_resolved_reader_t, parent);
+ const avro_resolved_array_reader_t *aiface =
+ container_of(iface, avro_resolved_array_reader_t, parent);
+ avro_resolved_array_value_t *self = (avro_resolved_array_value_t *) vself;
+
+ /*
+ * Ensure that our child wrapper array is big enough to hold
+ * this many elements.
+ */
+ new_size = index + 1;
+ check(rval, avro_raw_array_ensure_size0(&self->children, new_size));
+ old_size = avro_raw_array_size(&self->children);
+ if (old_size <= index) {
+ size_t i;
+ for (i = old_size; i < new_size; i++) {
+ check(rval, avro_resolved_reader_init
+ (aiface->child_resolver,
+ avro_raw_array_get_raw(&self->children, i)));
+ }
+ avro_raw_array_size(&self->children) = index+1;
+ }
+
+ child->iface = &aiface->child_resolver->parent;
+ child->self = avro_raw_array_get_raw(&self->children, index);
+
+ DEBUG("Getting element %" PRIsz " from array %p", index, self->wrapped.self);
+ return avro_value_get_by_index(&self->wrapped, index, (avro_value_t *) child->self, name);
+}
+
+static avro_resolved_array_reader_t *
+avro_resolved_array_reader_create(avro_schema_t wschema, avro_schema_t rschema)
+{
+ avro_resolved_reader_t *self = (avro_resolved_reader_t *) avro_new(avro_resolved_array_reader_t);
+ memset(self, 0, sizeof(avro_resolved_array_reader_t));
+
+ self->parent.incref_iface = avro_resolved_reader_incref_iface;
+ self->parent.decref_iface = avro_resolved_reader_decref_iface;
+ self->parent.incref = avro_resolved_reader_incref;
+ self->parent.decref = avro_resolved_reader_decref;
+ self->parent.reset = avro_resolved_reader_reset;
+ self->parent.get_type = avro_resolved_reader_get_type;
+ self->parent.get_schema = avro_resolved_reader_get_schema;
+ self->parent.get_size = avro_resolved_array_reader_get_size;
+ self->parent.get_by_index = avro_resolved_array_reader_get_by_index;
+
+ self->refcount = 1;
+ self->wschema = avro_schema_incref(wschema);
+ self->rschema = avro_schema_incref(rschema);
+ self->calculate_size = avro_resolved_array_reader_calculate_size;
+ self->free_iface = avro_resolved_array_reader_free_iface;
+ self->init = avro_resolved_array_reader_init;
+ self->done = avro_resolved_array_reader_done;
+ self->reset_wrappers = avro_resolved_array_reader_reset;
+ return container_of(self, avro_resolved_array_reader_t, parent);
+}
+
+static avro_resolved_reader_t *
+try_array(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ /*
+ * First verify that the writer is an array.
+ */
+
+ if (!is_avro_array(wschema)) {
+ return 0;
+ }
+
+ /*
+ * Array schemas have to have compatible element schemas to be
+ * compatible themselves. Try to create an resolver to check
+ * the compatibility.
+ */
+
+ avro_resolved_array_reader_t *aself =
+ avro_resolved_array_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, aself);
+
+ avro_schema_t witems = avro_schema_array_items(wschema);
+ avro_schema_t ritems = avro_schema_array_items(rschema);
+
+ avro_resolved_reader_t *item_resolver =
+ avro_resolved_reader_new_memoized(state, witems, ritems);
+ if (item_resolver == NULL) {
+ avro_memoize_delete(&state->mem, wschema, rschema);
+ avro_value_iface_decref(&aself->parent.parent);
+ avro_prefix_error("Array values aren't compatible: ");
+ return NULL;
+ }
+
+ /*
+ * The two schemas are compatible. Store the item schema's
+ * resolver into the child_resolver field.
+ */
+
+ aself->child_resolver = item_resolver;
+ return &aself->parent;
+}
+
+
+/*-----------------------------------------------------------------------
+ * enum
+ */
+
+static int
+avro_resolved_reader_get_enum(const avro_value_iface_t *viface,
+ const void *vself, int *val)
+{
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Getting enum from %p", src->self);
+ return avro_value_get_enum(src, val);
+}
+
+static avro_resolved_reader_t *
+try_enum(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ /*
+ * Enum schemas have to have the same name — but not the same
+ * list of symbols — to be compatible.
+ */
+
+ if (is_avro_enum(wschema)) {
+ const char *wname = avro_schema_name(wschema);
+ const char *rname = avro_schema_name(rschema);
+
+ if (strcmp(wname, rname) == 0) {
+ avro_resolved_reader_t *self =
+ avro_resolved_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, self);
+ self->parent.get_enum = avro_resolved_reader_get_enum;
+ return self;
+ }
+ }
+ avro_set_error("Writer %s not compatible with reader %s",
+ avro_schema_type_name(wschema),
+ avro_schema_type_name(rschema));
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * fixed
+ */
+
+static int
+avro_resolved_reader_get_fixed(const avro_value_iface_t *viface,
+ const void *vself, const void **buf, size_t *size)
+{
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Getting fixed from %p", vself);
+ return avro_value_get_fixed(src, buf, size);
+}
+
+static int
+avro_resolved_reader_grab_fixed(const avro_value_iface_t *viface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ DEBUG("Grabbing fixed from %p", vself);
+ return avro_value_grab_fixed(src, dest);
+}
+
+static avro_resolved_reader_t *
+try_fixed(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ /*
+ * Fixed schemas need the same name and size to be compatible.
+ */
+
+ if (avro_schema_equal(wschema, rschema)) {
+ avro_resolved_reader_t *self =
+ avro_resolved_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, self);
+ self->parent.get_fixed = avro_resolved_reader_get_fixed;
+ self->parent.grab_fixed = avro_resolved_reader_grab_fixed;
+ return self;
+ }
+ avro_set_error("Writer %s not compatible with reader %s",
+ avro_schema_type_name(wschema),
+ avro_schema_type_name(rschema));
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * map
+ */
+
+typedef struct avro_resolved_map_reader {
+ avro_resolved_reader_t parent;
+ avro_resolved_reader_t *child_resolver;
+} avro_resolved_map_reader_t;
+
+typedef struct avro_resolved_map_value {
+ avro_value_t wrapped;
+ avro_raw_array_t children;
+} avro_resolved_map_value_t;
+
+static void
+avro_resolved_map_reader_calculate_size(avro_resolved_reader_t *iface)
+{
+ avro_resolved_map_reader_t *miface =
+ container_of(iface, avro_resolved_map_reader_t, parent);
+
+ /* Only calculate the size for any resolver once */
+ iface->calculate_size = NULL;
+
+ DEBUG("Calculating size for %s->%s",
+ avro_schema_type_name((iface)->wschema),
+ avro_schema_type_name((iface)->rschema));
+ iface->instance_size = sizeof(avro_resolved_map_value_t);
+
+ avro_resolved_reader_calculate_size(miface->child_resolver);
+}
+
+static void
+avro_resolved_map_reader_free_iface(avro_resolved_reader_t *iface, st_table *freeing)
+{
+ avro_resolved_map_reader_t *miface =
+ container_of(iface, avro_resolved_map_reader_t, parent);
+ free_resolver(miface->child_resolver, freeing);
+ avro_schema_decref(iface->wschema);
+ avro_schema_decref(iface->rschema);
+ avro_freet(avro_resolved_map_reader_t, iface);
+}
+
+static int
+avro_resolved_map_reader_init(const avro_resolved_reader_t *iface, void *vself)
+{
+ const avro_resolved_map_reader_t *miface =
+ container_of(iface, avro_resolved_map_reader_t, parent);
+ avro_resolved_map_value_t *self = (avro_resolved_map_value_t *) vself;
+ size_t child_instance_size = miface->child_resolver->instance_size;
+ DEBUG("Initializing child array for map (child_size=%" PRIsz ")", child_instance_size);
+ avro_raw_array_init(&self->children, child_instance_size);
+ return 0;
+}
+
+static void
+avro_resolved_map_reader_free_elements(const avro_resolved_reader_t *child_iface,
+ avro_resolved_map_value_t *self)
+{
+ size_t i;
+ for (i = 0; i < avro_raw_array_size(&self->children); i++) {
+ void *child_self = avro_raw_array_get_raw(&self->children, i);
+ avro_resolved_reader_done(child_iface, child_self);
+ }
+}
+
+static void
+avro_resolved_map_reader_done(const avro_resolved_reader_t *iface, void *vself)
+{
+ const avro_resolved_map_reader_t *miface =
+ container_of(iface, avro_resolved_map_reader_t, parent);
+ avro_resolved_map_value_t *self = (avro_resolved_map_value_t *) vself;
+ avro_resolved_map_reader_free_elements(miface->child_resolver, self);
+ avro_raw_array_done(&self->children);
+}
+
+static int
+avro_resolved_map_reader_reset(const avro_resolved_reader_t *iface, void *vself)
+{
+ const avro_resolved_map_reader_t *miface =
+ container_of(iface, avro_resolved_map_reader_t, parent);
+ avro_resolved_map_value_t *self = (avro_resolved_map_value_t *) vself;
+
+ /* Clear out our cache of wrapped children */
+ avro_resolved_map_reader_free_elements(miface->child_resolver, self);
+ return 0;
+}
+
+static int
+avro_resolved_map_reader_get_size(const avro_value_iface_t *viface,
+ const void *vself, size_t *size)
+{
+ AVRO_UNUSED(viface);
+ const avro_value_t *src = (const avro_value_t *) vself;
+ return avro_value_get_size(src, size);
+}
+
+static int
+avro_resolved_map_reader_get_by_index(const avro_value_iface_t *viface,
+ const void *vself, size_t index,
+ avro_value_t *child, const char **name)
+{
+ int rval;
+ const avro_resolved_reader_t *iface =
+ container_of(viface, avro_resolved_reader_t, parent);
+ const avro_resolved_map_reader_t *miface =
+ container_of(iface, avro_resolved_map_reader_t, parent);
+ avro_resolved_map_value_t *self = (avro_resolved_map_value_t *) vself;
+
+ /*
+ * Ensure that our child wrapper array is big enough to hold
+ * this many elements.
+ */
+ check(rval, avro_raw_array_ensure_size0(&self->children, index+1));
+ if (avro_raw_array_size(&self->children) <= index) {
+ avro_raw_array_size(&self->children) = index+1;
+ }
+
+ child->iface = &miface->child_resolver->parent;
+ child->self = avro_raw_array_get_raw(&self->children, index);
+
+ DEBUG("Getting element %" PRIsz " from map %p", index, self->wrapped.self);
+ return avro_value_get_by_index(&self->wrapped, index, (avro_value_t *) child->self, name);
+}
+
+static int
+avro_resolved_map_reader_get_by_name(const avro_value_iface_t *viface,
+ const void *vself, const char *name,
+ avro_value_t *child, size_t *index)
+{
+ int rval;
+ const avro_resolved_reader_t *iface =
+ container_of(viface, avro_resolved_reader_t, parent);
+ const avro_resolved_map_reader_t *miface =
+ container_of(iface, avro_resolved_map_reader_t, parent);
+ avro_resolved_map_value_t *self = (avro_resolved_map_value_t *) vself;
+
+ /*
+ * This is a bit convoluted. We need to stash the wrapped child
+ * value somewhere in our children array. But we don't know
+ * where to put it until the wrapped map tells us what its index
+ * is.
+ */
+
+ avro_value_t real_child;
+ size_t real_index;
+
+ DEBUG("Getting element %s from map %p", name, self->wrapped.self);
+ check(rval, avro_value_get_by_name
+ (&self->wrapped, name, &real_child, &real_index));
+
+ /*
+ * Ensure that our child wrapper array is big enough to hold
+ * this many elements.
+ */
+ check(rval, avro_raw_array_ensure_size0(&self->children, real_index+1));
+ if (avro_raw_array_size(&self->children) <= real_index) {
+ avro_raw_array_size(&self->children) = real_index+1;
+ }
+
+ child->iface = &miface->child_resolver->parent;
+ child->self = avro_raw_array_get_raw(&self->children, real_index);
+ avro_value_t *child_vself = (avro_value_t *) child->self;
+ *child_vself = real_child;
+
+ if (index != NULL) {
+ *index = real_index;
+ }
+ return 0;
+}
+
+static avro_resolved_map_reader_t *
+avro_resolved_map_reader_create(avro_schema_t wschema, avro_schema_t rschema)
+{
+ avro_resolved_reader_t *self = (avro_resolved_reader_t *) avro_new(avro_resolved_map_reader_t);
+ memset(self, 0, sizeof(avro_resolved_map_reader_t));
+
+ self->parent.incref_iface = avro_resolved_reader_incref_iface;
+ self->parent.decref_iface = avro_resolved_reader_decref_iface;
+ self->parent.incref = avro_resolved_reader_incref;
+ self->parent.decref = avro_resolved_reader_decref;
+ self->parent.reset = avro_resolved_reader_reset;
+ self->parent.get_type = avro_resolved_reader_get_type;
+ self->parent.get_schema = avro_resolved_reader_get_schema;
+ self->parent.get_size = avro_resolved_map_reader_get_size;
+ self->parent.get_by_index = avro_resolved_map_reader_get_by_index;
+ self->parent.get_by_name = avro_resolved_map_reader_get_by_name;
+
+ self->refcount = 1;
+ self->wschema = avro_schema_incref(wschema);
+ self->rschema = avro_schema_incref(rschema);
+ self->calculate_size = avro_resolved_map_reader_calculate_size;
+ self->free_iface = avro_resolved_map_reader_free_iface;
+ self->init = avro_resolved_map_reader_init;
+ self->done = avro_resolved_map_reader_done;
+ self->reset_wrappers = avro_resolved_map_reader_reset;
+ return container_of(self, avro_resolved_map_reader_t, parent);
+}
+
+static avro_resolved_reader_t *
+try_map(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ /*
+ * First verify that the reader is an map.
+ */
+
+ if (!is_avro_map(wschema)) {
+ return 0;
+ }
+
+ /*
+ * Map schemas have to have compatible element schemas to be
+ * compatible themselves. Try to create an resolver to check
+ * the compatibility.
+ */
+
+ avro_resolved_map_reader_t *mself =
+ avro_resolved_map_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, mself);
+
+ avro_schema_t witems = avro_schema_map_values(wschema);
+ avro_schema_t ritems = avro_schema_map_values(rschema);
+
+ avro_resolved_reader_t *item_resolver =
+ avro_resolved_reader_new_memoized(state, witems, ritems);
+ if (item_resolver == NULL) {
+ avro_memoize_delete(&state->mem, wschema, rschema);
+ avro_value_iface_decref(&mself->parent.parent);
+ avro_prefix_error("Map values aren't compatible: ");
+ return NULL;
+ }
+
+ /*
+ * The two schemas are compatible. Store the item schema's
+ * resolver into the child_resolver field.
+ */
+
+ mself->child_resolver = item_resolver;
+ return &mself->parent;
+}
+
+
+/*-----------------------------------------------------------------------
+ * record
+ */
+
+typedef struct avro_resolved_record_reader {
+ avro_resolved_reader_t parent;
+ size_t field_count;
+ size_t *field_offsets;
+ avro_resolved_reader_t **field_resolvers;
+ size_t *index_mapping;
+} avro_resolved_record_reader_t;
+
+typedef struct avro_resolved_record_value {
+ avro_value_t wrapped;
+ /* The rest of the struct is taken up by the inline storage
+ * needed for each field. */
+} avro_resolved_record_value_t;
+
+/** Return a pointer to the given field within a record struct. */
+#define avro_resolved_record_field(iface, rec, index) \
+ (((char *) (rec)) + (iface)->field_offsets[(index)])
+
+
+static void
+avro_resolved_record_reader_calculate_size(avro_resolved_reader_t *iface)
+{
+ avro_resolved_record_reader_t *riface =
+ container_of(iface, avro_resolved_record_reader_t, parent);
+
+ /* Only calculate the size for any resolver once */
+ iface->calculate_size = NULL;
+
+ DEBUG("Calculating size for %s->%s",
+ avro_schema_type_name((iface)->wschema),
+ avro_schema_type_name((iface)->rschema));
+
+ /*
+ * Once we've figured out which reader fields we actually need,
+ * calculate an offset for each one.
+ */
+
+ size_t ri;
+ size_t next_offset = sizeof(avro_resolved_record_value_t);
+ for (ri = 0; ri < riface->field_count; ri++) {
+ riface->field_offsets[ri] = next_offset;
+ if (riface->field_resolvers[ri] != NULL) {
+ avro_resolved_reader_calculate_size
+ (riface->field_resolvers[ri]);
+ size_t field_size =
+ riface->field_resolvers[ri]->instance_size;
+ DEBUG("Field %" PRIsz " has size %" PRIsz, ri, field_size);
+ next_offset += field_size;
+ } else {
+ DEBUG("Field %" PRIsz " is being skipped", ri);
+ }
+ }
+
+ DEBUG("Record has size %" PRIsz, next_offset);
+ iface->instance_size = next_offset;
+}
+
+
+static void
+avro_resolved_record_reader_free_iface(avro_resolved_reader_t *iface, st_table *freeing)
+{
+ avro_resolved_record_reader_t *riface =
+ container_of(iface, avro_resolved_record_reader_t, parent);
+
+ if (riface->field_offsets != NULL) {
+ avro_free(riface->field_offsets,
+ riface->field_count * sizeof(size_t));
+ }
+
+ if (riface->field_resolvers != NULL) {
+ size_t i;
+ for (i = 0; i < riface->field_count; i++) {
+ if (riface->field_resolvers[i] != NULL) {
+ DEBUG("Freeing field %" PRIsz " %p", i,
+ riface->field_resolvers[i]);
+ free_resolver(riface->field_resolvers[i], freeing);
+ }
+ }
+ avro_free(riface->field_resolvers,
+ riface->field_count * sizeof(avro_resolved_reader_t *));
+ }
+
+ if (riface->index_mapping != NULL) {
+ avro_free(riface->index_mapping,
+ riface->field_count * sizeof(size_t));
+ }
+
+ avro_schema_decref(iface->wschema);
+ avro_schema_decref(iface->rschema);
+ avro_freet(avro_resolved_record_reader_t, iface);
+}
+
+static int
+avro_resolved_record_reader_init(const avro_resolved_reader_t *iface, void *vself)
+{
+ int rval;
+ const avro_resolved_record_reader_t *riface =
+ container_of(iface, avro_resolved_record_reader_t, parent);
+ avro_resolved_record_value_t *self = (avro_resolved_record_value_t *) vself;
+
+ /* Initialize each field */
+ size_t i;
+ for (i = 0; i < riface->field_count; i++) {
+ if (riface->field_resolvers[i] != NULL) {
+ check(rval, avro_resolved_reader_init
+ (riface->field_resolvers[i],
+ avro_resolved_record_field(riface, self, i)));
+ }
+ }
+
+ return 0;
+}
+
+static void
+avro_resolved_record_reader_done(const avro_resolved_reader_t *iface, void *vself)
+{
+ const avro_resolved_record_reader_t *riface =
+ container_of(iface, avro_resolved_record_reader_t, parent);
+ avro_resolved_record_value_t *self = (avro_resolved_record_value_t *) vself;
+
+ /* Finalize each field */
+ size_t i;
+ for (i = 0; i < riface->field_count; i++) {
+ if (riface->field_resolvers[i] != NULL) {
+ avro_resolved_reader_done
+ (riface->field_resolvers[i],
+ avro_resolved_record_field(riface, self, i));
+ }
+ }
+}
+
+static int
+avro_resolved_record_reader_reset(const avro_resolved_reader_t *iface, void *vself)
+{
+ int rval;
+ const avro_resolved_record_reader_t *riface =
+ container_of(iface, avro_resolved_record_reader_t, parent);
+ avro_resolved_record_value_t *self = (avro_resolved_record_value_t *) vself;
+
+ /* Reset each field */
+ size_t i;
+ for (i = 0; i < riface->field_count; i++) {
+ if (riface->field_resolvers[i] != NULL) {
+ check(rval, avro_resolved_reader_reset_wrappers
+ (riface->field_resolvers[i],
+ avro_resolved_record_field(riface, self, i)));
+ }
+ }
+
+ return 0;
+}
+
+static int
+avro_resolved_record_reader_get_size(const avro_value_iface_t *viface,
+ const void *vself, size_t *size)
+{
+ AVRO_UNUSED(vself);
+ const avro_resolved_reader_t *iface =
+ container_of(viface, avro_resolved_reader_t, parent);
+ const avro_resolved_record_reader_t *riface =
+ container_of(iface, avro_resolved_record_reader_t, parent);
+ *size = riface->field_count;
+ return 0;
+}
+
+static int
+avro_resolved_record_reader_get_by_index(const avro_value_iface_t *viface,
+ const void *vself, size_t index,
+ avro_value_t *child, const char **name)
+{
+ const avro_resolved_reader_t *iface =
+ container_of(viface, avro_resolved_reader_t, parent);
+ const avro_resolved_record_reader_t *riface =
+ container_of(iface, avro_resolved_record_reader_t, parent);
+ const avro_resolved_record_value_t *self = (avro_resolved_record_value_t *) vself;
+
+ DEBUG("Getting reader field %" PRIsz " from record %p", index, self->wrapped.self);
+ if (riface->field_resolvers[index] == NULL) {
+ /*
+ * TODO: Return the default value if the writer record
+ * doesn't contain this field.
+ */
+ DEBUG("Writer doesn't have field");
+ avro_set_error("NIY: Default values");
+ return EINVAL;
+ }
+
+ size_t writer_index = riface->index_mapping[index];
+ DEBUG(" Writer field is %" PRIsz, writer_index);
+ child->iface = &riface->field_resolvers[index]->parent;
+ child->self = avro_resolved_record_field(riface, self, index);
+ return avro_value_get_by_index(&self->wrapped, writer_index, (avro_value_t *) child->self, name);
+}
+
+static int
+avro_resolved_record_reader_get_by_name(const avro_value_iface_t *viface,
+ const void *vself, const char *name,
+ avro_value_t *child, size_t *index)
+{
+ const avro_resolved_reader_t *iface =
+ container_of(viface, avro_resolved_reader_t, parent);
+
+ int ri = avro_schema_record_field_get_index(iface->rschema, name);
+ if (ri == -1) {
+ avro_set_error("Record doesn't have field named %s", name);
+ return EINVAL;
+ }
+
+ DEBUG("Reader field %s is at index %d", name, ri);
+ if (index != NULL) {
+ *index = ri;
+ }
+ return avro_resolved_record_reader_get_by_index(viface, vself, ri, child, NULL);
+}
+
+static avro_resolved_record_reader_t *
+avro_resolved_record_reader_create(avro_schema_t wschema, avro_schema_t rschema)
+{
+ avro_resolved_reader_t *self = (avro_resolved_reader_t *) avro_new(avro_resolved_record_reader_t);
+ memset(self, 0, sizeof(avro_resolved_record_reader_t));
+
+ self->parent.incref_iface = avro_resolved_reader_incref_iface;
+ self->parent.decref_iface = avro_resolved_reader_decref_iface;
+ self->parent.incref = avro_resolved_reader_incref;
+ self->parent.decref = avro_resolved_reader_decref;
+ self->parent.reset = avro_resolved_reader_reset;
+ self->parent.get_type = avro_resolved_reader_get_type;
+ self->parent.get_schema = avro_resolved_reader_get_schema;
+ self->parent.get_size = avro_resolved_record_reader_get_size;
+ self->parent.get_by_index = avro_resolved_record_reader_get_by_index;
+ self->parent.get_by_name = avro_resolved_record_reader_get_by_name;
+
+ self->refcount = 1;
+ self->wschema = avro_schema_incref(wschema);
+ self->rschema = avro_schema_incref(rschema);
+ self->calculate_size = avro_resolved_record_reader_calculate_size;
+ self->free_iface = avro_resolved_record_reader_free_iface;
+ self->init = avro_resolved_record_reader_init;
+ self->done = avro_resolved_record_reader_done;
+ self->reset_wrappers = avro_resolved_record_reader_reset;
+ return container_of(self, avro_resolved_record_reader_t, parent);
+}
+
+static avro_resolved_reader_t *
+try_record(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ /*
+ * First verify that the writer is also a record, and has the
+ * same name as the reader.
+ */
+
+ if (!is_avro_record(wschema)) {
+ return 0;
+ }
+
+ const char *wname = avro_schema_name(wschema);
+ const char *rname = avro_schema_name(rschema);
+
+ if (strcmp(wname, rname) != 0) {
+ return 0;
+ }
+
+ /*
+ * Categorize the fields in the record schemas. Fields that are
+ * only in the writer are ignored. Fields that are only in the
+ * reader raise a schema mismatch error, unless the field has a
+ * default value. Fields that are in both are resolved
+ * recursively.
+ *
+ * The field_resolvers array will contain an avro_value_iface_t
+ * for each field in the reader schema. To build this array, we
+ * loop through the fields of the reader schema. If that field
+ * is also in the writer schema, we resolve them recursively,
+ * and store the resolver into the array. If the field isn't in
+ * the writer schema, we raise an error. (TODO: Eventually,
+ * we'll handle default values here.) After this loop finishes,
+ * any NULLs in the field_resolvers array will represent fields
+ * in the writer but not the reader; these fields should be
+ * skipped, and won't be accessible in the resolved reader.
+ */
+
+ avro_resolved_record_reader_t *rself =
+ avro_resolved_record_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, rself);
+
+ size_t rfields = avro_schema_record_size(rschema);
+
+ DEBUG("Checking reader record schema %s", wname);
+
+ avro_resolved_reader_t **field_resolvers =
+ (avro_resolved_reader_t **) avro_calloc(rfields, sizeof(avro_resolved_reader_t *));
+ size_t *field_offsets = (size_t *) avro_calloc(rfields, sizeof(size_t));
+ size_t *index_mapping = (size_t *) avro_calloc(rfields, sizeof(size_t));
+
+ size_t ri;
+ for (ri = 0; ri < rfields; ri++) {
+ avro_schema_t rfield =
+ avro_schema_record_field_get_by_index(rschema, ri);
+ const char *field_name =
+ avro_schema_record_field_name(rschema, ri);
+
+ DEBUG("Resolving reader record field %" PRIsz " (%s)", ri, field_name);
+
+ /*
+ * See if this field is also in the writer schema.
+ */
+
+ int wi = avro_schema_record_field_get_index(wschema, field_name);
+
+ if (wi == -1) {
+ /*
+ * This field isn't in the writer schema —
+ * that's an error! TODO: Handle default
+ * values!
+ */
+
+ DEBUG("Field %s isn't in writer", field_name);
+ avro_set_error("Reader field %s doesn't appear in writer",
+ field_name);
+ goto error;
+ }
+
+ /*
+ * Try to recursively resolve the schemas for this
+ * field. If they're not compatible, that's an error.
+ */
+
+ avro_schema_t wfield =
+ avro_schema_record_field_get_by_index(wschema, wi);
+ avro_resolved_reader_t *field_resolver =
+ avro_resolved_reader_new_memoized(state, wfield, rfield);
+
+ if (field_resolver == NULL) {
+ avro_prefix_error("Field %s isn't compatible: ", field_name);
+ goto error;
+ }
+
+ /*
+ * Save the details for this field.
+ */
+
+ DEBUG("Found match for field %s (%" PRIsz " in reader, %d in writer)",
+ field_name, ri, wi);
+ field_resolvers[ri] = field_resolver;
+ index_mapping[ri] = wi;
+ }
+
+ /*
+ * We might not have found matches for all of the writer fields,
+ * but that's okay — any extras will be ignored.
+ */
+
+ rself->field_count = rfields;
+ rself->field_offsets = field_offsets;
+ rself->field_resolvers = field_resolvers;
+ rself->index_mapping = index_mapping;
+ return &rself->parent;
+
+error:
+ /*
+ * Clean up any resolver we might have already created.
+ */
+
+ avro_memoize_delete(&state->mem, wschema, rschema);
+ avro_value_iface_decref(&rself->parent.parent);
+
+ {
+ unsigned int i;
+ for (i = 0; i < rfields; i++) {
+ if (field_resolvers[i]) {
+ avro_value_iface_decref(&field_resolvers[i]->parent);
+ }
+ }
+ }
+
+ avro_free(field_resolvers, rfields * sizeof(avro_resolved_reader_t *));
+ avro_free(field_offsets, rfields * sizeof(size_t));
+ avro_free(index_mapping, rfields * sizeof(size_t));
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * writer union
+ */
+
+/*
+ * For writer unions, we maintain a list of resolvers for each branch of
+ * the union. When we encounter a writer value, we see which branch it
+ * is, and choose a reader resolver based on that.
+ */
+
+typedef struct avro_resolved_wunion_reader {
+ avro_resolved_reader_t parent;
+
+ /* The number of branches in the writer union */
+ size_t branch_count;
+
+ /* A child resolver for each branch of the writer union. If any
+ * of these are NULL, then we don't have anything on the reader
+ * side that's compatible with that writer branch. */
+ avro_resolved_reader_t **branch_resolvers;
+
+} avro_resolved_wunion_reader_t;
+
+typedef struct avro_resolved_wunion_value {
+ avro_value_t wrapped;
+
+ /** The currently active branch of the union. -1 if no branch
+ * is selected. */
+ int discriminant;
+
+ /* The rest of the struct is taken up by the inline storage
+ * needed for the active branch. */
+} avro_resolved_wunion_value_t;
+
+/** Return a pointer to the active branch within a union struct. */
+#define avro_resolved_wunion_branch(_wunion) \
+ (((char *) (_wunion)) + sizeof(avro_resolved_wunion_value_t))
+
+
+static void
+avro_resolved_wunion_reader_calculate_size(avro_resolved_reader_t *iface)
+{
+ avro_resolved_wunion_reader_t *uiface =
+ container_of(iface, avro_resolved_wunion_reader_t, parent);
+
+ /* Only calculate the size for any resolver once */
+ iface->calculate_size = NULL;
+
+ DEBUG("Calculating size for %s->%s",
+ avro_schema_type_name((iface)->wschema),
+ avro_schema_type_name((iface)->rschema));
+
+ size_t i;
+ size_t max_branch_size = 0;
+ for (i = 0; i < uiface->branch_count; i++) {
+ if (uiface->branch_resolvers[i] == NULL) {
+ DEBUG("No match for writer union branch %" PRIsz, i);
+ } else {
+ avro_resolved_reader_calculate_size
+ (uiface->branch_resolvers[i]);
+ size_t branch_size =
+ uiface->branch_resolvers[i]->instance_size;
+ DEBUG("Writer branch %" PRIsz " has size %" PRIsz, i, branch_size);
+ if (branch_size > max_branch_size) {
+ max_branch_size = branch_size;
+ }
+ }
+ }
+
+ DEBUG("Maximum branch size is %" PRIsz, max_branch_size);
+ iface->instance_size =
+ sizeof(avro_resolved_wunion_value_t) + max_branch_size;
+ DEBUG("Total union size is %" PRIsz, iface->instance_size);
+}
+
+
+static void
+avro_resolved_wunion_reader_free_iface(avro_resolved_reader_t *iface, st_table *freeing)
+{
+ avro_resolved_wunion_reader_t *uiface =
+ container_of(iface, avro_resolved_wunion_reader_t, parent);
+
+ if (uiface->branch_resolvers != NULL) {
+ size_t i;
+ for (i = 0; i < uiface->branch_count; i++) {
+ if (uiface->branch_resolvers[i] != NULL) {
+ free_resolver(uiface->branch_resolvers[i], freeing);
+ }
+ }
+ avro_free(uiface->branch_resolvers,
+ uiface->branch_count * sizeof(avro_resolved_reader_t *));
+ }
+
+ avro_schema_decref(iface->wschema);
+ avro_schema_decref(iface->rschema);
+ avro_freet(avro_resolved_wunion_reader_t, iface);
+}
+
+static int
+avro_resolved_wunion_reader_init(const avro_resolved_reader_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_wunion_value_t *self = (avro_resolved_wunion_value_t *) vself;
+ self->discriminant = -1;
+ return 0;
+}
+
+static void
+avro_resolved_wunion_reader_done(const avro_resolved_reader_t *iface, void *vself)
+{
+ const avro_resolved_wunion_reader_t *uiface =
+ container_of(iface, avro_resolved_wunion_reader_t, parent);
+ avro_resolved_wunion_value_t *self = (avro_resolved_wunion_value_t *) vself;
+ if (self->discriminant >= 0) {
+ avro_resolved_reader_done
+ (uiface->branch_resolvers[self->discriminant],
+ avro_resolved_wunion_branch(self));
+ self->discriminant = -1;
+ }
+}
+
+static int
+avro_resolved_wunion_reader_reset(const avro_resolved_reader_t *iface, void *vself)
+{
+ const avro_resolved_wunion_reader_t *uiface =
+ container_of(iface, avro_resolved_wunion_reader_t, parent);
+ avro_resolved_wunion_value_t *self = (avro_resolved_wunion_value_t *) vself;
+
+ /* Keep the same branch selected, for the common case that we're
+ * about to reuse it. */
+ if (self->discriminant >= 0) {
+ return avro_resolved_reader_reset_wrappers
+ (uiface->branch_resolvers[self->discriminant],
+ avro_resolved_wunion_branch(self));
+ }
+
+ return 0;
+}
+
+static int
+avro_resolved_wunion_get_real_src(const avro_value_iface_t *viface,
+ const void *vself, avro_value_t *real_src)
+{
+ int rval;
+ const avro_resolved_reader_t *iface =
+ container_of(viface, avro_resolved_reader_t, parent);
+ const avro_resolved_wunion_reader_t *uiface =
+ container_of(iface, avro_resolved_wunion_reader_t, parent);
+ avro_resolved_wunion_value_t *self = (avro_resolved_wunion_value_t *) vself;
+ int writer_disc;
+ check(rval, avro_value_get_discriminant(&self->wrapped, &writer_disc));
+ DEBUG("Writer is branch %d", writer_disc);
+
+ if (uiface->branch_resolvers[writer_disc] == NULL) {
+ avro_set_error("Reader isn't compatible with writer branch %d",
+ writer_disc);
+ return EINVAL;
+ }
+
+ if (self->discriminant == writer_disc) {
+ DEBUG("Writer branch %d already selected", writer_disc);
+ } else {
+ if (self->discriminant >= 0) {
+ DEBUG("Finalizing old writer branch %d", self->discriminant);
+ avro_resolved_reader_done
+ (uiface->branch_resolvers[self->discriminant],
+ avro_resolved_wunion_branch(self));
+ }
+ DEBUG("Initializing writer branch %d", writer_disc);
+ check(rval, avro_resolved_reader_init
+ (uiface->branch_resolvers[writer_disc],
+ avro_resolved_wunion_branch(self)));
+ self->discriminant = writer_disc;
+ }
+
+ real_src->iface = &uiface->branch_resolvers[writer_disc]->parent;
+ real_src->self = avro_resolved_wunion_branch(self);
+ return avro_value_get_current_branch(&self->wrapped, (avro_value_t *) real_src->self);
+}
+
+static int
+avro_resolved_wunion_reader_get_boolean(const avro_value_iface_t *viface,
+ const void *vself, int *out)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_get_boolean(&src, out);
+}
+
+static int
+avro_resolved_wunion_reader_get_bytes(const avro_value_iface_t *viface,
+ const void *vself, const void **buf, size_t *size)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_get_bytes(&src, buf, size);
+}
+
+static int
+avro_resolved_wunion_reader_grab_bytes(const avro_value_iface_t *viface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_grab_bytes(&src, dest);
+}
+
+static int
+avro_resolved_wunion_reader_get_double(const avro_value_iface_t *viface,
+ const void *vself, double *out)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_get_double(&src, out);
+}
+
+static int
+avro_resolved_wunion_reader_get_float(const avro_value_iface_t *viface,
+ const void *vself, float *out)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_get_float(&src, out);
+}
+
+static int
+avro_resolved_wunion_reader_get_int(const avro_value_iface_t *viface,
+ const void *vself, int32_t *out)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_get_int(&src, out);
+}
+
+static int
+avro_resolved_wunion_reader_get_long(const avro_value_iface_t *viface,
+ const void *vself, int64_t *out)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_get_long(&src, out);
+}
+
+static int
+avro_resolved_wunion_reader_get_null(const avro_value_iface_t *viface,
+ const void *vself)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_get_null(&src);
+}
+
+static int
+avro_resolved_wunion_reader_get_string(const avro_value_iface_t *viface,
+ const void *vself, const char **str, size_t *size)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_get_string(&src, str, size);
+}
+
+static int
+avro_resolved_wunion_reader_grab_string(const avro_value_iface_t *viface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_grab_string(&src, dest);
+}
+
+static int
+avro_resolved_wunion_reader_get_enum(const avro_value_iface_t *viface,
+ const void *vself, int *out)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_get_enum(&src, out);
+}
+
+static int
+avro_resolved_wunion_reader_get_fixed(const avro_value_iface_t *viface,
+ const void *vself, const void **buf, size_t *size)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_get_fixed(&src, buf, size);
+}
+
+static int
+avro_resolved_wunion_reader_grab_fixed(const avro_value_iface_t *viface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_grab_fixed(&src, dest);
+}
+
+static int
+avro_resolved_wunion_reader_set_boolean(const avro_value_iface_t *viface,
+ void *vself, int val)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_set_boolean(&src, val);
+}
+
+static int
+avro_resolved_wunion_reader_set_bytes(const avro_value_iface_t *viface,
+ void *vself, void *buf, size_t size)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_set_bytes(&src, buf, size);
+}
+
+static int
+avro_resolved_wunion_reader_give_bytes(const avro_value_iface_t *viface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_give_bytes(&src, buf);
+}
+
+static int
+avro_resolved_wunion_reader_set_double(const avro_value_iface_t *viface,
+ void *vself, double val)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_set_double(&src, val);
+}
+
+static int
+avro_resolved_wunion_reader_set_float(const avro_value_iface_t *viface,
+ void *vself, float val)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_set_float(&src, val);
+}
+
+static int
+avro_resolved_wunion_reader_set_int(const avro_value_iface_t *viface,
+ void *vself, int32_t val)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_set_int(&src, val);
+}
+
+static int
+avro_resolved_wunion_reader_set_long(const avro_value_iface_t *viface,
+ void *vself, int64_t val)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_set_long(&src, val);
+}
+
+static int
+avro_resolved_wunion_reader_set_null(const avro_value_iface_t *viface,
+ void *vself)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_set_null(&src);
+}
+
+static int
+avro_resolved_wunion_reader_set_string(const avro_value_iface_t *viface,
+ void *vself, const char *str)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_set_string(&src, str);
+}
+
+static int
+avro_resolved_wunion_reader_set_string_len(const avro_value_iface_t *viface,
+ void *vself, const char *str, size_t size)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_set_string_len(&src, str, size);
+}
+
+static int
+avro_resolved_wunion_reader_give_string_len(const avro_value_iface_t *viface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_give_string_len(&src, buf);
+}
+
+static int
+avro_resolved_wunion_reader_set_enum(const avro_value_iface_t *viface,
+ void *vself, int val)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_set_enum(&src, val);
+}
+
+static int
+avro_resolved_wunion_reader_set_fixed(const avro_value_iface_t *viface,
+ void *vself, void *buf, size_t size)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_set_fixed(&src, buf, size);
+}
+
+static int
+avro_resolved_wunion_reader_give_fixed(const avro_value_iface_t *viface,
+ void *vself, avro_wrapped_buffer_t *dest)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_give_fixed(&src, dest);
+}
+
+static int
+avro_resolved_wunion_reader_get_size(const avro_value_iface_t *viface,
+ const void *vself, size_t *size)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_get_size(&src, size);
+}
+
+static int
+avro_resolved_wunion_reader_get_by_index(const avro_value_iface_t *viface,
+ const void *vself, size_t index,
+ avro_value_t *child, const char **name)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_get_by_index(&src, index, child, name);
+}
+
+static int
+avro_resolved_wunion_reader_get_by_name(const avro_value_iface_t *viface,
+ const void *vself, const char *name,
+ avro_value_t *child, size_t *index)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_get_by_name(&src, name, child, index);
+}
+
+static int
+avro_resolved_wunion_reader_get_discriminant(const avro_value_iface_t *viface,
+ const void *vself, int *out)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_get_discriminant(&src, out);
+}
+
+static int
+avro_resolved_wunion_reader_get_current_branch(const avro_value_iface_t *viface,
+ const void *vself, avro_value_t *branch)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_get_current_branch(&src, branch);
+}
+
+static int
+avro_resolved_wunion_reader_append(const avro_value_iface_t *viface,
+ void *vself, avro_value_t *child_out,
+ size_t *new_index)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_append(&src, child_out, new_index);
+}
+
+static int
+avro_resolved_wunion_reader_add(const avro_value_iface_t *viface,
+ void *vself, const char *key,
+ avro_value_t *child, size_t *index, int *is_new)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_add(&src, key, child, index, is_new);
+}
+
+static int
+avro_resolved_wunion_reader_set_branch(const avro_value_iface_t *viface,
+ void *vself, int discriminant,
+ avro_value_t *branch)
+{
+ int rval;
+ avro_value_t src;
+ check(rval, avro_resolved_wunion_get_real_src(viface, vself, &src));
+ return avro_value_set_branch(&src, discriminant, branch);
+}
+
+static avro_resolved_wunion_reader_t *
+avro_resolved_wunion_reader_create(avro_schema_t wschema, avro_schema_t rschema)
+{
+ avro_resolved_reader_t *self = (avro_resolved_reader_t *) avro_new(avro_resolved_wunion_reader_t);
+ memset(self, 0, sizeof(avro_resolved_wunion_reader_t));
+
+ self->parent.incref_iface = avro_resolved_reader_incref_iface;
+ self->parent.decref_iface = avro_resolved_reader_decref_iface;
+ self->parent.incref = avro_resolved_reader_incref;
+ self->parent.decref = avro_resolved_reader_decref;
+ self->parent.reset = avro_resolved_reader_reset;
+ self->parent.get_type = avro_resolved_reader_get_type;
+ self->parent.get_schema = avro_resolved_reader_get_schema;
+
+ self->parent.get_boolean = avro_resolved_wunion_reader_get_boolean;
+ self->parent.grab_bytes = avro_resolved_wunion_reader_grab_bytes;
+ self->parent.get_bytes = avro_resolved_wunion_reader_get_bytes;
+ self->parent.get_double = avro_resolved_wunion_reader_get_double;
+ self->parent.get_float = avro_resolved_wunion_reader_get_float;
+ self->parent.get_int = avro_resolved_wunion_reader_get_int;
+ self->parent.get_long = avro_resolved_wunion_reader_get_long;
+ self->parent.get_null = avro_resolved_wunion_reader_get_null;
+ self->parent.get_string = avro_resolved_wunion_reader_get_string;
+ self->parent.grab_string = avro_resolved_wunion_reader_grab_string;
+ self->parent.get_enum = avro_resolved_wunion_reader_get_enum;
+ self->parent.get_fixed = avro_resolved_wunion_reader_get_fixed;
+ self->parent.grab_fixed = avro_resolved_wunion_reader_grab_fixed;
+
+ self->parent.set_boolean = avro_resolved_wunion_reader_set_boolean;
+ self->parent.set_bytes = avro_resolved_wunion_reader_set_bytes;
+ self->parent.give_bytes = avro_resolved_wunion_reader_give_bytes;
+ self->parent.set_double = avro_resolved_wunion_reader_set_double;
+ self->parent.set_float = avro_resolved_wunion_reader_set_float;
+ self->parent.set_int = avro_resolved_wunion_reader_set_int;
+ self->parent.set_long = avro_resolved_wunion_reader_set_long;
+ self->parent.set_null = avro_resolved_wunion_reader_set_null;
+ self->parent.set_string = avro_resolved_wunion_reader_set_string;
+ self->parent.set_string_len = avro_resolved_wunion_reader_set_string_len;
+ self->parent.give_string_len = avro_resolved_wunion_reader_give_string_len;
+ self->parent.set_enum = avro_resolved_wunion_reader_set_enum;
+ self->parent.set_fixed = avro_resolved_wunion_reader_set_fixed;
+ self->parent.give_fixed = avro_resolved_wunion_reader_give_fixed;
+
+ self->parent.get_size = avro_resolved_wunion_reader_get_size;
+ self->parent.get_by_index = avro_resolved_wunion_reader_get_by_index;
+ self->parent.get_by_name = avro_resolved_wunion_reader_get_by_name;
+ self->parent.get_discriminant = avro_resolved_wunion_reader_get_discriminant;
+ self->parent.get_current_branch = avro_resolved_wunion_reader_get_current_branch;
+
+ self->parent.append = avro_resolved_wunion_reader_append;
+ self->parent.add = avro_resolved_wunion_reader_add;
+ self->parent.set_branch = avro_resolved_wunion_reader_set_branch;
+
+ self->refcount = 1;
+ self->wschema = avro_schema_incref(wschema);
+ self->rschema = avro_schema_incref(rschema);
+ self->calculate_size = avro_resolved_wunion_reader_calculate_size;
+ self->free_iface = avro_resolved_wunion_reader_free_iface;
+ self->init = avro_resolved_wunion_reader_init;
+ self->done = avro_resolved_wunion_reader_done;
+ self->reset_wrappers = avro_resolved_wunion_reader_reset;
+ return container_of(self, avro_resolved_wunion_reader_t, parent);
+}
+
+static avro_resolved_reader_t *
+try_writer_union(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ /*
+ * For a writer union, we check each branch of the union in turn
+ * against the reader schema. For each one that is compatible,
+ * we save the child resolver that can be used to process a
+ * writer value of that branch.
+ */
+
+ size_t branch_count = avro_schema_union_size(wschema);
+ DEBUG("Checking %" PRIsz "-branch writer union schema", branch_count);
+
+ avro_resolved_wunion_reader_t *uself =
+ avro_resolved_wunion_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, uself);
+
+ avro_resolved_reader_t **branch_resolvers =
+ (avro_resolved_reader_t **) avro_calloc(branch_count, sizeof(avro_resolved_reader_t *));
+ int some_branch_compatible = 0;
+
+ size_t i;
+ for (i = 0; i < branch_count; i++) {
+ avro_schema_t branch_schema =
+ avro_schema_union_branch(wschema, i);
+
+ DEBUG("Resolving writer union branch %" PRIsz " (%s)", i,
+ avro_schema_type_name(branch_schema));
+
+ /*
+ * Try to recursively resolve this branch of the writer
+ * union against the reader schema. Don't raise
+ * an error if this fails — we just need one of
+ * the writer branches to be compatible.
+ */
+
+ branch_resolvers[i] =
+ avro_resolved_reader_new_memoized(state, branch_schema, rschema);
+ if (branch_resolvers[i] == NULL) {
+ DEBUG("No match for writer union branch %" PRIsz, i);
+ } else {
+ DEBUG("Found match for writer union branch %" PRIsz, i);
+ some_branch_compatible = 1;
+ }
+ }
+
+ /*
+ * If we didn't find a match, that's an error.
+ */
+
+ if (!some_branch_compatible) {
+ DEBUG("No writer union branches match");
+ avro_set_error("No branches in the writer are compatible "
+ "with reader schema %s",
+ avro_schema_type_name(rschema));
+ goto error;
+ }
+
+ uself->branch_count = branch_count;
+ uself->branch_resolvers = branch_resolvers;
+ return &uself->parent;
+
+error:
+ /*
+ * Clean up any resolver we might have already created.
+ */
+
+ avro_memoize_delete(&state->mem, wschema, rschema);
+ avro_value_iface_decref(&uself->parent.parent);
+
+ {
+ unsigned int i;
+ for (i = 0; i < branch_count; i++) {
+ if (branch_resolvers[i]) {
+ avro_value_iface_decref(&branch_resolvers[i]->parent);
+ }
+ }
+ }
+
+ avro_free(branch_resolvers, branch_count * sizeof(avro_resolved_reader_t *));
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * reader union
+ */
+
+/*
+ * For reader unions, we only resolve them against writers which aren't
+ * unions. (We'll have already broken any writer union apart into its
+ * separate branches.) We just have to record which branch of the
+ * reader union the writer schema is compatible with.
+ */
+
+typedef struct avro_resolved_runion_reader {
+ avro_resolved_reader_t parent;
+
+ /* The reader union branch that's compatible with the writer
+ * schema. */
+ size_t active_branch;
+
+ /* A child resolver for the reader branch. */
+ avro_resolved_reader_t *branch_resolver;
+} avro_resolved_runion_reader_t;
+
+
+static void
+avro_resolved_runion_reader_calculate_size(avro_resolved_reader_t *iface)
+{
+ avro_resolved_runion_reader_t *uiface =
+ container_of(iface, avro_resolved_runion_reader_t, parent);
+
+ /* Only calculate the size for any resolver once */
+ iface->calculate_size = NULL;
+
+ DEBUG("Calculating size for %s->%s",
+ avro_schema_type_name((iface)->wschema),
+ avro_schema_type_name((iface)->rschema));
+
+ avro_resolved_reader_calculate_size(uiface->branch_resolver);
+ iface->instance_size = uiface->branch_resolver->instance_size;
+}
+
+
+static void
+avro_resolved_runion_reader_free_iface(avro_resolved_reader_t *iface, st_table *freeing)
+{
+ avro_resolved_runion_reader_t *uiface =
+ container_of(iface, avro_resolved_runion_reader_t, parent);
+
+ if (uiface->branch_resolver != NULL) {
+ free_resolver(uiface->branch_resolver, freeing);
+ }
+
+ avro_schema_decref(iface->wschema);
+ avro_schema_decref(iface->rschema);
+ avro_freet(avro_resolved_runion_reader_t, iface);
+}
+
+static int
+avro_resolved_runion_reader_init(const avro_resolved_reader_t *iface, void *vself)
+{
+ avro_resolved_runion_reader_t *uiface =
+ container_of(iface, avro_resolved_runion_reader_t, parent);
+ return avro_resolved_reader_init(uiface->branch_resolver, vself);
+}
+
+static void
+avro_resolved_runion_reader_done(const avro_resolved_reader_t *iface, void *vself)
+{
+ avro_resolved_runion_reader_t *uiface =
+ container_of(iface, avro_resolved_runion_reader_t, parent);
+ avro_resolved_reader_done(uiface->branch_resolver, vself);
+}
+
+static int
+avro_resolved_runion_reader_reset(const avro_resolved_reader_t *iface, void *vself)
+{
+ avro_resolved_runion_reader_t *uiface =
+ container_of(iface, avro_resolved_runion_reader_t, parent);
+ return avro_resolved_reader_reset_wrappers(uiface->branch_resolver, vself);
+}
+
+static int
+avro_resolved_runion_reader_get_discriminant(const avro_value_iface_t *viface,
+ const void *vself, int *out)
+{
+ AVRO_UNUSED(vself);
+ const avro_resolved_reader_t *iface =
+ container_of(viface, avro_resolved_reader_t, parent);
+ const avro_resolved_runion_reader_t *uiface =
+ container_of(iface, avro_resolved_runion_reader_t, parent);
+ DEBUG("Reader union is branch %" PRIsz, uiface->active_branch);
+ *out = uiface->active_branch;
+ return 0;
+}
+
+static int
+avro_resolved_runion_reader_get_current_branch(const avro_value_iface_t *viface,
+ const void *vself, avro_value_t *branch)
+{
+ const avro_resolved_reader_t *iface =
+ container_of(viface, avro_resolved_reader_t, parent);
+ const avro_resolved_runion_reader_t *uiface =
+ container_of(iface, avro_resolved_runion_reader_t, parent);
+ DEBUG("Getting reader branch %" PRIsz " for union %p", uiface->active_branch, vself);
+ branch->iface = &uiface->branch_resolver->parent;
+ branch->self = (void *) vself;
+ return 0;
+}
+
+static avro_resolved_runion_reader_t *
+avro_resolved_runion_reader_create(avro_schema_t wschema, avro_schema_t rschema)
+{
+ avro_resolved_reader_t *self = (avro_resolved_reader_t *) avro_new(avro_resolved_runion_reader_t);
+ memset(self, 0, sizeof(avro_resolved_runion_reader_t));
+
+ self->parent.incref_iface = avro_resolved_reader_incref_iface;
+ self->parent.decref_iface = avro_resolved_reader_decref_iface;
+ self->parent.incref = avro_resolved_reader_incref;
+ self->parent.decref = avro_resolved_reader_decref;
+ self->parent.reset = avro_resolved_reader_reset;
+ self->parent.get_type = avro_resolved_reader_get_type;
+ self->parent.get_schema = avro_resolved_reader_get_schema;
+ self->parent.get_discriminant = avro_resolved_runion_reader_get_discriminant;
+ self->parent.get_current_branch = avro_resolved_runion_reader_get_current_branch;
+
+ self->refcount = 1;
+ self->wschema = avro_schema_incref(wschema);
+ self->rschema = avro_schema_incref(rschema);
+ self->calculate_size = avro_resolved_runion_reader_calculate_size;
+ self->free_iface = avro_resolved_runion_reader_free_iface;
+ self->init = avro_resolved_runion_reader_init;
+ self->done = avro_resolved_runion_reader_done;
+ self->reset_wrappers = avro_resolved_runion_reader_reset;
+ return container_of(self, avro_resolved_runion_reader_t, parent);
+}
+
+static avro_resolved_reader_t *
+try_reader_union(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ /*
+ * For a reader union, we have to identify which branch
+ * corresponds to the writer schema. (The writer won't be a
+ * union, since we'll have already broken it into its branches.)
+ */
+
+ size_t branch_count = avro_schema_union_size(rschema);
+ DEBUG("Checking %" PRIsz "-branch reader union schema", branch_count);
+
+ avro_resolved_runion_reader_t *uself =
+ avro_resolved_runion_reader_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, uself);
+
+ size_t i;
+ for (i = 0; i < branch_count; i++) {
+ avro_schema_t branch_schema =
+ avro_schema_union_branch(rschema, i);
+
+ DEBUG("Resolving reader union branch %" PRIsz " (%s)", i,
+ avro_schema_type_name(branch_schema));
+
+ /*
+ * Try to recursively resolve this branch of the reader
+ * union against the writer schema. Don't raise
+ * an error if this fails — we just need one of
+ * the reader branches to be compatible.
+ */
+
+ uself->branch_resolver =
+ avro_resolved_reader_new_memoized(state, wschema, branch_schema);
+ if (uself->branch_resolver == NULL) {
+ DEBUG("No match for reader union branch %" PRIsz, i);
+ } else {
+ DEBUG("Found match for reader union branch %" PRIsz, i);
+ uself->active_branch = i;
+ return &uself->parent;
+ }
+ }
+
+ /*
+ * If we didn't find a match, that's an error.
+ */
+
+ DEBUG("No reader union branches match");
+ avro_set_error("No branches in the reader are compatible "
+ "with writer schema %s",
+ avro_schema_type_name(wschema));
+ goto error;
+
+error:
+ /*
+ * Clean up any resolver we might have already created.
+ */
+
+ avro_memoize_delete(&state->mem, wschema, rschema);
+ avro_value_iface_decref(&uself->parent.parent);
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * Schema type dispatcher
+ */
+
+static avro_resolved_reader_t *
+avro_resolved_reader_new_memoized(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ check_param(NULL, is_avro_schema(wschema), "writer schema");
+ check_param(NULL, is_avro_schema(rschema), "reader schema");
+
+ /*
+ * First see if we've already matched these two schemas. If so,
+ * just return that resolver.
+ */
+
+ avro_resolved_reader_t *saved = NULL;
+ if (avro_memoize_get(&state->mem, wschema, rschema, (void **) &saved)) {
+ DEBUG("Already resolved %s%s%s->%s%s%s",
+ is_avro_link(wschema)? "[": "",
+ avro_schema_type_name(wschema),
+ is_avro_link(wschema)? "]": "",
+ is_avro_link(rschema)? "[": "",
+ avro_schema_type_name(rschema),
+ is_avro_link(rschema)? "]": "");
+ return saved;
+ } else {
+ DEBUG("Resolving %s%s%s->%s%s%s",
+ is_avro_link(wschema)? "[": "",
+ avro_schema_type_name(wschema),
+ is_avro_link(wschema)? "]": "",
+ is_avro_link(rschema)? "[": "",
+ avro_schema_type_name(rschema),
+ is_avro_link(rschema)? "]": "");
+ }
+
+ /*
+ * Otherwise we have some work to do. First check if the writer
+ * schema is a union. If so, break it apart.
+ */
+
+ if (is_avro_union(wschema)) {
+ return try_writer_union(state, wschema, rschema);
+ }
+
+ else if (is_avro_link(wschema)) {
+ return try_wlink(state, wschema, rschema);
+ }
+
+ /*
+ * If the writer isn't a union, than choose a resolver based on
+ * the reader schema.
+ */
+
+ switch (avro_typeof(rschema))
+ {
+ case AVRO_BOOLEAN:
+ return try_boolean(state, wschema, rschema);
+
+ case AVRO_BYTES:
+ return try_bytes(state, wschema, rschema);
+
+ case AVRO_DOUBLE:
+ return try_double(state, wschema, rschema);
+
+ case AVRO_FLOAT:
+ return try_float(state, wschema, rschema);
+
+ case AVRO_INT32:
+ return try_int(state, wschema, rschema);
+
+ case AVRO_INT64:
+ return try_long(state, wschema, rschema);
+
+ case AVRO_NULL:
+ return try_null(state, wschema, rschema);
+
+ case AVRO_STRING:
+ return try_string(state, wschema, rschema);
+
+ case AVRO_ARRAY:
+ return try_array(state, wschema, rschema);
+
+ case AVRO_ENUM:
+ return try_enum(state, wschema, rschema);
+
+ case AVRO_FIXED:
+ return try_fixed(state, wschema, rschema);
+
+ case AVRO_MAP:
+ return try_map(state, wschema, rschema);
+
+ case AVRO_RECORD:
+ return try_record(state, wschema, rschema);
+
+ case AVRO_UNION:
+ return try_reader_union(state, wschema, rschema);
+
+ case AVRO_LINK:
+ return try_rlink(state, wschema, rschema);
+
+ default:
+ avro_set_error("Unknown reader schema type");
+ return NULL;
+ }
+
+ return NULL;
+}
+
+
+avro_value_iface_t *
+avro_resolved_reader_new(avro_schema_t wschema, avro_schema_t rschema)
+{
+ /*
+ * Create a state to keep track of the value implementations
+ * that we create for each subschema.
+ */
+
+ memoize_state_t state;
+ avro_memoize_init(&state.mem);
+ state.links = NULL;
+
+ /*
+ * Create the value implementations.
+ */
+
+ avro_resolved_reader_t *result =
+ avro_resolved_reader_new_memoized(&state, wschema, rschema);
+ if (result == NULL) {
+ avro_memoize_done(&state.mem);
+ return NULL;
+ }
+
+ /*
+ * Fix up any link schemas so that their value implementations
+ * point to their target schemas' implementations.
+ */
+
+ avro_resolved_reader_calculate_size(result);
+ while (state.links != NULL) {
+ avro_resolved_link_reader_t *liface = state.links;
+ avro_resolved_reader_calculate_size(liface->target_resolver);
+ state.links = liface->next;
+ liface->next = NULL;
+ }
+
+ /*
+ * And now we can return.
+ */
+
+ avro_memoize_done(&state.mem);
+ return &result->parent;
+}
diff --git a/fluent-bit/lib/avro/src/resolved-writer.c b/fluent-bit/lib/avro/src/resolved-writer.c
new file mode 100644
index 000000000..0eafba00d
--- /dev/null
+++ b/fluent-bit/lib/avro/src/resolved-writer.c
@@ -0,0 +1,2911 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <avro/platform.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro_private.h"
+#include "avro/allocation.h"
+#include "avro/basics.h"
+#include "avro/data.h"
+#include "avro/errors.h"
+#include "avro/refcount.h"
+#include "avro/resolver.h"
+#include "avro/schema.h"
+#include "avro/value.h"
+#include "st.h"
+
+#ifndef AVRO_RESOLVER_DEBUG
+#define AVRO_RESOLVER_DEBUG 0
+#endif
+
+#if AVRO_RESOLVER_DEBUG
+#include <stdio.h>
+#define DEBUG(...) \
+ do { \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ } while (0)
+#else
+#define DEBUG(...) /* don't print messages */
+#endif
+
+
+typedef struct avro_resolved_writer avro_resolved_writer_t;
+
+struct avro_resolved_writer {
+ avro_value_iface_t parent;
+
+ /** The reference count for this interface. */
+ volatile int refcount;
+
+ /** The writer schema. */
+ avro_schema_t wschema;
+
+ /** The reader schema. */
+ avro_schema_t rschema;
+
+ /* If the reader schema is a union, but the writer schema is
+ * not, this field indicates which branch of the reader union
+ * should be selected. */
+ int reader_union_branch;
+
+ /* The size of the value instances for this resolver. */
+ size_t instance_size;
+
+ /* A function to calculate the instance size once the overall
+ * top-level resolver (and all of its children) have been
+ * constructed. */
+ void
+ (*calculate_size)(avro_resolved_writer_t *iface);
+
+ /* A free function for this resolver interface */
+ void
+ (*free_iface)(avro_resolved_writer_t *iface, st_table *freeing);
+
+ /* An initialization function for instances of this resolver. */
+ int
+ (*init)(const avro_resolved_writer_t *iface, void *self);
+
+ /* A finalization function for instances of this resolver. */
+ void
+ (*done)(const avro_resolved_writer_t *iface, void *self);
+
+ /* Clear out any existing wrappers, if any */
+ int
+ (*reset_wrappers)(const avro_resolved_writer_t *iface, void *self);
+};
+
+#define avro_resolved_writer_calculate_size(iface) \
+ do { \
+ if ((iface)->calculate_size != NULL) { \
+ (iface)->calculate_size((iface)); \
+ } \
+ } while (0)
+#define avro_resolved_writer_init(iface, self) \
+ ((iface)->init == NULL? 0: (iface)->init((iface), (self)))
+#define avro_resolved_writer_done(iface, self) \
+ ((iface)->done == NULL? (void) 0: (iface)->done((iface), (self)))
+#define avro_resolved_writer_reset_wrappers(iface, self) \
+ ((iface)->reset_wrappers == NULL? 0: \
+ (iface)->reset_wrappers((iface), (self)))
+
+
+/*
+ * We assume that each instance type in this value contains an an
+ * avro_value_t as its first element, which is the current wrapped
+ * value.
+ */
+
+void
+avro_resolved_writer_set_dest(avro_value_t *resolved,
+ avro_value_t *dest)
+{
+ avro_value_t *self = (avro_value_t *) resolved->self;
+ if (self->self != NULL) {
+ avro_value_decref(self);
+ }
+ avro_value_copy_ref(self, dest);
+}
+
+void
+avro_resolved_writer_clear_dest(avro_value_t *resolved)
+{
+ avro_value_t *self = (avro_value_t *) resolved->self;
+ if (self->self != NULL) {
+ avro_value_decref(self);
+ }
+ self->iface = NULL;
+ self->self = NULL;
+}
+
+int
+avro_resolved_writer_new_value(avro_value_iface_t *viface,
+ avro_value_t *value)
+{
+ int rval;
+ avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ void *self = avro_malloc(iface->instance_size + sizeof(volatile int));
+ if (self == NULL) {
+ value->iface = NULL;
+ value->self = NULL;
+ return ENOMEM;
+ }
+
+ memset(self, 0, iface->instance_size + sizeof(volatile int));
+ volatile int *refcount = (volatile int *) self;
+ self = (char *) self + sizeof(volatile int);
+
+ rval = avro_resolved_writer_init(iface, self);
+ if (rval != 0) {
+ avro_free(self, iface->instance_size + sizeof(volatile int));
+ value->iface = NULL;
+ value->self = NULL;
+ return rval;
+ }
+
+ *refcount = 1;
+ value->iface = avro_value_iface_incref(viface);
+ value->self = self;
+ return 0;
+}
+
+static void
+avro_resolved_writer_free_value(const avro_value_iface_t *viface, void *vself)
+{
+ avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+
+ avro_resolved_writer_done(iface, vself);
+ if (self->self != NULL) {
+ avro_value_decref(self);
+ }
+
+ vself = (char *) vself - sizeof(volatile int);
+ avro_free(vself, iface->instance_size + sizeof(volatile int));
+}
+
+static void
+avro_resolved_writer_incref(avro_value_t *value)
+{
+ /*
+ * This only works if you pass in the top-level value.
+ */
+
+ volatile int *refcount = (volatile int *) ((char *) value->self - sizeof(volatile int));
+ avro_refcount_inc(refcount);
+}
+
+static void
+avro_resolved_writer_decref(avro_value_t *value)
+{
+ /*
+ * This only works if you pass in the top-level value.
+ */
+
+ volatile int *refcount = (volatile int *) ((char *) value->self - sizeof(volatile int));
+ if (avro_refcount_dec(refcount)) {
+ avro_resolved_writer_free_value(value->iface, value->self);
+ }
+}
+
+
+static avro_value_iface_t *
+avro_resolved_writer_incref_iface(avro_value_iface_t *viface)
+{
+ avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_refcount_inc(&iface->refcount);
+ return viface;
+}
+
+static void
+free_resolver(avro_resolved_writer_t *iface, st_table *freeing)
+{
+ /* First check if we've already started freeing this resolver. */
+ if (st_lookup(freeing, (st_data_t) iface, NULL)) {
+ DEBUG("Already freed %p", iface);
+ return;
+ }
+
+ /* Otherwise add this resolver to the freeing set, then free it. */
+ st_insert(freeing, (st_data_t) iface, (st_data_t) NULL);
+ DEBUG("Freeing resolver %p (%s->%s)", iface,
+ avro_schema_type_name(iface->wschema),
+ avro_schema_type_name(iface->rschema));
+
+ iface->free_iface(iface, freeing);
+}
+
+static void
+avro_resolved_writer_calculate_size_(avro_resolved_writer_t *iface)
+{
+ /* Only calculate the size for any resolver once */
+ iface->calculate_size = NULL;
+
+ DEBUG("Calculating size for %s->%s",
+ avro_schema_type_name((iface)->wschema),
+ avro_schema_type_name((iface)->rschema));
+ iface->instance_size = sizeof(avro_value_t);
+}
+
+static void
+avro_resolved_writer_free_iface(avro_resolved_writer_t *iface, st_table *freeing)
+{
+ AVRO_UNUSED(freeing);
+ avro_schema_decref(iface->wschema);
+ avro_schema_decref(iface->rschema);
+ avro_freet(avro_resolved_writer_t, iface);
+}
+
+static void
+avro_resolved_writer_decref_iface(avro_value_iface_t *viface)
+{
+ avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ DEBUG("Decref resolver %p (before=%d)", iface, iface->refcount);
+ if (avro_refcount_dec(&iface->refcount)) {
+ avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+
+ st_table *freeing = st_init_numtable();
+ free_resolver(iface, freeing);
+ st_free_table(freeing);
+ }
+}
+
+
+static int
+avro_resolved_writer_reset(const avro_value_iface_t *viface, void *vself)
+{
+ /*
+ * To reset a wrapped value, we first clear out any wrappers,
+ * and then have the wrapped value reset itself.
+ */
+
+ int rval;
+ avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ check(rval, avro_resolved_writer_reset_wrappers(iface, vself));
+ return avro_value_reset(self);
+}
+
+static avro_type_t
+avro_resolved_writer_get_type(const avro_value_iface_t *viface, const void *vself)
+{
+ AVRO_UNUSED(vself);
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ return avro_typeof(iface->wschema);
+}
+
+static avro_schema_t
+avro_resolved_writer_get_schema(const avro_value_iface_t *viface, const void *vself)
+{
+ AVRO_UNUSED(vself);
+ avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ return iface->wschema;
+}
+
+
+static avro_resolved_writer_t *
+avro_resolved_writer_create(avro_schema_t wschema, avro_schema_t rschema)
+{
+ avro_resolved_writer_t *self = (avro_resolved_writer_t *) avro_new(avro_resolved_writer_t);
+ memset(self, 0, sizeof(avro_resolved_writer_t));
+
+ self->parent.incref_iface = avro_resolved_writer_incref_iface;
+ self->parent.decref_iface = avro_resolved_writer_decref_iface;
+ self->parent.incref = avro_resolved_writer_incref;
+ self->parent.decref = avro_resolved_writer_decref;
+ self->parent.reset = avro_resolved_writer_reset;
+ self->parent.get_type = avro_resolved_writer_get_type;
+ self->parent.get_schema = avro_resolved_writer_get_schema;
+
+ self->refcount = 1;
+ self->wschema = avro_schema_incref(wschema);
+ self->rschema = avro_schema_incref(rschema);
+ self->reader_union_branch = -1;
+ self->calculate_size = avro_resolved_writer_calculate_size_;
+ self->free_iface = avro_resolved_writer_free_iface;
+ self->reset_wrappers = NULL;
+ return self;
+}
+
+static inline int
+avro_resolved_writer_get_real_dest(const avro_resolved_writer_t *iface,
+ const avro_value_t *dest, avro_value_t *real_dest)
+{
+ if (iface->reader_union_branch < 0) {
+ /*
+ * The reader schema isn't a union, so use the dest
+ * field as-is.
+ */
+
+ *real_dest = *dest;
+ return 0;
+ }
+
+ DEBUG("Retrieving union branch %d for %s value",
+ iface->reader_union_branch,
+ avro_schema_type_name(iface->wschema));
+
+ return avro_value_set_branch(dest, iface->reader_union_branch, real_dest);
+}
+
+
+#define skip_links(schema) \
+ while (is_avro_link(schema)) { \
+ schema = avro_schema_link_target(schema); \
+ }
+
+
+/*-----------------------------------------------------------------------
+ * Memoized resolvers
+ */
+
+typedef struct avro_resolved_link_writer avro_resolved_link_writer_t;
+
+typedef struct memoize_state_t {
+ avro_memoize_t mem;
+ avro_resolved_link_writer_t *links;
+} memoize_state_t;
+
+static avro_resolved_writer_t *
+avro_resolved_writer_new_memoized(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema);
+
+
+/*-----------------------------------------------------------------------
+ * Reader unions
+ */
+
+/*
+ * For each Avro type, we have to check whether the reader schema on its
+ * own is compatible, and also whether the reader is a union that
+ * contains a compatible type. The macros in this section help us
+ * perform both of these checks with less code.
+ */
+
+
+/**
+ * A helper macro that handles the case where neither writer nor reader
+ * are unions. Uses @ref check_func to see if the two schemas are
+ * compatible.
+ */
+
+#define check_non_union(saved, wschema, rschema, check_func) \
+do { \
+ avro_resolved_writer_t *self = NULL; \
+ int rc = check_func(saved, &self, wschema, rschema, \
+ rschema); \
+ if (self) { \
+ DEBUG("Non-union schemas %s (writer) " \
+ "and %s (reader) match", \
+ avro_schema_type_name(wschema), \
+ avro_schema_type_name(rschema)); \
+ \
+ self->reader_union_branch = -1; \
+ return self; \
+ } \
+ \
+ if (rc) { \
+ return NULL; \
+ } \
+} while (0)
+
+
+/**
+ * Helper macro that handles the case where the reader is a union, and
+ * the writer is not. Checks each branch of the reader union schema,
+ * looking for the first branch that is compatible with the writer
+ * schema. The @ref check_func argument should be a function that can
+ * check the compatiblity of each branch schema.
+ */
+
+#define check_reader_union(saved, wschema, rschema, check_func) \
+do { \
+ if (!is_avro_union(rschema)) { \
+ break; \
+ } \
+ \
+ DEBUG("Checking reader union schema"); \
+ size_t num_branches = avro_schema_union_size(rschema); \
+ unsigned int i; \
+ \
+ for (i = 0; i < num_branches; i++) { \
+ avro_schema_t branch_schema = \
+ avro_schema_union_branch(rschema, i); \
+ skip_links(branch_schema); \
+ \
+ DEBUG("Trying branch %u %s%s%s->%s", i, \
+ is_avro_link(wschema)? "[": "", \
+ avro_schema_type_name(wschema), \
+ is_avro_link(wschema)? "]": "", \
+ avro_schema_type_name(branch_schema)); \
+ \
+ avro_resolved_writer_t *self = NULL; \
+ int rc = check_func(saved, &self, \
+ wschema, branch_schema, rschema); \
+ if (self) { \
+ DEBUG("Reader union branch %d (%s) " \
+ "and writer %s match", \
+ i, avro_schema_type_name(branch_schema), \
+ avro_schema_type_name(wschema)); \
+ self->reader_union_branch = i; \
+ return self; \
+ } else { \
+ DEBUG("Reader union branch %d (%s) " \
+ "doesn't match", \
+ i, avro_schema_type_name(branch_schema)); \
+ } \
+ \
+ if (rc) { \
+ return NULL; \
+ } \
+ } \
+ \
+ DEBUG("No reader union branches match"); \
+} while (0)
+
+/**
+ * A helper macro that wraps together check_non_union and
+ * check_reader_union for a simple (non-union) writer schema type.
+ */
+
+#define check_simple_writer(saved, wschema, rschema, type_name) \
+do { \
+ check_non_union(saved, wschema, rschema, try_##type_name); \
+ check_reader_union(saved, wschema, rschema, try_##type_name); \
+ DEBUG("Writer %s doesn't match reader %s", \
+ avro_schema_type_name(wschema), \
+ avro_schema_type_name(rschema)); \
+ avro_set_error("Cannot store " #type_name " into %s", \
+ avro_schema_type_name(rschema)); \
+ return NULL; \
+} while (0)
+
+
+/*-----------------------------------------------------------------------
+ * Recursive schemas
+ */
+
+/*
+ * Recursive schemas are handled specially; the value implementation for
+ * an AVRO_LINK schema is simply a wrapper around the value
+ * implementation for the link's target schema. The value methods all
+ * delegate to the wrapped implementation.
+ */
+
+struct avro_resolved_link_writer {
+ avro_resolved_writer_t parent;
+
+ /**
+ * A pointer to the “next” link resolver that we've had to
+ * create. We use this as we're creating the overall top-level
+ * resolver to keep track of which ones we have to fix up
+ * afterwards.
+ */
+ avro_resolved_link_writer_t *next;
+
+ /** The target's implementation. */
+ avro_resolved_writer_t *target_resolver;
+};
+
+typedef struct avro_resolved_link_value {
+ avro_value_t wrapped;
+ avro_value_t target;
+} avro_resolved_link_value_t;
+
+static void
+avro_resolved_link_writer_calculate_size(avro_resolved_writer_t *iface)
+{
+ /* Only calculate the size for any resolver once */
+ iface->calculate_size = NULL;
+
+ DEBUG("Calculating size for [%s]->%s",
+ avro_schema_type_name((iface)->wschema),
+ avro_schema_type_name((iface)->rschema));
+ iface->instance_size = sizeof(avro_resolved_link_value_t);
+}
+
+static void
+avro_resolved_link_writer_free_iface(avro_resolved_writer_t *iface, st_table *freeing)
+{
+ avro_resolved_link_writer_t *liface =
+ container_of(iface, avro_resolved_link_writer_t, parent);
+ if (liface->target_resolver != NULL) {
+ free_resolver(liface->target_resolver, freeing);
+ }
+ avro_schema_decref(iface->wschema);
+ avro_schema_decref(iface->rschema);
+ avro_freet(avro_resolved_link_writer_t, iface);
+}
+
+static int
+avro_resolved_link_writer_init(const avro_resolved_writer_t *iface, void *vself)
+{
+ int rval;
+ const avro_resolved_link_writer_t *liface =
+ container_of(iface, avro_resolved_link_writer_t, parent);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ size_t target_instance_size = liface->target_resolver->instance_size;
+
+ self->target.iface = &liface->target_resolver->parent;
+ self->target.self = avro_malloc(target_instance_size);
+ if (self->target.self == NULL) {
+ return ENOMEM;
+ }
+ DEBUG("Allocated <%p:%" PRIsz "> for link", self->target.self, target_instance_size);
+
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+
+ rval = avro_resolved_writer_init(liface->target_resolver, self->target.self);
+ if (rval != 0) {
+ avro_free(self->target.self, target_instance_size);
+ }
+ return rval;
+}
+
+static void
+avro_resolved_link_writer_done(const avro_resolved_writer_t *iface, void *vself)
+{
+ const avro_resolved_link_writer_t *liface =
+ container_of(iface, avro_resolved_link_writer_t, parent);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ size_t target_instance_size = liface->target_resolver->instance_size;
+ DEBUG("Freeing <%p:%" PRIsz "> for link", self->target.self, target_instance_size);
+ avro_resolved_writer_done(liface->target_resolver, self->target.self);
+ avro_free(self->target.self, target_instance_size);
+ self->target.iface = NULL;
+ self->target.self = NULL;
+}
+
+static int
+avro_resolved_link_writer_reset(const avro_resolved_writer_t *iface, void *vself)
+{
+ const avro_resolved_link_writer_t *liface =
+ container_of(iface, avro_resolved_link_writer_t, parent);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ return avro_resolved_writer_reset_wrappers
+ (liface->target_resolver, self->target.self);
+}
+
+static avro_type_t
+avro_resolved_link_writer_get_type(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_type(&self->target);
+}
+
+static avro_schema_t
+avro_resolved_link_writer_get_schema(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_schema(&self->target);
+}
+
+static int
+avro_resolved_link_writer_get_boolean(const avro_value_iface_t *iface,
+ const void *vself, int *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_boolean(&self->target, out);
+}
+
+static int
+avro_resolved_link_writer_get_bytes(const avro_value_iface_t *iface,
+ const void *vself, const void **buf, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_bytes(&self->target, buf, size);
+}
+
+static int
+avro_resolved_link_writer_grab_bytes(const avro_value_iface_t *iface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_grab_bytes(&self->target, dest);
+}
+
+static int
+avro_resolved_link_writer_get_double(const avro_value_iface_t *iface,
+ const void *vself, double *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_double(&self->target, out);
+}
+
+static int
+avro_resolved_link_writer_get_float(const avro_value_iface_t *iface,
+ const void *vself, float *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_float(&self->target, out);
+}
+
+static int
+avro_resolved_link_writer_get_int(const avro_value_iface_t *iface,
+ const void *vself, int32_t *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_int(&self->target, out);
+}
+
+static int
+avro_resolved_link_writer_get_long(const avro_value_iface_t *iface,
+ const void *vself, int64_t *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_long(&self->target, out);
+}
+
+static int
+avro_resolved_link_writer_get_null(const avro_value_iface_t *iface, const void *vself)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_null(&self->target);
+}
+
+static int
+avro_resolved_link_writer_get_string(const avro_value_iface_t *iface,
+ const void *vself, const char **str, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_string(&self->target, str, size);
+}
+
+static int
+avro_resolved_link_writer_grab_string(const avro_value_iface_t *iface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_grab_string(&self->target, dest);
+}
+
+static int
+avro_resolved_link_writer_get_enum(const avro_value_iface_t *iface,
+ const void *vself, int *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_enum(&self->target, out);
+}
+
+static int
+avro_resolved_link_writer_get_fixed(const avro_value_iface_t *iface,
+ const void *vself, const void **buf, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_fixed(&self->target, buf, size);
+}
+
+static int
+avro_resolved_link_writer_grab_fixed(const avro_value_iface_t *iface,
+ const void *vself, avro_wrapped_buffer_t *dest)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_grab_fixed(&self->target, dest);
+}
+
+static int
+avro_resolved_link_writer_set_boolean(const avro_value_iface_t *iface,
+ void *vself, int val)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_boolean(&self->target, val);
+}
+
+static int
+avro_resolved_link_writer_set_bytes(const avro_value_iface_t *iface,
+ void *vself, void *buf, size_t size)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_bytes(&self->target, buf, size);
+}
+
+static int
+avro_resolved_link_writer_give_bytes(const avro_value_iface_t *iface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_give_bytes(&self->target, buf);
+}
+
+static int
+avro_resolved_link_writer_set_double(const avro_value_iface_t *iface,
+ void *vself, double val)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_double(&self->target, val);
+}
+
+static int
+avro_resolved_link_writer_set_float(const avro_value_iface_t *iface,
+ void *vself, float val)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_float(&self->target, val);
+}
+
+static int
+avro_resolved_link_writer_set_int(const avro_value_iface_t *iface,
+ void *vself, int32_t val)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_int(&self->target, val);
+}
+
+static int
+avro_resolved_link_writer_set_long(const avro_value_iface_t *iface,
+ void *vself, int64_t val)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_long(&self->target, val);
+}
+
+static int
+avro_resolved_link_writer_set_null(const avro_value_iface_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_null(&self->target);
+}
+
+static int
+avro_resolved_link_writer_set_string(const avro_value_iface_t *iface,
+ void *vself, const char *str)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_string(&self->target, str);
+}
+
+static int
+avro_resolved_link_writer_set_string_len(const avro_value_iface_t *iface,
+ void *vself, const char *str, size_t size)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_string_len(&self->target, str, size);
+}
+
+static int
+avro_resolved_link_writer_give_string_len(const avro_value_iface_t *iface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_give_string_len(&self->target, buf);
+}
+
+static int
+avro_resolved_link_writer_set_enum(const avro_value_iface_t *iface,
+ void *vself, int val)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_enum(&self->target, val);
+}
+
+static int
+avro_resolved_link_writer_set_fixed(const avro_value_iface_t *iface,
+ void *vself, void *buf, size_t size)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_fixed(&self->target, buf, size);
+}
+
+static int
+avro_resolved_link_writer_give_fixed(const avro_value_iface_t *iface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_give_fixed(&self->target, buf);
+}
+
+static int
+avro_resolved_link_writer_get_size(const avro_value_iface_t *iface,
+ const void *vself, size_t *size)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_size(&self->target, size);
+}
+
+static int
+avro_resolved_link_writer_get_by_index(const avro_value_iface_t *iface,
+ const void *vself, size_t index,
+ avro_value_t *child, const char **name)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_by_index(&self->target, index, child, name);
+}
+
+static int
+avro_resolved_link_writer_get_by_name(const avro_value_iface_t *iface,
+ const void *vself, const char *name,
+ avro_value_t *child, size_t *index)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_by_name(&self->target, name, child, index);
+}
+
+static int
+avro_resolved_link_writer_get_discriminant(const avro_value_iface_t *iface,
+ const void *vself, int *out)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_discriminant(&self->target, out);
+}
+
+static int
+avro_resolved_link_writer_get_current_branch(const avro_value_iface_t *iface,
+ const void *vself, avro_value_t *branch)
+{
+ AVRO_UNUSED(iface);
+ const avro_resolved_link_value_t *self = (const avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_get_current_branch(&self->target, branch);
+}
+
+static int
+avro_resolved_link_writer_append(const avro_value_iface_t *iface,
+ void *vself, avro_value_t *child_out,
+ size_t *new_index)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_append(&self->target, child_out, new_index);
+}
+
+static int
+avro_resolved_link_writer_add(const avro_value_iface_t *iface,
+ void *vself, const char *key,
+ avro_value_t *child, size_t *index, int *is_new)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_add(&self->target, key, child, index, is_new);
+}
+
+static int
+avro_resolved_link_writer_set_branch(const avro_value_iface_t *iface,
+ void *vself, int discriminant,
+ avro_value_t *branch)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_link_value_t *self = (avro_resolved_link_value_t *) vself;
+ avro_value_t *target_vself = (avro_value_t *) self->target.self;
+ *target_vself = self->wrapped;
+ return avro_value_set_branch(&self->target, discriminant, branch);
+}
+
+static avro_resolved_link_writer_t *
+avro_resolved_link_writer_create(avro_schema_t wschema, avro_schema_t rschema)
+{
+ avro_resolved_writer_t *self = (avro_resolved_writer_t *) avro_new(avro_resolved_link_writer_t);
+ memset(self, 0, sizeof(avro_resolved_link_writer_t));
+
+ self->parent.incref_iface = avro_resolved_writer_incref_iface;
+ self->parent.decref_iface = avro_resolved_writer_decref_iface;
+ self->parent.incref = avro_resolved_writer_incref;
+ self->parent.decref = avro_resolved_writer_decref;
+ self->parent.reset = avro_resolved_writer_reset;
+ self->parent.get_type = avro_resolved_link_writer_get_type;
+ self->parent.get_schema = avro_resolved_link_writer_get_schema;
+ self->parent.get_size = avro_resolved_link_writer_get_size;
+ self->parent.get_by_index = avro_resolved_link_writer_get_by_index;
+ self->parent.get_by_name = avro_resolved_link_writer_get_by_name;
+
+ self->refcount = 1;
+ self->wschema = avro_schema_incref(wschema);
+ self->rschema = avro_schema_incref(rschema);
+ self->reader_union_branch = -1;
+ self->calculate_size = avro_resolved_link_writer_calculate_size;
+ self->free_iface = avro_resolved_link_writer_free_iface;
+ self->init = avro_resolved_link_writer_init;
+ self->done = avro_resolved_link_writer_done;
+ self->reset_wrappers = avro_resolved_link_writer_reset;
+
+ self->parent.get_boolean = avro_resolved_link_writer_get_boolean;
+ self->parent.get_bytes = avro_resolved_link_writer_get_bytes;
+ self->parent.grab_bytes = avro_resolved_link_writer_grab_bytes;
+ self->parent.get_double = avro_resolved_link_writer_get_double;
+ self->parent.get_float = avro_resolved_link_writer_get_float;
+ self->parent.get_int = avro_resolved_link_writer_get_int;
+ self->parent.get_long = avro_resolved_link_writer_get_long;
+ self->parent.get_null = avro_resolved_link_writer_get_null;
+ self->parent.get_string = avro_resolved_link_writer_get_string;
+ self->parent.grab_string = avro_resolved_link_writer_grab_string;
+ self->parent.get_enum = avro_resolved_link_writer_get_enum;
+ self->parent.get_fixed = avro_resolved_link_writer_get_fixed;
+ self->parent.grab_fixed = avro_resolved_link_writer_grab_fixed;
+
+ self->parent.set_boolean = avro_resolved_link_writer_set_boolean;
+ self->parent.set_bytes = avro_resolved_link_writer_set_bytes;
+ self->parent.give_bytes = avro_resolved_link_writer_give_bytes;
+ self->parent.set_double = avro_resolved_link_writer_set_double;
+ self->parent.set_float = avro_resolved_link_writer_set_float;
+ self->parent.set_int = avro_resolved_link_writer_set_int;
+ self->parent.set_long = avro_resolved_link_writer_set_long;
+ self->parent.set_null = avro_resolved_link_writer_set_null;
+ self->parent.set_string = avro_resolved_link_writer_set_string;
+ self->parent.set_string_len = avro_resolved_link_writer_set_string_len;
+ self->parent.give_string_len = avro_resolved_link_writer_give_string_len;
+ self->parent.set_enum = avro_resolved_link_writer_set_enum;
+ self->parent.set_fixed = avro_resolved_link_writer_set_fixed;
+ self->parent.give_fixed = avro_resolved_link_writer_give_fixed;
+
+ self->parent.get_size = avro_resolved_link_writer_get_size;
+ self->parent.get_by_index = avro_resolved_link_writer_get_by_index;
+ self->parent.get_by_name = avro_resolved_link_writer_get_by_name;
+ self->parent.get_discriminant = avro_resolved_link_writer_get_discriminant;
+ self->parent.get_current_branch = avro_resolved_link_writer_get_current_branch;
+
+ self->parent.append = avro_resolved_link_writer_append;
+ self->parent.add = avro_resolved_link_writer_add;
+ self->parent.set_branch = avro_resolved_link_writer_set_branch;
+
+ return container_of(self, avro_resolved_link_writer_t, parent);
+}
+
+static int
+try_link(memoize_state_t *state, avro_resolved_writer_t **self,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ AVRO_UNUSED(rschema);
+
+ /*
+ * For link schemas, we create a special value implementation
+ * that allocates space for its wrapped value at runtime. This
+ * lets us handle recursive types without having to instantiate
+ * in infinite-size value.
+ */
+
+ avro_schema_t wtarget = avro_schema_link_target(wschema);
+ avro_resolved_link_writer_t *lself =
+ avro_resolved_link_writer_create(wtarget, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, lself);
+
+ avro_resolved_writer_t *target_resolver =
+ avro_resolved_writer_new_memoized(state, wtarget, rschema);
+ if (target_resolver == NULL) {
+ avro_memoize_delete(&state->mem, wschema, root_rschema);
+ avro_value_iface_decref(&lself->parent.parent);
+ avro_prefix_error("Link target isn't compatible: ");
+ DEBUG("%s", avro_strerror());
+ return EINVAL;
+ }
+
+ lself->target_resolver = target_resolver;
+ lself->next = state->links;
+ state->links = lself;
+
+ *self = &lself->parent;
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * boolean
+ */
+
+static int
+avro_resolved_writer_set_boolean(const avro_value_iface_t *viface,
+ void *vself, int val)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Storing %s into %p", val? "TRUE": "FALSE", dest.self);
+ return avro_value_set_boolean(&dest, val);
+}
+
+static int
+try_boolean(memoize_state_t *state, avro_resolved_writer_t **self,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ if (is_avro_boolean(rschema)) {
+ *self = avro_resolved_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, *self);
+ (*self)->parent.set_boolean = avro_resolved_writer_set_boolean;
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * bytes
+ */
+
+static int
+avro_resolved_writer_set_bytes(const avro_value_iface_t *viface,
+ void *vself, void *buf, size_t size)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Storing <%p:%" PRIsz "> into %p", buf, size, dest.self);
+ return avro_value_set_bytes(&dest, buf, size);
+}
+
+static int
+avro_resolved_writer_give_bytes(const avro_value_iface_t *viface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Storing [%p] into %p", buf, dest.self);
+ return avro_value_give_bytes(&dest, buf);
+}
+
+static int
+try_bytes(memoize_state_t *state, avro_resolved_writer_t **self,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ if (is_avro_bytes(rschema)) {
+ *self = avro_resolved_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, *self);
+ (*self)->parent.set_bytes = avro_resolved_writer_set_bytes;
+ (*self)->parent.give_bytes = avro_resolved_writer_give_bytes;
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * double
+ */
+
+static int
+avro_resolved_writer_set_double(const avro_value_iface_t *viface,
+ void *vself, double val)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Storing %le into %p", val, dest.self);
+ return avro_value_set_double(&dest, val);
+}
+
+static int
+try_double(memoize_state_t *state, avro_resolved_writer_t **self,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ if (is_avro_double(rschema)) {
+ *self = avro_resolved_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, *self);
+ (*self)->parent.set_double = avro_resolved_writer_set_double;
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * float
+ */
+
+static int
+avro_resolved_writer_set_float(const avro_value_iface_t *viface,
+ void *vself, float val)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Storing %e into %p", val, dest.self);
+ return avro_value_set_float(&dest, val);
+}
+
+static int
+avro_resolved_writer_set_float_double(const avro_value_iface_t *viface,
+ void *vself, float val)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Promoting float %e into double %p", val, dest.self);
+ return avro_value_set_double(&dest, val);
+}
+
+static int
+try_float(memoize_state_t *state, avro_resolved_writer_t **self,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ if (is_avro_float(rschema)) {
+ *self = avro_resolved_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, *self);
+ (*self)->parent.set_float = avro_resolved_writer_set_float;
+ }
+
+ else if (is_avro_double(rschema)) {
+ *self = avro_resolved_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, *self);
+ (*self)->parent.set_float = avro_resolved_writer_set_float_double;
+ }
+
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * int
+ */
+
+static int
+avro_resolved_writer_set_int(const avro_value_iface_t *viface,
+ void *vself, int32_t val)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Storing %" PRId32 " into %p", val, dest.self);
+ return avro_value_set_int(&dest, val);
+}
+
+static int
+avro_resolved_writer_set_int_double(const avro_value_iface_t *viface,
+ void *vself, int32_t val)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Promoting int %" PRId32 " into double %p", val, dest.self);
+ return avro_value_set_double(&dest, val);
+}
+
+static int
+avro_resolved_writer_set_int_float(const avro_value_iface_t *viface,
+ void *vself, int32_t val)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Promoting int %" PRId32 " into float %p", val, dest.self);
+ return avro_value_set_float(&dest, (float) val);
+}
+
+static int
+avro_resolved_writer_set_int_long(const avro_value_iface_t *viface,
+ void *vself, int32_t val)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Promoting int %" PRId32 " into long %p", val, dest.self);
+ return avro_value_set_long(&dest, val);
+}
+
+static int
+try_int(memoize_state_t *state, avro_resolved_writer_t **self,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ if (is_avro_int32(rschema)) {
+ *self = avro_resolved_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, *self);
+ (*self)->parent.set_int = avro_resolved_writer_set_int;
+ }
+
+ else if (is_avro_int64(rschema)) {
+ *self = avro_resolved_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, *self);
+ (*self)->parent.set_int = avro_resolved_writer_set_int_long;
+ }
+
+ else if (is_avro_double(rschema)) {
+ *self = avro_resolved_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, *self);
+ (*self)->parent.set_int = avro_resolved_writer_set_int_double;
+ }
+
+ else if (is_avro_float(rschema)) {
+ *self = avro_resolved_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, *self);
+ (*self)->parent.set_int = avro_resolved_writer_set_int_float;
+ }
+
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * long
+ */
+
+static int
+avro_resolved_writer_set_long(const avro_value_iface_t *viface,
+ void *vself, int64_t val)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Storing %" PRId64 " into %p", val, dest.self);
+ return avro_value_set_long(&dest, val);
+}
+
+static int
+avro_resolved_writer_set_long_double(const avro_value_iface_t *viface,
+ void *vself, int64_t val)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Promoting long %" PRId64 " into double %p", val, dest.self);
+ return avro_value_set_double(&dest, (double) val);
+}
+
+static int
+avro_resolved_writer_set_long_float(const avro_value_iface_t *viface,
+ void *vself, int64_t val)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Promoting long %" PRId64 " into float %p", val, dest.self);
+ return avro_value_set_float(&dest, (float) val);
+}
+
+static int
+try_long(memoize_state_t *state, avro_resolved_writer_t **self,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ if (is_avro_int64(rschema)) {
+ *self = avro_resolved_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, *self);
+ (*self)->parent.set_long = avro_resolved_writer_set_long;
+ }
+
+ else if (is_avro_double(rschema)) {
+ *self = avro_resolved_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, *self);
+ (*self)->parent.set_long = avro_resolved_writer_set_long_double;
+ }
+
+ else if (is_avro_float(rschema)) {
+ *self = avro_resolved_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, *self);
+ (*self)->parent.set_long = avro_resolved_writer_set_long_float;
+ }
+
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * null
+ */
+
+static int
+avro_resolved_writer_set_null(const avro_value_iface_t *viface,
+ void *vself)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Storing NULL into %p", dest.self);
+ return avro_value_set_null(&dest);
+}
+
+static int
+try_null(memoize_state_t *state, avro_resolved_writer_t **self,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ if (is_avro_null(rschema)) {
+ *self = avro_resolved_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, *self);
+ (*self)->parent.set_null = avro_resolved_writer_set_null;
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * string
+ */
+
+static int
+avro_resolved_writer_set_string(const avro_value_iface_t *viface,
+ void *vself, const char *str)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Storing \"%s\" into %p", str, dest.self);
+ return avro_value_set_string(&dest, str);
+}
+
+static int
+avro_resolved_writer_set_string_len(const avro_value_iface_t *viface,
+ void *vself, const char *str, size_t size)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Storing <%p:%" PRIsz "> into %p", str, size, dest.self);
+ return avro_value_set_string_len(&dest, str, size);
+}
+
+static int
+avro_resolved_writer_give_string_len(const avro_value_iface_t *viface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Storing [%p] into %p", buf, dest.self);
+ return avro_value_give_string_len(&dest, buf);
+}
+
+static int
+try_string(memoize_state_t *state, avro_resolved_writer_t **self,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ if (is_avro_string(rschema)) {
+ *self = avro_resolved_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, *self);
+ (*self)->parent.set_string = avro_resolved_writer_set_string;
+ (*self)->parent.set_string_len = avro_resolved_writer_set_string_len;
+ (*self)->parent.give_string_len = avro_resolved_writer_give_string_len;
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * array
+ */
+
+typedef struct avro_resolved_array_writer {
+ avro_resolved_writer_t parent;
+ avro_resolved_writer_t *child_resolver;
+} avro_resolved_array_writer_t;
+
+typedef struct avro_resolved_array_value {
+ avro_value_t wrapped;
+ avro_raw_array_t children;
+} avro_resolved_array_value_t;
+
+static void
+avro_resolved_array_writer_calculate_size(avro_resolved_writer_t *iface)
+{
+ avro_resolved_array_writer_t *aiface =
+ container_of(iface, avro_resolved_array_writer_t, parent);
+
+ /* Only calculate the size for any resolver once */
+ iface->calculate_size = NULL;
+
+ DEBUG("Calculating size for %s->%s",
+ avro_schema_type_name((iface)->wschema),
+ avro_schema_type_name((iface)->rschema));
+ iface->instance_size = sizeof(avro_resolved_array_value_t);
+
+ avro_resolved_writer_calculate_size(aiface->child_resolver);
+}
+
+static void
+avro_resolved_array_writer_free_iface(avro_resolved_writer_t *iface, st_table *freeing)
+{
+ avro_resolved_array_writer_t *aiface =
+ container_of(iface, avro_resolved_array_writer_t, parent);
+ free_resolver(aiface->child_resolver, freeing);
+ avro_schema_decref(iface->wschema);
+ avro_schema_decref(iface->rschema);
+ avro_freet(avro_resolved_array_writer_t, iface);
+}
+
+static int
+avro_resolved_array_writer_init(const avro_resolved_writer_t *iface, void *vself)
+{
+ const avro_resolved_array_writer_t *aiface =
+ container_of(iface, avro_resolved_array_writer_t, parent);
+ avro_resolved_array_value_t *self = (avro_resolved_array_value_t *) vself;
+ size_t child_instance_size = aiface->child_resolver->instance_size;
+ DEBUG("Initializing child array (child_size=%" PRIsz ")", child_instance_size);
+ avro_raw_array_init(&self->children, child_instance_size);
+ return 0;
+}
+
+static void
+avro_resolved_array_writer_free_elements(const avro_resolved_writer_t *child_iface,
+ avro_resolved_array_value_t *self)
+{
+ size_t i;
+ for (i = 0; i < avro_raw_array_size(&self->children); i++) {
+ void *child_self = avro_raw_array_get_raw(&self->children, i);
+ avro_resolved_writer_done(child_iface, child_self);
+ }
+}
+
+static void
+avro_resolved_array_writer_done(const avro_resolved_writer_t *iface, void *vself)
+{
+ const avro_resolved_array_writer_t *aiface =
+ container_of(iface, avro_resolved_array_writer_t, parent);
+ avro_resolved_array_value_t *self = (avro_resolved_array_value_t *) vself;
+ avro_resolved_array_writer_free_elements(aiface->child_resolver, self);
+ avro_raw_array_done(&self->children);
+}
+
+static int
+avro_resolved_array_writer_reset(const avro_resolved_writer_t *iface, void *vself)
+{
+ const avro_resolved_array_writer_t *aiface =
+ container_of(iface, avro_resolved_array_writer_t, parent);
+ avro_resolved_array_value_t *self = (avro_resolved_array_value_t *) vself;
+
+ /* Clear out our cache of wrapped children */
+ avro_resolved_array_writer_free_elements(aiface->child_resolver, self);
+ avro_raw_array_clear(&self->children);
+ return 0;
+}
+
+static int
+avro_resolved_array_writer_get_size(const avro_value_iface_t *viface,
+ const void *vself, size_t *size)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ const avro_resolved_array_value_t *self = (const avro_resolved_array_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, &self->wrapped, &dest));
+ return avro_value_get_size(&dest, size);
+}
+
+static int
+avro_resolved_array_writer_append(const avro_value_iface_t *viface,
+ void *vself, avro_value_t *child_out,
+ size_t *new_index)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ const avro_resolved_array_writer_t *aiface =
+ container_of(iface, avro_resolved_array_writer_t, parent);
+ avro_resolved_array_value_t *self = (avro_resolved_array_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, &self->wrapped, &dest));
+
+ child_out->iface = &aiface->child_resolver->parent;
+ child_out->self = avro_raw_array_append(&self->children);
+ if (child_out->self == NULL) {
+ avro_set_error("Couldn't expand array");
+ return ENOMEM;
+ }
+
+ DEBUG("Appending to array %p", dest.self);
+ check(rval, avro_value_append(&dest, (avro_value_t *) child_out->self, new_index));
+ return avro_resolved_writer_init(aiface->child_resolver, child_out->self);
+}
+
+static avro_resolved_array_writer_t *
+avro_resolved_array_writer_create(avro_schema_t wschema, avro_schema_t rschema)
+{
+ avro_resolved_writer_t *self = (avro_resolved_writer_t *) avro_new(avro_resolved_array_writer_t);
+ memset(self, 0, sizeof(avro_resolved_array_writer_t));
+
+ self->parent.incref_iface = avro_resolved_writer_incref_iface;
+ self->parent.decref_iface = avro_resolved_writer_decref_iface;
+ self->parent.incref = avro_resolved_writer_incref;
+ self->parent.decref = avro_resolved_writer_decref;
+ self->parent.reset = avro_resolved_writer_reset;
+ self->parent.get_type = avro_resolved_writer_get_type;
+ self->parent.get_schema = avro_resolved_writer_get_schema;
+ self->parent.get_size = avro_resolved_array_writer_get_size;
+ self->parent.append = avro_resolved_array_writer_append;
+
+ self->refcount = 1;
+ self->wschema = avro_schema_incref(wschema);
+ self->rschema = avro_schema_incref(rschema);
+ self->reader_union_branch = -1;
+ self->calculate_size = avro_resolved_array_writer_calculate_size;
+ self->free_iface = avro_resolved_array_writer_free_iface;
+ self->init = avro_resolved_array_writer_init;
+ self->done = avro_resolved_array_writer_done;
+ self->reset_wrappers = avro_resolved_array_writer_reset;
+ return container_of(self, avro_resolved_array_writer_t, parent);
+}
+
+static int
+try_array(memoize_state_t *state, avro_resolved_writer_t **self,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ /*
+ * First verify that the reader is an array.
+ */
+
+ if (!is_avro_array(rschema)) {
+ return 0;
+ }
+
+ /*
+ * Array schemas have to have compatible element schemas to be
+ * compatible themselves. Try to create an resolver to check
+ * the compatibility.
+ */
+
+ avro_resolved_array_writer_t *aself =
+ avro_resolved_array_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, aself);
+
+ avro_schema_t witems = avro_schema_array_items(wschema);
+ avro_schema_t ritems = avro_schema_array_items(rschema);
+
+ avro_resolved_writer_t *item_resolver =
+ avro_resolved_writer_new_memoized(state, witems, ritems);
+ if (item_resolver == NULL) {
+ avro_memoize_delete(&state->mem, wschema, root_rschema);
+ avro_value_iface_decref(&aself->parent.parent);
+ avro_prefix_error("Array values aren't compatible: ");
+ return EINVAL;
+ }
+
+ /*
+ * The two schemas are compatible. Store the item schema's
+ * resolver into the child_resolver field.
+ */
+
+ aself->child_resolver = item_resolver;
+ *self = &aself->parent;
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * enum
+ */
+
+static int
+avro_resolved_writer_set_enum(const avro_value_iface_t *viface,
+ void *vself, int val)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Storing %d into %p", val, dest.self);
+ return avro_value_set_enum(&dest, val);
+}
+
+static int
+try_enum(memoize_state_t *state, avro_resolved_writer_t **self,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ /*
+ * Enum schemas have to have the same name — but not the same
+ * list of symbols — to be compatible.
+ */
+
+ if (is_avro_enum(rschema)) {
+ const char *wname = avro_schema_name(wschema);
+ const char *rname = avro_schema_name(rschema);
+
+ if (strcmp(wname, rname) == 0) {
+ *self = avro_resolved_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, *self);
+ (*self)->parent.set_enum = avro_resolved_writer_set_enum;
+ }
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * fixed
+ */
+
+static int
+avro_resolved_writer_set_fixed(const avro_value_iface_t *viface,
+ void *vself, void *buf, size_t size)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Storing <%p:%" PRIsz "> into (fixed) %p", buf, size, dest.self);
+ return avro_value_set_fixed(&dest, buf, size);
+}
+
+static int
+avro_resolved_writer_give_fixed(const avro_value_iface_t *viface,
+ void *vself, avro_wrapped_buffer_t *buf)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ avro_value_t *self = (avro_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, self, &dest));
+ DEBUG("Storing [%p] into (fixed) %p", buf, dest.self);
+ return avro_value_give_fixed(&dest, buf);
+}
+
+static int
+try_fixed(memoize_state_t *state, avro_resolved_writer_t **self,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ /*
+ * Fixed schemas need the same name and size to be compatible.
+ */
+
+ if (avro_schema_equal(wschema, rschema)) {
+ *self = avro_resolved_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, *self);
+ (*self)->parent.set_fixed = avro_resolved_writer_set_fixed;
+ (*self)->parent.give_fixed = avro_resolved_writer_give_fixed;
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * map
+ */
+
+typedef struct avro_resolved_map_writer {
+ avro_resolved_writer_t parent;
+ avro_resolved_writer_t *child_resolver;
+} avro_resolved_map_writer_t;
+
+typedef struct avro_resolved_map_value {
+ avro_value_t wrapped;
+ avro_raw_array_t children;
+} avro_resolved_map_value_t;
+
+static void
+avro_resolved_map_writer_calculate_size(avro_resolved_writer_t *iface)
+{
+ avro_resolved_map_writer_t *miface =
+ container_of(iface, avro_resolved_map_writer_t, parent);
+
+ /* Only calculate the size for any resolver once */
+ iface->calculate_size = NULL;
+
+ DEBUG("Calculating size for %s->%s",
+ avro_schema_type_name((iface)->wschema),
+ avro_schema_type_name((iface)->rschema));
+ iface->instance_size = sizeof(avro_resolved_map_value_t);
+
+ avro_resolved_writer_calculate_size(miface->child_resolver);
+}
+
+static void
+avro_resolved_map_writer_free_iface(avro_resolved_writer_t *iface, st_table *freeing)
+{
+ avro_resolved_map_writer_t *miface =
+ container_of(iface, avro_resolved_map_writer_t, parent);
+ free_resolver(miface->child_resolver, freeing);
+ avro_schema_decref(iface->wschema);
+ avro_schema_decref(iface->rschema);
+ avro_freet(avro_resolved_map_writer_t, iface);
+}
+
+static int
+avro_resolved_map_writer_init(const avro_resolved_writer_t *iface, void *vself)
+{
+ const avro_resolved_map_writer_t *miface =
+ container_of(iface, avro_resolved_map_writer_t, parent);
+ avro_resolved_map_value_t *self = (avro_resolved_map_value_t *) vself;
+ size_t child_instance_size = miface->child_resolver->instance_size;
+ DEBUG("Initializing child array for map (child_size=%" PRIsz ")", child_instance_size);
+ avro_raw_array_init(&self->children, child_instance_size);
+ return 0;
+}
+
+static void
+avro_resolved_map_writer_free_elements(const avro_resolved_writer_t *child_iface,
+ avro_resolved_map_value_t *self)
+{
+ size_t i;
+ for (i = 0; i < avro_raw_array_size(&self->children); i++) {
+ void *child_self = avro_raw_array_get_raw(&self->children, i);
+ avro_resolved_writer_done(child_iface, child_self);
+ }
+}
+
+static void
+avro_resolved_map_writer_done(const avro_resolved_writer_t *iface, void *vself)
+{
+ const avro_resolved_map_writer_t *miface =
+ container_of(iface, avro_resolved_map_writer_t, parent);
+ avro_resolved_map_value_t *self = (avro_resolved_map_value_t *) vself;
+ avro_resolved_map_writer_free_elements(miface->child_resolver, self);
+ avro_raw_array_done(&self->children);
+}
+
+static int
+avro_resolved_map_writer_reset(const avro_resolved_writer_t *iface, void *vself)
+{
+ const avro_resolved_map_writer_t *miface =
+ container_of(iface, avro_resolved_map_writer_t, parent);
+ avro_resolved_map_value_t *self = (avro_resolved_map_value_t *) vself;
+
+ /* Clear out our cache of wrapped children */
+ avro_resolved_map_writer_free_elements(miface->child_resolver, self);
+ return 0;
+}
+
+static int
+avro_resolved_map_writer_get_size(const avro_value_iface_t *viface,
+ const void *vself, size_t *size)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ const avro_resolved_map_value_t *self = (const avro_resolved_map_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, &self->wrapped, &dest));
+ return avro_value_get_size(&dest, size);
+}
+
+static int
+avro_resolved_map_writer_add(const avro_value_iface_t *viface,
+ void *vself, const char *key,
+ avro_value_t *child, size_t *index, int *is_new)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ const avro_resolved_map_writer_t *miface =
+ container_of(iface, avro_resolved_map_writer_t, parent);
+ avro_resolved_map_value_t *self = (avro_resolved_map_value_t *) vself;
+ avro_value_t dest;
+ check(rval, avro_resolved_writer_get_real_dest(iface, &self->wrapped, &dest));
+
+ /*
+ * This is a bit convoluted. We need to stash the wrapped child
+ * value somewhere in our children array. But we don't know
+ * where to put it until the wrapped map tells us whether this
+ * is a new value, and if not, which index the value should go
+ * in.
+ */
+
+ avro_value_t real_child;
+ size_t real_index;
+ int real_is_new;
+
+ DEBUG("Adding %s to map %p", key, dest.self);
+ check(rval, avro_value_add(&dest, key, &real_child, &real_index, &real_is_new));
+
+ child->iface = &miface->child_resolver->parent;
+ if (real_is_new) {
+ child->self = avro_raw_array_append(&self->children);
+ DEBUG("Element is new (child resolver=%p)", child->self);
+ if (child->self == NULL) {
+ avro_set_error("Couldn't expand map");
+ return ENOMEM;
+ }
+ check(rval, avro_resolved_writer_init
+ (miface->child_resolver, child->self));
+ } else {
+ child->self = avro_raw_array_get_raw(&self->children, real_index);
+ DEBUG("Element is old (child resolver=%p)", child->self);
+ }
+ avro_value_t *child_vself = (avro_value_t *) child->self;
+ *child_vself = real_child;
+
+ if (index != NULL) {
+ *index = real_index;
+ }
+ if (is_new != NULL) {
+ *is_new = real_is_new;
+ }
+ return 0;
+}
+
+static avro_resolved_map_writer_t *
+avro_resolved_map_writer_create(avro_schema_t wschema, avro_schema_t rschema)
+{
+ avro_resolved_writer_t *self = (avro_resolved_writer_t *) avro_new(avro_resolved_map_writer_t);
+ memset(self, 0, sizeof(avro_resolved_map_writer_t));
+
+ self->parent.incref_iface = avro_resolved_writer_incref_iface;
+ self->parent.decref_iface = avro_resolved_writer_decref_iface;
+ self->parent.incref = avro_resolved_writer_incref;
+ self->parent.decref = avro_resolved_writer_decref;
+ self->parent.reset = avro_resolved_writer_reset;
+ self->parent.get_type = avro_resolved_writer_get_type;
+ self->parent.get_schema = avro_resolved_writer_get_schema;
+ self->parent.get_size = avro_resolved_map_writer_get_size;
+ self->parent.add = avro_resolved_map_writer_add;
+
+ self->refcount = 1;
+ self->wschema = avro_schema_incref(wschema);
+ self->rschema = avro_schema_incref(rschema);
+ self->reader_union_branch = -1;
+ self->calculate_size = avro_resolved_map_writer_calculate_size;
+ self->free_iface = avro_resolved_map_writer_free_iface;
+ self->init = avro_resolved_map_writer_init;
+ self->done = avro_resolved_map_writer_done;
+ self->reset_wrappers = avro_resolved_map_writer_reset;
+ return container_of(self, avro_resolved_map_writer_t, parent);
+}
+
+static int
+try_map(memoize_state_t *state, avro_resolved_writer_t **self,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ /*
+ * First verify that the reader is an map.
+ */
+
+ if (!is_avro_map(rschema)) {
+ return 0;
+ }
+
+ /*
+ * Map schemas have to have compatible element schemas to be
+ * compatible themselves. Try to create an resolver to check
+ * the compatibility.
+ */
+
+ avro_resolved_map_writer_t *mself =
+ avro_resolved_map_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, mself);
+
+ avro_schema_t witems = avro_schema_map_values(wschema);
+ avro_schema_t ritems = avro_schema_map_values(rschema);
+
+ avro_resolved_writer_t *item_resolver =
+ avro_resolved_writer_new_memoized(state, witems, ritems);
+ if (item_resolver == NULL) {
+ avro_memoize_delete(&state->mem, wschema, root_rschema);
+ avro_value_iface_decref(&mself->parent.parent);
+ avro_prefix_error("Map values aren't compatible: ");
+ return EINVAL;
+ }
+
+ /*
+ * The two schemas are compatible. Store the item schema's
+ * resolver into the child_resolver field.
+ */
+
+ mself->child_resolver = item_resolver;
+ *self = &mself->parent;
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * record
+ */
+
+typedef struct avro_resolved_record_writer {
+ avro_resolved_writer_t parent;
+ size_t field_count;
+ size_t *field_offsets;
+ avro_resolved_writer_t **field_resolvers;
+ size_t *index_mapping;
+} avro_resolved_record_writer_t;
+
+typedef struct avro_resolved_record_value {
+ avro_value_t wrapped;
+ /* The rest of the struct is taken up by the inline storage
+ * needed for each field. */
+} avro_resolved_record_value_t;
+
+/** Return a pointer to the given field within a record struct. */
+#define avro_resolved_record_field(iface, rec, index) \
+ (((char *) (rec)) + (iface)->field_offsets[(index)])
+
+
+static void
+avro_resolved_record_writer_calculate_size(avro_resolved_writer_t *iface)
+{
+ avro_resolved_record_writer_t *riface =
+ container_of(iface, avro_resolved_record_writer_t, parent);
+
+ /* Only calculate the size for any resolver once */
+ iface->calculate_size = NULL;
+
+ DEBUG("Calculating size for %s->%s",
+ avro_schema_type_name((iface)->wschema),
+ avro_schema_type_name((iface)->rschema));
+
+ /*
+ * Once we've figured out which writer fields we actually need,
+ * calculate an offset for each one.
+ */
+
+ size_t wi;
+ size_t next_offset = sizeof(avro_resolved_record_value_t);
+ for (wi = 0; wi < riface->field_count; wi++) {
+ riface->field_offsets[wi] = next_offset;
+ if (riface->field_resolvers[wi] != NULL) {
+ avro_resolved_writer_calculate_size
+ (riface->field_resolvers[wi]);
+ size_t field_size =
+ riface->field_resolvers[wi]->instance_size;
+ DEBUG("Field %" PRIsz " has size %" PRIsz, wi, field_size);
+ next_offset += field_size;
+ } else {
+ DEBUG("Field %" PRIsz " is being skipped", wi);
+ }
+ }
+
+ DEBUG("Record has size %" PRIsz, next_offset);
+ iface->instance_size = next_offset;
+}
+
+static void
+avro_resolved_record_writer_free_iface(avro_resolved_writer_t *iface, st_table *freeing)
+{
+ avro_resolved_record_writer_t *riface =
+ container_of(iface, avro_resolved_record_writer_t, parent);
+
+ if (riface->field_offsets != NULL) {
+ avro_free(riface->field_offsets,
+ riface->field_count * sizeof(size_t));
+ }
+
+ if (riface->field_resolvers != NULL) {
+ size_t i;
+ for (i = 0; i < riface->field_count; i++) {
+ if (riface->field_resolvers[i] != NULL) {
+ DEBUG("Freeing field %" PRIsz " %p", i,
+ riface->field_resolvers[i]);
+ free_resolver(riface->field_resolvers[i], freeing);
+ }
+ }
+ avro_free(riface->field_resolvers,
+ riface->field_count * sizeof(avro_resolved_writer_t *));
+ }
+
+ if (riface->index_mapping != NULL) {
+ avro_free(riface->index_mapping,
+ riface->field_count * sizeof(size_t));
+ }
+
+ avro_schema_decref(iface->wschema);
+ avro_schema_decref(iface->rschema);
+ avro_freet(avro_resolved_record_writer_t, iface);
+}
+
+static int
+avro_resolved_record_writer_init(const avro_resolved_writer_t *iface, void *vself)
+{
+ int rval;
+ const avro_resolved_record_writer_t *riface =
+ container_of(iface, avro_resolved_record_writer_t, parent);
+ avro_resolved_record_value_t *self = (avro_resolved_record_value_t *) vself;
+
+ /* Initialize each field */
+ size_t i;
+ for (i = 0; i < riface->field_count; i++) {
+ if (riface->field_resolvers[i] != NULL) {
+ check(rval, avro_resolved_writer_init
+ (riface->field_resolvers[i],
+ avro_resolved_record_field(riface, self, i)));
+ }
+ }
+
+ return 0;
+}
+
+static void
+avro_resolved_record_writer_done(const avro_resolved_writer_t *iface, void *vself)
+{
+ const avro_resolved_record_writer_t *riface =
+ container_of(iface, avro_resolved_record_writer_t, parent);
+ avro_resolved_record_value_t *self = (avro_resolved_record_value_t *) vself;
+
+ /* Finalize each field */
+ size_t i;
+ for (i = 0; i < riface->field_count; i++) {
+ if (riface->field_resolvers[i] != NULL) {
+ avro_resolved_writer_done
+ (riface->field_resolvers[i],
+ avro_resolved_record_field(riface, self, i));
+ }
+ }
+}
+
+static int
+avro_resolved_record_writer_reset(const avro_resolved_writer_t *iface, void *vself)
+{
+ int rval;
+ const avro_resolved_record_writer_t *riface =
+ container_of(iface, avro_resolved_record_writer_t, parent);
+ avro_resolved_record_value_t *self = (avro_resolved_record_value_t *) vself;
+
+ /* Reset each field */
+ size_t i;
+ for (i = 0; i < riface->field_count; i++) {
+ if (riface->field_resolvers[i] != NULL) {
+ check(rval, avro_resolved_writer_reset_wrappers
+ (riface->field_resolvers[i],
+ avro_resolved_record_field(riface, self, i)));
+ }
+ }
+
+ return 0;
+}
+
+static int
+avro_resolved_record_writer_get_size(const avro_value_iface_t *viface,
+ const void *vself, size_t *size)
+{
+ AVRO_UNUSED(vself);
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ const avro_resolved_record_writer_t *riface =
+ container_of(iface, avro_resolved_record_writer_t, parent);
+ *size = riface->field_count;
+ return 0;
+}
+
+static int
+avro_resolved_record_writer_get_by_index(const avro_value_iface_t *viface,
+ const void *vself, size_t index,
+ avro_value_t *child, const char **name)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ const avro_resolved_record_writer_t *riface =
+ container_of(iface, avro_resolved_record_writer_t, parent);
+ const avro_resolved_record_value_t *self = (const avro_resolved_record_value_t *) vself;
+ avro_value_t dest;
+
+ DEBUG("Getting writer field %" PRIsz " from record %p", index, self);
+ if (riface->field_resolvers[index] == NULL) {
+ DEBUG("Reader doesn't have field, skipping");
+ child->iface = NULL;
+ child->self = NULL;
+ return 0;
+ }
+
+ check(rval, avro_resolved_writer_get_real_dest(iface, &self->wrapped, &dest));
+ size_t reader_index = riface->index_mapping[index];
+ DEBUG(" Reader field is %" PRIsz, reader_index);
+ child->iface = &riface->field_resolvers[index]->parent;
+ child->self = avro_resolved_record_field(riface, self, index);
+
+ return avro_value_get_by_index(&dest, reader_index, (avro_value_t *) child->self, name);
+}
+
+static int
+avro_resolved_record_writer_get_by_name(const avro_value_iface_t *viface,
+ const void *vself, const char *name,
+ avro_value_t *child, size_t *index)
+{
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+
+ int wi = avro_schema_record_field_get_index(iface->wschema, name);
+ if (wi == -1) {
+ avro_set_error("Record doesn't have field named %s", name);
+ return EINVAL;
+ }
+
+ DEBUG("Writer field %s is at index %d", name, wi);
+ if (index != NULL) {
+ *index = wi;
+ }
+ return avro_resolved_record_writer_get_by_index(viface, vself, wi, child, NULL);
+}
+
+static avro_resolved_record_writer_t *
+avro_resolved_record_writer_create(avro_schema_t wschema, avro_schema_t rschema)
+{
+ avro_resolved_writer_t *self = (avro_resolved_writer_t *) avro_new(avro_resolved_record_writer_t);
+ memset(self, 0, sizeof(avro_resolved_record_writer_t));
+
+ self->parent.incref_iface = avro_resolved_writer_incref_iface;
+ self->parent.decref_iface = avro_resolved_writer_decref_iface;
+ self->parent.incref = avro_resolved_writer_incref;
+ self->parent.decref = avro_resolved_writer_decref;
+ self->parent.reset = avro_resolved_writer_reset;
+ self->parent.get_type = avro_resolved_writer_get_type;
+ self->parent.get_schema = avro_resolved_writer_get_schema;
+ self->parent.get_size = avro_resolved_record_writer_get_size;
+ self->parent.get_by_index = avro_resolved_record_writer_get_by_index;
+ self->parent.get_by_name = avro_resolved_record_writer_get_by_name;
+
+ self->refcount = 1;
+ self->wschema = avro_schema_incref(wschema);
+ self->rschema = avro_schema_incref(rschema);
+ self->reader_union_branch = -1;
+ self->calculate_size = avro_resolved_record_writer_calculate_size;
+ self->free_iface = avro_resolved_record_writer_free_iface;
+ self->init = avro_resolved_record_writer_init;
+ self->done = avro_resolved_record_writer_done;
+ self->reset_wrappers = avro_resolved_record_writer_reset;
+ return container_of(self, avro_resolved_record_writer_t, parent);
+}
+
+static int
+try_record(memoize_state_t *state, avro_resolved_writer_t **self,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ /*
+ * First verify that the reader is also a record, and has the
+ * same name as the writer.
+ */
+
+ if (!is_avro_record(rschema)) {
+ return 0;
+ }
+
+ const char *wname = avro_schema_name(wschema);
+ const char *rname = avro_schema_name(rschema);
+
+ if (strcmp(wname, rname) != 0) {
+ return 0;
+ }
+
+ /*
+ * Categorize the fields in the record schemas. Fields that are
+ * only in the writer are ignored. Fields that are only in the
+ * reader raise a schema mismatch error, unless the field has a
+ * default value. Fields that are in both are resolved
+ * recursively.
+ *
+ * The field_resolvers array will contain an avro_value_iface_t
+ * for each field in the writer schema. To build this array, we
+ * loop through the fields of the reader schema. If that field
+ * is also in the writer schema, we resolve them recursively,
+ * and store the resolver into the array. If the field isn't in
+ * the writer schema, we raise an error. (TODO: Eventually,
+ * we'll handle default values here.) After this loop finishes,
+ * any NULLs in the field_resolvers array will represent fields
+ * in the writer but not the reader; these fields will be
+ * skipped when processing the input.
+ */
+
+ avro_resolved_record_writer_t *rself =
+ avro_resolved_record_writer_create(wschema, root_rschema);
+ avro_memoize_set(&state->mem, wschema, root_rschema, rself);
+
+ size_t wfields = avro_schema_record_size(wschema);
+ size_t rfields = avro_schema_record_size(rschema);
+
+ DEBUG("Checking writer record schema %s", wname);
+
+ avro_resolved_writer_t **field_resolvers =
+ (avro_resolved_writer_t **) avro_calloc(wfields, sizeof(avro_resolved_writer_t *));
+ size_t *field_offsets = (size_t *) avro_calloc(wfields, sizeof(size_t));
+ size_t *index_mapping = (size_t *) avro_calloc(wfields, sizeof(size_t));
+
+ size_t ri;
+ for (ri = 0; ri < rfields; ri++) {
+ avro_schema_t rfield =
+ avro_schema_record_field_get_by_index(rschema, ri);
+ const char *field_name =
+ avro_schema_record_field_name(rschema, ri);
+
+ DEBUG("Resolving reader record field %" PRIsz " (%s)", ri, field_name);
+
+ /*
+ * See if this field is also in the writer schema.
+ */
+
+ int wi = avro_schema_record_field_get_index(wschema, field_name);
+
+ if (wi == -1) {
+ /*
+ * This field isn't in the writer schema —
+ * that's an error! TODO: Handle default
+ * values!
+ */
+
+ DEBUG("Field %s isn't in writer", field_name);
+
+ /* Allow missing fields in the writer. They
+ * will default to zero. So skip over the
+ * missing field, and continue building the
+ * resolver. Note also that all missing values
+ * are zero because avro_generic_value_new()
+ * initializes all values of the reader to 0
+ * on creation. This is a work-around because
+ * default values are not implemented yet.
+ */
+ #ifdef AVRO_ALLOW_MISSING_FIELDS_IN_RESOLVED_WRITER
+ continue;
+ #else
+ avro_set_error("Reader field %s doesn't appear in writer",
+ field_name);
+ goto error;
+ #endif
+ }
+
+ /*
+ * Try to recursively resolve the schemas for this
+ * field. If they're not compatible, that's an error.
+ */
+
+ avro_schema_t wfield =
+ avro_schema_record_field_get_by_index(wschema, wi);
+ avro_resolved_writer_t *field_resolver =
+ avro_resolved_writer_new_memoized(state, wfield, rfield);
+
+ if (field_resolver == NULL) {
+ avro_prefix_error("Field %s isn't compatible: ", field_name);
+ goto error;
+ }
+
+ /*
+ * Save the details for this field.
+ */
+
+ DEBUG("Found match for field %s (%" PRIsz " in reader, %d in writer)",
+ field_name, ri, wi);
+ field_resolvers[wi] = field_resolver;
+ index_mapping[wi] = ri;
+ }
+
+ /*
+ * We might not have found matches for all of the writer fields,
+ * but that's okay — any extras will be ignored.
+ */
+
+ rself->field_count = wfields;
+ rself->field_offsets = field_offsets;
+ rself->field_resolvers = field_resolvers;
+ rself->index_mapping = index_mapping;
+ *self = &rself->parent;
+ return 0;
+
+error:
+ /*
+ * Clean up any resolver we might have already created.
+ */
+
+ avro_memoize_delete(&state->mem, wschema, root_rschema);
+ avro_value_iface_decref(&rself->parent.parent);
+
+ {
+ unsigned int i;
+ for (i = 0; i < wfields; i++) {
+ if (field_resolvers[i]) {
+ avro_value_iface_decref(&field_resolvers[i]->parent);
+ }
+ }
+ }
+
+ avro_free(field_resolvers, wfields * sizeof(avro_resolved_writer_t *));
+ avro_free(field_offsets, wfields * sizeof(size_t));
+ avro_free(index_mapping, wfields * sizeof(size_t));
+ return EINVAL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * union
+ */
+
+typedef struct avro_resolved_union_writer {
+ avro_resolved_writer_t parent;
+ size_t branch_count;
+ avro_resolved_writer_t **branch_resolvers;
+} avro_resolved_union_writer_t;
+
+typedef struct avro_resolved_union_value {
+ avro_value_t wrapped;
+
+ /** The currently active branch of the union. -1 if no branch
+ * is selected. */
+ int discriminant;
+
+ /* The rest of the struct is taken up by the inline storage
+ * needed for the active branch. */
+} avro_resolved_union_value_t;
+
+/** Return a pointer to the active branch within a union struct. */
+#define avro_resolved_union_branch(_union) \
+ (((char *) (_union)) + sizeof(avro_resolved_union_value_t))
+
+
+static void
+avro_resolved_union_writer_calculate_size(avro_resolved_writer_t *iface)
+{
+ avro_resolved_union_writer_t *uiface =
+ container_of(iface, avro_resolved_union_writer_t, parent);
+
+ /* Only calculate the size for any resolver once */
+ iface->calculate_size = NULL;
+
+ DEBUG("Calculating size for %s->%s",
+ avro_schema_type_name((iface)->wschema),
+ avro_schema_type_name((iface)->rschema));
+
+ size_t i;
+ size_t max_branch_size = 0;
+ for (i = 0; i < uiface->branch_count; i++) {
+ if (uiface->branch_resolvers[i] == NULL) {
+ DEBUG("No match for writer union branch %" PRIsz, i);
+ } else {
+ avro_resolved_writer_calculate_size
+ (uiface->branch_resolvers[i]);
+ size_t branch_size =
+ uiface->branch_resolvers[i]->instance_size;
+ DEBUG("Writer branch %" PRIsz " has size %" PRIsz, i, branch_size);
+ if (branch_size > max_branch_size) {
+ max_branch_size = branch_size;
+ }
+ }
+ }
+
+ DEBUG("Maximum branch size is %" PRIsz, max_branch_size);
+ iface->instance_size =
+ sizeof(avro_resolved_union_value_t) + max_branch_size;
+ DEBUG("Total union size is %" PRIsz, iface->instance_size);
+}
+
+static void
+avro_resolved_union_writer_free_iface(avro_resolved_writer_t *iface, st_table *freeing)
+{
+ avro_resolved_union_writer_t *uiface =
+ container_of(iface, avro_resolved_union_writer_t, parent);
+
+ if (uiface->branch_resolvers != NULL) {
+ size_t i;
+ for (i = 0; i < uiface->branch_count; i++) {
+ if (uiface->branch_resolvers[i] != NULL) {
+ free_resolver(uiface->branch_resolvers[i], freeing);
+ }
+ }
+ avro_free(uiface->branch_resolvers,
+ uiface->branch_count * sizeof(avro_resolved_writer_t *));
+ }
+
+ avro_schema_decref(iface->wschema);
+ avro_schema_decref(iface->rschema);
+ avro_freet(avro_resolved_union_writer_t, iface);
+}
+
+static int
+avro_resolved_union_writer_init(const avro_resolved_writer_t *iface, void *vself)
+{
+ AVRO_UNUSED(iface);
+ avro_resolved_union_value_t *self = (avro_resolved_union_value_t *) vself;
+ self->discriminant = -1;
+ return 0;
+}
+
+static void
+avro_resolved_union_writer_done(const avro_resolved_writer_t *iface, void *vself)
+{
+ const avro_resolved_union_writer_t *uiface =
+ container_of(iface, avro_resolved_union_writer_t, parent);
+ avro_resolved_union_value_t *self = (avro_resolved_union_value_t *) vself;
+ if (self->discriminant >= 0) {
+ avro_resolved_writer_done
+ (uiface->branch_resolvers[self->discriminant],
+ avro_resolved_union_branch(self));
+ self->discriminant = -1;
+ }
+}
+
+static int
+avro_resolved_union_writer_reset(const avro_resolved_writer_t *iface, void *vself)
+{
+ const avro_resolved_union_writer_t *uiface =
+ container_of(iface, avro_resolved_union_writer_t, parent);
+ avro_resolved_union_value_t *self = (avro_resolved_union_value_t *) vself;
+
+ /* Keep the same branch selected, for the common case that we're
+ * about to reuse it. */
+ if (self->discriminant >= 0) {
+ return avro_resolved_writer_reset_wrappers
+ (uiface->branch_resolvers[self->discriminant],
+ avro_resolved_union_branch(self));
+ }
+
+ return 0;
+}
+
+static int
+avro_resolved_union_writer_set_branch(const avro_value_iface_t *viface,
+ void *vself, int discriminant,
+ avro_value_t *branch)
+{
+ int rval;
+ const avro_resolved_writer_t *iface =
+ container_of(viface, avro_resolved_writer_t, parent);
+ const avro_resolved_union_writer_t *uiface =
+ container_of(iface, avro_resolved_union_writer_t, parent);
+ avro_resolved_union_value_t *self = (avro_resolved_union_value_t *) vself;
+
+ DEBUG("Getting writer branch %d from union %p", discriminant, vself);
+ avro_resolved_writer_t *branch_resolver =
+ uiface->branch_resolvers[discriminant];
+ if (branch_resolver == NULL) {
+ DEBUG("Reader doesn't have branch, skipping");
+ avro_set_error("Writer union branch %d is incompatible "
+ "with reader schema \"%s\"",
+ discriminant, avro_schema_type_name(iface->rschema));
+ return EINVAL;
+ }
+
+ if (self->discriminant == discriminant) {
+ DEBUG("Writer branch %d already selected", discriminant);
+ } else {
+ if (self->discriminant >= 0) {
+ DEBUG("Finalizing old writer branch %d", self->discriminant);
+ avro_resolved_writer_done
+ (uiface->branch_resolvers[self->discriminant],
+ avro_resolved_union_branch(self));
+ }
+ DEBUG("Initializing writer branch %d", discriminant);
+ check(rval, avro_resolved_writer_init
+ (uiface->branch_resolvers[discriminant],
+ avro_resolved_union_branch(self)));
+ self->discriminant = discriminant;
+ }
+
+ branch->iface = &branch_resolver->parent;
+ branch->self = avro_resolved_union_branch(self);
+ avro_value_t *branch_vself = (avro_value_t *) branch->self;
+ *branch_vself = self->wrapped;
+ return 0;
+}
+
+static avro_resolved_union_writer_t *
+avro_resolved_union_writer_create(avro_schema_t wschema, avro_schema_t rschema)
+{
+ avro_resolved_writer_t *self = (avro_resolved_writer_t *) avro_new(avro_resolved_union_writer_t);
+ memset(self, 0, sizeof(avro_resolved_union_writer_t));
+
+ self->parent.incref_iface = avro_resolved_writer_incref_iface;
+ self->parent.decref_iface = avro_resolved_writer_decref_iface;
+ self->parent.incref = avro_resolved_writer_incref;
+ self->parent.decref = avro_resolved_writer_decref;
+ self->parent.reset = avro_resolved_writer_reset;
+ self->parent.get_type = avro_resolved_writer_get_type;
+ self->parent.get_schema = avro_resolved_writer_get_schema;
+ self->parent.set_branch = avro_resolved_union_writer_set_branch;
+
+ self->refcount = 1;
+ self->wschema = avro_schema_incref(wschema);
+ self->rschema = avro_schema_incref(rschema);
+ self->reader_union_branch = -1;
+ self->calculate_size = avro_resolved_union_writer_calculate_size;
+ self->free_iface = avro_resolved_union_writer_free_iface;
+ self->init = avro_resolved_union_writer_init;
+ self->done = avro_resolved_union_writer_done;
+ self->reset_wrappers = avro_resolved_union_writer_reset;
+ return container_of(self, avro_resolved_union_writer_t, parent);
+}
+
+static avro_resolved_writer_t *
+try_union(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ /*
+ * For a writer union, we recursively try to resolve each branch
+ * against the reader schema. This will work correctly whether
+ * or not the reader is also a union — if the reader is a union,
+ * then we'll resolve each (non-union) writer branch against the
+ * reader union, which will be checked in our calls to
+ * check_simple_writer below. The net result is that we might
+ * end up trying every combination of writer and reader
+ * branches, when looking for compatible schemas.
+ *
+ * Regardless of what the reader schema is, for each writer
+ * branch, we stash away the recursive resolver into the
+ * branch_resolvers array. A NULL entry in this array means
+ * that that branch isn't compatible with the reader. This
+ * isn't an immediate schema resolution error, since we allow
+ * incompatible branches in the types as long as that branch
+ * never appears in the actual data. We only return an error if
+ * there are *no* branches that are compatible.
+ */
+
+ size_t branch_count = avro_schema_union_size(wschema);
+ DEBUG("Checking %" PRIsz "-branch writer union schema", branch_count);
+
+ avro_resolved_union_writer_t *uself =
+ avro_resolved_union_writer_create(wschema, rschema);
+ avro_memoize_set(&state->mem, wschema, rschema, uself);
+
+ avro_resolved_writer_t **branch_resolvers =
+ (avro_resolved_writer_t **) avro_calloc(branch_count, sizeof(avro_resolved_writer_t *));
+ int some_branch_compatible = 0;
+
+ size_t i;
+ for (i = 0; i < branch_count; i++) {
+ avro_schema_t branch_schema =
+ avro_schema_union_branch(wschema, i);
+
+ DEBUG("Resolving writer union branch %" PRIsz " (%s)", i,
+ avro_schema_type_name(branch_schema));
+
+ /*
+ * Try to recursively resolve this branch of the writer
+ * union. Don't raise an error if this fails — it's
+ * okay for some of the branches to not be compatible
+ * with the reader, as long as those branches never
+ * appear in the input.
+ */
+
+ branch_resolvers[i] =
+ avro_resolved_writer_new_memoized(state, branch_schema, rschema);
+ if (branch_resolvers[i] == NULL) {
+ DEBUG("No match for writer union branch %" PRIsz, i);
+ } else {
+ DEBUG("Found match for writer union branch %" PRIsz, i);
+ some_branch_compatible = 1;
+ }
+ }
+
+ /*
+ * As long as there's at least one branch that's compatible with
+ * the reader, then we consider this schema resolution a
+ * success.
+ */
+
+ if (!some_branch_compatible) {
+ DEBUG("No writer union branches match");
+ avro_set_error("No branches in the writer are compatible "
+ "with reader schema %s",
+ avro_schema_type_name(rschema));
+ goto error;
+ }
+
+ uself->branch_count = branch_count;
+ uself->branch_resolvers = branch_resolvers;
+ return &uself->parent;
+
+error:
+ /*
+ * Clean up any resolver we might have already created.
+ */
+
+ avro_memoize_delete(&state->mem, wschema, rschema);
+ avro_value_iface_decref(&uself->parent.parent);
+
+ {
+ unsigned int i;
+ for (i = 0; i < branch_count; i++) {
+ if (branch_resolvers[i]) {
+ avro_value_iface_decref(&branch_resolvers[i]->parent);
+ }
+ }
+ }
+
+ avro_free(branch_resolvers, branch_count * sizeof(avro_resolved_writer_t *));
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * Schema type dispatcher
+ */
+
+static avro_resolved_writer_t *
+avro_resolved_writer_new_memoized(memoize_state_t *state,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ check_param(NULL, is_avro_schema(wschema), "writer schema");
+ check_param(NULL, is_avro_schema(rschema), "reader schema");
+
+ skip_links(rschema);
+
+ /*
+ * First see if we've already matched these two schemas. If so,
+ * just return that resolver.
+ */
+
+ avro_resolved_writer_t *saved = NULL;
+ if (avro_memoize_get(&state->mem, wschema, rschema, (void **) &saved)) {
+ DEBUG("Already resolved %s%s%s->%s",
+ is_avro_link(wschema)? "[": "",
+ avro_schema_type_name(wschema),
+ is_avro_link(wschema)? "]": "",
+ avro_schema_type_name(rschema));
+ avro_value_iface_incref(&saved->parent);
+ return saved;
+ } else {
+ DEBUG("Resolving %s%s%s->%s",
+ is_avro_link(wschema)? "[": "",
+ avro_schema_type_name(wschema),
+ is_avro_link(wschema)? "]": "",
+ avro_schema_type_name(rschema));
+ }
+
+ /*
+ * Otherwise we have some work to do.
+ */
+
+ switch (avro_typeof(wschema))
+ {
+ case AVRO_BOOLEAN:
+ check_simple_writer(state, wschema, rschema, boolean);
+ return NULL;
+
+ case AVRO_BYTES:
+ check_simple_writer(state, wschema, rschema, bytes);
+ return NULL;
+
+ case AVRO_DOUBLE:
+ check_simple_writer(state, wschema, rschema, double);
+ return NULL;
+
+ case AVRO_FLOAT:
+ check_simple_writer(state, wschema, rschema, float);
+ return NULL;
+
+ case AVRO_INT32:
+ check_simple_writer(state, wschema, rschema, int);
+ return NULL;
+
+ case AVRO_INT64:
+ check_simple_writer(state, wschema, rschema, long);
+ return NULL;
+
+ case AVRO_NULL:
+ check_simple_writer(state, wschema, rschema, null);
+ return NULL;
+
+ case AVRO_STRING:
+ check_simple_writer(state, wschema, rschema, string);
+ return NULL;
+
+ case AVRO_ARRAY:
+ check_simple_writer(state, wschema, rschema, array);
+ return NULL;
+
+ case AVRO_ENUM:
+ check_simple_writer(state, wschema, rschema, enum);
+ return NULL;
+
+ case AVRO_FIXED:
+ check_simple_writer(state, wschema, rschema, fixed);
+ return NULL;
+
+ case AVRO_MAP:
+ check_simple_writer(state, wschema, rschema, map);
+ return NULL;
+
+ case AVRO_RECORD:
+ check_simple_writer(state, wschema, rschema, record);
+ return NULL;
+
+ case AVRO_UNION:
+ return try_union(state, wschema, rschema);
+
+ case AVRO_LINK:
+ check_simple_writer(state, wschema, rschema, link);
+ return NULL;
+
+ default:
+ avro_set_error("Unknown schema type");
+ return NULL;
+ }
+
+ return NULL;
+}
+
+
+avro_value_iface_t *
+avro_resolved_writer_new(avro_schema_t wschema, avro_schema_t rschema)
+{
+ /*
+ * Create a state to keep track of the value implementations
+ * that we create for each subschema.
+ */
+
+ memoize_state_t state;
+ avro_memoize_init(&state.mem);
+ state.links = NULL;
+
+ /*
+ * Create the value implementations.
+ */
+
+ avro_resolved_writer_t *result =
+ avro_resolved_writer_new_memoized(&state, wschema, rschema);
+ if (result == NULL) {
+ avro_memoize_done(&state.mem);
+ return NULL;
+ }
+
+ /*
+ * Fix up any link schemas so that their value implementations
+ * point to their target schemas' implementations.
+ */
+
+ avro_resolved_writer_calculate_size(result);
+ while (state.links != NULL) {
+ avro_resolved_link_writer_t *liface = state.links;
+ avro_resolved_writer_calculate_size(liface->target_resolver);
+ state.links = liface->next;
+ liface->next = NULL;
+ }
+
+ /*
+ * And now we can return.
+ */
+
+ avro_memoize_done(&state.mem);
+ return &result->parent;
+}
diff --git a/fluent-bit/lib/avro/src/resolver.c b/fluent-bit/lib/avro/src/resolver.c
new file mode 100644
index 000000000..f0256c265
--- /dev/null
+++ b/fluent-bit/lib/avro/src/resolver.c
@@ -0,0 +1,1338 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <avro/platform.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro/allocation.h"
+#include "avro/consumer.h"
+#include "avro/data.h"
+#include "avro/errors.h"
+#include "avro/legacy.h"
+#include "avro/schema.h"
+#include "avro_private.h"
+#include "st.h"
+
+
+#if !defined(DEBUG_RESOLVER)
+#define DEBUG_RESOLVER 0
+#endif
+
+#if DEBUG_RESOLVER
+#include <stdio.h>
+#define debug(...) { fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); }
+#else
+#define debug(...) /* no debug output */
+#endif
+
+
+typedef struct avro_resolver_t avro_resolver_t;
+
+struct avro_resolver_t {
+ avro_consumer_t parent;
+
+ /* The reader schema for this resolver. */
+ avro_schema_t rschema;
+
+ /* An array of any child resolvers needed for the subschemas of
+ * wschema */
+ avro_consumer_t **child_resolvers;
+
+ /* If the reader and writer schemas are records, this field
+ * contains a mapping from writer field indices to reader field
+ * indices. */
+ int *index_mapping;
+
+ /* The number of elements in the child_resolvers and
+ * index_mapping arrays. */
+ size_t num_children;
+
+ /* If the reader schema is a union, but the writer schema is
+ * not, this field indicates which branch of the reader union
+ * should be selected. */
+ int reader_union_branch;
+};
+
+
+/**
+ * Frees a resolver object, while ensuring that all of the resolvers in
+ * a graph of resolvers is only freed once.
+ */
+
+static void
+avro_resolver_free_cycles(avro_consumer_t *consumer, st_table *freeing)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+
+ /*
+ * First check if we've already started freeing this resolver.
+ */
+
+ if (st_lookup(freeing, (st_data_t) resolver, NULL)) {
+ return;
+ }
+
+ /*
+ * Otherwise add this resolver to the freeing set, and then
+ * actually free the thing.
+ */
+
+ st_insert(freeing, (st_data_t) resolver, (st_data_t) NULL);
+
+ avro_schema_decref(resolver->parent.schema);
+ avro_schema_decref(resolver->rschema);
+ if (resolver->child_resolvers) {
+ unsigned int i;
+ for (i = 0; i < resolver->num_children; i++) {
+ avro_consumer_t *child = resolver->child_resolvers[i];
+ if (child) {
+ avro_resolver_free_cycles(child, freeing);
+ }
+ }
+ avro_free(resolver->child_resolvers,
+ sizeof(avro_resolver_t *) * resolver->num_children);
+ }
+ if (resolver->index_mapping) {
+ avro_free(resolver->index_mapping,
+ sizeof(int) * resolver->num_children);
+ }
+ avro_freet(avro_resolver_t, resolver);
+}
+
+
+static void
+avro_resolver_free(avro_consumer_t *consumer)
+{
+ st_table *freeing = st_init_numtable();
+ avro_resolver_free_cycles(consumer, freeing);
+ st_free_table(freeing);
+}
+
+/**
+ * Create a new avro_resolver_t instance. You must fill in the callback
+ * pointers that are appropriate for the writer schema after this
+ * function returns.
+ */
+
+static avro_resolver_t *
+avro_resolver_create(avro_schema_t wschema,
+ avro_schema_t rschema)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) avro_new(avro_resolver_t);
+ memset(resolver, 0, sizeof(avro_resolver_t));
+
+ resolver->parent.free = avro_resolver_free;
+ resolver->parent.schema = avro_schema_incref(wschema);
+ resolver->rschema = avro_schema_incref(rschema);
+ resolver->reader_union_branch = -1;
+ return resolver;
+}
+
+
+static avro_datum_t
+avro_resolver_get_real_dest(avro_resolver_t *resolver, avro_datum_t dest)
+{
+ if (resolver->reader_union_branch < 0) {
+ /*
+ * The reader schema isn't a union, so use the dest
+ * field as-is.
+ */
+
+ return dest;
+ }
+
+ debug("Retrieving union branch %d for %s value",
+ resolver->reader_union_branch,
+ avro_schema_type_name(resolver->parent.schema));
+
+ avro_datum_t branch = NULL;
+ avro_union_set_discriminant
+ (dest, resolver->reader_union_branch, &branch);
+ return branch;
+}
+
+
+#define skip_links(schema) \
+ while (is_avro_link(schema)) { \
+ schema = avro_schema_link_target(schema); \
+ }
+
+
+/*-----------------------------------------------------------------------
+ * Memoized resolvers
+ */
+
+static avro_consumer_t *
+avro_resolver_new_memoized(avro_memoize_t *mem,
+ avro_schema_t wschema, avro_schema_t rschema);
+
+
+/*-----------------------------------------------------------------------
+ * Reader unions
+ */
+
+/*
+ * For each Avro type, we have to check whether the reader schema on its
+ * own is compatible, and whether the reader is a union that contains a
+ * compatible type. The macros in this section help us perform both of
+ * these checks with less code.
+ */
+
+
+/**
+ * A helper macro that handles the case where neither writer nor reader
+ * are unions. Uses @ref check_func to see if the two schemas are
+ * compatible.
+ */
+
+#define check_non_union(saved, wschema, rschema, check_func) \
+do { \
+ avro_resolver_t *self = NULL; \
+ int rc = check_func(saved, &self, wschema, rschema, \
+ rschema); \
+ if (self) { \
+ debug("Non-union schemas %s (writer) " \
+ "and %s (reader) match", \
+ avro_schema_type_name(wschema), \
+ avro_schema_type_name(rschema)); \
+ \
+ self->reader_union_branch = -1; \
+ return &self->parent; \
+ } \
+ \
+ if (rc) { \
+ return NULL; \
+ } \
+} while (0)
+
+
+/**
+ * Helper macro that handles the case where the reader is a union, and
+ * the writer is not. Checks each branch of the reader union schema,
+ * looking for the first branch that is compatible with the writer
+ * schema. The @ref check_func argument should be a function that can
+ * check the compatiblity of each branch schema.
+ */
+
+#define check_reader_union(saved, wschema, rschema, check_func) \
+do { \
+ if (!is_avro_union(rschema)) { \
+ break; \
+ } \
+ \
+ debug("Checking reader union schema"); \
+ size_t num_branches = avro_schema_union_size(rschema); \
+ unsigned int i; \
+ \
+ for (i = 0; i < num_branches; i++) { \
+ avro_schema_t branch_schema = \
+ avro_schema_union_branch(rschema, i); \
+ skip_links(branch_schema); \
+ avro_resolver_t *self = NULL; \
+ int rc = check_func(saved, &self, \
+ wschema, branch_schema, \
+ rschema); \
+ if (self) { \
+ debug("Reader union branch %d (%s) " \
+ "and writer %s match", \
+ i, avro_schema_type_name(branch_schema), \
+ avro_schema_type_name(wschema)); \
+ self->reader_union_branch = i; \
+ return &self->parent; \
+ } else { \
+ debug("Reader union branch %d (%s) " \
+ "doesn't match", \
+ i, avro_schema_type_name(branch_schema)); \
+ } \
+ \
+ if (rc) { \
+ return NULL; \
+ } \
+ } \
+ \
+ debug("No reader union branches match"); \
+} while (0)
+
+/**
+ * A helper macro that defines wraps together check_non_union and
+ * check_reader_union for a simple (non-union) writer schema type.
+ */
+
+#define check_simple_writer(saved, wschema, rschema, type_name) \
+do { \
+ check_non_union(saved, wschema, rschema, try_##type_name); \
+ check_reader_union(saved, wschema, rschema, try_##type_name); \
+ debug("Writer %s doesn't match reader %s", \
+ avro_schema_type_name(wschema), \
+ avro_schema_type_name(rschema)); \
+ avro_set_error("Cannot store " #type_name " into %s", \
+ avro_schema_type_name(rschema)); \
+ return NULL; \
+} while (0)
+
+
+/*-----------------------------------------------------------------------
+ * primitives
+ */
+
+static int
+avro_resolver_boolean_value(avro_consumer_t *consumer, int value,
+ void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ debug("Storing %s into %p", value? "TRUE": "FALSE", dest);
+ return avro_boolean_set(dest, value);
+}
+
+static int
+try_boolean(avro_memoize_t *mem, avro_resolver_t **resolver,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ if (is_avro_boolean(rschema)) {
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+ (*resolver)->parent.boolean_value = avro_resolver_boolean_value;
+ }
+ return 0;
+}
+
+
+static void
+free_bytes(void *ptr, size_t sz)
+{
+ /*
+ * The binary encoder class allocates bytes values with an extra
+ * byte, so that they're NUL terminated.
+ */
+ avro_free(ptr, sz+1);
+}
+
+static int
+avro_resolver_bytes_value(avro_consumer_t *consumer,
+ const void *value, size_t value_len,
+ void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ debug("Storing %" PRIsz " bytes into %p", value_len, dest);
+ return avro_givebytes_set(dest, (const char *) value, value_len, free_bytes);
+}
+
+static int
+try_bytes(avro_memoize_t *mem, avro_resolver_t **resolver,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ if (is_avro_bytes(rschema)) {
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+ (*resolver)->parent.bytes_value = avro_resolver_bytes_value;
+ }
+ return 0;
+}
+
+
+static int
+avro_resolver_double_value(avro_consumer_t *consumer, double value,
+ void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ debug("Storing %le into %p", value, dest);
+ return avro_double_set(dest, value);
+}
+
+static int
+try_double(avro_memoize_t *mem, avro_resolver_t **resolver,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ if (is_avro_double(rschema)) {
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+ (*resolver)->parent.double_value = avro_resolver_double_value;
+ }
+ return 0;
+}
+
+
+static int
+avro_resolver_float_value(avro_consumer_t *consumer, float value,
+ void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ debug("Storing %e into %p", value, dest);
+ return avro_float_set(dest, value);
+}
+
+static int
+avro_resolver_float_double_value(avro_consumer_t *consumer, float value,
+ void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ debug("Storing %e into %p (promoting float to double)", value, dest);
+ return avro_double_set(dest, value);
+}
+
+static int
+try_float(avro_memoize_t *mem, avro_resolver_t **resolver,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ if (is_avro_float(rschema)) {
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+ (*resolver)->parent.float_value = avro_resolver_float_value;
+ }
+ else if (is_avro_double(rschema)) {
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+ (*resolver)->parent.float_value = avro_resolver_float_double_value;
+ }
+ return 0;
+}
+
+
+static int
+avro_resolver_int_value(avro_consumer_t *consumer, int32_t value,
+ void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ debug("Storing %" PRId32 " into %p", value, dest);
+ return avro_int32_set(dest, value);
+}
+
+static int
+avro_resolver_int_long_value(avro_consumer_t *consumer, int32_t value,
+ void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ debug("Storing %" PRId32 " into %p (promoting int to long)", value, dest);
+ return avro_int64_set(dest, value);
+}
+
+static int
+avro_resolver_int_double_value(avro_consumer_t *consumer, int32_t value,
+ void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ debug("Storing %" PRId32 " into %p (promoting int to double)", value, dest);
+ return avro_double_set(dest, value);
+}
+
+static int
+avro_resolver_int_float_value(avro_consumer_t *consumer, int32_t value,
+ void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ debug("Storing %" PRId32 " into %p (promoting int to float)", value, dest);
+ return avro_float_set(dest, (const float) value);
+}
+
+static int
+try_int(avro_memoize_t *mem, avro_resolver_t **resolver,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ if (is_avro_int32(rschema)) {
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+ (*resolver)->parent.int_value = avro_resolver_int_value;
+ }
+ else if (is_avro_int64(rschema)) {
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+ (*resolver)->parent.int_value = avro_resolver_int_long_value;
+ }
+ else if (is_avro_double(rschema)) {
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+ (*resolver)->parent.int_value = avro_resolver_int_double_value;
+ }
+ else if (is_avro_float(rschema)) {
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+ (*resolver)->parent.int_value = avro_resolver_int_float_value;
+ }
+ return 0;
+}
+
+
+static int
+avro_resolver_long_value(avro_consumer_t *consumer, int64_t value,
+ void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ debug("Storing %" PRId64 " into %p", value, dest);
+ return avro_int64_set(dest, value);
+}
+
+static int
+avro_resolver_long_float_value(avro_consumer_t *consumer, int64_t value,
+ void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ debug("Storing %" PRId64 " into %p (promoting long to float)", value, dest);
+ return avro_float_set(dest, (const float) value);
+}
+
+static int
+avro_resolver_long_double_value(avro_consumer_t *consumer, int64_t value,
+ void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ debug("Storing %" PRId64 " into %p (promoting long to double)", value, dest);
+ return avro_double_set(dest, (const double) value);
+}
+
+static int
+try_long(avro_memoize_t *mem, avro_resolver_t **resolver,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ if (is_avro_int64(rschema)) {
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+ (*resolver)->parent.long_value = avro_resolver_long_value;
+ }
+ else if (is_avro_double(rschema)) {
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+ (*resolver)->parent.long_value = avro_resolver_long_double_value;
+ }
+ else if (is_avro_float(rschema)) {
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+ (*resolver)->parent.long_value = avro_resolver_long_float_value;
+ }
+ return 0;
+}
+
+
+static int
+avro_resolver_null_value(avro_consumer_t *consumer, void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+
+ AVRO_UNUSED(dest);
+ debug("Storing null into %p", dest);
+ return 0;
+}
+
+static int
+try_null(avro_memoize_t *mem, avro_resolver_t **resolver,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ if (is_avro_null(rschema)) {
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+ (*resolver)->parent.null_value = avro_resolver_null_value;
+ }
+ return 0;
+}
+
+
+static int
+avro_resolver_string_value(avro_consumer_t *consumer,
+ const void *value, size_t value_len,
+ void *user_data)
+{
+ AVRO_UNUSED(value_len);
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ debug("Storing \"%s\" into %p", (const char *) value, dest);
+ return avro_givestring_set(dest, (const char *) value, avro_alloc_free_func);
+}
+
+static int
+try_string(avro_memoize_t *mem, avro_resolver_t **resolver,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ if (is_avro_string(rschema)) {
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+ (*resolver)->parent.string_value = avro_resolver_string_value;
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * arrays
+ */
+
+static int
+avro_resolver_array_start_block(avro_consumer_t *consumer,
+ int is_first_block,
+ unsigned int block_count,
+ void *user_data)
+{
+ if (is_first_block) {
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ AVRO_UNUSED(dest);
+
+ debug("Starting array %p", dest);
+ }
+
+ AVRO_UNUSED(block_count);
+ return 0;
+}
+
+static int
+avro_resolver_array_element(avro_consumer_t *consumer,
+ unsigned int index,
+ avro_consumer_t **element_consumer,
+ void **element_user_data,
+ void *user_data)
+{
+ AVRO_UNUSED(index);
+
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ debug("Adding element to array %p", dest);
+
+ /*
+ * Allocate a new element datum and add it to the array.
+ */
+
+ avro_schema_t array_schema = avro_datum_get_schema(dest);
+ avro_schema_t item_schema = avro_schema_array_items(array_schema);
+ avro_datum_t element = avro_datum_from_schema(item_schema);
+ avro_array_append_datum(dest, element);
+ avro_datum_decref(element);
+
+ /*
+ * Return the consumer that we allocated to process the array's
+ * children.
+ */
+
+ *element_consumer = resolver->child_resolvers[0];
+ *element_user_data = element;
+ return 0;
+}
+
+static int
+try_array(avro_memoize_t *mem, avro_resolver_t **resolver,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ /*
+ * First verify that the reader is an array.
+ */
+
+ if (!is_avro_array(rschema)) {
+ return 0;
+ }
+
+ /*
+ * Array schemas have to have compatible element schemas to be
+ * compatible themselves. Try to create an avro_resolver_t to
+ * check the compatibility.
+ */
+
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+
+ avro_schema_t witems = avro_schema_array_items(wschema);
+ avro_schema_t ritems = avro_schema_array_items(rschema);
+
+ avro_consumer_t *item_consumer =
+ avro_resolver_new_memoized(mem, witems, ritems);
+ if (!item_consumer) {
+ avro_memoize_delete(mem, wschema, root_rschema);
+ avro_consumer_free(&(*resolver)->parent);
+ avro_prefix_error("Array values aren't compatible: ");
+ return EINVAL;
+ }
+
+ /*
+ * The two schemas are compatible, so go ahead and create a
+ * GavroResolver for the array. Store the item schema's
+ * resolver into the child_resolvers field.
+ */
+
+ (*resolver)->num_children = 1;
+ (*resolver)->child_resolvers = (avro_consumer_t **) avro_calloc(1, sizeof(avro_consumer_t *));
+ (*resolver)->child_resolvers[0] = item_consumer;
+ (*resolver)->parent.array_start_block = avro_resolver_array_start_block;
+ (*resolver)->parent.array_element = avro_resolver_array_element;
+
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * enums
+ */
+
+static int
+avro_resolver_enum_value(avro_consumer_t *consumer, int value,
+ void *user_data)
+{
+ AVRO_UNUSED(value);
+
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+
+ const char *symbol_name = avro_schema_enum_get(resolver->parent.schema, value);
+ debug("Storing symbol %s into %p", symbol_name, dest);
+ return avro_enum_set_name(dest, symbol_name);
+}
+
+static int
+try_enum(avro_memoize_t *mem, avro_resolver_t **resolver,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ /*
+ * Enum schemas have to have the same name — but not the same
+ * list of symbols — to be compatible.
+ */
+
+ if (is_avro_enum(rschema)) {
+ const char *wname = avro_schema_name(wschema);
+ const char *rname = avro_schema_name(rschema);
+
+ if (!strcmp(wname, rname)) {
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+ (*resolver)->parent.enum_value = avro_resolver_enum_value;
+ }
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * fixed
+ */
+
+static int
+avro_resolver_fixed_value(avro_consumer_t *consumer,
+ const void *value, size_t value_len,
+ void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ debug("Storing (fixed) %" PRIsz " bytes into %p", value_len, dest);
+ return avro_givefixed_set(dest, (const char *) value, value_len, avro_alloc_free_func);
+}
+
+static int
+try_fixed(avro_memoize_t *mem, avro_resolver_t **resolver,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ /*
+ * Fixed schemas need the same name and size to be compatible.
+ */
+
+ if (avro_schema_equal(wschema, rschema)) {
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+ (*resolver)->parent.fixed_value = avro_resolver_fixed_value;
+ }
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * maps
+ */
+
+static int
+avro_resolver_map_start_block(avro_consumer_t *consumer,
+ int is_first_block,
+ unsigned int block_count,
+ void *user_data)
+{
+ if (is_first_block) {
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ AVRO_UNUSED(dest);
+
+ debug("Starting map %p", dest);
+ }
+
+ AVRO_UNUSED(block_count);
+ return 0;
+}
+
+static int
+avro_resolver_map_element(avro_consumer_t *consumer,
+ unsigned int index,
+ const char *key,
+ avro_consumer_t **value_consumer,
+ void **value_user_data,
+ void *user_data)
+{
+ AVRO_UNUSED(index);
+
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ debug("Adding element to map %p", dest);
+
+ /*
+ * Allocate a new element datum and add it to the map.
+ */
+
+ avro_schema_t map_schema = avro_datum_get_schema(dest);
+ avro_schema_t value_schema = avro_schema_map_values(map_schema);
+ avro_datum_t value = avro_datum_from_schema(value_schema);
+ avro_map_set(dest, key, value);
+ avro_datum_decref(value);
+
+ /*
+ * Return the consumer that we allocated to process the map's
+ * children.
+ */
+
+ *value_consumer = resolver->child_resolvers[0];
+ *value_user_data = value;
+ return 0;
+}
+
+static int
+try_map(avro_memoize_t *mem, avro_resolver_t **resolver,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ /*
+ * First verify that the reader is an map.
+ */
+
+ if (!is_avro_map(rschema)) {
+ return 0;
+ }
+
+ /*
+ * Array schemas have to have compatible element schemas to be
+ * compatible themselves. Try to create an avro_resolver_t to
+ * check the compatibility.
+ */
+
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+
+ avro_schema_t wvalues = avro_schema_map_values(wschema);
+ avro_schema_t rvalues = avro_schema_map_values(rschema);
+
+ avro_consumer_t *value_consumer =
+ avro_resolver_new_memoized(mem, wvalues, rvalues);
+ if (!value_consumer) {
+ avro_memoize_delete(mem, wschema, root_rschema);
+ avro_consumer_free(&(*resolver)->parent);
+ avro_prefix_error("Map values aren't compatible: ");
+ return EINVAL;
+ }
+
+ /*
+ * The two schemas are compatible, so go ahead and create a
+ * GavroResolver for the map. Store the value schema's
+ * resolver into the child_resolvers field.
+ */
+
+ (*resolver)->num_children = 1;
+ (*resolver)->child_resolvers = (avro_consumer_t **) avro_calloc(1, sizeof(avro_consumer_t *));
+ (*resolver)->child_resolvers[0] = value_consumer;
+ (*resolver)->parent.map_start_block = avro_resolver_map_start_block;
+ (*resolver)->parent.map_element = avro_resolver_map_element;
+
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------------
+ * records
+ */
+
+static int
+avro_resolver_record_start(avro_consumer_t *consumer,
+ void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+ AVRO_UNUSED(dest);
+
+ debug("Starting record at %p", dest);
+
+ /*
+ * TODO: Eventually, we'll fill in default values for the extra
+ * reader fields here.
+ */
+
+ return 0;
+}
+
+static int
+avro_resolver_record_field(avro_consumer_t *consumer,
+ unsigned int index,
+ avro_consumer_t **field_consumer,
+ void **field_user_data,
+ void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+ avro_datum_t ud_dest = (avro_datum_t) user_data;
+ avro_datum_t dest = avro_resolver_get_real_dest(resolver, ud_dest);
+
+ const char *field_name =
+ avro_schema_record_field_name(consumer->schema, index);
+
+ /*
+ * Grab the resolver for this field of the writer record. If
+ * it's NULL, this this field doesn't exist in the reader
+ * record, and should be skipped.
+ */
+
+ debug("Retrieving resolver for writer field %i (%s)",
+ index, field_name);
+
+ if (!resolver->child_resolvers[index]) {
+ debug("Reader doesn't have field %s, skipping", field_name);
+ return 0;
+ }
+
+ /*
+ * TODO: Once we can retrieve record fields by index (quickly),
+ * use the index_mapping.
+ */
+
+ avro_datum_t field = NULL;
+ avro_record_get(dest, field_name, &field);
+
+ *field_consumer = resolver->child_resolvers[index];
+ *field_user_data = field;
+ return 0;
+}
+
+static int
+try_record(avro_memoize_t *mem, avro_resolver_t **resolver,
+ avro_schema_t wschema, avro_schema_t rschema,
+ avro_schema_t root_rschema)
+{
+ /*
+ * First verify that the reader is also a record, and has the
+ * same name as the writer.
+ */
+
+ if (!is_avro_record(rschema)) {
+ return 0;
+ }
+
+ const char *wname = avro_schema_name(wschema);
+ const char *rname = avro_schema_name(rschema);
+
+ if (strcmp(wname, rname)) {
+ return 0;
+ }
+
+ /*
+ * Categorize the fields in the record schemas. Fields that are
+ * only in the writer are ignored. Fields that are only in the
+ * reader raise a schema mismatch error, unless the field has a
+ * default value. Fields that are in both are resolved
+ * recursively.
+ *
+ * The child_resolver array will contain an avro_resolver_t for
+ * each field in the writer schema. To build this array, we
+ * loop through the fields of the reader schema. If that field
+ * is also in the writer schema, we resolve them recursively,
+ * and store the resolver into the array. If the field isn't in
+ * the writer schema, we raise an error. (TODO: Eventually,
+ * we'll handle default values here.) After this loop finishes,
+ * any NULLs in the child_resolver array will represent fields
+ * in the writer but not the reader; these fields will be
+ * skipped when processing the input.
+ */
+
+ *resolver = avro_resolver_create(wschema, root_rschema);
+ avro_memoize_set(mem, wschema, root_rschema, *resolver);
+
+ size_t wfields = avro_schema_record_size(wschema);
+ size_t rfields = avro_schema_record_size(rschema);
+
+ debug("Checking writer record schema %s", wname);
+
+ avro_consumer_t **child_resolvers =
+ (avro_consumer_t **) avro_calloc(wfields, sizeof(avro_consumer_t *));
+ int *index_mapping = (int *) avro_calloc(wfields, sizeof(int));
+
+ unsigned int ri;
+ for (ri = 0; ri < rfields; ri++) {
+ avro_schema_t rfield =
+ avro_schema_record_field_get_by_index(rschema, ri);
+ const char *field_name =
+ avro_schema_record_field_name(rschema, ri);
+
+ debug("Resolving reader record field %u (%s)", ri, field_name);
+
+ /*
+ * See if this field is also in the writer schema.
+ */
+
+ int wi = avro_schema_record_field_get_index(wschema, field_name);
+
+ if (wi == -1) {
+ /*
+ * This field isn't in the writer schema —
+ * that's an error! TODO: Handle default
+ * values!
+ */
+
+ debug("Field %s isn't in writer", field_name);
+ avro_set_error("Reader field %s doesn't appear in writer",
+ field_name);
+ goto error;
+ }
+
+ /*
+ * Try to recursively resolve the schemas for this
+ * field. If they're not compatible, that's an error.
+ */
+
+ avro_schema_t wfield =
+ avro_schema_record_field_get_by_index(wschema, wi);
+ avro_consumer_t *field_resolver =
+ avro_resolver_new_memoized(mem, wfield, rfield);
+
+ if (!field_resolver) {
+ avro_prefix_error("Field %s isn't compatible: ", field_name);
+ goto error;
+ }
+
+ /*
+ * Save the details for this field.
+ */
+
+ debug("Found match for field %s (%u in reader, %d in writer)",
+ field_name, ri, wi);
+ child_resolvers[wi] = field_resolver;
+ index_mapping[wi] = ri;
+ }
+
+ /*
+ * We might not have found matches for all of the writer fields,
+ * but that's okay — any extras will be ignored.
+ */
+
+ (*resolver)->num_children = wfields;
+ (*resolver)->child_resolvers = child_resolvers;
+ (*resolver)->index_mapping = index_mapping;
+ (*resolver)->parent.record_start = avro_resolver_record_start;
+ (*resolver)->parent.record_field = avro_resolver_record_field;
+ return 0;
+
+error:
+ /*
+ * Clean up any consumer we might have already created.
+ */
+
+ avro_memoize_delete(mem, wschema, root_rschema);
+ avro_consumer_free(&(*resolver)->parent);
+
+ {
+ unsigned int i;
+ for (i = 0; i < wfields; i++) {
+ if (child_resolvers[i]) {
+ avro_consumer_free(child_resolvers[i]);
+ }
+ }
+ }
+
+ avro_free(child_resolvers, wfields * sizeof(avro_consumer_t *));
+ avro_free(index_mapping, wfields * sizeof(int));
+ return EINVAL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * union
+ */
+
+static int
+avro_resolver_union_branch(avro_consumer_t *consumer,
+ unsigned int discriminant,
+ avro_consumer_t **branch_consumer,
+ void **branch_user_data,
+ void *user_data)
+{
+ avro_resolver_t *resolver = (avro_resolver_t *) consumer;
+
+ /*
+ * Grab the resolver for this branch of the writer union. If
+ * it's NULL, then this branch is incompatible with the reader.
+ */
+
+ debug("Retrieving resolver for writer branch %u", discriminant);
+
+ if (!resolver->child_resolvers[discriminant]) {
+ avro_set_error("Writer union branch %u is incompatible "
+ "with reader schema \"%s\"",
+ discriminant, avro_schema_type_name(resolver->rschema));
+ return EINVAL;
+ }
+
+ /*
+ * Return the branch's resolver.
+ */
+
+ *branch_consumer = resolver->child_resolvers[discriminant];
+ *branch_user_data = user_data;
+ return 0;
+}
+
+static avro_consumer_t *
+try_union(avro_memoize_t *mem, avro_schema_t wschema, avro_schema_t rschema)
+{
+ /*
+ * For a writer union, we recursively try to resolve each branch
+ * against the reader schema. This will work correctly whether
+ * or not the reader is also a union — if the reader is a union,
+ * then we'll resolve each (non-union) writer branch against the
+ * reader union, which will be checked in our calls to
+ * check_simple_writer below. The net result is that we might
+ * end up trying every combination of writer and reader
+ * branches, when looking for compatible schemas.
+ *
+ * Regardless of what the reader schema is, for each writer
+ * branch, we stash away the recursive avro_resolver_t into the
+ * child_resolvers array. A NULL entry in this array means that
+ * that branch isn't compatible with the reader. This isn't an
+ * immediate schema resolution error, since we allow
+ * incompatible branches in the types as long as that branch
+ * never appears in the actual data. We only return an error if
+ * there are *no* branches that are compatible.
+ */
+
+ size_t num_branches = avro_schema_union_size(wschema);
+ debug("Checking %" PRIsz "-branch writer union schema", num_branches);
+
+ avro_resolver_t *resolver = avro_resolver_create(wschema, rschema);
+ avro_memoize_set(mem, wschema, rschema, resolver);
+
+ avro_consumer_t **child_resolvers =
+ (avro_consumer_t **) avro_calloc(num_branches, sizeof(avro_consumer_t *));
+ int some_branch_compatible = 0;
+
+ unsigned int i;
+ for (i = 0; i < num_branches; i++) {
+ avro_schema_t branch_schema =
+ avro_schema_union_branch(wschema, i);
+
+ debug("Resolving writer union branch %u (%s)",
+ i, avro_schema_type_name(branch_schema));
+
+ /*
+ * Try to recursively resolve this branch of the writer
+ * union. Don't raise an error if this fails — it's
+ * okay for some of the branches to not be compatible
+ * with the reader, as long as those branches never
+ * appear in the input.
+ */
+
+ child_resolvers[i] =
+ avro_resolver_new_memoized(mem, branch_schema, rschema);
+ if (child_resolvers[i]) {
+ debug("Found match for writer union branch %u", i);
+ some_branch_compatible = 1;
+ } else {
+ debug("No match for writer union branch %u", i);
+ }
+ }
+
+ /*
+ * As long as there's at least one branch that's compatible with
+ * the reader, then we consider this schema resolution a
+ * success.
+ */
+
+ if (!some_branch_compatible) {
+ debug("No writer union branches match");
+ avro_set_error("No branches in the writer are compatible "
+ "with reader schema %s",
+ avro_schema_type_name(rschema));
+ goto error;
+ }
+
+ resolver->num_children = num_branches;
+ resolver->child_resolvers = child_resolvers;
+ resolver->parent.union_branch = avro_resolver_union_branch;
+ return &resolver->parent;
+
+error:
+ /*
+ * Clean up any consumer we might have already created.
+ */
+
+ avro_memoize_delete(mem, wschema, rschema);
+ avro_consumer_free(&resolver->parent);
+
+ for (i = 0; i < num_branches; i++) {
+ if (child_resolvers[i]) {
+ avro_consumer_free(child_resolvers[i]);
+ }
+ }
+
+ avro_free(child_resolvers, num_branches * sizeof(avro_consumer_t *));
+ return NULL;
+}
+
+
+/*-----------------------------------------------------------------------
+ * schema type dispatcher
+ */
+
+static avro_consumer_t *
+avro_resolver_new_memoized(avro_memoize_t *mem,
+ avro_schema_t wschema, avro_schema_t rschema)
+{
+ check_param(NULL, is_avro_schema(wschema), "writer schema");
+ check_param(NULL, is_avro_schema(rschema), "reader schema");
+
+ skip_links(wschema);
+ skip_links(rschema);
+
+ /*
+ * First see if we've already matched these two schemas. If so,
+ * just return that resolver.
+ */
+
+ avro_resolver_t *saved = NULL;
+ if (avro_memoize_get(mem, wschema, rschema, (void **) &saved)) {
+ debug("Already resolved %s and %s",
+ avro_schema_type_name(wschema),
+ avro_schema_type_name(rschema));
+ return &saved->parent;
+ }
+
+ /*
+ * Otherwise we have some work to do.
+ */
+
+ switch (avro_typeof(wschema))
+ {
+ case AVRO_BOOLEAN:
+ check_simple_writer(mem, wschema, rschema, boolean);
+ return NULL;
+
+ case AVRO_BYTES:
+ check_simple_writer(mem, wschema, rschema, bytes);
+ return NULL;
+
+ case AVRO_DOUBLE:
+ check_simple_writer(mem, wschema, rschema, double);
+ return NULL;
+
+ case AVRO_FLOAT:
+ check_simple_writer(mem, wschema, rschema, float);
+ return NULL;
+
+ case AVRO_INT32:
+ check_simple_writer(mem, wschema, rschema, int);
+ return NULL;
+
+ case AVRO_INT64:
+ check_simple_writer(mem, wschema, rschema, long);
+ return NULL;
+
+ case AVRO_NULL:
+ check_simple_writer(mem, wschema, rschema, null);
+ return NULL;
+
+ case AVRO_STRING:
+ check_simple_writer(mem, wschema, rschema, string);
+ return NULL;
+
+ case AVRO_ARRAY:
+ check_simple_writer(mem, wschema, rschema, array);
+ return NULL;
+
+ case AVRO_ENUM:
+ check_simple_writer(mem, wschema, rschema, enum);
+ return NULL;
+
+ case AVRO_FIXED:
+ check_simple_writer(mem, wschema, rschema, fixed);
+ return NULL;
+
+ case AVRO_MAP:
+ check_simple_writer(mem, wschema, rschema, map);
+ return NULL;
+
+ case AVRO_RECORD:
+ check_simple_writer(mem, wschema, rschema, record);
+ return NULL;
+
+ case AVRO_UNION:
+ return try_union(mem, wschema, rschema);
+
+ default:
+ avro_set_error("Unknown schema type");
+ return NULL;
+ }
+
+ return NULL;
+}
+
+
+avro_consumer_t *
+avro_resolver_new(avro_schema_t wschema, avro_schema_t rschema)
+{
+ avro_memoize_t mem;
+ avro_memoize_init(&mem);
+ avro_consumer_t *result =
+ avro_resolver_new_memoized(&mem, wschema, rschema);
+ avro_memoize_done(&mem);
+ return result;
+}
diff --git a/fluent-bit/lib/avro/src/schema.c b/fluent-bit/lib/avro/src/schema.c
new file mode 100644
index 000000000..7b389002b
--- /dev/null
+++ b/fluent-bit/lib/avro/src/schema.c
@@ -0,0 +1,1897 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include "avro/allocation.h"
+#include "avro/refcount.h"
+#include "avro/errors.h"
+#include "avro/io.h"
+#include "avro/legacy.h"
+#include "avro/schema.h"
+#include "avro_private.h"
+#include <avro/platform.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "jansson.h"
+#include "st.h"
+#include "schema.h"
+
+#define DEFAULT_TABLE_SIZE 32
+
+/* forward declaration */
+static int
+avro_schema_to_json2(const avro_schema_t schema, avro_writer_t out,
+ const char *parent_namespace);
+
+static void avro_schema_init(avro_schema_t schema, avro_type_t type)
+{
+ schema->type = type;
+ schema->class_type = AVRO_SCHEMA;
+ avro_refcount_set(&schema->refcount, 1);
+}
+
+static int is_avro_id(const char *name)
+{
+ size_t i, len;
+ if (name) {
+ len = strlen(name);
+ if (len < 1) {
+ return 0;
+ }
+ for (i = 0; i < len; i++) {
+ if (!(isalpha(name[i])
+ || name[i] == '_' || (i && isdigit(name[i])))) {
+ return 0;
+ }
+ }
+ /*
+ * starts with [A-Za-z_] subsequent [A-Za-z0-9_]
+ */
+ return 1;
+ }
+ return 0;
+}
+
+/* Splits a qualified name by the last period, e.g. fullname "foo.bar.Baz" into
+ * name "Baz" and namespace "foo.bar". Sets name_out to the name part (pointing
+ * to a later position in the buffer that was passed in), and returns the
+ * namespace (as a newly allocated buffer using Avro's allocator). */
+static char *split_namespace_name(const char *fullname, const char **name_out)
+{
+ char *last_dot = strrchr(fullname, '.');
+ if (last_dot == NULL) {
+ *name_out = fullname;
+ return NULL;
+ } else {
+ *name_out = last_dot + 1;
+ return avro_strndup(fullname, last_dot - fullname);
+ }
+}
+
+static int record_free_foreach(int i, struct avro_record_field_t *field,
+ void *arg)
+{
+ AVRO_UNUSED(i);
+ AVRO_UNUSED(arg);
+
+ avro_str_free(field->name);
+ avro_schema_decref(field->type);
+ avro_freet(struct avro_record_field_t, field);
+ return ST_DELETE;
+}
+
+static int enum_free_foreach(int i, char *sym, void *arg)
+{
+ AVRO_UNUSED(i);
+ AVRO_UNUSED(arg);
+
+ avro_str_free(sym);
+ return ST_DELETE;
+}
+
+static int union_free_foreach(int i, avro_schema_t schema, void *arg)
+{
+ AVRO_UNUSED(i);
+ AVRO_UNUSED(arg);
+
+ avro_schema_decref(schema);
+ return ST_DELETE;
+}
+
+static void avro_schema_free(avro_schema_t schema)
+{
+ if (is_avro_schema(schema)) {
+ switch (avro_typeof(schema)) {
+ case AVRO_STRING:
+ case AVRO_BYTES:
+ case AVRO_INT32:
+ case AVRO_INT64:
+ case AVRO_FLOAT:
+ case AVRO_DOUBLE:
+ case AVRO_BOOLEAN:
+ case AVRO_NULL:
+ /* no memory allocated for primitives */
+ return;
+
+ case AVRO_RECORD:{
+ struct avro_record_schema_t *record;
+ record = avro_schema_to_record(schema);
+ avro_str_free(record->name);
+ if (record->space) {
+ avro_str_free(record->space);
+ }
+ st_foreach(record->fields, HASH_FUNCTION_CAST record_free_foreach,
+ 0);
+ st_free_table(record->fields_byname);
+ st_free_table(record->fields);
+ avro_freet(struct avro_record_schema_t, record);
+ }
+ break;
+
+ case AVRO_ENUM:{
+ struct avro_enum_schema_t *enump;
+ enump = avro_schema_to_enum(schema);
+ avro_str_free(enump->name);
+ if (enump->space) {
+ avro_str_free(enump->space);
+ }
+ st_foreach(enump->symbols, HASH_FUNCTION_CAST enum_free_foreach,
+ 0);
+ st_free_table(enump->symbols);
+ st_free_table(enump->symbols_byname);
+ avro_freet(struct avro_enum_schema_t, enump);
+ }
+ break;
+
+ case AVRO_FIXED:{
+ struct avro_fixed_schema_t *fixed;
+ fixed = avro_schema_to_fixed(schema);
+ avro_str_free((char *) fixed->name);
+ if (fixed->space) {
+ avro_str_free((char *) fixed->space);
+ }
+ avro_freet(struct avro_fixed_schema_t, fixed);
+ }
+ break;
+
+ case AVRO_MAP:{
+ struct avro_map_schema_t *map;
+ map = avro_schema_to_map(schema);
+ avro_schema_decref(map->values);
+ avro_freet(struct avro_map_schema_t, map);
+ }
+ break;
+
+ case AVRO_ARRAY:{
+ struct avro_array_schema_t *array;
+ array = avro_schema_to_array(schema);
+ avro_schema_decref(array->items);
+ avro_freet(struct avro_array_schema_t, array);
+ }
+ break;
+ case AVRO_UNION:{
+ struct avro_union_schema_t *unionp;
+ unionp = avro_schema_to_union(schema);
+ st_foreach(unionp->branches, HASH_FUNCTION_CAST union_free_foreach,
+ 0);
+ st_free_table(unionp->branches);
+ st_free_table(unionp->branches_byname);
+ avro_freet(struct avro_union_schema_t, unionp);
+ }
+ break;
+
+ case AVRO_LINK:{
+ struct avro_link_schema_t *link;
+ link = avro_schema_to_link(schema);
+ /* Since we didn't increment the
+ * reference count of the target
+ * schema when we created the link, we
+ * should not decrement the reference
+ * count of the target schema when we
+ * free the link.
+ */
+ avro_freet(struct avro_link_schema_t, link);
+ }
+ break;
+ }
+ }
+}
+
+avro_schema_t avro_schema_incref(avro_schema_t schema)
+{
+ if (schema) {
+ avro_refcount_inc(&schema->refcount);
+ }
+ return schema;
+}
+
+int
+avro_schema_decref(avro_schema_t schema)
+{
+ if (schema && avro_refcount_dec(&schema->refcount)) {
+ avro_schema_free(schema);
+ return 0;
+ }
+ return 1;
+}
+
+avro_schema_t avro_schema_string(void)
+{
+ static struct avro_obj_t obj = {
+ AVRO_STRING,
+ AVRO_SCHEMA,
+ 1
+ };
+ return avro_schema_incref(&obj);
+}
+
+avro_schema_t avro_schema_bytes(void)
+{
+ static struct avro_obj_t obj = {
+ AVRO_BYTES,
+ AVRO_SCHEMA,
+ 1
+ };
+ return avro_schema_incref(&obj);
+}
+
+avro_schema_t avro_schema_int(void)
+{
+ static struct avro_obj_t obj = {
+ AVRO_INT32,
+ AVRO_SCHEMA,
+ 1
+ };
+ return avro_schema_incref(&obj);
+}
+
+avro_schema_t avro_schema_long(void)
+{
+ static struct avro_obj_t obj = {
+ AVRO_INT64,
+ AVRO_SCHEMA,
+ 1
+ };
+ return avro_schema_incref(&obj);
+}
+
+avro_schema_t avro_schema_float(void)
+{
+ static struct avro_obj_t obj = {
+ AVRO_FLOAT,
+ AVRO_SCHEMA,
+ 1
+ };
+ return avro_schema_incref(&obj);
+}
+
+avro_schema_t avro_schema_double(void)
+{
+ static struct avro_obj_t obj = {
+ AVRO_DOUBLE,
+ AVRO_SCHEMA,
+ 1
+ };
+ return avro_schema_incref(&obj);
+}
+
+avro_schema_t avro_schema_boolean(void)
+{
+ static struct avro_obj_t obj = {
+ AVRO_BOOLEAN,
+ AVRO_SCHEMA,
+ 1
+ };
+ return avro_schema_incref(&obj);
+}
+
+avro_schema_t avro_schema_null(void)
+{
+ static struct avro_obj_t obj = {
+ AVRO_NULL,
+ AVRO_SCHEMA,
+ 1
+ };
+ return avro_schema_incref(&obj);
+}
+
+avro_schema_t avro_schema_fixed(const char *name, const int64_t size)
+{
+ return avro_schema_fixed_ns(name, NULL, size);
+}
+
+avro_schema_t avro_schema_fixed_ns(const char *name, const char *space,
+ const int64_t size)
+{
+ if (!is_avro_id(name)) {
+ avro_set_error("Invalid Avro identifier");
+ return NULL;
+ }
+
+ struct avro_fixed_schema_t *fixed =
+ (struct avro_fixed_schema_t *) avro_new(struct avro_fixed_schema_t);
+ if (!fixed) {
+ avro_set_error("Cannot allocate new fixed schema");
+ return NULL;
+ }
+ fixed->name = avro_strdup(name);
+ if (!fixed->name) {
+ avro_set_error("Cannot allocate new fixed schema");
+ avro_freet(struct avro_fixed_schema_t, fixed);
+ return NULL;
+ }
+ fixed->space = space ? avro_strdup(space) : NULL;
+ if (space && !fixed->space) {
+ avro_set_error("Cannot allocate new fixed schema");
+ avro_str_free((char *) fixed->name);
+ avro_freet(struct avro_fixed_schema_t, fixed);
+ return NULL;
+ }
+ fixed->size = size;
+ avro_schema_init(&fixed->obj, AVRO_FIXED);
+ return &fixed->obj;
+}
+
+int64_t avro_schema_fixed_size(const avro_schema_t fixed)
+{
+ return avro_schema_to_fixed(fixed)->size;
+}
+
+avro_schema_t avro_schema_union(void)
+{
+ struct avro_union_schema_t *schema =
+ (struct avro_union_schema_t *) avro_new(struct avro_union_schema_t);
+ if (!schema) {
+ avro_set_error("Cannot allocate new union schema");
+ return NULL;
+ }
+ schema->branches = st_init_numtable_with_size(DEFAULT_TABLE_SIZE);
+ if (!schema->branches) {
+ avro_set_error("Cannot allocate new union schema");
+ avro_freet(struct avro_union_schema_t, schema);
+ return NULL;
+ }
+ schema->branches_byname =
+ st_init_strtable_with_size(DEFAULT_TABLE_SIZE);
+ if (!schema->branches_byname) {
+ avro_set_error("Cannot allocate new union schema");
+ st_free_table(schema->branches);
+ avro_freet(struct avro_union_schema_t, schema);
+ return NULL;
+ }
+
+ avro_schema_init(&schema->obj, AVRO_UNION);
+ return &schema->obj;
+}
+
+int
+avro_schema_union_append(const avro_schema_t union_schema,
+ const avro_schema_t schema)
+{
+ check_param(EINVAL, is_avro_schema(union_schema), "union schema");
+ check_param(EINVAL, is_avro_union(union_schema), "union schema");
+ check_param(EINVAL, is_avro_schema(schema), "schema");
+
+ struct avro_union_schema_t *unionp = avro_schema_to_union(union_schema);
+ int new_index = unionp->branches->num_entries;
+ st_insert(unionp->branches, new_index, (st_data_t) schema);
+ const char *name = avro_schema_type_name(schema);
+ st_insert(unionp->branches_byname, (st_data_t) name,
+ (st_data_t) new_index);
+ avro_schema_incref(schema);
+ return 0;
+}
+
+size_t avro_schema_union_size(const avro_schema_t union_schema)
+{
+ check_param(EINVAL, is_avro_schema(union_schema), "union schema");
+ check_param(EINVAL, is_avro_union(union_schema), "union schema");
+ struct avro_union_schema_t *unionp = avro_schema_to_union(union_schema);
+ return unionp->branches->num_entries;
+}
+
+avro_schema_t avro_schema_union_branch(avro_schema_t unionp,
+ int branch_index)
+{
+ union {
+ st_data_t data;
+ avro_schema_t schema;
+ } val;
+ if (st_lookup(avro_schema_to_union(unionp)->branches,
+ branch_index, &val.data)) {
+ return val.schema;
+ } else {
+ avro_set_error("No union branch for discriminant %d",
+ branch_index);
+ return NULL;
+ }
+}
+
+avro_schema_t avro_schema_union_branch_by_name
+(avro_schema_t unionp, int *branch_index, const char *name)
+{
+ union {
+ st_data_t data;
+ int branch_index;
+ } val;
+
+ if (!st_lookup(avro_schema_to_union(unionp)->branches_byname,
+ (st_data_t) name, &val.data)) {
+ avro_set_error("No union branch named %s", name);
+ return NULL;
+ }
+
+ if (branch_index != NULL) {
+ *branch_index = val.branch_index;
+ }
+ return avro_schema_union_branch(unionp, val.branch_index);
+}
+
+avro_schema_t avro_schema_array(const avro_schema_t items)
+{
+ struct avro_array_schema_t *array =
+ (struct avro_array_schema_t *) avro_new(struct avro_array_schema_t);
+ if (!array) {
+ avro_set_error("Cannot allocate new array schema");
+ return NULL;
+ }
+ array->items = avro_schema_incref(items);
+ avro_schema_init(&array->obj, AVRO_ARRAY);
+ return &array->obj;
+}
+
+avro_schema_t avro_schema_array_items(avro_schema_t array)
+{
+ return avro_schema_to_array(array)->items;
+}
+
+avro_schema_t avro_schema_map(const avro_schema_t values)
+{
+ struct avro_map_schema_t *map =
+ (struct avro_map_schema_t *) avro_new(struct avro_map_schema_t);
+ if (!map) {
+ avro_set_error("Cannot allocate new map schema");
+ return NULL;
+ }
+ map->values = avro_schema_incref(values);
+ avro_schema_init(&map->obj, AVRO_MAP);
+ return &map->obj;
+}
+
+avro_schema_t avro_schema_map_values(avro_schema_t map)
+{
+ return avro_schema_to_map(map)->values;
+}
+
+avro_schema_t avro_schema_enum(const char *name)
+{
+ return avro_schema_enum_ns(name, NULL);
+}
+
+avro_schema_t avro_schema_enum_ns(const char *name, const char *space)
+{
+ if (!is_avro_id(name)) {
+ avro_set_error("Invalid Avro identifier");
+ return NULL;
+ }
+
+ struct avro_enum_schema_t *enump = (struct avro_enum_schema_t *) avro_new(struct avro_enum_schema_t);
+ if (!enump) {
+ avro_set_error("Cannot allocate new enum schema");
+ return NULL;
+ }
+ enump->name = avro_strdup(name);
+ if (!enump->name) {
+ avro_set_error("Cannot allocate new enum schema");
+ avro_freet(struct avro_enum_schema_t, enump);
+ return NULL;
+ }
+ enump->space = space ? avro_strdup(space) : NULL;
+ if (space && !enump->space) {
+ avro_set_error("Cannot allocate new enum schema");
+ avro_str_free(enump->name);
+ avro_freet(struct avro_enum_schema_t, enump);
+ return NULL;
+ }
+ enump->symbols = st_init_numtable_with_size(DEFAULT_TABLE_SIZE);
+ if (!enump->symbols) {
+ avro_set_error("Cannot allocate new enum schema");
+ if (enump->space) avro_str_free(enump->space);
+ avro_str_free(enump->name);
+ avro_freet(struct avro_enum_schema_t, enump);
+ return NULL;
+ }
+ enump->symbols_byname = st_init_strtable_with_size(DEFAULT_TABLE_SIZE);
+ if (!enump->symbols_byname) {
+ avro_set_error("Cannot allocate new enum schema");
+ st_free_table(enump->symbols);
+ if (enump->space) avro_str_free(enump->space);
+ avro_str_free(enump->name);
+ avro_freet(struct avro_enum_schema_t, enump);
+ return NULL;
+ }
+ avro_schema_init(&enump->obj, AVRO_ENUM);
+ return &enump->obj;
+}
+
+const char *avro_schema_enum_get(const avro_schema_t enump,
+ int index)
+{
+ union {
+ st_data_t data;
+ char *sym;
+ } val;
+ st_lookup(avro_schema_to_enum(enump)->symbols, index, &val.data);
+ return val.sym;
+}
+
+int avro_schema_enum_get_by_name(const avro_schema_t enump,
+ const char *symbol_name)
+{
+ union {
+ st_data_t data;
+ long idx;
+ } val;
+
+ if (st_lookup(avro_schema_to_enum(enump)->symbols_byname,
+ (st_data_t) symbol_name, &val.data)) {
+ return val.idx;
+ } else {
+ avro_set_error("No enum symbol named %s", symbol_name);
+ return -1;
+ }
+}
+
+int
+avro_schema_enum_symbol_append(const avro_schema_t enum_schema,
+ const char *symbol)
+{
+ check_param(EINVAL, is_avro_schema(enum_schema), "enum schema");
+ check_param(EINVAL, is_avro_enum(enum_schema), "enum schema");
+ check_param(EINVAL, symbol, "symbol");
+
+ char *sym;
+ long idx;
+ struct avro_enum_schema_t *enump = avro_schema_to_enum(enum_schema);
+ sym = avro_strdup(symbol);
+ if (!sym) {
+ avro_set_error("Cannot create copy of symbol name");
+ return ENOMEM;
+ }
+ idx = enump->symbols->num_entries;
+ st_insert(enump->symbols, (st_data_t) idx, (st_data_t) sym);
+ st_insert(enump->symbols_byname, (st_data_t) sym, (st_data_t) idx);
+ return 0;
+}
+
+int
+avro_schema_enum_number_of_symbols(const avro_schema_t enum_schema)
+{
+ check_param(EINVAL, is_avro_schema(enum_schema), "enum schema");
+ check_param(EINVAL, is_avro_enum(enum_schema), "enum schema");
+
+ struct avro_enum_schema_t *enump = avro_schema_to_enum(enum_schema);
+ return enump->symbols->num_entries;
+}
+
+int
+avro_schema_record_field_append(const avro_schema_t record_schema,
+ const char *field_name,
+ const avro_schema_t field_schema)
+{
+ check_param(EINVAL, is_avro_schema(record_schema), "record schema");
+ check_param(EINVAL, is_avro_record(record_schema), "record schema");
+ check_param(EINVAL, field_name, "field name");
+ check_param(EINVAL, is_avro_schema(field_schema), "field schema");
+
+ if (!is_avro_id(field_name)) {
+ avro_set_error("Invalid Avro identifier");
+ return EINVAL;
+ }
+
+ if (record_schema == field_schema) {
+ avro_set_error("Cannot create a circular schema");
+ return EINVAL;
+ }
+
+ struct avro_record_schema_t *record = avro_schema_to_record(record_schema);
+ struct avro_record_field_t *new_field = (struct avro_record_field_t *) avro_new(struct avro_record_field_t);
+ if (!new_field) {
+ avro_set_error("Cannot allocate new record field");
+ return ENOMEM;
+ }
+ new_field->index = record->fields->num_entries;
+ new_field->name = avro_strdup(field_name);
+ new_field->type = avro_schema_incref(field_schema);
+ st_insert(record->fields, record->fields->num_entries,
+ (st_data_t) new_field);
+ st_insert(record->fields_byname, (st_data_t) new_field->name,
+ (st_data_t) new_field);
+ return 0;
+}
+
+avro_schema_t avro_schema_record(const char *name, const char *space)
+{
+ if (!is_avro_id(name)) {
+ avro_set_error("Invalid Avro identifier");
+ return NULL;
+ }
+
+ struct avro_record_schema_t *record = (struct avro_record_schema_t *) avro_new(struct avro_record_schema_t);
+ if (!record) {
+ avro_set_error("Cannot allocate new record schema");
+ return NULL;
+ }
+ record->name = avro_strdup(name);
+ if (!record->name) {
+ avro_set_error("Cannot allocate new record schema");
+ avro_freet(struct avro_record_schema_t, record);
+ return NULL;
+ }
+ record->space = space ? avro_strdup(space) : NULL;
+ if (space && !record->space) {
+ avro_set_error("Cannot allocate new record schema");
+ avro_str_free(record->name);
+ avro_freet(struct avro_record_schema_t, record);
+ return NULL;
+ }
+ record->fields = st_init_numtable_with_size(DEFAULT_TABLE_SIZE);
+ if (!record->fields) {
+ avro_set_error("Cannot allocate new record schema");
+ if (record->space) {
+ avro_str_free(record->space);
+ }
+ avro_str_free(record->name);
+ avro_freet(struct avro_record_schema_t, record);
+ return NULL;
+ }
+ record->fields_byname = st_init_strtable_with_size(DEFAULT_TABLE_SIZE);
+ if (!record->fields_byname) {
+ avro_set_error("Cannot allocate new record schema");
+ st_free_table(record->fields);
+ if (record->space) {
+ avro_str_free(record->space);
+ }
+ avro_str_free(record->name);
+ avro_freet(struct avro_record_schema_t, record);
+ return NULL;
+ }
+
+ avro_schema_init(&record->obj, AVRO_RECORD);
+ return &record->obj;
+}
+
+size_t avro_schema_record_size(const avro_schema_t record)
+{
+ return avro_schema_to_record(record)->fields->num_entries;
+}
+
+avro_schema_t avro_schema_record_field_get(const avro_schema_t
+ record, const char *field_name)
+{
+ union {
+ st_data_t data;
+ struct avro_record_field_t *field;
+ } val;
+ st_lookup(avro_schema_to_record(record)->fields_byname,
+ (st_data_t) field_name, &val.data);
+ return val.field->type;
+}
+
+int avro_schema_record_field_get_index(const avro_schema_t schema,
+ const char *field_name)
+{
+ union {
+ st_data_t data;
+ struct avro_record_field_t *field;
+ } val;
+ if (st_lookup(avro_schema_to_record(schema)->fields_byname,
+ (st_data_t) field_name, &val.data)) {
+ return val.field->index;
+ }
+
+ avro_set_error("No field named %s in record", field_name);
+ return -1;
+}
+
+const char *avro_schema_record_field_name(const avro_schema_t schema, int index)
+{
+ union {
+ st_data_t data;
+ struct avro_record_field_t *field;
+ } val;
+ st_lookup(avro_schema_to_record(schema)->fields, index, &val.data);
+ return val.field->name;
+}
+
+avro_schema_t avro_schema_record_field_get_by_index
+(const avro_schema_t record, int index)
+{
+ union {
+ st_data_t data;
+ struct avro_record_field_t *field;
+ } val;
+ st_lookup(avro_schema_to_record(record)->fields, index, &val.data);
+ return val.field->type;
+}
+
+avro_schema_t avro_schema_link(avro_schema_t to)
+{
+ if (!is_avro_named_type(to)) {
+ avro_set_error("Can only link to named types");
+ return NULL;
+ }
+
+ struct avro_link_schema_t *link = (struct avro_link_schema_t *) avro_new(struct avro_link_schema_t);
+ if (!link) {
+ avro_set_error("Cannot allocate new link schema");
+ return NULL;
+ }
+
+ /* Do not increment the reference count of target schema
+ * pointed to by the AVRO_LINK. AVRO_LINKs are only valid
+ * internal to a schema. The target schema pointed to by a
+ * link will be valid as long as the top-level schema is
+ * valid. Similarly, the link will be valid as long as the
+ * top-level schema is valid. Therefore the validity of the
+ * link ensures the validity of its target, and we don't need
+ * an additional reference count on the target. This mechanism
+ * of an implied validity also breaks reference count cycles
+ * for recursive schemas, which result in memory leaks.
+ */
+ link->to = to;
+ avro_schema_init(&link->obj, AVRO_LINK);
+ return &link->obj;
+}
+
+avro_schema_t avro_schema_link_target(avro_schema_t schema)
+{
+ check_param(NULL, is_avro_schema(schema), "schema");
+ check_param(NULL, is_avro_link(schema), "schema");
+
+ struct avro_link_schema_t *link = avro_schema_to_link(schema);
+ return link->to;
+}
+
+static const char *
+qualify_name(const char *name, const char *namespace)
+{
+ char *full_name;
+ if (namespace != NULL && strchr(name, '.') == NULL) {
+ full_name = avro_str_alloc(strlen(name) + strlen(namespace) + 2);
+ sprintf(full_name, "%s.%s", namespace, name);
+ } else {
+ full_name = avro_strdup(name);
+ }
+ return full_name;
+}
+
+static int
+save_named_schemas(const avro_schema_t schema, st_table *st)
+{
+ const char *name = avro_schema_name(schema);
+ const char *namespace = avro_schema_namespace(schema);
+ const char *full_name = qualify_name(name, namespace);
+ int rval = st_insert(st, (st_data_t) full_name, (st_data_t) schema);
+ return rval;
+}
+
+static avro_schema_t
+find_named_schemas(const char *name, const char *namespace, st_table *st)
+{
+ union {
+ avro_schema_t schema;
+ st_data_t data;
+ } val;
+ const char *full_name = qualify_name(name, namespace);
+ int rval = st_lookup(st, (st_data_t) full_name, &(val.data));
+ avro_str_free((char *)full_name);
+ if (rval) {
+ return val.schema;
+ }
+ avro_set_error("No schema type named %s", name);
+ return NULL;
+};
+
+static int
+avro_type_from_json_t(json_t *json, avro_type_t *type,
+ st_table *named_schemas, avro_schema_t *named_type,
+ const char *namespace)
+{
+ json_t *json_type;
+ const char *type_str;
+
+ if (json_is_array(json)) {
+ *type = AVRO_UNION;
+ return 0;
+ } else if (json_is_object(json)) {
+ json_type = json_object_get(json, "type");
+ } else {
+ json_type = json;
+ }
+ if (!json_is_string(json_type)) {
+ avro_set_error("\"type\" field must be a string");
+ return EINVAL;
+ }
+ type_str = json_string_value(json_type);
+ if (!type_str) {
+ avro_set_error("\"type\" field must be a string");
+ return EINVAL;
+ }
+ /*
+ * TODO: gperf/re2c this
+ */
+ if (strcmp(type_str, "string") == 0) {
+ *type = AVRO_STRING;
+ } else if (strcmp(type_str, "bytes") == 0) {
+ *type = AVRO_BYTES;
+ } else if (strcmp(type_str, "int") == 0) {
+ *type = AVRO_INT32;
+ } else if (strcmp(type_str, "long") == 0) {
+ *type = AVRO_INT64;
+ } else if (strcmp(type_str, "float") == 0) {
+ *type = AVRO_FLOAT;
+ } else if (strcmp(type_str, "double") == 0) {
+ *type = AVRO_DOUBLE;
+ } else if (strcmp(type_str, "boolean") == 0) {
+ *type = AVRO_BOOLEAN;
+ } else if (strcmp(type_str, "null") == 0) {
+ *type = AVRO_NULL;
+ } else if (strcmp(type_str, "record") == 0) {
+ *type = AVRO_RECORD;
+ } else if (strcmp(type_str, "enum") == 0) {
+ *type = AVRO_ENUM;
+ } else if (strcmp(type_str, "array") == 0) {
+ *type = AVRO_ARRAY;
+ } else if (strcmp(type_str, "map") == 0) {
+ *type = AVRO_MAP;
+ } else if (strcmp(type_str, "fixed") == 0) {
+ *type = AVRO_FIXED;
+ } else if ((*named_type = find_named_schemas(type_str, namespace, named_schemas))) {
+ *type = AVRO_LINK;
+ } else {
+ avro_set_error("Unknown Avro \"type\": %s", type_str);
+ return EINVAL;
+ }
+ return 0;
+}
+
+static int
+avro_schema_from_json_t(json_t *json, avro_schema_t *schema,
+ st_table *named_schemas, const char *parent_namespace)
+{
+#ifdef _WIN32
+ #pragma message("#warning: Bug: '0' is not of type avro_type_t.")
+#else
+ #warning "Bug: '0' is not of type avro_type_t."
+#endif
+ /* We should really have an "AVRO_INVALID" type in
+ * avro_type_t. Suppress warning below in which we set type to 0.
+ */
+ avro_type_t type = (avro_type_t) 0;
+ unsigned int i;
+ avro_schema_t named_type = NULL;
+
+ if (avro_type_from_json_t(json, &type, named_schemas, &named_type, parent_namespace)) {
+ return EINVAL;
+ }
+
+ switch (type) {
+ case AVRO_LINK:
+ *schema = avro_schema_link(named_type);
+ break;
+
+ case AVRO_STRING:
+ *schema = avro_schema_string();
+ break;
+
+ case AVRO_BYTES:
+ *schema = avro_schema_bytes();
+ break;
+
+ case AVRO_INT32:
+ *schema = avro_schema_int();
+ break;
+
+ case AVRO_INT64:
+ *schema = avro_schema_long();
+ break;
+
+ case AVRO_FLOAT:
+ *schema = avro_schema_float();
+ break;
+
+ case AVRO_DOUBLE:
+ *schema = avro_schema_double();
+ break;
+
+ case AVRO_BOOLEAN:
+ *schema = avro_schema_boolean();
+ break;
+
+ case AVRO_NULL:
+ *schema = avro_schema_null();
+ break;
+
+ case AVRO_RECORD:
+ {
+ json_t *json_name = json_object_get(json, "name");
+ json_t *json_namespace =
+ json_object_get(json, "namespace");
+ json_t *json_fields = json_object_get(json, "fields");
+ unsigned int num_fields;
+ const char *fullname, *name;
+
+ if (!json_is_string(json_name)) {
+ avro_set_error("Record type must have a \"name\"");
+ return EINVAL;
+ }
+ if (!json_is_array(json_fields)) {
+ avro_set_error("Record type must have \"fields\"");
+ return EINVAL;
+ }
+ num_fields = json_array_size(json_fields);
+ fullname = json_string_value(json_name);
+ if (!fullname) {
+ avro_set_error("Record type must have a \"name\"");
+ return EINVAL;
+ }
+
+ if (strchr(fullname, '.')) {
+ char *namespace = split_namespace_name(fullname, &name);
+ *schema = avro_schema_record(name, namespace);
+ avro_str_free(namespace);
+ } else if (json_is_string(json_namespace)) {
+ const char *namespace = json_string_value(json_namespace);
+ if (strlen(namespace) == 0) {
+ namespace = NULL;
+ }
+ *schema = avro_schema_record(fullname, namespace);
+ } else {
+ *schema = avro_schema_record(fullname, parent_namespace);
+ }
+
+ if (*schema == NULL) {
+ return ENOMEM;
+ }
+ if (save_named_schemas(*schema, named_schemas)) {
+ avro_set_error("Cannot save record schema");
+ return ENOMEM;
+ }
+ for (i = 0; i < num_fields; i++) {
+ json_t *json_field =
+ json_array_get(json_fields, i);
+ json_t *json_field_name;
+ json_t *json_field_type;
+ avro_schema_t json_field_type_schema;
+ int field_rval;
+
+ if (!json_is_object(json_field)) {
+ avro_set_error("Record field %d must be an array", i);
+ avro_schema_decref(*schema);
+ return EINVAL;
+ }
+ json_field_name =
+ json_object_get(json_field, "name");
+ if (!json_field_name) {
+ avro_set_error("Record field %d must have a \"name\"", i);
+ avro_schema_decref(*schema);
+ return EINVAL;
+ }
+ json_field_type =
+ json_object_get(json_field, "type");
+ if (!json_field_type) {
+ avro_set_error("Record field %d must have a \"type\"", i);
+ avro_schema_decref(*schema);
+ return EINVAL;
+ }
+ field_rval =
+ avro_schema_from_json_t(json_field_type,
+ &json_field_type_schema,
+ named_schemas,
+ avro_schema_namespace(*schema));
+ if (field_rval) {
+ avro_schema_decref(*schema);
+ return field_rval;
+ }
+ field_rval =
+ avro_schema_record_field_append(*schema,
+ json_string_value
+ (json_field_name),
+ json_field_type_schema);
+ avro_schema_decref(json_field_type_schema);
+ if (field_rval != 0) {
+ avro_schema_decref(*schema);
+ return field_rval;
+ }
+ }
+ }
+ break;
+
+ case AVRO_ENUM:
+ {
+ json_t *json_name = json_object_get(json, "name");
+ json_t *json_symbols = json_object_get(json, "symbols");
+ json_t *json_namespace = json_object_get(json, "namespace");
+ const char *fullname, *name;
+ unsigned int num_symbols;
+
+ if (!json_is_string(json_name)) {
+ avro_set_error("Enum type must have a \"name\"");
+ return EINVAL;
+ }
+ if (!json_is_array(json_symbols)) {
+ avro_set_error("Enum type must have \"symbols\"");
+ return EINVAL;
+ }
+
+ fullname = json_string_value(json_name);
+ if (!fullname) {
+ avro_set_error("Enum type must have a \"name\"");
+ return EINVAL;
+ }
+ num_symbols = json_array_size(json_symbols);
+ if (num_symbols == 0) {
+ avro_set_error("Enum type must have at least one symbol");
+ return EINVAL;
+ }
+
+ if (strchr(fullname, '.')) {
+ char *namespace;
+ namespace = split_namespace_name(fullname, &name);
+ *schema = avro_schema_enum_ns(name, namespace);
+ avro_str_free(namespace);
+ } else if (json_is_string(json_namespace)) {
+ const char *namespace = json_string_value(json_namespace);
+ if (strlen(namespace) == 0) {
+ namespace = NULL;
+ }
+ *schema = avro_schema_enum_ns(fullname, namespace);
+ } else {
+ *schema = avro_schema_enum_ns(fullname, parent_namespace);
+ }
+
+ if (*schema == NULL) {
+ return ENOMEM;
+ }
+ if (save_named_schemas(*schema, named_schemas)) {
+ avro_set_error("Cannot save enum schema");
+ return ENOMEM;
+ }
+ for (i = 0; i < num_symbols; i++) {
+ int enum_rval;
+ json_t *json_symbol =
+ json_array_get(json_symbols, i);
+ const char *symbol;
+ if (!json_is_string(json_symbol)) {
+ avro_set_error("Enum symbol %d must be a string", i);
+ avro_schema_decref(*schema);
+ return EINVAL;
+ }
+ symbol = json_string_value(json_symbol);
+ enum_rval =
+ avro_schema_enum_symbol_append(*schema,
+ symbol);
+ if (enum_rval != 0) {
+ avro_schema_decref(*schema);
+ return enum_rval;
+ }
+ }
+ }
+ break;
+
+ case AVRO_ARRAY:
+ {
+ int items_rval;
+ json_t *json_items = json_object_get(json, "items");
+ avro_schema_t items_schema;
+ if (!json_items) {
+ avro_set_error("Array type must have \"items\"");
+ return EINVAL;
+ }
+ items_rval =
+ avro_schema_from_json_t(json_items, &items_schema,
+ named_schemas, parent_namespace);
+ if (items_rval) {
+ return items_rval;
+ }
+ *schema = avro_schema_array(items_schema);
+ avro_schema_decref(items_schema);
+ }
+ break;
+
+ case AVRO_MAP:
+ {
+ int values_rval;
+ json_t *json_values = json_object_get(json, "values");
+ avro_schema_t values_schema;
+
+ if (!json_values) {
+ avro_set_error("Map type must have \"values\"");
+ return EINVAL;
+ }
+ values_rval =
+ avro_schema_from_json_t(json_values, &values_schema,
+ named_schemas, parent_namespace);
+ if (values_rval) {
+ return values_rval;
+ }
+ *schema = avro_schema_map(values_schema);
+ avro_schema_decref(values_schema);
+ }
+ break;
+
+ case AVRO_UNION:
+ {
+ unsigned int num_schemas = json_array_size(json);
+ avro_schema_t s;
+ if (num_schemas == 0) {
+ avro_set_error("Union type must have at least one branch");
+ return EINVAL;
+ }
+ *schema = avro_schema_union();
+ for (i = 0; i < num_schemas; i++) {
+ int schema_rval;
+ json_t *schema_json = json_array_get(json, i);
+ if (!schema_json) {
+ avro_set_error("Cannot retrieve branch JSON");
+ return EINVAL;
+ }
+ schema_rval =
+ avro_schema_from_json_t(schema_json, &s,
+ named_schemas, parent_namespace);
+ if (schema_rval != 0) {
+ avro_schema_decref(*schema);
+ return schema_rval;
+ }
+ schema_rval =
+ avro_schema_union_append(*schema, s);
+ avro_schema_decref(s);
+ if (schema_rval != 0) {
+ avro_schema_decref(*schema);
+ return schema_rval;
+ }
+ }
+ }
+ break;
+
+ case AVRO_FIXED:
+ {
+ json_t *json_size = json_object_get(json, "size");
+ json_t *json_name = json_object_get(json, "name");
+ json_t *json_namespace = json_object_get(json, "namespace");
+ json_int_t size;
+ const char *fullname, *name;
+ if (!json_is_integer(json_size)) {
+ avro_set_error("Fixed type must have a \"size\"");
+ return EINVAL;
+ }
+ if (!json_is_string(json_name)) {
+ avro_set_error("Fixed type must have a \"name\"");
+ return EINVAL;
+ }
+ size = json_integer_value(json_size);
+ fullname = json_string_value(json_name);
+
+ if (strchr(fullname, '.')) {
+ char *namespace;
+ namespace = split_namespace_name(fullname, &name);
+ *schema = avro_schema_fixed_ns(name, namespace, (int64_t) size);
+ avro_str_free(namespace);
+ } else if (json_is_string(json_namespace)) {
+ const char *namespace = json_string_value(json_namespace);
+ if (strlen(namespace) == 0) {
+ namespace = NULL;
+ }
+ *schema = avro_schema_fixed_ns(fullname, namespace, (int64_t) size);
+ } else {
+ *schema = avro_schema_fixed_ns(fullname, parent_namespace, (int64_t) size);
+ }
+
+ if (*schema == NULL) {
+ return ENOMEM;
+ }
+ if (save_named_schemas(*schema, named_schemas)) {
+ avro_set_error("Cannot save fixed schema");
+ return ENOMEM;
+ }
+ }
+ break;
+
+ default:
+ avro_set_error("Unknown schema type");
+ return EINVAL;
+ }
+ return 0;
+}
+
+static int named_schema_free_foreach(char *full_name, st_data_t value, st_data_t arg)
+{
+ AVRO_UNUSED(value);
+ AVRO_UNUSED(arg);
+
+ avro_str_free(full_name);
+ return ST_DELETE;
+}
+
+static int
+avro_schema_from_json_root(json_t *root, avro_schema_t *schema)
+{
+ int rval;
+ st_table *named_schemas;
+
+ named_schemas = st_init_strtable_with_size(DEFAULT_TABLE_SIZE);
+ if (!named_schemas) {
+ avro_set_error("Cannot allocate named schema map");
+ json_decref(root);
+ return ENOMEM;
+ }
+
+ /* json_dumpf(root, stderr, 0); */
+ rval = avro_schema_from_json_t(root, schema, named_schemas, NULL);
+ json_decref(root);
+ st_foreach(named_schemas, HASH_FUNCTION_CAST named_schema_free_foreach, 0);
+ st_free_table(named_schemas);
+ return rval;
+}
+
+int
+avro_schema_from_json(const char *jsontext, const int32_t len,
+ avro_schema_t *schema, avro_schema_error_t *e)
+{
+ check_param(EINVAL, jsontext, "JSON text");
+ check_param(EINVAL, schema, "schema pointer");
+
+ json_t *root;
+ json_error_t json_error;
+
+ AVRO_UNUSED(len);
+ AVRO_UNUSED(e);
+
+ root = json_loads(jsontext, JSON_DECODE_ANY, &json_error);
+ if (!root) {
+ avro_set_error("Error parsing JSON: %s", json_error.text);
+ return EINVAL;
+ }
+
+ return avro_schema_from_json_root(root, schema);
+}
+
+int
+avro_schema_from_json_length(const char *jsontext, size_t length,
+ avro_schema_t *schema)
+{
+ check_param(EINVAL, jsontext, "JSON text");
+ check_param(EINVAL, schema, "schema pointer");
+
+ json_t *root;
+ json_error_t json_error;
+
+ root = json_loadb(jsontext, length, JSON_DECODE_ANY, &json_error);
+ if (!root) {
+ avro_set_error("Error parsing JSON: %s", json_error.text);
+ return EINVAL;
+ }
+
+ return avro_schema_from_json_root(root, schema);
+}
+
+avro_schema_t avro_schema_copy_root(avro_schema_t schema, st_table *named_schemas)
+{
+ long i;
+ avro_schema_t new_schema = NULL;
+ if (!schema) {
+ return NULL;
+ }
+ switch (avro_typeof(schema)) {
+ case AVRO_STRING:
+ case AVRO_BYTES:
+ case AVRO_INT32:
+ case AVRO_INT64:
+ case AVRO_FLOAT:
+ case AVRO_DOUBLE:
+ case AVRO_BOOLEAN:
+ case AVRO_NULL:
+ /*
+ * No need to copy primitives since they're static
+ */
+ new_schema = schema;
+ break;
+
+ case AVRO_RECORD:
+ {
+ struct avro_record_schema_t *record_schema =
+ avro_schema_to_record(schema);
+ new_schema =
+ avro_schema_record(record_schema->name,
+ record_schema->space);
+ if (save_named_schemas(new_schema, named_schemas)) {
+ avro_set_error("Cannot save enum schema");
+ return NULL;
+ }
+ for (i = 0; i < record_schema->fields->num_entries; i++) {
+ union {
+ st_data_t data;
+ struct avro_record_field_t *field;
+ } val;
+ st_lookup(record_schema->fields, i, &val.data);
+ avro_schema_t type_copy =
+ avro_schema_copy_root(val.field->type, named_schemas);
+ avro_schema_record_field_append(new_schema,
+ val.field->name,
+ type_copy);
+ avro_schema_decref(type_copy);
+ }
+ }
+ break;
+
+ case AVRO_ENUM:
+ {
+ struct avro_enum_schema_t *enum_schema =
+ avro_schema_to_enum(schema);
+ new_schema = avro_schema_enum_ns(enum_schema->name,
+ enum_schema->space);
+ if (save_named_schemas(new_schema, named_schemas)) {
+ avro_set_error("Cannot save enum schema");
+ return NULL;
+ }
+ for (i = 0; i < enum_schema->symbols->num_entries; i++) {
+ union {
+ st_data_t data;
+ char *sym;
+ } val;
+ st_lookup(enum_schema->symbols, i, &val.data);
+ avro_schema_enum_symbol_append(new_schema,
+ val.sym);
+ }
+ }
+ break;
+
+ case AVRO_FIXED:
+ {
+ struct avro_fixed_schema_t *fixed_schema =
+ avro_schema_to_fixed(schema);
+ new_schema =
+ avro_schema_fixed_ns(fixed_schema->name,
+ fixed_schema->space,
+ fixed_schema->size);
+ if (save_named_schemas(new_schema, named_schemas)) {
+ avro_set_error("Cannot save fixed schema");
+ return NULL;
+ }
+ }
+ break;
+
+ case AVRO_MAP:
+ {
+ struct avro_map_schema_t *map_schema =
+ avro_schema_to_map(schema);
+ avro_schema_t values_copy =
+ avro_schema_copy_root(map_schema->values, named_schemas);
+ if (!values_copy) {
+ return NULL;
+ }
+ new_schema = avro_schema_map(values_copy);
+ avro_schema_decref(values_copy);
+ }
+ break;
+
+ case AVRO_ARRAY:
+ {
+ struct avro_array_schema_t *array_schema =
+ avro_schema_to_array(schema);
+ avro_schema_t items_copy =
+ avro_schema_copy_root(array_schema->items, named_schemas);
+ if (!items_copy) {
+ return NULL;
+ }
+ new_schema = avro_schema_array(items_copy);
+ avro_schema_decref(items_copy);
+ }
+ break;
+
+ case AVRO_UNION:
+ {
+ struct avro_union_schema_t *union_schema =
+ avro_schema_to_union(schema);
+
+ new_schema = avro_schema_union();
+ for (i = 0; i < union_schema->branches->num_entries;
+ i++) {
+ avro_schema_t schema_copy;
+ union {
+ st_data_t data;
+ avro_schema_t schema;
+ } val;
+ st_lookup(union_schema->branches, i, &val.data);
+ schema_copy = avro_schema_copy_root(val.schema, named_schemas);
+ if (avro_schema_union_append
+ (new_schema, schema_copy)) {
+ avro_schema_decref(new_schema);
+ return NULL;
+ }
+ avro_schema_decref(schema_copy);
+ }
+ }
+ break;
+
+ case AVRO_LINK:
+ {
+ struct avro_link_schema_t *link_schema =
+ avro_schema_to_link(schema);
+ avro_schema_t to;
+
+ to = find_named_schemas(avro_schema_name(link_schema->to),
+ avro_schema_namespace(link_schema->to),
+ named_schemas);
+ new_schema = avro_schema_link(to);
+ }
+ break;
+
+ default:
+ return NULL;
+ }
+ return new_schema;
+}
+
+avro_schema_t avro_schema_copy(avro_schema_t schema)
+{
+ avro_schema_t new_schema;
+ st_table *named_schemas;
+
+ named_schemas = st_init_strtable_with_size(DEFAULT_TABLE_SIZE);
+ if (!named_schemas) {
+ avro_set_error("Cannot allocate named schema map");
+ return NULL;
+ }
+
+ new_schema = avro_schema_copy_root(schema, named_schemas);
+ st_foreach(named_schemas, HASH_FUNCTION_CAST named_schema_free_foreach, 0);
+ st_free_table(named_schemas);
+ return new_schema;
+}
+
+avro_schema_t avro_schema_get_subschema(const avro_schema_t schema,
+ const char *name)
+{
+ if (is_avro_record(schema)) {
+ const struct avro_record_schema_t *rschema =
+ avro_schema_to_record(schema);
+ union {
+ st_data_t data;
+ struct avro_record_field_t *field;
+ } field;
+
+ if (st_lookup(rschema->fields_byname,
+ (st_data_t) name, &field.data))
+ {
+ return field.field->type;
+ }
+
+ avro_set_error("No record field named %s", name);
+ return NULL;
+ } else if (is_avro_union(schema)) {
+ const struct avro_union_schema_t *uschema =
+ avro_schema_to_union(schema);
+ long i;
+
+ for (i = 0; i < uschema->branches->num_entries; i++) {
+ union {
+ st_data_t data;
+ avro_schema_t schema;
+ } val;
+ st_lookup(uschema->branches, i, &val.data);
+ if (strcmp(avro_schema_type_name(val.schema),
+ name) == 0)
+ {
+ return val.schema;
+ }
+ }
+
+ avro_set_error("No union branch named %s", name);
+ return NULL;
+ } else if (is_avro_array(schema)) {
+ if (strcmp(name, "[]") == 0) {
+ const struct avro_array_schema_t *aschema =
+ avro_schema_to_array(schema);
+ return aschema->items;
+ }
+
+ avro_set_error("Array subschema must be called \"[]\"");
+ return NULL;
+ } else if (is_avro_map(schema)) {
+ if (strcmp(name, "{}") == 0) {
+ const struct avro_map_schema_t *mschema =
+ avro_schema_to_map(schema);
+ return mschema->values;
+ }
+
+ avro_set_error("Map subschema must be called \"{}\"");
+ return NULL;
+ }
+
+ avro_set_error("Can only retrieve subschemas from record, union, array, or map");
+ return NULL;
+}
+
+const char *avro_schema_name(const avro_schema_t schema)
+{
+ if (is_avro_record(schema)) {
+ return (avro_schema_to_record(schema))->name;
+ } else if (is_avro_enum(schema)) {
+ return (avro_schema_to_enum(schema))->name;
+ } else if (is_avro_fixed(schema)) {
+ return (avro_schema_to_fixed(schema))->name;
+ }
+ avro_set_error("Schema has no name");
+ return NULL;
+}
+
+const char *avro_schema_namespace(const avro_schema_t schema)
+{
+ if (is_avro_record(schema)) {
+ return (avro_schema_to_record(schema))->space;
+ } else if (is_avro_enum(schema)) {
+ return (avro_schema_to_enum(schema))->space;
+ } else if (is_avro_fixed(schema)) {
+ return (avro_schema_to_fixed(schema))->space;
+ }
+ return NULL;
+}
+
+const char *avro_schema_type_name(const avro_schema_t schema)
+{
+ if (is_avro_record(schema)) {
+ return (avro_schema_to_record(schema))->name;
+ } else if (is_avro_enum(schema)) {
+ return (avro_schema_to_enum(schema))->name;
+ } else if (is_avro_fixed(schema)) {
+ return (avro_schema_to_fixed(schema))->name;
+ } else if (is_avro_union(schema)) {
+ return "union";
+ } else if (is_avro_array(schema)) {
+ return "array";
+ } else if (is_avro_map(schema)) {
+ return "map";
+ } else if (is_avro_int32(schema)) {
+ return "int";
+ } else if (is_avro_int64(schema)) {
+ return "long";
+ } else if (is_avro_float(schema)) {
+ return "float";
+ } else if (is_avro_double(schema)) {
+ return "double";
+ } else if (is_avro_boolean(schema)) {
+ return "boolean";
+ } else if (is_avro_null(schema)) {
+ return "null";
+ } else if (is_avro_string(schema)) {
+ return "string";
+ } else if (is_avro_bytes(schema)) {
+ return "bytes";
+ } else if (is_avro_link(schema)) {
+ avro_schema_t target = avro_schema_link_target(schema);
+ return avro_schema_type_name(target);
+ }
+ avro_set_error("Unknown schema type");
+ return NULL;
+}
+
+avro_datum_t avro_datum_from_schema(const avro_schema_t schema)
+{
+ check_param(NULL, is_avro_schema(schema), "schema");
+
+ switch (avro_typeof(schema)) {
+ case AVRO_STRING:
+ return avro_givestring("", NULL);
+
+ case AVRO_BYTES:
+ return avro_givebytes("", 0, NULL);
+
+ case AVRO_INT32:
+ return avro_int32(0);
+
+ case AVRO_INT64:
+ return avro_int64(0);
+
+ case AVRO_FLOAT:
+ return avro_float(0);
+
+ case AVRO_DOUBLE:
+ return avro_double(0);
+
+ case AVRO_BOOLEAN:
+ return avro_boolean(0);
+
+ case AVRO_NULL:
+ return avro_null();
+
+ case AVRO_RECORD:
+ {
+ const struct avro_record_schema_t *record_schema =
+ avro_schema_to_record(schema);
+
+ avro_datum_t rec = avro_record(schema);
+
+ int i;
+ for (i = 0; i < record_schema->fields->num_entries; i++) {
+ union {
+ st_data_t data;
+ struct avro_record_field_t *field;
+ } val;
+ st_lookup(record_schema->fields, i, &val.data);
+
+ avro_datum_t field =
+ avro_datum_from_schema(val.field->type);
+ avro_record_set(rec, val.field->name, field);
+ avro_datum_decref(field);
+ }
+
+ return rec;
+ }
+
+ case AVRO_ENUM:
+ return avro_enum(schema, 0);
+
+ case AVRO_FIXED:
+ {
+ const struct avro_fixed_schema_t *fixed_schema =
+ avro_schema_to_fixed(schema);
+ return avro_givefixed(schema, NULL, fixed_schema->size, NULL);
+ }
+
+ case AVRO_MAP:
+ return avro_map(schema);
+
+ case AVRO_ARRAY:
+ return avro_array(schema);
+
+ case AVRO_UNION:
+ return avro_union(schema, -1, NULL);
+
+ case AVRO_LINK:
+ {
+ const struct avro_link_schema_t *link_schema =
+ avro_schema_to_link(schema);
+ return avro_datum_from_schema(link_schema->to);
+ }
+
+ default:
+ avro_set_error("Unknown schema type");
+ return NULL;
+ }
+}
+
+/* simple helper for writing strings */
+static int avro_write_str(avro_writer_t out, const char *str)
+{
+ return avro_write(out, (char *)str, strlen(str));
+}
+
+static int write_field(avro_writer_t out, const struct avro_record_field_t *field,
+ const char *parent_namespace)
+{
+ int rval;
+ check(rval, avro_write_str(out, "{\"name\":\""));
+ check(rval, avro_write_str(out, field->name));
+ check(rval, avro_write_str(out, "\",\"type\":"));
+ check(rval, avro_schema_to_json2(field->type, out, parent_namespace));
+ return avro_write_str(out, "}");
+}
+
+static int write_record(avro_writer_t out, const struct avro_record_schema_t *record,
+ const char *parent_namespace)
+{
+ int rval;
+ long i;
+
+ check(rval, avro_write_str(out, "{\"type\":\"record\",\"name\":\""));
+ check(rval, avro_write_str(out, record->name));
+ check(rval, avro_write_str(out, "\","));
+ if (nullstrcmp(record->space, parent_namespace)) {
+ check(rval, avro_write_str(out, "\"namespace\":\""));
+ if (record->space) {
+ check(rval, avro_write_str(out, record->space));
+ }
+ check(rval, avro_write_str(out, "\","));
+ }
+ check(rval, avro_write_str(out, "\"fields\":["));
+ for (i = 0; i < record->fields->num_entries; i++) {
+ union {
+ st_data_t data;
+ struct avro_record_field_t *field;
+ } val;
+ st_lookup(record->fields, i, &val.data);
+ if (i) {
+ check(rval, avro_write_str(out, ","));
+ }
+ check(rval, write_field(out, val.field, record->space));
+ }
+ return avro_write_str(out, "]}");
+}
+
+static int write_enum(avro_writer_t out, const struct avro_enum_schema_t *enump,
+ const char *parent_namespace)
+{
+ int rval;
+ long i;
+ check(rval, avro_write_str(out, "{\"type\":\"enum\",\"name\":\""));
+ check(rval, avro_write_str(out, enump->name));
+ check(rval, avro_write_str(out, "\","));
+ if (nullstrcmp(enump->space, parent_namespace)) {
+ check(rval, avro_write_str(out, "\"namespace\":\""));
+ if (enump->space) {
+ check(rval, avro_write_str(out, enump->space));
+ }
+ check(rval, avro_write_str(out, "\","));
+ }
+ check(rval, avro_write_str(out, "\"symbols\":["));
+
+ for (i = 0; i < enump->symbols->num_entries; i++) {
+ union {
+ st_data_t data;
+ char *sym;
+ } val;
+ st_lookup(enump->symbols, i, &val.data);
+ if (i) {
+ check(rval, avro_write_str(out, ","));
+ }
+ check(rval, avro_write_str(out, "\""));
+ check(rval, avro_write_str(out, val.sym));
+ check(rval, avro_write_str(out, "\""));
+ }
+ return avro_write_str(out, "]}");
+}
+
+static int write_fixed(avro_writer_t out, const struct avro_fixed_schema_t *fixed,
+ const char *parent_namespace)
+{
+ int rval;
+ char size[16];
+ check(rval, avro_write_str(out, "{\"type\":\"fixed\",\"name\":\""));
+ check(rval, avro_write_str(out, fixed->name));
+ check(rval, avro_write_str(out, "\","));
+ if (nullstrcmp(fixed->space, parent_namespace)) {
+ check(rval, avro_write_str(out, "\"namespace\":\""));
+ if (fixed->space) {
+ check(rval, avro_write_str(out, fixed->space));
+ }
+ check(rval, avro_write_str(out, "\","));
+ }
+ check(rval, avro_write_str(out, "\"size\":"));
+ snprintf(size, sizeof(size), "%" PRId64, fixed->size);
+ check(rval, avro_write_str(out, size));
+ return avro_write_str(out, "}");
+}
+
+static int write_map(avro_writer_t out, const struct avro_map_schema_t *map,
+ const char *parent_namespace)
+{
+ int rval;
+ check(rval, avro_write_str(out, "{\"type\":\"map\",\"values\":"));
+ check(rval, avro_schema_to_json2(map->values, out, parent_namespace));
+ return avro_write_str(out, "}");
+}
+static int write_array(avro_writer_t out, const struct avro_array_schema_t *array,
+ const char *parent_namespace)
+{
+ int rval;
+ check(rval, avro_write_str(out, "{\"type\":\"array\",\"items\":"));
+ check(rval, avro_schema_to_json2(array->items, out, parent_namespace));
+ return avro_write_str(out, "}");
+}
+static int write_union(avro_writer_t out, const struct avro_union_schema_t *unionp,
+ const char *parent_namespace)
+{
+ int rval;
+ long i;
+ check(rval, avro_write_str(out, "["));
+
+ for (i = 0; i < unionp->branches->num_entries; i++) {
+ union {
+ st_data_t data;
+ avro_schema_t schema;
+ } val;
+ st_lookup(unionp->branches, i, &val.data);
+ if (i) {
+ check(rval, avro_write_str(out, ","));
+ }
+ check(rval, avro_schema_to_json2(val.schema, out, parent_namespace));
+ }
+ return avro_write_str(out, "]");
+}
+static int write_link(avro_writer_t out, const struct avro_link_schema_t *link,
+ const char *parent_namespace)
+{
+ int rval;
+ check(rval, avro_write_str(out, "\""));
+ const char *namespace = avro_schema_namespace(link->to);
+ if (namespace && nullstrcmp(namespace, parent_namespace)) {
+ check(rval, avro_write_str(out, namespace));
+ check(rval, avro_write_str(out, "."));
+ }
+ check(rval, avro_write_str(out, avro_schema_name(link->to)));
+ return avro_write_str(out, "\"");
+}
+
+static int
+avro_schema_to_json2(const avro_schema_t schema, avro_writer_t out,
+ const char *parent_namespace)
+{
+ check_param(EINVAL, is_avro_schema(schema), "schema");
+ check_param(EINVAL, out, "writer");
+
+ int rval;
+
+ if (is_avro_primitive(schema)) {
+ check(rval, avro_write_str(out, "{\"type\":\""));
+ }
+
+ switch (avro_typeof(schema)) {
+ case AVRO_STRING:
+ check(rval, avro_write_str(out, "string"));
+ break;
+ case AVRO_BYTES:
+ check(rval, avro_write_str(out, "bytes"));
+ break;
+ case AVRO_INT32:
+ check(rval, avro_write_str(out, "int"));
+ break;
+ case AVRO_INT64:
+ check(rval, avro_write_str(out, "long"));
+ break;
+ case AVRO_FLOAT:
+ check(rval, avro_write_str(out, "float"));
+ break;
+ case AVRO_DOUBLE:
+ check(rval, avro_write_str(out, "double"));
+ break;
+ case AVRO_BOOLEAN:
+ check(rval, avro_write_str(out, "boolean"));
+ break;
+ case AVRO_NULL:
+ check(rval, avro_write_str(out, "null"));
+ break;
+ case AVRO_RECORD:
+ return write_record(out, avro_schema_to_record(schema), parent_namespace);
+ case AVRO_ENUM:
+ return write_enum(out, avro_schema_to_enum(schema), parent_namespace);
+ case AVRO_FIXED:
+ return write_fixed(out, avro_schema_to_fixed(schema), parent_namespace);
+ case AVRO_MAP:
+ return write_map(out, avro_schema_to_map(schema), parent_namespace);
+ case AVRO_ARRAY:
+ return write_array(out, avro_schema_to_array(schema), parent_namespace);
+ case AVRO_UNION:
+ return write_union(out, avro_schema_to_union(schema), parent_namespace);
+ case AVRO_LINK:
+ return write_link(out, avro_schema_to_link(schema), parent_namespace);
+ }
+
+ if (is_avro_primitive(schema)) {
+ return avro_write_str(out, "\"}");
+ }
+ avro_set_error("Unknown schema type");
+ return EINVAL;
+}
+
+int avro_schema_to_json(const avro_schema_t schema, avro_writer_t out)
+{
+ return avro_schema_to_json2(schema, out, NULL);
+}
diff --git a/fluent-bit/lib/avro/src/schema.h b/fluent-bit/lib/avro/src/schema.h
new file mode 100644
index 000000000..3c99ee630
--- /dev/null
+++ b/fluent-bit/lib/avro/src/schema.h
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+#ifndef AVRO_SCHEMA_PRIV_H
+#define AVRO_SCHEMA_PRIV_H
+
+#include <avro/platform.h>
+#include "avro/basics.h"
+#include "avro/schema.h"
+#include "avro_private.h"
+#include "st.h"
+
+struct avro_record_field_t {
+ int index;
+ char *name;
+ avro_schema_t type;
+ /*
+ * TODO: default values
+ */
+};
+
+struct avro_record_schema_t {
+ struct avro_obj_t obj;
+ char *name;
+ char *space;
+ st_table *fields;
+ st_table *fields_byname;
+};
+
+struct avro_enum_schema_t {
+ struct avro_obj_t obj;
+ char *name;
+ char *space;
+ st_table *symbols;
+ st_table *symbols_byname;
+};
+
+struct avro_array_schema_t {
+ struct avro_obj_t obj;
+ avro_schema_t items;
+};
+
+struct avro_map_schema_t {
+ struct avro_obj_t obj;
+ avro_schema_t values;
+};
+
+struct avro_union_schema_t {
+ struct avro_obj_t obj;
+ st_table *branches;
+ st_table *branches_byname;
+};
+
+struct avro_fixed_schema_t {
+ struct avro_obj_t obj;
+ const char *name;
+ const char *space;
+ int64_t size;
+};
+
+struct avro_link_schema_t {
+ struct avro_obj_t obj;
+ avro_schema_t to;
+};
+
+#define avro_schema_to_record(schema_) (container_of(schema_, struct avro_record_schema_t, obj))
+#define avro_schema_to_enum(schema_) (container_of(schema_, struct avro_enum_schema_t, obj))
+#define avro_schema_to_array(schema_) (container_of(schema_, struct avro_array_schema_t, obj))
+#define avro_schema_to_map(schema_) (container_of(schema_, struct avro_map_schema_t, obj))
+#define avro_schema_to_union(schema_) (container_of(schema_, struct avro_union_schema_t, obj))
+#define avro_schema_to_fixed(schema_) (container_of(schema_, struct avro_fixed_schema_t, obj))
+#define avro_schema_to_link(schema_) (container_of(schema_, struct avro_link_schema_t, obj))
+
+#endif
diff --git a/fluent-bit/lib/avro/src/schema_equal.c b/fluent-bit/lib/avro/src/schema_equal.c
new file mode 100644
index 000000000..419ed1278
--- /dev/null
+++ b/fluent-bit/lib/avro/src/schema_equal.c
@@ -0,0 +1,204 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include "avro_private.h"
+#include "schema.h"
+#include <string.h>
+
+static int
+schema_record_equal(struct avro_record_schema_t *a,
+ struct avro_record_schema_t *b)
+{
+ long i;
+ if (strcmp(a->name, b->name)) {
+ /*
+ * They have different names
+ */
+ return 0;
+ }
+ if (nullstrcmp(a->space, b->space)) {
+ return 0;
+ }
+ if (a->fields->num_entries != b->fields->num_entries) {
+ /* They have different numbers of fields */
+ return 0;
+ }
+ for (i = 0; i < a->fields->num_entries; i++) {
+ union {
+ st_data_t data;
+ struct avro_record_field_t *f;
+ } fa, fb;
+ st_lookup(a->fields, i, &fa.data);
+ if (!st_lookup(b->fields, i, &fb.data)) {
+ return 0;
+ }
+ if (strcmp(fa.f->name, fb.f->name)) {
+ /*
+ * They have fields with different names
+ */
+ return 0;
+ }
+ if (!avro_schema_equal(fa.f->type, fb.f->type)) {
+ /*
+ * They have fields with different schemas
+ */
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+schema_enum_equal(struct avro_enum_schema_t *a, struct avro_enum_schema_t *b)
+{
+ long i;
+ if (strcmp(a->name, b->name)) {
+ /*
+ * They have different names
+ */
+ return 0;
+ }
+ if (nullstrcmp(a->space, b->space)) {
+ return 0;
+ }
+ for (i = 0; i < a->symbols->num_entries; i++) {
+ union {
+ st_data_t data;
+ char *sym;
+ } sa, sb;
+ st_lookup(a->symbols, i, &sa.data);
+ if (!st_lookup(b->symbols, i, &sb.data)) {
+ return 0;
+ }
+ if (strcmp(sa.sym, sb.sym) != 0) {
+ /*
+ * They have different symbol names
+ */
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+schema_fixed_equal(struct avro_fixed_schema_t *a, struct avro_fixed_schema_t *b)
+{
+ if (strcmp(a->name, b->name)) {
+ /*
+ * They have different names
+ */
+ return 0;
+ }
+ if (nullstrcmp(a->space, b->space)) {
+ return 0;
+ }
+ return (a->size == b->size);
+}
+
+static int
+schema_map_equal(struct avro_map_schema_t *a, struct avro_map_schema_t *b)
+{
+ return avro_schema_equal(a->values, b->values);
+}
+
+static int
+schema_array_equal(struct avro_array_schema_t *a, struct avro_array_schema_t *b)
+{
+ return avro_schema_equal(a->items, b->items);
+}
+
+static int
+schema_union_equal(struct avro_union_schema_t *a, struct avro_union_schema_t *b)
+{
+ long i;
+ for (i = 0; i < a->branches->num_entries; i++) {
+ union {
+ st_data_t data;
+ avro_schema_t schema;
+ } ab, bb;
+ st_lookup(a->branches, i, &ab.data);
+ if (!st_lookup(b->branches, i, &bb.data)) {
+ return 0;
+ }
+ if (!avro_schema_equal(ab.schema, bb.schema)) {
+ /*
+ * They don't have the same schema types
+ */
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int
+schema_link_equal(struct avro_link_schema_t *a, struct avro_link_schema_t *b)
+{
+ /*
+ * NOTE: links can only be used for named types. They are used in
+ * recursive schemas so we just check the name of the schema pointed
+ * to instead of a deep check. Otherwise, we recurse forever...
+ */
+ if (is_avro_record(a->to)) {
+ if (!is_avro_record(b->to)) {
+ return 0;
+ }
+ if (nullstrcmp(avro_schema_to_record(a->to)->space,
+ avro_schema_to_record(b->to)->space)) {
+ return 0;
+ }
+ }
+ return (strcmp(avro_schema_name(a->to), avro_schema_name(b->to)) == 0);
+}
+
+int avro_schema_equal(avro_schema_t a, avro_schema_t b)
+{
+ if (!a || !b) {
+ /*
+ * this is an error. protecting from segfault.
+ */
+ return 0;
+ } else if (a == b) {
+ /*
+ * an object is equal to itself
+ */
+ return 1;
+ } else if (avro_typeof(a) != avro_typeof(b)) {
+ return 0;
+ } else if (is_avro_record(a)) {
+ return schema_record_equal(avro_schema_to_record(a),
+ avro_schema_to_record(b));
+ } else if (is_avro_enum(a)) {
+ return schema_enum_equal(avro_schema_to_enum(a),
+ avro_schema_to_enum(b));
+ } else if (is_avro_fixed(a)) {
+ return schema_fixed_equal(avro_schema_to_fixed(a),
+ avro_schema_to_fixed(b));
+ } else if (is_avro_map(a)) {
+ return schema_map_equal(avro_schema_to_map(a),
+ avro_schema_to_map(b));
+ } else if (is_avro_array(a)) {
+ return schema_array_equal(avro_schema_to_array(a),
+ avro_schema_to_array(b));
+ } else if (is_avro_union(a)) {
+ return schema_union_equal(avro_schema_to_union(a),
+ avro_schema_to_union(b));
+ } else if (is_avro_link(a)) {
+ return schema_link_equal(avro_schema_to_link(a),
+ avro_schema_to_link(b));
+ }
+ return 1;
+}
diff --git a/fluent-bit/lib/avro/src/schema_specific.c b/fluent-bit/lib/avro/src/schema_specific.c
new file mode 100644
index 000000000..7a0150c5f
--- /dev/null
+++ b/fluent-bit/lib/avro/src/schema_specific.c
@@ -0,0 +1,232 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include "avro_private.h"
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include "schema.h"
+
+enum specific_state {
+ START_STATE,
+};
+typedef enum specific_state specific_state;
+
+struct specific_ctx {
+ FILE *header;
+ FILE *source;
+ int depth;
+ specific_state state;
+};
+typedef struct specific_ctx specific_ctx;
+
+static void indent(specific_ctx * ctx, FILE * fp)
+{
+ int i;
+ for (i = 0; i < ctx->depth; i++) {
+ fprintf(fp, " ");
+ }
+}
+
+static int avro_schema_to_source(avro_schema_t schema, specific_ctx * ctx)
+{
+ switch (schema->type) {
+ default:
+ return 0;
+ }
+ return EINVAL;
+}
+
+static int avro_schema_to_header(avro_schema_t schema, specific_ctx * ctx)
+{
+ size_t i;
+ FILE *fp = ctx->header;
+
+ indent(ctx, fp);
+ ctx->depth++;
+
+ if (is_avro_primitive(schema) && !ctx->name) {
+ return 0;
+ }
+
+ switch (schema->type) {
+ case AVRO_STRING:
+ fprintf(fp, "char *%s;\n", ctx->name);
+ break;
+
+ case AVRO_BYTES:
+ fprintf(fp, "struct %s { size_t %s_len; char *%s_val } %s;\n",
+ ctx->name, ctx->name, ctx->name, ctx->name);
+ break;
+
+ case AVRO_INT:
+ fprintf(fp, "int %s;\n", ctx->name);
+ break;
+
+ case AVRO_LONG:
+ fprintf(fp, "long %s;\n", ctx->name);
+ break;
+
+ case AVRO_FLOAT:
+ fprintf(fp, "float %s;\n", ctx->name);
+ break;
+
+ case AVRO_DOUBLE:
+ fprintf(fp, "double %s;\n", ctx->name);
+ break;
+
+ case AVRO_BOOLEAN:
+ fprintf(fp, "int %s; /* boolean */\n", ctx->name);
+ break;
+
+ case AVRO_NULL:
+ break;
+
+ case AVRO_RECORD:
+ {
+ struct schema_record_t *record_schema =
+ avro_schema_to_record(schema);
+ fprintf(fp, "struct %s {\n", record_schema->name);
+ for (i = 0; i < record_schema->num_fields; i++) {
+ struct record_field_t *field =
+ record_schema->fields[i];
+ ctx->name = field->name;
+ avro_schema_to_header(field->type, ctx);
+ ctx->name = NULL;
+ }
+ fprintf(fp, "};\n");
+ fprintf(fp, "typedef struct %s %s;\n\n",
+ record_schema->name, record_schema->name);
+ }
+ break;
+
+ case AVRO_ENUM:
+ {
+ struct schema_enum_t *enum_schema =
+ avro_schema_to_enum(schema);
+ fprintf(fp, "enum %s {\n", enum_schema->name);
+ ctx->depth++;
+ for (i = 0; i < enum_schema->num_symbols; i++) {
+ indent(ctx, fp);
+ fprintf(fp, "%s = %ld,\n",
+ enum_schema->symbols[i], i);
+ }
+ ctx->depth--;
+ fprintf(fp, "};\n");
+ fprintf(fp, "typedef enum %s %s;\n\n",
+ enum_schema->name, enum_schema->name);
+ }
+ break;
+
+ case AVRO_FIXED:
+ {
+ struct schema_fixed_t *fixed_schema =
+ avro_schema_to_fixed(schema);
+ fprintf(fp, "char %s[%ld];\n", fixed_schema->name,
+ fixed_schema->size);
+ }
+ break;
+
+ case AVRO_MAP:
+ {
+
+ }
+ break;
+
+ case AVRO_ARRAY:
+ {
+ struct schema_array_t *array_schema =
+ avro_schema_to_array(schema);
+ if (!ctx->name) {
+ break;
+ }
+ fprintf(fp, "struct { size_t %s_len; ", ctx->name);
+ if (is_avro_named_type(array_schema->items)) {
+ fprintf(fp, "%s",
+ avro_schema_name(array_schema->items));
+ } else if (is_avro_link(array_schema->items)) {
+ struct schema_link_t *link_schema =
+ avro_schema_to_link(array_schema->items);
+ fprintf(fp, "struct %s",
+ avro_schema_name(link_schema->to));
+ } else {
+ avro_schema_to_header(array_schema->items, ctx);
+ }
+ fprintf(fp, " *%s_val;} %s;\n", ctx->name, ctx->name);
+ }
+ break;
+ case AVRO_UNION:
+ {
+ struct schema_union_t *union_schema =
+ avro_schema_to_array(schema);
+ if (!ctx->name) {
+ break;
+ }
+ fprintf(fp, "union {\n");
+ for (i = 0; i < union_schema->num_schemas; i++) {
+ avro_schema_to_header(union_schema->schemas[i],
+ ctx);
+ }
+ fprintf(fp, "%s_u;\n");
+ }
+ break;
+ case AVRO_LINK:
+ break;
+ default:
+ return EINVAL;
+ }
+
+ ctx->depth--;
+ return 0;
+}
+
+int avro_schema_to_specific(avro_schema_t schema, const char *prefix)
+{
+ specific_ctx ctx;
+ char buf[1024];
+ int rval;
+
+ if (!schema) {
+ return EINVAL;
+ }
+
+ memset(&ctx, 0, sizeof(ctx));
+ snprintf(buf, sizeof(buf), "%s_avro.h", prefix);
+ ctx.header = fopen(buf, "w");
+ if (!ctx.header) {
+ return errno;
+ }
+ snprintf(buf, sizeof(buf), "%s_avro.c", prefix);
+ ctx.source = fopen(buf, "w");
+ if (!ctx.source) {
+ fclose(ctx.header);
+ return errno;
+ }
+
+ rval = avro_schema_to_header(schema, &ctx);
+ if (rval) {
+ goto out;
+ }
+
+ rval = avro_schema_to_source(schema, &ctx);
+
+ out:
+ fclose(ctx.header);
+ fclose(ctx.source);
+ return rval;
+}
diff --git a/fluent-bit/lib/avro/src/st.c b/fluent-bit/lib/avro/src/st.c
new file mode 100644
index 000000000..27578289e
--- /dev/null
+++ b/fluent-bit/lib/avro/src/st.c
@@ -0,0 +1,543 @@
+/*
+ * This is a public domain general purpose hash table package written by
+ * Peter Moore @ UCB.
+ */
+
+/*
+ * static char sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible";
+ */
+
+#include "avro_private.h"
+#include "avro/allocation.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "st.h"
+
+typedef struct st_table_entry st_table_entry;
+
+struct st_table_entry {
+ unsigned int hash;
+ st_data_t key;
+ st_data_t record;
+ st_table_entry *next;
+};
+
+#define ST_DEFAULT_MAX_DENSITY 5
+#define ST_DEFAULT_INIT_TABLE_SIZE 11
+
+ /*
+ * DEFAULT_MAX_DENSITY is the default for the largest we allow the
+ * average number of items per bin before increasing the number of
+ * bins
+ *
+ * DEFAULT_INIT_TABLE_SIZE is the default for the number of bins
+ * allocated initially
+ *
+ */
+static int numcmp(long, long);
+static int numhash(long);
+static struct st_hash_type type_numhash = {
+ HASH_FUNCTION_CAST numcmp,
+ HASH_FUNCTION_CAST numhash
+};
+
+/*
+ * extern int strcmp(const char *, const char *);
+ */
+static int strhash(const char *);
+static struct st_hash_type type_strhash = {
+ HASH_FUNCTION_CAST strcmp,
+ HASH_FUNCTION_CAST strhash
+};
+
+static void rehash(st_table *);
+
+#ifdef RUBY
+#define malloc xmalloc
+#define calloc xcalloc
+#endif
+
+#define Calloc(n,s) (char*)avro_calloc((n),(s))
+
+#define free_bins(tbl) \
+ avro_free(tbl->bins, tbl->num_bins * sizeof(st_table_entry *))
+
+#define EQUAL(table,x,y) ((x)==(y) || (*table->type->compare)((x),(y)) == 0)
+
+#define do_hash(key,table) (unsigned int)(*(table)->type->hash)((key))
+#define do_hash_bin(key,table) (do_hash(key, table)%(table)->num_bins)
+
+/*
+ * MINSIZE is the minimum size of a dictionary.
+ */
+
+#define MINSIZE 8
+
+/*
+ * Table of prime numbers 2^n+a, 2<=n<=30.
+ */
+static long primes[] = {
+ 8 + 3,
+ 16 + 3,
+ 32 + 5,
+ 64 + 3,
+ 128 + 3,
+ 256 + 27,
+ 512 + 9,
+ 1024 + 9,
+ 2048 + 5,
+ 4096 + 3,
+ 8192 + 27,
+ 16384 + 43,
+ 32768 + 3,
+ 65536 + 45,
+ 131072 + 29,
+ 262144 + 3,
+ 524288 + 21,
+ 1048576 + 7,
+ 2097152 + 17,
+ 4194304 + 15,
+ 8388608 + 9,
+ 16777216 + 43,
+ 33554432 + 35,
+ 67108864 + 15,
+ 134217728 + 29,
+ 268435456 + 3,
+ 536870912 + 11,
+ 1073741824 + 85,
+ 0
+};
+
+static int new_size(int size)
+{
+ unsigned int i;
+
+#if 0
+ for (i = 3; i < 31; i++) {
+ if ((1 << i) > size)
+ return 1 << i;
+ }
+ return -1;
+#else
+ int newsize;
+
+ for (i = 0, newsize = MINSIZE;
+ i < sizeof(primes) / sizeof(primes[0]); i++, newsize <<= 1) {
+ if (newsize > size)
+ return primes[i];
+ }
+ /*
+ * Ran out of polynomials
+ */
+ return -1; /* should raise exception */
+#endif
+}
+
+#ifdef HASH_LOG
+static int collision = 0;
+static int init_st = 0;
+
+static void stat_col()
+{
+ FILE *f = fopen("/tmp/col", "w");
+ fprintf(f, "collision: %d\n", collision);
+ fclose(f);
+}
+#endif
+
+st_table *st_init_table_with_size(struct st_hash_type *type, int size)
+{
+ st_table *tbl;
+
+#ifdef HASH_LOG
+ if (init_st == 0) {
+ init_st = 1;
+ atexit(stat_col);
+ }
+#endif
+
+ size = new_size(size); /* round up to prime number */
+
+ tbl = (st_table *) avro_new(st_table);
+ tbl->type = type;
+ tbl->num_entries = 0;
+ tbl->num_bins = size;
+ tbl->bins = (st_table_entry **) Calloc(size, sizeof(st_table_entry *));
+
+ return tbl;
+}
+
+st_table *st_init_table(struct st_hash_type *type)
+{
+ return st_init_table_with_size(type, 0);
+}
+
+st_table *st_init_numtable(void)
+{
+ return st_init_table(&type_numhash);
+}
+
+st_table *st_init_numtable_with_size(int size)
+{
+ return st_init_table_with_size(&type_numhash, size);
+}
+
+st_table *st_init_strtable(void)
+{
+ return st_init_table(&type_strhash);
+}
+
+st_table *st_init_strtable_with_size(int size)
+{
+ return st_init_table_with_size(&type_strhash, size);
+}
+
+void st_free_table(st_table *table)
+{
+ register st_table_entry *ptr, *next;
+ int i;
+
+ for (i = 0; i < table->num_bins; i++) {
+ ptr = table->bins[i];
+ while (ptr != 0) {
+ next = ptr->next;
+ avro_freet(st_table_entry, ptr);
+ ptr = next;
+ }
+ }
+ free_bins(table);
+ avro_freet(st_table, table);
+}
+
+#define PTR_NOT_EQUAL(table, ptr, hash_val, key) \
+((ptr) != 0 && (ptr->hash != (hash_val) || !EQUAL((table), (key), (ptr)->key)))
+
+#ifdef HASH_LOG
+#define COLLISION collision++
+#else
+#define COLLISION
+#endif
+
+#define FIND_ENTRY(table, ptr, hash_val, bin_pos) do {\
+ bin_pos = hash_val%(table)->num_bins;\
+ ptr = (table)->bins[bin_pos];\
+ if (PTR_NOT_EQUAL(table, ptr, hash_val, key)) {\
+ COLLISION;\
+ while (PTR_NOT_EQUAL(table, ptr->next, hash_val, key)) {\
+ ptr = ptr->next;\
+ }\
+ ptr = ptr->next;\
+ }\
+} while (0)
+
+int st_lookup(st_table *table, register st_data_t key, st_data_t *value)
+{
+ unsigned int hash_val, bin_pos;
+ register st_table_entry *ptr;
+
+ hash_val = do_hash(key, table);
+ FIND_ENTRY(table, ptr, hash_val, bin_pos);
+
+ if (ptr == 0) {
+ return 0;
+ } else {
+ if (value != 0)
+ *value = ptr->record;
+ return 1;
+ }
+}
+
+#define ADD_DIRECT(table, key, value, hash_val, bin_pos)\
+do {\
+ st_table_entry *entry;\
+ if (table->num_entries/(table->num_bins) > ST_DEFAULT_MAX_DENSITY) {\
+ rehash(table);\
+ bin_pos = hash_val % table->num_bins;\
+ }\
+ \
+ entry = (st_table_entry *) avro_new(st_table_entry);\
+ \
+ entry->hash = hash_val;\
+ entry->key = key;\
+ entry->record = value;\
+ entry->next = table->bins[bin_pos];\
+ table->bins[bin_pos] = entry;\
+ table->num_entries++;\
+} while (0)
+
+int st_insert(register st_table *table, register st_data_t key, st_data_t value)
+{
+ unsigned int hash_val, bin_pos;
+ register st_table_entry *ptr;
+
+ hash_val = do_hash(key, table);
+ FIND_ENTRY(table, ptr, hash_val, bin_pos);
+
+ if (ptr == 0) {
+ ADD_DIRECT(table, key, value, hash_val, bin_pos);
+ return 0;
+ } else {
+ ptr->record = value;
+ return 1;
+ }
+}
+
+void st_add_direct(st_table *table,st_data_t key,st_data_t value)
+{
+ unsigned int hash_val, bin_pos;
+
+ hash_val = do_hash(key, table);
+ bin_pos = hash_val % table->num_bins;
+ ADD_DIRECT(table, key, value, hash_val, bin_pos);
+}
+
+static void rehash(register st_table *table)
+{
+ register st_table_entry *ptr, *next, **new_bins;
+ int i, old_num_bins = table->num_bins, new_num_bins;
+ unsigned int hash_val;
+
+ new_num_bins = new_size(old_num_bins + 1);
+ new_bins =
+ (st_table_entry **) Calloc(new_num_bins, sizeof(st_table_entry *));
+
+ for (i = 0; i < old_num_bins; i++) {
+ ptr = table->bins[i];
+ while (ptr != 0) {
+ next = ptr->next;
+ hash_val = ptr->hash % new_num_bins;
+ ptr->next = new_bins[hash_val];
+ new_bins[hash_val] = ptr;
+ ptr = next;
+ }
+ }
+ free_bins(table);
+ table->num_bins = new_num_bins;
+ table->bins = new_bins;
+}
+
+st_table *st_copy(st_table *old_table)
+{
+ st_table *new_table;
+ st_table_entry *ptr, *entry;
+ int i, num_bins = old_table->num_bins;
+
+ new_table = (st_table *) avro_new(st_table);
+ if (new_table == 0) {
+ return 0;
+ }
+
+ *new_table = *old_table;
+ new_table->bins = (st_table_entry **)
+ Calloc((unsigned)num_bins, sizeof(st_table_entry *));
+
+ if (new_table->bins == 0) {
+ avro_freet(st_table, new_table);
+ return 0;
+ }
+
+ for (i = 0; i < num_bins; i++) {
+ new_table->bins[i] = 0;
+ ptr = old_table->bins[i];
+ while (ptr != 0) {
+ entry = (st_table_entry *) avro_new(st_table_entry);
+ if (entry == 0) {
+ free_bins(new_table);
+ avro_freet(st_table, new_table);
+ return 0;
+ }
+ *entry = *ptr;
+ entry->next = new_table->bins[i];
+ new_table->bins[i] = entry;
+ ptr = ptr->next;
+ }
+ }
+ return new_table;
+}
+
+int st_delete(register st_table *table,register st_data_t *key,st_data_t *value)
+{
+ unsigned int hash_val;
+ st_table_entry *tmp;
+ register st_table_entry *ptr;
+
+ hash_val = do_hash_bin(*key, table);
+ ptr = table->bins[hash_val];
+
+ if (ptr == 0) {
+ if (value != 0)
+ *value = 0;
+ return 0;
+ }
+
+ if (EQUAL(table, *key, ptr->key)) {
+ table->bins[hash_val] = ptr->next;
+ table->num_entries--;
+ if (value != 0)
+ *value = ptr->record;
+ *key = ptr->key;
+ avro_freet(st_table_entry, ptr);
+ return 1;
+ }
+
+ for (; ptr->next != 0; ptr = ptr->next) {
+ if (EQUAL(table, ptr->next->key, *key)) {
+ tmp = ptr->next;
+ ptr->next = ptr->next->next;
+ table->num_entries--;
+ if (value != 0)
+ *value = tmp->record;
+ *key = tmp->key;
+ avro_freet(st_table_entry, tmp);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int st_delete_safe(register st_table *table,register st_data_t *key,st_data_t *value,st_data_t never)
+{
+ unsigned int hash_val;
+ register st_table_entry *ptr;
+
+ hash_val = do_hash_bin(*key, table);
+ ptr = table->bins[hash_val];
+
+ if (ptr == 0) {
+ if (value != 0)
+ *value = 0;
+ return 0;
+ }
+
+ for (; ptr != 0; ptr = ptr->next) {
+ if ((ptr->key != never) && EQUAL(table, ptr->key, *key)) {
+ table->num_entries--;
+ *key = ptr->key;
+ if (value != 0)
+ *value = ptr->record;
+ ptr->key = ptr->record = never;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int delete_never(st_data_t key, st_data_t value, st_data_t never)
+{
+ AVRO_UNUSED(key);
+
+ if (value == never)
+ return ST_DELETE;
+ return ST_CONTINUE;
+}
+
+void st_cleanup_safe(st_table *table,st_data_t never)
+{
+ int num_entries = table->num_entries;
+
+ st_foreach(table, HASH_FUNCTION_CAST delete_never, never);
+ table->num_entries = num_entries;
+}
+
+int st_foreach(st_table *table,int (*func) (ANYARGS),st_data_t arg)
+{
+ st_table_entry *ptr, *last, *tmp;
+ enum st_retval retval;
+ int i;
+
+ for (i = 0; i < table->num_bins; i++) {
+ last = 0;
+ for (ptr = table->bins[i]; ptr != 0;) {
+ retval = (enum st_retval) (*func) (ptr->key, ptr->record, arg);
+ switch (retval) {
+ case ST_CHECK: /* check if hash is modified during
+ * iteration */
+ tmp = 0;
+ if (i < table->num_bins) {
+ for (tmp = table->bins[i]; tmp;
+ tmp = tmp->next) {
+ if (tmp == ptr)
+ break;
+ }
+ }
+ if (!tmp) {
+ /*
+ * call func with error notice
+ */
+ return 1;
+ }
+ /*
+ * fall through
+ */
+ case ST_CONTINUE:
+ last = ptr;
+ ptr = ptr->next;
+ break;
+ case ST_STOP:
+ return 0;
+ case ST_DELETE:
+ tmp = ptr;
+ if (last == 0) {
+ table->bins[i] = ptr->next;
+ } else {
+ last->next = ptr->next;
+ }
+ ptr = ptr->next;
+ avro_freet(st_table_entry, tmp);
+ table->num_entries--;
+ }
+ }
+ }
+ return 0;
+}
+
+static int strhash(register const char *string)
+{
+ register int c;
+
+#ifdef HASH_ELFHASH
+ register unsigned int h = 0, g;
+
+ while ((c = *string++) != '\0') {
+ h = (h << 4) + c;
+ if (g = h & 0xF0000000)
+ h ^= g >> 24;
+ h &= ~g;
+ }
+ return h;
+#elif defined(HASH_PERL)
+ register int val = 0;
+
+ while ((c = *string++) != '\0') {
+ val += c;
+ val += (val << 10);
+ val ^= (val >> 6);
+ }
+ val += (val << 3);
+ val ^= (val >> 11);
+
+ return val + (val << 15);
+#else
+ register int val = 0;
+
+ while ((c = *string++) != '\0') {
+ val = val * 997 + c;
+ }
+
+ return val + (val >> 5);
+#endif
+}
+
+static int numcmp(long x, long y)
+{
+ return x != y;
+}
+
+static int numhash(long n)
+{
+ return n;
+}
diff --git a/fluent-bit/lib/avro/src/st.h b/fluent-bit/lib/avro/src/st.h
new file mode 100644
index 000000000..cf8a22491
--- /dev/null
+++ b/fluent-bit/lib/avro/src/st.h
@@ -0,0 +1,87 @@
+/*
+ * This is a public domain general purpose hash table package written by
+ * Peter Moore @ UCB.
+ */
+
+/*
+ * @(#) st.h 5.1 89/12/14
+ */
+
+#ifndef ST_INCLUDED
+#define ST_INCLUDED
+#ifdef __cplusplus
+extern "C" {
+#define CLOSE_EXTERN }
+#else
+#define CLOSE_EXTERN
+#endif
+
+#include <avro/platform.h> /* for uintptr_t */
+
+#pragma GCC visibility push(hidden)
+
+#ifndef ANYARGS
+ #ifdef __cplusplus
+ #define ANYARGS ...
+ #else
+ #define ANYARGS
+ #endif
+#endif
+
+#ifdef _WIN32
+ #define HASH_FUNCTION_CAST (int (__cdecl *)(ANYARGS))
+#else
+ #define HASH_FUNCTION_CAST
+#endif
+
+typedef uintptr_t st_data_t;
+typedef struct st_table st_table;
+
+struct st_hash_type {
+ int (*compare) (ANYARGS);
+ int (*hash) (ANYARGS);
+};
+
+struct st_table {
+ struct st_hash_type *type;
+ int num_bins;
+ int num_entries;
+ struct st_table_entry **bins;
+};
+
+#define st_is_member(table,key) st_lookup(table,key,(st_data_t *)0)
+
+enum st_retval { ST_CONTINUE, ST_STOP, ST_DELETE, ST_CHECK };
+
+#ifndef _
+# define _(args) args
+#endif
+
+st_table *st_init_table _((struct st_hash_type *));
+st_table *st_init_table_with_size _((struct st_hash_type *, int));
+st_table *st_init_numtable _((void));
+st_table *st_init_numtable_with_size _((int));
+st_table *st_init_strtable _((void));
+st_table *st_init_strtable_with_size _((int));
+int st_delete _((st_table *, st_data_t *, st_data_t *));
+int st_delete_safe _((st_table *, st_data_t *, st_data_t *, st_data_t));
+int st_insert _((st_table *, st_data_t, st_data_t));
+int st_lookup _((st_table *, st_data_t, st_data_t *));
+int st_foreach _((st_table *, int (*)(ANYARGS), st_data_t));
+void st_add_direct _((st_table *, st_data_t, st_data_t));
+void st_free_table _((st_table *));
+void st_cleanup_safe _((st_table *, st_data_t));
+st_table *st_copy _((st_table *));
+
+#define ST_NUMCMP ((int (*)()) 0)
+#define ST_NUMHASH ((int (*)()) -2)
+
+#define st_numcmp ST_NUMCMP
+#define st_numhash ST_NUMHASH
+
+int st_strhash();
+
+#pragma GCC visibility pop
+
+CLOSE_EXTERN
+#endif /* ST_INCLUDED */
diff --git a/fluent-bit/lib/avro/src/string.c b/fluent-bit/lib/avro/src/string.c
new file mode 100644
index 000000000..f5cde949e
--- /dev/null
+++ b/fluent-bit/lib/avro/src/string.c
@@ -0,0 +1,304 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro_private.h"
+#include "avro/data.h"
+#include "avro/allocation.h"
+#include "avro/errors.h"
+
+#ifndef AVRO_STRING_DEBUG
+#define AVRO_STRING_DEBUG 0
+#endif
+
+#if AVRO_STRING_DEBUG
+#include <stdio.h>
+#define DEBUG(...) \
+ do { \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ } while (0)
+#else
+#define DEBUG(...) /* don't print messages */
+#endif
+
+
+/*
+ * A resizable wrapped buffer implementation. This implementation makes
+ * actual copies in its copy method; if we wanted a zero-copy solution
+ * here, then we'd have to keep track of all copies of the buffer, so
+ * that we can update pointers whenever the buffer is resized (since
+ * this might change the location of the memory region).
+ */
+
+struct avro_wrapped_resizable {
+ size_t buf_size;
+};
+
+#define avro_wrapped_resizable_size(sz) \
+ (sizeof(struct avro_wrapped_resizable) + (sz))
+
+static void
+avro_wrapped_resizable_free(avro_wrapped_buffer_t *self)
+{
+ DEBUG("--- Freeing resizable <%p:%" PRIsz "> (%p)", self->buf, self->size, self->user_data);
+ struct avro_wrapped_resizable *resizable = (struct avro_wrapped_resizable *) self->user_data;
+ avro_free(resizable, avro_wrapped_resizable_size(resizable->buf_size));
+}
+
+static int
+avro_wrapped_resizable_resize(avro_wrapped_buffer_t *self, size_t desired)
+{
+ struct avro_wrapped_resizable *resizable = (struct avro_wrapped_resizable *) self->user_data;
+
+ /*
+ * If we've already allocated enough memory for the desired
+ * size, there's nothing to do.
+ */
+
+ if (resizable->buf_size >= desired) {
+ return 0;
+ }
+
+ size_t new_buf_size = resizable->buf_size * 2;
+ if (desired > new_buf_size) {
+ new_buf_size = desired;
+ }
+
+ DEBUG("--- Resizing <%p:%" PRIsz "> (%p) -> %" PRIsz,
+ self->buf, self->buf_size, self->user_data, new_buf_size);
+
+ struct avro_wrapped_resizable *new_resizable =
+ (struct avro_wrapped_resizable *) avro_realloc(resizable,
+ avro_wrapped_resizable_size(resizable->buf_size),
+ avro_wrapped_resizable_size(new_buf_size));
+ if (new_resizable == NULL) {
+ return ENOMEM;
+ }
+ DEBUG("--- New buffer <%p:%" PRIsz ">", new_buf, new_buf_size);
+
+ new_resizable->buf_size = new_buf_size;
+
+ char *old_buf = (char *) resizable;
+ char *new_buf = (char *) new_resizable;
+
+ ptrdiff_t offset = (char *) self->buf - old_buf;
+ DEBUG("--- Old data pointer is %p", self->buf);
+ self->buf = new_buf + offset;
+ self->user_data = new_resizable;
+ DEBUG("--- New data pointer is %p", self->buf);
+ return 0;
+}
+
+static int
+avro_wrapped_resizable_new(avro_wrapped_buffer_t *dest, size_t buf_size)
+{
+ size_t allocated_size = avro_wrapped_resizable_size(buf_size);
+ struct avro_wrapped_resizable *resizable =
+ (struct avro_wrapped_resizable *) avro_malloc(allocated_size);
+ if (resizable == NULL) {
+ return ENOMEM;
+ }
+
+ resizable->buf_size = buf_size;
+
+ dest->buf = ((char *) resizable) + sizeof(struct avro_wrapped_resizable);
+ DEBUG("--- Creating resizable <%p:%" PRIsz "> (%p)", dest->buf, buf_size, resizable);
+ dest->size = buf_size;
+ dest->user_data = resizable;
+ dest->free = avro_wrapped_resizable_free;
+ dest->copy = NULL;
+ dest->slice = NULL;
+ return 0;
+}
+
+#define is_resizable(buf) \
+ ((buf).free == avro_wrapped_resizable_free)
+
+
+
+void
+avro_raw_string_init(avro_raw_string_t *str)
+{
+ memset(str, 0, sizeof(avro_raw_string_t));
+}
+
+
+void
+avro_raw_string_clear(avro_raw_string_t *str)
+{
+ /*
+ * If the string's buffer is one that we control, then we don't
+ * free it; that lets us reuse the storage on the next call to
+ * avro_raw_string_set[_length].
+ */
+
+ if (is_resizable(str->wrapped)) {
+ DEBUG("--- Clearing resizable buffer");
+ str->wrapped.size = 0;
+ } else {
+ DEBUG("--- Freeing wrapped buffer");
+ avro_wrapped_buffer_free(&str->wrapped);
+ avro_raw_string_init(str);
+ }
+}
+
+
+void
+avro_raw_string_done(avro_raw_string_t *str)
+{
+ avro_wrapped_buffer_free(&str->wrapped);
+ avro_raw_string_init(str);
+}
+
+
+/**
+ * Makes sure that the string's buffer is one that we allocated
+ * ourselves, and that the buffer is big enough to hold a string of the
+ * given length.
+ */
+
+static int
+avro_raw_string_ensure_buf(avro_raw_string_t *str, size_t length)
+{
+ int rval;
+
+ DEBUG("--- Ensuring resizable buffer of size %" PRIsz, length);
+ if (is_resizable(str->wrapped)) {
+ /*
+ * If we've already got a resizable buffer, just have it
+ * resize itself.
+ */
+
+ return avro_wrapped_resizable_resize(&str->wrapped, length);
+ } else {
+ /*
+ * Stash a copy of the old wrapped buffer, and then
+ * create a new resizable buffer to store our content
+ * in.
+ */
+
+ avro_wrapped_buffer_t orig = str->wrapped;
+ check(rval, avro_wrapped_resizable_new(&str->wrapped, length));
+
+ /*
+ * If there was any content in the old wrapped buffer,
+ * copy it into the new resizable one.
+ */
+
+ if (orig.size > 0) {
+ size_t to_copy =
+ (orig.size < length)? orig.size: length;
+ memcpy((void *) str->wrapped.buf, orig.buf, to_copy);
+ }
+ avro_wrapped_buffer_free(&orig);
+
+ return 0;
+ }
+}
+
+
+void
+avro_raw_string_set_length(avro_raw_string_t *str,
+ const void *src, size_t length)
+{
+ avro_raw_string_ensure_buf(str, length+1);
+ memcpy((void *) str->wrapped.buf, src, length);
+ ((char *) str->wrapped.buf)[length] = '\0';
+ str->wrapped.size = length;
+}
+
+
+void avro_raw_string_append_length(avro_raw_string_t *str,
+ const void *src,
+ size_t length)
+{
+ if (avro_raw_string_length(str) == 0) {
+ return avro_raw_string_set_length(str, src, length);
+ }
+
+ avro_raw_string_ensure_buf(str, str->wrapped.size + length);
+ memcpy((char *) str->wrapped.buf + str->wrapped.size, src, length);
+ str->wrapped.size += length;
+}
+
+
+void
+avro_raw_string_set(avro_raw_string_t *str, const char *src)
+{
+ size_t length = strlen(src);
+ avro_raw_string_ensure_buf(str, length+1);
+ memcpy((void *) str->wrapped.buf, src, length+1);
+ str->wrapped.size = length+1;
+}
+
+
+void
+avro_raw_string_append(avro_raw_string_t *str, const char *src)
+{
+ if (avro_raw_string_length(str) == 0) {
+ return avro_raw_string_set(str, src);
+ }
+
+ /* Assume that str->wrapped.size includes a NUL terminator */
+ size_t length = strlen(src);
+ avro_raw_string_ensure_buf(str, str->wrapped.size + length);
+ memcpy((char *) str->wrapped.buf + str->wrapped.size - 1, src, length+1);
+ str->wrapped.size += length;
+}
+
+
+void
+avro_raw_string_give(avro_raw_string_t *str,
+ avro_wrapped_buffer_t *src)
+{
+ DEBUG("--- Giving control of <%p:%" PRIsz "> (%p) to string",
+ src->buf, src->size, src);
+ avro_wrapped_buffer_free(&str->wrapped);
+ avro_wrapped_buffer_move(&str->wrapped, src);
+}
+
+int
+avro_raw_string_grab(const avro_raw_string_t *str,
+ avro_wrapped_buffer_t *dest)
+{
+ return avro_wrapped_buffer_copy(dest, &str->wrapped, 0, str->wrapped.size);
+}
+
+
+int
+avro_raw_string_equals(const avro_raw_string_t *str1,
+ const avro_raw_string_t *str2)
+{
+ if (str1 == str2) {
+ return 1;
+ }
+
+ if (!str1 || !str2) {
+ return 0;
+ }
+
+ if (str1->wrapped.size != str2->wrapped.size) {
+ return 0;
+ }
+
+ return (memcmp(str1->wrapped.buf, str2->wrapped.buf,
+ str1->wrapped.size) == 0);
+}
diff --git a/fluent-bit/lib/avro/src/value-hash.c b/fluent-bit/lib/avro/src/value-hash.c
new file mode 100644
index 000000000..c717924be
--- /dev/null
+++ b/fluent-bit/lib/avro/src/value-hash.c
@@ -0,0 +1,294 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <avro/platform.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro/allocation.h"
+#include "avro/data.h"
+#include "avro/errors.h"
+#include "avro/value.h"
+#include "avro_private.h"
+
+#define check_return(retval, call) \
+ do { \
+ int rval = call; \
+ if (rval != 0) { return (retval); } \
+ } while (0)
+
+/*
+ * We currently use MurmurHash3 [1], which is public domain, as our hash
+ * implementation.
+ *
+ * [1] https://code.google.com/p/smhasher/
+ */
+
+/* Our seed is the MurmurHash3 of the string "avro.value" */
+#define SEED 0xaf4c78df
+
+#define ROTL32(a,b) (((a) << ((b) & 0x1f)) | ((a) >> (32 - ((b) & 0x1f))))
+
+static inline uint32_t
+fmix(uint32_t h)
+{
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+ return h;
+}
+
+static const uint32_t c1 = 0xcc9e2d51;
+static const uint32_t c2 = 0x1b873593;
+
+static inline uint32_t
+add_hash(uint32_t start, uint32_t current)
+{
+ current *= c1;
+ current = ROTL32(current, 15);
+ current *= c2;
+
+ start ^= current;
+ start = ROTL32(start, 13);
+ start = start * 5 + 0xe6546b64;
+
+ return start;
+}
+
+static inline uint32_t
+hash_buffer(uint32_t start, const void *src, size_t len)
+{
+ const uint8_t *data = (const uint8_t *) src;
+ const int nblocks = len / 4;
+
+ uint32_t h1 = start;
+
+ //----------
+ // body
+
+ const uint32_t *blocks = (const uint32_t *) (data + nblocks*4);
+ int i;
+
+ for (i = -nblocks; i != 0; i++) {
+ uint32_t k1 = blocks[i];
+
+ k1 *= c1;
+ k1 = ROTL32(k1,15);
+ k1 *= c2;
+
+ h1 ^= k1;
+ h1 = ROTL32(h1,13);
+ h1 = h1*5+0xe6546b64;
+ }
+
+ //----------
+ // tail
+
+ const uint8_t *tail = (const uint8_t *) (data + nblocks*4);
+
+ uint32_t k1 = 0;
+
+ switch (len & 3)
+ {
+ case 3: k1 ^= tail[2] << 16;
+ case 2: k1 ^= tail[1] << 8;
+ case 1: k1 ^= tail[0];
+ k1 *= c1; k1 = ROTL32(k1,15); k1 *= c2; h1 ^= k1;
+ };
+
+ //----------
+ // finalization
+
+ h1 ^= len;
+ return h1;
+}
+
+static uint32_t
+avro_value_hash_fast(avro_value_t *value, uint32_t start)
+{
+ avro_type_t type = avro_value_get_type(value);
+
+ switch (type) {
+ case AVRO_BOOLEAN:
+ {
+ int v;
+ check_return(0, avro_value_get_boolean(value, &v));
+ return add_hash(start, v);
+ }
+
+ case AVRO_BYTES:
+ {
+ const void *buf;
+ size_t size;
+ check_return(0, avro_value_get_bytes(value, &buf, &size));
+ return hash_buffer(start, buf, size);
+ }
+
+ case AVRO_DOUBLE:
+ {
+ union {
+ double d;
+ uint32_t u32[2];
+ } v;
+ check_return(0, avro_value_get_double(value, &v.d));
+ return add_hash(add_hash(start, v.u32[0]), v.u32[1]);
+ }
+
+ case AVRO_FLOAT:
+ {
+ union {
+ float f;
+ uint32_t u32;
+ } v;
+ check_return(0, avro_value_get_float(value, &v.f));
+ return add_hash(start, v.u32);
+ }
+
+ case AVRO_INT32:
+ {
+ int32_t v;
+ check_return(0, avro_value_get_int(value, &v));
+ return add_hash(start, v);
+ }
+
+ case AVRO_INT64:
+ {
+ union {
+ int64_t u64;
+ uint32_t u32[2];
+ } v;
+ check_return(0, avro_value_get_long(value, &v.u64));
+ return add_hash(add_hash(start, v.u32[0]), v.u32[1]);
+ }
+
+ case AVRO_NULL:
+ {
+ check_return(0, avro_value_get_null(value));
+ return add_hash(start, 0);
+ }
+
+ case AVRO_STRING:
+ {
+ const char *buf;
+ size_t size;
+ check_return(0, avro_value_get_string(value, &buf, &size));
+ return hash_buffer(start, buf, size);
+ }
+
+ case AVRO_ARRAY:
+ {
+ size_t count;
+ size_t i;
+ check_return(0, avro_value_get_size(value, &count));
+
+ for (i = 0; i < count; i++) {
+ avro_value_t child;
+ check_return(0, avro_value_get_by_index
+ (value, i, &child, NULL));
+ start = avro_value_hash_fast(&child, start);
+ }
+
+ start ^= count;
+ return start;
+ }
+
+ case AVRO_ENUM:
+ {
+ int v;
+ check_return(0, avro_value_get_enum(value, &v));
+ return add_hash(start, v);
+ }
+
+ case AVRO_FIXED:
+ {
+ const void *buf;
+ size_t size;
+ check_return(0, avro_value_get_fixed(value, &buf, &size));
+ return hash_buffer(start, buf, size);
+ }
+
+ case AVRO_MAP:
+ {
+ size_t count;
+ size_t i;
+ check_return(0, avro_value_get_size(value, &count));
+
+ /*
+ * The hash for a map must be built up without
+ * taking into account the order of the elements
+ */
+ uint32_t map_hash = 0;
+ for (i = 0; i < count; i++) {
+ avro_value_t child;
+ const char *key;
+ check_return(0, avro_value_get_by_index
+ (value, i, &child, &key));
+
+ uint32_t element = SEED;
+ element = hash_buffer(element, key, strlen(key));
+ element = avro_value_hash_fast(&child, element);
+ element = fmix(element);
+
+ map_hash ^= element;
+ }
+ map_hash ^= count;
+
+ return add_hash(start, map_hash);
+ }
+
+ case AVRO_RECORD:
+ {
+ size_t count;
+ size_t i;
+ check_return(0, avro_value_get_size(value, &count));
+
+ for (i = 0; i < count; i++) {
+ avro_value_t child;
+ check_return(0, avro_value_get_by_index
+ (value, i, &child, NULL));
+ start = avro_value_hash_fast(&child, start);
+ }
+
+ start ^= count;
+ return start;
+ }
+
+ case AVRO_UNION:
+ {
+ int disc;
+ avro_value_t branch;
+ check_return(0, avro_value_get_discriminant(value, &disc));
+ check_return(0, avro_value_get_current_branch(value, &branch));
+
+ start = add_hash(start, disc);
+ start = avro_value_hash_fast(&branch, start);
+ return start;
+ }
+
+ default:
+ return 0;
+ }
+}
+
+uint32_t
+avro_value_hash(avro_value_t *value)
+{
+ uint32_t hash = avro_value_hash_fast(value, SEED);
+ return (hash == 0)? hash: fmix(hash);
+}
diff --git a/fluent-bit/lib/avro/src/value-json.c b/fluent-bit/lib/avro/src/value-json.c
new file mode 100644
index 000000000..53c2b3d3e
--- /dev/null
+++ b/fluent-bit/lib/avro/src/value-json.c
@@ -0,0 +1,417 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <errno.h>
+#include <avro/platform.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro/allocation.h"
+#include "avro/errors.h"
+#include "avro/legacy.h"
+#include "avro/schema.h"
+#include "avro/value.h"
+#include "avro_private.h"
+#include "jansson.h"
+
+/*
+ * Converts a binary buffer into a NUL-terminated JSON UTF-8 string.
+ * Avro bytes and fixed values are encoded in JSON as a string, and JSON
+ * strings must be in UTF-8. For these Avro types, the JSON string is
+ * restricted to the characters U+0000..U+00FF, which corresponds to the
+ * ISO-8859-1 character set. This function performs this conversion.
+ * The resulting string must be freed using avro_free when you're done
+ * with it.
+ */
+
+static int
+encode_utf8_bytes(const void *src, size_t src_len,
+ void **dest, size_t *dest_len)
+{
+ check_param(EINVAL, src, "source");
+ check_param(EINVAL, dest, "dest");
+ check_param(EINVAL, dest_len, "dest_len");
+
+ // First, determine the size of the resulting UTF-8 buffer.
+ // Bytes in the range 0x00..0x7f will take up one byte; bytes in
+ // the range 0x80..0xff will take up two.
+ const uint8_t *src8 = (const uint8_t *) src;
+
+ size_t utf8_len = src_len + 1; // +1 for NUL terminator
+ size_t i;
+ for (i = 0; i < src_len; i++) {
+ if (src8[i] & 0x80) {
+ utf8_len++;
+ }
+ }
+
+ // Allocate a new buffer for the UTF-8 string and fill it in.
+ uint8_t *dest8 = (uint8_t *) avro_malloc(utf8_len);
+ if (dest8 == NULL) {
+ avro_set_error("Cannot allocate JSON bytes buffer");
+ return ENOMEM;
+ }
+
+ uint8_t *curr = dest8;
+ for (i = 0; i < src_len; i++) {
+ if (src8[i] & 0x80) {
+ *curr++ = (0xc0 | (src8[i] >> 6));
+ *curr++ = (0x80 | (src8[i] & 0x3f));
+ } else {
+ *curr++ = src8[i];
+ }
+ }
+
+ *curr = '\0';
+
+ // And we're good.
+ *dest = dest8;
+ *dest_len = utf8_len;
+ return 0;
+}
+
+#define return_json(type, exp) \
+ { \
+ json_t *result = exp; \
+ if (result == NULL) { \
+ avro_set_error("Cannot allocate JSON " type); \
+ } \
+ return result; \
+ }
+
+#define check_return(retval, call) \
+ do { \
+ int __rc; \
+ __rc = call; \
+ if (__rc != 0) { \
+ return retval; \
+ } \
+ } while (0)
+
+static json_t *
+avro_value_to_json_t(const avro_value_t *value)
+{
+ switch (avro_value_get_type(value)) {
+ case AVRO_BOOLEAN:
+ {
+ int val;
+ check_return(NULL, avro_value_get_boolean(value, &val));
+ return_json("boolean",
+ val? json_true(): json_false());
+ }
+
+ case AVRO_BYTES:
+ {
+ const void *val;
+ size_t size;
+ void *encoded = NULL;
+ size_t encoded_size = 0;
+
+ check_return(NULL, avro_value_get_bytes(value, &val, &size));
+
+ if (encode_utf8_bytes(val, size, &encoded, &encoded_size)) {
+ return NULL;
+ }
+
+ json_t *result = json_string_nocheck((const char *) encoded);
+ avro_free(encoded, encoded_size);
+ if (result == NULL) {
+ avro_set_error("Cannot allocate JSON bytes");
+ }
+ return result;
+ }
+
+ case AVRO_DOUBLE:
+ {
+ double val;
+ check_return(NULL, avro_value_get_double(value, &val));
+ return_json("double", json_real(val));
+ }
+
+ case AVRO_FLOAT:
+ {
+ float val;
+ check_return(NULL, avro_value_get_float(value, &val));
+ return_json("float", json_real(val));
+ }
+
+ case AVRO_INT32:
+ {
+ int32_t val;
+ check_return(NULL, avro_value_get_int(value, &val));
+ return_json("int", json_integer(val));
+ }
+
+ case AVRO_INT64:
+ {
+ int64_t val;
+ check_return(NULL, avro_value_get_long(value, &val));
+ return_json("long", json_integer(val));
+ }
+
+ case AVRO_NULL:
+ {
+ check_return(NULL, avro_value_get_null(value));
+ return_json("null", json_null());
+ }
+
+ case AVRO_STRING:
+ {
+ const char *val;
+ size_t size;
+ check_return(NULL, avro_value_get_string(value, &val, &size));
+ return_json("string", json_string(val));
+ }
+
+ case AVRO_ARRAY:
+ {
+ int rc;
+ size_t element_count, i;
+ json_t *result = json_array();
+ if (result == NULL) {
+ avro_set_error("Cannot allocate JSON array");
+ return NULL;
+ }
+
+ rc = avro_value_get_size(value, &element_count);
+ if (rc != 0) {
+ json_decref(result);
+ return NULL;
+ }
+
+ for (i = 0; i < element_count; i++) {
+ avro_value_t element;
+ rc = avro_value_get_by_index(value, i, &element, NULL);
+ if (rc != 0) {
+ json_decref(result);
+ return NULL;
+ }
+
+ json_t *element_json = avro_value_to_json_t(&element);
+ if (element_json == NULL) {
+ json_decref(result);
+ return NULL;
+ }
+
+ if (json_array_append_new(result, element_json)) {
+ avro_set_error("Cannot append element to array");
+ json_decref(result);
+ return NULL;
+ }
+ }
+
+ return result;
+ }
+
+ case AVRO_ENUM:
+ {
+ avro_schema_t enum_schema;
+ int symbol_value;
+ const char *symbol_name;
+
+ check_return(NULL, avro_value_get_enum(value, &symbol_value));
+ enum_schema = avro_value_get_schema(value);
+ symbol_name = avro_schema_enum_get(enum_schema, symbol_value);
+ return_json("enum", json_string(symbol_name));
+ }
+
+ case AVRO_FIXED:
+ {
+ const void *val;
+ size_t size;
+ void *encoded = NULL;
+ size_t encoded_size = 0;
+
+ check_return(NULL, avro_value_get_fixed(value, &val, &size));
+
+ if (encode_utf8_bytes(val, size, &encoded, &encoded_size)) {
+ return NULL;
+ }
+
+ json_t *result = json_string_nocheck((const char *) encoded);
+ avro_free(encoded, encoded_size);
+ if (result == NULL) {
+ avro_set_error("Cannot allocate JSON fixed");
+ }
+ return result;
+ }
+
+ case AVRO_MAP:
+ {
+ int rc;
+ size_t element_count, i;
+ json_t *result = json_object();
+ if (result == NULL) {
+ avro_set_error("Cannot allocate JSON map");
+ return NULL;
+ }
+
+ rc = avro_value_get_size(value, &element_count);
+ if (rc != 0) {
+ json_decref(result);
+ return NULL;
+ }
+
+ for (i = 0; i < element_count; i++) {
+ const char *key;
+ avro_value_t element;
+
+ rc = avro_value_get_by_index(value, i, &element, &key);
+ if (rc != 0) {
+ json_decref(result);
+ return NULL;
+ }
+
+ json_t *element_json = avro_value_to_json_t(&element);
+ if (element_json == NULL) {
+ json_decref(result);
+ return NULL;
+ }
+
+ if (json_object_set_new(result, key, element_json)) {
+ avro_set_error("Cannot append element to map");
+ json_decref(result);
+ return NULL;
+ }
+ }
+
+ return result;
+ }
+
+ case AVRO_RECORD:
+ {
+ int rc;
+ size_t field_count, i;
+ json_t *result = json_object();
+ if (result == NULL) {
+ avro_set_error("Cannot allocate new JSON record");
+ return NULL;
+ }
+
+ rc = avro_value_get_size(value, &field_count);
+ if (rc != 0) {
+ json_decref(result);
+ return NULL;
+ }
+
+ for (i = 0; i < field_count; i++) {
+ const char *field_name;
+ avro_value_t field;
+
+ rc = avro_value_get_by_index(value, i, &field, &field_name);
+ if (rc != 0) {
+ json_decref(result);
+ return NULL;
+ }
+
+ json_t *field_json = avro_value_to_json_t(&field);
+ if (field_json == NULL) {
+ json_decref(result);
+ return NULL;
+ }
+
+ if (json_object_set_new(result, field_name, field_json)) {
+ avro_set_error("Cannot append field to record");
+ json_decref(result);
+ return NULL;
+ }
+ }
+
+ return result;
+ }
+
+ case AVRO_UNION:
+ {
+ int disc;
+ avro_value_t branch;
+ avro_schema_t union_schema;
+ avro_schema_t branch_schema;
+ const char *branch_name;
+
+ check_return(NULL, avro_value_get_current_branch(value, &branch));
+
+ if (avro_value_get_type(&branch) == AVRO_NULL) {
+ return_json("null", json_null());
+ }
+
+ check_return(NULL, avro_value_get_discriminant(value, &disc));
+ union_schema = avro_value_get_schema(value);
+ branch_schema =
+ avro_schema_union_branch(union_schema, disc);
+ branch_name = avro_schema_type_name(branch_schema);
+
+ json_t *result = json_object();
+ if (result == NULL) {
+ avro_set_error("Cannot allocate JSON union");
+ return NULL;
+ }
+
+ json_t *branch_json = avro_value_to_json_t(&branch);
+ if (branch_json == NULL) {
+ json_decref(result);
+ return NULL;
+ }
+
+ if (json_object_set_new(result, branch_name, branch_json)) {
+ avro_set_error("Cannot append branch to union");
+ json_decref(result);
+ return NULL;
+ }
+
+ return result;
+ }
+
+ default:
+ return NULL;
+ }
+}
+
+int
+avro_value_to_json(const avro_value_t *value,
+ int one_line, char **json_str)
+{
+ check_param(EINVAL, value, "value");
+ check_param(EINVAL, json_str, "string buffer");
+
+ json_t *json = avro_value_to_json_t(value);
+ if (json == NULL) {
+ return ENOMEM;
+ }
+
+ /*
+ * Jansson will only encode an object or array as the root
+ * element.
+ */
+
+ *json_str = json_dumps
+ (json,
+ JSON_ENCODE_ANY |
+ JSON_INDENT(one_line? 0: 2) |
+ JSON_ENSURE_ASCII |
+ JSON_PRESERVE_ORDER);
+ json_decref(json);
+ return 0;
+}
+
+int
+avro_datum_to_json(const avro_datum_t datum,
+ int one_line, char **json_str)
+{
+ avro_value_t value;
+ avro_datum_as_value(&value, datum);
+ return avro_value_to_json(&value, one_line, json_str);
+}
diff --git a/fluent-bit/lib/avro/src/value-read.c b/fluent-bit/lib/avro/src/value-read.c
new file mode 100644
index 000000000..b6b6e79fa
--- /dev/null
+++ b/fluent-bit/lib/avro/src/value-read.c
@@ -0,0 +1,392 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <avro/platform.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro/allocation.h"
+#include "avro/basics.h"
+#include "avro/data.h"
+#include "avro/io.h"
+#include "avro/value.h"
+#include "avro_private.h"
+#include "encoding.h"
+
+
+/*
+ * Forward declaration; this is basically the same as avro_value_read,
+ * but it doesn't reset dest first. (Since it will have already been
+ * reset in avro_value_read itself).
+ */
+
+static int
+read_value(avro_reader_t reader, avro_value_t *dest);
+
+
+static int
+read_array_value(avro_reader_t reader, avro_value_t *dest)
+{
+ int rval;
+ size_t i; /* index within the current block */
+ size_t index = 0; /* index within the entire array */
+ int64_t block_count;
+ int64_t block_size;
+
+ check_prefix(rval, avro_binary_encoding.
+ read_long(reader, &block_count),
+ "Cannot read array block count: ");
+
+ while (block_count != 0) {
+ if (block_count < 0) {
+ block_count = block_count * -1;
+ check_prefix(rval, avro_binary_encoding.
+ read_long(reader, &block_size),
+ "Cannot read array block size: ");
+ }
+
+ for (i = 0; i < (size_t) block_count; i++, index++) {
+ avro_value_t child;
+
+ check(rval, avro_value_append(dest, &child, NULL));
+ check(rval, read_value(reader, &child));
+ }
+
+ check_prefix(rval, avro_binary_encoding.
+ read_long(reader, &block_count),
+ "Cannot read array block count: ");
+ }
+
+ return 0;
+}
+
+
+static int
+read_map_value(avro_reader_t reader, avro_value_t *dest)
+{
+ int rval;
+ size_t i; /* index within the current block */
+ size_t index = 0; /* index within the entire array */
+ int64_t block_count;
+ int64_t block_size;
+
+ check_prefix(rval, avro_binary_encoding.read_long(reader, &block_count),
+ "Cannot read map block count: ");
+
+ while (block_count != 0) {
+ if (block_count < 0) {
+ block_count = block_count * -1;
+ check_prefix(rval, avro_binary_encoding.
+ read_long(reader, &block_size),
+ "Cannot read map block size: ");
+ }
+
+ for (i = 0; i < (size_t) block_count; i++, index++) {
+ char *key;
+ int64_t key_size;
+ avro_value_t child;
+
+ check_prefix(rval, avro_binary_encoding.
+ read_string(reader, &key, &key_size),
+ "Cannot read map key: ");
+
+ rval = avro_value_add(dest, key, &child, NULL, NULL);
+ if (rval) {
+ avro_free(key, key_size);
+ return rval;
+ }
+
+ rval = read_value(reader, &child);
+ if (rval) {
+ avro_free(key, key_size);
+ return rval;
+ }
+
+ avro_free(key, key_size);
+ }
+
+ check_prefix(rval, avro_binary_encoding.
+ read_long(reader, &block_count),
+ "Cannot read map block count: ");
+ }
+
+ return 0;
+}
+
+
+static int
+read_record_value(avro_reader_t reader, avro_value_t *dest)
+{
+ int rval;
+ size_t field_count;
+ size_t i;
+
+ avro_schema_t record_schema = avro_value_get_schema(dest);
+
+ check(rval, avro_value_get_size(dest, &field_count));
+ for (i = 0; i < field_count; i++) {
+ avro_value_t field;
+
+ check(rval, avro_value_get_by_index(dest, i, &field, NULL));
+ if (field.iface != NULL) {
+ check(rval, read_value(reader, &field));
+ } else {
+ avro_schema_t field_schema =
+ avro_schema_record_field_get_by_index(record_schema, i);
+ check(rval, avro_skip_data(reader, field_schema));
+ }
+ }
+
+ return 0;
+}
+
+
+static int
+read_union_value(avro_reader_t reader, avro_value_t *dest)
+{
+ int rval;
+ int64_t discriminant;
+ avro_schema_t union_schema;
+ int64_t branch_count;
+ avro_value_t branch;
+
+ check_prefix(rval, avro_binary_encoding.
+ read_long(reader, &discriminant),
+ "Cannot read union discriminant: ");
+
+ union_schema = avro_value_get_schema(dest);
+ branch_count = avro_schema_union_size(union_schema);
+
+ if (discriminant < 0 || discriminant >= branch_count) {
+ avro_set_error("Invalid union discriminant value: (%d)",
+ discriminant);
+ return 1;
+ }
+
+ check(rval, avro_value_set_branch(dest, discriminant, &branch));
+ check(rval, read_value(reader, &branch));
+ return 0;
+}
+
+
+/*
+ * A wrapped buffer implementation that takes control of a buffer
+ * allocated using avro_malloc.
+ */
+
+struct avro_wrapped_alloc {
+ const void *original;
+ size_t allocated_size;
+};
+
+static void
+avro_wrapped_alloc_free(avro_wrapped_buffer_t *self)
+{
+ struct avro_wrapped_alloc *alloc = (struct avro_wrapped_alloc *) self->user_data;
+ avro_free((void *) alloc->original, alloc->allocated_size);
+ avro_freet(struct avro_wrapped_alloc, alloc);
+}
+
+static int
+avro_wrapped_alloc_new(avro_wrapped_buffer_t *dest,
+ const void *buf, size_t length)
+{
+ struct avro_wrapped_alloc *alloc = (struct avro_wrapped_alloc *) avro_new(struct avro_wrapped_alloc);
+ if (alloc == NULL) {
+ return ENOMEM;
+ }
+
+ dest->buf = buf;
+ dest->size = length;
+ dest->user_data = alloc;
+ dest->free = avro_wrapped_alloc_free;
+ dest->copy = NULL;
+ dest->slice = NULL;
+
+ alloc->original = buf;
+ alloc->allocated_size = length;
+ return 0;
+}
+
+
+static int
+read_value(avro_reader_t reader, avro_value_t *dest)
+{
+ int rval;
+
+ switch (avro_value_get_type(dest)) {
+ case AVRO_BOOLEAN:
+ {
+ int8_t val;
+ check_prefix(rval, avro_binary_encoding.
+ read_boolean(reader, &val),
+ "Cannot read boolean value: ");
+ return avro_value_set_boolean(dest, val);
+ }
+
+ case AVRO_BYTES:
+ {
+ char *bytes;
+ int64_t len;
+ check_prefix(rval, avro_binary_encoding.
+ read_bytes(reader, &bytes, &len),
+ "Cannot read bytes value: ");
+
+ /*
+ * read_bytes allocates an extra byte to always
+ * ensure that the data is NUL terminated, but
+ * that byte isn't included in the length. We
+ * include that extra byte in the allocated
+ * size, but not in the length of the buffer.
+ */
+
+ avro_wrapped_buffer_t buf;
+ check(rval, avro_wrapped_alloc_new(&buf, bytes, len+1));
+ buf.size--;
+ return avro_value_give_bytes(dest, &buf);
+ }
+
+ case AVRO_DOUBLE:
+ {
+ double val;
+ check_prefix(rval, avro_binary_encoding.
+ read_double(reader, &val),
+ "Cannot read double value: ");
+ return avro_value_set_double(dest, val);
+ }
+
+ case AVRO_FLOAT:
+ {
+ float val;
+ check_prefix(rval, avro_binary_encoding.
+ read_float(reader, &val),
+ "Cannot read float value: ");
+ return avro_value_set_float(dest, val);
+ }
+
+ case AVRO_INT32:
+ {
+ int32_t val;
+ check_prefix(rval, avro_binary_encoding.
+ read_int(reader, &val),
+ "Cannot read int value: ");
+ return avro_value_set_int(dest, val);
+ }
+
+ case AVRO_INT64:
+ {
+ int64_t val;
+ check_prefix(rval, avro_binary_encoding.
+ read_long(reader, &val),
+ "Cannot read long value: ");
+ return avro_value_set_long(dest, val);
+ }
+
+ case AVRO_NULL:
+ {
+ check_prefix(rval, avro_binary_encoding.
+ read_null(reader),
+ "Cannot read null value: ");
+ return avro_value_set_null(dest);
+ }
+
+ case AVRO_STRING:
+ {
+ char *str;
+ int64_t size;
+
+ /*
+ * read_string returns a size that includes the
+ * NUL terminator, and the free function will be
+ * called with a size that also includes the NUL
+ */
+
+ check_prefix(rval, avro_binary_encoding.
+ read_string(reader, &str, &size),
+ "Cannot read string value: ");
+
+ avro_wrapped_buffer_t buf;
+ check(rval, avro_wrapped_alloc_new(&buf, str, size));
+ return avro_value_give_string_len(dest, &buf);
+ }
+
+ case AVRO_ARRAY:
+ return read_array_value(reader, dest);
+
+ case AVRO_ENUM:
+ {
+ int64_t val;
+ check_prefix(rval, avro_binary_encoding.
+ read_long(reader, &val),
+ "Cannot read enum value: ");
+ return avro_value_set_enum(dest, val);
+ }
+
+ case AVRO_FIXED:
+ {
+ avro_schema_t schema = avro_value_get_schema(dest);
+ char *bytes;
+ int64_t size = avro_schema_fixed_size(schema);
+
+ bytes = (char *) avro_malloc(size);
+ if (!bytes) {
+ avro_prefix_error("Cannot allocate new fixed value");
+ return ENOMEM;
+ }
+ rval = avro_read(reader, bytes, size);
+ if (rval) {
+ avro_prefix_error("Cannot read fixed value: ");
+ avro_free(bytes, size);
+ return rval;
+ }
+
+ avro_wrapped_buffer_t buf;
+ rval = avro_wrapped_alloc_new(&buf, bytes, size);
+ if (rval != 0) {
+ avro_free(bytes, size);
+ return rval;
+ }
+
+ return avro_value_give_fixed(dest, &buf);
+ }
+
+ case AVRO_MAP:
+ return read_map_value(reader, dest);
+
+ case AVRO_RECORD:
+ return read_record_value(reader, dest);
+
+ case AVRO_UNION:
+ return read_union_value(reader, dest);
+
+ default:
+ {
+ avro_set_error("Unknown schema type");
+ return EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+int
+avro_value_read(avro_reader_t reader, avro_value_t *dest)
+{
+ int rval;
+ check(rval, avro_value_reset(dest));
+ return read_value(reader, dest);
+}
diff --git a/fluent-bit/lib/avro/src/value-sizeof.c b/fluent-bit/lib/avro/src/value-sizeof.c
new file mode 100644
index 000000000..bcbffb5b6
--- /dev/null
+++ b/fluent-bit/lib/avro/src/value-sizeof.c
@@ -0,0 +1,230 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <avro/platform.h>
+#include <stdlib.h>
+
+#include "avro/basics.h"
+#include "avro/io.h"
+#include "avro/value.h"
+#include "avro_private.h"
+#include "encoding.h"
+
+
+/*
+ * Forward declaration; this is basically the same as avro_value_sizeof,
+ * but it doesn't initialize size first. (Since it will have already
+ * been initialized in avro_value_sizeof itself).
+ */
+
+static int
+sizeof_value(avro_value_t *src, size_t *size);
+
+
+static int
+sizeof_array_value(avro_value_t *src, size_t *size)
+{
+ int rval;
+ size_t element_count;
+ check(rval, avro_value_get_size(src, &element_count));
+
+ if (element_count > 0) {
+ *size += avro_binary_encoding.size_long(NULL, element_count);
+
+ size_t i;
+ for (i = 0; i < element_count; i++) {
+ avro_value_t child;
+ check(rval, avro_value_get_by_index(src, i, &child, NULL));
+ check(rval, sizeof_value(&child, size));
+ }
+ }
+
+ *size += avro_binary_encoding.size_long(NULL, 0);
+ return 0;
+}
+
+
+static int
+sizeof_map_value(avro_value_t *src, size_t *size)
+{
+ int rval;
+ size_t element_count;
+ check(rval, avro_value_get_size(src, &element_count));
+
+ if (element_count > 0) {
+ *size += avro_binary_encoding.size_long(NULL, element_count);
+
+ size_t i;
+ for (i = 0; i < element_count; i++) {
+ avro_value_t child;
+ const char *key;
+ check(rval, avro_value_get_by_index(src, i, &child, &key));
+ *size += avro_binary_encoding.size_string(NULL, key);
+ check(rval, sizeof_value(&child, size));
+ }
+ }
+
+ *size += avro_binary_encoding.size_long(NULL, 0);
+ return 0;
+}
+
+static int
+sizeof_record_value(avro_value_t *src, size_t *size)
+{
+ int rval;
+ size_t field_count;
+ check(rval, avro_value_get_size(src, &field_count));
+
+ size_t i;
+ for (i = 0; i < field_count; i++) {
+ avro_value_t field;
+ check(rval, avro_value_get_by_index(src, i, &field, NULL));
+ check(rval, sizeof_value(&field, size));
+ }
+
+ return 0;
+}
+
+static int
+sizeof_union_value(avro_value_t *src, size_t *size)
+{
+ int rval;
+ int discriminant;
+ avro_value_t branch;
+
+ check(rval, avro_value_get_discriminant(src, &discriminant));
+ check(rval, avro_value_get_current_branch(src, &branch));
+ *size += avro_binary_encoding.size_long(NULL, discriminant);
+ return sizeof_value(&branch, size);
+}
+
+static int
+sizeof_value(avro_value_t *src, size_t *size)
+{
+ int rval;
+
+ switch (avro_value_get_type(src)) {
+ case AVRO_BOOLEAN:
+ {
+ int val;
+ check(rval, avro_value_get_boolean(src, &val));
+ *size += avro_binary_encoding.size_boolean(NULL, val);
+ return 0;
+ }
+
+ case AVRO_BYTES:
+ {
+ const void *buf;
+ size_t sz;
+ check(rval, avro_value_get_bytes(src, &buf, &sz));
+ *size += avro_binary_encoding.size_bytes(NULL, (const char *) buf, sz);
+ return 0;
+ }
+
+ case AVRO_DOUBLE:
+ {
+ double val;
+ check(rval, avro_value_get_double(src, &val));
+ *size += avro_binary_encoding.size_double(NULL, val);
+ return 0;
+ }
+
+ case AVRO_FLOAT:
+ {
+ float val;
+ check(rval, avro_value_get_float(src, &val));
+ *size += avro_binary_encoding.size_float(NULL, val);
+ return 0;
+ }
+
+ case AVRO_INT32:
+ {
+ int32_t val;
+ check(rval, avro_value_get_int(src, &val));
+ *size += avro_binary_encoding.size_long(NULL, val);
+ return 0;
+ }
+
+ case AVRO_INT64:
+ {
+ int64_t val;
+ check(rval, avro_value_get_long(src, &val));
+ *size += avro_binary_encoding.size_long(NULL, val);
+ return 0;
+ }
+
+ case AVRO_NULL:
+ {
+ check(rval, avro_value_get_null(src));
+ *size += avro_binary_encoding.size_null(NULL);
+ return 0;
+ }
+
+ case AVRO_STRING:
+ {
+ const char *str;
+ size_t sz;
+ check(rval, avro_value_get_string(src, &str, &sz));
+ *size += avro_binary_encoding.size_bytes(NULL, str, sz-1);
+ return 0;
+ }
+
+ case AVRO_ARRAY:
+ return sizeof_array_value(src, size);
+
+ case AVRO_ENUM:
+ {
+ int val;
+ check(rval, avro_value_get_enum(src, &val));
+ *size += avro_binary_encoding.size_long(NULL, val);
+ return 0;
+ }
+
+ case AVRO_FIXED:
+ {
+ size_t sz;
+ check(rval, avro_value_get_fixed(src, NULL, &sz));
+ *size += sz;
+ return 0;
+ }
+
+ case AVRO_MAP:
+ return sizeof_map_value(src, size);
+
+ case AVRO_RECORD:
+ return sizeof_record_value(src, size);
+
+ case AVRO_UNION:
+ return sizeof_union_value(src, size);
+
+ default:
+ {
+ avro_set_error("Unknown schema type");
+ return EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+int
+avro_value_sizeof(avro_value_t *src, size_t *size)
+{
+ check_param(EINVAL, size, "size pointer");
+ *size = 0;
+ return sizeof_value(src, size);
+}
diff --git a/fluent-bit/lib/avro/src/value-write.c b/fluent-bit/lib/avro/src/value-write.c
new file mode 100644
index 000000000..bcd0fb0a4
--- /dev/null
+++ b/fluent-bit/lib/avro/src/value-write.c
@@ -0,0 +1,209 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <avro/platform.h>
+#include <stdlib.h>
+
+#include "avro/basics.h"
+#include "avro/io.h"
+#include "avro/value.h"
+#include "avro_private.h"
+#include "encoding.h"
+
+
+static int
+write_array_value(avro_writer_t writer, avro_value_t *src)
+{
+ int rval;
+ size_t element_count;
+ check(rval, avro_value_get_size(src, &element_count));
+
+ if (element_count > 0) {
+ check_prefix(rval, avro_binary_encoding.write_long
+ (writer, element_count),
+ "Cannot write array block count: ");
+
+ size_t i;
+ for (i = 0; i < element_count; i++) {
+ avro_value_t child;
+ check(rval, avro_value_get_by_index(src, i, &child, NULL));
+ check(rval, avro_value_write(writer, &child));
+ }
+ }
+
+ check_prefix(rval, avro_binary_encoding.write_long(writer, 0),
+ "Cannot write array block count: ");
+ return 0;
+}
+
+
+static int
+write_map_value(avro_writer_t writer, avro_value_t *src)
+{
+ int rval;
+ size_t element_count;
+ check(rval, avro_value_get_size(src, &element_count));
+
+ if (element_count > 0) {
+ check_prefix(rval, avro_binary_encoding.write_long
+ (writer, element_count),
+ "Cannot write map block count: ");
+
+ size_t i;
+ for (i = 0; i < element_count; i++) {
+ avro_value_t child;
+ const char *key;
+ check(rval, avro_value_get_by_index(src, i, &child, &key));
+ check(rval, avro_binary_encoding.write_string(writer, key));
+ check(rval, avro_value_write(writer, &child));
+ }
+ }
+
+ check_prefix(rval, avro_binary_encoding.write_long(writer, 0),
+ "Cannot write map block count: ");
+ return 0;
+}
+
+static int
+write_record_value(avro_writer_t writer, avro_value_t *src)
+{
+ int rval;
+ size_t field_count;
+ check(rval, avro_value_get_size(src, &field_count));
+
+ size_t i;
+ for (i = 0; i < field_count; i++) {
+ avro_value_t field;
+ check(rval, avro_value_get_by_index(src, i, &field, NULL));
+ check(rval, avro_value_write(writer, &field));
+ }
+
+ return 0;
+}
+
+static int
+write_union_value(avro_writer_t writer, avro_value_t *src)
+{
+ int rval;
+ int discriminant;
+ avro_value_t branch;
+
+ check(rval, avro_value_get_discriminant(src, &discriminant));
+ check(rval, avro_value_get_current_branch(src, &branch));
+ check(rval, avro_binary_encoding.write_long(writer, discriminant));
+ return avro_value_write(writer, &branch);
+}
+
+int
+avro_value_write(avro_writer_t writer, avro_value_t *src)
+{
+ int rval;
+
+ switch (avro_value_get_type(src)) {
+ case AVRO_BOOLEAN:
+ {
+ int val;
+ check(rval, avro_value_get_boolean(src, &val));
+ return avro_binary_encoding.write_boolean(writer, val);
+ }
+
+ case AVRO_BYTES:
+ {
+ const void *buf;
+ size_t size;
+ check(rval, avro_value_get_bytes(src, &buf, &size));
+ return avro_binary_encoding.write_bytes(writer, (const char *) buf, size);
+ }
+
+ case AVRO_DOUBLE:
+ {
+ double val;
+ check(rval, avro_value_get_double(src, &val));
+ return avro_binary_encoding.write_double(writer, val);
+ }
+
+ case AVRO_FLOAT:
+ {
+ float val;
+ check(rval, avro_value_get_float(src, &val));
+ return avro_binary_encoding.write_float(writer, val);
+ }
+
+ case AVRO_INT32:
+ {
+ int32_t val;
+ check(rval, avro_value_get_int(src, &val));
+ return avro_binary_encoding.write_long(writer, val);
+ }
+
+ case AVRO_INT64:
+ {
+ int64_t val;
+ check(rval, avro_value_get_long(src, &val));
+ return avro_binary_encoding.write_long(writer, val);
+ }
+
+ case AVRO_NULL:
+ {
+ check(rval, avro_value_get_null(src));
+ return avro_binary_encoding.write_null(writer);
+ }
+
+ case AVRO_STRING:
+ {
+ const char *str;
+ size_t size;
+ check(rval, avro_value_get_string(src, &str, &size));
+ return avro_binary_encoding.write_bytes(writer, str, size-1);
+ }
+
+ case AVRO_ARRAY:
+ return write_array_value(writer, src);
+
+ case AVRO_ENUM:
+ {
+ int val;
+ check(rval, avro_value_get_enum(src, &val));
+ return avro_binary_encoding.write_long(writer, val);
+ }
+
+ case AVRO_FIXED:
+ {
+ const void *buf;
+ size_t size;
+ check(rval, avro_value_get_fixed(src, &buf, &size));
+ return avro_write(writer, (void *) buf, size);
+ }
+
+ case AVRO_MAP:
+ return write_map_value(writer, src);
+
+ case AVRO_RECORD:
+ return write_record_value(writer, src);
+
+ case AVRO_UNION:
+ return write_union_value(writer, src);
+
+ default:
+ {
+ avro_set_error("Unknown schema type");
+ return EINVAL;
+ }
+ }
+
+ return 0;
+}
diff --git a/fluent-bit/lib/avro/src/value.c b/fluent-bit/lib/avro/src/value.c
new file mode 100644
index 000000000..b177504e5
--- /dev/null
+++ b/fluent-bit/lib/avro/src/value.c
@@ -0,0 +1,690 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro/allocation.h"
+#include "avro/data.h"
+#include "avro/errors.h"
+#include "avro/value.h"
+#include "avro_private.h"
+
+
+#define check_return(retval, call) \
+ do { \
+ int rval = call; \
+ if (rval != 0) { return (retval); } \
+ } while (0)
+
+
+void
+avro_value_incref(avro_value_t *value)
+{
+ value->iface->incref(value);
+}
+
+void
+avro_value_decref(avro_value_t *value)
+{
+ value->iface->decref(value);
+ avro_value_iface_decref(value->iface);
+ value->iface = NULL;
+ value->self = NULL;
+}
+
+void
+avro_value_copy_ref(avro_value_t *dest, const avro_value_t *src)
+{
+ dest->iface = src->iface;
+ dest->self = src->self;
+ avro_value_iface_incref(dest->iface);
+ dest->iface->incref(dest);
+}
+
+void
+avro_value_move_ref(avro_value_t *dest, avro_value_t *src)
+{
+ dest->iface = src->iface;
+ dest->self = src->self;
+ src->iface = NULL;
+ src->self = NULL;
+}
+
+
+int
+avro_value_equal_fast(avro_value_t *val1, avro_value_t *val2)
+{
+ avro_type_t type1 = avro_value_get_type(val1);
+ avro_type_t type2 = avro_value_get_type(val2);
+ if (type1 != type2) {
+ return 0;
+ }
+
+ switch (type1) {
+ case AVRO_BOOLEAN:
+ {
+ int v1;
+ int v2;
+ check_return(0, avro_value_get_boolean(val1, &v1));
+ check_return(0, avro_value_get_boolean(val2, &v2));
+ return (v1 == v2);
+ }
+
+ case AVRO_BYTES:
+ {
+ const void *buf1;
+ const void *buf2;
+ size_t size1;
+ size_t size2;
+ check_return(0, avro_value_get_bytes(val1, &buf1, &size1));
+ check_return(0, avro_value_get_bytes(val2, &buf2, &size2));
+ if (size1 != size2) {
+ return 0;
+ }
+ return (memcmp(buf1, buf2, size1) == 0);
+ }
+
+ case AVRO_DOUBLE:
+ {
+ double v1;
+ double v2;
+ check_return(0, avro_value_get_double(val1, &v1));
+ check_return(0, avro_value_get_double(val2, &v2));
+ return (v1 == v2);
+ }
+
+ case AVRO_FLOAT:
+ {
+ float v1;
+ float v2;
+ check_return(0, avro_value_get_float(val1, &v1));
+ check_return(0, avro_value_get_float(val2, &v2));
+ return (v1 == v2);
+ }
+
+ case AVRO_INT32:
+ {
+ int32_t v1;
+ int32_t v2;
+ check_return(0, avro_value_get_int(val1, &v1));
+ check_return(0, avro_value_get_int(val2, &v2));
+ return (v1 == v2);
+ }
+
+ case AVRO_INT64:
+ {
+ int64_t v1;
+ int64_t v2;
+ check_return(0, avro_value_get_long(val1, &v1));
+ check_return(0, avro_value_get_long(val2, &v2));
+ return (v1 == v2);
+ }
+
+ case AVRO_NULL:
+ {
+ check_return(0, avro_value_get_null(val1));
+ check_return(0, avro_value_get_null(val2));
+ return 1;
+ }
+
+ case AVRO_STRING:
+ {
+ const char *buf1;
+ const char *buf2;
+ size_t size1;
+ size_t size2;
+ check_return(0, avro_value_get_string(val1, &buf1, &size1));
+ check_return(0, avro_value_get_string(val2, &buf2, &size2));
+ if (size1 != size2) {
+ return 0;
+ }
+ return (memcmp(buf1, buf2, size1) == 0);
+ }
+
+ case AVRO_ARRAY:
+ {
+ size_t count1;
+ size_t count2;
+ check_return(0, avro_value_get_size(val1, &count1));
+ check_return(0, avro_value_get_size(val2, &count2));
+ if (count1 != count2) {
+ return 0;
+ }
+
+ size_t i;
+ for (i = 0; i < count1; i++) {
+ avro_value_t child1;
+ avro_value_t child2;
+ check_return(0, avro_value_get_by_index
+ (val1, i, &child1, NULL));
+ check_return(0, avro_value_get_by_index
+ (val2, i, &child2, NULL));
+ if (!avro_value_equal_fast(&child1, &child2)) {
+ return 0;
+ }
+ }
+
+ return 1;
+ }
+
+ case AVRO_ENUM:
+ {
+ int v1;
+ int v2;
+ check_return(0, avro_value_get_enum(val1, &v1));
+ check_return(0, avro_value_get_enum(val2, &v2));
+ return (v1 == v2);
+ }
+
+ case AVRO_FIXED:
+ {
+ const void *buf1;
+ const void *buf2;
+ size_t size1;
+ size_t size2;
+ check_return(0, avro_value_get_fixed(val1, &buf1, &size1));
+ check_return(0, avro_value_get_fixed(val2, &buf2, &size2));
+ if (size1 != size2) {
+ return 0;
+ }
+ return (memcmp(buf1, buf2, size1) == 0);
+ }
+
+ case AVRO_MAP:
+ {
+ size_t count1;
+ size_t count2;
+ check_return(0, avro_value_get_size(val1, &count1));
+ check_return(0, avro_value_get_size(val2, &count2));
+ if (count1 != count2) {
+ return 0;
+ }
+
+ size_t i;
+ for (i = 0; i < count1; i++) {
+ avro_value_t child1;
+ avro_value_t child2;
+ const char *key1;
+ check_return(0, avro_value_get_by_index
+ (val1, i, &child1, &key1));
+ check_return(0, avro_value_get_by_name
+ (val2, key1, &child2, NULL));
+ if (!avro_value_equal_fast(&child1, &child2)) {
+ return 0;
+ }
+ }
+
+ return 1;
+ }
+
+ case AVRO_RECORD:
+ {
+ size_t count1;
+ check_return(0, avro_value_get_size(val1, &count1));
+
+ size_t i;
+ for (i = 0; i < count1; i++) {
+ avro_value_t child1;
+ avro_value_t child2;
+ check_return(0, avro_value_get_by_index
+ (val1, i, &child1, NULL));
+ check_return(0, avro_value_get_by_index
+ (val2, i, &child2, NULL));
+ if (!avro_value_equal_fast(&child1, &child2)) {
+ return 0;
+ }
+ }
+
+ return 1;
+ }
+
+ case AVRO_UNION:
+ {
+ int disc1;
+ int disc2;
+ check_return(0, avro_value_get_discriminant(val1, &disc1));
+ check_return(0, avro_value_get_discriminant(val2, &disc2));
+ if (disc1 != disc2) {
+ return 0;
+ }
+
+ avro_value_t branch1;
+ avro_value_t branch2;
+ check_return(0, avro_value_get_current_branch(val1, &branch1));
+ check_return(0, avro_value_get_current_branch(val2, &branch2));
+ return avro_value_equal_fast(&branch1, &branch2);
+ }
+
+ default:
+ return 0;
+ }
+}
+
+int
+avro_value_equal(avro_value_t *val1, avro_value_t *val2)
+{
+ avro_schema_t schema1 = avro_value_get_schema(val1);
+ avro_schema_t schema2 = avro_value_get_schema(val2);
+ if (!avro_schema_equal(schema1, schema2)) {
+ return 0;
+ }
+
+ return avro_value_equal_fast(val1, val2);
+}
+
+
+#define cmp(v1, v2) \
+ (((v1) == (v2))? 0: \
+ ((v1) < (v2))? -1: 1)
+int
+avro_value_cmp_fast(avro_value_t *val1, avro_value_t *val2)
+{
+ avro_type_t type1 = avro_value_get_type(val1);
+ avro_type_t type2 = avro_value_get_type(val2);
+ if (type1 != type2) {
+ return -1;
+ }
+
+ switch (type1) {
+ case AVRO_BOOLEAN:
+ {
+ int v1;
+ int v2;
+ check_return(0, avro_value_get_boolean(val1, &v1));
+ check_return(0, avro_value_get_boolean(val2, &v2));
+ return cmp(!!v1, !!v2);
+ }
+
+ case AVRO_BYTES:
+ {
+ const void *buf1;
+ const void *buf2;
+ size_t size1;
+ size_t size2;
+ size_t min_size;
+ int result;
+
+ check_return(0, avro_value_get_bytes(val1, &buf1, &size1));
+ check_return(0, avro_value_get_bytes(val2, &buf2, &size2));
+
+ min_size = (size1 < size2)? size1: size2;
+ result = memcmp(buf1, buf2, min_size);
+ if (result != 0) {
+ return result;
+ } else {
+ return cmp(size1, size2);
+ }
+ }
+
+ case AVRO_DOUBLE:
+ {
+ double v1;
+ double v2;
+ check_return(0, avro_value_get_double(val1, &v1));
+ check_return(0, avro_value_get_double(val2, &v2));
+ return cmp(v1, v2);
+ }
+
+ case AVRO_FLOAT:
+ {
+ float v1;
+ float v2;
+ check_return(0, avro_value_get_float(val1, &v1));
+ check_return(0, avro_value_get_float(val2, &v2));
+ return cmp(v1, v2);
+ }
+
+ case AVRO_INT32:
+ {
+ int32_t v1;
+ int32_t v2;
+ check_return(0, avro_value_get_int(val1, &v1));
+ check_return(0, avro_value_get_int(val2, &v2));
+ return cmp(v1, v2);
+ }
+
+ case AVRO_INT64:
+ {
+ int64_t v1;
+ int64_t v2;
+ check_return(0, avro_value_get_long(val1, &v1));
+ check_return(0, avro_value_get_long(val2, &v2));
+ return cmp(v1, v2);
+ }
+
+ case AVRO_NULL:
+ {
+ check_return(0, avro_value_get_null(val1));
+ check_return(0, avro_value_get_null(val2));
+ return 0;
+ }
+
+ case AVRO_STRING:
+ {
+ const char *buf1;
+ const char *buf2;
+ size_t size1;
+ size_t size2;
+ size_t min_size;
+ int result;
+ check_return(0, avro_value_get_string(val1, &buf1, &size1));
+ check_return(0, avro_value_get_string(val2, &buf2, &size2));
+
+ min_size = (size1 < size2)? size1: size2;
+ result = memcmp(buf1, buf2, min_size);
+ if (result != 0) {
+ return result;
+ } else {
+ return cmp(size1, size2);
+ }
+ }
+
+ case AVRO_ARRAY:
+ {
+ size_t count1;
+ size_t count2;
+ size_t min_count;
+ size_t i;
+ check_return(0, avro_value_get_size(val1, &count1));
+ check_return(0, avro_value_get_size(val2, &count2));
+
+ min_count = (count1 < count2)? count1: count2;
+ for (i = 0; i < min_count; i++) {
+ avro_value_t child1;
+ avro_value_t child2;
+ int result;
+ check_return(0, avro_value_get_by_index
+ (val1, i, &child1, NULL));
+ check_return(0, avro_value_get_by_index
+ (val2, i, &child2, NULL));
+ result = avro_value_cmp_fast(&child1, &child2);
+ if (result != 0) {
+ return result;
+ }
+ }
+
+ return cmp(count1, count2);
+ }
+
+ case AVRO_ENUM:
+ {
+ int v1;
+ int v2;
+ check_return(0, avro_value_get_enum(val1, &v1));
+ check_return(0, avro_value_get_enum(val2, &v2));
+ return cmp(v1, v2);
+ }
+
+ case AVRO_FIXED:
+ {
+ const void *buf1;
+ const void *buf2;
+ size_t size1;
+ size_t size2;
+ check_return(0, avro_value_get_fixed(val1, &buf1, &size1));
+ check_return(0, avro_value_get_fixed(val2, &buf2, &size2));
+ if (size1 != size2) {
+ return -1;
+ }
+ return memcmp(buf1, buf2, size1);
+ }
+
+ case AVRO_MAP:
+ {
+ return -1;
+ }
+
+ case AVRO_RECORD:
+ {
+ size_t count1;
+ check_return(0, avro_value_get_size(val1, &count1));
+
+ size_t i;
+ for (i = 0; i < count1; i++) {
+ avro_value_t child1;
+ avro_value_t child2;
+ int result;
+
+ check_return(0, avro_value_get_by_index
+ (val1, i, &child1, NULL));
+ check_return(0, avro_value_get_by_index
+ (val2, i, &child2, NULL));
+ result = avro_value_cmp_fast(&child1, &child2);
+ if (result != 0) {
+ return result;
+ }
+ }
+
+ return 0;
+ }
+
+ case AVRO_UNION:
+ {
+ int disc1;
+ int disc2;
+ check_return(0, avro_value_get_discriminant(val1, &disc1));
+ check_return(0, avro_value_get_discriminant(val2, &disc2));
+
+ if (disc1 == disc2) {
+ avro_value_t branch1;
+ avro_value_t branch2;
+ check_return(0, avro_value_get_current_branch(val1, &branch1));
+ check_return(0, avro_value_get_current_branch(val2, &branch2));
+ return avro_value_cmp_fast(&branch1, &branch2);
+ } else {
+ return cmp(disc1, disc2);
+ }
+ }
+
+ default:
+ return 0;
+ }
+}
+
+int
+avro_value_cmp(avro_value_t *val1, avro_value_t *val2)
+{
+ avro_schema_t schema1 = avro_value_get_schema(val1);
+ avro_schema_t schema2 = avro_value_get_schema(val2);
+ if (!avro_schema_equal(schema1, schema2)) {
+ return 0;
+ }
+
+ return avro_value_cmp_fast(val1, val2);
+}
+
+
+int
+avro_value_copy_fast(avro_value_t *dest, const avro_value_t *src)
+{
+ avro_type_t dest_type = avro_value_get_type(dest);
+ avro_type_t src_type = avro_value_get_type(src);
+ if (dest_type != src_type) {
+ return 0;
+ }
+
+ int rval;
+ check(rval, avro_value_reset(dest));
+
+ switch (dest_type) {
+ case AVRO_BOOLEAN:
+ {
+ int val;
+ check(rval, avro_value_get_boolean(src, &val));
+ return avro_value_set_boolean(dest, val);
+ }
+
+ case AVRO_BYTES:
+ {
+ avro_wrapped_buffer_t val;
+ check(rval, avro_value_grab_bytes(src, &val));
+ return avro_value_give_bytes(dest, &val);
+ }
+
+ case AVRO_DOUBLE:
+ {
+ double val;
+ check(rval, avro_value_get_double(src, &val));
+ return avro_value_set_double(dest, val);
+ }
+
+ case AVRO_FLOAT:
+ {
+ float val;
+ check(rval, avro_value_get_float(src, &val));
+ return avro_value_set_float(dest, val);
+ }
+
+ case AVRO_INT32:
+ {
+ int32_t val;
+ check(rval, avro_value_get_int(src, &val));
+ return avro_value_set_int(dest, val);
+ }
+
+ case AVRO_INT64:
+ {
+ int64_t val;
+ check(rval, avro_value_get_long(src, &val));
+ return avro_value_set_long(dest, val);
+ }
+
+ case AVRO_NULL:
+ {
+ check(rval, avro_value_get_null(src));
+ return avro_value_set_null(dest);
+ }
+
+ case AVRO_STRING:
+ {
+ avro_wrapped_buffer_t val;
+ check(rval, avro_value_grab_string(src, &val));
+ return avro_value_give_string_len(dest, &val);
+ }
+
+ case AVRO_ARRAY:
+ {
+ size_t count;
+ check(rval, avro_value_get_size(src, &count));
+
+ size_t i;
+ for (i = 0; i < count; i++) {
+ avro_value_t src_child;
+ avro_value_t dest_child;
+
+ check(rval, avro_value_get_by_index
+ (src, i, &src_child, NULL));
+ check(rval, avro_value_append
+ (dest, &dest_child, NULL));
+ check(rval, avro_value_copy_fast
+ (&dest_child, &src_child));
+ }
+
+ return 0;
+ }
+
+ case AVRO_ENUM:
+ {
+ int val;
+ check(rval, avro_value_get_enum(src, &val));
+ return avro_value_set_enum(dest, val);
+ }
+
+ case AVRO_FIXED:
+ {
+ avro_wrapped_buffer_t val;
+ check(rval, avro_value_grab_fixed(src, &val));
+ return avro_value_give_fixed(dest, &val);
+ }
+
+ case AVRO_MAP:
+ {
+ size_t count;
+ check(rval, avro_value_get_size(src, &count));
+
+ size_t i;
+ for (i = 0; i < count; i++) {
+ avro_value_t src_child;
+ avro_value_t dest_child;
+ const char *key;
+
+ check(rval, avro_value_get_by_index
+ (src, i, &src_child, &key));
+ check(rval, avro_value_add
+ (dest, key, &dest_child, NULL, NULL));
+ check(rval, avro_value_copy_fast
+ (&dest_child, &src_child));
+ }
+
+ return 0;
+ }
+
+ case AVRO_RECORD:
+ {
+ size_t count;
+ check(rval, avro_value_get_size(src, &count));
+
+ size_t i;
+ for (i = 0; i < count; i++) {
+ avro_value_t src_child;
+ avro_value_t dest_child;
+
+ check(rval, avro_value_get_by_index
+ (src, i, &src_child, NULL));
+ check(rval, avro_value_get_by_index
+ (dest, i, &dest_child, NULL));
+ check(rval, avro_value_copy_fast
+ (&dest_child, &src_child));
+ }
+
+ return 0;
+ }
+
+ case AVRO_UNION:
+ {
+ int disc;
+ check(rval, avro_value_get_discriminant(src, &disc));
+
+ avro_value_t src_branch;
+ avro_value_t dest_branch;
+
+ check(rval, avro_value_get_current_branch(src, &src_branch));
+ check(rval, avro_value_set_branch(dest, disc, &dest_branch));
+
+ return avro_value_copy_fast(&dest_branch, &src_branch);
+ }
+
+ default:
+ return 0;
+ }
+}
+
+
+int
+avro_value_copy(avro_value_t *dest, const avro_value_t *src)
+{
+ avro_schema_t dest_schema = avro_value_get_schema(dest);
+ avro_schema_t src_schema = avro_value_get_schema(src);
+ if (!avro_schema_equal(dest_schema, src_schema)) {
+ avro_set_error("Schemas don't match");
+ return EINVAL;
+ }
+
+ return avro_value_copy_fast(dest, src);
+}
diff --git a/fluent-bit/lib/avro/src/wrapped-buffer.c b/fluent-bit/lib/avro/src/wrapped-buffer.c
new file mode 100644
index 000000000..e7496b424
--- /dev/null
+++ b/fluent-bit/lib/avro/src/wrapped-buffer.c
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "avro_private.h"
+#include "avro/allocation.h"
+#include "avro/data.h"
+#include "avro/refcount.h"
+
+struct avro_wrapped_copy {
+ volatile int refcount;
+ size_t allocated_size;
+};
+
+static void
+avro_wrapped_copy_free(avro_wrapped_buffer_t *self)
+{
+ struct avro_wrapped_copy *copy = (struct avro_wrapped_copy *) self->user_data;
+ if (avro_refcount_dec(&copy->refcount)) {
+ avro_free(copy, copy->allocated_size);
+ }
+}
+
+static int
+avro_wrapped_copy_copy(avro_wrapped_buffer_t *dest,
+ const avro_wrapped_buffer_t *src,
+ size_t offset, size_t length)
+{
+ struct avro_wrapped_copy *copy = (struct avro_wrapped_copy *) src->user_data;
+ avro_refcount_inc(&copy->refcount);
+ dest->buf = (char *) src->buf + offset;
+ dest->size = length;
+ dest->user_data = copy;
+ dest->free = avro_wrapped_copy_free;
+ dest->copy = avro_wrapped_copy_copy;
+ dest->slice = NULL;
+ return 0;
+}
+
+int
+avro_wrapped_buffer_new_copy(avro_wrapped_buffer_t *dest,
+ const void *buf, size_t length)
+{
+ size_t allocated_size = sizeof(struct avro_wrapped_copy) + length;
+ struct avro_wrapped_copy *copy = (struct avro_wrapped_copy *) avro_malloc(allocated_size);
+ if (copy == NULL) {
+ return ENOMEM;
+ }
+
+ dest->buf = ((char *) copy) + sizeof(struct avro_wrapped_copy);
+ dest->size = length;
+ dest->user_data = copy;
+ dest->free = avro_wrapped_copy_free;
+ dest->copy = avro_wrapped_copy_copy;
+ dest->slice = NULL;
+
+ avro_refcount_set(&copy->refcount, 1);
+ copy->allocated_size = allocated_size;
+ memcpy((void *) dest->buf, buf, length);
+ return 0;
+}
+
+int
+avro_wrapped_buffer_new(avro_wrapped_buffer_t *dest,
+ const void *buf, size_t length)
+{
+ dest->buf = buf;
+ dest->size = length;
+ dest->user_data = NULL;
+ dest->free = NULL;
+ dest->copy = NULL;
+ dest->slice = NULL;
+ return 0;
+}
+
+
+void
+avro_wrapped_buffer_move(avro_wrapped_buffer_t *dest,
+ avro_wrapped_buffer_t *src)
+{
+ memcpy(dest, src, sizeof(avro_wrapped_buffer_t));
+ memset(src, 0, sizeof(avro_wrapped_buffer_t));
+}
+
+int
+avro_wrapped_buffer_copy(avro_wrapped_buffer_t *dest,
+ const avro_wrapped_buffer_t *src,
+ size_t offset, size_t length)
+{
+ if (offset > src->size) {
+ avro_set_error("Invalid offset when slicing buffer");
+ return EINVAL;
+ }
+
+ if ((offset+length) > src->size) {
+ avro_set_error("Invalid length when slicing buffer");
+ return EINVAL;
+ }
+
+ if (src->copy == NULL) {
+ return avro_wrapped_buffer_new_copy(dest, (char *) src->buf + offset, length);
+ } else {
+ return src->copy(dest, src, offset, length);
+ }
+}
+
+int
+avro_wrapped_buffer_slice(avro_wrapped_buffer_t *self,
+ size_t offset, size_t length)
+{
+ if (offset > self->size) {
+ avro_set_error("Invalid offset when slicing buffer");
+ return EINVAL;
+ }
+
+ if ((offset+length) > self->size) {
+ avro_set_error("Invalid length when slicing buffer");
+ return EINVAL;
+ }
+
+ if (self->slice == NULL) {
+ self->buf = (char *) self->buf + offset;
+ self->size = length;
+ return 0;
+ } else {
+ return self->slice(self, offset, length);
+ }
+}