Merge pull request #3 from sbertin-telular/null_for_size_jimsch

Determine buffer size needed without encoding.
diff --git a/include/cn-cbor/cn-cbor.h b/include/cn-cbor/cn-cbor.h
index 109eb9e..9a36ac5 100644
--- a/include/cn-cbor/cn-cbor.h
+++ b/include/cn-cbor/cn-cbor.h
@@ -299,10 +299,13 @@
 /**
  * Write a CBOR value and all of the child values.
  *
- * @param[in]  buf        The buffer into which to write
+ * @param[in]  buf        The buffer into which to write. May be NULL to
+ *                        determine the necessary size.
  * @param[in]  buf_offset The offset (in bytes) from the beginning of the buffer
  *                        to start writing at
- * @param[in]  buf_size   The total length (in bytes) of the buffer
+ * @param[in]  buf_size   The total length (in bytes) of the buffer. If buf is
+ *                        NULL, this is an upper limit and may be 0 to specify
+ *                        no limit.
  * @param[in]  cb         [description]
  * @return                -1 on fail, or number of bytes written
  */
diff --git a/src/cn-encoder.c b/src/cn-encoder.c
index 939c0e3..76ff50b 100644
--- a/src/cn-encoder.c
+++ b/src/cn-encoder.c
@@ -49,13 +49,20 @@
 }
 
 #define write_byte_and_data(b, data, sz) \
-    ws->buf[ws->offset++] = (b); \
-    memcpy(ws->buf + ws->offset, (data), (sz)); \
-    ws->offset += sz;
+if(ws->buf) { \
+  ws->buf[ws->offset++] = (b); \
+  memcpy(ws->buf+ws->offset, (data), (sz)); \
+} else { \
+  ws->offset++; \
+} \
+ws->offset += sz;
 
 #define write_byte(b) \
-{ if (ws->buf == NULL) ws->offset++; \
-else ws->buf[ws->offset++] = (b); }
+if(ws->buf) { \
+  ws->buf[ws->offset++] = (b); \
+} else { \
+  ws->offset++; \
+}
 
 #define write_byte_ensured(b) \
 ensure_writable(1); \
@@ -266,7 +273,9 @@
   case CN_CBOR_BYTES:
     CHECK(_write_positive(ws, cb->type, cb->length));
     ensure_writable(cb->length);
-    memcpy(ws->buf+ws->offset, cb->v.str, cb->length);
+    if (ws->buf) {
+      memcpy(ws->buf+ws->offset, cb->v.str, cb->length);
+    }
     ws->offset += cb->length;
     break;
 
@@ -320,6 +329,7 @@
 			      const cn_cbor *cb)
 {
   cn_write_state ws = { buf, buf_offset, buf_size };
+  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) { return -1; }
   return ws.offset - buf_offset;
diff --git a/test/cbor_test.c b/test/cbor_test.c
index 3266631..857363b 100644
--- a/test/cbor_test.c
+++ b/test/cbor_test.c
@@ -132,6 +132,7 @@
     size_t i;
     unsigned char encoded[1024];
     ssize_t enc_sz;
+    ssize_t enc_sz2;
 
     for (i=0; i<sizeof(tests)/sizeof(char*); i++) {
         ASSERT_TRUE(parse_hex(tests[i], &b));
@@ -141,7 +142,9 @@
         ASSERT_EQUAL(err.err, CN_CBOR_NO_ERROR);
         ASSERT_NOT_NULL(cb);
 
+        enc_sz2 = cn_cbor_encoder_write(NULL, 0, sizeof(encoded), cb);
         enc_sz = cn_cbor_encoder_write(encoded, 0, sizeof(encoded), cb);
+        ASSERT_EQUAL(enc_sz, enc_sz2);
         ASSERT_DATA(b.ptr, b.sz, encoded, enc_sz);
         free(b.ptr);
         cn_cbor_free(cb CONTEXT_NULL);
@@ -180,6 +183,7 @@
     size_t i;
     unsigned char encoded[1024];
     ssize_t enc_sz;
+    ssize_t enc_sz2;
 
     for (i=0; i<sizeof(basic_tests)/sizeof(char*); i+=2) {
         ASSERT_TRUE(parse_hex(basic_tests[i], &b));
@@ -190,7 +194,9 @@
         ASSERT_EQUAL(err.err, CN_CBOR_NO_ERROR);
         ASSERT_NOT_NULL(cb);
 
+        enc_sz2 = cn_cbor_encoder_write(NULL, 0, sizeof(encoded), cb);
         enc_sz = cn_cbor_encoder_write(encoded, 0, sizeof(encoded), cb);
+        ASSERT_EQUAL(enc_sz, enc_sz2);
         ASSERT_DATA(b2.ptr, b2.sz, encoded, enc_sz);
         free(b.ptr);
         free(b2.ptr);
@@ -211,7 +217,9 @@
         ASSERT_NULL(cb);
 #endif /* CBOR_NO_FLOAT */
 
+        /* enc_sz2 = cn_cbor_encoder_write(NULL, 0, sizeof(encoded), cb); */
         /* enc_sz = cn_cbor_encoder_write(encoded, 0, sizeof(encoded), cb); */
+        /* ASSERT_EQUAL(enc_sz, enc_sz2); */
         /* ASSERT_DATA(b2.ptr, b2.sz, encoded, enc_sz); */
         free(b.ptr);
         free(b2.ptr);
@@ -274,13 +282,16 @@
     size_t i;
     unsigned char encoded[1024];
     ssize_t enc_sz;
+    ssize_t enc_sz2;
 
     for (i=0; i<sizeof(tests)/sizeof(char*); i++) {
         ASSERT_TRUE(parse_hex(tests[i], &b));
         cb = cn_cbor_decode(b.ptr, b.sz CONTEXT_NULL, &err);
         ASSERT_NOT_NULL(cb);
 
+        enc_sz2 = cn_cbor_encoder_write(NULL, 0, sizeof(encoded), cb);
         enc_sz = cn_cbor_encoder_write(encoded, 0, sizeof(encoded), cb);
+        ASSERT_EQUAL(enc_sz, enc_sz2);
         ASSERT_DATA(b.ptr, b.sz, encoded, enc_sz);
 
         free(b.ptr);
@@ -441,6 +452,8 @@
   ASSERT_NOT_NULL(cdata);
 
   ASSERT_TRUE(cn_cbor_mapput_int(map, 0, cdata, CONTEXT_NULL_COMMA NULL));
+  enc_sz = cn_cbor_encoder_write(NULL, 0, sizeof(encoded), map);
+  ASSERT_EQUAL(7, enc_sz);
   enc_sz = cn_cbor_encoder_write(encoded, 0, sizeof(encoded), map);
   ASSERT_EQUAL(7, enc_sz);
 }