checkpoint
diff --git a/.gitignore b/.gitignore
index 241e782..957b6a3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
 build
 Testing/Temporary
 *.pc
+*.bat
 
 # Emacs temp files
 *~
diff --git a/.travis.yml b/.travis.yml
index 0d7c96f..e07a385 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,6 +6,7 @@
 env:
   - OPTIONS=-DCN_CBOR_USE_CONTEXT=OFF
   - OPTIONS=-DCN_CBOR_USE_CONTEXT=ON
+    COVERALLS="-DCN_CBOR_COVERALLS_SEND=ON"
   - OPTIONS=-DCN_CBOR_NO_FLOATS=ON
   - OPTIONS=-DCN_CBOR_ALIGN_READS=ON
 
@@ -16,5 +17,12 @@
     packages:
       - cmake
       - cmake-data
+
 script:
-- "./build.sh all test"
+  - cmake --version
+  - mkdir build
+  - cd build && cmake $OPTIONS $COVERALLS .. && make all test
+
+after_success:
+  - make coveralls
+
diff --git a/include/cn-cbor/cn-cbor.h b/include/cn-cbor/cn-cbor.h
index 2dceae0..6d908eb 100644
--- a/include/cn-cbor/cn-cbor.h
+++ b/include/cn-cbor/cn-cbor.h
@@ -13,18 +13,18 @@
 #endif
 
 #ifndef MYLIB_EXPORT
-#if defined (_WIN32) 
+#if defined(_WIN32)
 #if defined(CN_CBOR_IS_DLL)
-#define  MYLIB_EXPORT __declspec(dllimport)
+#define MYLIB_EXPORT __declspec(dllimport)
 #else
 #define MYLIB_EXPORT
 #endif /* CN_CBOR_IS_DLL */
-#else /* defined (_WIN32) */
+#else  /* defined (_WIN32) */
 #define MYLIB_EXPORT
-#endif 
+#endif
 #endif
 
