int amqp_decode_table(amqp_bytes_t encoded, amqp_pool_t *pool, amqp_table_t *output, int *offsetptr) { int offset = *offsetptr; uint32_t tablesize = D_32(encoded, offset); int num_entries = 0; amqp_table_entry_t *entries = malloc(INITIAL_TABLE_SIZE * sizeof(amqp_table_entry_t)); int allocated_entries = INITIAL_TABLE_SIZE; int limit; if (entries == NULL) { return -ENOMEM; } offset += 4; limit = offset + tablesize; while (offset < limit) { size_t keylen; amqp_table_entry_t *entry; keylen = D_8(encoded, offset); offset++; if (num_entries >= allocated_entries) { void *newentries; allocated_entries = allocated_entries * 2; newentries = realloc(entries, allocated_entries * sizeof(amqp_table_entry_t)); if (newentries == NULL) { free(entries); return -ENOMEM; } entries = newentries; } entry = &entries[num_entries]; entry->key.len = keylen; entry->key.bytes = D_BYTES(encoded, offset, keylen); offset += keylen; entry->kind = D_8(encoded, offset); offset++; switch (entry->kind) { case 'S': entry->value.bytes.len = D_32(encoded, offset); offset += 4; entry->value.bytes.bytes = D_BYTES(encoded, offset, entry->value.bytes.len); offset += entry->value.bytes.len; break; case 'I': entry->value.i32 = (int32_t) D_32(encoded, offset); offset += 4; break; case 'D': entry->value.decimal.decimals = D_8(encoded, offset); offset++; entry->value.decimal.value = D_32(encoded, offset); offset += 4; break; case 'T': entry->value.u64 = D_64(encoded, offset); offset += 8; break; case 'F': AMQP_CHECK_RESULT(amqp_decode_table(encoded, pool, &(entry->value.table), &offset)); break; case 't': entry->value.boolean = D_8(encoded, offset); offset += 1; break; default: return -EINVAL; } num_entries++; } output->num_entries = num_entries; output->entries = amqp_pool_alloc(pool, num_entries * sizeof(amqp_table_entry_t)); output->size = num_entries; memcpy(output->entries, entries, num_entries * sizeof(amqp_table_entry_t)); *offsetptr = offset; return 0; }
static void test_table_codec(FILE *out) { amqp_pool_t pool; int result; amqp_table_entry_t inner_entries[2]; amqp_table_t inner_table; amqp_field_value_t inner_values[2]; amqp_array_t inner_array; amqp_table_entry_t entries[14]; amqp_table_t table; inner_entries[0].key = amqp_cstring_bytes("one"); inner_entries[0].value.kind = AMQP_FIELD_KIND_I32; inner_entries[0].value.value.i32 = 54321; inner_entries[1].key = amqp_cstring_bytes("two"); inner_entries[1].value.kind = AMQP_FIELD_KIND_UTF8; inner_entries[1].value.value.bytes = amqp_cstring_bytes("A long string"); inner_table.num_entries = 2; inner_table.entries = inner_entries; inner_values[0].kind = AMQP_FIELD_KIND_I32; inner_values[0].value.i32 = 54321; inner_values[1].kind = AMQP_FIELD_KIND_UTF8; inner_values[1].value.bytes = amqp_cstring_bytes("A long string"); inner_array.num_entries = 2; inner_array.entries = inner_values; entries[0].key = amqp_cstring_bytes("longstr"); entries[0].value.kind = AMQP_FIELD_KIND_UTF8; entries[0].value.value.bytes = amqp_cstring_bytes("Here is a long string"); entries[1].key = amqp_cstring_bytes("signedint"); entries[1].value.kind = AMQP_FIELD_KIND_I32; entries[1].value.value.i32 = 12345; entries[2].key = amqp_cstring_bytes("decimal"); entries[2].value.kind = AMQP_FIELD_KIND_DECIMAL; entries[2].value.value.decimal.decimals = 3; entries[2].value.value.decimal.value = 123456; entries[3].key = amqp_cstring_bytes("timestamp"); entries[3].value.kind = AMQP_FIELD_KIND_TIMESTAMP; entries[3].value.value.u64 = 109876543209876; entries[4].key = amqp_cstring_bytes("table"); entries[4].value.kind = AMQP_FIELD_KIND_TABLE; entries[4].value.value.table = inner_table; entries[5].key = amqp_cstring_bytes("byte"); entries[5].value.kind = AMQP_FIELD_KIND_I8; entries[5].value.value.i8 = (int8_t)255; entries[6].key = amqp_cstring_bytes("long"); entries[6].value.kind = AMQP_FIELD_KIND_I64; entries[6].value.value.i64 = 1234567890; entries[7].key = amqp_cstring_bytes("short"); entries[7].value.kind = AMQP_FIELD_KIND_I16; entries[7].value.value.i16 = 655; entries[8].key = amqp_cstring_bytes("bool"); entries[8].value.kind = AMQP_FIELD_KIND_BOOLEAN; entries[8].value.value.boolean = 1; entries[9].key = amqp_cstring_bytes("binary"); entries[9].value.kind = AMQP_FIELD_KIND_BYTES; entries[9].value.value.bytes = amqp_cstring_bytes("a binary string"); entries[10].key = amqp_cstring_bytes("void"); entries[10].value.kind = AMQP_FIELD_KIND_VOID; entries[11].key = amqp_cstring_bytes("array"); entries[11].value.kind = AMQP_FIELD_KIND_ARRAY; entries[11].value.value.array = inner_array; entries[12].key = amqp_cstring_bytes("float"); entries[12].value.kind = AMQP_FIELD_KIND_F32; entries[12].value.value.f32 = M_PI; entries[13].key = amqp_cstring_bytes("double"); entries[13].value.kind = AMQP_FIELD_KIND_F64; entries[13].value.value.f64 = M_PI; table.num_entries = 14; table.entries = entries; fprintf(out, "AAAAAAAAAA\n"); { amqp_field_value_t val; val.kind = AMQP_FIELD_KIND_TABLE; val.value.table = table; dump_value(0, val, out); } init_amqp_pool(&pool, 4096); { amqp_table_t decoded; size_t decoding_offset = 0; amqp_bytes_t decoding_bytes; decoding_bytes.len = sizeof(pre_encoded_table); decoding_bytes.bytes = pre_encoded_table; result = amqp_decode_table(decoding_bytes, &pool, &decoded, &decoding_offset); if (result < 0) die("Table decoding failed: %s", amqp_error_string(-result)); fprintf(out, "BBBBBBBBBB\n"); { amqp_field_value_t val; val.kind = AMQP_FIELD_KIND_TABLE; val.value.table = decoded; dump_value(0, val, out); } } { uint8_t encoding_buffer[4096]; amqp_bytes_t encoding_result; size_t offset = 0; memset(&encoding_buffer[0], 0, sizeof(encoding_buffer)); encoding_result.len = sizeof(encoding_buffer); encoding_result.bytes = &encoding_buffer[0]; result = amqp_encode_table(encoding_result, &table, &offset); if (result < 0) die("Table encoding failed: %s", amqp_error_string(-result)); if (offset != sizeof(pre_encoded_table)) die("Offset should be %ld, was %ld", (long)sizeof(pre_encoded_table), (long)offset); result = memcmp(pre_encoded_table, encoding_buffer, offset); if (result != 0) die("Table encoding differed", result); } empty_amqp_pool(&pool); }