/src/librabbitmq/librabbitmq/amqp_table.c
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2007 - 2021, Alan Antonuk and the rabbitmq-c contributors. |
2 | | // SPDX-License-Identifier: mit |
3 | | |
4 | | #ifdef HAVE_CONFIG_H |
5 | | #include "config.h" |
6 | | #endif |
7 | | |
8 | | #include "amqp_private.h" |
9 | | #include "amqp_table.h" |
10 | | #include <assert.h> |
11 | | #include <stdint.h> |
12 | | #include <stdio.h> |
13 | | #include <stdlib.h> |
14 | | #include <string.h> |
15 | | |
16 | 85.1k | #define INITIAL_ARRAY_SIZE 16 |
17 | 28.4k | #define INITIAL_TABLE_SIZE 16 |
18 | 13.0M | #define TABLE_DEPTH_LIMIT 100 |
19 | | |
20 | | static int amqp_decode_field_value(amqp_bytes_t encoded, amqp_pool_t *pool, |
21 | | amqp_field_value_t *entry, size_t *offset, |
22 | | int depth); |
23 | | |
24 | | static int amqp_encode_field_value(amqp_bytes_t encoded, |
25 | | amqp_field_value_t *entry, size_t *offset); |
26 | | |
27 | | /*---------------------------------------------------------------------------*/ |
28 | | |
29 | | static int amqp_decode_array(amqp_bytes_t encoded, amqp_pool_t *pool, |
30 | 85.1k | amqp_array_t *output, size_t *offset, int depth) { |
31 | 85.1k | uint32_t arraysize; |
32 | 85.1k | int num_entries = 0; |
33 | 85.1k | int allocated_entries = INITIAL_ARRAY_SIZE; |
34 | 85.1k | amqp_field_value_t *entries; |
35 | 85.1k | size_t limit; |
36 | 85.1k | int res; |
37 | | |
38 | 85.1k | if (!amqp_decode_32(encoded, offset, &arraysize)) { |
39 | 31 | return AMQP_STATUS_BAD_AMQP_DATA; |
40 | 31 | } |
41 | | |
42 | 85.1k | if (arraysize + *offset > encoded.len) { |
43 | 53 | return AMQP_STATUS_BAD_AMQP_DATA; |
44 | 53 | } |
45 | | |
46 | 85.0k | entries = malloc(allocated_entries * sizeof(amqp_field_value_t)); |
47 | 85.0k | if (entries == NULL) { |
48 | 0 | return AMQP_STATUS_NO_MEMORY; |
49 | 0 | } |
50 | | |
51 | 85.0k | limit = *offset + arraysize; |
52 | 12.5M | while (*offset < limit) { |
53 | 12.4M | if (num_entries >= allocated_entries) { |
54 | 189k | void *newentries; |
55 | 189k | allocated_entries = allocated_entries * 2; |
56 | 189k | newentries = |
57 | 189k | realloc(entries, allocated_entries * sizeof(amqp_field_value_t)); |
58 | 189k | res = AMQP_STATUS_NO_MEMORY; |
59 | 189k | if (newentries == NULL) { |
60 | 0 | goto out; |
61 | 0 | } |
62 | | |
63 | 189k | entries = newentries; |
64 | 189k | } |
65 | | |
66 | 12.4M | res = amqp_decode_field_value(encoded, pool, &entries[num_entries], offset, |
67 | 12.4M | depth); |
68 | 12.4M | if (res < 0) { |
69 | 6.13k | goto out; |
70 | 6.13k | } |
71 | | |
72 | 12.4M | num_entries++; |
73 | 12.4M | } |
74 | | |
75 | 78.9k | output->num_entries = num_entries; |
76 | 78.9k | output->entries = |
77 | 78.9k | amqp_pool_alloc(pool, num_entries * sizeof(amqp_field_value_t)); |
78 | | /* NULL is legitimate if we requested a zero-length block. */ |
79 | 78.9k | if (output->entries == NULL) { |
80 | 5.65k | if (num_entries == 0) { |
81 | 5.65k | res = AMQP_STATUS_OK; |
82 | 5.65k | } else { |
83 | 0 | res = AMQP_STATUS_NO_MEMORY; |
84 | 0 | } |
85 | 5.65k | goto out; |
86 | 5.65k | } |
87 | | |
88 | 73.2k | memcpy(output->entries, entries, num_entries * sizeof(amqp_field_value_t)); |
89 | 73.2k | res = AMQP_STATUS_OK; |
90 | | |
91 | 85.0k | out: |
92 | 85.0k | free(entries); |
93 | 85.0k | return res; |
94 | 73.2k | } |
95 | | |
96 | | static int amqp_decode_table_internal(amqp_bytes_t encoded, amqp_pool_t *pool, |
97 | | amqp_table_t *output, size_t *offset, |
98 | 28.4k | int depth) { |
99 | 28.4k | uint32_t tablesize; |
100 | 28.4k | int num_entries = 0; |
101 | 28.4k | amqp_table_entry_t *entries; |
102 | 28.4k | int allocated_entries = INITIAL_TABLE_SIZE; |
103 | 28.4k | size_t limit; |
104 | 28.4k | int res; |
105 | | |
106 | 28.4k | if (!amqp_decode_32(encoded, offset, &tablesize)) { |
107 | 22 | return AMQP_STATUS_BAD_AMQP_DATA; |
108 | 22 | } |
109 | | |
110 | 28.4k | if (tablesize + *offset > encoded.len) { |
111 | 53 | return AMQP_STATUS_BAD_AMQP_DATA; |
112 | 53 | } |
113 | | |
114 | 28.4k | entries = malloc(allocated_entries * sizeof(amqp_table_entry_t)); |
115 | 28.4k | if (entries == NULL) { |
116 | 0 | return AMQP_STATUS_NO_MEMORY; |
117 | 0 | } |
118 | | |
119 | 28.4k | limit = *offset + tablesize; |
120 | 629k | while (*offset < limit) { |
121 | 603k | uint8_t keylen; |
122 | | |
123 | 603k | res = AMQP_STATUS_BAD_AMQP_DATA; |
124 | 603k | if (!amqp_decode_8(encoded, offset, &keylen)) { |
125 | 0 | goto out; |
126 | 0 | } |
127 | | |
128 | 603k | if (num_entries >= allocated_entries) { |
129 | 2.15k | void *newentries; |
130 | 2.15k | allocated_entries = allocated_entries * 2; |
131 | 2.15k | newentries = |
132 | 2.15k | realloc(entries, allocated_entries * sizeof(amqp_table_entry_t)); |
133 | 2.15k | res = AMQP_STATUS_NO_MEMORY; |
134 | 2.15k | if (newentries == NULL) { |
135 | 0 | goto out; |
136 | 0 | } |
137 | | |
138 | 2.15k | entries = newentries; |
139 | 2.15k | } |
140 | | |
141 | 603k | res = AMQP_STATUS_BAD_AMQP_DATA; |
142 | 603k | if (!amqp_decode_bytes(encoded, offset, &entries[num_entries].key, |
143 | 603k | keylen)) { |
144 | 54 | goto out; |
145 | 54 | } |
146 | | |
147 | 603k | res = amqp_decode_field_value(encoded, pool, &entries[num_entries].value, |
148 | 603k | offset, depth); |
149 | 603k | if (res < 0) { |
150 | 2.08k | goto out; |
151 | 2.08k | } |
152 | | |
153 | 601k | num_entries++; |
154 | 601k | } |
155 | | |
156 | 26.2k | output->num_entries = num_entries; |
157 | 26.2k | output->entries = |
158 | 26.2k | amqp_pool_alloc(pool, num_entries * sizeof(amqp_table_entry_t)); |
159 | | /* NULL is legitimate if we requested a zero-length block. */ |
160 | 26.2k | if (output->entries == NULL) { |
161 | 1.68k | if (num_entries == 0) { |
162 | 1.68k | res = AMQP_STATUS_OK; |
163 | 1.68k | } else { |
164 | 0 | res = AMQP_STATUS_NO_MEMORY; |
165 | 0 | } |
166 | 1.68k | goto out; |
167 | 1.68k | } |
168 | | |
169 | 24.5k | memcpy(output->entries, entries, num_entries * sizeof(amqp_table_entry_t)); |
170 | 24.5k | res = AMQP_STATUS_OK; |
171 | | |
172 | 28.4k | out: |
173 | 28.4k | free(entries); |
174 | 28.4k | return res; |
175 | 24.5k | } |
176 | | |
177 | | int amqp_decode_table(amqp_bytes_t encoded, amqp_pool_t *pool, |
178 | 1.02k | amqp_table_t *output, size_t *offset) { |
179 | 1.02k | return amqp_decode_table_internal(encoded, pool, output, offset, 0); |
180 | 1.02k | } |
181 | | |
182 | | static int amqp_decode_field_value(amqp_bytes_t encoded, amqp_pool_t *pool, |
183 | | amqp_field_value_t *entry, size_t *offset, |
184 | 13.0M | int depth) { |
185 | 13.0M | int res = AMQP_STATUS_BAD_AMQP_DATA; |
186 | | |
187 | 13.0M | if (depth > TABLE_DEPTH_LIMIT) { |
188 | 5 | return AMQP_STATUS_BAD_AMQP_DATA; |
189 | 5 | } |
190 | | |
191 | 13.0M | if (!amqp_decode_8(encoded, offset, &entry->kind)) { |
192 | 39 | goto out; |
193 | 39 | } |
194 | | |
195 | 13.0M | #define TRIVIAL_FIELD_DECODER(bits) \ |
196 | 13.0M | if (!amqp_decode_##bits(encoded, offset, &entry->value.u##bits)) goto out; \ |
197 | 1.03M | break |
198 | 13.0M | #define SIMPLE_FIELD_DECODER(bits, dest, how) \ |
199 | 13.0M | { \ |
200 | 2.92M | uint##bits##_t val; \ |
201 | 2.92M | if (!amqp_decode_##bits(encoded, offset, &val)) goto out; \ |
202 | 4.56M | entry->value.dest = how; \ |
203 | 2.92M | } \ |
204 | 2.92M | break |
205 | | |
206 | 13.0M | switch (entry->kind) { |
207 | 2.28M | case AMQP_FIELD_KIND_BOOLEAN: |
208 | 2.28M | SIMPLE_FIELD_DECODER(8, boolean, val ? 1 : 0); |
209 | | |
210 | 17.7k | case AMQP_FIELD_KIND_I8: |
211 | 17.7k | SIMPLE_FIELD_DECODER(8, i8, (int8_t)val); |
212 | 597k | case AMQP_FIELD_KIND_U8: |
213 | 597k | TRIVIAL_FIELD_DECODER(8); |
214 | | |
215 | 597k | case AMQP_FIELD_KIND_I16: |
216 | 477k | SIMPLE_FIELD_DECODER(16, i16, (int16_t)val); |
217 | 248k | case AMQP_FIELD_KIND_U16: |
218 | 248k | TRIVIAL_FIELD_DECODER(16); |
219 | | |
220 | 248k | case AMQP_FIELD_KIND_I32: |
221 | 41.3k | SIMPLE_FIELD_DECODER(32, i32, (int32_t)val); |
222 | 68.0k | case AMQP_FIELD_KIND_U32: |
223 | 68.0k | TRIVIAL_FIELD_DECODER(32); |
224 | | |
225 | 107k | case AMQP_FIELD_KIND_I64: |
226 | 107k | SIMPLE_FIELD_DECODER(64, i64, (int64_t)val); |
227 | 9.87k | case AMQP_FIELD_KIND_U64: |
228 | 9.87k | TRIVIAL_FIELD_DECODER(64); |
229 | | |
230 | 9.86k | case AMQP_FIELD_KIND_F32: |
231 | 7.77k | TRIVIAL_FIELD_DECODER(32); |
232 | | /* and by punning, f32 magically gets the right value...! */ |
233 | | |
234 | 13.8k | case AMQP_FIELD_KIND_F64: |
235 | 13.8k | TRIVIAL_FIELD_DECODER(64); |
236 | | /* and by punning, f64 magically gets the right value...! */ |
237 | | |
238 | 94.4k | case AMQP_FIELD_KIND_DECIMAL: |
239 | 94.4k | if (!amqp_decode_8(encoded, offset, &entry->value.decimal.decimals) || |
240 | 94.4k | !amqp_decode_32(encoded, offset, &entry->value.decimal.value)) { |
241 | 41 | goto out; |
242 | 41 | } |
243 | 94.4k | break; |
244 | | |
245 | 94.4k | case AMQP_FIELD_KIND_UTF8: |
246 | | /* AMQP_FIELD_KIND_UTF8 and AMQP_FIELD_KIND_BYTES have the |
247 | | same implementation, but different interpretations. */ |
248 | | /* fall through */ |
249 | 32.0k | case AMQP_FIELD_KIND_BYTES: { |
250 | 32.0k | uint32_t len; |
251 | 32.0k | if (!amqp_decode_32(encoded, offset, &len) || |
252 | 32.0k | !amqp_decode_bytes(encoded, offset, &entry->value.bytes, len)) { |
253 | 81 | goto out; |
254 | 81 | } |
255 | 31.9k | break; |
256 | 32.0k | } |
257 | | |
258 | 85.1k | case AMQP_FIELD_KIND_ARRAY: |
259 | 85.1k | res = amqp_decode_array(encoded, pool, &(entry->value.array), offset, |
260 | 85.1k | depth + 1); |
261 | 85.1k | goto out; |
262 | | |
263 | 87.6k | case AMQP_FIELD_KIND_TIMESTAMP: |
264 | 87.6k | TRIVIAL_FIELD_DECODER(64); |
265 | | |
266 | 87.5k | case AMQP_FIELD_KIND_TABLE: |
267 | 27.4k | res = amqp_decode_table_internal(encoded, pool, &(entry->value.table), |
268 | 27.4k | offset, depth + 1); |
269 | 27.4k | goto out; |
270 | | |
271 | 8.86M | case AMQP_FIELD_KIND_VOID: |
272 | 8.86M | break; |
273 | | |
274 | 43 | default: |
275 | 43 | goto out; |
276 | 13.0M | } |
277 | | |
278 | 12.9M | res = AMQP_STATUS_OK; |
279 | | |
280 | 13.0M | out: |
281 | 13.0M | return res; |
282 | 12.9M | } |
283 | | |
284 | | /*---------------------------------------------------------------------------*/ |
285 | | |
286 | | static int amqp_encode_array(amqp_bytes_t encoded, amqp_array_t *input, |
287 | 0 | size_t *offset) { |
288 | 0 | size_t start = *offset; |
289 | 0 | int i, res; |
290 | |
|
291 | 0 | *offset += 4; /* size of the array gets filled in later on */ |
292 | |
|
293 | 0 | for (i = 0; i < input->num_entries; i++) { |
294 | 0 | res = amqp_encode_field_value(encoded, &input->entries[i], offset); |
295 | 0 | if (res < 0) { |
296 | 0 | goto out; |
297 | 0 | } |
298 | 0 | } |
299 | | |
300 | 0 | if (!amqp_encode_32(encoded, &start, (uint32_t)(*offset - start - 4))) { |
301 | 0 | res = AMQP_STATUS_TABLE_TOO_BIG; |
302 | 0 | goto out; |
303 | 0 | } |
304 | | |
305 | 0 | res = AMQP_STATUS_OK; |
306 | |
|
307 | 0 | out: |
308 | 0 | return res; |
309 | 0 | } |
310 | | |
311 | | int amqp_encode_table(amqp_bytes_t encoded, amqp_table_t *input, |
312 | 0 | size_t *offset) { |
313 | 0 | size_t start = *offset; |
314 | 0 | int i, res; |
315 | |
|
316 | 0 | *offset += 4; /* size of the table gets filled in later on */ |
317 | |
|
318 | 0 | for (i = 0; i < input->num_entries; i++) { |
319 | 0 | if (!amqp_encode_8(encoded, offset, (uint8_t)input->entries[i].key.len)) { |
320 | 0 | res = AMQP_STATUS_TABLE_TOO_BIG; |
321 | 0 | goto out; |
322 | 0 | } |
323 | | |
324 | 0 | if (!amqp_encode_bytes(encoded, offset, input->entries[i].key)) { |
325 | 0 | res = AMQP_STATUS_TABLE_TOO_BIG; |
326 | 0 | goto out; |
327 | 0 | } |
328 | | |
329 | 0 | res = amqp_encode_field_value(encoded, &input->entries[i].value, offset); |
330 | 0 | if (res < 0) { |
331 | 0 | goto out; |
332 | 0 | } |
333 | 0 | } |
334 | | |
335 | 0 | if (!amqp_encode_32(encoded, &start, (uint32_t)(*offset - start - 4))) { |
336 | 0 | res = AMQP_STATUS_TABLE_TOO_BIG; |
337 | 0 | goto out; |
338 | 0 | } |
339 | | |
340 | 0 | res = AMQP_STATUS_OK; |
341 | |
|
342 | 0 | out: |
343 | 0 | return res; |
344 | 0 | } |
345 | | |
346 | | static int amqp_encode_field_value(amqp_bytes_t encoded, |
347 | 0 | amqp_field_value_t *entry, size_t *offset) { |
348 | 0 | int res = AMQP_STATUS_BAD_AMQP_DATA; |
349 | |
|
350 | 0 | if (!amqp_encode_8(encoded, offset, entry->kind)) { |
351 | 0 | goto out; |
352 | 0 | } |
353 | | |
354 | 0 | #define FIELD_ENCODER(bits, val) \ |
355 | 0 | if (!amqp_encode_##bits(encoded, offset, val)) { \ |
356 | 0 | res = AMQP_STATUS_TABLE_TOO_BIG; \ |
357 | 0 | goto out; \ |
358 | 0 | } \ |
359 | 0 | break |
360 | | |
361 | 0 | switch (entry->kind) { |
362 | 0 | case AMQP_FIELD_KIND_BOOLEAN: |
363 | 0 | FIELD_ENCODER(8, entry->value.boolean ? 1 : 0); |
364 | | |
365 | 0 | case AMQP_FIELD_KIND_I8: |
366 | 0 | FIELD_ENCODER(8, entry->value.i8); |
367 | 0 | case AMQP_FIELD_KIND_U8: |
368 | 0 | FIELD_ENCODER(8, entry->value.u8); |
369 | | |
370 | 0 | case AMQP_FIELD_KIND_I16: |
371 | 0 | FIELD_ENCODER(16, entry->value.i16); |
372 | 0 | case AMQP_FIELD_KIND_U16: |
373 | 0 | FIELD_ENCODER(16, entry->value.u16); |
374 | | |
375 | 0 | case AMQP_FIELD_KIND_I32: |
376 | 0 | FIELD_ENCODER(32, entry->value.i32); |
377 | 0 | case AMQP_FIELD_KIND_U32: |
378 | 0 | FIELD_ENCODER(32, entry->value.u32); |
379 | | |
380 | 0 | case AMQP_FIELD_KIND_I64: |
381 | 0 | FIELD_ENCODER(64, entry->value.i64); |
382 | 0 | case AMQP_FIELD_KIND_U64: |
383 | 0 | FIELD_ENCODER(64, entry->value.u64); |
384 | | |
385 | 0 | case AMQP_FIELD_KIND_F32: |
386 | | /* by punning, u32 magically gets the right value...! */ |
387 | 0 | FIELD_ENCODER(32, entry->value.u32); |
388 | | |
389 | 0 | case AMQP_FIELD_KIND_F64: |
390 | | /* by punning, u64 magically gets the right value...! */ |
391 | 0 | FIELD_ENCODER(64, entry->value.u64); |
392 | | |
393 | 0 | case AMQP_FIELD_KIND_DECIMAL: |
394 | 0 | if (!amqp_encode_8(encoded, offset, entry->value.decimal.decimals) || |
395 | 0 | !amqp_encode_32(encoded, offset, entry->value.decimal.value)) { |
396 | 0 | res = AMQP_STATUS_TABLE_TOO_BIG; |
397 | 0 | goto out; |
398 | 0 | } |
399 | 0 | break; |
400 | | |
401 | 0 | case AMQP_FIELD_KIND_UTF8: |
402 | | /* AMQP_FIELD_KIND_UTF8 and AMQP_FIELD_KIND_BYTES have the |
403 | | same implementation, but different interpretations. */ |
404 | | /* fall through */ |
405 | 0 | case AMQP_FIELD_KIND_BYTES: |
406 | 0 | if (!amqp_encode_32(encoded, offset, (uint32_t)entry->value.bytes.len) || |
407 | 0 | !amqp_encode_bytes(encoded, offset, entry->value.bytes)) { |
408 | 0 | res = AMQP_STATUS_TABLE_TOO_BIG; |
409 | 0 | goto out; |
410 | 0 | } |
411 | 0 | break; |
412 | | |
413 | 0 | case AMQP_FIELD_KIND_ARRAY: |
414 | 0 | res = amqp_encode_array(encoded, &entry->value.array, offset); |
415 | 0 | goto out; |
416 | | |
417 | 0 | case AMQP_FIELD_KIND_TIMESTAMP: |
418 | 0 | FIELD_ENCODER(64, entry->value.u64); |
419 | | |
420 | 0 | case AMQP_FIELD_KIND_TABLE: |
421 | 0 | res = amqp_encode_table(encoded, &entry->value.table, offset); |
422 | 0 | goto out; |
423 | | |
424 | 0 | case AMQP_FIELD_KIND_VOID: |
425 | 0 | break; |
426 | | |
427 | 0 | default: |
428 | 0 | res = AMQP_STATUS_INVALID_PARAMETER; |
429 | 0 | goto out; |
430 | 0 | } |
431 | | |
432 | 0 | res = AMQP_STATUS_OK; |
433 | |
|
434 | 0 | out: |
435 | 0 | return res; |
436 | 0 | } |
437 | | |
438 | | /*---------------------------------------------------------------------------*/ |
439 | | |
440 | 0 | int amqp_table_entry_cmp(void const *entry1, void const *entry2) { |
441 | 0 | amqp_table_entry_t const *p1 = (amqp_table_entry_t const *)entry1; |
442 | 0 | amqp_table_entry_t const *p2 = (amqp_table_entry_t const *)entry2; |
443 | |
|
444 | 0 | int d; |
445 | 0 | size_t minlen; |
446 | |
|
447 | 0 | minlen = p1->key.len; |
448 | 0 | if (p2->key.len < minlen) { |
449 | 0 | minlen = p2->key.len; |
450 | 0 | } |
451 | |
|
452 | 0 | d = memcmp(p1->key.bytes, p2->key.bytes, minlen); |
453 | 0 | if (d != 0) { |
454 | 0 | return d; |
455 | 0 | } |
456 | | |
457 | 0 | return (int)p1->key.len - (int)p2->key.len; |
458 | 0 | } |
459 | | |
460 | | static int amqp_field_value_clone(const amqp_field_value_t *original, |
461 | | amqp_field_value_t *clone, |
462 | 0 | amqp_pool_t *pool) { |
463 | 0 | int i; |
464 | 0 | int res; |
465 | 0 | clone->kind = original->kind; |
466 | |
|
467 | 0 | switch (clone->kind) { |
468 | 0 | case AMQP_FIELD_KIND_BOOLEAN: |
469 | 0 | clone->value.boolean = original->value.boolean; |
470 | 0 | break; |
471 | | |
472 | 0 | case AMQP_FIELD_KIND_I8: |
473 | 0 | clone->value.i8 = original->value.i8; |
474 | 0 | break; |
475 | | |
476 | 0 | case AMQP_FIELD_KIND_U8: |
477 | 0 | clone->value.u8 = original->value.u8; |
478 | 0 | break; |
479 | | |
480 | 0 | case AMQP_FIELD_KIND_I16: |
481 | 0 | clone->value.i16 = original->value.i16; |
482 | 0 | break; |
483 | | |
484 | 0 | case AMQP_FIELD_KIND_U16: |
485 | 0 | clone->value.u16 = original->value.u16; |
486 | 0 | break; |
487 | | |
488 | 0 | case AMQP_FIELD_KIND_I32: |
489 | 0 | clone->value.i32 = original->value.i32; |
490 | 0 | break; |
491 | | |
492 | 0 | case AMQP_FIELD_KIND_U32: |
493 | 0 | clone->value.u32 = original->value.u32; |
494 | 0 | break; |
495 | | |
496 | 0 | case AMQP_FIELD_KIND_I64: |
497 | 0 | clone->value.i64 = original->value.i64; |
498 | 0 | break; |
499 | | |
500 | 0 | case AMQP_FIELD_KIND_U64: |
501 | 0 | case AMQP_FIELD_KIND_TIMESTAMP: |
502 | 0 | clone->value.u64 = original->value.u64; |
503 | 0 | break; |
504 | | |
505 | 0 | case AMQP_FIELD_KIND_F32: |
506 | 0 | clone->value.f32 = original->value.f32; |
507 | 0 | break; |
508 | | |
509 | 0 | case AMQP_FIELD_KIND_F64: |
510 | 0 | clone->value.f64 = original->value.f64; |
511 | 0 | break; |
512 | | |
513 | 0 | case AMQP_FIELD_KIND_DECIMAL: |
514 | 0 | clone->value.decimal = original->value.decimal; |
515 | 0 | break; |
516 | | |
517 | 0 | case AMQP_FIELD_KIND_UTF8: |
518 | 0 | case AMQP_FIELD_KIND_BYTES: |
519 | 0 | if (0 == original->value.bytes.len) { |
520 | 0 | clone->value.bytes = amqp_empty_bytes; |
521 | 0 | } else { |
522 | 0 | amqp_pool_alloc_bytes(pool, original->value.bytes.len, |
523 | 0 | &clone->value.bytes); |
524 | 0 | if (NULL == clone->value.bytes.bytes) { |
525 | 0 | return AMQP_STATUS_NO_MEMORY; |
526 | 0 | } |
527 | 0 | memcpy(clone->value.bytes.bytes, original->value.bytes.bytes, |
528 | 0 | clone->value.bytes.len); |
529 | 0 | } |
530 | 0 | break; |
531 | | |
532 | 0 | case AMQP_FIELD_KIND_ARRAY: |
533 | 0 | if (0 == original->value.array.entries) { |
534 | 0 | clone->value.array = amqp_empty_array; |
535 | 0 | } else { |
536 | 0 | clone->value.array.num_entries = original->value.array.num_entries; |
537 | 0 | clone->value.array.entries = amqp_pool_alloc( |
538 | 0 | pool, clone->value.array.num_entries * sizeof(amqp_field_value_t)); |
539 | 0 | if (NULL == clone->value.array.entries) { |
540 | 0 | return AMQP_STATUS_NO_MEMORY; |
541 | 0 | } |
542 | | |
543 | 0 | for (i = 0; i < clone->value.array.num_entries; ++i) { |
544 | 0 | res = amqp_field_value_clone(&original->value.array.entries[i], |
545 | 0 | &clone->value.array.entries[i], pool); |
546 | 0 | if (AMQP_STATUS_OK != res) { |
547 | 0 | return res; |
548 | 0 | } |
549 | 0 | } |
550 | 0 | } |
551 | 0 | break; |
552 | | |
553 | 0 | case AMQP_FIELD_KIND_TABLE: |
554 | 0 | return amqp_table_clone(&original->value.table, &clone->value.table, |
555 | 0 | pool); |
556 | | |
557 | 0 | case AMQP_FIELD_KIND_VOID: |
558 | 0 | break; |
559 | | |
560 | 0 | default: |
561 | 0 | return AMQP_STATUS_INVALID_PARAMETER; |
562 | 0 | } |
563 | | |
564 | 0 | return AMQP_STATUS_OK; |
565 | 0 | } |
566 | | |
567 | | static int amqp_table_entry_clone(const amqp_table_entry_t *original, |
568 | | amqp_table_entry_t *clone, |
569 | 0 | amqp_pool_t *pool) { |
570 | 0 | if (0 == original->key.len) { |
571 | 0 | return AMQP_STATUS_INVALID_PARAMETER; |
572 | 0 | } |
573 | | |
574 | 0 | amqp_pool_alloc_bytes(pool, original->key.len, &clone->key); |
575 | 0 | if (NULL == clone->key.bytes) { |
576 | 0 | return AMQP_STATUS_NO_MEMORY; |
577 | 0 | } |
578 | | |
579 | 0 | memcpy(clone->key.bytes, original->key.bytes, clone->key.len); |
580 | |
|
581 | 0 | return amqp_field_value_clone(&original->value, &clone->value, pool); |
582 | 0 | } |
583 | | |
584 | | int amqp_table_clone(const amqp_table_t *original, amqp_table_t *clone, |
585 | 0 | amqp_pool_t *pool) { |
586 | 0 | int i; |
587 | 0 | int res; |
588 | 0 | clone->num_entries = original->num_entries; |
589 | 0 | if (0 == clone->num_entries) { |
590 | 0 | *clone = amqp_empty_table; |
591 | 0 | return AMQP_STATUS_OK; |
592 | 0 | } |
593 | | |
594 | 0 | clone->entries = |
595 | 0 | amqp_pool_alloc(pool, clone->num_entries * sizeof(amqp_table_entry_t)); |
596 | |
|
597 | 0 | if (NULL == clone->entries) { |
598 | 0 | return AMQP_STATUS_NO_MEMORY; |
599 | 0 | } |
600 | | |
601 | 0 | for (i = 0; i < clone->num_entries; ++i) { |
602 | 0 | res = |
603 | 0 | amqp_table_entry_clone(&original->entries[i], &clone->entries[i], pool); |
604 | 0 | if (AMQP_STATUS_OK != res) { |
605 | 0 | goto error_out1; |
606 | 0 | } |
607 | 0 | } |
608 | | |
609 | 0 | return AMQP_STATUS_OK; |
610 | | |
611 | 0 | error_out1: |
612 | 0 | return res; |
613 | 0 | } |
614 | | |
615 | | amqp_table_entry_t amqp_table_construct_utf8_entry(const char *key, |
616 | 0 | const char *value) { |
617 | 0 | amqp_table_entry_t ret; |
618 | 0 | ret.key = amqp_cstring_bytes(key); |
619 | 0 | ret.value.kind = AMQP_FIELD_KIND_UTF8; |
620 | 0 | ret.value.value.bytes = amqp_cstring_bytes(value); |
621 | 0 | return ret; |
622 | 0 | } |
623 | | |
624 | | amqp_table_entry_t amqp_table_construct_table_entry(const char *key, |
625 | 0 | const amqp_table_t *value) { |
626 | 0 | amqp_table_entry_t ret; |
627 | 0 | ret.key = amqp_cstring_bytes(key); |
628 | 0 | ret.value.kind = AMQP_FIELD_KIND_TABLE; |
629 | 0 | ret.value.value.table = *value; |
630 | 0 | return ret; |
631 | 0 | } |
632 | | |
633 | | amqp_table_entry_t amqp_table_construct_bool_entry(const char *key, |
634 | 0 | const int value) { |
635 | 0 | amqp_table_entry_t ret; |
636 | 0 | ret.key = amqp_cstring_bytes(key); |
637 | 0 | ret.value.kind = AMQP_FIELD_KIND_BOOLEAN; |
638 | 0 | ret.value.value.boolean = value; |
639 | 0 | return ret; |
640 | 0 | } |
641 | | |
642 | | amqp_table_entry_t *amqp_table_get_entry_by_key(const amqp_table_t *table, |
643 | 0 | const amqp_bytes_t key) { |
644 | 0 | int i; |
645 | 0 | assert(table != NULL); |
646 | 0 | for (i = 0; i < table->num_entries; ++i) { |
647 | 0 | if (amqp_bytes_equal(table->entries[i].key, key)) { |
648 | 0 | return &table->entries[i]; |
649 | 0 | } |
650 | 0 | } |
651 | 0 | return NULL; |
652 | 0 | } |