-#ifdef  __cplusplus
+#ifdef __cplusplus
 extern "C" {
 #endif
 #ifdef EMACS_INDENTATION_HELPER
@@ -53,42 +53,42 @@
  * All of the different kinds of CBOR values.
  */
 typedef enum cn_cbor_type {
-  /** false */
-  CN_CBOR_FALSE,
-  /** true */
-  CN_CBOR_TRUE,
-  /** null */
-  CN_CBOR_NULL,
-  /** undefined */
-  CN_CBOR_UNDEF,
-  /** Positive integers */
-  CN_CBOR_UINT,
-  /** Negative integers */
-  CN_CBOR_INT,
-  /** Byte string */
-  CN_CBOR_BYTES,
-  /** UTF-8 string */
-  CN_CBOR_TEXT,
-  /** Byte string, in chunks.  Each chunk is a child. */
-  CN_CBOR_BYTES_CHUNKED,
-  /** UTF-8 string, in chunks.  Each chunk is a child */
-  CN_CBOR_TEXT_CHUNKED,
-  /** Array of CBOR values.  Each array element is a child, in order */
-  CN_CBOR_ARRAY,
-  /** Map of key/value pairs.  Each key and value is a child, alternating. */
-  CN_CBOR_MAP,
-  /** Tag describing the next value.  The next value is the single child. */
-  CN_CBOR_TAG,
-  /** Simple value, other than the defined ones */
-  CN_CBOR_SIMPLE,
+	/** false */
+	CN_CBOR_FALSE,
+	/** true */
+	CN_CBOR_TRUE,
+	/** null */
+	CN_CBOR_NULL,
+	/** undefined */
+	CN_CBOR_UNDEF,
+	/** Positive integers */
+	CN_CBOR_UINT,
+	/** Negative integers */
+	CN_CBOR_INT,
+	/** Byte string */
+	CN_CBOR_BYTES,
+	/** UTF-8 string */
+	CN_CBOR_TEXT,
+	/** Byte string, in chunks.  Each chunk is a child. */
+	CN_CBOR_BYTES_CHUNKED,
+	/** UTF-8 string, in chunks.  Each chunk is a child */
+	CN_CBOR_TEXT_CHUNKED,
+	/** Array of CBOR values.  Each array element is a child, in order */
+	CN_CBOR_ARRAY,
+	/** Map of key/value pairs.  Each key and value is a child, alternating. */
+	CN_CBOR_MAP,
+	/** Tag describing the next value.  The next value is the single child. */
+	CN_CBOR_TAG,
+	/** Simple value, other than the defined ones */
+	CN_CBOR_SIMPLE,
 #ifndef CBOR_NO_FLOAT
-  /** Doubles, floats, and half-floats */
-  CN_CBOR_DOUBLE,
-  /** Floats, and half-floats */
-  CN_CBOR_FLOAT,
+	/** Doubles, floats, and half-floats */
+	CN_CBOR_DOUBLE,
+	/** Floats, and half-floats */
+	CN_CBOR_FLOAT,
 #endif
-  /** An error has occurred */
-  CN_CBOR_INVALID
+	/** An error has occurred */
+	CN_CBOR_INVALID
 } cn_cbor_type;
 
 /**
@@ -96,102 +96,97 @@
  * `cn_cbor` structure.
  */
 typedef enum cn_cbor_flags {
-  /** The count field will be used for parsing */
-  CN_CBOR_FL_COUNT = 1,
-  /** An indefinite number of children */
-  CN_CBOR_FL_INDEF = 2,
-  /** Not used yet; the structure must free the v.str pointer when the
-     structure is freed */
-  CN_CBOR_FL_OWNER = 0x80,            /* of str */
+	/** The count field will be used for parsing */
+	CN_CBOR_FL_COUNT = 1,
+	/** An indefinite number of children */
+	CN_CBOR_FL_INDEF = 2,
+	/** Don't compress floating points value to smaller */
+	CN_CBOR_FL_KEEP_FLOAT_SIZE = 4,
+	/** This node was not allocated - don't free */
+	CN_CBOR_FL_EXT_SELF = 0x40,
+	/** The data is not owned by this node - don't free */
+	CN_CBOR_FL_EXT_DATA = 0x80
 } cn_cbor_flags;
 
 /**
  * A CBOR value
  */
 typedef struct cn_cbor {
-  /** The type of value */
-  cn_cbor_type type;
-  /** Flags used at parse time */
-  cn_cbor_flags flags;
-  /** Data associated with the value; different branches of the union are
-      used depending on the `type` field. */
-  union {
-    /** CN_CBOR_BYTES */
-    const uint8_t* bytes;
-    /** CN_CBOR_TEXT */
-    const char* str;
-    /** CN_CBOR_INT */
+	/** The type of value */
+	cn_cbor_type type;
+	/** Flags used at parse time */
+	cn_cbor_flags flags;
+	/** Data associated with the value; different branches of the union are
+		used depending on the `type` field. */
+	union {
+		/** CN_CBOR_BYTES */
+		const uint8_t* bytes;
+		/** CN_CBOR_TEXT */
+		const char* str;
+		/** CN_CBOR_INT */
 #ifdef _MSC_VER
-	int64_t sint;
+		int64_t sint;
 #else
-    long sint;
+		long sint;
 #endif
-    /** CN_CBOR_UINT */
+		/** CN_CBOR_UINT */
 #ifdef _MSC_VER
-	uint64_t uint;
+		uint64_t uint;
 #else
-    unsigned long uint;
+		unsigned long uint;
 #endif
 #ifndef CBOR_NO_FLOAT
-    /** CN_CBOR_DOUBLE */
-    double dbl;
-    /** CN_CBOR_FLOAT */
-    float f;
+		/** CN_CBOR_DOUBLE */
+		double dbl;
+		/** CN_CBOR_FLOAT */
+		float f;
 #endif
-    /** for use during parsing */
-#ifdef _MSC_VER
-	uint64_t count;
-#else
-	unsigned long count;
-#endif
-  } v;                          /* TBD: optimize immediate */
-  /** Number of children.
-    * @note: for maps, this is 2x the number of entries */
-#ifdef _MSC_VER
-  size_t length;
-#else
-  int length;
-#endif
-  /** The first child value */
-  struct cn_cbor* first_child;
-  /** The last child value */
-  struct cn_cbor* last_child;
-  /** The sibling after this one, or NULL if this is the last */
-  struct cn_cbor* next;
-  /** The parent of this value, or NULL if this is the root */
-  struct cn_cbor* parent;
+		/** for use during parsing */
+		size_t count;
+	} v; /* TBD: optimize immediate */
+	/** Number of children.
+	 * @note: for maps, this is 2x the number of entries */
+	size_t length;
+	/** The first child value */
+	struct cn_cbor* first_child;
+	/** The last child value */
+	struct cn_cbor* last_child;
+	/** The sibling after this one, or NULL if this is the last */
+	struct cn_cbor* next;
+	/** The parent of this value, or NULL if this is the root */
+	struct cn_cbor* parent;
 } cn_cbor;
 
 /**
  * All of the different kinds of errors
  */
 typedef enum cn_cbor_error {
-  /** No error has occurred */
-  CN_CBOR_NO_ERROR,
-  /** More data was expected while parsing */
-  CN_CBOR_ERR_OUT_OF_DATA,
-  /** Some extra data was left over at the end of parsing */
-  CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED,
-  /** A map should be alternating keys and values.  A break was found
-      when a value was expected */
-  CN_CBOR_ERR_ODD_SIZE_INDEF_MAP,
-  /** A break was found where it wasn't expected */
-  CN_CBOR_ERR_BREAK_OUTSIDE_INDEF,
-  /** Indefinite encoding works for bstrs, strings, arrays, and maps.
-      A different major type tried to use it. */
-  CN_CBOR_ERR_MT_UNDEF_FOR_INDEF,
-  /** Additional Information values 28-30 are reserved */
-  CN_CBOR_ERR_RESERVED_AI,
-  /** A chunked encoding was used for a string or bstr, and one of the elements
-      wasn't the expected (string/bstr) type */
-  CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING,
-  /** An invalid parameter was passed to a function */
-  CN_CBOR_ERR_INVALID_PARAMETER,
-  /** Allocation failed */
-  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
+	/** No error has occurred */
+	CN_CBOR_NO_ERROR,
+	/** More data was expected while parsing */
+	CN_CBOR_ERR_OUT_OF_DATA,
+	/** Some extra data was left over at the end of parsing */
+	CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED,
+	/** A map should be alternating keys and values.  A break was found
+		when a value was expected */
+	CN_CBOR_ERR_ODD_SIZE_INDEF_MAP,
+	/** A break was found where it wasn't expected */
+	CN_CBOR_ERR_BREAK_OUTSIDE_INDEF,
+	/** Indefinite encoding works for bstrs, strings, arrays, and maps.
+		A different major type tried to use it. */
+	CN_CBOR_ERR_MT_UNDEF_FOR_INDEF,
+	/** Additional Information values 28-30 are reserved */
+	CN_CBOR_ERR_RESERVED_AI,
+	/** A chunked encoding was used for a string or bstr, and one of the elements
+		wasn't the expected (string/bstr) type */
+	CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING,
+	/** An invalid parameter was passed to a function */
+	CN_CBOR_ERR_INVALID_PARAMETER,
+	/** Allocation failed */
+	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;
 
 /**
@@ -200,16 +195,16 @@
  * @todo: turn into a function to make the type safety more clear?
  */
 MYLIB_EXPORT
-extern const char *cn_cbor_error_str[];
+extern const char* cn_cbor_error_str[];
 
 /**
  * Errors
  */
 typedef struct cn_cbor_errback {
-  /** The position in the input where the erorr happened */
-  int pos;
-  /** The error, or CN_CBOR_NO_ERROR if none */
-  cn_cbor_error err;
+	/** The position in the input where the error happened */
+	size_t pos;
+	/** The error, or CN_CBOR_NO_ERROR if none */
+	cn_cbor_error err;
 } cn_cbor_errback;
 
 #ifdef USE_CBOR_CONTEXT
@@ -223,7 +218,7 @@
  * @param[in] size    The size of each item
  * @param[in] context The allocation context
  */
-typedef void* (*cn_calloc_func)(size_t count, size_t size, void *context);
+typedef void* (*cn_calloc_func)(size_t count, size_t size, void* context);
 
 /**
  * Free memory previously allocated with a context.  If using a pool allocator,
@@ -236,26 +231,26 @@
  * @param  context [description]
  * @return         [description]
  */
-typedef void (*cn_free_func)(void *ptr, void *context);
+typedef void (*cn_free_func)(void* ptr, void* context);
 
 /**
  * The allocation context.
  */
 typedef struct cn_cbor_context {
-    /** The pool `calloc` routine.  Must allocate and zero. */
-    cn_calloc_func calloc_func;
-    /** The pool `free` routine.  Often a no-op, but required. */
-    cn_free_func  free_func;
-    /** Typically, the pool object, to be used when calling `calloc_func`
-      * and `free_func` */
-    void *context;
+	/** The pool `calloc` routine.  Must allocate and zero. */
+	cn_calloc_func calloc_func;
+	/** The pool `free` routine.  Often a no-op, but required. */
+	cn_free_func free_func;
+	/** Typically, the pool object, to be used when calling `calloc_func`
+	 * and `free_func` */
+	void* context;
 } cn_cbor_context;
 
 /** When USE_CBOR_CONTEXT is defined, many functions take an extra `context`
-  * parameter */
-#define CBOR_CONTEXT , cn_cbor_context *context
+ * parameter */
+#define CBOR_CONTEXT , cn_cbor_context* context
 /** When USE_CBOR_CONTEXT is defined, some functions take an extra `context`
-  * parameter at the beginning */
+ * parameter at the beginning */
 #define CBOR_CONTEXT_COMMA cn_cbor_context *context,
 
 #else
@@ -266,8 +261,20 @@
 #endif
 
 /**
+ * Tag the data as not to be freed
+ *
+ */
+
+MYLIB_EXPORT
+void cn_cbor_dont_free_data(cn_cbor* cbor);
+
+/**
  * Decode an array of CBOR bytes into structures.
  *
+ * @note Pointers to the buffer are placed into the structure provided.
+ * This means that the buffer needs to be kept as long as the decoded
+ * structure is kept.
+ *
  * @param[in]  buf          The array of bytes to parse
  * @param[in]  len          The number of bytes in the array
  * @param[in]  CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined)
@@ -275,7 +282,7 @@
  * @return                  The parsed CBOR structure, or NULL on error
  */
 MYLIB_EXPORT
-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.
@@ -331,10 +338,7 @@
  * @param[in]  cb         [description]
  * @return                -1 on fail, or number of bytes written
  */
-ssize_t cn_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.
@@ -344,7 +348,7 @@
  * @return                   The created map, or NULL on error
  */
 MYLIB_EXPORT
-cn_cbor* cn_cbor_map_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp);
+cn_cbor* cn_cbor_map_create(CBOR_CONTEXT_COMMA cn_cbor_errback* errp);
 
 /**
  * Create a CBOR byte string.  The data in the byte string is *not* owned
@@ -357,9 +361,21 @@
  * @return                   The created object, or NULL on error
  */
 MYLIB_EXPORT
-cn_cbor* cn_cbor_data_create(const uint8_t* data, int len
-                             CBOR_CONTEXT,
-                             cn_cbor_errback *errp);
+cn_cbor* cn_cbor_data_create(const uint8_t* data, int len CBOR_CONTEXT, cn_cbor_errback* errp);
+
+/**
+ * Create a CBOR byte string.  Ownership of the passed in data is
+ * controlled by the flags.  Default is ownership is given up to CBOR.
+ *
+ * @param[in]   data         The data
+ * @param[in]   len          The number of bytes of data
+ * @param[in]   flags        CN_CBOR_FL_EXT_DATA or 0
+ * @param[in]   CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined)
+ * @param[out]  errp         Error, if NULL is returned
+ * @return                   The created object, or NULL on error
+ */
+MYLIB_EXPORT
+cn_cbor* cn_cbor_data_create2(const uint8_t* data, int len, int flags CBOR_CONTEXT, cn_cbor_errback* errp);
 
 /**
  * Create a CBOR UTF-8 string.  The data is not checked for UTF-8 correctness.
@@ -375,9 +391,24 @@
  * @return                   The created object, or NULL on error
  */
 MYLIB_EXPORT
-cn_cbor* cn_cbor_string_create(const char* data
-                               CBOR_CONTEXT,
-                               cn_cbor_errback *errp);
+cn_cbor* cn_cbor_string_create(const char* data CBOR_CONTEXT, cn_cbor_errback* errp);
+
+/**
+ * Create a CBOR UTF-8 string.  The data is not checked for UTF-8 correctness.
+ * Ownership of the passed in data is controlled by the flags.
+ * Default is ownership is given up to CBOR.
+ *
+ * @note: Do NOT use this function with untrusted data.  It calls strlen, and
+ * relies on proper NULL-termination.
+ *
+ * @param[in]   data         NULL-terminated UTF-8 string
+ * @param[in]   flags        CN_CBOR_FL_EXT_DATA or 0
+ * @param[in]   CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined)
+ * @param[out]  errp         Error, if NULL is returned
+ * @return                   The created object, or NULL on error
+ */
+MYLIB_EXPORT
+cn_cbor* cn_cbor_string_create2(const char* data, int flags CBOR_CONTEXT, cn_cbor_errback* errp);
 
 /**
  * Create a CBOR integer (either positive or negative).
@@ -388,9 +419,7 @@
  * @return                   The created object, or NULL on error
  */
 MYLIB_EXPORT
-cn_cbor* cn_cbor_int_create(int64_t value
-                            CBOR_CONTEXT,
-                            cn_cbor_errback *errp);
+cn_cbor* cn_cbor_int_create(int64_t value CBOR_CONTEXT, cn_cbor_errback* errp);
 
 #ifndef CBOR_NO_FLOAT
 /**
@@ -401,9 +430,7 @@
  * @param[out]  errp         Error, if NULL is returned
  * @return                   The created object, or NULL on error
  */
-cn_cbor* cn_cbor_float_create(float value
-                              CBOR_CONTEXT,
-                              cn_cbor_errback *errp);
+cn_cbor* cn_cbor_float_create(float value CBOR_CONTEXT, cn_cbor_errback* errp);
 
 /**
  * Create a CBOR double.
@@ -413,25 +440,87 @@
  * @param[out]  errp         Error, if NULL is returned
  * @return                   The created object, or NULL on error
  */
-cn_cbor* cn_cbor_double_create(double value
-                               CBOR_CONTEXT,
-                               cn_cbor_errback *errp);
+cn_cbor* cn_cbor_double_create(double value CBOR_CONTEXT, cn_cbor_errback* errp);
 #endif /* CBOR_NO_FLOAT */
 
 /**
+ * Create a CBOR simple boolean.
+ *
+ * @note: Do NOT use this function with untrusted data.  It calls strlen, and
+ * relies on proper NULL-termination.
+ *
+ * @param[in]   simpleValue  Simple value to have
+ * @param[in]   CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined)
+ * @param[out]  errp         Error, if NULL is returned
+ * @return                   The created object, or NULL on error
+ */
+MYLIB_EXPORT
+cn_cbor* cn_cbor_simple_create(int simpleValue CBOR_CONTEXT, cn_cbor_errback* errp);
+
+#define cn_cbor_null_create(context, error) cn_cbor_simple_create(22, context, error)
+
+/**
+ * Tag a CBOR object
+ *
+ * @param[in]   tag          Tag to be added
+ * @param[in]   child        child data to this object
+ * @param[in]   CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined)
+ * @param[in]   perr         Error, if NULL is returned
+ * @return                   The created object, or NULL on error
+ */
+
+cn_cbor* cn_cbor_tag_create(int tag, cn_cbor* child, CBOR_CONTEXT_COMMA cn_cbor_errback* perr);
+
+/**
+ * Create a CBOR UTF-8 string.  The data is not checked for UTF-8 correctness.
+ * The data being stored in the string is *not* owned the CBOR object, so it is
+ * not freed automatically.
+ *
+ * @note: Do NOT use this function with untrusted data.  It calls strlen, and
+ * relies on proper NULL-termination.
+ *
+ * @param[in]   value        true or false
+ * @param[in]   CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined)
+ * @param[out]  errp         Error, if NULL is returned
+ * @return                   The created object, or NULL on error
+ */
+MYLIB_EXPORT
+cn_cbor* cn_cbor_bool_create(bool value CBOR_CONTEXT, cn_cbor_errback* errp);
+
+/**
+ * Create a chunked text or byte string.
+ *
+ * @param[in]   type          CN_CBOR_BYTES or CN_CBOR_TEXT
+ * @param[in]   CBOR_CONTEXT  Allocation context (only if USE_CBOR_CONTEXT is defined)
+ * @param[in]   errp          Error; if NULL is returned
+ * @return                    The created object or NULL on error
+ */
+MYLIB_EXPORT
+cn_cbor* cn_cbor_chunked_create(int type, CBOR_CONTEXT_COMMA cn_cbor_errback* errp);
+
+/**
+ * Append a node to a chunked list.
+ *
+ * @param[in]   cb_array      Node tagged as chunked
+ * @param[in]   cb_value      Item to be appended
+ * @param[in]   errp          Error; if FALSE is returned
+ * @return                    True if successfully appended
+ */
+MYLIB_EXPORT
+bool cn_cbor_chunked_append(cn_cbor* cb_array, cn_cbor* cb_value, cn_cbor_errback* errp);
+
+/**
  * Put a CBOR object into a map with a CBOR object key.  Duplicate checks are NOT
  * currently performed.
  *
  * @param[in]   cb_map       The map to insert into
- * @param[in]   key          The key
+ * @param[in]   cb_key          The key
  * @param[in]   cb_value     The value
  * @param[out]  errp         Error
  * @return                   True on success
  */
 MYLIB_EXPORT
-bool cn_cbor_map_put(cn_cbor* cb_map,
-                     cn_cbor *cb_key, cn_cbor *cb_value,
-                     cn_cbor_errback *errp);
+bool cn_cbor_map_put(cn_cbor* cb_map, cn_cbor* cb_key, cn_cbor* cb_value, cn_cbor_errback* errp);
 
 /**
  * Put a CBOR object into a map with an integer key.  Duplicate checks are NOT
@@ -445,14 +534,11 @@
  * @return                   True on success
  */
 MYLIB_EXPORT
-bool cn_cbor_mapput_int(cn_cbor* cb_map,
-                        int64_t key, cn_cbor* cb_value
-                        CBOR_CONTEXT,
-                        cn_cbor_errback *errp);
+bool cn_cbor_mapput_int(cn_cbor* cb_map, int64_t key, cn_cbor* cb_value CBOR_CONTEXT, cn_cbor_errback* errp);
 
 /**
  * Put a CBOR object into a map with a string key.  Duplicate checks are NOT
- * currently performed.
+ * currently performed.  The string value is not freed when the object is freed.
  *
  * @note: do not call this routine with untrusted string data.  It calls
  * strlen, and requires a properly NULL-terminated key.
@@ -465,10 +551,29 @@
  * @return                   True on success
  */
 MYLIB_EXPORT
-bool cn_cbor_mapput_string(cn_cbor* cb_map,
-                           const char* key, cn_cbor* cb_value
-                           CBOR_CONTEXT,
-                           cn_cbor_errback *errp);
+bool cn_cbor_mapput_string(cn_cbor* cb_map, const char* key, cn_cbor* cb_value CBOR_CONTEXT, cn_cbor_errback* errp);
+
+/**
+ * Put a CBOR object into a map with a string key.  Duplicate checks are NOT
+ * currently performed.  The string will be freed depending on the flags.
+ *
+ * @note: do not call this routine with untrusted string data.  It calls
+ * strlen, and requires a properly NULL-terminated key.
+ *
+ * @param[in]   cb_map       The map to insert into
+ * @param[in]   key          The string key
+ * @param[in]   cb_value     The value
+ * @param[in]   flags        CN_CBOR_FL_EXT_DATA | 0
+ * @param[in]   CBOR_CONTEXT Allocation context (only if USE_CBOR_CONTEXT is defined)
+ * @param[out]  errp         Error
+ * @return                   True on success
+ */
+MYLIB_EXPORT
+bool cn_cbor_mapput_string2(cn_cbor* cb_map,
+	const char* key,
+	cn_cbor* cb_value,
+	int flags CBOR_CONTEXT,
+	cn_cbor_errback* errp);
 
 /**
  * Create a CBOR array
@@ -478,7 +583,7 @@
  * @return                   The created object, or NULL on error
  */
 MYLIB_EXPORT
-cn_cbor* cn_cbor_array_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp);
+cn_cbor* cn_cbor_array_create(CBOR_CONTEXT_COMMA cn_cbor_errback* errp);
 
 /**
  * Append an item to the end of a CBOR array.
@@ -489,9 +594,7 @@
  * @return                True on success
  */
 MYLIB_EXPORT
