Commit dumper program

Commit the dumper program in
Changes to get it to build w/ the 64-bit version of Visual Studio
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4ac2dcd..c186050 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -21,9 +21,10 @@
 option (verbose         "Produce verbose makefile output" OFF)
 option (optimize        "Optimize for size" OFF)
 option (fatal_warnings  "Treat build warnings as error" OFF)
-option (coveralls       "Generate coveralls data" ON)
-option ( coveralls_send "Send data to coveralls site" ON )
+option (coveralls       "Generate coveralls data" OFF)
+option ( coveralls_send "Send data to coveralls site" OFF )
 option (build_docs      "Create docs using Doxygen" ${DOXYGEN_FOUND} )
+option (build_shared_libs "Build Shared Libraries" OFF)
 
 set ( dist_dir          ${CMAKE_BINARY_DIR}/dist )
 set ( prefix            ${CMAKE_INSTALL_PREFIX} )
@@ -61,9 +62,14 @@
       add_definitions( /WX )
    endif ()
 else ()
-   message ( FATAL_ERROR "unhandled compiler id: ${CMAKE_C_COMPILER_ID}" )
+    message ( FATAL_ERROR "unhandled compiler id: ${CMAKE_C_COMPILER_ID}" )
 endif ()
 
+set (LIB_TYPE STATIC)
+if (build_shared_libs)
+   set (LIB_TYPE SHARED)
+endif (build_shared_libs)
+
 if (versbose)
    set (CMAKE_VERBOSE_MAKEFILE ON)
 endif ()
@@ -95,7 +101,7 @@
   project_cn-cbor
   GIT_REPOSITORY https://github.com/jimsch/cn-cbor
   GIT_TAG PrettyPrint
-  CMAKE_ARGS -Doptimize=OFF -Duse_context=ON -Dbuild_docs=OFF -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -Dcoveralls=OFF
+  CMAKE_ARGS -Doptimize=OFF -Duse_context=ON -Dbuild_docs=OFF -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR> -Dcoveralls=OFF -Dbuild_shared_libs=$(build_shared_libs)
   INSTALL_DIR "${dist_dir}"
   UPDATE_DISCONNECTED 1
 )
@@ -110,3 +116,5 @@
 ## include the parts
 add_subdirectory(src)
 add_subdirectory(test)
