Merge remote-tracking branch 'refs/remotes/origin/windows2' into complete
# Conflicts:
# .gitignore
# include/cn-cbor/cn-cbor.h
# src/cn-encoder.c
diff --git a/.gitignore b/.gitignore
index 65581da..dc37cea 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,12 +5,15 @@
# Emacs temp files
*~
+.#*
+*#
# Visual Stdio build directories
Debug
Release
*.vcxproj
*.vcxproj.filters
+*.vcxproj.user
# Output of CMake
CMakeCache.txt
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/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 3490bd4..15f150c 100644
--- a/include/cn-cbor/cn-cbor.h
+++ b/include/cn-cbor/cn-cbor.h
@@ -18,7 +18,7 @@
#include <stdint.h>
#ifdef _MSC_VER
#include <WinSock2.h>
-typedef long ssize_t;
+typedef signed long ssize_t;
#else
#include <unistd.h>
#endif
@@ -86,7 +86,9 @@
/** Data associated with the value; different branches of the union are
used depending on the `type` field. */
union {
- /** CN_CBOR_BYTES, CN_CBOR_TEXT */
+ /** CN_CBOR_BYTES */
+ const uint8_t * bytes;
+ /** CN_CBOR_TEXT */
const char* str;
/** CN_CBOR_INT */
long sint;
@@ -221,7 +223,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.
@@ -230,7 +232,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.
@@ -239,7 +241,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.
@@ -248,15 +250,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.
@@ -395,6 +399,21 @@
cn_cbor* cb_value,
cn_cbor_errback *errp);
+/**
+ * Dump the object to a file pointer
+ * If buffer is NULL, then return required size to generate output
+ *
+ * @param[in] buffer Location to place output
+ * @param[in] bufferSize Size of return buffer
+ * @param[in] fp File pointer to print on
+ * @param[in] cb tree to be dumped
+ * @param[in] indent string to use for each level of indention
+ * @param[in] crlf string to use for end of line marker
+ * @return size of output generated, -1 if buffer is too small
+ */
+
+extern ssize_t cn_cbor_printer_write(char * buffer, size_t bufferSize, const cn_cbor * cb, const char * indent, const char * crlf);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ceb0608..8193cc6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -8,6 +8,7 @@
cn-encoder.c
cn-error.c
cn-get.c
+ cn-print.c
)
if (use_context)
diff --git a/src/cn-cbor.c b/src/cn-cbor.c
index 83f576d..4947e63 100644
--- a/src/cn-cbor.c
+++ b/src/cn-cbor.c
@@ -24,8 +24,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 */
@@ -241,7 +242,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 f36bb8c..f5e4207 100644
--- a/src/cn-encoder.c
+++ b/src/cn-encoder.c
@@ -10,6 +10,7 @@
#ifdef _MSC_VER
#include <WinSock2.h>
+#define inline _inline
#else
#include <arpa/inet.h>
#endif
@@ -41,22 +42,23 @@
ssize_t size;
} cn_write_state;
-#define ensure_writable(sz) if ((ws->offset<0) || (ws->offset + (sz) >= ws->size)) { \
+#define ensure_writable(sz) if ((ws->buf != NULL) && ((ws->offset<0) || (ws->offset + (sz) > ws->size))) { \
ws->offset = -1; \
return; \
}
#define write_byte_and_data(b, data, sz) \
-ws->buf[ws->offset++] = (b); \
-memcpy(ws->buf+ws->offset, (data), (sz)); \
-ws->offset += sz;
+ ws->buf[ws->offset++] = (b); \
+ memcpy(ws->buf + ws->offset, (data), (sz)); \
+ ws->offset += sz;
#define write_byte(b) \
-ws->buf[ws->offset++] = (b); \
+{ if (ws->buf == NULL) ws->offset++; \
+else ws->buf[ws->offset++] = (b); }
#define write_byte_ensured(b) \
ensure_writable(1); \
-write_byte(b); \
+write_byte(b);
static uint8_t _xlate[] = {
IB_FALSE, /* CN_CBOR_FALSE */
@@ -184,7 +186,7 @@
// TODO: make public?
typedef void (*cn_visit_func)(const cn_cbor *cb, int depth, void *context);
-static void _visit(const cn_cbor *cb,
+void _visit(const cn_cbor *cb,
cn_visit_func visitor,
cn_visit_func breaker,
void *context)
@@ -200,17 +202,25 @@
depth++;
} else{
// Empty indefinite
+#ifdef CN_INCLUDE_DUMPER
+ breaker(p, depth, context);
+#else
if (is_indefinite(p)) {
- breaker(p->parent, depth, context);
+ breaker(p, depth, context);
}
+#endif
if (p->next) {
p = p->next;
} else {
while (p->parent) {
depth--;
+#ifdef CN_INCLUDE_DUMPER
+ breaker(p->parent, depth, context);
+#else
if (is_indefinite(p->parent)) {
breaker(p->parent, depth, context);
}
+#endif
if (p->parent->next) {
p = p->parent->next;
goto visit;
@@ -294,7 +304,13 @@
cn_write_state *ws = context;
UNUSED_PARAM(cb);
UNUSED_PARAM(depth);
- write_byte_ensured(IB_BREAK);
+#ifdef CN_INCLUDE_DUMPER
+ if (is_indefinite(cb)) {
+#endif
+ write_byte_ensured(IB_BREAK);
+#ifdef CN_INCLUDE_DUMPER
+ }
+#endif
}
ssize_t cn_cbor_encoder_write(uint8_t *buf,
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/src/cn-print.c b/src/cn-print.c
new file mode 100644
index 0000000..2eb76f4
--- /dev/null
+++ b/src/cn-print.c
@@ -0,0 +1,253 @@
+#ifndef CN_PRINT_C
+#define CN_PRINT_C
+#define CN_INCLUDE_DUMPER
+#ifdef CN_INCLUDE_DUMPER
+#define _CRT_SECURE_NO_WARNINGS 1
+
+#include <stdio.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef EMACS_INDENTATION_HELPER
+} /* Duh. */
+#endif
+
+#include <stdio.h>
+#ifdef MSV_CRT
+#include <winsock2.h>
+#else
+#define _snprintf snprintf
+#endif
+#include <string.h>
+#include <stdbool.h>
+#include <assert.h>
+
+#include "cn-cbor/cn-cbor.h"
+#include "cbor.h"
+
+typedef struct _write_state
+{
+ char * rgbOutput;
+ ssize_t ib;
+ size_t cbLeft;
+ uint8_t * rgFlags;
+ const char * szIndentWith;
+ const char * szEndOfLine;
+} cn_write_state;
+
+typedef void(*cn_visit_func)(const cn_cbor *cb, int depth, void *context);
+extern void _visit(const cn_cbor *cb,
+ cn_visit_func visitor,
+ cn_visit_func breaker,
+ void *context);
+
+const char RgchHex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
+'8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+bool _isWritable(cn_write_state * ws, size_t cb)
+{
+ if (ws->rgbOutput == NULL) return true;
+ if ((ws->ib < 0) || (ws->ib + cb > ws->cbLeft)) {
+ ws->ib = -1;
+ return false;
+ }
+ return true;
+}
+
+void write_data(cn_write_state * ws, const char * sz, size_t cb)
+{
+ if (_isWritable(ws, cb)) {
+ if (ws->rgbOutput != NULL) memcpy(ws->rgbOutput + ws->ib, sz, cb);
+ ws->ib += cb;
+ }
+}
+
+void _doIndent(cn_write_state * ws, int depth)
+{
+ int i;
+ char * sz = ws->rgbOutput + ws->ib;
+ size_t cbIndentWith = strlen(ws->szIndentWith);
+ int cbIndent = depth * cbIndentWith;
+
+
+ if (ws->rgbOutput == NULL) {
+ ws->ib += cbIndent;
+ return;
+ }
+
+ if (_isWritable(ws, cbIndent)) {
+ for (i = 0; i < depth; i++) {
+ memcpy(sz, ws->szIndentWith, cbIndentWith);
+ sz += cbIndentWith;
+ }
+ }
+
+ ws->ib += cbIndent;
+
+ return;
+}
+
+void _print_encoder(const cn_cbor * cb, int depth, void * context)
+{
+ int i;
+ char rgchT[256];
+ int cch;
+ cn_write_state * ws = (cn_write_state *)context;
+ uint8_t flags = ws->rgFlags[depth];
+
+ if (flags & 1) {
+ write_data(ws, ", ", 2);
+ ws->rgFlags[depth] &= 0xfe;
+
+ if (ws->szIndentWith) {
+ write_data(ws, ws->szEndOfLine, strlen(ws->szEndOfLine));
+ _doIndent(ws, depth);
+ }
+ }
+
+ if (flags & 2) {
+ write_data(ws, ": ", 2);
+ ws->rgFlags[depth] &= 0xfd;
+ }
+
+ switch (cb->type) {
+ case CN_CBOR_BYTES_CHUNKED:
+ case CN_CBOR_TEXT_CHUNKED:
+ break;
+
+ case CN_CBOR_ARRAY:
+ write_data(ws, "[", 1);
+ ws->rgFlags[depth] |= 4;
+
+ if (ws->szIndentWith) {
+ write_data(ws, ws->szEndOfLine, strlen(ws->szEndOfLine));
+ _doIndent(ws, depth + 1);
+ }
+ break;
+
+ case CN_CBOR_MAP:
+ write_data(ws, "{", 1);
+ ws->rgFlags[depth] |= 8;
+
+ if (ws->szIndentWith) {
+ write_data(ws, ws->szEndOfLine, strlen(ws->szEndOfLine));
+ _doIndent(ws, depth + 1);
+ }
+ break;
+
+ case CN_CBOR_TAG:
+ case CN_CBOR_UINT:
+ case CN_CBOR_SIMPLE:
+ cch = _snprintf(rgchT, sizeof(rgchT), "%u", (unsigned int) cb->v.uint);
+ write_data(ws, rgchT, cch);
+ break;
+
+ case CN_CBOR_FALSE:
+ write_data(ws, "false", 5);
+ break;
+
+ case CN_CBOR_TRUE:
+ write_data(ws, "true", 4);
+ break;
+
+ case CN_CBOR_NULL:
+ write_data(ws, "null", 4);
+ break;
+
+ case CN_CBOR_UNDEF:
+ write_data(ws, "undef", 5);
+ break;
+
+ case CN_CBOR_INT:
+ cch = _snprintf(rgchT, sizeof(rgchT), "%d", (unsigned int) cb->v.sint);
+ write_data(ws, rgchT, cch);
+ break;
+
+ case CN_CBOR_DOUBLE:
+ cch = _snprintf(rgchT, sizeof(rgchT), "%f", cb->v.dbl);
+ write_data(ws, rgchT, cch);
+ break;
+
+ case CN_CBOR_INVALID:
+ write_data(ws, "invalid", 7);
+ break;
+
+ case CN_CBOR_TEXT:
+ write_data(ws, "\"", 1);
+ write_data(ws, cb->v.str, cb->length);
+ write_data(ws, "\"", 1);
+ break;
+
+ case CN_CBOR_BYTES:
+ write_data(ws, "h'", 2);
+ for (i = 0; i < cb->length; i++) {
+ write_data(ws, &RgchHex[(cb->v.str[i] / 16) & 0xf], 1);
+ write_data(ws, &RgchHex[cb->v.str[i] & 0xf], 1);
+ }
+ write_data(ws, "\'", 1);
+ break;
+ }
+
+ if (depth > 0) {
+ if (ws->rgFlags[depth - 1] & 4) ws->rgFlags[depth] |= 1;
+ else if (ws->rgFlags[depth - 1] & 8) {
+ if (flags & 2) ws->rgFlags[depth] |= 1;
+ else ws->rgFlags[depth] |= 2;
+ }
+ }
+}
+
+void _print_breaker(const cn_cbor * cb, int depth, void * context)
+{
+ cn_write_state * ws = (cn_write_state *)context;
+
+ switch (cb->type) {
+ case CN_CBOR_ARRAY:
+ if (ws->szIndentWith) {
+ write_data(ws, ws->szEndOfLine, strlen(ws->szEndOfLine));
+ _doIndent(ws, depth);
+ }
+
+ write_data(ws, "]", 1);
+ ws->rgFlags[depth + 1] = 0;
+ break;
+
+ case CN_CBOR_MAP:
+ if (ws->szIndentWith) {
+ write_data(ws, ws->szEndOfLine, strlen(ws->szEndOfLine));
+ _doIndent(ws, depth);
+ }
+
+ write_data(ws, "}", 1);
+ ws->rgFlags[depth + 1] = 0;
+ break;
+
+ default:
+ break;
+ }
+}
+
+ssize_t cn_cbor_printer_write(char * rgbBuffer, size_t cbBuffer, const cn_cbor * cb, const char * szIndentWith, const char * szEndOfLine)
+{
+ uint8_t flags[128] = { 0 };
+ char rgchZero[1] = { 0 };
+
+ cn_write_state ws = { rgbBuffer, 0, cbBuffer, flags, szIndentWith, szEndOfLine };
+ _visit(cb, _print_encoder, _print_breaker, &ws);
+ write_data(&ws, rgchZero, 1);
+
+ return ws.ib;
+}
+
+#ifdef EMACS_INDENTATION_HELPER
+{ /* Duh. */
+#endif
+#ifdef _cplusplus
+} /* extern "C" */
+#endif
+
+#endif // CN_INCLUDE_DUMPER
+#endif // CN_PRINT_C
+
diff --git a/test/cbor_test.c b/test/cbor_test.c
index ebd5edd..3326497 100644
--- a/test/cbor_test.c
+++ b/test/cbor_test.c
@@ -111,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];
@@ -159,7 +159,7 @@
"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];
@@ -221,7 +221,7 @@
{"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];
@@ -253,7 +253,7 @@
"f9fc00", // -Inf
"f97c00", // Inf
};
- const cn_cbor *cb;
+ cn_cbor *cb;
buffer b;
size_t i;
unsigned char encoded[1024];
@@ -276,8 +276,8 @@
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));
diff --git a/test/test.c b/test/test.c
index 263f9fe..d24992f 100644
--- a/test/test.c
+++ b/test/test.c
@@ -115,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;