-bool cn_cbor_array_append(cn_cbor* cb_array,
-                          cn_cbor* cb_value,
-                          cn_cbor_errback *errp);
+bool cn_cbor_array_append(cn_cbor* cb_array, cn_cbor* cb_value, cn_cbor_errback* errp);
 
 /**
  * Dump the object to a file pointer
@@ -499,28 +602,29 @@
  *
  * @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);
+extern ssize_t cn_cbor_printer_write(char* buffer,
+	size_t bufferSize,
+	const cn_cbor* cb,
+	const char* indent,
+	const char* crlf);
 
 #ifdef __MBED__
-#define ntohs(a) ((uint16_t) (((((uint16_t) (a)) & 0xff) << 8) | (((uint16_t) (a)) & 0xff00) >> 8))
-#define htons(a)  ntohs(a)
-#define ntohl(a) ((uint32_t) ( \
-                      ((((uint32_t)(a)) & 0x000000ff) << 24) | \
-                      ((((uint32_t)(a)) & 0x0000ff00) <<  8) | \
-                      ((((uint32_t)(a)) & 0x00ff0000) >>  8) | \
-                      ((((uint32_t)(a)) & 0xff000000) >> 24)))
+#define ntohs(a) ((uint16_t)(((((uint16_t)(a)) & 0xff) << 8) | (((uint16_t)(a)) & 0xff00) >> 8))
+#define htons(a) ntohs(a)
+#define ntohl(a)                                                                                 \
+	((uint32_t)(((((uint32_t)(a)) & 0x000000ff) << 24) | ((((uint32_t)(a)) & 0x0000ff00) << 8) | \
+				((((uint32_t)(a)) & 0x00ff0000) >> 8) | ((((uint32_t)(a)) & 0xff000000) >> 24)))
 #define htonl(a) ntohl(a)
-#endif // __MBED__
+#endif	// __MBED__
 
-#ifdef  __cplusplus
+#ifdef __cplusplus
 }
 #endif
 
-#endif  /* CN_CBOR_H */
+#endif /* CN_CBOR_H */
diff --git a/src/cn-cbor.c b/src/cn-cbor.c
index 6219f97..d3eb317 100644
--- a/src/cn-cbor.c
+++ b/src/cn-cbor.c
@@ -33,6 +33,12 @@
 	} while (0)
 
 MYLIB_EXPORT
