Merge remote-tracking branch 'cabo/master'
diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f1c9628 --- /dev/null +++ b/.travis.yml
@@ -0,0 +1,14 @@ +language: c +compiler: +- clang +- gcc +sudo: false +before_install: +- wget http://www.cmake.org/files/v3.3/cmake-3.3.1-Linux-x86_64.tar.gz -O /tmp/cmake.tar.gz +- tar xzf /tmp/cmake.tar.gz +- export PATH=$PWD/cmake-3.3.1-Linux-x86_64/bin/:$PATH +script: +- "./build.sh all test" +notifications: + slack: + secure: WdgYxQrnFR5eu/eKygPuLjlFsuZxD9m2PLRWTLT85aj+18Gp2ooPjnI9UFdb1xY87+4InhWk6PvQU35j4bG0etPQtX+0H4T4Zdk/aD6KxgJBHIYGqtfZUMmdFfVpUH9cCPx99Jjw81mhKrxM+6rXiZdiWXuNhvbJOApRT6uxE2k=
diff --git a/CMakeLists.txt b/CMakeLists.txt index 67b9d95..195c780 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt
@@ -23,6 +23,7 @@ option ( coveralls "Generate coveralls data" ON ) option ( coveralls_send "Send data to coveralls site" OFF ) option ( build_docs "Create docs using Doxygen" ${DOXYGEN_FOUND} ) +option ( no_floats "Build without floating point support" OFF ) set ( dist_dir ${CMAKE_BINARY_DIR}/dist ) set ( prefix ${CMAKE_INSTALL_PREFIX} ) @@ -70,6 +71,10 @@ message ( FATAL_ERROR "unhandled compiler id: ${CMAKE_C_COMPILER_ID}" ) endif () +if ( no_floats ) + add_definitions(-DCBOR_NO_FLOAT) +endif() + if ( verbose ) set ( CMAKE_VERBOSE_MAKEFILE ON ) endif ()
diff --git a/README.md b/README.md index 9b57776..5820858 100644 --- a/README.md +++ b/README.md
@@ -1,3 +1,5 @@ +[](https://travis-ci.org/cabo/cn-cbor) + # cn-cbor: A constrained node implementation of CBOR in C This is a constrained node implementation of [CBOR](http://cbor.io) in
diff --git a/build.sh b/build.sh index a07f37f..69dd2e9 100755 --- a/build.sh +++ b/build.sh
@@ -1,3 +1,4 @@ +#!/bin/sh if [ ! -d "build" ]; then mkdir build fi
diff --git a/include/cn-cbor/cn-cbor.h b/include/cn-cbor/cn-cbor.h index 553aa55..2973581 100644 --- a/include/cn-cbor/cn-cbor.h +++ b/include/cn-cbor/cn-cbor.h
@@ -131,7 +131,10 @@ /** An invalid parameter was passed to a function */ CN_CBOR_ERR_INVALID_PARAMETER, /** Allocation failed */ - CN_CBOR_ERR_OUT_OF_MEMORY + CN_CBOR_ERR_OUT_OF_MEMORY, + /** A float was encountered during parse but the library was built without + support for float types. */ + CN_CBOR_ERR_FLOAT_NOT_SUPPORTED } cn_cbor_error; /** @@ -213,7 +216,7 @@ * @param[out] errp Error, if NULL is returned * @return The parsed CBOR structure, or NULL on error */ -const cn_cbor* cn_cbor_decode(const uint8_t *buf, size_t len CBOR_CONTEXT, cn_cbor_errback *errp); +cn_cbor* cn_cbor_decode(const uint8_t *buf, size_t len CBOR_CONTEXT, cn_cbor_errback *errp); /** * Get a value from a CBOR map that has the given string as a key. @@ -222,7 +225,7 @@ * @param[in] key The string to look up in the map * @return The matching value, or NULL if the key is not found */ -const cn_cbor* cn_cbor_mapget_string(const cn_cbor* cb, const char* key); +cn_cbor* cn_cbor_mapget_string(const cn_cbor* cb, const char* key); /** * Get a value from a CBOR map that has the given integer as a key. @@ -231,7 +234,7 @@ * @param[in] key The int to look up in the map * @return The matching value, or NULL if the key is not found */ -const cn_cbor* cn_cbor_mapget_int(const cn_cbor* cb, int key); +cn_cbor* cn_cbor_mapget_int(const cn_cbor* cb, int key); /** * Get the item with the given index from a CBOR array. @@ -240,15 +243,17 @@ * @param[in] idx The array index * @return The matching value, or NULL if the index is invalid */ -const cn_cbor* cn_cbor_index(const cn_cbor* cb, unsigned int idx); +cn_cbor* cn_cbor_index(const cn_cbor* cb, unsigned int idx); /** * Free the given CBOR structure. + * You MUST NOT try to free a cn_cbor structure with a parent (i.e., one + * that is not a root in the tree). * - * @param[in] cb The CBOR value to free + * @param[in] cb The CBOR value to free. May be NULL, or a root object. * @param[in] CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined) */ -void cn_cbor_free(const cn_cbor* cb CBOR_CONTEXT); +void cn_cbor_free(cn_cbor* cb CBOR_CONTEXT); /** * Write a CBOR value and all of the child values. @@ -260,10 +265,10 @@ * @param[in] cb [description] * @return -1 on fail, or number of bytes written */ -ssize_t cbor_encoder_write(uint8_t *buf, - size_t buf_offset, - size_t buf_size, - const cn_cbor *cb); +ssize_t cn_cbor_encoder_write(uint8_t *buf, + size_t buf_offset, + size_t buf_size, + const cn_cbor *cb); /** * Create a CBOR map.
diff --git a/src/cn-cbor.c b/src/cn-cbor.c index 5804720..a7677ae 100644 --- a/src/cn-cbor.c +++ b/src/cn-cbor.c
@@ -20,8 +20,9 @@ #define CN_CBOR_FAIL(code) do { pb->err = code; goto fail; } while(0) -void cn_cbor_free(const cn_cbor* cb CBOR_CONTEXT) { - cn_cbor* p = (cn_cbor*) cb; +void cn_cbor_free(cn_cbor* cb CBOR_CONTEXT) { + cn_cbor* p = cb; + assert(!p || !p->parent); while (p) { cn_cbor* p1; while ((p1 = p->first_child)) { /* go down */ @@ -36,6 +37,7 @@ } } +#ifndef CBOR_NO_FLOAT static double decode_half(int half) { int exp = (half >> 10) & 0x1f; int mant = half & 0x3ff; @@ -45,6 +47,7 @@ else val = mant == 0 ? INFINITY : NAN; return half & 0x8000 ? -val : val; } +#endif /* CBOR_NO_FLOAT */ /* Fix these if you can't do non-aligned reads */ #define ntoh8p(p) (*(unsigned char*)(p)) @@ -85,6 +88,7 @@ int ai; uint64_t val; cn_cbor* cb = NULL; +#ifndef CBOR_NO_FLOAT union { float f; uint32_t u; @@ -93,6 +97,7 @@ double d; uint64_t u; } u64; +#endif /* CBOR_NO_FLOAT */ again: TAKE(pos, ebuf, 1, ib = ntoh8p(pos) ); @@ -174,16 +179,31 @@ case VAL_TRUE: cb->type = CN_CBOR_TRUE; break; case VAL_NIL: cb->type = CN_CBOR_NULL; break; case VAL_UNDEF: cb->type = CN_CBOR_UNDEF; break; - case AI_2: cb->type = CN_CBOR_DOUBLE; cb->v.dbl = decode_half(val); break; + case AI_2: +#ifndef CBOR_NO_FLOAT + cb->type = CN_CBOR_DOUBLE; + cb->v.dbl = decode_half(val); +#else /* CBOR_NO_FLOAT */ + CN_CBOR_FAIL(CN_CBOR_ERR_FLOAT_NOT_SUPPORTED); +#endif /* CBOR_NO_FLOAT */ + break; case AI_4: +#ifndef CBOR_NO_FLOAT cb->type = CN_CBOR_DOUBLE; u32.u = val; cb->v.dbl = u32.f; +#else /* CBOR_NO_FLOAT */ + CN_CBOR_FAIL(CN_CBOR_ERR_FLOAT_NOT_SUPPORTED); +#endif /* CBOR_NO_FLOAT */ break; case AI_8: +#ifndef CBOR_NO_FLOAT cb->type = CN_CBOR_DOUBLE; u64.u = val; cb->v.dbl = u64.d; +#else /* CBOR_NO_FLOAT */ + CN_CBOR_FAIL(CN_CBOR_ERR_FLOAT_NOT_SUPPORTED); +#endif /* CBOR_NO_FLOAT */ break; default: cb->v.uint = val; } @@ -218,7 +238,7 @@ return 0; } -const cn_cbor* cn_cbor_decode(const unsigned char* buf, size_t len CBOR_CONTEXT, cn_cbor_errback *errp) { +cn_cbor* cn_cbor_decode(const unsigned char* buf, size_t len CBOR_CONTEXT, cn_cbor_errback *errp) { cn_cbor catcher = {CN_CBOR_INVALID, 0, {0}, 0, NULL, NULL, NULL, NULL}; struct parse_buf pb; cn_cbor* ret;
diff --git a/src/cn-encoder.c b/src/cn-encoder.c index 3182409..3365535 100644 --- a/src/cn-encoder.c +++ b/src/cn-encoder.c
@@ -112,6 +112,7 @@ } } +#ifndef CBOR_NO_FLOAT static void _write_double(cn_write_state *ws, double val) { float float_val = val; @@ -173,6 +174,7 @@ } } +#endif /* CBOR_NO_FLOAT */ // TODO: make public? typedef void (*cn_visit_func)(const cn_cbor *cb, int depth, void *context); @@ -270,7 +272,9 @@ break; case CN_CBOR_DOUBLE: +#ifndef CBOR_NO_FLOAT CHECK(_write_double(ws, cb->v.dbl)); +#endif /* CBOR_NO_FLOAT */ break; case CN_CBOR_INVALID: @@ -287,10 +291,10 @@ write_byte_ensured(IB_BREAK); } -ssize_t cbor_encoder_write(uint8_t *buf, - size_t buf_offset, - size_t buf_size, - const cn_cbor *cb) +ssize_t cn_cbor_encoder_write(uint8_t *buf, + size_t buf_offset, + size_t buf_size, + const cn_cbor *cb) { cn_write_state ws = { buf, buf_offset, buf_size }; _visit(cb, _encoder_visitor, _encoder_breaker, &ws);
diff --git a/src/cn-error.c b/src/cn-error.c index d4407d0..4953cc9 100644 --- a/src/cn-error.c +++ b/src/cn-error.c
@@ -8,5 +8,6 @@ "CN_CBOR_ERR_RESERVED_AI", "CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING", "CN_CBOR_ERR_INVALID_PARAMETER", - "CN_CBOR_ERR_OUT_OF_MEMORY" + "CN_CBOR_ERR_OUT_OF_MEMORY", + "CN_CBOR_ERR_FLOAT_NOT_SUPPORTED" };
diff --git a/src/cn-get.c b/src/cn-get.c index f4585b9..cc276a5 100644 --- a/src/cn-get.c +++ b/src/cn-get.c
@@ -4,7 +4,7 @@ #include "cn-cbor/cn-cbor.h" -const cn_cbor* cn_cbor_mapget_int(const cn_cbor* cb, int key) { +cn_cbor* cn_cbor_mapget_int(const cn_cbor* cb, int key) { cn_cbor* cp; assert(cb); for (cp = cb->first_child; cp && cp->next; cp = cp->next->next) { @@ -25,7 +25,7 @@ return NULL; } -const cn_cbor* cn_cbor_mapget_string(const cn_cbor* cb, const char* key) { +cn_cbor* cn_cbor_mapget_string(const cn_cbor* cb, const char* key) { cn_cbor *cp; int keylen; assert(cb); @@ -48,7 +48,7 @@ return NULL; } -const cn_cbor* cn_cbor_index(const cn_cbor* cb, unsigned int idx) { +cn_cbor* cn_cbor_index(const cn_cbor* cb, unsigned int idx) { cn_cbor *cp; unsigned int i = 0; assert(cb);
diff --git a/test/cbor_test.c b/test/cbor_test.c index 4918a87..3326497 100644 --- a/test/cbor_test.c +++ b/test/cbor_test.c
@@ -60,6 +60,7 @@ ASSERT_STR(cn_cbor_error_str[CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING], "CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING"); ASSERT_STR(cn_cbor_error_str[CN_CBOR_ERR_INVALID_PARAMETER], "CN_CBOR_ERR_INVALID_PARAMETER"); ASSERT_STR(cn_cbor_error_str[CN_CBOR_ERR_OUT_OF_MEMORY], "CN_CBOR_ERR_OUT_OF_MEMORY"); + ASSERT_STR(cn_cbor_error_str[CN_CBOR_ERR_FLOAT_NOT_SUPPORTED], "CN_CBOR_ERR_FLOAT_NOT_SUPPORTED"); } CTEST(cbor, parse) @@ -92,6 +93,7 @@ "f6", // null "f7", // undefined "f8ff", // simple(255) +#ifndef CBOR_NO_FLOAT "f93c00", // 1.0 "f9bc00", // -1.0 "f903ff", // 6.097555160522461e-05 @@ -101,6 +103,7 @@ "fa47800000", // 65536.0 "fb3ff199999999999a", // 1.1 "f97e00", // NaN +#endif /* CBOR_NO_FLOAT */ "5f42010243030405ff", // (_ h'0102', h'030405') "7f61616161ff", // (_ "a", "a") "9fff", // [_ ] @@ -108,7 +111,7 @@ "9f009f00ff00ff", // [_ 0, [_ 0], 0] "bf61610161629f0203ffff", // {_ "a": 1, "b": [_ 2, 3]} }; - const cn_cbor *cb; + cn_cbor *cb; buffer b; size_t i; unsigned char encoded[1024]; @@ -122,7 +125,7 @@ ASSERT_EQUAL(err.err, CN_CBOR_NO_ERROR); ASSERT_NOT_NULL(cb); - enc_sz = cbor_encoder_write(encoded, 0, sizeof(encoded), cb); + enc_sz = cn_cbor_encoder_write(encoded, 0, sizeof(encoded), cb); ASSERT_DATA(b.ptr, b.sz, encoded, enc_sz); free(b.ptr); cn_cbor_free(cb CONTEXT_NULL); @@ -133,7 +136,7 @@ CTEST(cbor, parse_normalize) { cn_cbor_errback err; - char *tests[] = { + char *basic_tests[] = { "00", "00", // 0 "1800", "00", "1818", "1818", @@ -146,6 +149,8 @@ "c600", "c600", // 6(0) (undefined tag) "d80600", "c600", "d9000600", "c600", + }; + char *float_tests[] = { "fb3ff0000000000000", "f93c00", // 1.0 "fbbff0000000000000", "f9bc00", // -1.0 "fb40f86a0000000000", "fa47c35000", // 100000.0 @@ -154,27 +159,48 @@ "fb3e78000000000000", "fa33c00000", // 8.940696716308594e-08 "fb3e80000000000000", "f90002", // 1.1920928955078125e-07 }; - const cn_cbor *cb; + cn_cbor *cb; buffer b, b2; size_t i; unsigned char encoded[1024]; ssize_t enc_sz; - for (i=0; i<sizeof(tests)/sizeof(char*); ) { - ASSERT_TRUE(parse_hex(tests[i++], &b)); - ASSERT_TRUE(parse_hex(tests[i++], &b2)); + for (i=0; i<sizeof(basic_tests)/sizeof(char*); i+=2) { + ASSERT_TRUE(parse_hex(basic_tests[i], &b)); + ASSERT_TRUE(parse_hex(basic_tests[i+1], &b2)); err.err = CN_CBOR_NO_ERROR; cb = cn_cbor_decode(b.ptr, b.sz CONTEXT_NULL, &err); - CTEST_LOG("%s: %s", tests[i], cn_cbor_error_str[err.err]); + CTEST_LOG("%s: %s", basic_tests[i], cn_cbor_error_str[err.err]); ASSERT_EQUAL(err.err, CN_CBOR_NO_ERROR); ASSERT_NOT_NULL(cb); - enc_sz = cbor_encoder_write(encoded, 0, sizeof(encoded), cb); + enc_sz = cn_cbor_encoder_write(encoded, 0, sizeof(encoded), cb); ASSERT_DATA(b2.ptr, b2.sz, encoded, enc_sz); free(b.ptr); free(b2.ptr); cn_cbor_free(cb CONTEXT_NULL); } + + for (i=0; i<sizeof(float_tests)/sizeof(char*); i+=2) { + ASSERT_TRUE(parse_hex(float_tests[i], &b)); + ASSERT_TRUE(parse_hex(float_tests[i+1], &b2)); + err.err = CN_CBOR_NO_ERROR; + cb = cn_cbor_decode(b.ptr, b.sz CONTEXT_NULL, &err); + CTEST_LOG("%s: %s", float_tests[i], cn_cbor_error_str[err.err]); +#ifndef CBOR_NO_FLOAT + ASSERT_EQUAL(err.err, CN_CBOR_NO_ERROR); + ASSERT_NOT_NULL(cb); +#else /* CBOR_NO_FLOAT */ + ASSERT_EQUAL(err.err, CN_CBOR_ERR_FLOAT_NOT_SUPPORTED); + ASSERT_NULL(cb); +#endif /* CBOR_NO_FLOAT */ + + /* enc_sz = cn_cbor_encoder_write(encoded, 0, sizeof(encoded), cb); */ + /* ASSERT_DATA(b2.ptr, b2.sz, encoded, enc_sz); */ + free(b.ptr); + free(b2.ptr); + cn_cbor_free(cb CONTEXT_NULL); + } } typedef struct _cbor_failure @@ -195,13 +221,13 @@ {"1c", CN_CBOR_ERR_RESERVED_AI}, {"7f4100", CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING}, }; - const cn_cbor *cb; + cn_cbor *cb; buffer b; size_t i; uint8_t buf[10]; cn_cbor inv = {CN_CBOR_INVALID, 0, {0}, 0, NULL, NULL, NULL, NULL}; - ASSERT_EQUAL(-1, cbor_encoder_write(buf, 0, sizeof(buf), &inv)); + ASSERT_EQUAL(-1, cn_cbor_encoder_write(buf, 0, sizeof(buf), &inv)); for (i=0; i<sizeof(tests)/sizeof(cbor_failure); i++) { ASSERT_TRUE(parse_hex(tests[i].hex, &b)); @@ -217,6 +243,7 @@ // Decoder loses float size information CTEST(cbor, float) { +#ifndef CBOR_NO_FLOAT cn_cbor_errback err; char *tests[] = { "f90001", // 5.960464477539063e-08 @@ -226,7 +253,7 @@ "f9fc00", // -Inf "f97c00", // Inf }; - const cn_cbor *cb; + cn_cbor *cb; buffer b; size_t i; unsigned char encoded[1024]; @@ -237,19 +264,20 @@ cb = cn_cbor_decode(b.ptr, b.sz CONTEXT_NULL, &err); ASSERT_NOT_NULL(cb); - enc_sz = cbor_encoder_write(encoded, 0, sizeof(encoded), cb); + enc_sz = cn_cbor_encoder_write(encoded, 0, sizeof(encoded), cb); ASSERT_DATA(b.ptr, b.sz, encoded, enc_sz); free(b.ptr); cn_cbor_free(cb CONTEXT_NULL); } +#endif /* CBOR_NO_FLOAT */ } CTEST(cbor, getset) { buffer b; - const cn_cbor *cb; - const cn_cbor *val; + cn_cbor *cb; + cn_cbor *val; cn_cbor_errback err; ASSERT_TRUE(parse_hex("a40000436363630262626201616100", &b)); @@ -397,6 +425,6 @@ ASSERT_NOT_NULL(cdata); ASSERT_TRUE(cn_cbor_mapput_int(map, 0, cdata, CONTEXT_NULL_COMMA NULL)); - enc_sz = cbor_encoder_write(encoded, 0, sizeof(encoded), map); + enc_sz = cn_cbor_encoder_write(encoded, 0, sizeof(encoded), map); ASSERT_EQUAL(7, enc_sz); }
diff --git a/test/test.c b/test/test.c index 42c6cf6..d24992f 100644 --- a/test/test.c +++ b/test/test.c
@@ -98,6 +98,7 @@ "CN_CBOR_ERR_RESERVED_AI", "CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING", "CN_CBOR_ERR_OUT_OF_MEMORY", + "CN_CBOR_ERR_FLOAT_NOT_SUPPORTED", }; static void cn_cbor_decode_test(const unsigned char *buf, int len) { @@ -114,7 +115,7 @@ char *bufend; unsigned char *s = load_file("cases.cbor", &end); printf("%zd\n", end-s); - const cn_cbor *cb = cn_cbor_decode(s, end-s CBOR_CONTEXT_PARAM, 0); + cn_cbor *cb = cn_cbor_decode(s, end-s CBOR_CONTEXT_PARAM, 0); if (cb) { dump(cb, buf, &bufend, 0); *bufend = 0;