+add_subdirectory(dumper)
+
diff --git a/dump/dump.c b/dump/dump.c
new file mode 100644
index 0000000..3102593
--- /dev/null
+++ b/dump/dump.c
@@ -0,0 +1,26 @@
+#include <stdio.h>
+#include <cn-cbor/cn-cbor.h>
+
+void dump_file(char * fileName)
+{
+    FILE * fp;
+
+
+    fp = fopen(fileName, "rb");
+    
+}
+
+int main(int argc, char ** argv)
+{
+    for (i=1; i<argc; i++) {
+        if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
+            fprintf(stderr, "No options defined for %s\n", argv[0]);
+            exit(-1);
+        }
+        else {
+            dump_file(argv[i]);
+        }
+    }
+    
+    exit(0);
+}
diff --git a/dumper/CMakeLists.txt b/dumper/CMakeLists.txt
new file mode 100644
index 0000000..cc8a46f
--- /dev/null
+++ b/dumper/CMakeLists.txt
@@ -0,0 +1,31 @@
+#
+#  Compiling/running tests
+#
+
+if (use_context)
+   add_definitions(-DUSE_CBOR_CONTEXT)
+endif()
+
+set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dist_dir}/dumper )
+
+add_executable ( cose_dumper dumper.c )
+
+target_link_libraries (cose_dumper PRIVATE cose-c )
+
+## OpenSSL
+message ( "LIBS: *** ${OPENSSL_LIBRARIES}")
+message ( "INC: *** ${OPENSSL_INCLUDE_DIR}")
+
+target_include_directories(cose_dumper PRIVATE ${OPENSSL_INCLUDE_DIR})
+#target_link_libraries( cose_dumper PRIVATE event_openssl)
+target_link_libraries( cose_dumper PRIVATE ${OPENSSL_LIBRARIES} )
+target_link_libraries( cose_dumper PRIVATE cn-cbor )
+
+target_include_directories ( cose_dumper PRIVATE ../include )
+target_include_directories ( cose_dumper PRIVATE ../src )
+target_include_directories ( cose_dumper PUBLIC ../../cose/cn-cbor/include )
+target_include_directories ( cose_dumper PUBLIC ../../cn-cbor/implement/cn-cbor/include )
+
+enable_testing()
+# add_test ( NAME cose_dumper COMMAND cose_dumper )
+
diff --git a/dumper/dumper.c b/dumper/dumper.c
new file mode 100644
index 0000000..35b7d4d
--- /dev/null
+++ b/dumper/dumper.c
@@ -0,0 +1,537 @@
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <stdio.h>
+#include <cose.h>
+#include <sys/stat.h>
+#include <cn-cbor/cn-cbor.h>
+#include <io.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+typedef struct _FOO {
+    char *      fieldName;
+    int         type;
+	int			value;
+    struct _FOO * children;
+	int         count;
+	int			group;
+} FOO;
+
+FOO Recipients;
+
+FOO AlgorithmMap[32] = {
+	{ "ES512", CN_CBOR_INT, -9 },
+	{ "ES384", CN_CBOR_INT, -8 },
+	{"ES256", CN_CBOR_INT, -7},
+	{"direct", CN_CBOR_INT, -6},
+	{"A256KW", CN_CBOR_INT, -5},
+	{"A192KW", CN_CBOR_INT, -4},
+	{"A128KW", CN_CBOR_INT, -3},
+	{"AES-GCM 128", CN_CBOR_UINT, 1},
+	{"AES-GCM 192", CN_CBOR_UINT, 2},
+	{"AES-GCM 256", CN_CBOR_UINT, 3},
+	{"HMAC 256/256", CN_CBOR_UINT, 4},
+	{"HMAC 384/384", CN_CBOR_UINT, 5},
+	{"HMAC 512/512", CN_CBOR_UINT, 6},
+	{"AES-CCM-16-64-128", CN_CBOR_UINT, 10},
+	{"AES-CCM-16-64-256", CN_CBOR_UINT, 11},
+	{"AES-CCM-16-128-128", CN_CBOR_UINT, 12},
+	{"AES-CCM-16-128-256", CN_CBOR_UINT, 13},
+	{"ChaCha20/Poly1305", CN_CBOR_UINT, 24},
+	{"AES-CCM-64-64-128", CN_CBOR_UINT, 30},
+	{"AES-CCM-64-64-256", CN_CBOR_UINT, 31},
+	{"AES-CCM-64-128-128", CN_CBOR_UINT, 32},
+	{"AES-CCM-64-128-256", CN_CBOR_UINT, 33},
+	{"ECDH-ES + HKDF-256", CN_CBOR_UINT, 50},
+	{"ECDH-ES + HKDF-512", CN_CBOR_UINT, 51},
+	{"ECDH-SS + HKDF-256", CN_CBOR_UINT, 52},
+	{"ECDH-SS + HKDF-512", CN_CBOR_UINT, 53},
+	{"ECHD-ES+A128KW", CN_CBOR_UINT, 54},
+	{ "ECHD-ES+A192KW", CN_CBOR_UINT, 55 },
+	{ "ECHD-ES+A256KW", CN_CBOR_UINT, 56 },
+	{ "ECHD-SS+A128KW", CN_CBOR_UINT, 57 },
+	{ "ECHD-SS+A192KW", CN_CBOR_UINT, 58 },
+	{ "ECHD-SS+A256KW", CN_CBOR_UINT, 59 },
+};
+
+FOO KeyMap[9] = {
+	{"kty", CN_CBOR_UINT, 1 },
+	{"kid", CN_CBOR_UINT, 2 },
+	{"alg", CN_CBOR_UINT, 3, AlgorithmMap, _countof(AlgorithmMap) },
+	{"key_ops", CN_CBOR_UINT, 4},
+	{"crv", CN_CBOR_INT, -1, NULL, 0, 2},
+	{"x", CN_CBOR_INT, -2, NULL, 0, 2},
+	{"y", CN_CBOR_INT, -3, NULL, 0, 2},
+	{"d", CN_CBOR_INT, -4, NULL, 0, 2},
+	{"k", CN_CBOR_INT, -1, NULL, 0, 4}
+};
+
+FOO Key = {
+	NULL, CN_CBOR_MAP, 0, KeyMap, _countof(KeyMap)
+};
+
+FOO KeySet = {
+	NULL, CN_CBOR_ARRAY, 0, &Key, 1
+};
+
+FOO HeaderMap[26] = {
+	{ "alg", CN_CBOR_UINT, 1, AlgorithmMap, _countof(AlgorithmMap) },
+	{ "crit", CN_CBOR_UINT, 2, NULL },
+	{ "content type", CN_CBOR_UINT, 3, NULL},
+	{ "kid", CN_CBOR_UINT, 4, NULL},
+	{ "iv", CN_CBOR_UINT, 5, NULL },
+	{ "partial iv", CN_CBOR_UINT, 6, NULL },
+	{ "countersign", CN_CBOR_UINT, 7, NULL },
+	{ "ephemeral", CN_CBOR_INT, -1, KeyMap, _countof(KeyMap), 50},
+{"salt", CN_CBOR_INT, -20, NULL, 0, 50 },
+{ "U identity", CN_CBOR_INT, -21, NULL, 0, 50 },
+{ "U nonce", CN_CBOR_INT, -22, NULL, 0, 50 },
+{ "U other", CN_CBOR_INT, -23, NULL, 0, 50 },
+{ "V identity", CN_CBOR_INT, -24, NULL, 0, 50 },
+{ "V nonce", CN_CBOR_INT, -25, NULL, 0, 50 },
+{ "V other", CN_CBOR_INT, -26, NULL, 0, 50 },
+{ "static key", CN_CBOR_INT, -2, NULL, 0, 50},
+{ "static kid", CN_CBOR_INT, -3, NULL, 0, 50},
+{"salt", CN_CBOR_INT, -20, NULL, 0, 52 },
+{ "U identity", CN_CBOR_INT, -21, NULL, 0, 52 },
+{ "U nonce", CN_CBOR_INT, -22, NULL, 0, 52 },
+{ "U other", CN_CBOR_INT, -23, NULL, 0, 52 },
+{ "V identity", CN_CBOR_INT, -24, NULL, 0, 52 },
+{ "V nonce", CN_CBOR_INT, -25, NULL, 0, 52 },
+{ "V other", CN_CBOR_INT, -26, NULL, 0, 52 },
+{ "static key", CN_CBOR_INT, -2, NULL, 0, 52 },
+{ "static kid", CN_CBOR_INT, -3, NULL, 0, 52 }
+};
+
+FOO RecurseHeaderMap = {
+	NULL, CN_CBOR_MAP, 0, HeaderMap, _countof(HeaderMap)
+};
+
+FOO EncryptedBody[4] = {
+    { "protected", CN_CBOR_BYTES, 0, &RecurseHeaderMap, 1 },
+    { "unprotected", CN_CBOR_MAP, 0, HeaderMap, _countof(HeaderMap) },
+    { "ciphertext", CN_CBOR_BYTES, 0, NULL },
+    { "recipients", CN_CBOR_ARRAY, 0, &Recipients, 1 }
+};
+
+FOO Recipients = {
+    NULL, CN_CBOR_ARRAY, 0, EncryptedBody, _countof(EncryptedBody)
+};
+
+FOO MacBody[5] = {
+	{ "protected", CN_CBOR_BYTES, 0, &RecurseHeaderMap, 1 },
+	{ "unprotected", CN_CBOR_MAP, 0, HeaderMap, _countof(HeaderMap) },
+	{ "payload", CN_CBOR_BYTES, 0, NULL },
+	{ "tag", CN_CBOR_BYTES, 0, NULL },
+	{ "recipients", CN_CBOR_ARRAY, 0, &Recipients, 1 }
+};
+
+FOO Signer[5] = {
+	{ "protected", CN_CBOR_BYTES, 0, &RecurseHeaderMap, 1 },
+	{ "unprotected", CN_CBOR_MAP, 0, HeaderMap, _countof(HeaderMap) },
+	{ "signature", CN_CBOR_BYTES, 0, NULL },
+};
+
+FOO Signers = {
+	NULL, CN_CBOR_ARRAY, 0, Signer, _countof(Signer)
+};
+
+FOO SignBody[5] = {
+	{ "protected", CN_CBOR_BYTES, 0, &RecurseHeaderMap, 1 },
+	{ "unprotected", CN_CBOR_MAP, 0, HeaderMap, _countof(HeaderMap) },
+	{ "payload", CN_CBOR_BYTES, 0, NULL },
+	{ "signatures", CN_CBOR_ARRAY, 0, &Signers, 1 }
+};
+
+FOO EnvelopedMessage = {
+	NULL, CN_CBOR_ARRAY, 0, EncryptedBody, _countof(EncryptedBody)
+};
+FOO SignedMessage = {
+	NULL, CN_CBOR_ARRAY, 0, SignBody, _countof(SignBody)
+};
+FOO MacMessage = {
+	NULL, CN_CBOR_ARRAY, 0, MacBody, _countof(MacBody)
+};
+
+FOO EncryptedMessage = {
+    NULL, CN_CBOR_ARRAY, 0, EncryptedBody, _countof(EncryptedBody)-1
+};
+
+FOO EncryptedMessageWithTag = {
+    NULL, CN_CBOR_TAG, 997, &EncryptedMessage, 1
+};
+
+FOO EnvelopedMessageWithTag = {
+	NULL, CN_CBOR_TAG, 998, &EnvelopedMessage, 1
+};
+
+FOO SignedMessageWithTag = {
+	NULL, CN_CBOR_TAG, 999, &SignedMessage, 1
+};
+
+FOO MacMessageWithTag = {
+	NULL, CN_CBOR_TAG, 996, &MacMessage, 1
+};
+
+int WrapLineAt = 0;
+char OutputBuffer[4096];
+
+void WrapPrintF(FILE * fp, char * format, ...)
+{
+	va_list args;
+	char	buffer[4000];
+	char *  iRet;
+
+	va_start(args, format);
+	vsprintf(buffer, format, args);
+	if (WrapLineAt == 0) {
+		fprintf(fp, buffer);
+		return;
+	}
+
+	strcat_s(OutputBuffer, sizeof(OutputBuffer), buffer);
+
+	while (iRet = strchr(OutputBuffer, '\n')) {
+		char * t = OutputBuffer;
+		*iRet = 0;
+
+		while (strlen(t) > WrapLineAt) {
+			char x = t[WrapLineAt];
+			t[WrapLineAt] = 0;
+			fprintf(fp, t);
+			fprintf(fp, "\n");
+			t[WrapLineAt] = x;
+			t += WrapLineAt;
+		}
+
+		fprintf(fp, t);
+		fprintf(fp, "\n");
+		strcpy(OutputBuffer, iRet + 1);
+	}
+}
+
+
+void Indent(FILE * fp, int depth)
+{
+	int i;
+
+	for (i = 0; i < depth; i++) WrapPrintF(fp, "  ");
+}
+
+
+void PrintUsage()
+{
+    fprintf(stderr, "dumper [<filein> [<fileout>]]\n");
+    exit(1);
+}
+
+void DumpBytes(FILE * fp, const cn_cbor* cbor, int depth)
+{
+	int i;
+	int fText = true;
+
+	for (i = 0; i < cbor->length; i++) {
+		if ((cbor->v.bytes[i] < 32) || (cbor->v.bytes[i] > 126)) fText = false;
+	}
+
+	if (fText && (cbor->length > 0)) {
+		WrapPrintF(fp, "'");
+		for (i = 0; i < cbor->length; i++) {
+			WrapPrintF(fp, "%c", cbor->v.bytes[i]);
+		}
+		WrapPrintF(fp, "'");
+	}
+	else {
+		WrapPrintF(fp, "h'");
+		for (i = 0; i < cbor->length; i++) {
+			WrapPrintF(fp, "%02x", cbor->v.bytes[i]);
+		}
+		WrapPrintF(fp, "'");
+	}
+}
+
+void DumpTree(const cn_cbor * cbor, FILE * out, FOO *pFOO, int depth, int fField, int fValue, int fInComment)
+{
+	int i;
+	int i2;
+	const cn_cbor * cbor2;
+	const FOO * pFoo2;
+	int group;
+
+	if (pFOO != NULL) {
+		switch (pFOO->type) {
+		case CN_CBOR_TAG:
+			if (cbor->type != CN_CBOR_TAG) pFOO = NULL;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (fField && (pFOO != NULL) && (pFOO->fieldName != NULL)) {
+		if (fInComment) WrapPrintF(out, "\\ %s \\ ", pFOO -> fieldName);
+		else WrapPrintF(out, "/ %s / ", pFOO->fieldName);
+	}
+
+	switch (cbor->type) {
+	case CN_CBOR_TAG:
+		WrapPrintF(out, "%u(\n", cbor->v.uint);
+		Indent(out, depth + 1);
+		DumpTree(cbor->last_child, out, pFOO != NULL ? pFOO->children : NULL, depth+1, true, true, fInComment);
+		WrapPrintF(out, "\n");
+		Indent(out, depth);
+		WrapPrintF(out, ")");
+		break;
+
+	case CN_CBOR_ARRAY:
+		WrapPrintF(out, "[");
+		cbor2 = cbor->first_child;
+		for (i = 0; i < cbor->length; i++, cbor2 = cbor2->next) {
+			if (i != 0) WrapPrintF(out, ", ");
+			if (pFOO == NULL) pFoo2 = NULL;
+			else if (pFOO->count == 1) pFoo2 = pFOO->children;
+			else if (i >= pFOO->count) pFoo2 = NULL;
+			else pFoo2 = &pFOO->children[i];
+
+			WrapPrintF(out, "\n");
+			Indent(out, depth + 1);
+			DumpTree(cbor2, out, pFoo2, depth + 1, true, true, fInComment);
+		}
+		if (i > 0) {
+			WrapPrintF(out, "\n");
+			Indent(out, depth);
+		}
+				WrapPrintF(out, "]");
+		break;
+
+	case CN_CBOR_MAP:
+		WrapPrintF(out, "{");
+		cbor2 = cbor->first_child;
+		//  Determine the correct group - always assume it is at element UINT=1
+		group = 0;
+		for (i = 0; i < cbor->length; i+=2, cbor2 = cbor2->next->next) {
+			if ((cbor2->type == CN_CBOR_UINT) && (cbor2->v.uint == 1)) {
+				group = cbor2->next->v.uint;
+				break;
+			}
+		}
+
+		cbor2 = cbor->first_child;
+		//  Dump each element
+		for (i = 0; i < cbor->length; i+=2, cbor2 = cbor2->next) {
+			pFoo2 = NULL;
+			if (pFOO != NULL) {
+				//  Locate the right entry in foo
+				for (i2 = 0, pFoo2 = pFOO->children; i2 < pFOO->count; pFoo2++, i2 += 1) {
+					if (pFoo2->type != cbor2->type) continue;
+					switch (cbor2->type) {
+					case CN_CBOR_UINT:
+						if ((group != 0) && (pFoo2->group != 0) && (pFoo2->group != group)) continue;
+						if (pFoo2->value == cbor2->v.uint) i2 = pFOO->count + 1;
+						break;
+
+					case CN_CBOR_INT:
+						if ((group != 0) && (pFoo2->group != 0) && (pFoo2->group != group)) continue;
+						if (pFoo2->value == cbor2->v.sint) i2 = pFOO->count + 1;
+						break;
+					}
+
+					if (i2 == pFOO->count + 1) break;
+				}
+				if (i2 == pFOO->count) pFoo2 = NULL;
+			}
+			if (i != 0) WrapPrintF(out, ", ");
+			WrapPrintF(out, "\n");
+			Indent(out, depth + 1);
+			DumpTree(cbor2, out, pFoo2, depth + 1, true, false, fInComment);
+			WrapPrintF(out, ":");
+			cbor2 = cbor2->next;
+			DumpTree(cbor2, out, pFoo2, depth + 1, false, true, fInComment);
+		}
+		if (i > 0) {
+			WrapPrintF(out, "\n");
+			Indent(out, depth);
+		}
+			WrapPrintF(out, "}");
+		break;
+
+	case CN_CBOR_BYTES:
+		DumpBytes(out, cbor, depth);
+		if ((pFOO != NULL) && (pFOO->children != NULL)) {
+			const cn_cbor * cbor3 = cn_cbor_decode(cbor->v.bytes, cbor->length, NULL, NULL);
+			if (cbor3 != NULL) {
+				WrapPrintF(out, fInComment ? " \\ " : " / ");
+				DumpTree(cbor3, out, pFOO->children, depth+1, true, true, true);
+				WrapPrintF(out, fInComment ? " \\ " : " / ");
+			}
+		}
+		break;
+
+	case CN_CBOR_INT:
+		WrapPrintF(out, "%d", cbor->v.sint);
+		if (fValue) {
+			for (i = 0, pFoo2 = pFOO->children; i < pFOO->count; i++, pFoo2++) {
+				if ((pFoo2->type == CN_CBOR_INT) && (pFoo2->value == cbor->v.sint)) {
+					if (pFoo2->fieldName != NULL) {
+						if (fInComment) WrapPrintF(out, " \\ %s \\", pFoo2->fieldName);
+						else WrapPrintF(out, " / %s /", pFoo2->fieldName);
+					}
+					break;
+				}
+			}
+		}
+		break;
+
+	case CN_CBOR_UINT:
+		WrapPrintF(out, "%u", cbor->v.uint);
+		if (fValue && (pFOO != NULL)) {
+			for (i = 0, pFoo2 = pFOO->children; i < pFOO->count; i++, pFoo2++) {
+				if ((pFoo2->type == CN_CBOR_UINT) && (pFoo2->value == cbor->v.uint)) {
+					if (pFoo2->fieldName != NULL) {
+						if (fInComment) WrapPrintF(out, " \\ %s \\", pFoo2->fieldName);
+						else WrapPrintF(out, " / %s /", pFoo2->fieldName);
+					}
+					break;
+				}
+			}
+		}
+		break;
+
+	case CN_CBOR_TEXT:
+		WrapPrintF(out, "\"");
+		for (i = 0; i < cbor->length; i++) WrapPrintF(out, "%c", cbor->v.str[i]);
+		WrapPrintF(out, "\"");
+		break;
+
+	default:
+		WrapPrintF(out, "##");
+		break;
+	}
+}
+
+
+int main(int argc, char ** argv)
+{
+	int			i;
+    FILE *		in = NULL;
+    FILE *		out = NULL;
+    byte *      pb = NULL;
+    size_t      cb = 0;
+    byte        rgb[2048];
+    size_t      cbIn;
+	int			msg_type;
+	int			forXML = false;
+	FOO *		root = NULL;
+
+    for (i=1; i<argc; i++) {
+        if ((argv[i][0] == '-') || (argv[i][0] == '/')) {
+            if (strcmp(&argv[i][1], "someoption") == 0) {
+            }
+			else if (strcmp(&argv[i][1], "xml=yes") == 0) {
+				forXML = true;
+			}
+			else if (strcmp(&argv[i][1], "xml=no") == 0) forXML = false;
+			else if (strncmp(&argv[i][1], "wrap=", 5) == 0) {
+				WrapLineAt = atoi(&argv[i][6]);
+			}
+			else if (strncmp(&argv[i][1], "type=", 5) == 0) {
+				if (strcmp(&argv[i][1], "type=encrypt") == 0) root = &EncryptedMessage;
+				else if (strcmp(&argv[i][1], "type=envelope") == 0) root = &EnvelopedMessage;
+				else if (strcmp(&argv[i][1], "type=signed") == 0) root = &SignedMessage;
+				else if (strcmp(&argv[i][1], "type=mac") == 0) root = &MacMessage;
+				else if (strcmp(&argv[i][1], "type=keyset") == 0) root = &KeySet;
+				else if (strcmp(&argv[i][1], "type=key") == 0) root = &Key;
+				else PrintUsage();
+			}
+            else {
+                PrintUsage();
+                exit(1);
+            }
+        }
+        else {
+            if (in == NULL) {
+                in = fopen(argv[i], "rb");
+                if (in == NULL) {
+                    fprintf(stderr, "Unable to open file '%s'\n", argv[i]);
+                    exit(1);
+                }
+            }
+            else if (out == NULL) {
+                out = fopen(argv[i], "wt");
+                if (out == NULL) {
+                    fprintf(stderr, "Unable to open file '%s'\n", argv[i]);
+                    exit(1);
+                }
+            }
+            else {
+                PrintUsage();
+                exit(1);
+            }
+        }
+    }
+
+    //  Set defaults
+
+    if (in == NULL) {
+#ifdef _WIN32
+        in = stdin;
+        _setmode(_fileno(stdin), _O_BINARY);
+#else
+        in = fdreopen(_fileno(stdin), NULL, O_RDONLY | OPEN_O_BINARY);
+#endif
+    }
+    if (out == NULL) out = stdout;
+    
+    // Read the input to a buffer - needed for the parser
+
+	cbIn = 1;
+    while (cbIn > 0) {
+        cbIn = fread(rgb, 1, sizeof(rgb), in);
+        if (cbIn == 0) {
+            //  finished
+            break;
+        }
+
+        pb = realloc(pb, cb+cbIn);
+        if (pb == NULL) {
+            fprintf(stderr, "Error allocating memory\n");
+            exit(1);
+        }
+        memcpy(pb+cb, rgb, cbIn);
+        cb += cbIn;
+    }
+
+    //  Parse it
+
+    cn_cbor * cbor = cn_cbor_decode(pb, cb, NULL, NULL);
+	if (cbor == NULL) {
+		fprintf(stderr, "Error parsing CBOR");
+		exit(1);
+	}
+
+	if (root == NULL) {
+		if (cbor->type == CN_CBOR_TAG) {
+			switch (cbor->v.sint) {
+			case 999: root = &SignedMessageWithTag; break;
+			case 998: root = &EnvelopedMessageWithTag; break;
+			case 997: root = &EncryptedMessageWithTag; break;
+			case 996: root = &MacMessageWithTag; break;
+			}
+		}
+	}
+
+	if (forXML) {
+		fprintf(out, "<t>Size of binary file is %d bytes</t>\n\n", cb);
+		fprintf(out, "<figure><artwork type='CBORDiag'><![CDATA[\n");
+	}
+
+	DumpTree(cbor, out, root, 0, true, true, false);    
+	WrapPrintF(out, "\n");
+
+	if (forXML) {
+		fprintf(out, "]]></artwork></figure>\n");
+	}
+}
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5095105..dca89c8 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -18,7 +18,7 @@
     add_definitions(-DUSE_CBOR_CONTEXT)
 endif()
 
-add_library ( cose-c SHARED ${cose_sources} )
+add_library ( cose-c ${LIB_TYPE} ${cose_sources} )
 
 target_include_directories ( cose-c PRIVATE ${OPENSSL_INCLUDE_DIR} )
 target_include_directories ( cose-c PUBLIC ${dist_dir}/include )
diff --git a/src/Cose.c b/src/Cose.c
index b05d7c1..550fbf6 100644
--- a/src/Cose.c
+++ b/src/Cose.c
@@ -59,22 +59,27 @@
 {
 	const cn_cbor * pmap = NULL;
 	cn_cbor_errback errState; // = { 0 };
+#ifdef TAG_IN_ARRAY
 	cn_cbor * cbor;
+#endif // TAG_IN_ARRAY
 
 #ifdef USE_CBOR_CONTEXT
 	if (context != NULL) pobj->m_allocContext = *context;
 #endif
 	pobj->m_cbor = pcbor;
 
+#ifdef TAG_IN_ARRAY
 	cbor = cn_cbor_index(pobj->m_cbor, 0);
 	CHECK_CONDITION(cbor != NULL, COSE_ERR_INVALID_PARAMETER);
 
 	if (cbor->type == CN_CBOR_UINT) {
-		pobj->m_msgType = cbor->v.uint;
+		pobj->m_msgType = (int) cbor->v.uint;
 	}
+#endif
 
 #ifdef USE_ARRAY
 	pmap = _COSE_arrayget_int(pobj, INDEX_PROTECTED);
+
 	CHECK_CONDITION(pmap != NULL, COSE_ERR_INVALID_PARAMETER);
 #else
 	pmap = cn_cbor_mapget_int(pcbor, COSE_Header_Protected);
@@ -132,6 +137,7 @@
 	cbor = cn_cbor_decode(rgbData, cbData, CBOR_CONTEXT_PARAM_COMMA &cbor_err);
 	CHECK_CONDITION_CBOR(cbor != NULL, cbor_err);
 
+#ifdef TAG_IN_ARRAY
 #ifdef USE_ARRAY
 	CHECK_CONDITION(cbor->type == CN_CBOR_ARRAY, COSE_ERR_INVALID_PARAMETER);
 #else
@@ -149,8 +155,25 @@
 	pType = cn_cbor_mapget_int(cbor, COSE_Header_Type);
 #endif
 	CHECK_CONDITION(((pType != NULL) && (pType->type == CN_CBOR_UINT)), COSE_ERR_INVALID_PARAMETER);
+    *ptype = pType->v.sint;
+#else // ! TAG_IN_ARRAY
+	if (cbor->type != CN_CBOR_TAG) {
+		FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
+	}
+    switch (cbor->v.uint) {
+    case 998:
+        *ptype = MSG_TYPE_ENCRYPT;
+        break;
 
-	switch (pType->v.sint) {
+    default:
+        FAIL_CONDITION(COSE_ERR_INVALID_PARAMETER);
+    }
+
+    cbor = cbor->first_child;
+    CHECK_CONDITION(cbor->type == CN_CBOR_ARRAY, COSE_ERR_INVALID_PARAMETER);
+#endif // TAG_IN_ARRAY
+
+	switch (*ptype) {
 	case MSG_TYPE_ENCRYPT:
 		h = (HCOSE)_COSE_Encrypt_Init_From_Object(cbor, NULL, CBOR_CONTEXT_PARAM_COMMA perr);
 		if (h == NULL) {
diff --git a/src/Encrypt.c b/src/Encrypt.c
index 26459a5..dd69af1 100644
--- a/src/Encrypt.c
+++ b/src/Encrypt.c
@@ -259,7 +259,7 @@
 		return false;
 	}
 	CHECK_CONDITION((cn->type == CN_CBOR_UINT) || (cn->type == CN_CBOR_INT), CN_CBOR_ERR_INVALID_PARAMETER);
-	alg = cn->v.uint;
+	alg = (int) cn->v.uint;
 
 	switch (alg) {
 #ifdef INCLUDE_AES_CCM
@@ -398,7 +398,7 @@
 	if (cn_Alg == NULL) goto errorReturn;
 
 	CHECK_CONDITION((cn_Alg->type != CN_CBOR_UINT) && (cn_Alg->type != CN_CBOR_INT), COSE_ERR_INVALID_PARAMETER);
-	alg = cn_Alg->v.uint;
+	alg = (int) cn_Alg->v.uint;
 
 	//  Get the key size
 
@@ -463,7 +463,7 @@
 	pAuthData = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA &cbor_error);
 	CHECK_CONDITION_CBOR(pAuthData != NULL, cbor_error);
 
-	ptmp = cn_cbor_data_create(cbProtected->v.bytes, cbProtected->length, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
+	ptmp = cn_cbor_data_create(cbProtected->v.bytes, (int) cbProtected->length, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
 	CHECK_CONDITION_CBOR(ptmp != NULL, cbor_error);
 	CHECK_CONDITION_CBOR(cn_cbor_array_append(pAuthData, ptmp, &cbor_error), cbor_error);
 	ptmp = NULL;
diff --git a/src/MacMessage.c b/src/MacMessage.c
index 77d27fd..3bc42e8 100644
--- a/src/MacMessage.c
+++ b/src/MacMessage.c
@@ -274,7 +274,7 @@
 	if (cn_Alg == NULL) goto errorReturn;
 	CHECK_CONDITION(((cn_Alg->type == CN_CBOR_UINT || cn_Alg->type == CN_CBOR_INT)), COSE_ERR_INVALID_PARAMETER);
 
-	alg = cn_Alg->v.uint;
+	alg = (int) cn_Alg->v.uint;
 
 	//  Get the key size
 
@@ -341,7 +341,7 @@
 	pAuthData = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA NULL);
 	CHECK_CONDITION(pAuthData != NULL, COSE_ERR_OUT_OF_MEMORY);
 
-	ptmp = cn_cbor_data_create(cbProtected->v.bytes, cbProtected->length, CBOR_CONTEXT_PARAM_COMMA NULL);
+	ptmp = cn_cbor_data_create(cbProtected->v.bytes, (int) cbProtected->length, CBOR_CONTEXT_PARAM_COMMA NULL);
 	CHECK_CONDITION(ptmp != NULL, COSE_ERR_CBOR);
 
 	CHECK_CONDITION(cn_cbor_array_append(pAuthData, ptmp, NULL), COSE_ERR_CBOR);
@@ -352,7 +352,7 @@
 	CHECK_CONDITION_CBOR(cn_cbor_array_append(pAuthData, ptmp, &cbor_error), cbor_error);
 	ptmp = NULL;
 
-	ptmp = cn_cbor_data_create(cbBody->v.bytes, cbBody->length, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
+	ptmp = cn_cbor_data_create(cbBody->v.bytes, (int) cbBody->length, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
 	CHECK_CONDITION_CBOR(ptmp != NULL, cbor_error);
 	CHECK_CONDITION_CBOR(cn_cbor_array_append(pAuthData, ptmp, &cbor_error), cbor_error);
 	ptmp = NULL;
@@ -422,7 +422,7 @@
 	if (cn == NULL) goto errorReturn;
 	CHECK_CONDITION((cn->type == CN_CBOR_UINT || cn->type == CN_CBOR_INT), COSE_ERR_INVALID_PARAMETER);
 
-	alg = cn->v.uint;
+	alg = (int) cn->v.uint;
 
 	switch (alg) {
 	case COSE_Algorithm_HMAC_256_256:
@@ -463,7 +463,7 @@
 	pAuthData = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA &cbor_error);
 	CHECK_CONDITION_CBOR(pAuthData != NULL, cbor_error);
 
-	ptmp = cn_cbor_data_create(cnProtected->v.bytes, cnProtected->length, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
+	ptmp = cn_cbor_data_create(cnProtected->v.bytes, (int) cnProtected->length, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
 	CHECK_CONDITION_CBOR(ptmp != NULL, cbor_error);
 	CHECK_CONDITION_CBOR(cn_cbor_array_append(pAuthData, ptmp, &cbor_error), cbor_error);
 
@@ -471,7 +471,7 @@
 	CHECK_CONDITION_CBOR(ptmp != NULL, cbor_error);
 	CHECK_CONDITION_CBOR(cn_cbor_array_append(pAuthData, ptmp, &cbor_error), cbor_error);
 
-	ptmp = cn_cbor_data_create(cnContent->v.bytes, cnContent->length, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
+	ptmp = cn_cbor_data_create(cnContent->v.bytes, (int) cnContent->length, CBOR_CONTEXT_PARAM_COMMA &cbor_error);
 	CHECK_CONDITION_CBOR(ptmp != NULL, cbor_error);
 	CHECK_CONDITION_CBOR(cn_cbor_array_append(pAuthData, ptmp, &cbor_error), cbor_error);
 
diff --git a/test/test.c b/test/test.c
index 4387ca3..25212cc 100644
--- a/test/test.c
+++ b/test/test.c
@@ -43,9 +43,9 @@
 	char * szX;
 	int cbPrint = 0;
 	cn_cbor * cbor = COSE_get_cbor((HCOSE)hEncObj);
-	cbPrint = cn_cbor_printer_write(NULL, 0, cbor, "  ", "\r\n");
+	// cbPrint = cn_cbor_printer_write(NULL, 0, cbor, "  ", "\r\n");
 	szX = malloc(cbPrint);
-	cn_cbor_printer_write(szX, cbPrint, cbor, "  ", "\r\n");
+	// cn_cbor_printer_write(szX, cbPrint, cbor, "  ", "\r\n");
 	fprintf(stdout, "%s", szX);
 	fprintf(stdout, "\r\n");
 
@@ -111,9 +111,9 @@
 	char * szX;
 	int cbPrint = 0;
 	cn_cbor * cbor = COSE_get_cbor((HCOSE)hEncObj);
-	cbPrint = cn_cbor_printer_write(NULL, 0, cbor, "  ", "\r\n");
+	// cbPrint = cn_cbor_printer_write(NULL, 0, cbor, "  ", "\r\n");
 	szX = malloc(cbPrint);
-	cn_cbor_printer_write(szX, cbPrint, cbor, "  ", "\r\n");
+	// cn_cbor_printer_write(szX, cbPrint, cbor, "  ", "\r\n");
 	fprintf(stdout, "%s", szX);
 	fprintf(stdout, "\r\n");
 
@@ -154,9 +154,9 @@
 	char * szX;
 	int cbPrint = 0;
 	cn_cbor * cbor = COSE_get_cbor((HCOSE) hEncObj);
-	cbPrint = cn_cbor_printer_write(NULL, 0, cbor, "  ", "\r\n");
+	// cbPrint = cn_cbor_printer_write(NULL, 0, cbor, "  ", "\r\n");
 	szX = malloc(cbPrint);
-	cn_cbor_printer_write(szX, cbPrint, cbor, "  ", "\r\n");
+	// cn_cbor_printer_write(szX, cbPrint, cbor, "  ", "\r\n");
 	fprintf(stdout, "%s", szX);
 	fprintf(stdout, "\r\n");