+void cn_cbor_dont_free_data(cn_cbor *cbor)
+{
+	cbor->flags |= CN_CBOR_FL_EXT_DATA;
+}
+
+MYLIB_EXPORT
 void cn_cbor_free(cn_cbor *cb CBOR_CONTEXT)
 {
 	cn_cbor *p = (cn_cbor *)cb;
@@ -47,7 +53,21 @@
 				p1->first_child = 0;
 			}
 		}
-		CN_CBOR_FREE_CONTEXT(p);
+
+		if ((p->flags & CN_CBOR_FL_EXT_DATA) == 0) {
+			switch (p->type) {
+				case CN_CBOR_BYTES:
+				case CN_CBOR_TEXT:
+					CN_CBOR_FREE_CONTEXT(p->v.bytes);
+					break;
+
+				default:
+					break;
+			}
+		}
+		if ((p->flags & CN_CBOR_FL_EXT_SELF) == 0) {
+			CN_CBOR_FREE_CONTEXT(p);
+		}
 		p = p1;
 	}
 }
@@ -128,10 +148,10 @@
 	unsigned char *pos = pb->buf;
 	unsigned char *ebuf = pb->ebuf;
 	cn_cbor *parent = top_parent;
-	int ib;
-	unsigned int mt;
-	int ai;
-	uint64_t val;
+	int ib = 0;
+	unsigned int mt = 0;
+	int ai = 0;
+	uint64_t val = 0;
 	cn_cbor *cb = NULL;
 #ifndef CBOR_NO_FLOAT
 	union {
@@ -155,11 +175,18 @@
 			case CN_CBOR_TEXT:
 				parent->type += 2; /* CN_CBOR_* -> CN_CBOR_*_CHUNKED */
 				break;
+
 			case CN_CBOR_MAP:
 				if (parent->length & 1) {
 					CN_CBOR_FAIL(CN_CBOR_ERR_ODD_SIZE_INDEF_MAP);
 				}
-			default:;
+				break;
+
+			case CN_CBOR_ARRAY:
+				break;
+
+			default:
+				CN_CBOR_FAIL(CN_CBOR_ERR_WRONG_NESTING_IN_INDEF_STRING);
 		}
 		goto complete;
 	}
@@ -209,7 +236,10 @@
 			else {
 				CN_CBOR_FAIL(CN_CBOR_ERR_MT_UNDEF_FOR_INDEF);
 			}
+		default:
+			break;
 	}
+
 	// process content
 	switch (mt) {
 		case MT_UNSIGNED:
@@ -223,6 +253,7 @@
 			cb->v.str = (char *)pos;
 			cb->length = (size_t)val;
 			TAKE(pos, ebuf, val, ;);
+			cb->flags |= CN_CBOR_FL_EXT_DATA;
 			break;
 		case MT_MAP:
 			val <<= 1;
@@ -278,8 +309,16 @@
 					break;
 				default:
 					cb->v.uint = val;
+					if (24 <= val && val < 32) {
+						CN_CBOR_FAIL(CN_CBOR_ERR_INVALID_PARAMETER);
+					}
+					break;
 			}
+
+		default:
+			CN_CBOR_FAIL(CN_CBOR_ERR_INVALID_PARAMETER);
 	}
