diff --git a/Makefile b/Makefile index f3a2a712..7e2105cb 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,11 @@ RMDIR = rmdir SED = sed # Our sources -TINYCBOR_HEADERS = src/cbor.h src/cborjson.h +TINYCBOR_HEADERS = \ + src/cbor.h \ + src/cborjson.h \ + src/cbor_enocoder_writer.h \ + src/cbor_decoder_reader.h TINYCBOR_SOURCES = \ src/cborerrorstrings.c \ src/cborencoder.c \ @@ -31,6 +35,8 @@ TINYCBOR_SOURCES = \ src/cborpretty_stdio.c \ src/cbortojson.c \ src/cborvalidation.c \ + src/cbor_buf_reader.c \ + src/cbor_buf_writer.c # CBORDUMP_SOURCES = tools/cbordump/cbordump.c @@ -95,7 +101,7 @@ endif # version using funopen or fopencookie ifeq ($(open_memstream-pass),) ifeq ($(funopen-pass)$(fopencookie-pass),) - CFLAGS += -DWITHOUT_OPEN_MEMSTREAM + CFLAGS += -DCBOR_WITHOUT_OPEN_MEMSTREAM $(warning warning: funopen and fopencookie unavailable, open_memstream can not be implemented and conversion to JSON will not work properly!) else TINYCBOR_SOURCES += src/open_memstream.c diff --git a/Makefile.nmake b/Makefile.nmake index defc30aa..4033ed3a 100644 --- a/Makefile.nmake +++ b/Makefile.nmake @@ -1,6 +1,6 @@ CFLAGS = -W3 -TINYCBOR_HEADERS = src\cbor.h src\cborjson.h +TINYCBOR_HEADERS = src TINYCBOR_SOURCES = \ src\cborerrorstrings.c \ src\cborencoder.c \ @@ -9,7 +9,9 @@ TINYCBOR_SOURCES = \ src\cborparser_dup_string.c \ src\cborpretty.c \ src\cborpretty_stdio.c \ - src\cborvalidation.c + src\cborvalidation.c \ + src\cbor_buf_reader.c \ + src\cbor_buf_writer.c TINYCBOR_OBJS = \ src\cborerrorstrings.obj \ src\cborencoder.obj \ @@ -18,7 +20,9 @@ TINYCBOR_OBJS = \ src\cborparser_dup_string.obj \ src\cborpretty.obj \ src\cborpretty_stdio.obj \ - src\cborvalidation.obj + src\cborvalidation.obj \ + src\cbor_buf_writer.obj \ + src\cbor_buf_reader.obj all: lib\tinycbor.lib check: tests\Makefile lib\tinycbor.lib diff --git a/src/cbor.h b/src/cbor.h index 24c6df69..f1158a71 100644 --- a/src/cbor.h +++ b/src/cbor.h @@ -34,6 +34,8 @@ #include #include +#include "cbor_buf_writer.h" +#include "cbor_buf_reader.h" #include "tinycbor-version.h" #define TINYCBOR_VERSION ((TINYCBOR_VERSION_MAJOR << 16) | (TINYCBOR_VERSION_MINOR << 8) | TINYCBOR_VERSION_PATCH) @@ -204,19 +206,23 @@ CBOR_API const char *cbor_error_string(CborError error); /* Encoder API */ struct CborEncoder { - union { - uint8_t *ptr; - ptrdiff_t bytes_needed; - } data; - const uint8_t *end; + cbor_encoder_writer *writer; + void *writer_arg; +#ifndef CBOR_NO_DFLT_WRITER + struct cbor_buf_writer wr; +#endif size_t remaining; int flags; }; + typedef struct CborEncoder CborEncoder; static const size_t CborIndefiniteLength = SIZE_MAX; +#ifndef CBOR_NO_DFLT_WRITER CBOR_API void cbor_encoder_init(CborEncoder *encoder, uint8_t *buffer, size_t size, int flags); +#endif +CBOR_API void cbor_encoder_cust_writer_init(CborEncoder *encoder, struct cbor_encoder_writer *w, int flags); CBOR_API CborError cbor_encode_uint(CborEncoder *encoder, uint64_t value); CBOR_API CborError cbor_encode_int(CborEncoder *encoder, int64_t value); CBOR_API CborError cbor_encode_negative_int(CborEncoder *encoder, uint64_t absolute_value); @@ -227,7 +233,8 @@ CBOR_INLINE_API CborError cbor_encode_text_stringz(CborEncoder *encoder, const c { return cbor_encode_text_string(encoder, string, strlen(string)); } CBOR_API CborError cbor_encode_byte_string(CborEncoder *encoder, const uint8_t *string, size_t length); CBOR_API CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, const void *value); - +CBOR_INLINE_API int cbor_encode_bytes_written(CborEncoder *encoder) +{ return encoder->writer->bytes_written; } CBOR_INLINE_API CborError cbor_encode_boolean(CborEncoder *encoder, bool value) { return cbor_encode_simple_value(encoder, (int)value - 1 + (CborBooleanType & 0x1f)); } CBOR_INLINE_API CborError cbor_encode_null(CborEncoder *encoder) @@ -247,21 +254,6 @@ CBOR_API CborError cbor_encoder_create_map(CborEncoder *encoder, CborEncoder *ma CBOR_API CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder *containerEncoder); CBOR_API CborError cbor_encoder_close_container_checked(CborEncoder *encoder, const CborEncoder *containerEncoder); -CBOR_INLINE_API uint8_t *_cbor_encoder_get_buffer_pointer(const CborEncoder *encoder) -{ - return encoder->data.ptr; -} - -CBOR_INLINE_API size_t cbor_encoder_get_buffer_size(const CborEncoder *encoder, const uint8_t *buffer) -{ - return (size_t)(encoder->data.ptr - buffer); -} - -CBOR_INLINE_API size_t cbor_encoder_get_extra_bytes_needed(const CborEncoder *encoder) -{ - return encoder->end ? 0 : (size_t)encoder->data.bytes_needed; -} - /* Parser API */ enum CborParserIteratorFlags @@ -275,7 +267,11 @@ enum CborParserIteratorFlags struct CborParser { - const uint8_t *end; +#ifndef CBOR_NO_DFLT_READER + struct cbor_buf_reader br; +#endif + struct cbor_decoder_reader *d; + int end; int flags; }; typedef struct CborParser CborParser; @@ -283,22 +279,24 @@ typedef struct CborParser CborParser; struct CborValue { const CborParser *parser; - const uint8_t *ptr; + int offset; uint32_t remaining; + uint32_t remainingclen; uint16_t extra; uint8_t type; uint8_t flags; }; typedef struct CborValue CborValue; +#ifndef CBOR_NO_DFLT_READER CBOR_API CborError cbor_parser_init(const uint8_t *buffer, size_t size, int flags, CborParser *parser, CborValue *it); +#endif +CBOR_API CborError cbor_parser_cust_reader_init(struct cbor_decoder_reader *r, int flags, CborParser *parser, CborValue *it); CBOR_API CborError cbor_value_validate_basic(const CborValue *it); CBOR_INLINE_API bool cbor_value_at_end(const CborValue *it) { return it->remaining == 0; } -CBOR_INLINE_API const uint8_t *cbor_value_get_next_byte(const CborValue *it) -{ return it->ptr; } CBOR_API CborError cbor_value_advance_fixed(CborValue *it); CBOR_API CborError cbor_value_advance(CborValue *it); CBOR_INLINE_API bool cbor_value_is_container(const CborValue *it) diff --git a/src/cbor_buf_reader.c b/src/cbor_buf_reader.c new file mode 100644 index 00000000..c3e6a573 --- /dev/null +++ b/src/cbor_buf_reader.c @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#include "cbor_buf_reader.h" +#include "compilersupport_p.h" + +/** + * \addtogroup CborParsing + * @{ + */ + +/** + * Gets 16 bit unsigned value from the passed in ptr location, it also + * converts it to host byte order + */ +CBOR_INLINE_API uint16_t get16(const uint8_t *ptr) +{ + uint16_t result; + memcpy(&result, ptr, sizeof(result)); + return cbor_ntohs(result); +} + +/** + * Gets 32 bit unsigned value from the passed in ptr location, it also + * converts it to host byte order + */ +CBOR_INLINE_API uint32_t get32(const uint8_t *ptr) +{ + uint32_t result; + memcpy(&result, ptr, sizeof(result)); + return cbor_ntohl(result); +} + +/** + * Gets 64 bit unsigned value from the passed in ptr location, it also + * converts it to host byte order + */ +CBOR_INLINE_API uint64_t get64(const uint8_t *ptr) +{ + uint64_t result; + memcpy(&result, ptr, sizeof(result)); + return cbor_ntohll(result); +} + +/** + * Gets a string chunk from the passed in ptr location + */ +CBOR_INLINE_API uintptr_t get_string_chunk(const uint8_t *ptr) +{ + return (uintptr_t)ptr; +} + +/** + * Gets 8 bit unsigned value using the buffer pointed to by the + * decoder reader from passed in offset + */ +static uint8_t +cbuf_buf_reader_get8(struct cbor_decoder_reader *d, int offset) +{ + struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d; + return cb->buffer[offset]; +} + +/** + * Gets 16 bit unsigned value using the buffer pointed to by the + * decoder reader from passed in offset + */ +static uint16_t +cbuf_buf_reader_get16(struct cbor_decoder_reader *d, int offset) +{ + struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d; + return get16(cb->buffer + offset); +} + +/** + * Gets 32 bit unsigned value using the buffer pointed to by the + * decoder reader from passed in offset + */ +static uint32_t +cbuf_buf_reader_get32(struct cbor_decoder_reader *d, int offset) +{ + uint32_t val; + struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d; + val = get32(cb->buffer + offset); + return val; +} + +/** + * Gets 64 bit unsigned value using the buffer pointed to by the + * decoder reader from passed in offset + */ +static uint64_t +cbuf_buf_reader_get64(struct cbor_decoder_reader *d, int offset) +{ + struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d; + return get64(cb->buffer + offset); +} + +static uintptr_t +cbor_buf_reader_get_string_chunk(struct cbor_decoder_reader *d, + int offset, size_t *len) +{ + struct cbor_buf_reader *cb = (struct cbor_buf_reader *)d; + + (void)*len; + + return get_string_chunk(cb->buffer + offset); +} + +static uintptr_t +cbor_buf_reader_cmp(struct cbor_decoder_reader *d, char *dst, int src_offset, + size_t len) +{ + struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d; + + return !memcmp(dst, cb->buffer + src_offset, len); +} + +static uintptr_t +cbor_buf_reader_cpy(struct cbor_decoder_reader *d, char *dst, int src_offset, + size_t len) +{ + struct cbor_buf_reader *cb = (struct cbor_buf_reader *) d; + return (uintptr_t) memcpy(dst, cb->buffer + src_offset, len); +} + +void +cbor_buf_reader_init(struct cbor_buf_reader *cb, const uint8_t *buffer, + size_t data) +{ + cb->buffer = buffer; + cb->r.get8 = &cbuf_buf_reader_get8; + cb->r.get16 = &cbuf_buf_reader_get16; + cb->r.get32 = &cbuf_buf_reader_get32; + cb->r.get64 = &cbuf_buf_reader_get64; + cb->r.cmp = &cbor_buf_reader_cmp; + cb->r.cpy = &cbor_buf_reader_cpy; + cb->r.get_string_chunk = &cbor_buf_reader_get_string_chunk; + cb->r.message_size = data; +} + +/** @} */ diff --git a/src/cbor_buf_reader.h b/src/cbor_buf_reader.h new file mode 100644 index 00000000..70408fd6 --- /dev/null +++ b/src/cbor_buf_reader.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#ifndef CBOR_BUF_READER_H +#define CBOR_BUF_READER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "cbor_decoder_reader.h" + +struct cbor_buf_reader { + struct cbor_decoder_reader r; + const uint8_t *buffer; +}; + +void cbor_buf_reader_init(struct cbor_buf_reader *cb, const uint8_t *buffer, + size_t data); + +#ifdef __cplusplus +} +#endif + +#endif /* CBOR_BUF_READER_H */ + diff --git a/src/cbor_buf_writer.c b/src/cbor_buf_writer.c new file mode 100644 index 00000000..fb401bcf --- /dev/null +++ b/src/cbor_buf_writer.c @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#include "cbor.h" +#include "cbor_buf_writer.h" + +CBOR_INLINE_API int +would_overflow(struct cbor_buf_writer *cb, size_t len) +{ + ptrdiff_t remaining = (ptrdiff_t)cb->end; + + if (!remaining) + return 1; + remaining -= (ptrdiff_t)cb->ptr; + remaining -= (ptrdiff_t)len; + return (remaining < 0); +} + +int +cbor_buf_writer(struct cbor_encoder_writer *arg, const char *data, int len) +{ + struct cbor_buf_writer *cb = (struct cbor_buf_writer *) arg; + + if (would_overflow(cb, len)) { + if (cb->end != NULL) { + len -= cb->end - cb->ptr; + cb->end = NULL; + cb->bytes_needed = 0; + } + + cb->bytes_needed += len; + + return CborErrorOutOfMemory; + } + + memcpy(cb->ptr, data, len); + cb->ptr += len; + cb->enc.bytes_written += len; + return CborNoError; +} + +void +cbor_buf_writer_init(struct cbor_buf_writer *cb, uint8_t *buffer, size_t size) +{ + cb->ptr = buffer; + cb->end = buffer + size; + cb->enc.bytes_written = 0; + cb->bytes_needed = 0; + cb->enc.write = cbor_buf_writer; +} + +size_t +cbor_buf_writer_buffer_size(struct cbor_buf_writer *cb, const uint8_t *buffer) +{ + return (size_t)(cb->ptr - buffer); +} + +size_t cbor_encoder_get_extra_bytes_needed(const CborEncoder *encoder) +{ + struct cbor_buf_writer *wr = (struct cbor_buf_writer *)encoder->writer; + + return wr->end ? 0 : (size_t)wr->bytes_needed; +} + +size_t cbor_encoder_get_buffer_size(const CborEncoder *encoder, const uint8_t *buffer) +{ + struct cbor_buf_writer *wr = (struct cbor_buf_writer *)encoder->writer; + + return (size_t)(wr->ptr - buffer); +} + +uint8_t *_cbor_encoder_get_buffer_pointer(const CborEncoder *encoder) +{ + struct cbor_buf_writer *wr = (struct cbor_buf_writer *)encoder->writer; + + return wr->ptr; +} + diff --git a/src/cbor_buf_writer.h b/src/cbor_buf_writer.h new file mode 100644 index 00000000..f9f714f7 --- /dev/null +++ b/src/cbor_buf_writer.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#ifndef CBOR_BUF_WRITER_H +#define CBOR_BUF_WRITER_H + +#include "cbor_encoder_writer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct cbor_buf_writer { + struct cbor_encoder_writer enc; + uint8_t *ptr; + const uint8_t *end; + int bytes_needed; +}; + +struct CborEncoder; + +void cbor_buf_writer_init(struct cbor_buf_writer *cb, uint8_t *buffer, + size_t data); +size_t cbor_buf_writer_buffer_size(struct cbor_buf_writer *cb, + const uint8_t *buffer); +size_t cbor_encoder_get_extra_bytes_needed(const struct CborEncoder *encoder); +size_t cbor_encoder_get_buffer_size(const struct CborEncoder *encoder, + const uint8_t *buffer); + +#ifdef __cplusplus +} +#endif + +#endif /* CBOR_BUF_WRITER_H */ diff --git a/src/cbor_cnt_writer.h b/src/cbor_cnt_writer.h new file mode 100644 index 00000000..7cf34649 --- /dev/null +++ b/src/cbor_cnt_writer.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#ifndef CBOR_CNT_WRITER_H +#define CBOR_CNT_WRITER_H + +#include "cbor.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + /* use this count writer if you want to try out a cbor encoding to see + * how long it would be (before allocating memory). This replaced the + * code in tinycbor.h that would try to do this once the encoding failed + * in a buffer. Its much easier to understand this way (for me) + */ + +struct CborCntWriter { + struct cbor_encoder_writer enc; +}; + +static inline int +cbor_cnt_writer(struct cbor_encoder_writer *arg, const char *data, int len) { + struct CborCntWriter *cb = (struct CborCntWriter *) arg; + cb->enc.bytes_written += len; + return CborNoError; +} + +static inline void +cbor_cnt_writer_init(struct CborCntWriter *cb) { + cb->enc.bytes_written = 0; + cb->enc.write = &cbor_cnt_writer; +} + +#ifdef __cplusplus +} +#endif + +#endif /* CBOR_CNT_WRITER_H */ + diff --git a/src/cbor_decoder_reader.h b/src/cbor_decoder_reader.h new file mode 100644 index 00000000..c3ecabab --- /dev/null +++ b/src/cbor_decoder_reader.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#ifndef CBOR_DECODER_WRITER_H +#define CBOR_DECODER_WRITER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct cbor_decoder_reader; + +typedef uint8_t (cbor_reader_get8)(struct cbor_decoder_reader *d, int offset); +typedef uint16_t (cbor_reader_get16)(struct cbor_decoder_reader *d, int offset); +typedef uint32_t (cbor_reader_get32)(struct cbor_decoder_reader *d, int offset); +typedef uint64_t (cbor_reader_get64)(struct cbor_decoder_reader *d, int offset); +typedef uintptr_t (cbor_memcmp)(struct cbor_decoder_reader *d, char *buf, int offset, size_t len); +typedef uintptr_t (cbor_memcpy)(struct cbor_decoder_reader *d, char *buf, int offset, size_t len); +typedef uintptr_t (cbor_get_string_chunk)(struct cbor_decoder_reader *d, int offset, size_t *len); + +struct cbor_decoder_reader { + cbor_reader_get8 *get8; + cbor_reader_get16 *get16; + cbor_reader_get32 *get32; + cbor_reader_get64 *get64; + cbor_memcmp *cmp; + cbor_memcpy *cpy; + cbor_get_string_chunk *get_string_chunk; + size_t message_size; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/cbor_encoder_writer.h b/src/cbor_encoder_writer.h new file mode 100644 index 00000000..37fd3990 --- /dev/null +++ b/src/cbor_encoder_writer.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Intel Corporation +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in +** all copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +** THE SOFTWARE. +** +****************************************************************************/ + +#ifndef CBOR_ENCODER_H +#define CBOR_ENCODER_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct cbor_encoder_writer; + +typedef int (cbor_encoder_write)(struct cbor_encoder_writer *, const char *data, int len); + +typedef struct cbor_encoder_writer { + cbor_encoder_write *write; + int bytes_written; +} cbor_encoder_writer; + +#ifdef __cplusplus +} +#endif + +#endif /* CBOR_ENCODER_WRITER_H */ diff --git a/src/cborencoder.c b/src/cborencoder.c index fb950240..81ac2431 100644 --- a/src/cborencoder.c +++ b/src/cborencoder.c @@ -35,6 +35,7 @@ #include "cbor.h" #include "cborinternal_p.h" #include "compilersupport_p.h" +#include "cbor_buf_writer.h" #include #include @@ -195,6 +196,7 @@ * Structure used to encode to CBOR. */ +#ifndef CBOR_NO_DFLT_WRITER /** * Initializes a CborEncoder structure \a encoder by pointing it to buffer \a * buffer of size \a size. The \a flags field is currently unused and must be @@ -202,17 +204,32 @@ */ void cbor_encoder_init(CborEncoder *encoder, uint8_t *buffer, size_t size, int flags) { - encoder->data.ptr = buffer; - encoder->end = buffer + size; + cbor_buf_writer_init(&encoder->wr, buffer, size); + + cbor_encoder_cust_writer_init(encoder, &encoder->wr.enc, flags); +} +#endif + +/** + * Initializes a CborEncoder structure \a encoder by pointing it to buffer \a + * buffer of size \a size. The \a flags field is currently unused and must be + * zero. + */ +void cbor_encoder_cust_writer_init(CborEncoder *encoder, struct cbor_encoder_writer *w, int flags) +{ + encoder->writer = w; encoder->remaining = 2; encoder->flags = flags; } + +#ifndef CBOR_NO_FLOATING_POINT static inline void put16(void *where, uint16_t v) { v = cbor_htons(v); memcpy(where, &v, sizeof(v)); } +#endif /* Note: Since this is currently only used in situations where OOM is the only * valid error, we KNOW this to be true. Thus, this function now returns just 'true', @@ -225,11 +242,13 @@ static inline bool isOomError(CborError err) return true; } +#ifndef CBOR_NO_FLOATING_POINT static inline void put32(void *where, uint32_t v) { v = cbor_htonl(v); memcpy(where, &v, sizeof(v)); } +#endif static inline void put64(void *where, uint64_t v) { @@ -237,38 +256,9 @@ static inline void put64(void *where, uint64_t v) memcpy(where, &v, sizeof(v)); } -static inline bool would_overflow(CborEncoder *encoder, size_t len) -{ - ptrdiff_t remaining = (ptrdiff_t)encoder->end; - remaining -= remaining ? (ptrdiff_t)encoder->data.ptr : encoder->data.bytes_needed; - remaining -= (ptrdiff_t)len; - return unlikely(remaining < 0); -} - -static inline void advance_ptr(CborEncoder *encoder, size_t n) -{ - if (encoder->end) - encoder->data.ptr += n; - else - encoder->data.bytes_needed += n; -} - static inline CborError append_to_buffer(CborEncoder *encoder, const void *data, size_t len) { - if (would_overflow(encoder, len)) { - if (encoder->end != NULL) { - len -= encoder->end - encoder->data.ptr; - encoder->end = NULL; - encoder->data.bytes_needed = 0; - } - - advance_ptr(encoder, len); - return CborErrorOutOfMemory; - } - - memcpy(encoder->data.ptr, data, len); - encoder->data.ptr += len; - return CborNoError; + return (CborError)encoder->writer->write(encoder->writer, (const char *)data, len); } static inline CborError append_byte_to_buffer(CborEncoder *encoder, uint8_t byte) @@ -373,6 +363,7 @@ CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value) return encode_number(encoder, value, SimpleTypesType << MajorTypeShift); } +#ifndef CBOR_NO_FLOATING_POINT /** * Appends the floating-point value of type \a fpType and pointed to by \a * value to the CBOR stream provided by \a encoder. The value of \a fpType must @@ -400,6 +391,7 @@ CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, cons saturated_decrement(encoder); return append_to_buffer(encoder, buf, size + 1); } +#endif /** * Appends the CBOR tag \a tag to the CBOR stream provided by \a encoder. @@ -460,8 +452,10 @@ __attribute__((noinline)) static CborError create_container(CborEncoder *encoder, CborEncoder *container, size_t length, uint8_t shiftedMajorType) { CborError err; - container->data.ptr = encoder->data.ptr; - container->end = encoder->end; + container->writer = encoder->writer; +#ifndef CBOR_NO_DFLT_WRITER + container->wr.end = encoder->wr.end; +#endif saturated_decrement(encoder); container->remaining = length + 1; /* overflow ok on CborIndefiniteLength */ @@ -538,19 +532,20 @@ CborError cbor_encoder_create_map(CborEncoder *encoder, CborEncoder *mapEncoder, */ CborError cbor_encoder_close_container(CborEncoder *encoder, const CborEncoder *containerEncoder) { - if (encoder->end) - encoder->data.ptr = containerEncoder->data.ptr; - else - encoder->data.bytes_needed = containerEncoder->data.bytes_needed; - encoder->end = containerEncoder->end; + encoder->writer = containerEncoder->writer; + if (containerEncoder->flags & CborIteratorFlag_UnknownLength) return append_byte_to_buffer(encoder, BreakByte); if (containerEncoder->remaining != 1) return containerEncoder->remaining == 0 ? CborErrorTooManyItems : CborErrorTooFewItems; - if (!encoder->end) - return CborErrorOutOfMemory; /* keep the state */ +#ifndef CBOR_NO_DFLT_WRITER + if (!encoder->wr.end) { + return CborErrorOutOfMemory; + } +#endif + return CborNoError; } diff --git a/src/cborinternal_p.h b/src/cborinternal_p.h index 06fa6a2e..ddeb2c2b 100644 --- a/src/cborinternal_p.h +++ b/src/cborinternal_p.h @@ -83,7 +83,7 @@ enum { BreakByte = (unsigned)Break | (SimpleTypesType << MajorTypeShift) }; -CBOR_INTERNAL_API CBOR_INTERNAL_API_CC CborError _cbor_value_extract_number(const uint8_t **ptr, const uint8_t *end, uint64_t *len); +CBOR_INTERNAL_API CBOR_INTERNAL_API_CC CborError _cbor_value_extract_number(const CborParser *p, int *offset, uint64_t *len); CBOR_INTERNAL_API CBOR_INTERNAL_API_CC CborError _cbor_value_prepare_string_iteration(CborValue *it); #endif /* CBORINTERNAL_P_H */ diff --git a/src/cborparser.c b/src/cborparser.c index 6410fafd..9ebc7056 100644 --- a/src/cborparser.c +++ b/src/cborparser.c @@ -38,6 +38,7 @@ #include +#include "cbor_buf_reader.h" /** * \defgroup CborParsing Parsing CBOR streams * \brief Group of functions used to parse CBOR streams. @@ -142,31 +143,10 @@ * \endif */ -static inline uint16_t get16(const uint8_t *ptr) +CBOR_INTERNAL_API_CC CborError _cbor_value_extract_number(const CborParser *p, int *offset, uint64_t *len) { - uint16_t result; - memcpy(&result, ptr, sizeof(result)); - return cbor_ntohs(result); -} - -static inline uint32_t get32(const uint8_t *ptr) -{ - uint32_t result; - memcpy(&result, ptr, sizeof(result)); - return cbor_ntohl(result); -} - -static inline uint64_t get64(const uint8_t *ptr) -{ - uint64_t result; - memcpy(&result, ptr, sizeof(result)); - return cbor_ntohll(result); -} - -CBOR_INTERNAL_API_CC CborError _cbor_value_extract_number(const uint8_t **ptr, const uint8_t *end, uint64_t *len) -{ - uint8_t additional_information = **ptr & SmallValueMask; - ++*ptr; + uint8_t additional_information = p->d->get8(p->d, *offset) & SmallValueMask; + ++*offset; if (additional_information < Value8Bit) { *len = additional_information; return CborNoError; @@ -175,25 +155,26 @@ CBOR_INTERNAL_API_CC CborError _cbor_value_extract_number(const uint8_t **ptr, c return CborErrorIllegalNumber; size_t bytesNeeded = (size_t)(1 << (additional_information - Value8Bit)); - if (unlikely(bytesNeeded > (size_t)(end - *ptr))) { + if (unlikely(bytesNeeded > (size_t)(p->end - *offset))) { return CborErrorUnexpectedEOF; } else if (bytesNeeded == 1) { - *len = (uint8_t)(*ptr)[0]; + *len = p->d->get8(p->d, *offset); } else if (bytesNeeded == 2) { - *len = get16(*ptr); + *len = p->d->get16(p->d, *offset); } else if (bytesNeeded == 4) { - *len = get32(*ptr); + *len = p->d->get32(p->d, *offset); } else { - *len = get64(*ptr); + *len = p->d->get64(p->d, *offset); } - *ptr += bytesNeeded; + *offset += bytesNeeded; return CborNoError; } -static CborError extract_length(const CborParser *parser, const uint8_t **ptr, size_t *len) +static CborError extract_length(const CborParser *parser, + int *offset, size_t *len) { uint64_t v; - CborError err = _cbor_value_extract_number(ptr, parser->end, &v); + CborError err = _cbor_value_extract_number(parser, offset, &v); if (err) { *len = 0; return err; @@ -217,15 +198,18 @@ static CborError preparse_value(CborValue *it) it->type = CborInvalidType; /* are we at the end? */ - if (it->ptr == parser->end) + if (it->offset == parser->end) return CborErrorUnexpectedEOF; - uint8_t descriptor = *it->ptr; + uint8_t descriptor = parser->d->get8(parser->d, it->offset); uint8_t type = descriptor & MajorTypeMask; it->type = type; it->flags = 0; + it->remainingclen = 0; it->extra = (descriptor &= SmallValueMask); + size_t bytesNeeded = descriptor < Value8Bit ? 0 : (1 << (descriptor - Value8Bit)); + if (descriptor > Value64Bit) { if (unlikely(descriptor != IndefiniteLength)) return type == CborSimpleType ? CborErrorUnknownType : CborErrorIllegalNumber; @@ -238,8 +222,7 @@ static CborError preparse_value(CborValue *it) return type == CborSimpleType ? CborErrorUnexpectedBreak : CborErrorIllegalNumber; } - size_t bytesNeeded = descriptor < Value8Bit ? 0 : (1 << (descriptor - Value8Bit)); - if (bytesNeeded + 1 > (size_t)(parser->end - it->ptr)) + if (bytesNeeded + 1 > (size_t)(parser->end - it->offset)) return CborErrorUnexpectedEOF; uint8_t majortype = type >> MajorTypeShift; @@ -261,11 +244,11 @@ static CborError preparse_value(CborValue *it) case NullValue: case UndefinedValue: case HalfPrecisionFloat: - it->type = *it->ptr; + it->type = parser->d->get8(parser->d, it->offset); break; case SimpleTypeInNextByte: - it->extra = (uint8_t)it->ptr[1]; + it->extra = parser->d->get8(parser->d, it->offset + 1); #ifndef CBOR_PARSER_NO_STRICT_CHECKS if (unlikely(it->extra < 32)) { it->type = CborInvalidType; @@ -289,9 +272,9 @@ static CborError preparse_value(CborValue *it) return CborNoError; if (descriptor == Value8Bit) - it->extra = (uint8_t)it->ptr[1]; + it->extra = parser->d->get8(parser->d, it->offset + 1); else if (descriptor == Value16Bit) - it->extra = get16(it->ptr + 1); + it->extra = parser->d->get16(parser->d, it->offset + 1); else it->flags |= CborIteratorFlag_IntegerValueTooLarge; /* Value32Bit or Value64Bit */ return CborNoError; @@ -305,9 +288,10 @@ static CborError preparse_next_value(CborValue *it) it->type = CborInvalidType; return CborNoError; } - } else if (it->remaining == UINT32_MAX && it->ptr != it->parser->end && *it->ptr == (uint8_t)BreakByte) { + } else if (it->remaining == UINT32_MAX && it->offset != it->parser->end && + it->parser->d->get8(it->parser->d, it->offset) == (uint8_t)BreakByte) { /* end of map or array */ - ++it->ptr; + ++it->offset; it->type = CborInvalidType; it->remaining = 0; return CborNoError; @@ -319,13 +303,14 @@ static CborError preparse_next_value(CborValue *it) static CborError advance_internal(CborValue *it) { uint64_t length; - CborError err = _cbor_value_extract_number(&it->ptr, it->parser->end, &length); + CborError err; + err = _cbor_value_extract_number(it->parser, &it->offset, &length); cbor_assert(err == CborNoError); if (it->type == CborByteStringType || it->type == CborTextStringType) { cbor_assert(length == (size_t)length); cbor_assert((it->flags & CborIteratorFlag_UnknownLength) == 0); - it->ptr += length; + it->offset += length; } return preparse_next_value(it); @@ -343,19 +328,22 @@ static CborError advance_internal(CborValue *it) */ uint64_t _cbor_value_decode_int64_internal(const CborValue *value) { + uint8_t val = value->parser->d->get8(value->parser->d, value->offset); + cbor_assert(value->flags & CborIteratorFlag_IntegerValueTooLarge || value->type == CborFloatType || value->type == CborDoubleType); /* since the additional information can only be Value32Bit or Value64Bit, * we just need to test for the one bit those two options differ */ - cbor_assert((*value->ptr & SmallValueMask) == Value32Bit || (*value->ptr & SmallValueMask) == Value64Bit); - if ((*value->ptr & 1) == (Value32Bit & 1)) - return get32(value->ptr + 1); + cbor_assert((val & SmallValueMask) == Value32Bit || (val & SmallValueMask) == Value64Bit); + if ((val & 1) == (Value32Bit & 1)) + return value->parser->d->get32(value->parser->d, value->offset + 1); - cbor_assert((*value->ptr & SmallValueMask) == Value64Bit); - return get64(value->ptr + 1); + cbor_assert((val & SmallValueMask) == Value64Bit); + return value->parser->d->get64(value->parser->d, value->offset + 1); } +#ifndef CBOR_NO_DFLT_READER /** * Initializes the CBOR parser for parsing \a size bytes beginning at \a * buffer. Parsing will use flags set in \a flags. The iterator to the first @@ -369,11 +357,30 @@ uint64_t _cbor_value_decode_int64_internal(const CborValue *value) CborError cbor_parser_init(const uint8_t *buffer, size_t size, int flags, CborParser *parser, CborValue *it) { memset(parser, 0, sizeof(*parser)); - parser->end = buffer + size; + + cbor_buf_reader_init(&parser->br, buffer, size); + + return cbor_parser_cust_reader_init(&parser->br.r, flags, parser, it); +} +#endif + +/** + * Initializes the CBOR parser for parsing. It uses the \a decoder reader. Parsing will + * use flags set in \a flags. The iterator to the first element is returned in \a it. + * + * The \a parser structure needs to remain valid throughout the decoding + * process. It is not thread-safe to share one CborParser among multiple + * threads iterating at the same time, but the object can be copied so multiple + * threads can iterate. + */ +CborError cbor_parser_cust_reader_init(struct cbor_decoder_reader *r, int flags, CborParser *parser, CborValue *it) +{ + parser->d = r; + parser->end = r->message_size; parser->flags = flags; it->parser = parser; - it->ptr = buffer; - it->remaining = 1; /* there's one type altogether, usually an array or map */ + it->offset = 0; + it->remaining = 1;/* there's one type altogether, usually an array or map */ return preparse_value(it); } @@ -584,29 +591,29 @@ CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed) if (it->flags & CborIteratorFlag_UnknownLength) { recursed->remaining = UINT32_MAX; - ++recursed->ptr; + ++recursed->offset; err = preparse_value(recursed); if (err != CborErrorUnexpectedBreak) return err; /* actually, break was expected here * it's just an empty container */ - ++recursed->ptr; + ++recursed->offset; } else { uint64_t len; - err = _cbor_value_extract_number(&recursed->ptr, recursed->parser->end, &len); + err = _cbor_value_extract_number(recursed->parser, &recursed->offset, &len); cbor_assert(err == CborNoError); recursed->remaining = (uint32_t)len; if (recursed->remaining != len || len == UINT32_MAX) { /* back track the pointer to indicate where the error occurred */ - recursed->ptr = it->ptr; + recursed->offset = it->offset; return CborErrorDataTooLarge; } if (recursed->type == CborMapType) { /* maps have keys and values, so we need to multiply by 2 */ if (recursed->remaining > UINT32_MAX / 2) { /* back track the pointer to indicate where the error occurred */ - recursed->ptr = it->ptr; + recursed->offset = it->offset; return CborErrorDataTooLarge; } recursed->remaining *= 2; @@ -637,7 +644,8 @@ CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed) { cbor_assert(cbor_value_is_container(it)); cbor_assert(recursed->type == CborInvalidType); - it->ptr = recursed->ptr; + it->offset = recursed->offset; + return preparse_next_value(it); } @@ -975,7 +983,7 @@ static inline void prepare_string_iteration(CborValue *it) if (!cbor_value_is_length_known(it)) { /* chunked string: we're before the first chunk; * advance to the first chunk */ - ++it->ptr; + ++it->offset; it->flags |= CborIteratorFlag_IteratingStringChunks; } } @@ -986,15 +994,36 @@ CBOR_INTERNAL_API_CC CborError _cbor_value_prepare_string_iteration(CborValue *i prepare_string_iteration(it); /* are we at the end? */ - if (it->ptr == it->parser->end) + if (it->offset == it->parser->end) return CborErrorUnexpectedEOF; + return CborNoError; } +static const void * +get_string_chunk_update(CborValue *it, const void **bufferptr, size_t *len) +{ + *bufferptr = (const void *)it->parser->d->get_string_chunk(it->parser->d, + it->offset, len); + it->offset += *len; + it->remainingclen -= *len; + + return *bufferptr; +} + static CborError get_string_chunk(CborValue *it, const void **bufferptr, size_t *len) { CborError err; + + if (it->remainingclen) { + *len = it->remainingclen; + + *bufferptr = get_string_chunk_update(it, bufferptr, len); + + return CborNoError; + } + /* Possible states: * length known | iterating | meaning * no | no | before the first chunk of a chunked string @@ -1012,26 +1041,34 @@ static CborError get_string_chunk(CborValue *it, const void **bufferptr, size_t prepare_string_iteration(it); } + uint8_t val; + + val = it->parser->d->get8(it->parser->d, it->offset); + /* are we at the end? */ - if (it->ptr == it->parser->end) + if (it->offset == it->parser->end) return CborErrorUnexpectedEOF; - if (*it->ptr == BreakByte) { + if (val == (uint8_t)BreakByte) { /* last chunk */ - ++it->ptr; + ++it->offset; last_chunk: *bufferptr = NULL; *len = 0; + it->remainingclen = 0; return preparse_next_value(it); - } else if ((uint8_t)(*it->ptr & MajorTypeMask) == it->type) { - err = extract_length(it->parser, &it->ptr, len); + } else if ((val & MajorTypeMask) == it->type) { + err = extract_length(it->parser, &it->offset, len); if (err) return err; - if (*len > (size_t)(it->parser->end - it->ptr)) + + if (*len > (size_t)(it->parser->end - it->offset)) return CborErrorUnexpectedEOF; - *bufferptr = it->ptr; - it->ptr += *len; + it->remainingclen = *len; + + *bufferptr = get_string_chunk_update(it, bufferptr, len); + } else { return CborErrorIllegalType; } @@ -1128,6 +1165,7 @@ CborError _cbor_value_get_string_chunk(const CborValue *value, const void **buff if (!next) next = &tmp; *next = *value; + return get_string_chunk(next, bufferptr, len); } @@ -1135,26 +1173,17 @@ CborError _cbor_value_get_string_chunk(const CborValue *value, const void **buff * function. The choice is to optimize for memcpy, which is used in the base * parser API (cbor_value_copy_string), while memcmp is used in convenience API * only. */ -typedef uintptr_t (*IterateFunction)(char *, const uint8_t *, size_t); +typedef uintptr_t (*IterateFunction)(struct cbor_decoder_reader *d, char *dst, int src_offset, size_t len); -static uintptr_t iterate_noop(char *dest, const uint8_t *src, size_t len) +static uintptr_t iterate_noop(struct cbor_decoder_reader *d, char *dst, int src_offset, size_t len) { - (void)dest; - (void)src; + (void)d; + (void)dst; + (void)src_offset; (void)len; return true; } -static uintptr_t iterate_memcmp(char *s1, const uint8_t *s2, size_t len) -{ - return memcmp(s1, (const char *)s2, len) == 0; -} - -static uintptr_t iterate_memcpy(char *dest, const uint8_t *src, size_t len) -{ - return (uintptr_t)memcpy(dest, src, len); -} - static CborError iterate_string_chunks(const CborValue *value, char *buffer, size_t *buflen, bool *result, CborValue *next, IterateFunction func) { @@ -1172,7 +1201,7 @@ static CborError iterate_string_chunks(const CborValue *value, char *buffer, siz while (1) { size_t newTotal; - size_t chunkLen; + size_t chunkLen = 0; err = get_string_chunk(next, &ptr, &chunkLen); if (err) return err; @@ -1183,19 +1212,15 @@ static CborError iterate_string_chunks(const CborValue *value, char *buffer, siz return CborErrorDataTooLarge; if (*result && *buflen >= newTotal) - *result = !!func(buffer + total, (const uint8_t *)ptr, chunkLen); + *result = !!func(value->parser->d, buffer + total, next->offset - chunkLen, chunkLen); else *result = false; total = newTotal; } - /* is there enough room for the ending NUL byte? */ - if (*result && *buflen > total) { - uint8_t nul[] = { 0 }; - *result = !!func(buffer + total, nul, 1); - } *buflen = total; + return CborNoError; } @@ -1269,9 +1294,20 @@ CborError _cbor_value_copy_string(const CborValue *value, void *buffer, { bool copied_all; CborError err = iterate_string_chunks(value, (char*)buffer, buflen, &copied_all, next, - buffer ? iterate_memcpy : iterate_noop); - return err ? err : - copied_all ? CborNoError : CborErrorOutOfMemory; + buffer ? (IterateFunction) value->parser->d->cpy : iterate_noop); + if (err) { + return err; + } + + if (!copied_all) { + return CborErrorOutOfMemory; + } + + if (buffer) { + *((uint8_t *)buffer + *buflen) = '\0'; + } + + return CborNoError; } /** @@ -1296,6 +1332,7 @@ CborError cbor_value_text_string_equals(const CborValue *value, const char *stri { CborValue copy = *value; CborError err = cbor_value_skip_tag(©); + if (err) return err; if (!cbor_value_is_text_string(©)) { @@ -1304,7 +1341,17 @@ CborError cbor_value_text_string_equals(const CborValue *value, const char *stri } size_t len = strlen(string); - return iterate_string_chunks(©, CONST_CAST(char *, string), &len, result, NULL, iterate_memcmp); + err = iterate_string_chunks(©, CONST_CAST(char *, string), &len, + result, NULL, value->parser->d->cmp); + if (err) { + return err; + } + + if (*result && string[len] != '\0') { + *result = false; + } + + return CborNoError; } /** @@ -1396,10 +1443,10 @@ CborError cbor_value_map_find_value(const CborValue *map, const char *string, Cb bool equals; size_t dummyLen = len; err = iterate_string_chunks(element, CONST_CAST(char *, string), &dummyLen, - &equals, element, iterate_memcmp); + &equals, element, map->parser->d->cmp); if (err) goto error; - if (equals) + if (equals && string[dummyLen] == '\0') return preparse_value(element); } else { /* skip this key */ @@ -1495,9 +1542,10 @@ CborError cbor_value_get_half_float(const CborValue *value, void *result) cbor_assert(cbor_value_is_half_float(value)); /* size has been computed already */ - uint16_t v = get16(value->ptr + 1); + uint16_t v = value->parser->d->get16(value->parser->d, value->offset + 1); memcpy(result, &v, sizeof(v)); return CborNoError; } + /** @} */ diff --git a/src/cborparser_dup_string.c b/src/cborparser_dup_string.c index 66a908e5..1fda05e0 100644 --- a/src/cborparser_dup_string.c +++ b/src/cborparser_dup_string.c @@ -33,8 +33,8 @@ #endif #include "cbor.h" -#include "compilersupport_p.h" #include +#include "compilersupport_p.h" /** * \fn CborError cbor_value_dup_text_string(const CborValue *value, char **buffer, size_t *buflen, CborValue *next) diff --git a/src/cborpretty.c b/src/cborpretty.c index 0995f512..1a8280ee 100644 --- a/src/cborpretty.c +++ b/src/cborpretty.c @@ -29,13 +29,15 @@ #endif #include "cbor.h" -#include "cborinternal_p.h" #include "compilersupport_p.h" +#include "cborinternal_p.h" #include "utf8_p.h" -#include #include +#include +#ifndef CBOR_NO_FLOATING_POINT #include +#endif #include /** @@ -224,7 +226,7 @@ static CborError utf8EscapedDump(CborStreamFunction stream, void *out, const voi return err; } -static const char *resolve_indicator(const uint8_t *ptr, const uint8_t *end, int flags) +static const char *resolve_indicator(const CborValue *it, int flags) { static const char indicators[8][3] = { "_0", "_1", "_2", "_3", @@ -236,11 +238,15 @@ static const char *resolve_indicator(const uint8_t *ptr, const uint8_t *end, int uint8_t expected_information; uint64_t value; CborError err; + int offset; + uint8_t val; - if (ptr == end) + if (it->offset == it->parser->end) return NULL; /* CborErrorUnexpectedEOF */ - additional_information = (*ptr & SmallValueMask); + val = it->parser->d->get8(it->parser->d, it->offset); + + additional_information = (val & SmallValueMask); if (additional_information < Value8Bit) return no_indicator; @@ -251,7 +257,9 @@ static const char *resolve_indicator(const uint8_t *ptr, const uint8_t *end, int if ((flags & CborPrettyIndicateOverlongNumbers) == 0) return no_indicator; - err = _cbor_value_extract_number(&ptr, end, &value); + offset = it->offset; + + err = _cbor_value_extract_number(it->parser, &offset, &value); if (err) return NULL; /* CborErrorUnexpectedEOF */ @@ -271,7 +279,7 @@ static const char *resolve_indicator(const uint8_t *ptr, const uint8_t *end, int static const char *get_indicator(const CborValue *it, int flags) { - return resolve_indicator(it->ptr, it->parser->end, flags); + return resolve_indicator(it, flags); } static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue *it, int flags, int recursionsLeft); @@ -322,12 +330,12 @@ static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue err = cbor_value_enter_container(it, &recursed); if (err) { - it->ptr = recursed.ptr; + it->offset = recursed.offset; return err; /* parse error */ } err = container_to_pretty(stream, out, &recursed, type, flags, recursionsLeft - 1); if (err) { - it->ptr = recursed.ptr; + it->offset = recursed.offset; return err; /* parse error */ } err = cbor_value_leave_container(it, &recursed); @@ -386,7 +394,7 @@ static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue while (!err) { if (showingFragments || indicator == NULL) { /* any iteration, except the second for a non-chunked string */ - indicator = resolve_indicator(it->ptr, it->parser->end, flags); + indicator = resolve_indicator(it, flags); } err = _cbor_value_get_string_chunk(it, &ptr, &n, it); @@ -451,7 +459,7 @@ static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue err = stream(out, val ? "true" : "false"); break; } - +#ifndef CBOR_NO_FLOATING_POINT case CborDoubleType: { const char *suffix; double val; @@ -462,12 +470,14 @@ static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue cbor_value_get_float(it, &f); val = f; suffix = flags & CborPrettyNumericEncodingIndicators ? "_2" : "f"; +#ifndef CBOR_NO_HALF_FLOAT_TYPE } else if (false) { uint16_t f16; case CborHalfFloatType: cbor_value_get_half_float(it, &f16); val = decode_half(f16); suffix = flags & CborPrettyNumericEncodingIndicators ? "_1" : "f16"; +#endif } else { cbor_value_get_double(it, &val); suffix = ""; @@ -490,12 +500,11 @@ static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue } break; } - +#endif case CborInvalidType: err = stream(out, "invalid"); if (err) return err; - return CborErrorUnknownType; } if (!err) diff --git a/src/cbortojson.c b/src/cbortojson.c index 0b3c8116..bc070abc 100644 --- a/src/cbortojson.c +++ b/src/cbortojson.c @@ -36,7 +36,9 @@ #include #include +#ifndef CBOR_NO_FLOATING_POINT #include +#endif #include #include #include @@ -401,7 +403,7 @@ static CborError stringify_map_key(char **key, CborValue *it, int flags, CborTyp { (void)flags; /* unused */ (void)type; /* unused */ -#ifdef WITHOUT_OPEN_MEMSTREAM +#ifdef CBOR_WITHOUT_OPEN_MEMSTREAM (void)key; /* unused */ (void)it; /* unused */ return CborErrorJsonNotImplemented; @@ -497,7 +499,7 @@ static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType typ CborValue recursed; err = cbor_value_enter_container(it, &recursed); if (err) { - it->ptr = recursed.ptr; + it->offset = recursed.offset; return err; /* parse error */ } if (fputc(type == CborArrayType ? '[' : '{', out) < 0) @@ -507,7 +509,7 @@ static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType typ array_to_json(out, &recursed, flags, status) : map_to_json(out, &recursed, flags, status); if (err) { - it->ptr = recursed.ptr; + it->offset = recursed.offset; return err; /* parse error */ } @@ -592,7 +594,7 @@ static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType typ return CborErrorIO; break; } - +#ifndef CBOR_NO_FLOATING_POINT case CborDoubleType: { double val; if (false) { @@ -601,12 +603,14 @@ static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType typ status->flags = TypeWasNotNative; cbor_value_get_float(it, &f); val = f; +#ifndef CBOR_NO_HALF_FLOAT_TYPE } else if (false) { uint16_t f16; case CborHalfFloatType: status->flags = TypeWasNotNative; cbor_value_get_half_float(it, &f16); val = decode_half(f16); +#endif } else { cbor_value_get_double(it, &val); } @@ -632,8 +636,10 @@ static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType typ } break; } +#endif case CborInvalidType: + default: return CborErrorUnknownType; } @@ -641,6 +647,7 @@ static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType typ } /** + * \enum CborToJsonFlags * The CborToJsonFlags enum contains flags that control the conversion of CBOR to JSON. * diff --git a/src/cborvalidation.c b/src/cborvalidation.c index bbdabac2..2553a3aa 100644 --- a/src/cborvalidation.c +++ b/src/cborvalidation.c @@ -22,8 +22,12 @@ ** ****************************************************************************/ +#ifndef _BSD_SOURCE #define _BSD_SOURCE 1 +#endif +#ifndef _DEFAULT_SOURCE #define _DEFAULT_SOURCE 1 +#endif #ifndef __STDC_LIMIT_MACROS # define __STDC_LIMIT_MACROS 1 #endif @@ -35,9 +39,9 @@ #include +#include #ifndef CBOR_NO_FLOATING_POINT -# include -# include +#include #endif @@ -290,19 +294,20 @@ static inline CborError validate_simple_type(uint8_t simple_type, int flags) static inline CborError validate_number(const CborValue *it, CborType type, int flags) { CborError err = CborNoError; - const uint8_t *ptr = it->ptr; uint64_t value; + int offset; if ((flags & CborValidateShortestIntegrals) == 0) return err; if (type >= CborHalfFloatType && type <= CborDoubleType) return err; /* checked elsewhere */ - err = _cbor_value_extract_number(&ptr, it->parser->end, &value); + offset = it->offset; + err = _cbor_value_extract_number(it->parser, &offset, &value); if (err) return err; - size_t bytesUsed = (size_t)(ptr - it->ptr - 1); + size_t bytesUsed = (size_t)(offset - it->offset - 1); size_t bytesNeeded = 0; if (value >= Value8Bit) ++bytesNeeded; @@ -435,14 +440,14 @@ static inline CborError validate_floating_point(CborValue *it, CborType type, in static CborError validate_container(CborValue *it, int containerType, int flags, int recursionLeft) { CborError err; - const uint8_t *previous = NULL; - const uint8_t *previous_end = NULL; + int previous = -1; + int previous_end = -1; if (!recursionLeft) return CborErrorNestingTooDeep; while (!cbor_value_at_end(it)) { - const uint8_t *current = cbor_value_get_next_byte(it); + int current = it->offset; if (containerType == CborMapType) { if (flags & CborValidateMapKeysAreString) { @@ -468,34 +473,42 @@ static CborError validate_container(CborValue *it, int containerType, int flags, continue; if (flags & CborValidateMapIsSorted) { - if (previous) { + if (previous != -1) { uint64_t len1, len2; - const uint8_t *ptr; + int offset; /* extract the two lengths */ - ptr = previous; - _cbor_value_extract_number(&ptr, it->parser->end, &len1); - ptr = current; - _cbor_value_extract_number(&ptr, it->parser->end, &len2); + offset = previous; + _cbor_value_extract_number(it->parser, &offset, &len1); + offset = current; + _cbor_value_extract_number(it->parser, &offset, &len2); if (len1 > len2) return CborErrorMapNotSorted; if (len1 == len2) { - size_t bytelen1 = (size_t)(previous_end - previous); - size_t bytelen2 = (size_t)(it->ptr - current); - int r = memcmp(previous, current, bytelen1 <= bytelen2 ? bytelen1 : bytelen2); - - if (r == 0 && bytelen1 != bytelen2) - r = bytelen1 < bytelen2 ? -1 : +1; - if (r > 0) - return CborErrorMapNotSorted; - if (r == 0 && (flags & CborValidateMapKeysAreUnique) == CborValidateMapKeysAreUnique) - return CborErrorMapKeysNotUnique; + int bytelen1 = (previous_end - previous); + int bytelen2 = (it->offset - current); + int i; + + for (i = 0; i < (bytelen1 <= bytelen2 ? bytelen1 : bytelen2); i++) { + int r = it->parser->d->get8(it->parser->d, previous + i) - + it->parser->d->get8(it->parser->d, current + i); + + if (r < 0) { + break; + } + if (r == 0 && bytelen1 != bytelen2) + r = bytelen1 < bytelen2 ? -1 : +1; + if (r > 0) + return CborErrorMapNotSorted; + if (r == 0 && (flags & CborValidateMapKeysAreUnique) == CborValidateMapKeysAreUnique) + return CborErrorMapKeysNotUnique; + } } } previous = current; - previous_end = it->ptr; + previous_end = it->offset; } /* map: that was the key, so get the value */ @@ -529,7 +542,7 @@ static CborError validate_value(CborValue *it, int flags, int recursionLeft) if (!err) err = validate_container(&recursed, type, flags, recursionLeft - 1); if (err) { - it->ptr = recursed.ptr; + it->offset = recursed.offset; return err; } err = cbor_value_leave_container(it, &recursed); @@ -651,7 +664,7 @@ CborError cbor_value_validate(const CborValue *it, int flags) CborError err = validate_value(&value, flags, CBOR_PARSER_MAX_RECURSIONS); if (err) return err; - if (flags & CborValidateCompleteData && it->ptr != it->parser->end) + if (flags & CborValidateCompleteData && it->offset != it->parser->end) return CborErrorGarbageAtEnd; return CborNoError; } diff --git a/src/compilersupport_p.h b/src/compilersupport_p.h index 113e963d..d21a86bc 100644 --- a/src/compilersupport_p.h +++ b/src/compilersupport_p.h @@ -27,6 +27,10 @@ #include "cbor.h" +#ifdef __cplusplus +extern "C" { +#endif + #ifndef _BSD_SOURCE # define _BSD_SOURCE #endif @@ -37,7 +41,9 @@ # include #endif #include +#ifndef CBOR_NO_FLOATING_TYPE #include +#endif #include #include #include @@ -53,7 +59,7 @@ #if __STDC_VERSION__ >= 201112L || __cplusplus >= 201103L || __cpp_static_assert >= 200410 # define cbor_static_assert(x) static_assert(x, #x) #elif !defined(__cplusplus) && defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 406) && (__STDC_VERSION__ > 199901L) -# define cbor_static_assert(x) _Static_assert(x, #x) +# define cbor_static_assert(x) static_assert(x, #x) #else # define cbor_static_assert(x) ((void)sizeof(char[2*!!(x) - 1])) #endif @@ -199,6 +205,7 @@ static inline bool add_check_overflow(size_t v1, size_t v2, size_t *r) #endif } +#ifndef CBOR_NO_HALF_FLOAT_TYPE static inline unsigned short encode_half(double val) { #ifdef __F16C__ @@ -251,5 +258,11 @@ static inline double decode_half(unsigned short half) #endif } +#endif + +#ifdef __cplusplus +} +#endif + #endif /* COMPILERSUPPORT_H */ diff --git a/src/open_memstream.c b/src/open_memstream.c index e7ceac4d..e9d54494 100644 --- a/src/open_memstream.c +++ b/src/open_memstream.c @@ -26,6 +26,8 @@ #define _DEFAULT_SOURCE 1 #define _GNU_SOURCE 1 +#ifndef CBOR_WITHOUT_OPEN_MEMSTREAM + #include #include #include @@ -112,3 +114,4 @@ FILE *open_memstream(char **bufptr, size_t *lenptr) #endif } +#endif diff --git a/src/src.pri b/src/src.pri index 01887aa4..14228d0e 100644 --- a/src/src.pri +++ b/src/src.pri @@ -7,6 +7,8 @@ SOURCES += \ $$PWD/cborpretty.c \ $$PWD/cbortojson.c \ $$PWD/cborvalidation.c \ + $$PWD/cbor_buf_reader.c \ + $$PWD/cbor_buf_writer.c HEADERS += $$PWD/cbor.h $$PWD/tinycbor-version.h diff --git a/tests/cpp/tst_cpp.cpp b/tests/cpp/tst_cpp.cpp index dcf3d1fc..e2219065 100644 --- a/tests/cpp/tst_cpp.cpp +++ b/tests/cpp/tst_cpp.cpp @@ -22,6 +22,8 @@ ** ****************************************************************************/ +#include "../../src/cbor_buf_writer.c" +#include "../../src/cbor_buf_reader.c" #include "../../src/cborencoder.c" #include "../../src/cborerrorstrings.c" #include "../../src/cborparser.c" diff --git a/tests/parser/tst_parser.cpp b/tests/parser/tst_parser.cpp index 6dd4a353..4a508f68 100644 --- a/tests/parser/tst_parser.cpp +++ b/tests/parser/tst_parser.cpp @@ -25,6 +25,7 @@ #define _XOPEN_SOURCE 700 #include #include "cbor.h" +#include "cbor_buf_reader.h" #include #include @@ -122,7 +123,7 @@ CborError parseOne(CborValue *it, QString *parsed) CborError parseOneChunk(CborValue *it, QString *parsed) { - CborError err; + CborError err = CborNoError; CborType ourType = cbor_value_get_type(it); if (ourType == CborByteStringType) { const uint8_t *bytes; @@ -223,7 +224,7 @@ void compareOne_real(const QByteArray &data, const QString &expected, int line, QCOMPARE(err2, err); // check that we consumed everything - QCOMPARE((void*)cbor_value_get_next_byte(&first), (void*)data.constEnd()); + QCOMPARE(cbor_value_at_end(&first), true); compareFailed = false; } @@ -963,7 +964,7 @@ static void chunkedStringTest(const QByteArray &data, const QString &concatenate err = cbor_value_leave_container(&first, &value); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); - QCOMPARE((void*)cbor_value_get_next_byte(&first), (void*)data.constEnd()); + QCOMPARE(cbor_value_at_end(&first), true); } void tst_Parser::chunkedString() @@ -2041,7 +2042,7 @@ void tst_Parser::endPointer() err = parseOne(&first, &decoded); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); - QCOMPARE(int(first.ptr - reinterpret_cast(data.constBegin())), offset); + QCOMPARE(first.offset, offset); } void tst_Parser::recursionLimit_data() diff --git a/tests/tojson/tst_tojson.cpp b/tests/tojson/tst_tojson.cpp index e045cf30..53f827b0 100644 --- a/tests/tojson/tst_tojson.cpp +++ b/tests/tojson/tst_tojson.cpp @@ -225,7 +225,7 @@ void compareOne_real(const QByteArray &data, const QString &expected, int flags, QCOMPARE(decoded, expected); // check that we consumed everything - QCOMPARE((void*)first.ptr, (void*)data.constEnd()); + QCOMPARE(cbor_value_at_end(&first), true); compareFailed = false; } @@ -665,7 +665,7 @@ void compareMetaData(QByteArray data, const QString &expected, int otherFlags = "\"; decoded stream:\n" + decoded.toLatin1()); // check that we consumed everything - QCOMPARE((void*)first.ptr, (void*)data.constEnd()); + QCOMPARE(cbor_value_at_end(&first), true); } QVERIFY(decoded.startsWith("{\"v\":")); diff --git a/tools/Makefile b/tools/Makefile index fed6108e..2ed8969f 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -6,7 +6,7 @@ all: ../bin ../bin/cbordump ../bin: @-mkdir ../bin -../bin/cbordump: cbordump.o cborparser.o cborparser_dup_string.o cbortojson.o cborerrorstrings.o cborpretty.o +../bin/cbordump: cbordump.o cborparser.o cborparser_dup_string.o cbortojson.o cborerrorstrings.o cborpretty.o cbor_buf_reader.o cbor_buf_writer.o $(CC) -o $@ $^ $(RM) $^ diff --git a/tools/cbordump/cbordump.c b/tools/cbordump/cbordump.c index e139f7fd..a5c8d9f4 100644 --- a/tools/cbordump/cbordump.c +++ b/tools/cbordump/cbordump.c @@ -25,6 +25,7 @@ #define _POSIX_C_SOURCE 200809L #include "cbor.h" #include "cborjson.h" +#include "cbor_buf_reader.h" #include #include #include @@ -79,7 +80,7 @@ void dumpFile(FILE *in, const char *fname, bool printJosn, int flags) if (!err) puts(""); } - if (!err && value.ptr != buffer + buflen) + if (!err && value.offset != (int)buflen) err = CborErrorGarbageAtEnd; if (err) printerror(err, fname); diff --git a/tools/json2cbor/json2cbor.c b/tools/json2cbor/json2cbor.c index b9f5a846..64395017 100644 --- a/tools/json2cbor/json2cbor.c +++ b/tools/json2cbor/json2cbor.c @@ -484,7 +484,7 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - fwrite(buffer, 1, encoder.data.ptr - buffer, stdout); + fwrite(buffer, 1, cb.ptr - buffer, stdout); free(buffer); return EXIT_SUCCESS; }