blob: 6fe02bf7c06453ecb6f477066a3a2df15c49b4b9 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
#include <proton/error.h>
#include <proton/object.h>
#include <proton/codec.h>
#include "encodings.h"
#include "decoder.h"
#include <string.h>
static inline pn_error_t *pni_decoder_error(pn_decoder_t *decoder)
{
if (!decoder->error) decoder->error = pn_error();
return decoder->error;
}
void pn_decoder_initialize(pn_decoder_t *decoder)
{
decoder->input = NULL;
decoder->size = 0;
decoder->position = NULL;
decoder->error = NULL;
}
void pn_decoder_finalize(pn_decoder_t *decoder)
{
pn_error_free(decoder->error);
}
static inline uint8_t pn_decoder_readf8(pn_decoder_t *decoder)
{
uint8_t r = decoder->position[0];
decoder->position++;
return r;
}
static inline uint16_t pn_decoder_readf16(pn_decoder_t *decoder)
{
uint16_t a = (uint8_t) decoder->position[0];
uint16_t b = (uint8_t) decoder->position[1];
uint16_t r = a << 8
| b;
decoder->position += 2;
return r;
}
static inline uint32_t pn_decoder_readf32(pn_decoder_t *decoder)
{
uint32_t a = (uint8_t) decoder->position[0];
uint32_t b = (uint8_t) decoder->position[1];
uint32_t c = (uint8_t) decoder->position[2];
uint32_t d = (uint8_t) decoder->position[3];
uint32_t r = a << 24
| b << 16
| c << 8
| d;
decoder->position += 4;
return r;
}
static inline uint64_t pn_decoder_readf64(pn_decoder_t *decoder)
{
uint64_t a = pn_decoder_readf32(decoder);
uint64_t b = pn_decoder_readf32(decoder);
return a << 32 | b;
}
static inline void pn_decoder_readf128(pn_decoder_t *decoder, void *dst)
{
memmove(dst, decoder->position, 16);
decoder->position += 16;
}
static inline size_t pn_decoder_remaining(pn_decoder_t *decoder)
{
return decoder->input + decoder->size - decoder->position;
}
typedef union {
uint32_t i;
uint32_t a[2];
uint64_t l;
float f;
double d;
} conv_t;
static inline pn_type_t pn_code2type(uint8_t code)
{
switch (code)
{
case PNE_DESCRIPTOR:
return (pn_type_t) PN_ARG_ERR;
case PNE_NULL:
return PN_NULL;
case PNE_TRUE:
case PNE_FALSE:
case PNE_BOOLEAN:
return PN_BOOL;
case PNE_UBYTE:
return PN_UBYTE;
case PNE_BYTE:
return PN_BYTE;
case PNE_USHORT:
return PN_USHORT;
case PNE_SHORT:
return PN_SHORT;
case PNE_UINT0:
case PNE_SMALLUINT:
case PNE_UINT:
return PN_UINT;
case PNE_SMALLINT:
case PNE_INT:
return PN_INT;
case PNE_UTF32:
return PN_CHAR;
case PNE_FLOAT:
return PN_FLOAT;
case PNE_LONG:
case PNE_SMALLLONG:
return PN_LONG;
case PNE_MS64:
return PN_TIMESTAMP;
case PNE_DOUBLE:
return PN_DOUBLE;
case PNE_DECIMAL32:
return PN_DECIMAL32;
case PNE_DECIMAL64:
return PN_DECIMAL64;
case PNE_DECIMAL128:
return PN_DECIMAL128;
case PNE_UUID:
return PN_UUID;
case PNE_ULONG0:
case PNE_SMALLULONG:
case PNE_ULONG:
return PN_ULONG;
case PNE_VBIN8:
case PNE_VBIN32:
return PN_BINARY;
case PNE_STR8_UTF8:
case PNE_STR32_UTF8:
return PN_STRING;
case PNE_SYM8:
case PNE_SYM32:
return PN_SYMBOL;
case PNE_LIST0:
case PNE_LIST8:
case PNE_LIST32:
return PN_LIST;
case PNE_ARRAY8:
case PNE_ARRAY32:
return PN_ARRAY;
case PNE_MAP8:
case PNE_MAP32:
return PN_MAP;
default:
return (pn_type_t) PN_ARG_ERR;
}
}
static int pni_decoder_decode_type(pn_decoder_t *decoder, pn_data_t *data, uint8_t *code);
static int pni_decoder_single_described(pn_decoder_t *decoder, pn_data_t *data);
static int pni_decoder_single(pn_decoder_t *decoder, pn_data_t *data);
void pni_data_set_array_type(pn_data_t *data, pn_type_t type);
static int pni_decoder_decode_value(pn_decoder_t *decoder, pn_data_t *data, uint8_t code)
{
int err;
conv_t conv;
pn_decimal128_t dec128;
pn_uuid_t uuid;
size_t size;
size_t count;
switch (code)
{
case PNE_NULL:
err = pn_data_put_null(data);
break;
case PNE_TRUE:
err = pn_data_put_bool(data, true);
break;
case PNE_FALSE:
err = pn_data_put_bool(data, false);
break;
case PNE_BOOLEAN:
if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
err = pn_data_put_bool(data, pn_decoder_readf8(decoder) != 0);
break;
case PNE_UBYTE:
if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
err = pn_data_put_ubyte(data, pn_decoder_readf8(decoder));
break;
case PNE_BYTE:
if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
err = pn_data_put_byte(data, pn_decoder_readf8(decoder));
break;
case PNE_USHORT:
if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
err = pn_data_put_ushort(data, pn_decoder_readf16(decoder));
break;
case PNE_SHORT:
if (pn_decoder_remaining(decoder) < 2) return PN_UNDERFLOW;
err = pn_data_put_short(data, pn_decoder_readf16(decoder));
break;
case PNE_UINT:
if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
err = pn_data_put_uint(data, pn_decoder_readf32(decoder));
break;
case PNE_UINT0:
err = pn_data_put_uint(data, 0);
break;
case PNE_SMALLUINT:
if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
err = pn_data_put_uint(data, pn_decoder_readf8(decoder));
break;
case PNE_SMALLINT:
if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
err = pn_data_put_int(data, (int8_t)pn_decoder_readf8(decoder));
break;
case PNE_INT:
if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
err = pn_data_put_int(data, pn_decoder_readf32(decoder));
break;
case PNE_UTF32:
if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
err = pn_data_put_char(data, pn_decoder_readf32(decoder));
break;
case PNE_FLOAT:
if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
// XXX: this assumes the platform uses IEEE floats
conv.i = pn_decoder_readf32(decoder);
err = pn_data_put_float(data, conv.f);
break;
case PNE_DECIMAL32:
if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
err = pn_data_put_decimal32(data, pn_decoder_readf32(decoder));
break;
case PNE_ULONG:
if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
err = pn_data_put_ulong(data, pn_decoder_readf64(decoder));
break;
case PNE_LONG:
if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
err = pn_data_put_long(data, pn_decoder_readf64(decoder));
break;
case PNE_MS64:
if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
err = pn_data_put_timestamp(data, pn_decoder_readf64(decoder));
break;
case PNE_DOUBLE:
// XXX: this assumes the platform uses IEEE floats
if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
conv.l = pn_decoder_readf64(decoder);
err = pn_data_put_double(data, conv.d);
break;
case PNE_DECIMAL64:
if (pn_decoder_remaining(decoder) < 8) return PN_UNDERFLOW;
err = pn_data_put_decimal64(data, pn_decoder_readf64(decoder));
break;
case PNE_ULONG0:
err = pn_data_put_ulong(data, 0);
break;
case PNE_SMALLULONG:
if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
err = pn_data_put_ulong(data, pn_decoder_readf8(decoder));
break;
case PNE_SMALLLONG:
if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
err = pn_data_put_long(data, (int8_t)pn_decoder_readf8(decoder));
break;
case PNE_DECIMAL128:
if (pn_decoder_remaining(decoder) < 16) return PN_UNDERFLOW;
pn_decoder_readf128(decoder, &dec128);
err = pn_data_put_decimal128(data, dec128);
break;
case PNE_UUID:
if (pn_decoder_remaining(decoder) < 16) return PN_UNDERFLOW;
pn_decoder_readf128(decoder, &uuid);
err = pn_data_put_uuid(data, uuid);
break;
case PNE_VBIN8:
case PNE_STR8_UTF8:
case PNE_SYM8:
case PNE_VBIN32:
case PNE_STR32_UTF8:
case PNE_SYM32:
switch (code & 0xF0)
{
case 0xA0:
if (!pn_decoder_remaining(decoder)) return PN_UNDERFLOW;
size = pn_decoder_readf8(decoder);
break;
case 0xB0:
if (pn_decoder_remaining(decoder) < 4) return PN_UNDERFLOW;
size = pn_decoder_readf32(decoder);
break;
default:
return PN_ARG_ERR;
}
if (pn_decoder_remaining(decoder) < size) return PN_UNDERFLOW;
{
char *start = (char *) decoder->position;
pn_bytes_t bytes = {size, start};
switch (code & 0x0F)
{
case 0x0:
err = pn_data_put_binary(data, bytes);
break;
case 0x1:
err = pn_data_put_string(data, bytes);
break;
case 0x3:
err = pn_data_put_symbol(data, bytes);
break;
default:
return PN_ARG_ERR;
}
}
decoder->position += size;
break;
case PNE_LIST0:
err = pn_data_put_list(data);
break;
case PNE_ARRAY8:
case PNE_ARRAY32:
case PNE_LIST8:
case PNE_LIST32:
case PNE_MAP8:
case PNE_MAP32: {
size_t min_expected_size = 0;
switch (code)
{
case PNE_ARRAY8:
min_expected_size += 1; // Array has a constructor of at least 1 byte
case PNE_LIST8:
case PNE_MAP8:
min_expected_size += 1; // All these types have a count
if (pn_decoder_remaining(decoder) < min_expected_size+1) return PN_UNDERFLOW;
size = pn_decoder_readf8(decoder);
// size must be at least big enough for count or count+constructor
if (size < min_expected_size) return PN_ARG_ERR;
if (pn_decoder_remaining(decoder) < size) return PN_UNDERFLOW;
count = pn_decoder_readf8(decoder);
break;
case PNE_ARRAY32:
min_expected_size += 1; // Array has a constructor of at least 1 byte
case PNE_LIST32:
case PNE_MAP32:
min_expected_size += 4; // All these types have a count
if (pn_decoder_remaining(decoder) < min_expected_size+4) return PN_UNDERFLOW;
size = pn_decoder_readf32(decoder);
// size must be at least big enough for count or count+constructor
if (size < min_expected_size) return PN_ARG_ERR;
if (pn_decoder_remaining(decoder) < size) return PN_UNDERFLOW;
count = pn_decoder_readf32(decoder);
break;
default:
return PN_ARG_ERR;
}
switch (code)
{
case PNE_ARRAY8:
case PNE_ARRAY32:
{
uint8_t next = *decoder->position;
bool described = (next == PNE_DESCRIPTOR);
err = pn_data_put_array(data, described, (pn_type_t) 0);
if (err) return err;
pn_data_enter(data);
uint8_t acode;
int e = pni_decoder_decode_type(decoder, data, &acode);
if (e) return e;
pn_type_t type = pn_code2type(acode);
if ((int)type < 0) return (int)type;
for (size_t i = 0; i < count; i++)
{
e = pni_decoder_decode_value(decoder, data, acode);
if (e) return e;
}
pn_data_exit(data);
pni_data_set_array_type(data, type);
}
return 0;
case PNE_LIST8:
case PNE_LIST32:
err = pn_data_put_list(data);
if (err) return err;
break;
case PNE_MAP8:
case PNE_MAP32:
err = pn_data_put_map(data);
if (err) return err;
break;
default:
return PN_ARG_ERR;
}
pn_data_enter(data);
for (size_t i = 0; i < count; i++)
{
int e = pni_decoder_single(decoder, data);
if (e) return e;
}
pn_data_exit(data);
return 0;
}
default:
return pn_error_format(pni_decoder_error(decoder), PN_ARG_ERR, "unrecognized typecode: %u", code);
}
return err;
}
pn_type_t pni_data_parent_type(pn_data_t *data);
static int pni_decoder_decode_type(pn_decoder_t *decoder, pn_data_t *data, uint8_t *code)
{
int err;
if (!pn_decoder_remaining(decoder)) {
return PN_UNDERFLOW;
}
uint8_t next = *decoder->position++;
if (next != PNE_DESCRIPTOR) {
*code = next;
return 0;
}
if (pni_data_parent_type(data) != PN_ARRAY) {
err = pn_data_put_described(data);
if (err) return err;
// pni_decoder_single has the corresponding exit
pn_data_enter(data);
}
err = pni_decoder_single_described(decoder, data);
if (err) return err;
err = pni_decoder_decode_type(decoder, data, code);
if (err) return err;
return 0;
}
size_t pn_data_siblings(pn_data_t *data);
// We disallow using any compound type as a described descriptor to avoid recursion
// in decoding. Although these seem syntactically valid they don't seem to be of any
// conceivable use!
static inline bool pni_allowed_descriptor_code(uint8_t code)
{
return
code != PNE_DESCRIPTOR &&
code != PNE_ARRAY8 && code != PNE_ARRAY32 &&
code != PNE_LIST8 && code != PNE_LIST32 &&
code != PNE_MAP8 && code != PNE_MAP32;
}
int pni_decoder_single_described(pn_decoder_t *decoder, pn_data_t *data)
{
if (!pn_decoder_remaining(decoder)) {
return PN_UNDERFLOW;
}
uint8_t code = *decoder->position++;;
if (!pni_allowed_descriptor_code(code)) {
return PN_ARG_ERR;
}
int err = pni_decoder_decode_value(decoder, data, code);
if (err) return err;
if (pni_data_parent_type(data) == PN_DESCRIBED && pn_data_siblings(data) > 1) {
pn_data_exit(data);
}
return 0;
}
int pni_decoder_single(pn_decoder_t *decoder, pn_data_t *data)
{
uint8_t code;
int err = pni_decoder_decode_type(decoder, data, &code);
if (err) return err;
err = pni_decoder_decode_value(decoder, data, code);
if (err) return err;
if (pni_data_parent_type(data) == PN_DESCRIBED && pn_data_siblings(data) > 1) {
pn_data_exit(data);
}
return 0;
}
ssize_t pn_decoder_decode(pn_decoder_t *decoder, const char *src, size_t size, pn_data_t *dst)
{
decoder->input = src;
decoder->size = size;
decoder->position = src;
int err = pni_decoder_single(decoder, dst);
if (err == PN_UNDERFLOW)
return pn_error_format(pn_data_error(dst), PN_UNDERFLOW, "not enough data to decode");
if (err) return err;
return decoder->position - decoder->input;
}