+
 fill: /* emulate loops */
 	if (parent->flags & CN_CBOR_FL_INDEF) {
 		if (parent->type == CN_CBOR_BYTES || parent->type == CN_CBOR_TEXT) {
@@ -320,7 +359,7 @@
 {
 	cn_cbor catcher = {CN_CBOR_INVALID, 0, {0}, 0, NULL, NULL, NULL, NULL};
 	struct parse_buf pb;
-	cn_cbor *ret;
+	cn_cbor *ret = NULL;
 
 	pb.buf = (unsigned char *)buf;
 	pb.ebuf = (unsigned char *)buf + len;
diff --git a/src/cn-create.c b/src/cn-create.c
index d292ed3..105dfa6 100644
--- a/src/cn-create.c
+++ b/src/cn-create.c
@@ -25,6 +25,79 @@
 	}
 
 MYLIB_EXPORT
+cn_cbor* cn_cbor_bool_create(bool value CBOR_CONTEXT, cn_cbor_errback* errp)
+{
+	cn_cbor* pcn = CN_CALLOC(context);
+	if (pcn == NULL) {
+		if (errp != NULL) {
+			errp->err = CN_CBOR_ERR_OUT_OF_MEMORY;
+		}
+		return NULL;
+	}
+
+	pcn->type = CN_CBOR_FALSE + (value != 0);
+	return pcn;
+}
+
+MYLIB_EXPORT
+cn_cbor* cn_cbor_simple_create(int simpleValue, CBOR_CONTEXT_COMMA cn_cbor_errback* errp)
+{
+	if (24 <= simpleValue && simpleValue <= 31) {
+		if (errp != NULL) {
+			errp->err = CN_CBOR_ERR_INVALID_PARAMETER;
+		}
+		return NULL;
+	}
+
+	cn_cbor* pcn = CN_CALLOC(context);
+	if (pcn == NULL) {
+		if (errp != NULL) {
+			errp->err = CN_CBOR_ERR_OUT_OF_MEMORY;
+		}
+		return NULL;
+	}
+
+	switch (simpleValue) {
+		case 20:
+			pcn->type = CN_CBOR_FALSE;
+			break;
+
+		case 21:
+			pcn->type = CN_CBOR_TRUE;
+			break;
+
+		case 22:
+			pcn->type = CN_CBOR_NULL;
+			break;
+
+		default:
+			pcn->type = CN_CBOR_SIMPLE;
+			pcn->v.uint = simpleValue;
+			break;
+	}
+	return pcn;
+}
+
+MYLIB_EXPORT
+cn_cbor* cn_cbor_tag_create(int tag, cn_cbor* child, CBOR_CONTEXT_COMMA cn_cbor_errback* perr)
+{
+	cn_cbor* pcnTag = CN_CALLOC(context);
+	if (pcnTag == NULL) {
+		if (perr != NULL) {
+			perr->err = CN_CBOR_ERR_OUT_OF_MEMORY;
+		}
+		return NULL;
+	}
+
+	pcnTag->type = CN_CBOR_TAG;
+	pcnTag->v.sint = tag;
+	pcnTag->first_child = child;
+	child->parent = pcnTag;
+
+	return pcnTag;
+}
+
+MYLIB_EXPORT
 cn_cbor* cn_cbor_map_create(CBOR_CONTEXT_COMMA cn_cbor_errback* errp)
 {
 	cn_cbor* ret;
@@ -37,27 +110,40 @@
 }
 
 MYLIB_EXPORT
-cn_cbor* cn_cbor_data_create(const uint8_t* data, int len CBOR_CONTEXT, cn_cbor_errback* errp)
+cn_cbor* cn_cbor_data_create(const uint8_t* data, int len, CBOR_CONTEXT_COMMA cn_cbor_errback* errp)
 {
-	cn_cbor* ret;
+	return cn_cbor_data_create2(data, len, CN_CBOR_FL_EXT_DATA CBOR_CONTEXT_PARAM, errp);
+}
+
+MYLIB_EXPORT
+cn_cbor* cn_cbor_data_create2(const uint8_t* data, int len, int flags CBOR_CONTEXT, cn_cbor_errback* errp)
+{
+	cn_cbor* ret = NULL;
 	INIT_CB(ret);
 
 	ret->type = CN_CBOR_BYTES;
 	ret->length = len;
 	ret->v.str = (const char*)data;	 // TODO: add v.ustr to the union?
-
+	ret->flags |= flags;
 	return ret;
 }
 
 MYLIB_EXPORT
-cn_cbor* cn_cbor_string_create(const char* data CBOR_CONTEXT, cn_cbor_errback* errp)
+cn_cbor* cn_cbor_string_create(const char* data, CBOR_CONTEXT_COMMA cn_cbor_errback* errp)
 {
-	cn_cbor* ret;
+	return cn_cbor_string_create2(data, CN_CBOR_FL_EXT_DATA CBOR_CONTEXT_PARAM, errp);
+}
+
+MYLIB_EXPORT
+cn_cbor* cn_cbor_string_create2(const char* data, int flags CBOR_CONTEXT, cn_cbor_errback* errp)
+{
+	cn_cbor* ret = NULL;
 	INIT_CB(ret);
 
 	ret->type = CN_CBOR_TEXT;
 	ret->length = strlen(data);
 	ret->v.str = data;
+	ret->flags |= flags;
 
 	return ret;
 }
@@ -160,8 +246,16 @@
 MYLIB_EXPORT
 bool cn_cbor_mapput_string(cn_cbor* cb_map, const char* key, cn_cbor* cb_value CBOR_CONTEXT, cn_cbor_errback* errp)
 {
-	cn_cbor* cb_key;
+	return cn_cbor_mapput_string2(cb_map, key, cb_value, CN_CBOR_FL_EXT_DATA CBOR_CONTEXT_PARAM, errp);
+}
 
+MYLIB_EXPORT
+bool cn_cbor_mapput_string2(cn_cbor* cb_map,
+	const char* key,
+	cn_cbor* cb_value,
+	int flags CBOR_CONTEXT,
+	cn_cbor_errback* errp)
+{
 	// Make sure input is a map. Otherwise
 	if (!cb_map || !cb_value || cb_map->type != CN_CBOR_MAP) {
 		if (errp) {
@@ -170,7 +264,7 @@
 		return false;
 	}
 
-	cb_key = cn_cbor_string_create(key CBOR_CONTEXT_PARAM, errp);
+	cn_cbor* cb_key = cn_cbor_string_create2(key, flags CBOR_CONTEXT_PARAM, errp);
 	if (!cb_key) {
 		return false;
 	}
@@ -213,6 +307,68 @@
 	return true;
 }
 
+MYLIB_EXPORT
+cn_cbor* cn_cbor_chunked_create(int type, CBOR_CONTEXT_COMMA cn_cbor_errback* errp)
+{
+	cn_cbor* ret;
+	INIT_CB(ret);
+
+	switch (type) {
+		case CN_CBOR_BYTES:
+			ret->type = CN_CBOR_BYTES_CHUNKED;
+			break;
+
+		case CN_CBOR_TEXT:
+			ret->type = CN_CBOR_TEXT_CHUNKED;
+			break;
+
+		default:
+			return NULL;
+	}
+
+	ret->flags |= CN_CBOR_FL_INDEF;
+
+	return ret;
+}
+
+MYLIB_EXPORT
+bool cn_cbor_chunked_append(cn_cbor* cb_array, cn_cbor* cb_value, cn_cbor_errback* errp)
+{
+	// Make sure input is an array.
+	if (!cb_array || !cb_value || (cb_array->type != CN_CBOR_BYTES_CHUNKED && cb_array->type != CN_CBOR_TEXT_CHUNKED)) {
+		if (errp) {
+			errp->err = CN_CBOR_ERR_INVALID_PARAMETER;
+		}
+		return false;
+	}
+
+	if (cb_array->type == CN_CBOR_BYTES_CHUNKED && cb_value->type != CN_CBOR_BYTES) {
+		if (errp) {
+			errp->err = CN_CBOR_ERR_INVALID_PARAMETER;
+		}
+		return false;
+	}
+
+	if (cb_array->type == CN_CBOR_TEXT_CHUNKED && cb_value->type != CN_CBOR_TEXT) {
+		if (errp) {
+			errp->err = CN_CBOR_ERR_INVALID_PARAMETER;
+		}
+		return false;
+	}
+
+	cb_value->parent = cb_array;
+	cb_value->next = NULL;
+	if (cb_array->last_child) {
+		cb_array->last_child->next = cb_value;
+	}
+	else {
+		cb_array->first_child = cb_value;
+	}
+	cb_array->last_child = cb_value;
+	cb_array->length++;
+	return true;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/cn-encoder.c b/src/cn-encoder.c
index 80d4968..e9392c0 100644
--- a/src/cn-encoder.c
+++ b/src/cn-encoder.c
@@ -43,14 +43,13 @@
 
 typedef struct _write_state {
 	uint8_t *buf;
-	ssize_t offset;
-	ssize_t size;
+	size_t offset;
+	size_t size;
 } cn_write_state;
 
 #define ensure_writable(sz)                                                          \
 	if ((ws->buf != NULL) && ((ws->offset < 0) || (ws->offset + (sz) > ws->size))) { \
-		ws->offset = -1;                                                             \
-		return;                                                                      \
+		return false;                                                                \
 	}
 
 #define write_byte_and_data(b, data, sz)            \
@@ -75,7 +74,7 @@
 	ensure_writable(1);       \
 	write_byte(b);
 
-static uint8_t _xlate[] = {
+static const uint8_t _xlate[] = {
 	IB_FALSE,	 /* CN_CBOR_FALSE */
 	IB_TRUE,	 /* CN_CBOR_TRUE */
 	IB_NIL,		 /* CN_CBOR_NULL */
@@ -99,16 +98,13 @@
 	return (cb->flags & CN_CBOR_FL_INDEF) != 0;
 }
 
-static void _write_positive(cn_write_state *ws, cn_cbor_type typ, uint64_t val)
+static bool _write_positive(cn_write_state *ws, cn_cbor_type typ, uint64_t val)
 {
-	uint8_t ib;
-
 	assert((size_t)typ < sizeof(_xlate));
 
-	ib = _xlate[typ];
+	const uint8_t ib = _xlate[typ];
 	if (ib == 0xFF) {
-		ws->offset = -1;
-		return;
+		return false;
 	}
 
 	if (val < 24) {
@@ -139,13 +135,15 @@
 		be64 = hton64p((const uint8_t *)&val);
 		write_byte_and_data(ib | 27, (const void *)&be64, 8);
 	}
+
+	return true;
 }
 
 #ifndef CBOR_NO_FLOAT
-static void _write_double(cn_write_state *ws, double val)
+static bool _write_double(cn_write_state *ws, double val, int size)
 {
-	float float_val = val;
-	if (float_val == val) { /* 32 bits is enough and we aren't NaN */
+	float float_val = (float)val;
+	if (float_val == val && (size != 64)) { /* 32 bits is enough and we aren't NaN */
 		uint32_t be32;
 		uint16_t be16, u16;
 		union {
@@ -153,12 +151,13 @@
 			uint32_t u;
 		} u32;
 		u32.f = float_val;
-		if ((u32.u & 0x1FFF) == 0) { /* worth trying half */
+
+		if ((u32.u & 0x1FFF) == 0 && (size == 0)) { /* worth trying half */
 			int s16 = (u32.u >> 16) & 0x8000;
-			int exp = (u32.u >> 23) & 0xff;
-			int mant = u32.u & 0x7fffff;
+			int exp = (int)((u32.u >> 23) & 0xff);
+			int mant = (int)(u32.u & 0x7fffff);
 			if (exp == 0 && mant == 0) {
-				;							   /* 0.0, -0.0 */
+				; /* 0.0, -0.0 */
 			}
 			else if (exp >= 113 && exp <= 142) {
 				/* normalized */
@@ -182,7 +181,7 @@
 			be16 = hton16p((const uint8_t *)&u16);
 
 			write_byte_and_data(IB_PRIM | 25, (const void *)&be16, 2);
-			return;
+			return true;
 		}
 	float32:
 		ensure_writable(5);
@@ -209,18 +208,22 @@
 
 		write_byte_and_data(IB_PRIM | 27, (const void *)&be64, 8);
 	}
+	return true;
 }
 #endif /* CBOR_NO_FLOAT */
 
 // TODO: make public?
-typedef void (*cn_visit_func)(const cn_cbor *cb, int depth, void *context);
-void _visit(const cn_cbor *cb, cn_visit_func visitor, cn_visit_func breaker, void *context)
+typedef bool (*cn_visit_func)(const cn_cbor *cb, int depth, void *context);
+bool _visit(const cn_cbor *cb, cn_visit_func visitor, cn_visit_func breaker, void *context)
 {
 	const cn_cbor *p = cb;
 	int depth = 0;
 	while (p) {
 	visit:
-		visitor(p, depth, context);
+		if (!visitor(p, depth, context)) {
+			return false;
+		}
+
 		if (p->first_child) {
 			p = p->first_child;
 			depth++;
@@ -228,10 +231,14 @@
 		else {
 			// Empty indefinite
 #ifdef CN_INCLUDE_DUMPER
-			breaker(p, depth, context);
+			if (!breaker(p, depth, context)) {
+				return false;
+			}
 #else
 			if (is_indefinite(p)) {
-				breaker(p, depth, context);
+				if (!breaker(p, depth, context)) {
+					return false;
+				}
 			}
 #endif
 			if (p->next) {
@@ -241,10 +248,14 @@
 				while (p->parent) {
 					depth--;
 #ifdef CN_INCLUDE_DUMPER
-					breaker(p->parent, depth, context);
+					if (!breaker(p->parent, depth, context)) {
+						return false;
+					}
 #else
 					if (is_indefinite(p->parent)) {
-						breaker(p->parent, depth, context);
+						if (!breaker(p->parent, depth, context)) {
+							return false;
+						}
 					}
 #endif
 					if (p->parent->next) {
@@ -253,19 +264,19 @@
 					}
 					p = p->parent;
 				}
-				return;
+				return true;
 			}
 		}
 	}
+	return true;
 }
 
-#define CHECK(st)         \
-	(st);                 \
-	if (ws->offset < 0) { \
-		return;           \
+#define CHECK(st)     \
+	if (!(st)) {      \
+		return false; \
 	}
 
-void _encoder_visitor(const cn_cbor *cb, int depth, void *context)
+bool _encoder_visitor(const cn_cbor *cb, int depth, void *context)
 {
 	cn_write_state *ws = context;
 	UNUSED_PARAM(depth);
@@ -279,6 +290,7 @@
 				CHECK(_write_positive(ws, CN_CBOR_ARRAY, cb->length));
 			}
 			break;
+
 		case CN_CBOR_MAP:
 			if (is_indefinite(cb)) {
 				write_byte_ensured(IB_MAP | AI_INDEF);
@@ -287,6 +299,7 @@
 				CHECK(_write_positive(ws, CN_CBOR_MAP, cb->length / 2));
 			}
 			break;
+
 		case CN_CBOR_BYTES_CHUNKED:
 		case CN_CBOR_TEXT_CHUNKED:
 			write_byte_ensured(_xlate[cb->type] | AI_INDEF);
@@ -322,21 +335,23 @@
 
 #ifndef CBOR_NO_FLOAT
 		case CN_CBOR_DOUBLE:
-			CHECK(_write_double(ws, cb->v.dbl));
+			CHECK(_write_double(ws, cb->v.dbl, (cb->flags & CN_CBOR_FL_KEEP_FLOAT_SIZE) ? 64 : 0));
 			break;
 
 		case CN_CBOR_FLOAT:
-			CHECK(_write_double(ws, cb->v.f));
-#endif /* CBOR_NO_FLOAT */
+			CHECK(_write_double(ws, cb->v.f, (cb->flags & CN_CBOR_FL_KEEP_FLOAT_SIZE) ? 32 : 0));
 			break;
+#endif /* CBOR_NO_FLOAT */
 
 		case CN_CBOR_INVALID:
-			ws->offset = -1;
-			break;
+		default:
+			return false;
 	}
+
+	return true;
 }
 
-void _encoder_breaker(const cn_cbor *cb, int depth, void *context)
+bool _encoder_breaker(const cn_cbor *cb, int depth, void *context)
 {
 	cn_write_state *ws = context;
 	UNUSED_PARAM(cb);
@@ -348,19 +363,19 @@
 #ifdef CN_INCLUDE_DUMPER
 	}
 #endif
+	return true;
 }
 
 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};
+	cn_write_state ws = {buf, buf_offset, buf_size - buf_offset};
 	if (!ws.buf && ws.size <= 0) {
 		ws.size = (ssize_t)(((size_t)-1) / 2);
 	}
-	_visit(cb, _encoder_visitor, _encoder_breaker, &ws);
-	if (ws.offset < 0) {
+	if (!_visit(cb, _encoder_visitor, _encoder_breaker, &ws)) {
 		return -1;
 	}
-	return ws.offset - buf_offset;
+	return (ssize_t)(ws.offset - buf_offset);
 }
 
 #ifdef __cplusplus
diff --git a/src/cn-print.c b/src/cn-print.c
index 38f844a..ca0f065 100644
--- a/src/cn-print.c
+++ b/src/cn-print.c
@@ -29,15 +29,15 @@
 
 typedef struct _write_state {
 	char *rgbOutput;
-	ssize_t ib;
+	size_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);
+typedef bool (*cn_visit_func)(const cn_cbor *cb, int depth, void *context);
+extern bool _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'};
 
@@ -53,40 +53,44 @@
 	return true;
 }
 
-void write_data(cn_write_state *ws, const char *sz, size_t cb)
+bool write_data(cn_write_state *ws, const char *sz, size_t cb)
 {
 	if (_isWritable(ws, cb)) {
-		if (ws->rgbOutput != NULL)
+		if (ws->rgbOutput != NULL) {
 			memcpy(ws->rgbOutput + ws->ib, sz, cb);
+		}
 		ws->ib += cb;
+		return true;
 	}
+	return false;
 }
 
-void _doIndent(cn_write_state *ws, int depth)
+bool _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;
+	const size_t cbIndentWith = strlen(ws->szIndentWith);
+	const size_t cbIndent = depth * cbIndentWith;
 
 	if (ws->rgbOutput == NULL) {
 		ws->ib += cbIndent;
-		return;
+		return true;
 	}
 
-	if (_isWritable(ws, cbIndent)) {
-		for (i = 0; i < depth; i++) {
-			memcpy(sz, ws->szIndentWith, cbIndentWith);
-			sz += cbIndentWith;
-		}
+	if (!_isWritable(ws, cbIndent)) {
+		return false;
+	}
+	for (i = 0; i < depth; i++) {
+		memcpy(sz, ws->szIndentWith, cbIndentWith);
+		sz += cbIndentWith;
 	}
 
 	ws->ib += cbIndent;
 
-	return;
+	return true;
 }
 
-void _print_encoder(const cn_cbor *cb, int depth, void *context)
+bool _print_encoder(const cn_cbor *cb, int depth, void *context)
 {
 	int i;
 	char rgchT[256];
@@ -207,17 +211,22 @@
 			}
 		}
 	}
+	return true;
 }
 
-void _print_breaker(const cn_cbor *cb, int depth, void *context)
+bool _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);
+				if (!write_data(ws, ws->szEndOfLine, strlen(ws->szEndOfLine))) {
+					return false;
+				}
+				if (!_doIndent(ws, depth)) {
+					return false;
+				}
 			}
 
 			write_data(ws, "]", 1);
