From: Youngjae Shin Date: Mon, 4 Jan 2016 07:23:01 +0000 (+0900) Subject: Merge branch 'upstream' into tizen X-Git-Tag: submit/tizen/20160104.224721^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f85d7e7587daa4ddb99f5aa2bdb6bde5a999e5d9;p=contrib%2Fiotivity.git Merge branch 'upstream' into tizen Conflicts: resource/csdk/connectivity/src/ip_adapter/caipserver.c tools/tizen/iotivity.spec --- f85d7e7587daa4ddb99f5aa2bdb6bde5a999e5d9 diff --cc build_common/SConscript index 3a3ac44,a73adab..0ec3f60 --- a/build_common/SConscript +++ b/build_common/SConscript @@@ -287,14 -279,9 +287,14 @@@ elif env.get('ROUTING') == 'EP' user_prefix = env.get('PREFIX') if user_prefix: - pc_vars = {'\@PREFIX\@': user_prefix, '\@EXEC_PREFIX\@':user_prefix, '\@VERSION\@':'0.9.2'} + pc_vars = {'\@PREFIX\@': user_prefix, + '\@LIB_INSTALL_DIR\@': env.get('LIB_INSTALL_DIR'), - '\@VERSION\@': '1.0.0', '\@ROUTING_DEFINE\@': routing_define ++ '\@VERSION\@': '1.0.1', '\@ROUTING_DEFINE\@': routing_define + } else: - pc_vars = {'\@PREFIX\@': env.get('BUILD_DIR'), '\@VERSION\@': '1.0.0', - pc_vars = {'\@PREFIX\@': env.get('BUILD_DIR'), '\@EXEC_PREFIX\@': env.get('BUILD_DIR'), '\@VERSION\@':'0.9.2'} ++ pc_vars = {'\@PREFIX\@': env.get('BUILD_DIR'), '\@VERSION\@': '1.0.1', + '\@ROUTING_DEFINE\@': routing_define + } env.Substfile(pc_file, SUBST_DICT = pc_vars) diff --cc extlibs/tinycbor/tinycbor/Makefile.configure index 0000000,0000000..afb23c4 new file mode 100644 --- /dev/null +++ b/extlibs/tinycbor/tinycbor/Makefile.configure @@@ -1,0 -1,0 +1,29 @@@ ++ALLTESTS = open_memstream funopen gc_sections \ ++ system-cjson cjson ++MAKEFILE := $(lastword $(MAKEFILE_LIST)) ++OUT := ++ ++PROGRAM-open_memstream = extern int open_memstream(); int main() { return open_memstream(); } ++PROGRAM-funopen = extern int funopen(); int main() { return funopen(); } ++PROGRAM-gc_sections = int main() {} ++CCFLAGS-gc_sections = -Wl,--gc-sections ++ ++PROGRAM-cjson = \#include \n ++PROGRAM-cjson += \#include \n ++PROGRAM-cjson += int main() { return cJSON_False; } ++CCFLAGS-cjson = -I$(dir $(MAKEFILE))src/cjson ++PROGRAM-system-cjson = $(PROGRAM-cjson) ++CCLFAGS-system-cjson = -lcJSON ++ ++sink: ++ @echo >&2 Please run from the top-level Makefile. ++ ++configure: $(foreach it,$(ALLTESTS),check-$(it)) ++ ++check-%: ++ @echo $(subst check-,,$@)-tested := 1 $(OUT) ++ $(if $(V),,@)if echo -e "$($(subst check-,PROGRAM-,$@))" | \ ++ $(CC) -xc $($(subst check-,CCFLAGS-,$@)) -o /dev/null - $(if $(V),,>/dev/null 2>&1); \ ++ then \ ++ echo $(subst check-,,$@)-pass := 1 $(OUT); \ ++ fi diff --cc extlibs/tinycbor/tinycbor/src/cborparser.c index 069401d,0000000..ab3cae1 mode 100644,000000..100644 --- a/extlibs/tinycbor/tinycbor/src/cborparser.c +++ b/extlibs/tinycbor/tinycbor/src/cborparser.c @@@ -1,736 -1,0 +1,736 @@@ +/**************************************************************************** +** +** 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 +#include "cbor.h" +#include "cborconstants_p.h" +#include "compilersupport_p.h" +#include "extract_number_p.h" + +#include +#include +#include + +#include "assert_p.h" /* Always include last */ + +#ifndef CBOR_PARSER_MAX_RECURSIONS +# define CBOR_PARSER_MAX_RECURSIONS 1024 +#endif + +/** + * \typedef CborValue + * This type contains one value parsed from the CBOR stream. + * + * To get the actual type, use cbor_value_get_type(). Then extract the value + * using one of the corresponding functions: cbor_value_get_boolean(), cbor_value_get_int64(), + * cbor_value_get_int(), cbor_value_copy_string(), cbor_value_get_array(), cbor_value_get_map(), + * cbor_value_get_double(), cbor_value_get_float(). + * + * In C++ and C11 modes, you can additionally use the cbor_value_get_integer() + * and cbor_value_get_floating_point() generic functions. + * + * \omit + * Implementation details: the CborValue contains these fields: + * \list + * \li ptr: pointer to the actual data + * \li flags: flags from the decoder + * \li extra: partially decoded integer value (0, 1 or 2 bytes) + * \li remaining: remaining items in this collection after this item or UINT32_MAX if length is unknown + * \endlist + * \endomit + */ + +static CborError extract_length(const CborParser *parser, const uint8_t **ptr, size_t *len) +{ + uint64_t v; + CborError err = extract_number(ptr, parser->end, &v); + if (err) + return err; + + *len = v; + if (v != *len) + return CborErrorDataTooLarge; + return CborNoError; +} + +static bool is_fixed_type(uint8_t type) +{ + return type != CborTextStringType && type != CborByteStringType && type != CborArrayType && + type != CborMapType; +} + +static CborError preparse_value(CborValue *it) +{ + const CborParser *parser = it->parser; + it->type = CborInvalidType; + + // are we at the end? + if (it->ptr == parser->end) + return CborErrorUnexpectedEOF; + + uint8_t descriptor = *it->ptr; + uint8_t type = descriptor & MajorTypeMask; + it->type = type; + it->flags = 0; + it->extra = (descriptor &= SmallValueMask); + + if (descriptor > Value64Bit) { + if (unlikely(descriptor != IndefiniteLength)) + return type == CborSimpleType ? CborErrorUnknownType : CborErrorIllegalNumber; + if (likely(!is_fixed_type(type))) { + // special case + it->flags |= CborIteratorFlag_UnknownLength; + it->type = type; + return CborNoError; + } + return type == CborSimpleType ? CborErrorUnexpectedBreak : CborErrorIllegalNumber; + } + + size_t bytesNeeded = descriptor < Value8Bit ? 0 : (1 << (descriptor - Value8Bit)); - if (it->ptr + 1 + bytesNeeded > parser->end) ++ if (bytesNeeded + 1 > (size_t)(parser->end - it->ptr)) + return CborErrorUnexpectedEOF; + + uint8_t majortype = type >> MajorTypeShift; + if (majortype == NegativeIntegerType) { + it->flags |= CborIteratorFlag_NegativeInteger; + it->type = CborIntegerType; + } else if (majortype == SimpleTypesType) { + switch (descriptor) { + case FalseValue: + it->extra = false; + it->type = CborBooleanType; + break; + + case SinglePrecisionFloat: + case DoublePrecisionFloat: + it->flags |= CborIteratorFlag_IntegerValueTooLarge; + // fall through + case TrueValue: + case NullValue: + case UndefinedValue: + case HalfPrecisionFloat: + it->type = *it->ptr; + break; + + case SimpleTypeInNextByte: + it->extra = (uint8_t)it->ptr[1]; +#ifndef CBOR_PARSER_NO_STRICT_CHECKS + if (unlikely(it->extra < 32)) { + it->type = CborInvalidType; + return CborErrorIllegalSimpleType; + } +#endif + break; + + case 28: + case 29: + case 30: + case Break: + assert(false); // these conditions can't be reached + return CborErrorUnexpectedBreak; + } + return CborNoError; + } + + // try to decode up to 16 bits + if (descriptor < Value8Bit) + return CborNoError; + + if (descriptor == Value8Bit) + it->extra = (uint8_t)it->ptr[1]; + else if (descriptor == Value16Bit) + it->extra = get16(it->ptr + 1); + else + it->flags |= CborIteratorFlag_IntegerValueTooLarge; // Value32Bit or Value64Bit + return CborNoError; +} + +static CborError preparse_next_value(CborValue *it) +{ + if (it->remaining != UINT32_MAX) { + // don't decrement the item count if the current item is tag: they don't count + if (it->type != CborTagType && !--it->remaining) { + it->type = CborInvalidType; + return CborNoError; + } + } else if (it->remaining == UINT32_MAX && it->ptr != it->parser->end && *it->ptr == (uint8_t)BreakByte) { + // end of map or array + ++it->ptr; + it->type = CborInvalidType; + it->remaining = 0; + return CborNoError; + } + + return preparse_value(it); +} + +static CborError advance_internal(CborValue *it) +{ + uint64_t length; + CborError err = extract_number(&it->ptr, it->parser->end, &length); + assert(err == CborNoError); + + if (it->type == CborByteStringType || it->type == CborTextStringType) { + assert(length == (size_t)length); + assert((it->flags & CborIteratorFlag_UnknownLength) == 0); + it->ptr += length; + } + + return preparse_next_value(it); +} + +/** \internal + * + * Decodes the CBOR integer value when it is larger than the 16 bits available + * in value->extra. This function requires that value->flags have the + * CborIteratorFlag_IntegerValueTooLarge flag set. + * + * This function is also used to extract single- and double-precision floating + * point values (SinglePrecisionFloat == Value32Bit and DoublePrecisionFloat == + * Value64Bit). + */ +uint64_t _cbor_value_decode_int64_internal(const CborValue *value) +{ + assert(value->flags & CborIteratorFlag_IntegerValueTooLarge || + value->type == CborFloatType || value->type == CborDoubleType); + + // since the additional information can only be Value32Bit or Value64Bit, + // we just need to test for the one bit those two options differ + assert((*value->ptr & SmallValueMask) == Value32Bit || (*value->ptr & SmallValueMask) == Value64Bit); + if ((*value->ptr & 1) == (Value32Bit & 1)) + return get32(value->ptr + 1); + + assert((*value->ptr & SmallValueMask) == Value64Bit); + return get64(value->ptr + 1); +} + +/** + * 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 + * 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. + * + * ### Write how to determine the end pointer + * ### Write how to do limited-buffer windowed decoding + */ +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; + parser->flags = flags; + it->parser = parser; + it->ptr = buffer; + it->remaining = 1; // there's one type altogether, usually an array or map + return preparse_value(it); +} + +/** + * Advances the CBOR value \a it by one fixed-size position. Fixed-size types + * are: integers, tags, simple types (including boolean, null and undefined + * values) and floating point types. + * + * \sa cbor_value_at_end(), cbor_value_advance(), cbor_value_begin_recurse(), cbor_value_end_recurse() + */ +CborError cbor_value_advance_fixed(CborValue *it) +{ + assert(it->type != CborInvalidType); + assert(is_fixed_type(it->type)); + if (!it->remaining) + return CborErrorAdvancePastEOF; + return advance_internal(it); +} + +static CborError advance_recursive(CborValue *it, int nestingLevel) +{ + if (is_fixed_type(it->type)) + return advance_internal(it); + + if (!cbor_value_is_container(it)) { + size_t len = SIZE_MAX; + return _cbor_value_copy_string(it, NULL, &len, it); + } + + // map or array + if (nestingLevel == CBOR_PARSER_MAX_RECURSIONS) + return CborErrorNestingTooDeep; + + CborError err; + CborValue recursed; + err = cbor_value_enter_container(it, &recursed); + if (err) + return err; + while (!cbor_value_at_end(&recursed)) { + err = advance_recursive(&recursed, nestingLevel + 1); + if (err) + return err; + } + return cbor_value_leave_container(it, &recursed); +} + + +/** + * Advances the CBOR value \a it by one element, skipping over containers. + * Unlike cbor_value_advance_fixed(), this function can be called on a CBOR + * value of any type. However, if the type is a container (map or array) or a + * string with a chunked payload, this function will not run in constant time + * and will recurse into itself (it will run on O(n) time for the number of + * elements or chunks and will use O(n) memory for the number of nested + * containers). + * + * \sa cbor_value_at_end(), cbor_value_advance_fixed(), cbor_value_begin_recurse(), cbor_value_end_recurse() + */ +CborError cbor_value_advance(CborValue *it) +{ + assert(it->type != CborInvalidType); + if (!it->remaining) + return CborErrorAdvancePastEOF; + return advance_recursive(it, 0); +} + +/** + * Advances the CBOR value \a it until it no longer points to a tag. If \a it is + * already not pointing to a tag, then this function returns it unchanged. + * + * \sa cbor_value_advance_fixed(), cbor_value_advance() + */ +CborError cbor_value_skip_tag(CborValue *it) +{ + while (cbor_value_is_tag(it)) { + CborError err = cbor_value_advance_fixed(it); + if (err) + return err; + } + return CborNoError; +} + +/** + * \fn bool cbor_value_is_container(const CborValue *it) + * + * Returns true if the \a it value is a container and requires recursion in + * order to decode (maps and arrays), false otherwise. + */ + +/** + * Creates a CborValue iterator pointing to the first element of the container + * represented by \a it and saves it in \a recursed. The \a it container object + * needs to be kept and passed again to cbor_value_leave_container() in order + * to continue iterating past this container. + * + * \sa cbor_value_is_container(), cbor_value_leave_container(), cbor_value_advance() + */ +CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed) +{ + CborError err; + assert(cbor_value_is_container(it)); + *recursed = *it; + + if (it->flags & CborIteratorFlag_UnknownLength) { + recursed->remaining = UINT32_MAX; + ++recursed->ptr; + err = preparse_value(recursed); + if (err != CborErrorUnexpectedBreak) + return err; + // actually, break was expected here + // it's just an empty container + ++recursed->ptr; + } else { + uint64_t len; + err = extract_number(&recursed->ptr, recursed->parser->end, &len); + assert(err == CborNoError); + + recursed->remaining = len; + if (recursed->remaining != len || len == UINT32_MAX) { + // back track the pointer to indicate where the error occurred + recursed->ptr = it->ptr; + 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; + return CborErrorDataTooLarge; + } + recursed->remaining *= 2; + } + if (len != 0) + return preparse_value(recursed); + } + + // the case of the empty container + recursed->type = CborInvalidType; + recursed->remaining = 0; + return CborNoError; +} + +/** + * Updates \a it to point to the next element after the container. The \a + * recursed object needs to point to the element obtained either by advancing + * the last element of the container (via cbor_value_advance(), + * cbor_value_advance_fixed(), a nested cbor_value_leave_container(), or the \c + * next pointer from cbor_value_copy_string() or cbor_value_dup_string()). + * + * \sa cbor_value_enter_container(), cbor_value_at_end() + */ +CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed) +{ + assert(cbor_value_is_container(it)); + assert(recursed->type == CborInvalidType); + it->ptr = recursed->ptr; + return preparse_next_value(it); +} + +/** + * Calculates the length of the string in \a value and stores the result in \a + * len. This function is different from cbor_value_get_string_length() in that + * it calculates the length even for strings sent in chunks. For that reason, + * this function may not run in constant time (it will run in O(n) time on the + * number of chunks). + * + * \note On 32-bit platforms, this function will return error condition of \ref + * CborErrorDataTooLarge if the stream indicates a length that is too big to + * fit in 32-bit. + * + * \sa cbor_value_get_string_length(), cbor_value_copy_string(), cbor_value_is_length_known() + */ +CborError cbor_value_calculate_string_length(const CborValue *value, size_t *len) +{ + *len = SIZE_MAX; + return _cbor_value_copy_string(value, NULL, len, NULL); +} + +/** + * \fn CborError cbor_value_dup_text_string(const CborValue *value, char **buffer, size_t *buflen, CborValue *next) + * + * Allocates memory for the string pointed by \a value and copies it into this + * buffer. The pointer to the buffer is stored in \a buffer and the number of + * bytes copied is stored in \a len (those variables must not be NULL). + * + * If \c malloc returns a NULL pointer, this function will return error + * condition \ref CborErrorOutOfMemory. + * + * On success, \c{*buffer} will contain a valid pointer that must be freed by + * calling \c{free()}. This is the case even for zero-length strings. + * + * The \a next pointer, if not null, will be updated to point to the next item + * after this string. If \a value points to the last item, then \a next will be + * invalid. + * + * \note This function does not perform UTF-8 validation on the incoming text + * string. + * + * \sa cbor_value_copy_text_string(), cbor_value_dup_byte_string() + */ + +/** + * \fn CborError cbor_value_dup_byte_string(const CborValue *value, uint8_t **buffer, size_t *buflen, CborValue *next) + * + * Allocates memory for the string pointed by \a value and copies it into this + * buffer. The pointer to the buffer is stored in \a buffer and the number of + * bytes copied is stored in \a len (those variables must not be NULL). + * + * If \c malloc returns a NULL pointer, this function will return error + * condition \ref CborErrorOutOfMemory. + * + * On success, \c{*buffer} will contain a valid pointer that must be freed by + * calling \c{free()}. This is the case even for zero-length strings. + * + * The \a next pointer, if not null, will be updated to point to the next item + * after this string. If \a value points to the last item, then \a next will be + * invalid. + * + * \sa cbor_value_copy_byte_string(), cbor_value_dup_text_string() + */ +CborError _cbor_value_dup_string(const CborValue *value, void **buffer, size_t *buflen, CborValue *next) +{ + assert(buffer); + assert(buflen); + *buflen = SIZE_MAX; + CborError err = _cbor_value_copy_string(value, NULL, buflen, NULL); + if (err) + return err; + + ++*buflen; + *buffer = malloc(*buflen); + if (!*buffer) { + // out of memory + return CborErrorOutOfMemory; + } + err = _cbor_value_copy_string(value, *buffer, buflen, next); + if (err) { + free(*buffer); + return err; + } + return CborNoError; +} + +// We return uintptr_t so that we can pass memcpy directly as the iteration +// 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); + +static uintptr_t iterate_noop(char *dest, const uint8_t *src, size_t len) +{ + (void)dest; + (void)src; + (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 CborError iterate_string_chunks(const CborValue *value, char *buffer, size_t *buflen, + bool *result, CborValue *next, IterateFunction func) +{ + assert(cbor_value_is_byte_string(value) || cbor_value_is_text_string(value)); + + size_t total; + CborError err; + const uint8_t *ptr = value->ptr; + if (cbor_value_is_length_known(value)) { + // easy case: fixed length + err = extract_length(value->parser, &ptr, &total); + if (err) + return err; - if (ptr + total > value->parser->end) ++ if (total > (size_t)(value->parser->end - ptr)) + return CborErrorUnexpectedEOF; + if (total <= *buflen) + *result = func(buffer, ptr, total); + else + *result = false; + ptr += total; + } else { + // chunked + ++ptr; + total = 0; + *result = true; + while (true) { + size_t chunkLen; + size_t newTotal; + + if (ptr == value->parser->end) + return CborErrorUnexpectedEOF; + + if (*ptr == (uint8_t)BreakByte) { + ++ptr; + break; + } + + // is this the right type? + if ((*ptr & MajorTypeMask) != value->type) + return CborErrorIllegalType; + + err = extract_length(value->parser, &ptr, &chunkLen); + if (err) + return err; + + if (unlikely(add_check_overflow(total, chunkLen, &newTotal))) + return CborErrorDataTooLarge; + - if (ptr + chunkLen > value->parser->end) ++ if (chunkLen > (size_t)(value->parser->end - ptr)) + return CborErrorUnexpectedEOF; + + if (*result && *buflen >= newTotal) + *result = func(buffer + total, ptr, chunkLen); + else + *result = false; + + ptr += chunkLen; + total = newTotal; + } + } + + // is there enough room for the ending NUL byte? + if (*result && *buflen > total) + *result = func(buffer + total, (const uint8_t *)"", 1); + *buflen = total; + + if (next) { + *next = *value; + next->ptr = ptr; + return preparse_next_value(next); + } + return CborNoError; +} + +/** + * \fn CborError cbor_value_copy_text_string(const CborValue *value, char *buffer, size_t *buflen, CborValue *next) + * + * Copies the string pointed by \a value into the buffer provided at \a buffer + * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not + * copy anything and will only update the \a next value. + * + * If the provided buffer length was too small, this function returns an error + * condition of \ref CborErrorOutOfMemory. If you need to calculate the length + * of the string in order to preallocate a buffer, use + * cbor_value_calculate_string_length(). + * + * On success, this function sets the number of bytes copied to \c{*buflen}. If + * the buffer is large enough, this function will insert a null byte after the + * last copied byte, to facilitate manipulation of text strings. That byte is + * not included in the returned value of \c{*buflen}. + * + * The \a next pointer, if not null, will be updated to point to the next item + * after this string. If \a value points to the last item, then \a next will be + * invalid. + * + * \note This function does not perform UTF-8 validation on the incoming text + * string. + * + * \sa cbor_value_dup_text_string(), cbor_value_copy_byte_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length() + */ + +/** + * \fn CborError cbor_value_copy_byte_string(const CborValue *value, uint8_t *buffer, size_t *buflen, CborValue *next) + * + * Copies the string pointed by \a value into the buffer provided at \a buffer + * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not + * copy anything and will only update the \a next value. + * + * If the provided buffer length was too small, this function returns an error + * condition of \ref CborErrorOutOfMemory. If you need to calculate the length + * of the string in order to preallocate a buffer, use + * cbor_value_calculate_string_length(). + * + * On success, this function sets the number of bytes copied to \c{*buflen}. If + * the buffer is large enough, this function will insert a null byte after the + * last copied byte, to facilitate manipulation of null-terminated strings. + * That byte is not included in the returned value of \c{*buflen}. + * + * The \a next pointer, if not null, will be updated to point to the next item + * after this string. If \a value points to the last item, then \a next will be + * invalid. + * + * \sa cbor_value_dup_text_string(), cbor_value_copy_text_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length() + */ + +CborError _cbor_value_copy_string(const CborValue *value, void *buffer, + size_t *buflen, CborValue *next) +{ + bool copied_all; + CborError err = iterate_string_chunks(value, (char*)buffer, buflen, &copied_all, next, + buffer ? (IterateFunction)memcpy : iterate_noop); + return err ? err : + copied_all ? CborNoError : CborErrorOutOfMemory; +} + +/** + * Compares the entry \a value with the string \a string and store the result + * in \a result. If the value is different from \a string or if it is not a + * text string, \a result will contain \c false. + * + * The entry at \a value may be a tagged string. If \a is not a string or a + * tagged string, the comparison result will be false. + */ +CborError cbor_value_text_string_equals(const CborValue *value, const char *string, bool *result) +{ + CborValue copy = *value; + CborError err = cbor_value_skip_tag(©); + if (err) + return err; + if (!cbor_value_is_text_string(©)) { + *result = false; + return CborNoError; + } + + size_t len = strlen(string); + return iterate_string_chunks(©, CONST_CAST(char *, string), &len, result, NULL, iterate_memcmp); +} + +/** + * Attempts to find the value in map \a map that corresponds to the text string + * entry \a string. If the item is found, it is stored in \a result. If no item + * is found matching the key, then \a result will contain an element of type + * \ref CborInvalidType. + * + * \note This function may be expensive to execute. + */ +CborError cbor_value_map_find_value(const CborValue *map, const char *string, CborValue *element) +{ + assert(cbor_value_is_map(map)); + size_t len = strlen(string); + CborError err = cbor_value_enter_container(map, element); + if (err) + goto error; + + while (!cbor_value_at_end(element)) { + // find the non-tag so we can compare + err = cbor_value_skip_tag(element); + if (err) + goto error; + if (cbor_value_is_text_string(element)) { + bool equals; + size_t dummyLen = len; + err = iterate_string_chunks(element, CONST_CAST(char *, string), &dummyLen, + &equals, element, iterate_memcmp); + if (err) + goto error; + if (equals) + return preparse_value(element); + } else { + // skip this key + err = cbor_value_advance(element); + if (err) + goto error; + } + + // skip this value + err = cbor_value_skip_tag(element); + if (err) + goto error; + err = cbor_value_advance(element); + if (err) + goto error; + } + + // not found + element->type = CborInvalidType; + return CborNoError; + +error: + element->type = CborInvalidType; + return err; +} + +/** + * Extracts a half-precision floating point from \a value and stores it in \a + * result. + */ +CborError cbor_value_get_half_float(const CborValue *value, void *result) +{ + assert(value->type == CborHalfFloatType); + + // size has been computed already + uint16_t v = get16(value->ptr + 1); + memcpy(result, &v, sizeof(v)); + return CborNoError; +} diff --cc extlibs/tinycbor/tinycbor/src/extract_number_p.h index 4767cc0,0000000..d6a430e mode 100644,000000..100644 --- a/extlibs/tinycbor/tinycbor/src/extract_number_p.h +++ b/extlibs/tinycbor/tinycbor/src/extract_number_p.h @@@ -1,76 -1,0 +1,76 @@@ +/**************************************************************************** +** +** 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 +#include "cbor.h" +#include "cborconstants_p.h" +#include "compilersupport_p.h" + +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) +{ + 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); +} + +static CborError extract_number(const uint8_t **ptr, const uint8_t *end, uint64_t *len) +{ + uint8_t additional_information = **ptr & SmallValueMask; + ++*ptr; + if (additional_information < Value8Bit) { + *len = additional_information; + return CborNoError; + } + if (unlikely(additional_information > Value64Bit)) + return CborErrorIllegalNumber; + + size_t bytesNeeded = 1 << (additional_information - Value8Bit); - if (unlikely(*ptr + bytesNeeded > end)) { ++ if (unlikely(bytesNeeded > (size_t)(end - *ptr))) { + return CborErrorUnexpectedEOF; + } else if (bytesNeeded == 1) { + *len = (uint8_t)(*ptr)[0]; + } else if (bytesNeeded == 2) { + *len = get16(*ptr); + } else if (bytesNeeded == 4) { + *len = get32(*ptr); + } else { + *len = get64(*ptr); + } + *ptr += bytesNeeded; + return CborNoError; +} diff --cc extlibs/tinycbor/tinycbor/tests/parser/tst_parser.cpp index 25aff29,0000000..7eb5963 mode 100644,000000..100644 --- a/extlibs/tinycbor/tinycbor/tests/parser/tst_parser.cpp +++ b/extlibs/tinycbor/tinycbor/tests/parser/tst_parser.cpp @@@ -1,1236 -1,0 +1,1256 @@@ +/**************************************************************************** +** +** 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 _XOPEN_SOURCE 700 +#include +#include "cbor.h" +#include +#include + +extern "C" FILE *open_memstream(char **bufptr, size_t *sizeptr); + +Q_DECLARE_METATYPE(CborError) + +class tst_Parser : public QObject +{ + Q_OBJECT +private slots: + void initParserEmpty(); + + // parsing API + void fixed_data(); + void fixed(); + void strings_data(); + void strings() { fixed(); } + void tags_data(); + void tags() { fixed(); } + void tagTags_data() { tags_data(); } + void tagTags(); + void emptyContainers_data(); + void emptyContainers(); + void arrays_data(); + void arrays(); + void undefLengthArrays_data() { arrays_data(); } + void undefLengthArrays(); + void nestedArrays_data() { arrays_data(); } + void nestedArrays(); + void maps_data(); + void maps(); + void undefLengthMaps_data() { maps_data(); } + void undefLengthMaps(); + void nestedMaps_data() { maps_data(); } + void nestedMaps(); + void mapMixed_data(); + void mapMixed() { arrays(); } + void mapsAndArrays_data() { arrays_data(); } + void mapsAndArrays(); + + // convenience API + void stringLength_data(); + void stringLength(); + void stringCompare_data(); + void stringCompare(); + void mapFind_data(); + void mapFind(); + + // validation & errors + void validation_data(); + void validation(); + void resumeParsing_data(); + void resumeParsing(); + void endPointer_data(); + void endPointer(); + void recursionLimit_data(); + void recursionLimit(); +}; + +CborError parseOne(CborValue *it, QString *parsed) +{ + CborError err; + char *buffer; + size_t size; + + setlocale(LC_ALL, "C"); + FILE *f = open_memstream(&buffer, &size); + err = cbor_value_to_pretty_advance(f, it); + fclose(f); + + *parsed = QString::fromLatin1(buffer, size); + free(buffer); + return err; +} + +template QByteArray raw(const char (&data)[N]) +{ + return QByteArray::fromRawData(data, N - 1); +} + +void tst_Parser::initParserEmpty() +{ + CborParser parser; + CborValue first; + CborError err = cbor_parser_init((const quint8 *)"", 0, 0, &parser, &first); + QCOMPARE(err, CborErrorUnexpectedEOF); +} + +void addColumns() +{ + QTest::addColumn("data"); + QTest::addColumn("expected"); + QTest::addColumn("n"); // some aux integer, not added in all columns +} + +bool compareFailed = true; +void compareOne_real(const QByteArray &data, const QString &expected, int line, int n = -1) +{ + 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) + "\""); + + if (cbor_value_get_type(&first) == CborArrayType) { + size_t len; + if (n >= 0) { + QCOMPARE(cbor_value_get_array_length(&first, &len), CborNoError); + QCOMPARE(len, size_t(len)); + } else { + QCOMPARE(cbor_value_get_array_length(&first, &len), CborErrorUnknownLength); + } + } else if (cbor_value_get_type(&first) == CborMapType) { + size_t len; + if (n >= 0) { + QCOMPARE(cbor_value_get_map_length(&first, &len), CborNoError); + QCOMPARE(len, size_t(len)); + } else { + QCOMPARE(cbor_value_get_map_length(&first, &len), CborErrorUnknownLength); + } + } + + QString decoded; + err = parseOne(&first, &decoded); + QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + + "\"; decoded stream:\n" + decoded.toLatin1()); + QCOMPARE(decoded, expected); + + // check that we consumed everything + QCOMPARE((void*)first.ptr, (void*)data.constEnd()); + + compareFailed = false; +} +#define compareOne(data, expected) compareOne_real(data, expected, __LINE__) +#define compareOneSize(n, data, expected) compareOne_real(data, expected, __LINE__, n) + +void addFixedData() +{ + // unsigned integers + QTest::newRow("0") << raw("\x00") << "0"; + QTest::newRow("1") << raw("\x01") << "1"; + QTest::newRow("10") << raw("\x0a") << "10"; + QTest::newRow("23") << raw("\x17") << "23"; + QTest::newRow("24") << raw("\x18\x18") << "24"; + QTest::newRow("UINT8_MAX") << raw("\x18\xff") << "255"; + QTest::newRow("UINT8_MAX+1") << raw("\x19\x01\x00") << "256"; + QTest::newRow("UINT16_MAX") << raw("\x19\xff\xff") << "65535"; + QTest::newRow("UINT16_MAX+1") << raw("\x1a\0\1\x00\x00") << "65536"; + QTest::newRow("UINT32_MAX") << raw("\x1a\xff\xff\xff\xff") << "4294967295"; + QTest::newRow("UINT32_MAX+1") << raw("\x1b\0\0\0\1\0\0\0\0") << "4294967296"; + QTest::newRow("UINT64_MAX") << raw("\x1b" "\xff\xff\xff\xff" "\xff\xff\xff\xff") + << QString::number(std::numeric_limits::max()); + + // negative integers + QTest::newRow("-1") << raw("\x20") << "-1"; + QTest::newRow("-2") << raw("\x21") << "-2"; + QTest::newRow("-24") << raw("\x37") << "-24"; + QTest::newRow("-25") << raw("\x38\x18") << "-25"; + QTest::newRow("-UINT8_MAX") << raw("\x38\xff") << "-256"; + QTest::newRow("-UINT8_MAX-1") << raw("\x39\x01\x00") << "-257"; + QTest::newRow("-UINT16_MAX") << raw("\x39\xff\xff") << "-65536"; + QTest::newRow("-UINT16_MAX-1") << raw("\x3a\0\1\x00\x00") << "-65537"; + QTest::newRow("-UINT32_MAX") << raw("\x3a\xff\xff\xff\xff") << "-4294967296"; + QTest::newRow("-UINT32_MAX-1") << raw("\x3b\0\0\0\1\0\0\0\0") << "-4294967297"; + QTest::newRow("INT64_MIN+1") << raw("\x3b\x7f\xff\xff\xff""\xff\xff\xff\xfe") + << QString::number(std::numeric_limits::min() + 1); + QTest::newRow("INT64_MIN") << raw("\x3b\x7f\xff\xff\xff""\xff\xff\xff\xff") + << QString::number(std::numeric_limits::min()); + QTest::newRow("INT64_MIN-1") << raw("\x3b\x80\0\0\0""\0\0\0\0") << "-9223372036854775809"; + QTest::newRow("-UINT64_MAX") << raw("\x3b" "\xff\xff\xff\xff" "\xff\xff\xff\xfe") + << '-' + QString::number(std::numeric_limits::max()); + QTest::newRow("-UINT64_MAX+1") << raw("\x3b" "\xff\xff\xff\xff" "\xff\xff\xff\xff") + << "-18446744073709551616"; + + // overlongs + QTest::newRow("0*1") << raw("\x18\x00") << "0"; + QTest::newRow("0*2") << raw("\x19\x00\x00") << "0"; + QTest::newRow("0*4") << raw("\x1a\0\0\0\0") << "0"; + QTest::newRow("0*8") << raw("\x1b\0\0\0\0\0\0\0\0") << "0"; + QTest::newRow("-1*1") << raw("\x38\x00") << "-1"; + QTest::newRow("-1*2") << raw("\x39\x00\x00") << "-1"; + QTest::newRow("-1*4") << raw("\x3a\0\0\0\0") << "-1"; + QTest::newRow("-1*8") << raw("\x3b\0\0\0\0\0\0\0\0") << "-1"; + + QTest::newRow("simple0") << raw("\xe0") << "simple(0)"; + QTest::newRow("simple19") << raw("\xf3") << "simple(19)"; + QTest::newRow("false") << raw("\xf4") << "false"; + QTest::newRow("true") << raw("\xf5") << "true"; + QTest::newRow("null") << raw("\xf6") << "null"; + QTest::newRow("undefined") << raw("\xf7") << "undefined"; + QTest::newRow("simple32") << raw("\xf8\x20") << "simple(32)"; + QTest::newRow("simple255") << raw("\xf8\xff") << "simple(255)"; + + // floating point + + QTest::newRow("0.f16") << raw("\xf9\0\0") << "0.f16"; + QTest::newRow("0.f") << raw("\xfa\0\0\0\0") << "0.f"; + QTest::newRow("0.") << raw("\xfb\0\0\0\0\0\0\0\0") << "0."; + QTest::newRow("-1.f16") << raw("\xf9\xbc\x00") << "-1.f16"; + QTest::newRow("-1.f") << raw("\xfa\xbf\x80\0\0") << "-1.f"; + QTest::newRow("-1.") << raw("\xfb\xbf\xf0\0\0\0\0\0\0") << "-1."; + QTest::newRow("65504.f16") << raw("\xf9\x7b\xff") << "65504.f16"; + QTest::newRow("16777215.f") << raw("\xfa\x4b\x7f\xff\xff") << "16777215.f"; + QTest::newRow("16777215.") << raw("\xfb\x41\x6f\xff\xff\xe0\0\0\0") << "16777215."; + QTest::newRow("-16777215.f") << raw("\xfa\xcb\x7f\xff\xff") << "-16777215.f"; + QTest::newRow("-16777215.") << raw("\xfb\xc1\x6f\xff\xff\xe0\0\0\0") << "-16777215."; + + QTest::newRow("0.5f16") << raw("\xf9\x38\0") << "0.5f16"; + QTest::newRow("0.5f") << raw("\xfa\x3f\0\0\0") << "0.5f"; + QTest::newRow("0.5") << raw("\xfb\x3f\xe0\0\0\0\0\0\0") << "0.5"; + QTest::newRow("2.f16^11-1") << raw("\xf9\x67\xff") << "2047.f16"; + QTest::newRow("2.f^24-1") << raw("\xfa\x4b\x7f\xff\xff") << "16777215.f"; + QTest::newRow("2.^53-1") << raw("\xfb\x43\x3f\xff\xff""\xff\xff\xff\xff") << "9007199254740991."; + QTest::newRow("2.f^64-epsilon") << raw("\xfa\x5f\x7f\xff\xff") << "18446742974197923840.f"; + QTest::newRow("2.^64-epsilon") << raw("\xfb\x43\xef\xff\xff""\xff\xff\xff\xff") << "18446744073709549568."; + QTest::newRow("2.f^64") << raw("\xfa\x5f\x80\0\0") << "1.8446744073709552e+19f"; + QTest::newRow("2.^64") << raw("\xfb\x43\xf0\0\0\0\0\0\0") << "1.8446744073709552e+19"; + + QTest::newRow("nan_f16") << raw("\xf9\x7e\x00") << "nan"; + QTest::newRow("nan_f") << raw("\xfa\x7f\xc0\0\0") << "nan"; + QTest::newRow("nan") << raw("\xfb\x7f\xf8\0\0\0\0\0\0") << "nan"; + QTest::newRow("-inf_f16") << raw("\xf9\xfc\x00") << "-inf"; + QTest::newRow("-inf_f") << raw("\xfa\xff\x80\0\0") << "-inf"; + QTest::newRow("-inf") << raw("\xfb\xff\xf0\0\0\0\0\0\0") << "-inf"; + QTest::newRow("+inf_f16") << raw("\xf9\x7c\x00") << "inf"; + QTest::newRow("+inf_f") << raw("\xfa\x7f\x80\0\0") << "inf"; + QTest::newRow("+inf") << raw("\xfb\x7f\xf0\0\0\0\0\0\0") << "inf"; + +} + +void tst_Parser::fixed_data() +{ + addColumns(); + addFixedData(); +} + +void tst_Parser::fixed() +{ + QFETCH(QByteArray, data); + QFETCH(QString, expected); + + compareOne(data, expected); +} + +void addStringsData() +{ + // byte strings + QTest::newRow("emptybytestring") << raw("\x40") << "h''"; + QTest::newRow("bytestring1") << raw("\x41 ") << "h'20'"; + QTest::newRow("bytestring1-nul") << raw("\x41\0") << "h'00'"; + QTest::newRow("bytestring5") << raw("\x45Hello") << "h'48656c6c6f'"; + QTest::newRow("bytestring24") << raw("\x58\x18""123456789012345678901234") + << "h'313233343536373839303132333435363738393031323334'"; + QTest::newRow("bytestring256") << raw("\x59\1\0") + QByteArray(256, '3') + << "h'" + QString(256 * 2, '3') + '\''; + + // text strings + QTest::newRow("emptytextstring") << raw("\x60") << "\"\""; + QTest::newRow("textstring1") << raw("\x61 ") << "\" \""; + QTest::newRow("textstring1-nul") << raw("\x61\0") << "\"\\u0000\""; + QTest::newRow("textstring5") << raw("\x65Hello") << "\"Hello\""; + QTest::newRow("textstring24") << raw("\x78\x18""123456789012345678901234") + << "\"123456789012345678901234\""; + QTest::newRow("textstring256") << raw("\x79\1\0") + QByteArray(256, '3') + << '"' + QString(256, '3') + '"'; + + // strings with overlong length + QTest::newRow("emptybytestring*1") << raw("\x58\x00") << "h''"; + QTest::newRow("emptytextstring*1") << raw("\x78\x00") << "\"\""; + QTest::newRow("emptybytestring*2") << raw("\x59\x00\x00") << "h''"; + QTest::newRow("emptytextstring*2") << raw("\x79\x00\x00") << "\"\""; + QTest::newRow("emptybytestring*4") << raw("\x5a\0\0\0\0") << "h''"; + QTest::newRow("emptytextstring*4") << raw("\x7a\0\0\0\0") << "\"\""; + QTest::newRow("emptybytestring*8") << raw("\x5b\0\0\0\0\0\0\0\0") << "h''"; + QTest::newRow("emptytextstring*8") << raw("\x7b\0\0\0\0\0\0\0\0") << "\"\""; + QTest::newRow("bytestring5*1") << raw("\x58\x05Hello") << "h'48656c6c6f'"; + QTest::newRow("textstring5*1") << raw("\x78\x05Hello") << "\"Hello\""; + QTest::newRow("bytestring5*2") << raw("\x59\0\5Hello") << "h'48656c6c6f'"; + QTest::newRow("textstring5*2") << raw("\x79\0\x05Hello") << "\"Hello\""; + QTest::newRow("bytestring5*4") << raw("\x5a\0\0\0\5Hello") << "h'48656c6c6f'"; + QTest::newRow("textstring5*4") << raw("\x7a\0\0\0\x05Hello") << "\"Hello\""; + QTest::newRow("bytestring5*8") << raw("\x5b\0\0\0\0\0\0\0\5Hello") << "h'48656c6c6f'"; + QTest::newRow("textstring5*8") << raw("\x7b\0\0\0\0\0\0\0\x05Hello") << "\"Hello\""; + + // strings with undefined length + QTest::newRow("_emptybytestring") << raw("\x5f\xff") << "h''"; + QTest::newRow("_emptytextstring") << raw("\x7f\xff") << "\"\""; + QTest::newRow("_emptybytestring2") << raw("\x5f\x40\xff") << "h''"; + QTest::newRow("_emptytextstring2") << raw("\x7f\x60\xff") << "\"\""; + QTest::newRow("_emptybytestring3") << raw("\x5f\x40\x40\xff") << "h''"; + QTest::newRow("_emptytextstring3") << raw("\x7f\x60\x60\xff") << "\"\""; + QTest::newRow("_bytestring5*2") << raw("\x5f\x43Hel\x42lo\xff") << "h'48656c6c6f'"; + QTest::newRow("_textstring5*2") << raw("\x7f\x63Hel\x62lo\xff") << "\"Hello\""; + QTest::newRow("_bytestring5*5") << raw("\x5f\x41H\x41""e\x41l\x41l\x41o\xff") << "h'48656c6c6f'"; + QTest::newRow("_textstring5*5") << raw("\x7f\x61H\x61""e\x61l\x61l\x61o\xff") << "\"Hello\""; + QTest::newRow("_bytestring5*6") << raw("\x5f\x41H\x41""e\x40\x41l\x41l\x41o\xff") << "h'48656c6c6f'"; + QTest::newRow("_textstring5*6") << raw("\x7f\x61H\x61""e\x61l\x60\x61l\x61o\xff") << "\"Hello\""; +} + +void tst_Parser::strings_data() +{ + addColumns(); + addStringsData(); +} + +void addTagsData() +{ + // since parseOne() works recursively for tags, we can't test lone tags + QTest::newRow("tag0") << raw("\xc0\x00") << "0(0)"; + QTest::newRow("tag1") << raw("\xc1\x00") << "1(0)"; + QTest::newRow("tag24") << raw("\xd8\x18\x00") << "24(0)"; + QTest::newRow("tag255") << raw("\xd8\xff\x00") << "255(0)"; + QTest::newRow("tag256") << raw("\xd9\1\0\x00") << "256(0)"; + QTest::newRow("tag65535") << raw("\xd9\xff\xff\x00") << "65535(0)"; + QTest::newRow("tag65536") << raw("\xda\0\1\0\0\x00") << "65536(0)"; + QTest::newRow("tagUINT32_MAX-1") << raw("\xda\xff\xff\xff\xff\x00") << "4294967295(0)"; + QTest::newRow("tagUINT32_MAX") << raw("\xdb\0\0\0\1\0\0\0\0\x00") << "4294967296(0)"; + QTest::newRow("tagUINT64_MAX") << raw("\xdb" "\xff\xff\xff\xff" "\xff\xff\xff\xff" "\x00") + << QString::number(std::numeric_limits::max()) + "(0)"; + + // overlong tags + QTest::newRow("tag0*1") << raw("\xd8\0\x00") << "0(0)"; + QTest::newRow("tag0*2") << raw("\xd9\0\0\x00") << "0(0)"; + QTest::newRow("tag0*4") << raw("\xda\0\0\0\0\x00") << "0(0)"; + QTest::newRow("tag0*8") << raw("\xdb\0\0\0\0\0\0\0\0\x00") << "0(0)"; + + // tag other things + QTest::newRow("unixtime") << raw("\xc1\x1a\x55\x4b\xbf\xd3") << "1(1431027667)"; + QTest::newRow("rfc3339date") << raw("\xc0\x78\x19" "2015-05-07 12:41:07-07:00") + << "0(\"2015-05-07 12:41:07-07:00\")"; + QTest::newRow("tag6+false") << raw("\xc6\xf4") << "6(false)"; + QTest::newRow("tag25+true") << raw("\xd8\x19\xf5") << "25(true)"; + QTest::newRow("tag256+null") << raw("\xd9\1\0\xf6") << "256(null)"; + QTest::newRow("tag65536+simple32") << raw("\xda\0\1\0\0\xf8\x20") << "65536(simple(32))"; + QTest::newRow("float+unixtime") << raw("\xc1\xfa\x4e\xaa\x97\x80") << "1(1431027712.f)"; + QTest::newRow("double+unixtime") << raw("\xc1\xfb" "\x41\xd5\x52\xef" "\xf4\xc7\xce\xfe") + << "1(1431027667.1220088)"; +} + +void tst_Parser::tags_data() +{ + addColumns(); + addTagsData(); +} + +void tst_Parser::tagTags() +{ + QFETCH(QByteArray, data); + QFETCH(QString, expected); + + compareOne("\xd9\xd9\xf7" + data, "55799(" + expected + ')'); + if (!compareFailed) + compareOne("\xd9\xd9\xf7" "\xd9\xd9\xf7" + data, "55799(55799(" + expected + "))"); +} + +void addEmptyContainersData() +{ + QTest::newRow("emptyarray") << raw("\x80") << "[]" << 0; + QTest::newRow("emptymap") << raw("\xa0") << "{}" << 0; + QTest::newRow("_emptyarray") << raw("\x9f\xff") << "[_ ]" << -1; + QTest::newRow("_emptymap") << raw("\xbf\xff") << "{_ }" << -1; +} + +void tst_Parser::emptyContainers_data() +{ + addColumns(); + addEmptyContainersData(); +} + +void tst_Parser::emptyContainers() +{ + QFETCH(QByteArray, data); + QFETCH(QString, expected); + QFETCH(int, n); + + compareOneSize(n, data, expected); +} + +void tst_Parser::arrays_data() +{ + addColumns(); + addFixedData(); + addStringsData(); + addTagsData(); +} + +void tst_Parser::arrays() +{ + QFETCH(QByteArray, data); + QFETCH(QString, expected); + + compareOneSize(1, "\x81" + data, '[' + expected + ']'); + if (compareFailed) return; + + compareOneSize(2, "\x82" + data + data, '[' + expected + ", " + expected + ']'); + if (compareFailed) return; + + // overlong length + compareOneSize(1, "\x98\1" + data, '[' + expected + ']'); + if (compareFailed) return; + compareOneSize(1, raw("\x99\0\1") + data, '[' + expected + ']'); + if (compareFailed) return; + compareOneSize(1, raw("\x9a\0\0\0\1") + data, '[' + expected + ']'); + if (compareFailed) return; + compareOneSize(1, raw("\x9b\0\0\0\0\0\0\0\1") + data, '[' + expected + ']'); + if (compareFailed) return; + + // medium-sized array: 32 elements (1 << 5) + expected += ", "; + for (int i = 0; i < 5; ++i) { + data += data; + expected += expected; + } + expected.chop(2); // remove the last ", " + compareOneSize(32, "\x98\x20" + data, '[' + expected + ']'); + if (compareFailed) return; + + // large array: 256 elements (32 << 3) + expected += ", "; + for (int i = 0; i < 3; ++i) { + data += data; + expected += expected; + } + expected.chop(2); // remove the last ", " + compareOneSize(256, raw("\x99\1\0") + data, '[' + expected + ']'); + if (compareFailed) return; +} + +void tst_Parser::undefLengthArrays() +{ + QFETCH(QByteArray, data); + QFETCH(QString, expected); + + compareOne("\x9f" + data + "\xff", "[_ " + expected + ']'); + if (compareFailed) return; + + compareOne("\x9f" + data + data + "\xff", "[_ " + expected + ", " + expected + ']'); +} + +void tst_Parser::nestedArrays() +{ + QFETCH(QByteArray, data); + QFETCH(QString, expected); + + compareOneSize(1, "\x81\x81" + data, "[[" + expected + "]]"); + if (compareFailed) return; + + compareOneSize(1, "\x81\x81\x81" + data, "[[[" + expected + "]]]"); + if (compareFailed) return; + + compareOneSize(1, "\x81\x82" + data + data, "[[" + expected + ", " + expected + "]]"); + if (compareFailed) return; + + compareOneSize(2, "\x82\x81" + data + data, "[[" + expected + "], " + expected + "]"); + if (compareFailed) return; + + compareOneSize(2, "\x82\x81" + data + '\x81' + data, "[[" + expected + "], [" + expected + "]]"); + if (compareFailed) return; + + // undefined length + compareOneSize(-1, "\x9f\x9f" + data + data + "\xff\xff", "[_ [_ " + expected + ", " + expected + "]]"); + if (compareFailed) return; + + compareOneSize(-1, "\x9f\x9f" + data + "\xff\x9f" + data + "\xff\xff", "[_ [_ " + expected + "], [_ " + expected + "]]"); + if (compareFailed) return; + + compareOneSize(-1, "\x9f\x9f" + data + data + "\xff\x9f" + data + "\xff\xff", + "[_ [_ " + expected + ", " + expected + "], [_ " + expected + "]]"); + if (compareFailed) return; + + // mix them + compareOneSize(1, "\x81\x9f" + data + "\xff", "[[_ " + expected + "]]"); + if (compareFailed) return; + + compareOneSize(-1, "\x9f\x81" + data + "\xff", "[_ [" + expected + "]]"); +} + +void tst_Parser::maps_data() +{ + arrays_data(); +} + +void tst_Parser::maps() +{ + QFETCH(QByteArray, data); + QFETCH(QString, expected); + + // integer key + compareOneSize(1, "\xa1\1" + data, "{1: " + expected + '}'); + if (compareFailed) return; + + // string key + compareOneSize(1, "\xa1\x65" "Hello" + data, "{\"Hello\": " + expected + '}'); + if (compareFailed) return; + + // map to self + compareOneSize(1, "\xa1" + data + data, '{' + expected + ": " + expected + '}'); + if (compareFailed) return; + + // two integer keys + compareOneSize(2, "\xa2\1" + data + "\2" + data, "{1: " + expected + ", 2: " + expected + '}'); + if (compareFailed) return; + + // OneSize integer and OneSize string key + compareOneSize(2, "\xa2\1" + data + "\x65" "Hello" + data, "{1: " + expected + ", \"Hello\": " + expected + '}'); + if (compareFailed) return; +} + +void tst_Parser::undefLengthMaps() +{ + QFETCH(QByteArray, data); + QFETCH(QString, expected); + + // integer key + compareOne("\xbf\1" + data + '\xff', "{_ 1: " + expected + '}'); + if (compareFailed) return; + + compareOne("\xbf\1" + data + '\2' + data + '\xff', "{_ 1: " + expected + ", 2: " + expected + '}'); + if (compareFailed) return; + + compareOne("\xbf\1" + data + "\x65Hello" + data + '\xff', "{_ 1: " + expected + ", \"Hello\": " + expected + '}'); + if (compareFailed) return; + + compareOne("\xbf\x65Hello" + data + '\1' + data + '\xff', "{_ \"Hello\": " + expected + ", 1: " + expected + '}'); +} + +void tst_Parser::nestedMaps() +{ + QFETCH(QByteArray, data); + QFETCH(QString, expected); + + // nested maps as values + compareOneSize(1, "\xa1\1\xa1\2" + data, "{1: {2: " + expected + "}}"); + if (compareFailed) return; + + compareOneSize(1, "\xa1\x65Hello\xa1\2" + data, "{\"Hello\": {2: " + expected + "}}"); + if (compareFailed) return; + + compareOneSize(1, "\xa1\1\xa2\2" + data + '\x20' + data, "{1: {2: " + expected + ", -1: " + expected + "}}"); + if (compareFailed) return; + + compareOneSize(2, "\xa2\1\xa1\2" + data + "\2\xa1\x20" + data, "{1: {2: " + expected + "}, 2: {-1: " + expected + "}}"); + if (compareFailed) return; + + // nested maps as keys + compareOneSize(1, "\xa1\xa1\xf4" + data + "\xf5", "{{false: " + expected + "}: true}"); + if (compareFailed) return; + + compareOneSize(1, "\xa1\xa1" + data + data + "\xa1" + data + data, + "{{" + expected + ": " + expected + "}: {" + expected + ": " + expected + "}}"); + if (compareFailed) return; + + // undefined length + compareOneSize(-1, "\xbf\1\xbf\2" + data + "\xff\xff", "{_ 1: {_ 2: " + expected + "}}"); + if (compareFailed) return; + + compareOneSize(-1, "\xbf\1\xbf\2" + data + '\x20' + data + "\xff\xff", "{_ 1: {_ 2: " + expected + ", -1: " + expected + "}}"); + if (compareFailed) return; + + compareOneSize(-1, "\xbf\1\xbf\2" + data + "\xff\2\xbf\x20" + data + "\xff\xff", + "{_ 1: {_ 2: " + expected + "}, 2: {_ -1: " + expected + "}}"); + if (compareFailed) return; + + compareOneSize(-1, "\xbf\xbf" + data + data + "\xff\xbf" + data + data + "\xff\xff", + "{_ {_ " + expected + ": " + expected + "}: {_ " + expected + ": " + expected + "}}"); + if (compareFailed) return; + + // mix them + compareOneSize(1, "\xa1\1\xbf\2" + data + "\xff", "{1: {_ 2: " + expected + "}}"); + if (compareFailed) return; + + compareOneSize(-1, "\xbf\1\xa1\2" + data + "\xff", "{_ 1: {2: " + expected + "}}"); + if (compareFailed) return; +} + +void addMapMixedData() +{ + QTest::newRow("map-0-24") << raw("\xa1\0\x18\x18") << "{0: 24}" << 1; + QTest::newRow("map-0*1-24") << raw("\xa1\x18\0\x18\x18") << "{0: 24}" << 1; + QTest::newRow("map-0*1-24*2") << raw("\xa1\x18\0\x19\0\x18") << "{0: 24}" << 1; + QTest::newRow("map-0*4-24*2") << raw("\xa1\x1a\0\0\0\0\x19\0\x18") << "{0: 24}" << 1; + QTest::newRow("map-24-0") << raw("\xa1\x18\x18\0") << "{24: 0}" << 1; + QTest::newRow("map-24-0*1") << raw("\xa1\x18\x18\0") << "{24: 0}" << 1; + QTest::newRow("map-255-65535") << raw("\xa1\x18\xff\x19\xff\xff") << "{255: 65535}" << 1; + + QTest::newRow("_map-0-24") << raw("\xbf\0\x18\x18\xff") << "{_ 0: 24}" << 1; + QTest::newRow("_map-0*1-24") << raw("\xbf\x18\0\x18\x18\xff") << "{_ 0: 24}" << 1; + QTest::newRow("_map-0*1-24*2") << raw("\xbf\x18\0\x19\0\x18\xff") << "{_ 0: 24}" << 1; + QTest::newRow("_map-0*4-24*2") << raw("\xbf\x1a\0\0\0\0\x19\0\x18\xff") << "{_ 0: 24}" << 1; + QTest::newRow("_map-24-0") << raw("\xbf\x18\x18\0\xff") << "{_ 24: 0}" << 1; + QTest::newRow("_map-24-0*1") << raw("\xbf\x18\x18\0\xff") << "{_ 24: 0}" << 1; + QTest::newRow("_map-255-65535") << raw("\xbf\x18\xff\x19\xff\xff\xff") << "{_ 255: 65535}" << 1; +} + +void tst_Parser::mapMixed_data() +{ + addColumns(); + addMapMixedData(); +} + +void tst_Parser::mapsAndArrays() +{ + QFETCH(QByteArray, data); + QFETCH(QString, expected); + + // arrays of maps + compareOneSize(1, "\x81\xa1\1" + data, "[{1: " + expected + "}]"); + if (compareFailed) return; + + compareOneSize(2, "\x82\xa1\1" + data + "\xa1\2" + data, "[{1: " + expected + "}, {2: " + expected + "}]"); + if (compareFailed) return; + + compareOneSize(1, "\x81\xa2\1" + data + "\2" + data, "[{1: " + expected + ", 2: " + expected + "}]"); + if (compareFailed) return; + + compareOneSize(-1, "\x9f\xa1\1" + data + "\xff", "[_ {1: " + expected + "}]"); + if (compareFailed) return; + + compareOneSize(1, "\x81\xbf\1" + data + "\xff", "[{_ 1: " + expected + "}]"); + if (compareFailed) return; + + compareOneSize(-1, "\x9f\xbf\1" + data + "\xff\xff", "[_ {_ 1: " + expected + "}]"); + if (compareFailed) return; + + // maps of arrays + compareOneSize(1, "\xa1\1\x81" + data, "{1: [" + expected + "]}"); + if (compareFailed) return; + + compareOneSize(1, "\xa1\1\x82" + data + data, "{1: [" + expected + ", " + expected + "]}"); + if (compareFailed) return; + + compareOneSize(2, "\xa2\1\x81" + data + "\x65Hello\x81" + data, "{1: [" + expected + "], \"Hello\": [" + expected + "]}"); + if (compareFailed) return; + + compareOneSize(1, "\xa1\1\x9f" + data + "\xff", "{1: [_ " + expected + "]}"); + if (compareFailed) return; + + compareOneSize(1, "\xa1\1\x9f" + data + data + "\xff", "{1: [_ " + expected + ", " + expected + "]}"); + if (compareFailed) return; + + compareOneSize(-1, "\xbf\1\x81" + data + "\xff", "{_ 1: [" + expected + "]}"); + if (compareFailed) return; + + compareOneSize(-1, "\xbf\1\x9f" + data + "\xff\xff", "{_ 1: [_ " + expected + "]}"); + if (compareFailed) return; + + compareOneSize(-1, "\xbf\1\x9f" + data + data + "\xff\xff", "{_ 1: [_ " + expected + ", " + expected + "]}"); + if (compareFailed) return; + + // mixed with indeterminate length strings + compareOneSize(-1, "\xbf\1\x9f" + data + "\xff\x65Hello\xbf" + data + "\x7f\xff\xff\xff", + "{_ 1: [_ " + expected + "], \"Hello\": {_ " + expected + ": \"\"}}"); +} + +void tst_Parser::stringLength_data() +{ + QTest::addColumn("data"); + QTest::addColumn("expected"); + + QTest::newRow("emptybytestring") << raw("\x40") << 0; + QTest::newRow("bytestring1") << raw("\x41 ") << 1; + QTest::newRow("bytestring1-nul") << raw("\x41\0") << 1; + QTest::newRow("bytestring5") << raw("\x45Hello") << 5; + QTest::newRow("bytestring24") << raw("\x58\x18""123456789012345678901234") << 24; + QTest::newRow("bytestring256") << raw("\x59\1\0") + QByteArray(256, '3') << 256; + + // text strings + QTest::newRow("emptytextstring") << raw("\x60") << 0; + QTest::newRow("textstring1") << raw("\x61 ") << 1; + QTest::newRow("textstring1-nul") << raw("\x61\0") << 1; + QTest::newRow("textstring5") << raw("\x65Hello") << 5; + QTest::newRow("textstring24") << raw("\x78\x18""123456789012345678901234") << 24; + QTest::newRow("textstring256") << raw("\x79\1\0") + QByteArray(256, '3') << 256; + + // strings with overlong length + QTest::newRow("emptybytestring*1") << raw("\x58\x00") << 0; + QTest::newRow("emptytextstring*1") << raw("\x78\x00") << 0; + QTest::newRow("emptybytestring*2") << raw("\x59\x00\x00") << 0; + QTest::newRow("emptytextstring*2") << raw("\x79\x00\x00") << 0; + QTest::newRow("emptybytestring*4") << raw("\x5a\0\0\0\0") << 0; + QTest::newRow("emptytextstring*4") << raw("\x7a\0\0\0\0") << 0; + QTest::newRow("emptybytestring*8") << raw("\x5b\0\0\0\0\0\0\0\0") << 0; + QTest::newRow("emptytextstring*8") << raw("\x7b\0\0\0\0\0\0\0\0") << 0; + QTest::newRow("bytestring5*1") << raw("\x58\x05Hello") << 5; + QTest::newRow("textstring5*1") << raw("\x78\x05Hello") << 5; + QTest::newRow("bytestring5*2") << raw("\x59\0\5Hello") << 5; + QTest::newRow("textstring5*2") << raw("\x79\0\x05Hello") << 5; + QTest::newRow("bytestring5*4") << raw("\x5a\0\0\0\5Hello") << 5; + QTest::newRow("textstring5*4") << raw("\x7a\0\0\0\x05Hello") << 5; + QTest::newRow("bytestring5*8") << raw("\x5b\0\0\0\0\0\0\0\5Hello") << 5; + QTest::newRow("textstring5*8") << raw("\x7b\0\0\0\0\0\0\0\x05Hello") << 5; + + // strings with undefined length + QTest::newRow("_emptybytestring") << raw("\x5f\xff") << 0; + QTest::newRow("_emptytextstring") << raw("\x7f\xff") << 0; + QTest::newRow("_emptybytestring2") << raw("\x5f\x40\xff") << 0; + QTest::newRow("_emptytextstring2") << raw("\x7f\x60\xff") << 0; + QTest::newRow("_emptybytestring3") << raw("\x5f\x40\x40\xff") << 0; + QTest::newRow("_emptytextstring3") << raw("\x7f\x60\x60\xff") << 0; + QTest::newRow("_bytestring5*2") << raw("\x5f\x43Hel\x42lo\xff") << 5; + QTest::newRow("_textstring5*2") << raw("\x7f\x63Hel\x62lo\xff") << 5; + QTest::newRow("_bytestring5*5") << raw("\x5f\x41H\x41""e\x41l\x41l\x41o\xff") << 5; + QTest::newRow("_textstring5*5") << raw("\x7f\x61H\x61""e\x61l\x61l\x61o\xff") << 5; + QTest::newRow("_bytestring5*6") << raw("\x5f\x41H\x41""e\x40\x41l\x41l\x41o\xff") << 5; + QTest::newRow("_textstring5*6") << raw("\x7f\x61H\x61""e\x61l\x60\x61l\x61o\xff") << 5; +} + +void tst_Parser::stringLength() +{ + QFETCH(QByteArray, data); + QFETCH(int, expected); + + 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) + "\""); + + size_t result; + err = cbor_value_calculate_string_length(&value, &result); + QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); + QCOMPARE(result, size_t(expected)); +} + +void tst_Parser::stringCompare_data() +{ + QTest::addColumn("data"); + QTest::addColumn("string"); + QTest::addColumn("expected"); + + // compare empty to empty + QTest::newRow("empty-empty") << raw("\x60") << QString() << true; + QTest::newRow("_empty-empty") << raw("\x7f\xff") << QString() << true; + QTest::newRow("_empty*1-empty") << raw("\x7f\x60\xff") << QString() << true; + QTest::newRow("_empty*2-empty") << raw("\x7f\x60\x60\xff") << QString() << true; + + // compare empty to non-empty + QTest::newRow("empty-nonempty") << raw("\x60") << "Hello" << false; + QTest::newRow("_empty-nonempty") << raw("\x7f\xff") << "Hello" << false; + QTest::newRow("_empty*1-nonempty") << raw("\x7f\x60\xff") << "Hello" << false; + QTest::newRow("_empty*2-nonempty") << raw("\x7f\x60\x60\xff") << "Hello" << false; + + // compare same strings + QTest::newRow("same-short-short") << raw("\x65Hello") << "Hello" << true; + QTest::newRow("same-_short*1-short") << raw("\x7f\x65Hello\xff") << "Hello" << true; + QTest::newRow("same-_short*2-short") << raw("\x7f\x63Hel\x62lo\xff") << "Hello" << true; + QTest::newRow("same-_short*5-short") << raw("\x7f\x61H\x61""e\x61l\x61l\x61o\xff") << "Hello" << true; + QTest::newRow("same-_short*8-short") << raw("\x7f\x61H\x60\x61""e\x60\x61l\x61l\x60\x61o\xff") << "Hello" << true; + QTest::newRow("same-long-long") << raw("\x78\x2aGood morning, good afternoon and goodnight") + << "Good morning, good afternoon and goodnight" << true; + QTest::newRow("same-_long*1-long") << raw("\x7f\x78\x2aGood morning, good afternoon and goodnight\xff") + << "Good morning, good afternoon and goodnight" << true; + QTest::newRow("same-_long*2-long") << raw("\x7f\x78\x1cGood morning, good afternoon\x6e and goodnight\xff") + << "Good morning, good afternoon and goodnight" << true; + + // compare different strings (same length) + QTest::newRow("diff-same-length-short-short") << raw("\x65Hello") << "World" << false; + QTest::newRow("diff-same-length-_short*1-short") << raw("\x7f\x65Hello\xff") << "World" << false; + QTest::newRow("diff-same-length-_short*2-short") << raw("\x7f\x63Hel\x62lo\xff") << "World" << false; + QTest::newRow("diff-same-length-_short*5-short") << raw("\x7f\x61H\x61""e\x61l\x61l\x61o\xff") << "World" << false; + QTest::newRow("diff-same-length-_short*8-short") << raw("\x7f\x61H\x60\x61""e\x60\x61l\x61l\x60\x61o\xff") << "World" << false; + QTest::newRow("diff-same-length-long-long") << raw("\x78\x2aGood morning, good afternoon and goodnight") + << "Good morning, good afternoon and goodnight, world" << false; + QTest::newRow("diff-same-length-_long*1-long") << raw("\x7f\x78\x2aGood morning, good afternoon and goodnight\xff") + << "Good morning, good afternoon and goodnight, world" << false; + QTest::newRow("diff-same-length-_long*2-long") << raw("\x7f\x78\x1cGood morning, good afternoon\x6e and goodnight\xff") + << "Good morning, good afternoon and goodnight, world" << false; + + // compare different strings (different length) + QTest::newRow("diff-diff-length-short-short") << raw("\x65Hello") << "Hello World" << false; + QTest::newRow("diff-diff-length-_short*1-short") << raw("\x7f\x65Hello\xff") << "Hello World" << false; + QTest::newRow("diff-diff-length-_short*2-short") << raw("\x7f\x63Hel\x62lo\xff") << "Hello World" << false; + QTest::newRow("diff-diff-length-_short*5-short") << raw("\x7f\x61H\x61""e\x61l\x61l\x61o\xff") << "Hello World" << false; + QTest::newRow("diff-diff-length-_short*8-short") << raw("\x7f\x61H\x60\x61""e\x60\x61l\x61l\x60\x61o\xff") << "Hello World" << false; + QTest::newRow("diff-diff-length-long-long") << raw("\x78\x2aGood morning, good afternoon and goodnight") + << "Good morning, good afternoon and goodnight World" << false; + QTest::newRow("diff-diff-length-_long*1-long") << raw("\x7f\x78\x2aGood morning, good afternoon and goodnight\xff") + << "Good morning, good afternoon and goodnight World" << false; + QTest::newRow("diff-diff-length-_long*2-long") << raw("\x7f\x78\x1cGood morning, good afternoon\x6e and goodnight\xff") + << "Good morning, good afternoon and goodnight World" << false; + + // compare against non-strings + QTest::newRow("unsigned") << raw("\0") << "0" << false; + QTest::newRow("negative") << raw("\x20") << "-1" << false; + QTest::newRow("emptybytestring") << raw("\x40") << "" << false; + QTest::newRow("_emptybytestring") << raw("\x5f\xff") << "" << false; + QTest::newRow("shortbytestring") << raw("\x45Hello") << "Hello" << false; + QTest::newRow("longbytestring") << raw("\x58\x2aGood morning, good afternoon and goodnight") + << "Good morning, good afternoon and goodnight" << false; + QTest::newRow("emptyarray") << raw("\x80") << "" << false; + QTest::newRow("emptymap") << raw("\xa0") << "" << false; + QTest::newRow("array") << raw("\x81\x65Hello") << "Hello" << false; + QTest::newRow("map") << raw("\xa1\x65Hello\x65World") << "Hello World" << false; + QTest::newRow("false") << raw("\xf4") << "false" << false; + QTest::newRow("true") << raw("\xf5") << "true" << false; + QTest::newRow("null") << raw("\xf6") << "null" << false; +} + +void compareOneString(const QByteArray &data, const QString &string, bool expected, int line) +{ + compareFailed = true; + + 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) + "\""); + + bool result; + err = cbor_value_text_string_equals(&value, string.toUtf8().constData(), &result); + QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\""); + QCOMPARE(result, expected); + + compareFailed = false; +} +#define compareOneString(data, string, expected) compareOneString(data, string, expected, __LINE__) + +void tst_Parser::stringCompare() +{ + QFETCH(QByteArray, data); + QFETCH(QString, string); + QFETCH(bool, expected); + + compareOneString(data, string, expected); + if (compareFailed) return; + + // tag it + compareOneString("\xc1" + data, string, expected); + if (compareFailed) return; + + compareOneString("\xc1\xc2" + data, string, expected); +} + +void tst_Parser::mapFind_data() +{ + // Rules: + // we are searching for string "needle" + // if present, the value should be the string "haystack" (with tag 42) + + QTest::addColumn("data"); + QTest::addColumn("expected"); + + QTest::newRow("emptymap") << raw("\xa0") << false; + QTest::newRow("_emptymap") << raw("\xbf\xff") << false; + + // maps not containing our items + QTest::newRow("absent-unsigned-unsigned") << raw("\xa1\0\0") << false; + QTest::newRow("absent-taggedunsigned-unsigned") << raw("\xa1\xc0\0\0") << false; + QTest::newRow("absent-unsigned-taggedunsigned") << raw("\xa1\0\xc0\0") << false; + QTest::newRow("absent-taggedunsigned-taggedunsigned") << raw("\xa1\xc0\0\xc0\0") << false; + QTest::newRow("absent-string-unsigned") << raw("\xa1\x68haystack\0") << false; + QTest::newRow("absent-taggedstring-unsigned") << raw("\xa1\xc0\x68haystack\0") << false; + QTest::newRow("absent-string-taggedunsigned") << raw("\xa1\x68haystack\xc0\0") << false; + QTest::newRow("absent-taggedstring-taggedunsigned") << raw("\xa1\xc0\x68haystack\xc0\0") << false; + QTest::newRow("absent-string-string") << raw("\xa1\x68haystack\x66needle") << false; + QTest::newRow("absent-string-taggedstring") << raw("\xa1\x68haystack\xc0\x66needle") << false; + QTest::newRow("absent-taggedstring-string") << raw("\xa1\xc0\x68haystack\x66needle") << false; + QTest::newRow("absent-string-taggedstring") << raw("\xa1\xc0\x68haystack\xc0\x66needle") << false; + + QTest::newRow("absent-string-emptyarray") << raw("\xa1\x68haystack\x80") << false; + QTest::newRow("absent-string-_emptyarray") << raw("\xa1\x68haystack\x9f\xff") << false; + QTest::newRow("absent-string-array1") << raw("\xa1\x68haystack\x81\0") << false; + QTest::newRow("absent-string-array2") << raw("\xa1\x68haystack\x85\0\1\2\3\4") << false; + QTest::newRow("absent-string-array3") << raw("\xa1\x68haystack\x85\x63one\x63two\x65three\x64""four\x64""five") << false; + + QTest::newRow("absent-string-emptymap") << raw("\xa1\x68haystack\xa0") << false; + QTest::newRow("absent-string-_emptymap") << raw("\xa1\x68haystack\xbf\xff") << false; + QTest::newRow("absent-string-map") << raw("\xa1\x68haystack\xa1\x68haystack\x66needle") << false; + QTest::newRow("absent-string-map2") << raw("\xa1\x68haystack\xa1\x68haystack\x66needle\61z\62yx") << false; + + // maps containing our items + QTest::newRow("alone") << raw("\xa1\x66needle\xd8\x2a\x68haystack") << true; + QTest::newRow("tagged") << raw("\xa1\xc1\x66needle\xd8\x2a\x68haystack") << true; + QTest::newRow("doubletagged") << raw("\xa1\xc1\xc2\x66needle\xd8\x2a\x68haystack") << true; + QTest::newRow("chunked") << raw("\xa1\x7f\x66needle\xff\xd8\x2a\x68haystack") << true; + QTest::newRow("chunked*2") << raw("\xa1\x7f\x60\x66needle\xff\xd8\x2a\x68haystack") << true; + QTest::newRow("chunked*2bis") << raw("\xa1\x7f\x66needle\x60\xff\xd8\x2a\x68haystack") << true; + QTest::newRow("chunked*3") << raw("\xa1\x7f\x62ne\x62""ed\x62le\xff\xd8\x2a\x68haystack") << true; + QTest::newRow("chunked*8") << raw("\xa1\x7f\x61n\x61""e\x60\x61""e\x61""d\x60\x62le\x60\xff\xd8\x2a\x68haystack") << true; + + QTest::newRow("1before") << raw("\xa2\x68haystack\x66needle\x66needle\xd8\x2a\x68haystack") << true; + QTest::newRow("tagged-1before") << raw("\xa2\xc1\x68haystack\x66needle\xc1\x66needle\xd8\x2a\x68haystack") << true; + QTest::newRow("doubletagged-1before2") << raw("\xa2\xc1\xc2\x68haystack\x66needle\xc1\xc2\x66needle\xd8\x2a\x68haystack") << true; + + QTest::newRow("arraybefore") << raw("\xa2\x61z\x80\x66needle\xd8\x2a\x68haystack") << true; + QTest::newRow("nestedarraybefore") << raw("\xa2\x61z\x81\x81\0\x66needle\xd8\x2a\x68haystack") << true; + QTest::newRow("arrayarraybefore") << raw("\xa2\x82\1\2\x80\x66needle\xd8\x2a\x68haystack") << true; + + QTest::newRow("mapbefore") << raw("\xa2\x61z\xa0\x66needle\xd8\x2a\x68haystack") << true; + QTest::newRow("nestedmapbefore") << raw("\xa2\x61z\xa1\0\x81\0\x66needle\xd8\x2a\x68haystack") << true; + QTest::newRow("mapmapbefore") << raw("\xa2\xa1\1\2\xa0\x66needle\xd8\x2a\x68haystack") << true; +} + +void tst_Parser::mapFind() +{ + QFETCH(QByteArray, data); + QFETCH(bool, expected); + + 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) + "\""); + + CborValue element; + err = cbor_value_map_find_value(&value, "needle", &element); + QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); + + if (expected) { + QCOMPARE(int(element.type), int(CborTagType)); + + CborTag tag; + err = cbor_value_get_tag(&element, &tag); + QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); + QCOMPARE(int(tag), 42); + + bool equals; + err = cbor_value_text_string_equals(&element, "haystack", &equals); + QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); + QVERIFY(equals); + } else { + QCOMPARE(int(element.type), int(CborInvalidType)); + } +} + +void tst_Parser::validation_data() +{ + QTest::addColumn("data"); + QTest::addColumn("flags"); // future + QTest::addColumn("expectedError"); + QTest::addColumn("offset"); + + // illegal numbers are future extension points + QTest::newRow("illegal-number-in-unsigned-1") << raw("\x81\x1c") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-unsigned-2") << raw("\x81\x1d") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-unsigned-3") << raw("\x81\x1e") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-unsigned-4") << raw("\x81\x1f") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-negative-1") << raw("\x81\x3c") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-negative-2") << raw("\x81\x3d") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-negative-3") << raw("\x81\x3e") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-negative-4") << raw("\x81\x3f") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-bytearray-length-1") << raw("\x81\x5c") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-bytearray-length-2") << raw("\x81\x5d") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-bytearray-length-3") << raw("\x81\x5e") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-string-length-1") << raw("\x81\x7c") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-string-length-2") << raw("\x81\x7d") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-string-length-3") << raw("\x81\x7e") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-array-length-1") << raw("\x81\x9c") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-array-length-2") << raw("\x81\x9d") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-array-length-3") << raw("\x81\x9e") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-map-length-1") << raw("\x81\xbc") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-map-length-2") << raw("\x81\xbd") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("illegal-number-in-map-length-3") << raw("\x81\xbe") << 0 << CborErrorIllegalNumber << 1; + + QTest::newRow("number-too-short-1-0") << raw("\x81\x18") << 0 << CborErrorUnexpectedEOF << 1; // requires 1 byte, 0 given + QTest::newRow("number-too-short-2-0") << raw("\x81\x19") << 0 << CborErrorUnexpectedEOF << 1; // requires 2 bytes, 0 given + QTest::newRow("number-too-short-2-1") << raw("\x81\x19\x01") << 0 << CborErrorUnexpectedEOF << 1; // etc + QTest::newRow("number-too-short-4-0") << raw("\x81\x1a") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("number-too-short-4-3") << raw("\x81\x1a\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("number-too-short-8-0") << raw("\x81\x1b") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("number-too-short-8-7") << raw("\x81\x1b\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("bytearray-length-too-short-1-0") << raw("\x81\x38") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("bytearray-length-too-short-2-0") << raw("\x81\x39") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("bytearray-length-too-short-2-1") << raw("\x81\x39\x01") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("bytearray-length-too-short-4-0") << raw("\x81\x3a") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("bytearray-length-too-short-4-3") << raw("\x81\x3a\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("bytearray-length-too-short-8-0") << raw("\x81\x3b") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("bytearray-length-too-short-8-7") << raw("\x81\x3b\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("string-length-too-short-1-0") << raw("\x81\x58") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("string-length-too-short-2-0") << raw("\x81\x59") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("string-length-too-short-2-1") << raw("\x81\x59\x01") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("string-length-too-short-4-0") << raw("\x81\x5a") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("string-length-too-short-4-3") << raw("\x81\x5a\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("string-length-too-short-8-0") << raw("\x81\x5b") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("string-length-too-short-8-7") << raw("\x81\x5b\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("array-length-too-short-1-0") << raw("\x81\x98") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("array-length-too-short-2-0") << raw("\x81\x99") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("array-length-too-short-2-1") << raw("\x81\x99\x01") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("array-length-too-short-4-0") << raw("\x81\x9a") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("array-length-too-short-4-3") << raw("\x81\x9a\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("array-length-too-short-8-0") << raw("\x81\x9b") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("array-length-too-short-8-7") << raw("\x81\x9b\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("map-length-too-short-1-0") << raw("\x81\xb8") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("map-length-too-short-2-0") << raw("\x81\xb9") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("map-length-too-short-2-1") << raw("\x81\xb9\x01") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("map-length-too-short-4-0") << raw("\x81\xba") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("map-length-too-short-4-3") << raw("\x81\xba\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("map-length-too-short-8-0") << raw("\x81\xbb") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("map-length-too-short-8-7") << raw("\x81\xbb\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("tag-too-short-1-0") << raw("\x81\xd8") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("tag-too-short-2-0") << raw("\x81\xd9") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("tag-too-short-2-1") << raw("\x81\xd9\x01") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("tag-too-short-4-0") << raw("\x81\xda") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("tag-too-short-4-3") << raw("\x81\xda\x01\x02\x03") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("tag-too-short-8-0") << raw("\x81\xdb") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("tag-too-short-8-7") << raw("\x81\xdb\1\2\3\4\5\6\7") << 0 << CborErrorUnexpectedEOF << 1; + + QTest::newRow("bytearray-too-short1") << raw("\x81\x41") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("bytearray-too-short2") << raw("\x81\x58") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("bytearray-too-short3") << raw("\x81\x58\x01") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("bytearray-too-short4") << raw("\x81\x59") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("bytearray-too-short5") << raw("\x81\x5a\0\0\0\1") << 0 << CborErrorUnexpectedEOF << 1; - QTest::newRow("bytearray-too-short6") << raw("\x81\x5a\xff\xff\xff\xff\0\0\0\0") << 0 << CborErrorUnexpectedEOF << 1; - QTest::newRow("bytearray-too-short7") << raw("\x81\x5b\xff\xff\xff\xff\0\0\0\0") << 0 << CborErrorUnexpectedEOF << 1; ++ QTest::newRow("bytearray-too-short6") << raw("\x81\x5b\0\0\0\0\0\0\0\1") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("string-too-short1") << raw("\x81\x61") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("string-too-short2") << raw("\x81\x78") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("string-too-short3") << raw("\x81\x78\x01") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("string-too-short4") << raw("\x81\x79") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("string-too-short5") << raw("\x81\x7a\0\0\0\1") << 0 << CborErrorUnexpectedEOF << 1; - QTest::newRow("string-too-short6") << raw("\x81\x7a\xff\xff\xff\xff\0\0\0\0") << 0 << CborErrorUnexpectedEOF << 1; - QTest::newRow("string-too-short7") << raw("\x81\x7b\xff\xff\xff\xff\0\0\0\0") << 0 << CborErrorUnexpectedEOF << 1; ++ QTest::newRow("string-too-short6") << raw("\x81\x7b\0\0\0\0\0\0\0\1") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("fp16-too-short1") << raw("\x81\xf9") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("fp16-too-short2") << raw("\x81\xf9\x00") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("float-too-short1") << raw("\x81\xfa") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("float-too-short2") << raw("\x81\xfa\0\0\0") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("double-too-short1") << raw("\x81\xfb") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("double-too-short2") << raw("\x81\xfb\0\0\0\0\0\0\0") << 0 << CborErrorUnexpectedEOF << 1; + ++ // check for pointer additions wrapping over the limit of the address space ++ CborError tooLargeOn32bit = (sizeof(void *) == 4) ? CborErrorDataTooLarge : CborErrorUnexpectedEOF; ++ // on 32-bit systems, this is a -1 ++ QTest::newRow("bytearray-wraparound1") << raw("\x81\x5a\xff\xff\xff\xff") << 0 << CborErrorUnexpectedEOF << 1; ++ QTest::newRow("string-wraparound1") << raw("\x81\x7a\xff\xff\xff\xff") << 0 << CborErrorUnexpectedEOF << 1; ++ // on 32-bit systems, a 4GB addition could be dropped ++ QTest::newRow("bytearray-wraparound2") << raw("\x81\x5b\0\0\0\1\0\0\0\0") << 0 << tooLargeOn32bit << 1; ++ QTest::newRow("string-wraparound2") << raw("\x81\x7b\0\0\0\1\0\0\0\0") << 0 << tooLargeOn32bit << 1; ++ // on 64-bit systems, this could be a -1 ++ QTest::newRow("bytearray-wraparound3") << raw("\x81\x5b\xff\xff\xff\xff\xff\xff\xff\xff") << 0 << tooLargeOn32bit << 1; ++ QTest::newRow("string-wraparound3") << raw("\x81\x7b\xff\xff\xff\xff\xff\xff\xff\xff") << 0 << tooLargeOn32bit << 1; ++ ++ // ditto on chunks ++ QTest::newRow("bytearray-chunk-wraparound1") << raw("\x81\x5f\x5a\xff\xff\xff\xff") << 0 << CborErrorUnexpectedEOF << 1; ++ QTest::newRow("string-chunk-wraparound1") << raw("\x81\x7f\x7a\xff\xff\xff\xff") << 0 << CborErrorUnexpectedEOF << 1; ++ // on 32-bit systems, a 4GB addition could be dropped ++ QTest::newRow("bytearray-chunk-wraparound2") << raw("\x81\x5f\x5b\0\0\0\1\0\0\0\0") << 0 << tooLargeOn32bit << 1; ++ QTest::newRow("string-chunk-wraparound2") << raw("\x81\x7f\x7b\0\0\0\1\0\0\0\0") << 0 << tooLargeOn32bit << 1; ++ // on 64-bit systems, this could be a -1 ++ QTest::newRow("bytearray-chunk-wraparound3") << raw("\x81\x5f\x5b\xff\xff\xff\xff\xff\xff\xff\xff") << 0 << tooLargeOn32bit << 1; ++ QTest::newRow("string-chunk-wraparound3") << raw("\x81\x7f\x7b\xff\xff\xff\xff\xff\xff\xff\xff") << 0 << tooLargeOn32bit << 1; ++ + QTest::newRow("eof-after-array") << raw("\x81") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("eof-after-array2") << raw("\x81\x78\x20") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("eof-after-array-element") << raw("\x81\x82\x01") << 0 << CborErrorUnexpectedEOF << 3; + QTest::newRow("eof-after-object") << raw("\x81\xa1") << 0 << CborErrorUnexpectedEOF << 2; + QTest::newRow("eof-after-object2") << raw("\x81\xb8\x20") << 0 << CborErrorUnexpectedEOF << 3; + QTest::newRow("eof-after-object-key") << raw("\x81\xa1\x01") << 0 << CborErrorUnexpectedEOF << 3; + QTest::newRow("eof-after-object-value") << raw("\x81\xa2\x01\x01") << 0 << CborErrorUnexpectedEOF << 4; + QTest::newRow("eof-after-tag") << raw("\x81\xc0") << 0 << CborErrorUnexpectedEOF << 2; + QTest::newRow("eof-after-tag2") << raw("\x81\xd8\x20") << 0 << CborErrorUnexpectedEOF << 3; + + // major type 7 has future types + QTest::newRow("future-type-28") << raw("\x81\xfc") << 0 << CborErrorUnknownType << 1; + QTest::newRow("future-type-29") << raw("\x81\xfd") << 0 << CborErrorUnknownType << 1; + QTest::newRow("future-type-30") << raw("\x81\xfe") << 0 << CborErrorUnknownType << 1; + QTest::newRow("unexpected-break") << raw("\x81\xff") << 0 << CborErrorUnexpectedBreak << 1; + QTest::newRow("illegal-simple-0") << raw("\x81\xf8\0") << 0 << CborErrorIllegalSimpleType << 1; + QTest::newRow("illegal-simple-31") << raw("\x81\xf8\x1f") << 0 << CborErrorIllegalSimpleType << 1; + + // not only too big (UINT_MAX or UINT_MAX+1 in size), but also incomplete + if (sizeof(size_t) < sizeof(uint64_t)) { + QTest::newRow("bytearray-too-big1") << raw("\x81\x5b\0\0\0\1\0\0\0\0") << 0 << CborErrorDataTooLarge << 1; + QTest::newRow("string-too-big1") << raw("\x81\x7b\0\0\0\1\0\0\0\0") << 0 << CborErrorDataTooLarge << 1; + } + QTest::newRow("array-too-big1") << raw("\x81\x9a\xff\xff\xff\xff\0\0\0\0") << 0 << CborErrorDataTooLarge << 1; + QTest::newRow("array-too-big2") << raw("\x81\x9b\0\0\0\1\0\0\0\0") << 0 << CborErrorDataTooLarge << 1; + QTest::newRow("object-too-big1") << raw("\x81\xba\xff\xff\xff\xff\0\0\0\0") << 0 << CborErrorDataTooLarge << 1; + QTest::newRow("object-too-big2") << raw("\x81\xbb\0\0\0\1\0\0\0\0") << 0 << CborErrorDataTooLarge << 1; + + QTest::newRow("no-break-for-array0") << raw("\x81\x9f") << 0 << CborErrorUnexpectedEOF << 2; + QTest::newRow("no-break-for-array1") << raw("\x81\x9f\x01") << 0 << CborErrorUnexpectedEOF << 3; + QTest::newRow("no-break-string0") << raw("\x81\x7f") << 0 << CborErrorUnexpectedEOF << 1; + QTest::newRow("no-break-string1") << raw("\x81\x7f\x61Z") << 0 << CborErrorUnexpectedEOF << 1; + + QTest::newRow("nested-indefinite-length-bytearrays") << raw("\x81\x5f\x5f\xff\xff") << 0 << CborErrorIllegalNumber << 1; + QTest::newRow("nested-indefinite-length-strings") << raw("\x81\x5f\x5f\xff\xff") << 0 << CborErrorIllegalNumber << 1; + + QTest::newRow("string-chunk-unsigned") << raw("\x81\x7f\0\xff") << 0 << CborErrorIllegalType << 1; + QTest::newRow("string-chunk-bytearray") << raw("\x81\x7f\x40\xff") << 0 << CborErrorIllegalType << 1; + QTest::newRow("string-chunk-array") << raw("\x81\x7f\x80\xff") << 0 << CborErrorIllegalType << 1; + QTest::newRow("bytearray-chunk-unsigned") << raw("\x81\x5f\0\xff") << 0 << CborErrorIllegalType << 1; + QTest::newRow("bytearray-chunk-string") << raw("\x81\x5f\x60\xff") << 0 << CborErrorIllegalType << 1; + QTest::newRow("bytearray-chunk-array") << raw("\x81\x5f\x80\xff") << 0 << CborErrorIllegalType << 1; +} + +void tst_Parser::validation() +{ + QFETCH(QByteArray, data); + QFETCH(int, flags); + QFETCH(CborError, expectedError); + QFETCH(int, offset); + + 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) + "\""); + + err = parseOne(&first, &decoded); + QCOMPARE(int(err), int(expectedError)); + QCOMPARE(int(first.ptr - reinterpret_cast(data.constBegin())), offset); +} + +void tst_Parser::resumeParsing_data() +{ + addColumns(); + addFixedData(); + addStringsData(); + addTagsData(); + addMapMixedData(); +} + +void tst_Parser::resumeParsing() +{ + QFETCH(QByteArray, data); + QFETCH(QString, expected); + + 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; + err = parseOne(&first, &decoded); + } + if (err != CborErrorUnexpectedEOF) + qDebug() << "Length is" << len; + QCOMPARE(int(err), int(CborErrorUnexpectedEOF)); + } +} + +void tst_Parser::endPointer_data() +{ + QTest::addColumn("data"); + QTest::addColumn("offset"); + + QTest::newRow("number1") << raw("\x81\x01\x01") << 2; + QTest::newRow("number24") << raw("\x81\x18\x18\x01") << 3; + QTest::newRow("string") << raw("\x81\x61Z\x01") << 3; + QTest::newRow("indefinite-string") << raw("\x81\x7f\x61Z\xff\x01") << 5; + QTest::newRow("array") << raw("\x81\x02\x01") << 2; + QTest::newRow("indefinite-array") << raw("\x81\x9f\x02\xff\x01") << 4; + QTest::newRow("object") << raw("\x81\xa1\x03\x02\x01") << 4; + QTest::newRow("indefinite-object") << raw("\x81\xbf\x03\x02\xff\x01") << 5; +} + +void tst_Parser::endPointer() +{ + QFETCH(QByteArray, data); + QFETCH(int, offset); + + 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); +} + +void tst_Parser::recursionLimit_data() +{ + static const int recursions = CBOR_PARSER_MAX_RECURSIONS + 2; + QTest::addColumn("data"); + + QTest::newRow("array") << QByteArray(recursions, '\x81') + '\x20'; + QTest::newRow("_array") << QByteArray(recursions, '\x9f') + '\x20' + QByteArray(recursions, '\xff'); + + QByteArray data; + for (int i = 0; i < recursions; ++i) + data += "\xa1\x65Hello"; + data += '\2'; + QTest::newRow("map-recursive-values") << data; + + data.clear(); + for (int i = 0; i < recursions; ++i) + data += "\xbf\x65World"; + data += '\2'; + for (int i = 0; i < recursions; ++i) + data += "\xff"; + QTest::newRow("_map-recursive-values") << data; + + data = QByteArray(recursions, '\xa1'); + data += '\2'; + for (int i = 0; i < recursions; ++i) + data += "\x7f\x64quux\xff"; + QTest::newRow("map-recursive-keys") << data; + + data = QByteArray(recursions, '\xbf'); + data += '\2'; + for (int i = 0; i < recursions; ++i) + data += "\1\xff"; + QTest::newRow("_map-recursive-keys") << data; + + data.clear(); + for (int i = 0; i < recursions / 2; ++i) + data += "\x81\xa1\1"; + data += '\2'; + QTest::newRow("mixed") << data; +} + +void tst_Parser::recursionLimit() +{ + QFETCH(QByteArray, data); + + 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) + "\""); + + // check that it is valid: + CborValue it = first; + { + QString dummy; + err = parseOne(&it, &dummy); + QVERIFY2(!err, QByteArray("Got error \"") + cbor_error_string(err) + "\""); + } + + it = first; + err = cbor_value_advance(&it); + QCOMPARE(int(err), int(CborErrorNestingTooDeep)); + + it = first; + if (cbor_value_is_map(&it)) { + CborValue dummy; + err = cbor_value_map_find_value(&it, "foo", &dummy); + QCOMPARE(int(err), int(CborErrorNestingTooDeep)); + } +} + +QTEST_MAIN(tst_Parser) +#include "tst_parser.moc" diff --cc packaging/iotivity.spec index 82d22cf,0000000..ac06cee mode 100644,000000..100644 --- a/packaging/iotivity.spec +++ b/packaging/iotivity.spec @@@ -1,220 -1,0 +1,220 @@@ +Name: iotivity - Version: 1.0.0 ++Version: 1.0.1 +Release: 0 +Summary: IoT Connectivity sponsored by the OIC +Group: Network & Connectivity/Other +License: Apache-2.0 +URL: https://www.iotivity.org/ +Source0: %{name}-%{version}.tar.bz2 +Source1001: %{name}.manifest +Source1002: %{name}-test.manifest +BuildRequires: gettext-tools, expat-devel +BuildRequires: python, libcurl-devel +BuildRequires: scons +BuildRequires: openssl-devel +BuildRequires: boost-devel +BuildRequires: boost-thread +BuildRequires: boost-system +BuildRequires: boost-filesystem +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(uuid) +BuildRequires: pkgconfig(capi-network-wifi) +BuildRequires: pkgconfig(capi-network-bluetooth) +BuildRequires: pkgconfig(capi-appfw-app-common) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(sqlite3) +Requires(postun): /sbin/ldconfig +Requires(post): /sbin/ldconfig + + +## If tizen 2.x, RELEASE follows tizen_build_binary_release_type_eng. ## +## and if tizen 3.0, RELEASE follows tizen_build_devel_mode. ## +%if 0%{?tizen_build_devel_mode} == 1 || 0%{?tizen_build_binary_release_type_eng} == 1 +%define RELEASE False +%else +%define RELEASE True +%endif + +%{!?TARGET_TRANSPORT: %define TARGET_TRANSPORT IP,BT} +%{!?SECURED: %define SECURED 0} +%{!?LOGGING: %define LOGGING True} +%{!?ROUTING: %define ROUTING GW} + +%description +An open source reference implementation of the OIC standard specifications +IoTivity Base Libraries are included. + + +%package service +Summary: Development files for %{name} +Group: Network & Connectivity/Service +Requires: %{name} = %{version}-%{release} + +%description service +The %{name}-service package contains service libraries files for +developing applications that use %{name}-service. + +%package test +Summary: Development files for %{name} +Group: Network & Connectivity/Testing +Requires: %{name} = %{version}-%{release} + +%description test +The %{name}-test package contains example files to show +how the iotivity works using %{name}-test + +%package devel +Summary: Development files for %{name} +Group: Network & Connectivity/Development +Requires: %{name} = %{version}-%{release} +Requires: pkgconfig + +%description devel +The %{name}-devel package contains libraries and header files for +developing applications that use %{name}. + +%prep +%setup -q +chmod g-w %_sourcedir/* + +cp LICENSE.md LICENSE.APLv2 +cp %{SOURCE1001} . +%if 0%{?tizen_version_major} < 3 +cp %{SOURCE1002} . +%else +cp %{SOURCE1001} ./%{name}-test.manifest +%endif + +%build +%define RPM_ARCH %{_arch} + +%ifarch armv7l armv7hl armv7nhl armv7tnhl armv7thl +%define RPM_ARCH "armeabi-v7a" +%endif + +%ifarch aarch64 +%define RPM_ARCH "arm64" +%endif + +%ifarch x86_64 +%define RPM_ARCH "x86_64" +%endif + +%ifarch %{ix86} +%define RPM_ARCH "x86" +%endif + +#VERBOSE=1 +scons -j2 --prefix=%{_prefix} \ + TARGET_OS=tizen TARGET_ARCH=%{RPM_ARCH} TARGET_TRANSPORT=%{TARGET_TRANSPORT} \ + RELEASE=%{RELEASE} SECURED=%{SECURED} LOGGING=%{LOGGING} ROUTING=%{ROUTING} \ + LIB_INSTALL_DIR=%{_libdir} + + +%install +rm -rf %{buildroot} +CFLAGS="${CFLAGS:-%optflags}" ; export CFLAGS ; +scons install --install-sandbox=%{buildroot} --prefix=%{_prefix} \ + TARGET_OS=tizen TARGET_ARCH=%{RPM_ARCH} TARGET_TRANSPORT=%{TARGET_TRANSPORT} \ + RELEASE=%{RELEASE} SECURED=%{SECURED} LOGGING=%{LOGGING} ROUTING=%{ROUTING} \ + LIB_INSTALL_DIR=%{_libdir} + + +# For Example +%if %{RELEASE} == "True" +%define build_mode release +%else +%define build_mode debug +%endif +%define ex_install_dir %{buildroot}%{_bindir} +mkdir -p %{ex_install_dir} +cp out/tizen/*/%{build_mode}/examples/OICMiddle/OICMiddle %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/devicediscoveryclient %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/devicediscoveryserver %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/fridgeclient %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/fridgeserver %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/garageclient %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/garageserver %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/groupclient %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/groupserver %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/lightserver %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/presenceclient %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/presenceserver %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/roomclient %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/roomserver %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/simpleclient %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/simpleclientHQ %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/simpleclientserver %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/simpleserver %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/simpleserverHQ %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/threadingsample %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/oic_svr_db_server.json %{ex_install_dir} +cp out/tizen/*/%{build_mode}/resource/examples/oic_svr_db_client.json %{ex_install_dir} +%if 0%{?SECURED} == 1 +mkdir -p %{ex_install_dir}/provisioning +cp out/tizen/*/%{build_mode}/resource/provisioning/examples/oic_svr_db_client.json %{ex_install_dir}/provisioning/ +cp out/tizen/*/%{build_mode}/resource/provisioning/examples/provisioningclient %{ex_install_dir}/provisioning/ +%endif + +# For iotcon +cp resource/csdk/stack/include/ocpayload.h %{buildroot}%{_includedir}/resource - cp resource/csdk/ocrandom/include/ocrandom.h %{buildroot}%{_includedir}/resource ++cp resource/c_common/ocrandom/include/ocrandom.h %{buildroot}%{_includedir}/resource + +%if 0%{?tizen_version_major} < 3 +mkdir -p %{buildroot}/%{_datadir}/license +cp LICENSE.APLv2 %{buildroot}/%{_datadir}/license/%{name} +cp LICENSE.APLv2 %{buildroot}/%{_datadir}/license/%{name}-service +cp LICENSE.APLv2 %{buildroot}/%{_datadir}/license/%{name}-test +%endif + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files +%manifest %{name}.manifest +%defattr(-,root,root,-) +%{_libdir}/liboc.so +%{_libdir}/liboc_logger.so +%{_libdir}/liboc_logger_core.so +%{_libdir}/liboctbstack.so +%{_libdir}/libconnectivity_abstraction.so +%if 0%{?tizen_version_major} < 3 +%{_datadir}/license/%{name} +%else +%license LICENSE.APLv2 +%endif + +%files service +%manifest %{name}.manifest +%defattr(-,root,root,-) +%{_libdir}/libBMISensorBundle.so +%{_libdir}/libDISensorBundle.so +%{_libdir}/libresource_hosting.so +%{_libdir}/libTGMSDKLibrary.so +%{_libdir}/libHueBundle.so +%{_libdir}/librcs_client.so +%{_libdir}/librcs_common.so +%{_libdir}/librcs_container.so +%{_libdir}/librcs_server.so +%if 0%{?tizen_version_major} < 3 +%{_datadir}/license/%{name}-service +%else +%license LICENSE.APLv2 +%endif + +%files test +%manifest %{name}-test.manifest +%defattr(-,root,root,-) +%{_bindir}/* +%if 0%{?tizen_version_major} < 3 +%{_datadir}/license/%{name}-test +%else +%license LICENSE.APLv2 +%endif + +%files devel +%defattr(-,root,root,-) +%{_libdir}/lib*.a +%{_libdir}/pkgconfig/%{name}.pc +%{_includedir}/* diff --cc resource/c_common/SConscript index 775a0b6,9bb80dc..a9682b9 --- a/resource/c_common/SConscript +++ b/resource/c_common/SConscript @@@ -52,4 -59,3 +59,4 @@@ common_src = commonlib = common_env.StaticLibrary('c_common', common_src) common_env.InstallTarget(commonlib, 'c_common') common_env.UserInstallTargetLib(commonlib, 'c_common') - common_env.UserInstallTargetHeader('platform_features.h', 'resource', 'platform_features.h') ++common_env.UserInstallTargetHeader('platform_features.h', 'resource', 'platform_features.h') diff --cc resource/csdk/connectivity/src/SConscript index 8c4309c,367590a..367590a mode 100644,100755..100644 --- a/resource/csdk/connectivity/src/SConscript +++ b/resource/csdk/connectivity/src/SConscript