From 423f94bedfa3129b7ae6e58cf2e3fd663f2e1ad8 Mon Sep 17 00:00:00 2001 From: Vipul Rahane Date: Tue, 14 Nov 2017 17:48:55 -0800 Subject: [PATCH] Bring tinycbor up to date with mynewt tinycbor - Removing cborencoder_close_container_checked.c since cborencoder_close_container() checks the number of elements now. - Add container_size for the container - cbor_encoder_close_container(): look at isMap flag to determine container_size for comparison - iterate_string_chunks(): fixing NULL compare at the end of string and moving it out of the iterate_string_chunks(). This is to avoid buffer specific parser calls in the function - cbor_value_get_next_byte() is removed in mynewt version of tinycbor, so, we track offsets of the buffer which can be used for comparison in the parser tests instead of calculating the offset - Move cbor_encoder_get_extra_bytes_needed() and cbor_encoder_get_buffer_size() to be part of cbor_buf_writer APIs - Add bytes_needed field to the buf writer - Adding encoder writer and parser reader as part of the encoder and parser structure. This is to make the encoder and parser use new function of encoder_writer and decoder_reader without breaking backwards compatibility. - Making the old API use flat buffers by default - Adding APIs for initializing encoder and parser with custom writer and reader - Make the default writer and reader conditional based on NO_DFLT_READER/WRITER define. This is because we want a default reader/writer to avoid API changes. - Move enums to cbor_defs.h - Use it->offset instead of it->ptr to track buffer offsets - Update resolve_indicator() static api paramaters to use cbor value and access offsets instead of taking pointers as input parameters - In validate_container() do a byte by byte comparison instead of memcmp since we no longer have access to teh buffer directly Also, use offets instead of pointers to validate sorted maps - Added a new dfine for conditionally compiling in float support (NO_FLOAT_SUPPORT). This is because we want the float support to be compiled in by default. - Use static_assert macro instead of Static_assert. Changed to avoid build failures. - Add api to get string chunk, this is a callback which can be used by buffer implementations to grab a string that is divided in chunks which spans across multiple chained buffers --- Makefile | 18 +- Makefile.nmake | 14 +- src/cbor.h | 273 ++-------------------- src/cbor_buf_reader.c | 125 ++++++++++ src/cbor_buf_reader.h | 47 ++++ src/cbor_buf_writer.c | 99 ++++++++ src/cbor_buf_writer.h | 55 +++++ src/cbor_cnt_writer.h | 63 +++++ src/cbor_decoder_reader.h | 60 +++++ src/cbor_defs.h | 253 ++++++++++++++++++++ src/cbor_encoder_writer.h | 45 ++++ src/cborencoder.c | 84 ++++--- src/cborencoder_close_container_checked.c | 77 ------ src/cborerrorstrings.c | 1 + src/cborinternal_p.h | 2 +- src/cborparser.c | 247 ++++++++++++-------- src/cborparser_dup_string.c | 2 +- src/cborpretty.c | 29 ++- src/cbortojson.c | 10 +- src/cborvalidation.c | 65 +++--- src/compilersupport_p.h | 10 +- src/open_memstream.c | 3 + src/src.pri | 7 +- tests/cpp/tst_cpp.cpp | 2 + tests/encoder/tst_encoder.cpp | 29 ++- tests/parser/tst_parser.cpp | 21 +- tests/tojson/tst_tojson.cpp | 7 +- tools/Makefile | 2 +- tools/cbordump/cbordump.c | 11 +- tools/json2cbor/json2cbor.c | 8 +- 30 files changed, 1122 insertions(+), 547 deletions(-) create mode 100644 src/cbor_buf_reader.c create mode 100644 src/cbor_buf_reader.h create mode 100644 src/cbor_buf_writer.c create mode 100644 src/cbor_buf_writer.h create mode 100644 src/cbor_cnt_writer.h create mode 100644 src/cbor_decoder_reader.h create mode 100644 src/cbor_defs.h create mode 100644 src/cbor_encoder_writer.h delete mode 100644 src/cborencoder_close_container_checked.c diff --git a/Makefile b/Makefile index f3a2a712..98c9a59a 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ prefix = /usr/local exec_prefix = $(prefix) bindir = $(exec_prefix)/bin libdir = $(exec_prefix)/lib -includedir = $(prefix)/include +includedir = $(prefix)/src pkgconfigdir = $(libdir)/pkgconfig CFLAGS = -Wall -Wextra @@ -20,17 +20,23 @@ 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 \ + src/cbor_defs.h TINYCBOR_SOURCES = \ src/cborerrorstrings.c \ src/cborencoder.c \ - src/cborencoder_close_container_checked.c \ src/cborparser.c \ src/cborparser_dup_string.c \ src/cborpretty.c \ 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 @@ -55,7 +61,7 @@ BINLIBRARY=lib/libtinycbor.a INSTALL_TARGETS += $(libdir)/libtinycbor.a endif INSTALL_TARGETS += $(pkgconfigdir)/tinycbor.pc -INSTALL_TARGETS += $(TINYCBOR_HEADERS:src/%=$(includedir)/tinycbor/%) +INSTALL_TARGETS += $(TINYCBOR_HEADERS:./%=$(includedir)/%) # setup VPATH MAKEFILE := $(lastword $(MAKEFILE_LIST)) @@ -170,7 +176,7 @@ $(DESTDIR)$(bindir)/%: bin/% $(DESTDIR)$(pkgconfigdir)/%: % $(INSTALL) -d $(@D) $(INSTALL_DATA) $< $@ -$(DESTDIR)$(includedir)/tinycbor/%: src/% +$(DESTDIR)$(includedir)/%: src/% $(INSTALL) -d $(@D) $(INSTALL_DATA) $< $@ @@ -215,7 +221,7 @@ tag: distcheck .PHONY: docs dist distcheck release .SECONDARY: -cflags := $(CPPFLAGS) -I$(SRCDIR)src +cflags := $(CPPFLAGS) -I$(SRCDIR)/src cflags += -DTINYCBOR_VERSION_SUFFIX=\"$(DIRTYSRC)\" cflags += -std=c99 $(CFLAGS) %.o: %.c diff --git a/Makefile.nmake b/Makefile.nmake index defc30aa..7be37d73 100644 --- a/Makefile.nmake +++ b/Makefile.nmake @@ -1,24 +1,26 @@ CFLAGS = -W3 -TINYCBOR_HEADERS = src\cbor.h src\cborjson.h +TINYCBOR_HEADERS = src TINYCBOR_SOURCES = \ src\cborerrorstrings.c \ src\cborencoder.c \ - src\cborencoder_close_container_checked.c \ src\cborparser.c \ 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 \ - src\cborencoder_close_container_checked.obj \ src\cborparser.obj \ 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 @@ -43,5 +45,5 @@ tag: @perl maketag.pl {src\}.c{src\}.obj: - $(CC) -nologo $(CFLAGS) -Isrc -DTINYCBOR_VERSION_SUFFIX="" -c -Fo$@ $< + $(CC) -nologo $(CFLAGS) -I$(TINYCBOR_HEADERS) -DTINYCBOR_VERSION_SUFFIX="" -c -Fo$@ $< diff --git a/src/cbor.h b/src/cbor.h index 9fc78074..ae87ed68 100644 --- a/src/cbor.h +++ b/src/cbor.h @@ -34,6 +34,9 @@ #include #include +#include "cbor_buf_writer.h" +#include "cbor_buf_reader.h" +#include "cbor_defs.h" #include "tinycbor-version.h" #define TINYCBOR_VERSION ((TINYCBOR_VERSION_MAJOR << 16) | (TINYCBOR_VERSION_MINOR << 8) | TINYCBOR_VERSION_PATCH) @@ -44,179 +47,27 @@ extern "C" { #include #endif -#ifndef SIZE_MAX -/* Some systems fail to define SIZE_MAX in , even though C99 requires it... - * Conversion from signed to unsigned is defined in 6.3.1.3 (Signed and unsigned integers) p2, - * which says: "the value is converted by repeatedly adding or subtracting one more than the - * maximum value that can be represented in the new type until the value is in the range of the - * new type." - * So -1 gets converted to size_t by adding SIZE_MAX + 1, which results in SIZE_MAX. - */ -# define SIZE_MAX ((size_t)-1) -#endif - -#ifndef CBOR_API -# define CBOR_API -#endif -#ifndef CBOR_PRIVATE_API -# define CBOR_PRIVATE_API -#endif -#ifndef CBOR_INLINE_API -# if defined(__cplusplus) -# define CBOR_INLINE inline -# define CBOR_INLINE_API inline -# else -# define CBOR_INLINE_API static CBOR_INLINE -# if defined(_MSC_VER) -# define CBOR_INLINE __inline -# elif defined(__GNUC__) -# define CBOR_INLINE __inline__ -# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L -# define CBOR_INLINE inline -# else -# define CBOR_INLINE -# endif -# endif -#endif - -typedef enum CborType { - CborIntegerType = 0x00, - CborByteStringType = 0x40, - CborTextStringType = 0x60, - CborArrayType = 0x80, - CborMapType = 0xa0, - CborTagType = 0xc0, - CborSimpleType = 0xe0, - CborBooleanType = 0xf5, - CborNullType = 0xf6, - CborUndefinedType = 0xf7, - CborHalfFloatType = 0xf9, - CborFloatType = 0xfa, - CborDoubleType = 0xfb, - - CborInvalidType = 0xff /* equivalent to the break byte, so it will never be used */ -} CborType; - -typedef uint64_t CborTag; -typedef enum CborKnownTags { - CborDateTimeStringTag = 0, - CborUnixTime_tTag = 1, - CborPositiveBignumTag = 2, - CborNegativeBignumTag = 3, - CborDecimalTag = 4, - CborBigfloatTag = 5, - CborCOSE_Encrypt0Tag = 16, - CborCOSE_Mac0Tag = 17, - CborCOSE_Sign1Tag = 18, - CborExpectedBase64urlTag = 21, - CborExpectedBase64Tag = 22, - CborExpectedBase16Tag = 23, - CborEncodedCborTag = 24, - CborUrlTag = 32, - CborBase64urlTag = 33, - CborBase64Tag = 34, - CborRegularExpressionTag = 35, - CborMimeMessageTag = 36, - CborCOSE_EncryptTag = 96, - CborCOSE_MacTag = 97, - CborCOSE_SignTag = 98, - CborSignatureTag = 55799 -} CborKnownTags; - -/* #define the constants so we can check with #ifdef */ -#define CborDateTimeStringTag CborDateTimeStringTag -#define CborUnixTime_tTag CborUnixTime_tTag -#define CborPositiveBignumTag CborPositiveBignumTag -#define CborNegativeBignumTag CborNegativeBignumTag -#define CborDecimalTag CborDecimalTag -#define CborBigfloatTag CborBigfloatTag -#define CborCOSE_Encrypt0Tag CborCOSE_Encrypt0Tag -#define CborCOSE_Mac0Tag CborCOSE_Mac0Tag -#define CborCOSE_Sign1Tag CborCOSE_Sign1Tag -#define CborExpectedBase64urlTag CborExpectedBase64urlTag -#define CborExpectedBase64Tag CborExpectedBase64Tag -#define CborExpectedBase16Tag CborExpectedBase16Tag -#define CborEncodedCborTag CborEncodedCborTag -#define CborUrlTag CborUrlTag -#define CborBase64urlTag CborBase64urlTag -#define CborBase64Tag CborBase64Tag -#define CborRegularExpressionTag CborRegularExpressionTag -#define CborMimeMessageTag CborMimeMessageTag -#define CborCOSE_EncryptTag CborCOSE_EncryptTag -#define CborCOSE_MacTag CborCOSE_MacTag -#define CborCOSE_SignTag CborCOSE_SignTag -#define CborSignatureTag CborSignatureTag - -/* Error API */ - -typedef enum CborError { - CborNoError = 0, - - /* errors in all modes */ - CborUnknownError, - CborErrorUnknownLength, /* request for length in array, map, or string with indeterminate length */ - CborErrorAdvancePastEOF, - CborErrorIO, - - /* parser errors streaming errors */ - CborErrorGarbageAtEnd = 256, - CborErrorUnexpectedEOF, - CborErrorUnexpectedBreak, - CborErrorUnknownType, /* can only heppen in major type 7 */ - CborErrorIllegalType, /* type not allowed here */ - CborErrorIllegalNumber, - CborErrorIllegalSimpleType, /* types of value less than 32 encoded in two bytes */ - - /* parser errors in strict mode parsing only */ - CborErrorUnknownSimpleType = 512, - CborErrorUnknownTag, - CborErrorInappropriateTagForType, - CborErrorDuplicateObjectKeys, - CborErrorInvalidUtf8TextString, - CborErrorExcludedType, - CborErrorExcludedValue, - CborErrorImproperValue, - CborErrorOverlongEncoding, - CborErrorMapKeyNotString, - CborErrorMapNotSorted, - CborErrorMapKeysNotUnique, - - /* encoder errors */ - CborErrorTooManyItems = 768, - CborErrorTooFewItems, - - /* internal implementation errors */ - CborErrorDataTooLarge = 1024, - CborErrorNestingTooDeep, - CborErrorUnsupportedType, - - /* errors in converting to JSON */ - CborErrorJsonObjectKeyIsAggregate, - CborErrorJsonObjectKeyNotString, - CborErrorJsonNotImplemented, - - CborErrorOutOfMemory = (int) (~0U / 2 + 1), - CborErrorInternalError = (int) (~0U / 2) /* INT_MAX on two's complement machines */ -} CborError; - 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 NO_DFLT_WRITER + struct cbor_buf_writer wr; +#endif size_t added; + size_t container_size; int flags; }; -typedef struct CborEncoder CborEncoder; -static const size_t CborIndefiniteLength = SIZE_MAX; +typedef struct CborEncoder CborEncoder; +#ifndef 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 +78,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,35 +99,14 @@ 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 -{ - CborIteratorFlag_IntegerValueTooLarge = 0x01, - CborIteratorFlag_NegativeInteger = 0x02, - CborIteratorFlag_IteratingStringChunks = 0x02, - CborIteratorFlag_UnknownLength = 0x04, - CborIteratorFlag_ContainerIsMap = 0x20 -}; - struct CborParser { - const uint8_t *end; +#ifndef NO_DFLT_READER + struct cbor_buf_reader br; +#endif + struct cbor_decoder_reader *d; + int end; int flags; }; typedef struct CborParser CborParser; @@ -283,22 +114,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 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) @@ -529,65 +362,10 @@ CBOR_INLINE_API CborError cbor_value_get_double(const CborValue *value, double * } /* Validation API */ - -enum CborValidationFlags { - /* Bit mapping: - * bits 0-7 (8 bits): canonical format - * bits 8-11 (4 bits): canonical format & strict mode - * bits 12-20 (8 bits): strict mode - * bits 21-31 (10 bits): other - */ - - CborValidateShortestIntegrals = 0x0001, - CborValidateShortestFloatingPoint = 0x0002, - CborValidateShortestNumbers = CborValidateShortestIntegrals | CborValidateShortestFloatingPoint, - CborValidateNoIndeterminateLength = 0x0100, - CborValidateMapIsSorted = 0x0200 | CborValidateNoIndeterminateLength, - - CborValidateCanonicalFormat = 0x0fff, - - CborValidateMapKeysAreUnique = 0x1000 | CborValidateMapIsSorted, - CborValidateTagUse = 0x2000, - CborValidateUtf8 = 0x4000, - - CborValidateStrictMode = 0xfff00, - - CborValidateMapKeysAreString = 0x100000, - CborValidateNoUndefined = 0x200000, - CborValidateNoTags = 0x400000, - CborValidateFiniteFloatingPoint = 0x800000, - /* unused = 0x1000000, */ - /* unused = 0x2000000, */ - - CborValidateNoUnknownSimpleTypesSA = 0x4000000, - CborValidateNoUnknownSimpleTypes = 0x8000000 | CborValidateNoUnknownSimpleTypesSA, - CborValidateNoUnknownTagsSA = 0x10000000, - CborValidateNoUnknownTagsSR = 0x20000000 | CborValidateNoUnknownTagsSA, - CborValidateNoUnknownTags = 0x40000000 | CborValidateNoUnknownTagsSR, - - CborValidateCompleteData = (int)0x80000000, - - CborValidateStrictest = (int)~0U, - CborValidateBasic = 0 -}; - CBOR_API CborError cbor_value_validate(const CborValue *it, int flags); /* Human-readable (dump) API */ -enum CborPrettyFlags { - CborPrettyNumericEncodingIndicators = 0x01, - CborPrettyTextualEncodingIndicators = 0, - - CborPrettyIndicateIndetermineLength = 0x02, - CborPrettyIndicateOverlongNumbers = 0x04, - - CborPrettyShowStringFragments = 0x100, - CborPrettyMergeStringFragments = 0, - - CborPrettyDefaultFlags = CborPrettyIndicateIndetermineLength -}; - typedef CborError (*CborStreamFunction)(void *token, const char *fmt, ...) #ifdef __GNUC__ __attribute__((__format__(printf, 2, 3))) @@ -612,4 +390,3 @@ CBOR_INLINE_API CborError cbor_value_to_pretty(FILE *out, const CborValue *value #endif #endif /* CBOR_H */ - diff --git a/src/cbor_buf_reader.c b/src/cbor_buf_reader.c new file mode 100644 index 00000000..54ec0679 --- /dev/null +++ b/src/cbor_buf_reader.c @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** 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" + +CBOR_INLINE_API uint16_t get16(const uint8_t *ptr) +{ + uint16_t result; + memcpy(&result, ptr, sizeof(result)); + return cbor_ntohs(result); +} + +CBOR_INLINE_API uint32_t get32(const uint8_t *ptr) +{ + uint32_t result; + memcpy(&result, ptr, sizeof(result)); + return cbor_ntohl(result); +} + +CBOR_INLINE_API uint64_t get64(const uint8_t *ptr) +{ + uint64_t result; + memcpy(&result, ptr, sizeof(result)); + return cbor_ntohll(result); +} + +CBOR_INLINE_API uintptr_t get_string_chunk(const uint8_t *ptr) +{ + return (uintptr_t)ptr; +} + +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]; +} + +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); +} + +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; +} + +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_defs.h b/src/cbor_defs.h new file mode 100644 index 00000000..a4975c6a --- /dev/null +++ b/src/cbor_defs.h @@ -0,0 +1,253 @@ +/**************************************************************************** +** +** 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_DEFS_H +#define CBOR_DEFS_H + +#include +#include +#include + +#ifndef SIZE_MAX +/* Some systems fail to define SIZE_MAX in , even though C99 requires it... + * Conversion from signed to unsigned is defined in 6.3.1.3 (Signed and unsigned integers) p2, + * which says: "the value is converted by repeatedly adding or subtracting one more than the + * maximum value that can be represented in the new type until the value is in the range of the + * new type." + * So -1 gets converted to size_t by adding SIZE_MAX + 1, which results in SIZE_MAX. + */ +# define SIZE_MAX ((size_t)-1) +#endif + +#ifndef CBOR_API +# define CBOR_API +#endif +#ifndef CBOR_PRIVATE_API +# define CBOR_PRIVATE_API +#endif +#ifndef CBOR_INLINE_API +# if defined(__cplusplus) +# define CBOR_INLINE inline +# define CBOR_INLINE_API inline +# else +# define CBOR_INLINE_API static CBOR_INLINE +# if defined(_MSC_VER) +# define CBOR_INLINE __inline +# elif defined(__GNUC__) +# define CBOR_INLINE __inline__ +# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +# define CBOR_INLINE inline +# else +# define CBOR_INLINE +# endif +# endif +#endif + +typedef enum CborType { + CborIntegerType = 0x00, + CborByteStringType = 0x40, + CborTextStringType = 0x60, + CborArrayType = 0x80, + CborMapType = 0xa0, + CborTagType = 0xc0, + CborSimpleType = 0xe0, + CborBooleanType = 0xf5, + CborNullType = 0xf6, + CborUndefinedType = 0xf7, + CborHalfFloatType = 0xf9, + CborFloatType = 0xfa, + CborDoubleType = 0xfb, + + CborInvalidType = 0xff /* equivalent to the break byte, so it will never be used */ +} CborType; + +typedef uint64_t CborTag; + +typedef enum CborKnownTags { + CborDateTimeStringTag = 0, /* RFC 3339 format: YYYY-MM-DD hh:mm:ss+zzzz */ + CborUnixTime_tTag = 1, + CborPositiveBignumTag = 2, + CborNegativeBignumTag = 3, + CborDecimalTag = 4, + CborBigfloatTag = 5, + CborExpectedBase64urlTag = 21, + CborExpectedBase64Tag = 22, + CborExpectedBase16Tag = 23, + CborUriTag = 32, + CborBase64urlTag = 33, + CborBase64Tag = 34, + CborRegularExpressionTag = 35, + CborMimeMessageTag = 36, /* RFC 2045-2047 */ + CborSignatureTag = 55799 +} CborKnownTags; + +/* #define the constants so we can check with #ifdef */ +#define CborDateTimeStringTag CborDateTimeStringTag +#define CborUnixTime_tTag CborUnixTime_tTag +#define CborPositiveBignumTag CborPositiveBignumTag +#define CborNegativeBignumTag CborNegativeBignumTag +#define CborDecimalTag CborDecimalTag +#define CborBigfloatTag CborBigfloatTag +#define CborCOSE_Encrypt0Tag CborCOSE_Encrypt0Tag +#define CborCOSE_Mac0Tag CborCOSE_Mac0Tag +#define CborCOSE_Sign1Tag CborCOSE_Sign1Tag +#define CborExpectedBase64urlTag CborExpectedBase64urlTag +#define CborExpectedBase64Tag CborExpectedBase64Tag +#define CborExpectedBase16Tag CborExpectedBase16Tag +#define CborEncodedCborTag CborEncodedCborTag +#define CborUrlTag CborUrlTag +#define CborBase64urlTag CborBase64urlTag +#define CborBase64Tag CborBase64Tag +#define CborRegularExpressionTag CborRegularExpressionTag +#define CborMimeMessageTag CborMimeMessageTag +#define CborCOSE_EncryptTag CborCOSE_EncryptTag +#define CborCOSE_MacTag CborCOSE_MacTag +#define CborCOSE_SignTag CborCOSE_SignTag +#define CborSignatureTag CborSignatureTag + +/* Error API */ + +typedef enum CborError { + CborNoError = 0, + + /* errors in all modes */ + CborUnknownError, + CborErrorUnknownLength, /* request for length in array, map, or string with indeterminate length */ + CborErrorAdvancePastEOF, + CborErrorIO, + + /* parser errors streaming errors */ + CborErrorGarbageAtEnd = 256, + CborErrorUnexpectedEOF, + CborErrorUnexpectedBreak, + CborErrorUnknownType, /* can only heppen in major type 7 */ + CborErrorIllegalType, /* type not allowed here */ + CborErrorIllegalNumber, + CborErrorIllegalSimpleType, /* types of value less than 32 encoded in two bytes */ + + /* parser errors in strict mode parsing only */ + CborErrorUnknownSimpleType = 512, + CborErrorUnknownTag, + CborErrorInappropriateTagForType, + CborErrorDuplicateObjectKeys, + CborErrorInvalidUtf8TextString, + CborErrorExcludedType, + CborErrorExcludedValue, + CborErrorImproperValue, + CborErrorOverlongEncoding, + CborErrorMapKeyNotString, + CborErrorMapNotSorted, + CborErrorMapKeysNotUnique, + + /* encoder errors */ + CborErrorTooManyItems = 768, + CborErrorTooFewItems, + + /* internal implementation errors */ + CborErrorDataTooLarge = 1024, + CborErrorNestingTooDeep, + CborErrorUnsupportedType, + + /* errors in converting to JSON */ + CborErrorJsonObjectKeyIsAggregate, + CborErrorJsonObjectKeyNotString, + CborErrorJsonNotImplemented, + + CborErrorOutOfMemory = (int) (~0U / 2 + 1), + CborErrorInternalError = (int) (~0U / 2) /* INT_MAX on two's complement machines */ +} CborError; + +/* Parser Flags */ + +enum CborParserIteratorFlags +{ + CborIteratorFlag_IntegerValueTooLarge = 0x01, + CborIteratorFlag_NegativeInteger = 0x02, + CborIteratorFlag_IteratingStringChunks = 0x02, + CborIteratorFlag_UnknownLength = 0x04, + CborIteratorFlag_ContainerIsMap = 0x20 +}; + +enum CborValidationFlags { + /* Bit mapping: + * bits 0-7 (8 bits): canonical format + * bits 8-11 (4 bits): canonical format & strict mode + * bits 12-20 (8 bits): strict mode + * bits 21-31 (10 bits): other + */ + + CborValidateShortestIntegrals = 0x0001, + CborValidateShortestFloatingPoint = 0x0002, + CborValidateShortestNumbers = CborValidateShortestIntegrals | CborValidateShortestFloatingPoint, + CborValidateNoIndeterminateLength = 0x0100, + CborValidateMapIsSorted = 0x0200 | CborValidateNoIndeterminateLength, + + CborValidateCanonicalFormat = 0x0fff, + + CborValidateMapKeysAreUnique = 0x1000 | CborValidateMapIsSorted, + CborValidateTagUse = 0x2000, + CborValidateUtf8 = 0x4000, + + CborValidateStrictMode = 0xfff00, + + CborValidateMapKeysAreString = 0x100000, + CborValidateNoUndefined = 0x200000, + CborValidateNoTags = 0x400000, + CborValidateFiniteFloatingPoint = 0x800000, + /* unused = 0x1000000, */ + /* unused = 0x2000000, */ + + CborValidateNoUnknownSimpleTypesSA = 0x4000000, + CborValidateNoUnknownSimpleTypes = 0x8000000 | CborValidateNoUnknownSimpleTypesSA, + CborValidateNoUnknownTagsSA = 0x10000000, + CborValidateNoUnknownTagsSR = 0x20000000 | CborValidateNoUnknownTagsSA, + CborValidateNoUnknownTags = 0x40000000 | CborValidateNoUnknownTagsSR, + + CborValidateCompleteData = (int)0x80000000, + + CborValidateStrictest = (int)~0U, + CborValidateBasic = 0 +}; + +static const size_t CborIndefiniteLength = SIZE_MAX; + +/* The following API requires a hosted C implementation (uses FILE*) */ +#if !defined(__STDC_HOSTED__) || __STDC_HOSTED__-0 == 1 + +enum CborPrettyFlags { + CborPrettyNumericEncodingIndicators = 0x01, + CborPrettyTextualEncodingIndicators = 0, + + CborPrettyIndicateIndetermineLength = 0x02, + CborPrettyIndicateOverlongNumbers = 0x04, + + CborPrettyShowStringFragments = 0x100, + CborPrettyMergeStringFragments = 0, + + CborPrettyDefaultFlags = CborPrettyIndicateIndetermineLength +}; + +#endif /* __STDC_HOSTED__ check */ + +#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 a60e8930..de66cad6 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 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,33 @@ */ 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->added = 0; encoder->flags = flags; + encoder->container_size = 0; } + +#ifndef NO_FLOAT_SUPPORT 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 +243,13 @@ static inline bool isOomError(CborError err) return true; } +#ifndef NO_FLOAT_SUPPORT 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 +257,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) @@ -365,6 +356,7 @@ CborError cbor_encode_simple_value(CborEncoder *encoder, uint8_t value) return encode_number(encoder, value, SimpleTypesType << MajorTypeShift); } +#ifndef NO_FLOAT_SUPPORT /** * 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 @@ -392,6 +384,7 @@ CborError cbor_encode_floating_point(CborEncoder *encoder, CborType fpType, cons ++encoder->added; return append_to_buffer(encoder, buf, size + 1); } +#endif /** * Appends the CBOR tag \a tag to the CBOR stream provided by \a encoder. @@ -452,10 +445,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; ++encoder->added; container->added = 0; + container->container_size = length; cbor_static_assert(((MapType << MajorTypeShift) & CborIteratorFlag_ContainerIsMap) == CborIteratorFlag_ContainerIsMap); cbor_static_assert(((ArrayType << MajorTypeShift) & CborIteratorFlag_ContainerIsMap) == 0); @@ -528,16 +521,21 @@ 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; - if (containerEncoder->flags & CborIteratorFlag_UnknownLength) + size_t container_size; + + encoder->writer = containerEncoder->writer; + + if (containerEncoder->flags & CborIteratorFlag_UnknownLength) { return append_byte_to_buffer(encoder, BreakByte); - if (!encoder->end) - return CborErrorOutOfMemory; /* keep the state */ - return CborNoError; + } else { + container_size = containerEncoder->container_size; + if (containerEncoder->flags & CborIteratorFlag_ContainerIsMap) { + container_size = containerEncoder->container_size * 2; + } + + return container_size == containerEncoder->added ? CborNoError : + container_size < containerEncoder->added ? CborErrorTooManyItems : CborErrorTooFewItems; + } } /** diff --git a/src/cborencoder_close_container_checked.c b/src/cborencoder_close_container_checked.c deleted file mode 100644 index 6a936bd5..00000000 --- a/src/cborencoder_close_container_checked.c +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** -** -** 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. -** -****************************************************************************/ - -#define _BSD_SOURCE 1 -#define _DEFAULT_SOURCE 1 -#ifndef __STDC_LIMIT_MACROS -# define __STDC_LIMIT_MACROS 1 -#endif - -#include "cbor.h" -#include "cborinternal_p.h" -#include "compilersupport_p.h" - -/** - * \addtogroup CborEncoding - * @{ - */ - -/** - * - * Closes the CBOR container (array or map) provided by \a containerEncoder and - * updates the CBOR stream provided by \a encoder. Both parameters must be the - * same as were passed to cbor_encoder_create_array() or - * cbor_encoder_create_map(). - * - * Unlike cbor_encoder_close_container(), this function checks that the number - * of items (or pair of items, in the case of a map) was correct. If the number - * of items inserted does not match the length originally passed to - * cbor_encoder_create_array() or cbor_encoder_create_map(), this function - * returns either CborErrorTooFewItems or CborErrorTooManyItems. - * - * \sa cbor_encoder_create_array(), cbor_encoder_create_map() - */ -CborError cbor_encoder_close_container_checked(CborEncoder *encoder, const CborEncoder *containerEncoder) -{ - const uint8_t *ptr = encoder->data.ptr; - CborError err = cbor_encoder_close_container(encoder, containerEncoder); - if (containerEncoder->flags & CborIteratorFlag_UnknownLength || encoder->end == NULL) - return err; - - /* check what the original length was */ - uint64_t actually_added; - err = _cbor_value_extract_number(&ptr, encoder->data.ptr, &actually_added); - if (err) - return err; - - if (containerEncoder->flags & CborIteratorFlag_ContainerIsMap) { - if (actually_added > SIZE_MAX / 2) - return CborErrorDataTooLarge; - actually_added *= 2; - } - return actually_added == containerEncoder->added ? CborNoError : - actually_added < containerEncoder->added ? CborErrorTooManyItems : CborErrorTooFewItems; -} - -/** @} */ diff --git a/src/cborerrorstrings.c b/src/cborerrorstrings.c index 4aa684dd..41319e46 100644 --- a/src/cborerrorstrings.c +++ b/src/cborerrorstrings.c @@ -22,6 +22,7 @@ ** ****************************************************************************/ +#include "cbor_defs.h" #include "cbor.h" #ifndef _ 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..a796f67c 100644 --- a/src/cborparser.c +++ b/src/cborparser.c @@ -38,6 +38,12 @@ #include +#include "cbor_buf_reader.h" + +#ifndef CBOR_PARSER_MAX_RECURSIONS +# define CBOR_PARSER_MAX_RECURSIONS 1024 +#endif + /** * \defgroup CborParsing Parsing CBOR streams * \brief Group of functions used to parse CBOR streams. @@ -142,31 +148,10 @@ * \endif */ -static inline uint16_t get16(const uint8_t *ptr) -{ - uint16_t result; - memcpy(&result, ptr, sizeof(result)); - return cbor_ntohs(result); -} - -static inline uint32_t get32(const uint8_t *ptr) +CBOR_INTERNAL_API_CC CborError _cbor_value_extract_number(const CborParser *p, int *offset, uint64_t *len) { - 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 +160,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; @@ -215,17 +201,19 @@ static CborError preparse_value(CborValue *it) { const CborParser *parser = it->parser; 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 +226,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 +248,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 +276,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 +292,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 +307,13 @@ 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 = _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 +331,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); + 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 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 +360,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 +594,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 +647,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 +986,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 +997,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 +1044,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 +1168,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 +1176,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 +1204,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 +1215,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 +1297,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 +1335,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 +1344,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 +1446,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 +1545,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..800d68c6 100644 --- a/src/cborpretty.c +++ b/src/cborpretty.c @@ -29,8 +29,8 @@ #endif #include "cbor.h" -#include "cborinternal_p.h" #include "compilersupport_p.h" +#include "cborinternal_p.h" #include "utf8_p.h" #include @@ -224,7 +224,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 +236,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 +255,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 +277,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 +328,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 +392,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 +457,7 @@ static CborError value_to_pretty(CborStreamFunction stream, void *out, CborValue err = stream(out, val ? "true" : "false"); break; } - +#ifndef NO_FLOAT_SUPPORT case CborDoubleType: { const char *suffix; double val; @@ -490,12 +496,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..babb23da 100644 --- a/src/cbortojson.c +++ b/src/cbortojson.c @@ -41,6 +41,7 @@ #include #include + /** * \defgroup CborToJson Converting CBOR to JSON * \brief Group of functions used to convert CBOR to JSON. @@ -497,7 +498,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 +508,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 +593,7 @@ static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType typ return CborErrorIO; break; } - +#ifndef NO_FLOAT_SUPPORT case CborDoubleType: { double val; if (false) { @@ -632,8 +633,10 @@ static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType typ } break; } +#endif case CborInvalidType: + default: return CborErrorUnknownType; } @@ -641,6 +644,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 325da8c6..4d093e44 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 @@ -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,17 +440,17 @@ 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; + int previous = -1; + int previous_end; if (!recursionLeft) return CborErrorNestingTooDeep; while (!cbor_value_at_end(it)) { - const uint8_t *current; + int current; if (containerType == CborMapType) { - current = it->ptr; + current = it->offset; if (flags & CborValidateMapKeysAreString) { CborType type = cbor_value_get_type(it); if (type == CborTagType) { @@ -469,34 +474,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 */ @@ -530,7 +543,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); @@ -652,7 +665,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..b7831f9f 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 @@ -53,7 +57,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 @@ -251,5 +255,9 @@ static inline double decode_half(unsigned short half) #endif } +#ifdef __cplusplus +} +#endif + #endif /* COMPILERSUPPORT_H */ diff --git a/src/open_memstream.c b/src/open_memstream.c index e7ceac4d..eaa53e55 100644 --- a/src/open_memstream.c +++ b/src/open_memstream.c @@ -26,6 +26,8 @@ #define _DEFAULT_SOURCE 1 #define _GNU_SOURCE 1 +#ifndef 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..1624598e 100644 --- a/src/src.pri +++ b/src/src.pri @@ -1,16 +1,17 @@ SOURCES += \ $$PWD/cborencoder.c \ - $$PWD/cborencoder_close_container_checked.c \ $$PWD/cborerrorstrings.c \ $$PWD/cborparser.c \ $$PWD/cborparser_dup_string.c \ $$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 +HEADERS += $$PWD/cbor.h $$PWD/tinycbor-version.h QMAKE_CFLAGS *= $$QMAKE_CFLAGS_SPLIT_SECTIONS QMAKE_LFLAGS *= $$QMAKE_LFLAGS_GCSECTIONS -INCLUDEPATH += $$PWD +INCLUDEPATH += $$PWD/ CONFIG(release, debug|release): DEFINES += NDEBUG 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/encoder/tst_encoder.cpp b/tests/encoder/tst_encoder.cpp index 858d712a..38338b1c 100644 --- a/tests/encoder/tst_encoder.cpp +++ b/tests/encoder/tst_encoder.cpp @@ -24,6 +24,7 @@ #include #include "cbor.h" +#include "cbor_buf_writer.h" #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) #include @@ -240,7 +241,7 @@ CborError encodeVariant(CborEncoder *encoder, const QVariant &v) if (err && !isOomError(err)) return err; } - return cbor_encoder_close_container_checked(encoder, &sub); + return static_cast(err | cbor_encoder_close_container(encoder, &sub)); } if (type == qMetaTypeId() || type == qMetaTypeId()) { CborEncoder sub; @@ -261,7 +262,7 @@ CborError encodeVariant(CborEncoder *encoder, const QVariant &v) if (err && !isOomError(err)) return err; } - return cbor_encoder_close_container_checked(encoder, &sub); + return (CborError)(err | cbor_encoder_close_container(encoder, &sub)); } } return CborErrorUnknownType; @@ -273,6 +274,7 @@ void compare(const QVariant &input, const QByteArray &output) QByteArray buffer(output.length(), Qt::Uninitialized); uint8_t *bufptr = reinterpret_cast(buffer.data()); CborEncoder encoder; + cbor_encoder_init(&encoder, bufptr, buffer.length(), 0); QCOMPARE(encodeVariant(&encoder, input), CborNoError); @@ -625,7 +627,9 @@ void tst_Encoder::shortBuffer() for (int len = 0; len < output.length(); ++len) { CborEncoder encoder; + cbor_encoder_init(&encoder, reinterpret_cast(buffer.data()), len, 0); + QCOMPARE(int(encodeVariant(&encoder, input)), int(CborErrorOutOfMemory)); QVERIFY(cbor_encoder_get_extra_bytes_needed(&encoder) != 0); QCOMPARE(len + cbor_encoder_get_extra_bytes_needed(&encoder), size_t(output.length())); @@ -639,11 +643,13 @@ void tst_Encoder::tooShortArrays() QByteArray buffer(output.length() + 1, Qt::Uninitialized); CborEncoder encoder, container; + cbor_encoder_init(&encoder, reinterpret_cast(buffer.data()), buffer.length(), 0); + QCOMPARE(cbor_encoder_create_array(&encoder, &container, 2), CborNoError); QCOMPARE(encodeVariant(&container, input), CborNoError); QCOMPARE(container.added, size_t(1)); - QCOMPARE(cbor_encoder_close_container_checked(&encoder, &container), CborErrorTooFewItems); + QCOMPARE(int(cbor_encoder_close_container(&encoder, &container)), int(CborErrorTooFewItems)); } void tst_Encoder::tooShortMaps() @@ -651,13 +657,14 @@ void tst_Encoder::tooShortMaps() QFETCH(QVariant, input); QFETCH(QByteArray, output); QByteArray buffer(output.length() + 1, Qt::Uninitialized); - CborEncoder encoder, container; + cbor_encoder_init(&encoder, reinterpret_cast(buffer.data()), buffer.length(), 0); + QCOMPARE(cbor_encoder_create_map(&encoder, &container, 2), CborNoError); QCOMPARE(encodeVariant(&container, input), CborNoError); QCOMPARE(container.added, size_t(1)); - QCOMPARE(cbor_encoder_close_container_checked(&encoder, &container), CborErrorTooFewItems); + QCOMPARE(int(cbor_encoder_close_container(&encoder, &container)), int(CborErrorTooFewItems)); } void tst_Encoder::tooBigArrays() @@ -667,12 +674,14 @@ void tst_Encoder::tooBigArrays() QByteArray buffer(output.length() * 2 + 1, Qt::Uninitialized); CborEncoder encoder, container; + cbor_encoder_init(&encoder, reinterpret_cast(buffer.data()), buffer.length(), 0); + QCOMPARE(cbor_encoder_create_array(&encoder, &container, 1), CborNoError); QCOMPARE(encodeVariant(&container, input), CborNoError); QCOMPARE(encodeVariant(&container, input), CborNoError); QCOMPARE(container.added, size_t(2)); - QCOMPARE(cbor_encoder_close_container_checked(&encoder, &container), CborErrorTooManyItems); + QCOMPARE(int(cbor_encoder_close_container(&encoder, &container)), int(CborErrorTooManyItems)); } void tst_Encoder::tooBigMaps() @@ -682,13 +691,15 @@ void tst_Encoder::tooBigMaps() QByteArray buffer(output.length() * 3 + 1, Qt::Uninitialized); CborEncoder encoder, container; - cbor_encoder_init(&encoder, reinterpret_cast(buffer.data()), buffer.length(), 0); + + cbor_encoder_init(&encoder,reinterpret_cast(buffer.data()), buffer.length(), 0); + QCOMPARE(cbor_encoder_create_map(&encoder, &container, 1), CborNoError); QCOMPARE(encodeVariant(&container, input), CborNoError); QCOMPARE(encodeVariant(&container, input), CborNoError); QCOMPARE(encodeVariant(&container, input), CborNoError); QCOMPARE(container.added, size_t(3)); - QCOMPARE(cbor_encoder_close_container_checked(&encoder, &container), CborErrorTooManyItems); + QCOMPARE(int(cbor_encoder_close_container(&encoder, &container)), int(CborErrorTooManyItems)); } void tst_Encoder::illegalSimpleType_data() @@ -709,7 +720,9 @@ void tst_Encoder::illegalSimpleType() quint8 buf[2]; CborEncoder encoder; + cbor_encoder_init(&encoder, buf, sizeof(buf), 0); + QCOMPARE(int(cbor_encode_simple_value(&encoder, type)), int(CborErrorIllegalSimpleType)); } diff --git a/tests/parser/tst_parser.cpp b/tests/parser/tst_parser.cpp index 28705c19..15bcc607 100644 --- a/tests/parser/tst_parser.cpp +++ b/tests/parser/tst_parser.cpp @@ -25,6 +25,8 @@ #define _XOPEN_SOURCE 700 #include #include "cbor.h" +#include "cbor_buf_reader.h" +#include #include #include @@ -120,7 +122,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; @@ -157,6 +159,7 @@ void tst_Parser::initParserEmpty() { CborParser parser; CborValue first; + CborError err = cbor_parser_init((const quint8 *)"", 0, 0, &parser, &first); QCOMPARE(err, CborErrorUnexpectedEOF); } @@ -174,6 +177,7 @@ void compareOne_real(const QByteArray &data, const QString &expected, int line, compareFailed = true; CborParser parser; CborValue first; + CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &first); QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\""); @@ -221,7 +225,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; } @@ -863,7 +867,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() @@ -955,6 +959,7 @@ void tst_Parser::stringLength() CborParser parser; CborValue value; + CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &value); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); @@ -1050,6 +1055,7 @@ void compareOneString(const QByteArray &data, const QString &string, bool expect CborParser parser; CborValue value; + CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &value); QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\""); @@ -1157,6 +1163,7 @@ void tst_Parser::mapFind() CborParser parser; CborValue value; + CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &value); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); @@ -1234,6 +1241,7 @@ void tst_Parser::checkedIntegers() CborParser parser; CborValue value; + CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &value); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); @@ -1507,6 +1515,7 @@ void tst_Parser::validation() QString decoded; CborParser parser; CborValue first; + CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), flags, &parser, &first); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); @@ -1514,6 +1523,7 @@ void tst_Parser::validation() CborError err3 = cbor_value_validate(&first, CborValidateBasic); err = parseOne(&first, &decoded); QCOMPARE(err, expectedError); + if (!QByteArray(QTest::currentDataTag()).contains("utf8")) { QCOMPARE(err2, expectedError); QCOMPARE(err3, expectedError); @@ -1902,6 +1912,7 @@ void tst_Parser::resumeParsing() for (int len = 0; len < data.length() - 1; ++len) { CborParser parser; CborValue first; + CborError err = cbor_parser_init(reinterpret_cast(data.constData()), len, 0, &parser, &first); if (!err) { QString decoded; @@ -1936,12 +1947,13 @@ void tst_Parser::endPointer() QString decoded; CborParser parser; CborValue first; + CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &first); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); 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() @@ -1991,6 +2003,7 @@ void tst_Parser::recursionLimit() CborParser parser; CborValue first; + CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &first); QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); diff --git a/tests/tojson/tst_tojson.cpp b/tests/tojson/tst_tojson.cpp index e045cf30..ccc177dc 100644 --- a/tests/tojson/tst_tojson.cpp +++ b/tests/tojson/tst_tojson.cpp @@ -215,6 +215,7 @@ void compareOne_real(const QByteArray &data, const QString &expected, int flags, compareFailed = true; CborParser parser; CborValue first; + CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &first); QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\""); @@ -225,7 +226,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; } @@ -421,6 +422,7 @@ void tst_ToJson::nonStringKeyMaps() CborParser parser; CborValue first; QString decoded; + cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &first); CborError err = parseOne(&first, &decoded, CborConvertRequireMapStringKeys); QCOMPARE(err, CborErrorJsonObjectKeyNotString); @@ -657,6 +659,7 @@ void compareMetaData(QByteArray data, const QString &expected, int otherFlags = { CborParser parser; CborValue first; + CborError err = cbor_parser_init(reinterpret_cast(data.constData()), data.length(), 0, &parser, &first); QVERIFY2(!err, QByteArrayLiteral(": Got error \"") + cbor_error_string(err) + "\""); @@ -665,7 +668,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..10f3356d 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 @@ -50,10 +51,10 @@ void printerror(CborError err, const char *fname) void dumpFile(FILE *in, const char *fname, bool printJosn, int flags) { static const size_t chunklen = 16 * 1024; - static size_t bufsize = 0; + static int bufsize = 0; static uint8_t *buffer = NULL; - size_t buflen = 0; + int buflen = 0; do { if (bufsize == buflen) buffer = xrealloc(buffer, bufsize += chunklen, fname); @@ -70,7 +71,9 @@ void dumpFile(FILE *in, const char *fname, bool printJosn, int flags) CborParser parser; CborValue value; - CborError err = cbor_parser_init(buffer, buflen, 0, &parser, &value); + CborError err = CborNoError; + + err |= cbor_parser_init(buffer, buflen, 0, &parser, &value); if (!err) { if (printJosn) err = cbor_value_to_json_advance(stdout, &value, flags); @@ -79,7 +82,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 != buflen) err = CborErrorGarbageAtEnd; if (err) printerror(err, fname); diff --git a/tools/json2cbor/json2cbor.c b/tools/json2cbor/json2cbor.c index b9f5a846..4994d3b9 100644 --- a/tools/json2cbor/json2cbor.c +++ b/tools/json2cbor/json2cbor.c @@ -355,7 +355,7 @@ CborError decode_json(cJSON *json, CborEncoder *encoder) if (err) return err; } - return cbor_encoder_close_container_checked(encoder, &container); + return cbor_encoder_close_container(encoder, &container); case cJSON_Object: err = cbor_encoder_create_map(encoder, &container, @@ -389,7 +389,7 @@ CborError decode_json(cJSON *json, CborEncoder *encoder) return err; } - return cbor_encoder_close_container_checked(encoder, &container); + return cbor_encoder_close_container(encoder, &container); } } @@ -473,7 +473,9 @@ int main(int argc, char **argv) /* 3. encode as CBOR */ // We're going to reuse the buffer, as CBOR is usually shorter than the equivalent JSON CborEncoder encoder; + cbor_encoder_init(&encoder, buffer, buffersize, 0); + CborError err = decode_json(doc, &encoder); cJSON_Delete(doc); @@ -484,7 +486,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; }