@@ -237,6 +246,7 @@
 		default:
 			break;
 	}
+	return true;
 }
 
 ssize_t cn_cbor_printer_write(char *rgbBuffer,
@@ -249,10 +259,14 @@
 	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);
+	if (!_visit(cb, _print_encoder, _print_breaker, &ws)) {
+		return -1;
+	}
+	if (!write_data(&ws, rgchZero, 1)) {
+		return -1;
+	}
 
-	return ws.ib;
+	return (ssize_t)ws.ib;
 }
 
 #ifdef EMACS_INDENTATION_HELPER
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index c0b76d7..f413543 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -15,6 +15,9 @@
 endfunction()
 
 create_test(cbor)
+# create_test(file)
+create_test(memory)
+target_sources(memory_test PRIVATE context.c)
 include(CTest)
 
 if(APPLE)
diff --git a/test/context.c b/test/context.c
new file mode 100644
index 0000000..75596c4
--- /dev/null
+++ b/test/context.c
@@ -0,0 +1,172 @@
+#include <stdlib.h>
+#ifdef _MSC_VER
+#endif
+#include <stdio.h>
+#include <memory.h>
+#include <assert.h>
+
+#include <cn-cbor/cn-cbor.h>
+
+#ifdef USE_CBOR_CONTEXT
+#include "context.h"
+
+typedef unsigned char byte;
+
+typedef struct {
+	cn_cbor_context context;
+	byte *pFirst;
+	unsigned int iFailLeft;
+	int allocCount;
+} MyContext;
+
+typedef struct _MyItem {
+	int allocNumber;
+	struct _MyItem *pNext;
+	size_t size;
+	byte pad[4];
+	byte data[4];
+} MyItem;
+
+bool CheckMemory(MyContext *pContext)
+{
+	MyItem *p = NULL;
+	//  Walk memory and check every block
+
+	for (p = (MyItem *)pContext->pFirst; p != NULL; p = p->pNext) {
+		if (p->pad[0] == (byte)0xab) {
+			//  Block has been freed
+			for (unsigned i = 0; i < p->size + 8; i++) {
+				if (p->pad[i] != (byte)0xab) {
+					fprintf(stderr, "Freed block is modified");
+					assert(false);
+				}
+			}
+		}
+		else if (p->pad[0] == (byte)0xef) {
+			for (unsigned i = 0; i < 4; i++) {
+				if ((p->pad[i] != (byte)0xef) || (p->pad[i + 4 + p->size] != (byte)0xef)) {
+					fprintf(stderr, "Current block was overrun");
+					assert(false);
+				}
+			}
+		}
+		else {
+			fprintf(stderr, "Incorrect pad value");
+			assert(false);
+		}
+	}
+
+	return true;
+}
+
+void *MyCalloc(size_t count, size_t size, void *context)
+{
+	MyItem *pb = NULL;
+	MyContext *myContext = (MyContext *)context;
+
+	CheckMemory(myContext);
+
+	if (myContext->iFailLeft != -1) {
+		if (myContext->iFailLeft == 0) {
+			return NULL;
+		}
+		myContext->iFailLeft--;
+	}
+
+	pb = (MyItem *)malloc(sizeof(MyItem) + count * size);
+
+	memset(pb, 0xef, sizeof(MyItem) + count * size);
+	memset(&pb->data, 0, count * size);
+
+	pb->pNext = (struct _MyItem *)myContext->pFirst;
+	myContext->pFirst = (byte *)pb;
+	pb->size = count * size;
+	pb->allocNumber = myContext->allocCount++;
+
+	return &pb->data;
+}
+
+void MyFree(void *ptr, void *context)
+{
+	MyItem *pb = (MyItem *)((byte *)ptr - sizeof(MyItem) + 4);
+	MyContext *myContext = (MyContext *)context;
+	MyItem *pItem = NULL;
+
+	CheckMemory(myContext);
+	if (ptr == NULL) {
+		return;
+	}
+
+	for (pItem = (MyItem *)myContext->pFirst; pItem != NULL; pItem = pItem->pNext) {
+		if (pItem == pb) {
+			break;
+		}
+	}
+
+	if (pItem == NULL) {
+		//  Not an item we allocated
+		assert(false);
+	}
+
+	if (pb->pad[0] == 0xab) {
+		// Item has already been freed
+		assert(false);
+	}
+
+	memset(&pb->pad, 0xab, pb->size + 8);
+}
+
+cn_cbor_context *CreateContext(unsigned int iFailPoint)
+{
+	MyContext *p = malloc(sizeof(MyContext));
+
+	p->context.calloc_func = MyCalloc;
+	p->context.free_func = MyFree;
+	p->context.context = p;
+	p->pFirst = NULL;
+	p->iFailLeft = iFailPoint;
+	p->allocCount = 0;
+
+	return &p->context;
+}
+
+void FreeContext(cn_cbor_context *pContext)
+{
+	MyContext *myContext = (MyContext *)pContext;
+	MyItem *pItem;
+	MyItem *pItem2;
+
+	CheckMemory(myContext);
+
+	for (pItem = (MyItem *)myContext->pFirst; pItem != NULL; pItem = pItem2) {
+		pItem2 = pItem->pNext;
+		free(pItem);
+	}
+
+	free(myContext);
+
+	return;
+}
+
+int IsContextEmpty(const cn_cbor_context *pContext)
+{
+	MyContext *myContext = (MyContext *)pContext;
+	MyItem *p;
+	int i = 0;
+
+	//  Walk memory and check every block
+
+	for (p = (MyItem *)myContext->pFirst; p != NULL; p = p->pNext) {
+		if (p->pad[0] == (byte)0xab) {
+			//  Block has been freed
+		}
+		else {
+			//  This block has not been freed
+			i += 1;
+		}
+	}
+
+	return i;
+}
+
+#endif	// USE_CBOR_CONTEXT
diff --git a/test/context.h b/test/context.h
new file mode 100644
index 0000000..96c2315
--- /dev/null
+++ b/test/context.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#ifdef USE_CBOR_CONTEXT
+
+extern cn_cbor_context* CreateContext(unsigned int failAt);
+extern void FreeContext(cn_cbor_context* pContext);
+int IsContextEmpty(const cn_cbor_context* pContext);
+
+#endif	// USE_CBOR_CONTEXT
diff --git a/test/file_test.c b/test/file_test.c
new file mode 100644
index 0000000..bc0e820
--- /dev/null
+++ b/test/file_test.c
@@ -0,0 +1,179 @@
+#ifndef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "cn-cbor/cn-cbor.h"
+
+#ifdef USE_CBOR_CONTEXT
+#define CBOR_CONTEXT_PARAM , NULL
+#else
+#define CBOR_CONTEXT_PARAM
+#endif
+
+#define ERROR(msg, p) fprintf(stderr, "ERROR: " msg " %s\n", (p));
+
+static unsigned char *load_file(const char *filepath, unsigned char **end)
+{
+	struct stat st;
+	if (stat(filepath, &st) == -1) {
+		ERROR("can't find file", filepath);
+		return 0;
+	}
+	int fd = open(filepath, _O_RDONLY | _O_BINARY);
+	if (fd == -1) {
+		ERROR("can't open file", filepath);
+		return 0;
+	}
+	unsigned char *text = malloc(st.st_size + 1);  // this is not going to be freed
+	if (st.st_size != read(fd, text, st.st_size)) {
+		ERROR("can't read file", filepath);
+		close(fd);
+		return 0;
+	}
+	close(fd);
+	text[st.st_size] = '\0';
+	*end = text + st.st_size;
+	return text;
+}
+
+static void dump(const cn_cbor *cb, char *out, char **end, int indent)
+{
+	if (!cb)
+		goto done;
+	int i;
+	cn_cbor *cp;
+	char finchar = ')'; /* most likely */
+
+#define CPY(s, l)      \
+	memcpy(out, s, l); \
+	out += l;
+#define OUT(s) CPY(s, sizeof(s) - 1)
+#define PRF(f, a) out += sprintf(out, f, a)
+
+	for (i = 0; i < indent; i++)
+		*out++ = ' ';
+	switch (cb->type) {
+		case CN_CBOR_TEXT_CHUNKED:
+			OUT("(_\n");
+			goto sequence;
+		case CN_CBOR_BYTES_CHUNKED:
+			OUT("(_\n\n");
+			goto sequence;
+		case CN_CBOR_TAG:
+			PRF("%ld(\n", cb->v.sint);
+			goto sequence;
+		case CN_CBOR_ARRAY:
+			finchar = ']';
+			OUT("[\n");
+			goto sequence;
+		case CN_CBOR_MAP:
+			finchar = '}';
+			OUT("{\n");
+			goto sequence;
+		sequence:
+			for (cp = cb->first_child; cp; cp = cp->next) {
+				dump(cp, out, &out, indent + 2);
+			}
+			for (i = 0; i < indent; i++)
+				*out++ = ' ';
+			*out++ = finchar;
+			break;
+		case CN_CBOR_BYTES:
+			OUT("h'");
+			for (i = 0; i < cb->length; i++)
+				PRF("%02x", cb->v.str[i] & 0xff);
+			*out++ = '\'';
+			break;
+		case CN_CBOR_TEXT:
+			*out++ = '"';
+			CPY(cb->v.str, cb->length); /* should escape stuff */
+			*out++ = '"';
+			break;
+		case CN_CBOR_NULL:
+			OUT("null");
+			break;
+		case CN_CBOR_TRUE:
+			OUT("true");
+			break;
+		case CN_CBOR_FALSE:
+			OUT("false");
+			break;
+		case CN_CBOR_UNDEF:
+			OUT("simple(23)");
+			break;
+		case CN_CBOR_INT:
+			PRF("%ld", cb->v.sint);
+			break;
+		case CN_CBOR_UINT:
+			PRF("%lu", cb->v.uint);
+			break;
+		case CN_CBOR_DOUBLE:
+			PRF("%e", cb->v.dbl);
+			break;
+		case CN_CBOR_SIMPLE:
+			PRF("simple(%ld)", cb->v.sint);
+			break;
+		default:
+			PRF("???%d???", cb->type);
+			break;
+	}
+	*out++ = '\n';
+done:
+	*end = out;
+}
+
+const char *err_name[] = {
+	"CN_CBOR_NO_ERROR",
+	"CN_CBOR_ERR_OUT_OF_DATA",
+	"CN_CBOR_ERR_NOT_ALL_DATA_CONSUMED",
+	"CN_CBOR_ERR_ODD_SIZE_INDEF_MAP",
+	"CN_CBOR_ERR_BREAK_OUTSIDE_INDEF",
+	"CN_CBOR_ERR_MT_UNDEF_FOR_INDEF",
+	"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)
+{
+	struct cn_cbor_errback back;
+	const cn_cbor *ret = cn_cbor_decode(buf, len CBOR_CONTEXT_PARAM, &back);
+	if (ret)
+		printf("oops 1");
+	printf("%s at %d\n", err_name[back.err], back.pos);
+}
+
+int main(void)
+{
+	char buf[100000];
+	unsigned char *end;
+	char *bufend;
+	unsigned char *s = load_file("cases.cbor", &end);
+	printf("%zd\n", end - s);
+	cn_cbor *cb = cn_cbor_decode(s, end - s CBOR_CONTEXT_PARAM, 0);
+	if (cb) {
+		dump(cb, buf, &bufend, 0);
+		*bufend = 0;
+		printf("%s\n", buf);
+		cn_cbor_free(cb CBOR_CONTEXT_PARAM);
+		cb = 0; /* for leaks testing */
+	}
+	cn_cbor_decode_test((const unsigned char *)"\xff", 1);		   /* break outside indef */
+	cn_cbor_decode_test((const unsigned char *)"\x1f", 1);		   /* mt undef for indef */
+	cn_cbor_decode_test((const unsigned char *)"\x00\x00", 2);	   /* not all data consumed */
+	cn_cbor_decode_test((const unsigned char *)"\x81", 1);		   /* out of data */
+	cn_cbor_decode_test((const unsigned char *)"\x1c", 1);		   /* reserved ai */
+	cn_cbor_decode_test((const unsigned char *)"\xbf\x00\xff", 3); /* odd size indef map */
+	cn_cbor_decode_test((const unsigned char *)"\x7f\x40\xff", 3); /* wrong nesting in indef string */
+																   // system("leaks test");
+}
+
+/* cn-cbor.c:112:    CN_CBOR_FAIL("out of memory"); */
diff --git a/test/memory_test.c b/test/memory_test.c
new file mode 100644
index 0000000..88c66f7
--- /dev/null
+++ b/test/memory_test.c
@@ -0,0 +1,209 @@
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#else
+#endif
+#include <string.h>
+
+#include "cn-cbor/cn-cbor.h"
+#include "context.h"
+
+#ifdef USE_CBOR_CONTEXT
+#define CBOR_CONTEXT_PARAM , NULL
+#else
+#define CBOR_CONTEXT_PARAM
+#endif
+
+int CFails;
+
+void CreateTests()
+{
+	cn_cbor_context* context = CreateContext(-1);
+
+	//  Check the simple create/delete for memory leaks.
+
+	cn_cbor* cbor = cn_cbor_map_create(context, NULL);
+	cn_cbor_free(cbor, context);
+
+	byte* pb = (byte*)context->calloc_func(10, 10, context);
+	cbor = cn_cbor_data_create2(pb, 10, 0, context, NULL);
+	cn_cbor_free(cbor, context);
+
+	char* sz = (char*)context->calloc_func(10, 1, context);
+	strcpy(sz, "ABC");
+	cbor = cn_cbor_string_create2(sz, 0, context, NULL);
+	cn_cbor_free(cbor, context);
+
+	cbor = cn_cbor_string_create("This is a string", context, NULL);
+	cn_cbor_dont_free_data(cbor);
+	cn_cbor_free(cbor, context);
+
+	cbor = cn_cbor_int_create(20, context, NULL);
+	cn_cbor_free(cbor, context);
+
+#ifndef CBOR_NO_FLOATS
+	cbor = cn_cbor_float_create((float)20.2, context, NULL);
+	cn_cbor_free(cbor, context);
+
+	cbor = cn_cbor_double_create(203.3, context, NULL);
+	cn_cbor_free(cbor, context);
+#endif
+
+	cbor = cn_cbor_array_create(context, NULL);
+	cn_cbor_free(cbor, context);
+
+	cbor = cn_cbor_bool_create(false, context, NULL);
+	cn_cbor_free(cbor, context);
+
+	cbor = cn_cbor_null_create(context, NULL);
+	cn_cbor_free(cbor, context);
+
+	cbor = cn_cbor_simple_create(23, context, NULL);
+	cn_cbor_free(cbor, context);
+
+	if (IsContextEmpty(context) > 0) {
+		CFails += 1;
+	}
+
+	//  Test more complex stuctures
+
+	cn_cbor* cbor_map = cn_cbor_map_create(context, NULL);
+	cn_cbor* cbor_array = cn_cbor_array_create(context, NULL);
+	cn_cbor* cbor2 = NULL;
+
+	for (int i = 0; i < 10; i++) {
+		cbor2 = cn_cbor_int_create(i, context, NULL);
+		cbor = cn_cbor_int_create(i, context, NULL);
+		cn_cbor_map_put(cbor_map, cbor, cbor2, NULL);
+
+		cbor = cn_cbor_int_create(i, context, NULL);
+		cn_cbor_array_append(cbor_array, cbor, NULL);
+	}
+
+	cn_cbor_mapput_string(cbor_map, "KEY", cn_cbor_int_create(20, context, NULL), context, NULL);
+	sz = (char*)context->calloc_func(10, 1, context);
+	strcpy(sz, "ABC");
+	cn_cbor_mapput_string2(cbor_map, sz, cn_cbor_int_create(-20, context, NULL), 0, context, NULL);
+
+	cn_cbor_mapput_int(cbor_map, -22, cn_cbor_simple_create(99, context, NULL), context, NULL);
+
+	cn_cbor_array_append(cbor_array, cbor_map, NULL);
+	cbor_array = cn_cbor_tag_create(99, cbor_array, context, NULL);
+	cn_cbor_free(cbor_array, context);
+
+	if (IsContextEmpty(context) > 0) {
+		CFails += 1;
+	}
+}
+
+void DecoderTests() {}
+
+void EncoderTests()
+{
+	cn_cbor_context* context = CreateContext(-1);
+
+	cn_cbor* cborRoot = cn_cbor_array_create(context, NULL);
+
+	cn_cbor* cbor = cn_cbor_array_create(context, NULL);
+	cbor->flags |= CN_CBOR_FL_INDEF;
+
+	cn_cbor* cbor2 = cn_cbor_simple_create(22, context, NULL);
+	cn_cbor_array_append(cbor, cbor2, NULL);
+	cbor2 = cn_cbor_simple_create(21, context, NULL);
+	cn_cbor_array_append(cbor, cbor2, NULL);
+	cn_cbor_array_append(cborRoot, cbor, NULL);
+
+	cbor = cn_cbor_bool_create(true, context, NULL);
+	cn_cbor_array_append(cborRoot, cbor, NULL);
+
+	cbor = cn_cbor_map_create(context, NULL);
+	cbor2 = cn_cbor_string_create("Text1", context, NULL);
+	cn_cbor_mapput_int(cbor, 5, cbor2, context, NULL);
+	cbor2 = cn_cbor_int_create(99, context, NULL);
+	cn_cbor_mapput_string(cbor, "key", cbor2, context, NULL);
+	cn_cbor_array_append(cborRoot, cbor, NULL);
+
+	cbor = cn_cbor_map_create(context, NULL);
+	cbor->flags |= CN_CBOR_FL_INDEF;
+	cbor2 = cn_cbor_string_create("Text1", context, NULL);
+	cn_cbor_mapput_int(cbor, 5, cbor2, context, NULL);
+	cbor2 = cn_cbor_int_create(99, context, NULL);
+	cn_cbor_mapput_string(cbor, "key", cbor2, context, NULL);
+	cn_cbor_array_append(cborRoot, cbor, NULL);
+
+	cbor = cn_cbor_chunked_create(CN_CBOR_BYTES, context, NULL);
+	byte* pb = context->calloc_func(10, 10, context);
+	cbor2 = cn_cbor_data_create2(pb, 100, 0, context, NULL);
+	cn_cbor_chunked_append(cbor, cbor2, NULL);
+	byte data2[20] = {1, 2, 3, 4, 5, 6, 7};
+	cbor2 = cn_cbor_data_create(data2, 20, context, NULL);
+	cn_cbor_chunked_append(cbor, cbor2, NULL);
+	cn_cbor_array_append(cborRoot, cbor, NULL);
+
+	cbor = cn_cbor_chunked_create(CN_CBOR_TEXT, context, NULL);
+	cbor2 = cn_cbor_string_create("This is a string", context, NULL);
+	cn_cbor_chunked_append(cbor, cbor2, NULL);
+	char* s = context->calloc_func(20, 1, context);
+	strcpy(s, "Hi Mom");
+	cbor2 = cn_cbor_string_create2(s, 0, context, NULL);
+	cn_cbor_chunked_append(cbor, cbor2, NULL);
+	cn_cbor_array_append(cborRoot, cbor, NULL);
+
+	cbor = cn_cbor_simple_create(4, context, NULL);
+	cbor = cn_cbor_tag_create(99, cbor, context, NULL);
+	cn_cbor_array_append(cborRoot, cbor, NULL);
+
+#ifndef CBOR_NO_FLOATS
+	cbor = cn_cbor_float_create(9, context, NULL);
+	cn_cbor_array_append(cborRoot, cbor, NULL);
+
+	cbor = cn_cbor_double_create(33.225932523223, context, NULL);
+	cn_cbor_array_append(cborRoot, cbor, NULL);
+
+	cbor = cn_cbor_float_create(9, context, NULL);
+	cbor->flags |= CN_CBOR_FL_KEEP_FLOAT_SIZE;
+	cn_cbor_array_append(cborRoot, cbor, NULL);
+
+	cbor = cn_cbor_double_create(9, context, NULL);
+	cbor->flags |= CN_CBOR_FL_KEEP_FLOAT_SIZE;
+	cn_cbor_array_append(cborRoot, cbor, NULL);
+#endif
+
+	ssize_t cb = cn_cbor_encoder_write(NULL, 0, 0, cborRoot);
+	pb = (byte*)context->calloc_func(cb + 2, 1, context);
+
+	ssize_t cb2 = cn_cbor_encoder_write(pb, 0, cb - 1, cborRoot);
+	if (cb2 != -1) {
+		CFails += 1;
+	}
+
+	cb2 = cn_cbor_encoder_write(pb, 0, cb, cborRoot);
+	if (cb2 != cb) {
+		CFails += 1;
+	}
+
+	cb2 = cn_cbor_encoder_write(pb, 0, cb + 1, cborRoot);
+	if (cb != cb2) {
+		CFails += 1;
+	}
+
+	cn_cbor_free(cborRoot, context);
+
+	cborRoot = cn_cbor_decode(pb, cb2, context, NULL);
+
+	cn_cbor_free(cborRoot, context);
+
+	context->free_func(pb, context);
+
+	if (IsContextEmpty(context) > 0) {
+		CFails += 1;
+	}
+}
+
+int main(void)
+{
+	CreateTests();
+	EncoderTests();
+	DecoderTests();
+
+	return CFails;
+}