1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to you under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 */
17
18 #include "avro_private.h"
19 #include "avro/errors.h"
20 #include <limits.h>
21 #include <errno.h>
22 #include <string.h>
23 #include "schema.h"
24 #include "datum.h"
25 #include "st.h"
26
27 struct validate_st {
28 avro_schema_t expected_schema;
29 int rval;
30 };
31
32 static int
schema_map_validate_foreach(char * key,avro_datum_t datum,struct validate_st * vst)33 schema_map_validate_foreach(char *key, avro_datum_t datum,
34 struct validate_st *vst)
35 {
36 AVRO_UNUSED(key);
37
38 if (!avro_schema_datum_validate(vst->expected_schema, datum)) {
39 vst->rval = 0;
40 return ST_STOP;
41 }
42 return ST_CONTINUE;
43 }
44
45 int
avro_schema_datum_validate(avro_schema_t expected_schema,avro_datum_t datum)46 avro_schema_datum_validate(avro_schema_t expected_schema, avro_datum_t datum)
47 {
48 check_param(EINVAL, expected_schema, "expected schema");
49 check_param(EINVAL, is_avro_datum(datum), "datum");
50
51 int rval;
52 long i;
53
54 switch (avro_typeof(expected_schema)) {
55 case AVRO_NULL:
56 return is_avro_null(datum);
57
58 case AVRO_BOOLEAN:
59 return is_avro_boolean(datum);
60
61 case AVRO_STRING:
62 return is_avro_string(datum);
63
64 case AVRO_BYTES:
65 return is_avro_bytes(datum);
66
67 case AVRO_INT32:
68 return is_avro_int32(datum)
69 || (is_avro_int64(datum)
70 && (INT_MIN <= avro_datum_to_int64(datum)->i64
71 && avro_datum_to_int64(datum)->i64 <= INT_MAX));
72
73 case AVRO_INT64:
74 return is_avro_int32(datum) || is_avro_int64(datum);
75
76 case AVRO_FLOAT:
77 return is_avro_int32(datum) || is_avro_int64(datum)
78 || is_avro_float(datum);
79
80 case AVRO_DOUBLE:
81 return is_avro_int32(datum) || is_avro_int64(datum)
82 || is_avro_float(datum) || is_avro_double(datum);
83
84 case AVRO_FIXED:
85 return (is_avro_fixed(datum)
86 && (avro_schema_to_fixed(expected_schema)->size ==
87 avro_datum_to_fixed(datum)->size));
88
89 case AVRO_ENUM:
90 if (is_avro_enum(datum)) {
91 long value = avro_datum_to_enum(datum)->value;
92 long max_value =
93 avro_schema_to_enum(expected_schema)->symbols->
94 num_entries;
95 return 0 <= value && value <= max_value;
96 }
97 return 0;
98
99 case AVRO_ARRAY:
100 if (is_avro_array(datum)) {
101 struct avro_array_datum_t *array =
102 avro_datum_to_array(datum);
103
104 for (i = 0; i < array->els->num_entries; i++) {
105 union {
106 st_data_t data;
107 avro_datum_t datum;
108 } val;
109 st_lookup(array->els, i, &val.data);
110 if (!avro_schema_datum_validate
111 ((avro_schema_to_array
112 (expected_schema))->items, val.datum)) {
113 return 0;
114 }
115 }
116 return 1;
117 }
118 return 0;
119
120 case AVRO_MAP:
121 if (is_avro_map(datum)) {
122 struct validate_st vst =
123 { avro_schema_to_map(expected_schema)->values, 1
124 };
125 st_foreach(avro_datum_to_map(datum)->map,
126 HASH_FUNCTION_CAST schema_map_validate_foreach,
127 (st_data_t) & vst);
128 return vst.rval;
129 }
130 break;
131
132 case AVRO_UNION:
133 if (is_avro_union(datum)) {
134 struct avro_union_schema_t *union_schema =
135 avro_schema_to_union(expected_schema);
136 struct avro_union_datum_t *union_datum =
137 avro_datum_to_union(datum);
138 union {
139 st_data_t data;
140 avro_schema_t schema;
141 } val;
142
143 if (!st_lookup
144 (union_schema->branches, union_datum->discriminant,
145 &val.data)) {
146 return 0;
147 }
148 return avro_schema_datum_validate(val.schema,
149 union_datum->value);
150 }
151 break;
152
153 case AVRO_RECORD:
154 if (is_avro_record(datum)) {
155 struct avro_record_schema_t *record_schema =
156 avro_schema_to_record(expected_schema);
157 for (i = 0; i < record_schema->fields->num_entries; i++) {
158 avro_datum_t field_datum;
159 union {
160 st_data_t data;
161 struct avro_record_field_t *field;
162 } val;
163 st_lookup(record_schema->fields, i, &val.data);
164
165 rval =
166 avro_record_get(datum, val.field->name,
167 &field_datum);
168 if (rval) {
169 /*
170 * TODO: check for default values
171 */
172 return rval;
173 }
174 if (!avro_schema_datum_validate
175 (val.field->type, field_datum)) {
176 return 0;
177 }
178 }
179 return 1;
180 }
181 break;
182
183 case AVRO_LINK:
184 {
185 return
186 avro_schema_datum_validate((avro_schema_to_link
187 (expected_schema))->to,
188 datum);
189 }
190 break;
191 }
192 return 0;
193 }
194