|
|
|
@ -78,6 +78,10 @@
|
|
|
|
|
if (stream->pos + bytes >= stream->size) { return 0; } \
|
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
|
|
#define CBOR_ENSURE_SIZE_READ(stream, bytes) do { \
|
|
|
|
|
if (bytes > stream->size) { return 0; } \
|
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
|
|
/* Extra defines not related to the protocol itself */
|
|
|
|
|
#define CBOR_STREAM_PRINT_BUFFERSIZE 1024 /* bytes */
|
|
|
|
|
|
|
|
|
@ -91,7 +95,20 @@
|
|
|
|
|
#define NAN (0.0/0.0)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* pack to force aligned access on ARMv7 (buggy GCC) */
|
|
|
|
|
#pragma GCC diagnostic error "-Wcast-align"
|
|
|
|
|
typedef struct __attribute__((packed)) {
|
|
|
|
|
unsigned char u8;
|
|
|
|
|
union {
|
|
|
|
|
uint16_t u16;
|
|
|
|
|
uint32_t u32;
|
|
|
|
|
uint64_t u64;
|
|
|
|
|
} u;
|
|
|
|
|
} cast_align_u8_t;
|
|
|
|
|
|
|
|
|
|
#ifndef CBOR_NO_FLOAT
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Convert float @p x to network format
|
|
|
|
|
*/
|
|
|
|
@ -323,10 +340,14 @@ static size_t decode_int(const cbor_stream_t *s, size_t offset, uint64_t *val)
|
|
|
|
|
|
|
|
|
|
*val = 0; /* clear val first */
|
|
|
|
|
|
|
|
|
|
CBOR_ENSURE_SIZE_READ(s, offset + 1);
|
|
|
|
|
|
|
|
|
|
unsigned char *in = &s->data[offset];
|
|
|
|
|
unsigned char additional_info = CBOR_ADDITIONAL_INFO(s, offset);
|
|
|
|
|
unsigned char bytes_follow = uint_bytes_follow(additional_info);
|
|
|
|
|
|
|
|
|
|
CBOR_ENSURE_SIZE_READ(s, offset + 1 + bytes_follow);
|
|
|
|
|
|
|
|
|
|
switch (bytes_follow) {
|
|
|
|
|
case 0:
|
|
|
|
|
*val = (in[0] & CBOR_INFO_MASK);
|
|
|
|
@ -337,15 +358,15 @@ static size_t decode_int(const cbor_stream_t *s, size_t offset, uint64_t *val)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
|
*val = HTONS(*((uint16_t *)&in[1]));
|
|
|
|
|
*val = HTONS(((cast_align_u8_t *)in)->u.u16);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
|
*val = HTONL(*((uint32_t *)&in[1]));
|
|
|
|
|
*val = HTONL(((cast_align_u8_t *)in)->u.u32);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
*val = HTONLL(*((uint64_t *)&in[1]));
|
|
|
|
|
*val = HTONLL(((cast_align_u8_t *)in)->u.u64);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -371,6 +392,8 @@ static size_t encode_bytes(unsigned char major_type, cbor_stream_t *s, const cha
|
|
|
|
|
|
|
|
|
|
static size_t decode_bytes(const cbor_stream_t *s, size_t offset, char *out, size_t length)
|
|
|
|
|
{
|
|
|
|
|
CBOR_ENSURE_SIZE_READ(s, offset + 1);
|
|
|
|
|
|
|
|
|
|
if ((CBOR_TYPE(s, offset) != CBOR_BYTES && CBOR_TYPE(s, offset) != CBOR_TEXT) || !out) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -386,13 +409,43 @@ static size_t decode_bytes(const cbor_stream_t *s, size_t offset, char *out, siz
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CBOR_ENSURE_SIZE_READ(s, offset + bytes_start + bytes_length);
|
|
|
|
|
|
|
|
|
|
memcpy(out, &s->data[offset + bytes_start], bytes_length);
|
|
|
|
|
out[bytes_length] = '\0';
|
|
|
|
|
return (bytes_start + bytes_length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* A zero copy version of decode_bytes.
|
|
|
|
|
Will not null termiante input, but will tell you the size of what you read.
|
|
|
|
|
Great for reading byte strings which could contain nulls inside of unknown size
|
|
|
|
|
without forced copies.
|
|
|
|
|
*/
|
|
|
|
|
static size_t decode_bytes_no_copy(const cbor_stream_t *s, size_t offset, unsigned char **out, size_t *length)
|
|
|
|
|
{
|
|
|
|
|
CBOR_ENSURE_SIZE_READ(s, offset + 1);
|
|
|
|
|
|
|
|
|
|
if ((CBOR_TYPE(s, offset) != CBOR_BYTES && CBOR_TYPE(s, offset) != CBOR_TEXT) || !out) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t bytes_length;
|
|
|
|
|
size_t bytes_start = decode_int(s, offset, &bytes_length);
|
|
|
|
|
|
|
|
|
|
if (!bytes_start) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CBOR_ENSURE_SIZE_READ(s, offset + bytes_start + bytes_length);
|
|
|
|
|
*out = &(s->data[offset + bytes_start]);
|
|
|
|
|
*length = bytes_length;
|
|
|
|
|
return (bytes_start + bytes_length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t cbor_deserialize_int(const cbor_stream_t *stream, size_t offset, int *val)
|
|
|
|
|
{
|
|
|
|
|
CBOR_ENSURE_SIZE_READ(stream, offset + 1);
|
|
|
|
|
|
|
|
|
|
if ((CBOR_TYPE(stream, offset) != CBOR_UINT && CBOR_TYPE(stream, offset) != CBOR_NEGINT) || !val) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -400,6 +453,10 @@ size_t cbor_deserialize_int(const cbor_stream_t *stream, size_t offset, int *val
|
|
|
|
|
uint64_t buf;
|
|
|
|
|
size_t read_bytes = decode_int(stream, offset, &buf);
|
|
|
|
|
|
|
|
|
|
if (!read_bytes) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (CBOR_TYPE(stream, offset) == CBOR_UINT) {
|
|
|
|
|
*val = buf; /* resolve as CBOR_UINT */
|
|
|
|
|
}
|
|
|
|
@ -521,7 +578,7 @@ size_t cbor_deserialize_float(const cbor_stream_t *stream, size_t offset, float
|
|
|
|
|
unsigned char *data = &stream->data[offset];
|
|
|
|
|
|
|
|
|
|
if (*data == CBOR_FLOAT32) {
|
|
|
|
|
*val = ntohf(*(uint32_t *)(data + 1));
|
|
|
|
|
*val = ntohf(((cast_align_u8_t *)data)->u.u32);
|
|
|
|
|
return 5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -540,6 +597,8 @@ size_t cbor_serialize_float(cbor_stream_t *s, float val)
|
|
|
|
|
|
|
|
|
|
size_t cbor_deserialize_double(const cbor_stream_t *stream, size_t offset, double *val)
|
|
|
|
|
{
|
|
|
|
|
CBOR_ENSURE_SIZE_READ(stream, offset + 1);
|
|
|
|
|
|
|
|
|
|
if (CBOR_TYPE(stream, offset) != CBOR_7 || !val) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -547,7 +606,8 @@ size_t cbor_deserialize_double(const cbor_stream_t *stream, size_t offset, doubl
|
|
|
|
|
unsigned char *data = &stream->data[offset];
|
|
|
|
|
|
|
|
|
|
if (*data == CBOR_FLOAT64) {
|
|
|
|
|
*val = ntohd(*(uint64_t *)(data + 1));
|
|
|
|
|
CBOR_ENSURE_SIZE_READ(stream, offset + 9);
|
|
|
|
|
*val = ntohd(((cast_align_u8_t *)data)->u.u64);
|
|
|
|
|
return 9;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -568,6 +628,8 @@ size_t cbor_serialize_double(cbor_stream_t *s, double val)
|
|
|
|
|
size_t cbor_deserialize_byte_string(const cbor_stream_t *stream, size_t offset, char *val,
|
|
|
|
|
size_t length)
|
|
|
|
|
{
|
|
|
|
|
CBOR_ENSURE_SIZE_READ(stream, offset + 1);
|
|
|
|
|
|
|
|
|
|
if (CBOR_TYPE(stream, offset) != CBOR_BYTES) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -575,6 +637,18 @@ size_t cbor_deserialize_byte_string(const cbor_stream_t *stream, size_t offset,
|
|
|
|
|
return decode_bytes(stream, offset, val, length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t cbor_deserialize_byte_string_no_copy(const cbor_stream_t *stream, size_t offset, unsigned char **val,
|
|
|
|
|
size_t *length)
|
|
|
|
|
{
|
|
|
|
|
CBOR_ENSURE_SIZE_READ(stream, offset + 1);
|
|
|
|
|
|
|
|
|
|
if (CBOR_TYPE(stream, offset) != CBOR_BYTES) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return decode_bytes_no_copy(stream, offset, val, length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t cbor_serialize_byte_string(cbor_stream_t *stream, const char *val)
|
|
|
|
|
{
|
|
|
|
|
return encode_bytes(CBOR_BYTES, stream, val, strlen(val));
|
|
|
|
@ -588,6 +662,8 @@ size_t cbor_serialize_byte_stringl(cbor_stream_t *stream, const char *val, size_
|
|
|
|
|
size_t cbor_deserialize_unicode_string(const cbor_stream_t *stream, size_t offset, char *val,
|
|
|
|
|
size_t length)
|
|
|
|
|
{
|
|
|
|
|
CBOR_ENSURE_SIZE_READ(stream, offset + 1);
|
|
|
|
|
|
|
|
|
|
if (CBOR_TYPE(stream, offset) != CBOR_TEXT) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -595,6 +671,18 @@ size_t cbor_deserialize_unicode_string(const cbor_stream_t *stream, size_t offse
|
|
|
|
|
return decode_bytes(stream, offset, val, length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t cbor_deserialize_unicode_string_no_copy(const cbor_stream_t *stream, size_t offset, unsigned char **val,
|
|
|
|
|
size_t *length)
|
|
|
|
|
{
|
|
|
|
|
CBOR_ENSURE_SIZE_READ(stream, offset + 1);
|
|
|
|
|
|
|
|
|
|
if (CBOR_TYPE(stream, offset) != CBOR_TEXT) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return decode_bytes_no_copy(stream, offset, val, length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t cbor_serialize_unicode_string(cbor_stream_t *stream, const char *val)
|
|
|
|
|
{
|
|
|
|
|
return encode_bytes(CBOR_TEXT, stream, val, strlen(val));
|
|
|
|
|