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 @@
+[![Build Status](https://travis-ci.org/cabo/cn-cbor.png?branch=master)](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;