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); }
int schema_traverse(const avro_schema_t schema, json_t *json, json_t *dft, avro_value_t *current_val, int quiet, int strjson, size_t max_str_sz) { json = json ? json : dft; if (!json) { fprintf(stderr, "ERROR: Avro schema does not match JSON\n"); return 1; } switch (schema->type) { case AVRO_RECORD: { if (!json_is_object(json)) { if (!quiet) fprintf(stderr, "ERROR: Expecting JSON object for Avro record, got something else\n"); return 1; } int len = avro_schema_record_size(schema), i; for (i=0; i<len; i++) { const char *name = avro_schema_record_field_name(schema, i); avro_schema_t field_schema = avro_schema_record_field_get_by_index(schema, i); json_t *json_val = json_object_get(json, name); json_t *dft = avro_schema_record_field_default_get_by_index(schema, i); avro_value_t field; avro_value_get_by_index(current_val, i, &field, NULL); if (schema_traverse(field_schema, json_val, dft, &field, quiet, strjson, max_str_sz)) return 1; } } break; case AVRO_LINK: /* TODO */ fprintf(stderr, "ERROR: AVRO_LINK is not implemented\n"); return 1; break; case AVRO_STRING: if (!json_is_string(json)) { if (json && strjson) { /* -j specified, just dump the remaining json as string */ char * js = json_dumps(json, JSON_COMPACT|JSON_SORT_KEYS|JSON_ENCODE_ANY); if (max_str_sz && (strlen(js) > max_str_sz)) js[max_str_sz] = 0; /* truncate the string - this will result in invalid JSON! */ avro_value_set_string(current_val, js); free(js); break; } if (!quiet) fprintf(stderr, "ERROR: Expecting JSON string for Avro string, got something else\n"); return 1; } else { const char *js = json_string_value(json); if (max_str_sz && (strlen(js) > max_str_sz)) { /* truncate the string */ char *jst = malloc(strlen(js)); strcpy(jst, js); jst[max_str_sz] = 0; avro_value_set_string(current_val, jst); free(jst); } else avro_value_set_string(current_val, js); } break; case AVRO_BYTES: if (!json_is_string(json)) { if (!quiet) fprintf(stderr, "ERROR: Expecting JSON string for Avro string, got something else\n"); return 1; } /* NB: Jansson uses null-terminated strings, so embedded nulls are NOT supported, not even escaped ones */ const char *s = json_string_value(json); avro_value_set_bytes(current_val, (void *)s, strlen(s)); break; case AVRO_INT32: if (!json_is_integer(json)) { if (!quiet) fprintf(stderr, "ERROR: Expecting JSON integer for Avro int, got something else\n"); return 1; } avro_value_set_int(current_val, json_integer_value(json)); break; case AVRO_INT64: if (!json_is_integer(json)) { if (!quiet) fprintf(stderr, "ERROR: Expecting JSON integer for Avro long, got something else\n"); return 1; } avro_value_set_long(current_val, json_integer_value(json)); break; case AVRO_FLOAT: if (!json_is_number(json)) { if (!quiet) fprintf(stderr, "ERROR: Expecting JSON number for Avro float, got something else\n"); return 1; } avro_value_set_float(current_val, json_number_value(json)); break; case AVRO_DOUBLE: if (!json_is_number(json)) { if (!quiet) fprintf(stderr, "ERROR: Expecting JSON number for Avro double, got something else\n"); return 1; } avro_value_set_double(current_val, json_number_value(json)); break; case AVRO_BOOLEAN: if (!json_is_boolean(json)) { if (!quiet) fprintf(stderr, "ERROR: Expecting JSON boolean for Avro boolean, got something else\n"); return 1; } avro_value_set_boolean(current_val, json_is_true(json)); break; case AVRO_NULL: if (!json_is_null(json)) { if (!quiet) fprintf(stderr, "ERROR: Expecting JSON null for Avro null, got something else\n"); return 1; } avro_value_set_null(current_val); break; case AVRO_ENUM: // TODO ??? break; case AVRO_ARRAY: if (!json_is_array(json)) { if (!quiet) fprintf(stderr, "ERROR: Expecting JSON array for Avro array, got something else\n"); return 1; } else { int i, len = json_array_size(json); avro_schema_t items = avro_schema_array_items(schema); avro_value_t val; for (i=0; i<len; i++) { avro_value_append(current_val, &val, NULL); if (schema_traverse(items, json_array_get(json, i), NULL, &val, quiet, strjson, max_str_sz)) return 1; } } break; case AVRO_MAP: if (!json_is_object(json)) { if (!quiet) fprintf(stderr, "ERROR: Expecting JSON object for Avro map, got something else\n"); return 1; } else { avro_schema_t values = avro_schema_map_values(schema); void *iter = json_object_iter(json); avro_value_t val; while (iter) { avro_value_add(current_val, json_object_iter_key(iter), &val, 0, 0); if (schema_traverse(values, json_object_iter_value(iter), NULL, &val, quiet, strjson, max_str_sz)) return 1; iter = json_object_iter_next(json, iter); } } break; case AVRO_UNION: { int i; avro_value_t branch; for (i=0; i<avro_schema_union_size(schema); i++) { avro_value_set_branch(current_val, i, &branch); avro_schema_t type = avro_schema_union_branch(schema, i); if (!schema_traverse(type, json, NULL, &branch, 1, strjson, max_str_sz)) break; } if (i==avro_schema_union_size(schema)) { fprintf(stderr, "ERROR: No type in the Avro union matched the JSON type we got\n"); return 1; } break; } case AVRO_FIXED: if (!json_is_string(json)) { if (!quiet) fprintf(stderr, "ERROR: Expecting JSON string for Avro fixed, got something else\n"); return 1; } /* NB: Jansson uses null-terminated strings, so embedded nulls are NOT supported, not even escaped ones */ const char *f = json_string_value(json); if (avro_value_set_fixed(current_val, (void *)f, strlen(f))) { fprintf(stderr, "ERROR: Setting Avro fixed value FAILED\n"); return 1; } break; default: fprintf(stderr, "ERROR: Unknown type: %d\n", schema->type); return 1; } return 0; }
PyObject * declare_types(ConvertInfo *info, avro_schema_t schema) { avro_type_t type = schema->type; switch (type) { case AVRO_NULL: /* PyNone_Type is not publicly visible */ return (PyObject *)Py_TYPE(Py_None); case AVRO_BOOLEAN: return (PyObject *)&PyBool_Type; case AVRO_BYTES: case AVRO_STRING: case AVRO_FIXED: return (PyObject *)&PyString_Type; case AVRO_DOUBLE: case AVRO_FLOAT: return (PyObject *)&PyFloat_Type; case AVRO_INT32: return (PyObject *)&PyInt_Type; case AVRO_ENUM: return get_python_enum_type(info->types, schema); case AVRO_INT64: return (PyObject *)&PyLong_Type; case AVRO_ARRAY: declare_types(info, avro_schema_array_items(schema)); return (PyObject *)&PyList_Type; case AVRO_MAP: declare_types(info, avro_schema_map_values(schema)); return (PyObject *)&PyDict_Type; case AVRO_UNION: { size_t union_size = avro_schema_union_size(schema); size_t i; for (i = 0; i < union_size; i++) { declare_types(info, avro_schema_union_branch(schema, i)); } } return (PyObject *)&PyBaseObject_Type; /* XXX list of types might be better */ case AVRO_RECORD: { size_t field_count = avro_schema_record_size(schema); size_t i; const char *record_name = avro_schema_name(schema); PyObject *record_type = PyObject_GetAttrString(info->types, record_name); PyObject *field_types; if (record_type != NULL) { /* already declared this record type */ Py_DECREF(record_type); return record_type; } /* create the Python type for this schema */ record_type = get_python_obj_type(info->types, schema); field_types = PyObject_GetAttrString(record_type, "_fieldtypes"); for (i = 0; i < field_count; i++) { PyObject *field_type = declare_types(info, avro_schema_record_field_get_by_index(schema, i)); /* this will INCREF, so takes hold of the object */ PyMapping_SetItemString(field_types, (char*)avro_schema_record_field_name(schema, i), field_type); } Py_DECREF(field_types); return record_type; } case AVRO_LINK: return declare_types(info, avro_schema_link_target(schema)); default: /* other types don't hold records */ break; } return NULL; }