|
Packit |
12c978 |
/*
|
|
Packit |
12c978 |
* ***** BEGIN LICENSE BLOCK *****
|
|
Packit |
12c978 |
* Version: MIT
|
|
Packit |
12c978 |
*
|
|
Packit |
12c978 |
* Portions created by Alan Antonuk are Copyright (c) 2012-2013
|
|
Packit |
12c978 |
* Alan Antonuk. All Rights Reserved.
|
|
Packit |
12c978 |
*
|
|
Packit |
12c978 |
* Portions created by VMware are Copyright (c) 2007-2012 VMware, Inc.
|
|
Packit |
12c978 |
* All Rights Reserved.
|
|
Packit |
12c978 |
*
|
|
Packit |
12c978 |
* Portions created by Tony Garnock-Jones are Copyright (c) 2009-2010
|
|
Packit |
12c978 |
* VMware, Inc. and Tony Garnock-Jones. All Rights Reserved.
|
|
Packit |
12c978 |
*
|
|
Packit |
12c978 |
* Permission is hereby granted, free of charge, to any person
|
|
Packit |
12c978 |
* obtaining a copy of this software and associated documentation
|
|
Packit |
12c978 |
* files (the "Software"), to deal in the Software without
|
|
Packit |
12c978 |
* restriction, including without limitation the rights to use, copy,
|
|
Packit |
12c978 |
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
Packit |
12c978 |
* of the Software, and to permit persons to whom the Software is
|
|
Packit |
12c978 |
* furnished to do so, subject to the following conditions:
|
|
Packit |
12c978 |
*
|
|
Packit |
12c978 |
* The above copyright notice and this permission notice shall be
|
|
Packit |
12c978 |
* included in all copies or substantial portions of the Software.
|
|
Packit |
12c978 |
*
|
|
Packit |
12c978 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
Packit |
12c978 |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
Packit |
12c978 |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
Packit |
12c978 |
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
Packit |
12c978 |
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
Packit |
12c978 |
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
Packit |
12c978 |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
Packit |
12c978 |
* SOFTWARE.
|
|
Packit |
12c978 |
* ***** END LICENSE BLOCK *****
|
|
Packit |
12c978 |
*/
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
12c978 |
#include "config.h"
|
|
Packit |
12c978 |
#endif
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
#include "amqp_private.h"
|
|
Packit |
12c978 |
#include "amqp_table.h"
|
|
Packit |
12c978 |
#include <assert.h>
|
|
Packit |
12c978 |
#include <stdint.h>
|
|
Packit |
12c978 |
#include <stdio.h>
|
|
Packit |
12c978 |
#include <stdlib.h>
|
|
Packit |
12c978 |
#include <string.h>
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
#define INITIAL_ARRAY_SIZE 16
|
|
Packit |
12c978 |
#define INITIAL_TABLE_SIZE 16
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
static int amqp_decode_field_value(amqp_bytes_t encoded, amqp_pool_t *pool,
|
|
Packit |
12c978 |
amqp_field_value_t *entry, size_t *offset);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
static int amqp_encode_field_value(amqp_bytes_t encoded,
|
|
Packit |
12c978 |
amqp_field_value_t *entry, size_t *offset);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
static int amqp_decode_array(amqp_bytes_t encoded, amqp_pool_t *pool,
|
|
Packit |
12c978 |
amqp_array_t *output, size_t *offset) {
|
|
Packit |
12c978 |
uint32_t arraysize;
|
|
Packit |
12c978 |
int num_entries = 0;
|
|
Packit |
12c978 |
int allocated_entries = INITIAL_ARRAY_SIZE;
|
|
Packit |
12c978 |
amqp_field_value_t *entries;
|
|
Packit |
12c978 |
size_t limit;
|
|
Packit |
12c978 |
int res;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
if (!amqp_decode_32(encoded, offset, &arraysize)) {
|
|
Packit |
12c978 |
return AMQP_STATUS_BAD_AMQP_DATA;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
if (arraysize + *offset > encoded.len) {
|
|
Packit |
12c978 |
return AMQP_STATUS_BAD_AMQP_DATA;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
entries = malloc(allocated_entries * sizeof(amqp_field_value_t));
|
|
Packit |
12c978 |
if (entries == NULL) {
|
|
Packit |
12c978 |
return AMQP_STATUS_NO_MEMORY;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
limit = *offset + arraysize;
|
|
Packit |
12c978 |
while (*offset < limit) {
|
|
Packit |
12c978 |
if (num_entries >= allocated_entries) {
|
|
Packit |
12c978 |
void *newentries;
|
|
Packit |
12c978 |
allocated_entries = allocated_entries * 2;
|
|
Packit |
12c978 |
newentries =
|
|
Packit |
12c978 |
realloc(entries, allocated_entries * sizeof(amqp_field_value_t));
|
|
Packit |
12c978 |
res = AMQP_STATUS_NO_MEMORY;
|
|
Packit |
12c978 |
if (newentries == NULL) {
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
entries = newentries;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
res = amqp_decode_field_value(encoded, pool, &entries[num_entries], offset);
|
|
Packit |
12c978 |
if (res < 0) {
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
num_entries++;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
output->num_entries = num_entries;
|
|
Packit |
12c978 |
output->entries =
|
|
Packit |
12c978 |
amqp_pool_alloc(pool, num_entries * sizeof(amqp_field_value_t));
|
|
Packit |
12c978 |
/* NULL is legitimate if we requested a zero-length block. */
|
|
Packit |
12c978 |
if (output->entries == NULL) {
|
|
Packit |
12c978 |
if (num_entries == 0) {
|
|
Packit |
12c978 |
res = AMQP_STATUS_OK;
|
|
Packit |
12c978 |
} else {
|
|
Packit |
12c978 |
res = AMQP_STATUS_NO_MEMORY;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
memcpy(output->entries, entries, num_entries * sizeof(amqp_field_value_t));
|
|
Packit |
12c978 |
res = AMQP_STATUS_OK;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
out:
|
|
Packit |
12c978 |
free(entries);
|
|
Packit |
12c978 |
return res;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
int amqp_decode_table(amqp_bytes_t encoded, amqp_pool_t *pool,
|
|
Packit |
12c978 |
amqp_table_t *output, size_t *offset) {
|
|
Packit |
12c978 |
uint32_t tablesize;
|
|
Packit |
12c978 |
int num_entries = 0;
|
|
Packit |
12c978 |
amqp_table_entry_t *entries;
|
|
Packit |
12c978 |
int allocated_entries = INITIAL_TABLE_SIZE;
|
|
Packit |
12c978 |
size_t limit;
|
|
Packit |
12c978 |
int res;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
if (!amqp_decode_32(encoded, offset, &tablesize)) {
|
|
Packit |
12c978 |
return AMQP_STATUS_BAD_AMQP_DATA;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
if (tablesize + *offset > encoded.len) {
|
|
Packit |
12c978 |
return AMQP_STATUS_BAD_AMQP_DATA;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
entries = malloc(allocated_entries * sizeof(amqp_table_entry_t));
|
|
Packit |
12c978 |
if (entries == NULL) {
|
|
Packit |
12c978 |
return AMQP_STATUS_NO_MEMORY;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
limit = *offset + tablesize;
|
|
Packit |
12c978 |
while (*offset < limit) {
|
|
Packit |
12c978 |
uint8_t keylen;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
res = AMQP_STATUS_BAD_AMQP_DATA;
|
|
Packit |
12c978 |
if (!amqp_decode_8(encoded, offset, &keylen)) {
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
if (num_entries >= allocated_entries) {
|
|
Packit |
12c978 |
void *newentries;
|
|
Packit |
12c978 |
allocated_entries = allocated_entries * 2;
|
|
Packit |
12c978 |
newentries =
|
|
Packit |
12c978 |
realloc(entries, allocated_entries * sizeof(amqp_table_entry_t));
|
|
Packit |
12c978 |
res = AMQP_STATUS_NO_MEMORY;
|
|
Packit |
12c978 |
if (newentries == NULL) {
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
entries = newentries;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
res = AMQP_STATUS_BAD_AMQP_DATA;
|
|
Packit |
12c978 |
if (!amqp_decode_bytes(encoded, offset, &entries[num_entries].key,
|
|
Packit |
12c978 |
keylen)) {
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
res = amqp_decode_field_value(encoded, pool, &entries[num_entries].value,
|
|
Packit |
12c978 |
offset);
|
|
Packit |
12c978 |
if (res < 0) {
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
num_entries++;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
output->num_entries = num_entries;
|
|
Packit |
12c978 |
output->entries =
|
|
Packit |
12c978 |
amqp_pool_alloc(pool, num_entries * sizeof(amqp_table_entry_t));
|
|
Packit |
12c978 |
/* NULL is legitimate if we requested a zero-length block. */
|
|
Packit |
12c978 |
if (output->entries == NULL) {
|
|
Packit |
12c978 |
if (num_entries == 0) {
|
|
Packit |
12c978 |
res = AMQP_STATUS_OK;
|
|
Packit |
12c978 |
} else {
|
|
Packit |
12c978 |
res = AMQP_STATUS_NO_MEMORY;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
memcpy(output->entries, entries, num_entries * sizeof(amqp_table_entry_t));
|
|
Packit |
12c978 |
res = AMQP_STATUS_OK;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
out:
|
|
Packit |
12c978 |
free(entries);
|
|
Packit |
12c978 |
return res;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
static int amqp_decode_field_value(amqp_bytes_t encoded, amqp_pool_t *pool,
|
|
Packit |
12c978 |
amqp_field_value_t *entry, size_t *offset) {
|
|
Packit |
12c978 |
int res = AMQP_STATUS_BAD_AMQP_DATA;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
if (!amqp_decode_8(encoded, offset, &entry->kind)) {
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
#define TRIVIAL_FIELD_DECODER(bits) \
|
|
Packit |
12c978 |
if (!amqp_decode_##bits(encoded, offset, &entry->value.u##bits)) goto out; \
|
|
Packit |
12c978 |
break
|
|
Packit |
12c978 |
#define SIMPLE_FIELD_DECODER(bits, dest, how) \
|
|
Packit |
12c978 |
{ \
|
|
Packit |
12c978 |
uint##bits##_t val; \
|
|
Packit |
12c978 |
if (!amqp_decode_##bits(encoded, offset, &val)) goto out; \
|
|
Packit |
12c978 |
entry->value.dest = how; \
|
|
Packit |
12c978 |
} \
|
|
Packit |
12c978 |
break
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
switch (entry->kind) {
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_BOOLEAN:
|
|
Packit |
12c978 |
SIMPLE_FIELD_DECODER(8, boolean, val ? 1 : 0);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_I8:
|
|
Packit |
12c978 |
SIMPLE_FIELD_DECODER(8, i8, (int8_t)val);
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_U8:
|
|
Packit |
12c978 |
TRIVIAL_FIELD_DECODER(8);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_I16:
|
|
Packit |
12c978 |
SIMPLE_FIELD_DECODER(16, i16, (int16_t)val);
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_U16:
|
|
Packit |
12c978 |
TRIVIAL_FIELD_DECODER(16);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_I32:
|
|
Packit |
12c978 |
SIMPLE_FIELD_DECODER(32, i32, (int32_t)val);
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_U32:
|
|
Packit |
12c978 |
TRIVIAL_FIELD_DECODER(32);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_I64:
|
|
Packit |
12c978 |
SIMPLE_FIELD_DECODER(64, i64, (int64_t)val);
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_U64:
|
|
Packit |
12c978 |
TRIVIAL_FIELD_DECODER(64);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_F32:
|
|
Packit |
12c978 |
TRIVIAL_FIELD_DECODER(32);
|
|
Packit |
12c978 |
/* and by punning, f32 magically gets the right value...! */
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_F64:
|
|
Packit |
12c978 |
TRIVIAL_FIELD_DECODER(64);
|
|
Packit |
12c978 |
/* and by punning, f64 magically gets the right value...! */
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_DECIMAL:
|
|
Packit |
12c978 |
if (!amqp_decode_8(encoded, offset, &entry->value.decimal.decimals) ||
|
|
Packit |
12c978 |
!amqp_decode_32(encoded, offset, &entry->value.decimal.value)) {
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_UTF8:
|
|
Packit |
12c978 |
/* AMQP_FIELD_KIND_UTF8 and AMQP_FIELD_KIND_BYTES have the
|
|
Packit |
12c978 |
same implementation, but different interpretations. */
|
|
Packit |
12c978 |
/* fall through */
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_BYTES: {
|
|
Packit |
12c978 |
uint32_t len;
|
|
Packit |
12c978 |
if (!amqp_decode_32(encoded, offset, &len) ||
|
|
Packit |
12c978 |
!amqp_decode_bytes(encoded, offset, &entry->value.bytes, len)) {
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_ARRAY:
|
|
Packit |
12c978 |
res = amqp_decode_array(encoded, pool, &(entry->value.array), offset);
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_TIMESTAMP:
|
|
Packit |
12c978 |
TRIVIAL_FIELD_DECODER(64);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_TABLE:
|
|
Packit |
12c978 |
res = amqp_decode_table(encoded, pool, &(entry->value.table), offset);
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_VOID:
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
default:
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
res = AMQP_STATUS_OK;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
out:
|
|
Packit |
12c978 |
return res;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
static int amqp_encode_array(amqp_bytes_t encoded, amqp_array_t *input,
|
|
Packit |
12c978 |
size_t *offset) {
|
|
Packit |
12c978 |
size_t start = *offset;
|
|
Packit |
12c978 |
int i, res;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
*offset += 4; /* size of the array gets filled in later on */
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
for (i = 0; i < input->num_entries; i++) {
|
|
Packit |
12c978 |
res = amqp_encode_field_value(encoded, &input->entries[i], offset);
|
|
Packit |
12c978 |
if (res < 0) {
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
if (!amqp_encode_32(encoded, &start, (uint32_t)(*offset - start - 4))) {
|
|
Packit |
12c978 |
res = AMQP_STATUS_TABLE_TOO_BIG;
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
res = AMQP_STATUS_OK;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
out:
|
|
Packit |
12c978 |
return res;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
int amqp_encode_table(amqp_bytes_t encoded, amqp_table_t *input,
|
|
Packit |
12c978 |
size_t *offset) {
|
|
Packit |
12c978 |
size_t start = *offset;
|
|
Packit |
12c978 |
int i, res;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
*offset += 4; /* size of the table gets filled in later on */
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
for (i = 0; i < input->num_entries; i++) {
|
|
Packit |
12c978 |
if (!amqp_encode_8(encoded, offset, (uint8_t)input->entries[i].key.len)) {
|
|
Packit |
12c978 |
res = AMQP_STATUS_TABLE_TOO_BIG;
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
if (!amqp_encode_bytes(encoded, offset, input->entries[i].key)) {
|
|
Packit |
12c978 |
res = AMQP_STATUS_TABLE_TOO_BIG;
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
res = amqp_encode_field_value(encoded, &input->entries[i].value, offset);
|
|
Packit |
12c978 |
if (res < 0) {
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
if (!amqp_encode_32(encoded, &start, (uint32_t)(*offset - start - 4))) {
|
|
Packit |
12c978 |
res = AMQP_STATUS_TABLE_TOO_BIG;
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
res = AMQP_STATUS_OK;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
out:
|
|
Packit |
12c978 |
return res;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
static int amqp_encode_field_value(amqp_bytes_t encoded,
|
|
Packit |
12c978 |
amqp_field_value_t *entry, size_t *offset) {
|
|
Packit |
12c978 |
int res = AMQP_STATUS_BAD_AMQP_DATA;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
if (!amqp_encode_8(encoded, offset, entry->kind)) {
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
#define FIELD_ENCODER(bits, val) \
|
|
Packit |
12c978 |
if (!amqp_encode_##bits(encoded, offset, val)) { \
|
|
Packit |
12c978 |
res = AMQP_STATUS_TABLE_TOO_BIG; \
|
|
Packit |
12c978 |
goto out; \
|
|
Packit |
12c978 |
} \
|
|
Packit |
12c978 |
break
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
switch (entry->kind) {
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_BOOLEAN:
|
|
Packit |
12c978 |
FIELD_ENCODER(8, entry->value.boolean ? 1 : 0);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_I8:
|
|
Packit |
12c978 |
FIELD_ENCODER(8, entry->value.i8);
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_U8:
|
|
Packit |
12c978 |
FIELD_ENCODER(8, entry->value.u8);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_I16:
|
|
Packit |
12c978 |
FIELD_ENCODER(16, entry->value.i16);
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_U16:
|
|
Packit |
12c978 |
FIELD_ENCODER(16, entry->value.u16);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_I32:
|
|
Packit |
12c978 |
FIELD_ENCODER(32, entry->value.i32);
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_U32:
|
|
Packit |
12c978 |
FIELD_ENCODER(32, entry->value.u32);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_I64:
|
|
Packit |
12c978 |
FIELD_ENCODER(64, entry->value.i64);
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_U64:
|
|
Packit |
12c978 |
FIELD_ENCODER(64, entry->value.u64);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_F32:
|
|
Packit |
12c978 |
/* by punning, u32 magically gets the right value...! */
|
|
Packit |
12c978 |
FIELD_ENCODER(32, entry->value.u32);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_F64:
|
|
Packit |
12c978 |
/* by punning, u64 magically gets the right value...! */
|
|
Packit |
12c978 |
FIELD_ENCODER(64, entry->value.u64);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_DECIMAL:
|
|
Packit |
12c978 |
if (!amqp_encode_8(encoded, offset, entry->value.decimal.decimals) ||
|
|
Packit |
12c978 |
!amqp_encode_32(encoded, offset, entry->value.decimal.value)) {
|
|
Packit |
12c978 |
res = AMQP_STATUS_TABLE_TOO_BIG;
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_UTF8:
|
|
Packit |
12c978 |
/* AMQP_FIELD_KIND_UTF8 and AMQP_FIELD_KIND_BYTES have the
|
|
Packit |
12c978 |
same implementation, but different interpretations. */
|
|
Packit |
12c978 |
/* fall through */
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_BYTES:
|
|
Packit |
12c978 |
if (!amqp_encode_32(encoded, offset, (uint32_t)entry->value.bytes.len) ||
|
|
Packit |
12c978 |
!amqp_encode_bytes(encoded, offset, entry->value.bytes)) {
|
|
Packit |
12c978 |
res = AMQP_STATUS_TABLE_TOO_BIG;
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_ARRAY:
|
|
Packit |
12c978 |
res = amqp_encode_array(encoded, &entry->value.array, offset);
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_TIMESTAMP:
|
|
Packit |
12c978 |
FIELD_ENCODER(64, entry->value.u64);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_TABLE:
|
|
Packit |
12c978 |
res = amqp_encode_table(encoded, &entry->value.table, offset);
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_VOID:
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
default:
|
|
Packit |
12c978 |
res = AMQP_STATUS_INVALID_PARAMETER;
|
|
Packit |
12c978 |
goto out;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
res = AMQP_STATUS_OK;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
out:
|
|
Packit |
12c978 |
return res;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
int amqp_table_entry_cmp(void const *entry1, void const *entry2) {
|
|
Packit |
12c978 |
amqp_table_entry_t const *p1 = (amqp_table_entry_t const *)entry1;
|
|
Packit |
12c978 |
amqp_table_entry_t const *p2 = (amqp_table_entry_t const *)entry2;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
int d;
|
|
Packit |
12c978 |
size_t minlen;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
minlen = p1->key.len;
|
|
Packit |
12c978 |
if (p2->key.len < minlen) {
|
|
Packit |
12c978 |
minlen = p2->key.len;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
d = memcmp(p1->key.bytes, p2->key.bytes, minlen);
|
|
Packit |
12c978 |
if (d != 0) {
|
|
Packit |
12c978 |
return d;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
return (int)p1->key.len - (int)p2->key.len;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
static int amqp_field_value_clone(const amqp_field_value_t *original,
|
|
Packit |
12c978 |
amqp_field_value_t *clone,
|
|
Packit |
12c978 |
amqp_pool_t *pool) {
|
|
Packit |
12c978 |
int i;
|
|
Packit |
12c978 |
int res;
|
|
Packit |
12c978 |
clone->kind = original->kind;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
switch (clone->kind) {
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_BOOLEAN:
|
|
Packit |
12c978 |
clone->value.boolean = original->value.boolean;
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_I8:
|
|
Packit |
12c978 |
clone->value.i8 = original->value.i8;
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_U8:
|
|
Packit |
12c978 |
clone->value.u8 = original->value.u8;
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_I16:
|
|
Packit |
12c978 |
clone->value.i16 = original->value.i16;
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_U16:
|
|
Packit |
12c978 |
clone->value.u16 = original->value.u16;
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_I32:
|
|
Packit |
12c978 |
clone->value.i32 = original->value.i32;
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_U32:
|
|
Packit |
12c978 |
clone->value.u32 = original->value.u32;
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_I64:
|
|
Packit |
12c978 |
clone->value.i64 = original->value.i64;
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_U64:
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_TIMESTAMP:
|
|
Packit |
12c978 |
clone->value.u64 = original->value.u64;
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_F32:
|
|
Packit |
12c978 |
clone->value.f32 = original->value.f32;
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_F64:
|
|
Packit |
12c978 |
clone->value.f64 = original->value.f64;
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_DECIMAL:
|
|
Packit |
12c978 |
clone->value.decimal = original->value.decimal;
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_UTF8:
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_BYTES:
|
|
Packit |
12c978 |
if (0 == original->value.bytes.len) {
|
|
Packit |
12c978 |
clone->value.bytes = amqp_empty_bytes;
|
|
Packit |
12c978 |
} else {
|
|
Packit |
12c978 |
amqp_pool_alloc_bytes(pool, original->value.bytes.len,
|
|
Packit |
12c978 |
&clone->value.bytes);
|
|
Packit |
12c978 |
if (NULL == clone->value.bytes.bytes) {
|
|
Packit |
12c978 |
return AMQP_STATUS_NO_MEMORY;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
memcpy(clone->value.bytes.bytes, original->value.bytes.bytes,
|
|
Packit |
12c978 |
clone->value.bytes.len);
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_ARRAY:
|
|
Packit |
12c978 |
if (0 == original->value.array.entries) {
|
|
Packit |
12c978 |
clone->value.array = amqp_empty_array;
|
|
Packit |
12c978 |
} else {
|
|
Packit |
12c978 |
clone->value.array.num_entries = original->value.array.num_entries;
|
|
Packit |
12c978 |
clone->value.array.entries = amqp_pool_alloc(
|
|
Packit |
12c978 |
pool, clone->value.array.num_entries * sizeof(amqp_field_value_t));
|
|
Packit |
12c978 |
if (NULL == clone->value.array.entries) {
|
|
Packit |
12c978 |
return AMQP_STATUS_NO_MEMORY;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
for (i = 0; i < clone->value.array.num_entries; ++i) {
|
|
Packit |
12c978 |
res = amqp_field_value_clone(&original->value.array.entries[i],
|
|
Packit |
12c978 |
&clone->value.array.entries[i], pool);
|
|
Packit |
12c978 |
if (AMQP_STATUS_OK != res) {
|
|
Packit |
12c978 |
return res;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_TABLE:
|
|
Packit |
12c978 |
return amqp_table_clone(&original->value.table, &clone->value.table,
|
|
Packit |
12c978 |
pool);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
case AMQP_FIELD_KIND_VOID:
|
|
Packit |
12c978 |
break;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
default:
|
|
Packit |
12c978 |
return AMQP_STATUS_INVALID_PARAMETER;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
return AMQP_STATUS_OK;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
static int amqp_table_entry_clone(const amqp_table_entry_t *original,
|
|
Packit |
12c978 |
amqp_table_entry_t *clone,
|
|
Packit |
12c978 |
amqp_pool_t *pool) {
|
|
Packit |
12c978 |
if (0 == original->key.len) {
|
|
Packit |
12c978 |
return AMQP_STATUS_INVALID_PARAMETER;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
amqp_pool_alloc_bytes(pool, original->key.len, &clone->key);
|
|
Packit |
12c978 |
if (NULL == clone->key.bytes) {
|
|
Packit |
12c978 |
return AMQP_STATUS_NO_MEMORY;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
memcpy(clone->key.bytes, original->key.bytes, clone->key.len);
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
return amqp_field_value_clone(&original->value, &clone->value, pool);
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
int amqp_table_clone(const amqp_table_t *original, amqp_table_t *clone,
|
|
Packit |
12c978 |
amqp_pool_t *pool) {
|
|
Packit |
12c978 |
int i;
|
|
Packit |
12c978 |
int res;
|
|
Packit |
12c978 |
clone->num_entries = original->num_entries;
|
|
Packit |
12c978 |
if (0 == clone->num_entries) {
|
|
Packit |
12c978 |
*clone = amqp_empty_table;
|
|
Packit |
12c978 |
return AMQP_STATUS_OK;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
clone->entries =
|
|
Packit |
12c978 |
amqp_pool_alloc(pool, clone->num_entries * sizeof(amqp_table_entry_t));
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
if (NULL == clone->entries) {
|
|
Packit |
12c978 |
return AMQP_STATUS_NO_MEMORY;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
for (i = 0; i < clone->num_entries; ++i) {
|
|
Packit |
12c978 |
res =
|
|
Packit |
12c978 |
amqp_table_entry_clone(&original->entries[i], &clone->entries[i], pool);
|
|
Packit |
12c978 |
if (AMQP_STATUS_OK != res) {
|
|
Packit |
12c978 |
goto error_out1;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
return AMQP_STATUS_OK;
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
error_out1:
|
|
Packit |
12c978 |
return res;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
amqp_table_entry_t amqp_table_construct_utf8_entry(const char *key,
|
|
Packit |
12c978 |
const char *value) {
|
|
Packit |
12c978 |
amqp_table_entry_t ret;
|
|
Packit |
12c978 |
ret.key = amqp_cstring_bytes(key);
|
|
Packit |
12c978 |
ret.value.kind = AMQP_FIELD_KIND_UTF8;
|
|
Packit |
12c978 |
ret.value.value.bytes = amqp_cstring_bytes(value);
|
|
Packit |
12c978 |
return ret;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
amqp_table_entry_t amqp_table_construct_table_entry(const char *key,
|
|
Packit |
12c978 |
const amqp_table_t *value) {
|
|
Packit |
12c978 |
amqp_table_entry_t ret;
|
|
Packit |
12c978 |
ret.key = amqp_cstring_bytes(key);
|
|
Packit |
12c978 |
ret.value.kind = AMQP_FIELD_KIND_TABLE;
|
|
Packit |
12c978 |
ret.value.value.table = *value;
|
|
Packit |
12c978 |
return ret;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
amqp_table_entry_t amqp_table_construct_bool_entry(const char *key,
|
|
Packit |
12c978 |
const int value) {
|
|
Packit |
12c978 |
amqp_table_entry_t ret;
|
|
Packit |
12c978 |
ret.key = amqp_cstring_bytes(key);
|
|
Packit |
12c978 |
ret.value.kind = AMQP_FIELD_KIND_BOOLEAN;
|
|
Packit |
12c978 |
ret.value.value.boolean = value;
|
|
Packit |
12c978 |
return ret;
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
|
|
Packit |
12c978 |
amqp_table_entry_t *amqp_table_get_entry_by_key(const amqp_table_t *table,
|
|
Packit |
12c978 |
const amqp_bytes_t key) {
|
|
Packit |
12c978 |
int i;
|
|
Packit |
12c978 |
assert(table != NULL);
|
|
Packit |
12c978 |
for (i = 0; i < table->num_entries; ++i) {
|
|
Packit |
12c978 |
if (amqp_bytes_equal(table->entries[i].key, key)) {
|
|
Packit |
12c978 |
return &table->entries[i];
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
}
|
|
Packit |
12c978 |
return NULL;
|
|
Packit |
12c978 |
}
|