Merge branch 'master' into complete
diff --git "a/\043CMakeLists.txt\043" "b/\043CMakeLists.txt\043"
new file mode 100644
index 0000000..fb5a071
--- /dev/null
+++ "b/\043CMakeLists.txt\043"
@@ -0,0 +1,146 @@
+#
+#
+# top level build file for cn-cbor
+
+## prepare CMAKE
+cmake_minimum_required ( VERSION 3.0.0 )
+
+set ( VERSION_MAJOR 0   CACHE STRING "Project major version number")
+set ( VERSION_MINOR "1" CACHE STRING "Project minor version number" )
+set ( VERSION_PATCH "0" CACHE STRING "Project patch version number" )
+set ( CN_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}" )
+mark_as_advanced(VERSION_MAJOR VERSION_MINOR VERSION_PATCH CN_VERSION)
+
+project ( "cn-cbor" VERSION "${CN_VERSION}")
+
+find_package(Doxygen)
+
+## setup options
+option ( use_context    "Use context pointer for CBOR functions" OFF )
+option ( verbose        "Produce verbose makefile output" OFF )
+option ( optimize       "Optimize for size" OFF )
+option ( fatal_warnings "Treat build warnings as errors" ON )
+option ( coveralls      "Generate coveralls data" ON )
+option ( coveralls_send "Send data to coveralls site" OFF )
+option ( build_docs "Create docs using Doxygen" ${DOXYGEN_FOUND} )
+option ( build_shared_libs "Build Shared Libraries" ON)
+option ( no_floats "Build without floating point support" OFF )
+
+set ( dist_dir    ${CMAKE_BINARY_DIR}/dist )
+set ( prefix      ${CMAKE_INSTALL_PREFIX} )
+set ( exec_prefix ${CMAKE_INSTALL_PREFIX}/bin )
+set ( libdir      ${CMAKE_INSTALL_PREFIX}/lib )
+set ( includedir  ${CMAKE_INSTALL_PREFIX}/include )
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cn-cbor.pc.in
+               ${CMAKE_CURRENT_BINARY_DIR}/cn-cbor.pc @ONLY)
+install (FILES ${CMAKE_CURRENT_BINARY_DIR}/cn-cbor.pc DESTINATION lib/pkgconfig )
+
+set ( package_prefix "${CMAKE_PACKAGE_NAME}-${CMAKE_SYSTEM_NAME}" )
+
+set ( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dist_dir}/bin )
+set ( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${dist_dir}/lib )
+set ( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${dist_dir}/lib )
+
+if (NOT CMAKE_BUILD_TYPE)
+  if ( optimize )
+    set ( CMAKE_BUILD_TYPE MinSizeRel )
+    set ( coveralls OFF )
+    set ( coveralls_send OFF )
+  else ()
+    set ( CMAKE_BUILD_TYPE Debug )
+  endif ()
+endif()
+
+if ( MSVC )
+   set (coveralls OFF)
+endif ()
+
+set (LIB_TYPE STATIC)
+if (build_shared_libs)
+  set (LIB_TYPE SHARED)
+endif (build_shared_libs)
+
+message ( "Build type: ${CMAKE_BUILD_TYPE}" )
+
+if ( CMAKE_C_COMPILER_ID STREQUAL "GNU" OR
+     CMAKE_C_COMPILER_ID MATCHES "Clang" )
+  message ( STATUS "adding GCC/Clang options ")
+  add_definitions ( -std=gnu99 -Wall -Wextra -pedantic )
+  if ( fatal_warnings )
+    add_definitions ( -Werror )
+  endif ()
+  if ( optimize )
+    add_definitions ( -Os )
+  endif ()
+elseif ( MSVC )
+  add_definitions ( /W3 )
+  if ( fatal_warnings )
+    add_definitions ( /WX )
+  endif ()
+else ()
+  message ( FATAL_ERROR "unhandled compiler id: ${CMAKE_C_COMPILER_ID}" )
+endif ()
+
+if ( no_floats )
+   add_definitions(-DCBOR_NO_FLOAT)
+endif()
+
+if ( verbose )
+  set ( CMAKE_VERBOSE_MAKEFILE ON )
+endif ()
+
+## include the parts
+add_subdirectory ( include )
+add_subdirectory ( src )
+add_subdirectory ( test )
+
+install (FILES LICENSE README.md DESTINATION .)
+
+## setup packaging
+set ( CPACK_GENERATOR "TGZ" )
+set ( CPACK_PACKAGE_VERSION "${PROJECT_VERSION}" )
+set ( CPACK_SOURCE_GENERATOR "TGZ" )
+set ( CPACK_SOURCE_IGNORE_FILES "/\\\\.git/" )
+file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/.gitignore igs)
+foreach (ig IN ITEMS ${igs})
+    # remove comments
+    string ( REGEX REPLACE "^\\s*#.*" "" ig "${ig}")
+    # remove any other whitespace
+    string ( STRIP "${ig}" ig)
+    # anything left?
+    if (ig)
+      # dots are literal
+      string ( REPLACE "." "\\\\." ig "${ig}" )
+      # stars are on thars
+      string ( REPLACE "*" ".*" ig "${ig}" )
+      list ( APPEND CPACK_SOURCE_IGNORE_FILES "/${ig}/" )
+    endif()
+endforeach()
+
+set ( CPACK_PACKAGE_DESCRIPTION_FILE ${CMAKE_CURRENT_SOURCE_DIR}/README.md )
+set ( CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" )
+
+include ( CPack )
+include ( CTest )
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake)
+include ( LCov )
+
+if (build_docs)
+    if(NOT DOXYGEN_FOUND)
+        message(FATAL_ERROR "Doxygen is needed to build the documentation.")
+    endif()
+
+    set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
+    set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
+
+    configure_file(${doxyfile_in} ${doxyfile} @ONLY)
+
+    add_custom_target(doc
+        COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile}
+        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+        COMMENT "Generating API documentation with Doxygen"
+        VERBATIM)
+
+    install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION share/doc)
+endif()
diff --git a/.appveyor.yml b/.appveyor.yml
new file mode 100644
index 0000000..9c01ae9
--- /dev/null
+++ b/.appveyor.yml
@@ -0,0 +1,16 @@
+image:
+  - Visual Studio 2019
+
+platform:
+  - x64
+
+configuration:
+  - release
+  - debug
+
+before_build:
+  - cmake -G "Visual Studio 16 2019" -Dfatal_warnings=OFF
+
+build:
+  project: $(APPVEYOR_BUILD_FOLDER)\$(APPVEYOR_PROJECT_NAME).sln
+
diff --git a/.gitignore b/.gitignore
index 09170e2..5fdd120 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,20 +3,25 @@
 *.o
 build
 
-# Files from Visual Studio Builds
-Debug
-Release
-
-# Files from emacs
+# Emacs temp files
 *~
 .#*
 *#
 
-# files from cmake
+# Visual Stdio build directories
+Debug
+Release
+*.sln
 *.vcxproj
 *.vcxproj.filters
 *.vcxproj.user
-CMakeFiles
-CMakeCache.txt
-*.cmake
+*.VC.db
+*.VC.opendb
+/.vscode/
 
+# Output of CMake
+CMakeCache.txt
+CMakeFiles
+Makefile
+*.cmake
+install_manifest.txt
diff --git a/CMakeLists.txt b/CMakeLists.txt
index e076dc8..96911b8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,137 +1,254 @@
-#
-#
-# top level build file for cn-cbor
+cmake_minimum_required(VERSION 3.0.0)
 
-## prepare CMAKE
-cmake_minimum_required ( VERSION 3.0.0 )
-
-set ( VERSION_MAJOR 0   CACHE STRING "Project major version number")
-set ( VERSION_MINOR "1" CACHE STRING "Project minor version number" )
-set ( VERSION_PATCH "0" CACHE STRING "Project patch version number" )
-set ( CN_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}" )
+set(VERSION_MAJOR
+    0
+    CACHE STRING "Project major version number")
+set(VERSION_MINOR
+    "1"
+    CACHE STRING "Project minor version number")
+set(VERSION_PATCH
+    "0"
+    CACHE STRING "Project patch version number")
+set(CN_VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
 mark_as_advanced(VERSION_MAJOR VERSION_MINOR VERSION_PATCH CN_VERSION)
 
-project ( "cn-cbor" VERSION "${CN_VERSION}")
+project("cn-cbor" VERSION "${CN_VERSION}")
 
-find_package(Doxygen)
+# ##############################################################################
+# OPTIONS
+# ##############################################################################
 
-## setup options
-option ( use_context    "Use context pointer for CBOR functions" OFF )
-option ( verbose        "Produce verbose makefile output" OFF )
-option ( optimize       "Optimize for size" OFF )
-option ( fatal_warnings "Treat build warnings as errors" ON )
-option ( coveralls      "Generate coveralls data" ON )
-option ( coveralls_send "Send data to coveralls site" OFF )
-option ( build_docs "Create docs using Doxygen" ${DOXYGEN_FOUND} )
-option ( no_floats "Build without floating point support" OFF )
-option ( align_reads    "Use memcpy in ntoh*p()" OFF )
+option(use_context "Use context pointer for CBOR functions" OFF)
+option(verbose "Produce verbose makefile output" OFF)
+option(optimize "Optimize for size" OFF)
+option(fatal_warnings "Treat build warnings as errors" ON)
+option(coveralls "Generate coveralls data" ON)
+option(coveralls_send "Send data to coveralls site" OFF)
+option(build_docs "Create docs using Doxygen" OFF)
+option(build_tests "Create tests" ON)
+option(no_floats "Build without floating point support" OFF)
+option(align_reads "Use memcpy in ntoh*p()" OFF)
 
-set ( dist_dir    ${CMAKE_BINARY_DIR}/dist )
-set ( prefix      ${CMAKE_INSTALL_PREFIX} )
-set ( exec_prefix ${CMAKE_INSTALL_PREFIX}/bin )
-set ( libdir      ${CMAKE_INSTALL_PREFIX}/lib )
-set ( includedir  ${CMAKE_INSTALL_PREFIX}/include )
+include(GNUInstallDirs)
+
+set(dist_dir ${CMAKE_BINARY_DIR}/dist)
+set(prefix ${CMAKE_INSTALL_PREFIX})
+set(exec_prefix ${CMAKE_INSTALL_PREFIX}/bin)
+set(libdir ${CMAKE_INSTALL_PREFIX}/lib)
+set(includedir ${CMAKE_INSTALL_PREFIX}/include)
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cn-cbor.pc.in
                ${CMAKE_CURRENT_BINARY_DIR}/cn-cbor.pc @ONLY)
-install (FILES ${CMAKE_CURRENT_BINARY_DIR}/cn-cbor.pc DESTINATION lib/pkgconfig )
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cn-cbor.pc DESTINATION lib/pkgconfig)
 
-set ( package_prefix "${CMAKE_PACKAGE_NAME}-${CMAKE_SYSTEM_NAME}" )
+set(package_prefix "${CMAKE_PACKAGE_NAME}-${CMAKE_SYSTEM_NAME}")
 
-set ( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dist_dir}/bin )
-set ( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${dist_dir}/lib )
-set ( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${dist_dir}/lib )
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dist_dir}/bin)
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${dist_dir}/lib)
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${dist_dir}/lib)
 
-if (NOT CMAKE_BUILD_TYPE)
-  if ( optimize )
-    set ( CMAKE_BUILD_TYPE MinSizeRel )
-    set ( coveralls OFF )
-    set ( coveralls_send OFF )
-  else ()
-    set ( CMAKE_BUILD_TYPE Debug )
-  endif ()
+if(NOT CMAKE_BUILD_TYPE)
+  if(optimize)
+    set(CMAKE_BUILD_TYPE MinSizeRel)
+    set(coveralls OFF)
+    set(coveralls_send OFF)
+  else()
+    set(CMAKE_BUILD_TYPE Debug)
+  endif()
 endif()
 
-message ( "Build type: ${CMAKE_BUILD_TYPE}" )
-
-if ( CMAKE_C_COMPILER_ID STREQUAL "GNU" OR
-     CMAKE_C_COMPILER_ID MATCHES "Clang" )
-  message ( STATUS "adding GCC/Clang options ")
-  add_definitions ( -std=gnu99 -Wall -Wextra -pedantic )
-  if ( fatal_warnings )
-    add_definitions ( -Werror )
-  endif ()
-  if ( optimize )
-    add_definitions ( -Os )
-  endif ()
-elseif ( MSVC )
-  add_definitions ( /W3 )
-  if ( fatal_warnings )
-    add_definitions ( /WX )
-  endif ()
-else ()
-  message ( FATAL_ERROR "unhandled compiler id: ${CMAKE_C_COMPILER_ID}" )
-endif ()
-
-if ( no_floats )
-   add_definitions(-DCBOR_NO_FLOAT)
+if(MSVC)
+  set(coveralls OFF)
 endif()
 
-if ( verbose )
-  set ( CMAKE_VERBOSE_MAKEFILE ON )
-endif ()
+message("Build type: ${CMAKE_BUILD_TYPE}")
 
-## include the parts
-add_subdirectory ( include )
-add_subdirectory ( src )
-add_subdirectory ( test )
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
+  message(STATUS "adding GCC/Clang options ")
+  add_definitions(-std=gnu99 -Wall -Wextra -pedantic)
+  if(fatal_warnings)
+    add_definitions(-Werror)
+  endif()
+  if(optimize)
+    add_definitions(-Os)
+  endif()
+elseif(MSVC)
+  add_definitions(/W3)
+  if(fatal_warnings)
+    add_definitions(/WX)
+  endif()
+else()
+  message(FATAL_ERROR "unhandled compiler id: ${CMAKE_C_COMPILER_ID}")
+endif()
 
-install (FILES LICENSE README.md DESTINATION .)
+if(no_floats)
+  add_definitions(-DCBOR_NO_FLOAT)
+endif()
 
-## setup packaging
-set ( CPACK_GENERATOR "TGZ" )
-set ( CPACK_PACKAGE_VERSION "${PROJECT_VERSION}" )
-set ( CPACK_SOURCE_GENERATOR "TGZ" )
-set ( CPACK_SOURCE_IGNORE_FILES "/\\\\.git/" )
-file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/.gitignore igs)
-foreach (ig IN ITEMS ${igs})
-    # remove comments
-    string ( REGEX REPLACE "^\\s*#.*" "" ig "${ig}")
-    # remove any other whitespace
-    string ( STRIP "${ig}" ig)
-    # anything left?
-    if (ig)
-      # dots are literal
-      string ( REPLACE "." "\\\\." ig "${ig}" )
-      # stars are on thars
-      string ( REPLACE "*" ".*" ig "${ig}" )
-      list ( APPEND CPACK_SOURCE_IGNORE_FILES "/${ig}/" )
-    endif()
-endforeach()
+if(verbose)
+  set(CMAKE_VERBOSE_MAKEFILE ON)
+endif()
 
-set ( CPACK_PACKAGE_DESCRIPTION_FILE ${CMAKE_CURRENT_SOURCE_DIR}/README.md )
-set ( CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" )
+# ##############################################################################
+# LIBRARY
+# ##############################################################################
 
-include ( CPack )
-include ( CTest )
+set(cbor_srcs src/cn-cbor.c src/cn-create.c src/cn-encoder.c src/cn-error.c
+              src/cn-get.c src/cn-print.c)
+
+if(align_reads)
+  add_definitions(-DCBOR_ALIGN_READS)
+endif()
+if(use_context)
+  add_definitions(-DUSE_CBOR_CONTEXT)
+endif()
+# default is static, can be shared if -DBUILD_SHARED_LIBS=ON passed to cmake
+add_library(${PROJECT_NAME})
+target_sources(${PROJECT_NAME} PRIVATE include/cn-cbor/cn-cbor.h ${cbor_srcs})
+target_include_directories(
+  ${PROJECT_NAME}
+  PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
+  PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src)
+if(MSVC)
+  message("test: ${BUILD_SHARED_LIBS}")
+  message("verbose: ${verbose}")
+  target_link_libraries(${PROJECT_NAME} ws2_32)
+endif()
+add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
 
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake)
-include ( LCov )
+if(coveralls)
+  include(Coveralls)
+  coveralls_turn_on_coverage()
 
-if (build_docs)
-    if(NOT DOXYGEN_FOUND)
-        message(FATAL_ERROR "Doxygen is needed to build the documentation.")
-    endif()
+  set(COVERAGE_SRCS "")
+  foreach(S ${cbor_srcs})
+    get_filename_component(S_ABS ${S} ABSOLUTE)
+    list(APPEND COVERAGE_SRCS ${S_ABS})
+  endforeach()
 
+  # Create the coveralls target.
+  coveralls_setup("${COVERAGE_SRCS}" ${coveralls_send} # If we should upload.
+  )
+
+  # add_dependencies(coveralls, all)
+endif()
+
+if(NOT MSVC)
+  add_custom_target(
+    size
+    COMMAND echo "${CMAKE_BINARY_DIR}/src/CMakeFiles/cn-cbor.dir/cn-cbor.c.o"
+    COMMAND size "${CMAKE_BINARY_DIR}/src/CMakeFiles/cn-cbor.dir/cn-cbor.c.o"
+    COMMAND size -m "${CMAKE_BINARY_DIR}/src/CMakeFiles/cn-cbor.dir/cn-cbor.c.o"
+    DEPENDS cn-cbor
+    COMMENT "Output the size of the parse routine")
+endif(NOT MSVC)
+
+# ##############################################################################
+# DOCS
+# ##############################################################################
+
+if(build_docs)
+  find_package(Doxygen)
+
+  if(NOT DOXYGEN_FOUND)
+    message(WARNING "Doxygen is needed to build the documentation.")
+  else()
     set(doxyfile_in ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
     set(doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
 
     configure_file(${doxyfile_in} ${doxyfile} @ONLY)
 
-    add_custom_target(doc
-        COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile}
-        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
-        COMMENT "Generating API documentation with Doxygen"
-        VERBATIM)
+    add_custom_target(
+      doc
+      COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile}
+      WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+      COMMENT "Generating API documentation with Doxygen"
+      VERBATIM)
 
     install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION share/doc)
+  endif()
 endif()
+
+# ##############################################################################
+# TESTS
+# ##############################################################################
+
+if(build_tests)
+  include(CTest)
+  add_subdirectory(test)
+  set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake)
+  include(LCov)
+endif()
+
+# ##############################################################################
+# PACKAGING
+# ##############################################################################
+
+set(CPACK_GENERATOR "TGZ")
+set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
+set(CPACK_SOURCE_GENERATOR "TGZ")
+set(CPACK_SOURCE_IGNORE_FILES "/\\\\.git/")
+file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/.gitignore igs)
+foreach(ig IN ITEMS ${igs})
+  # remove comments
+  string(REGEX REPLACE "^\\s*#.*" "" ig "${ig}")
+  # remove any other whitespace
+  string(STRIP "${ig}" ig)
+  # anything left?
+  if(ig)
+    # dots are literal
+    string(REPLACE "." "\\\\." ig "${ig}")
+    # stars are on thars
+    string(REPLACE "*" ".*" ig "${ig}")
+    list(APPEND CPACK_SOURCE_IGNORE_FILES "/${ig}/")
+  endif()
+endforeach()
+
+set(CPACK_PACKAGE_DESCRIPTION_FILE ${CMAKE_CURRENT_SOURCE_DIR}/README.md)
+set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
+
+include(CPack)
+
+# ##############################################################################
+# INSTALL
+# ##############################################################################
+
+include(GNUInstallDirs)
+include(CMakePackageConfigHelpers)
+
+install(FILES LICENSE README.md DESTINATION .)
+set(CN_CBOR_CONFIG_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME})
+
+install(
+  TARGETS ${PROJECT_NAME}
+  EXPORT ${PROJECT_NAME}Targets
+  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT lib
+  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT lib)
+
+install(
+  EXPORT ${PROJECT_NAME}Targets
+  DESTINATION ${CN_CBOR_CONFIG_INSTALL_DIR}
+  NAMESPACE ${PROJECT_NAME}::
+  COMPONENT dev)
+
+configure_package_config_file(cmake/Config.cmake.in ${PROJECT_NAME}Config.cmake
+                              INSTALL_DESTINATION ${CN_CBOR_CONFIG_INSTALL_DIR})
+write_basic_package_version_file(${PROJECT_NAME}ConfigVersion.cmake
+                                 COMPATIBILITY SameMajorVersion)
+install(
+  FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
+        ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
+  DESTINATION ${CN_CBOR_CONFIG_INSTALL_DIR}
+  COMPONENT dev)
+
+install(
+  DIRECTORY include/
+  DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+  COMPONENT dev
+  FILES_MATCHING
+  PATTERN "*.h")
+install(
+  TARGETS cn-cbor
+  LIBRARY DESTINATION lib
+  ARCHIVE DESTINATION lib
+  RUNTIME DESTINATION bin)
diff --git a/cmake/Config.cmake.in b/cmake/Config.cmake.in
new file mode 100644
index 0000000..9c15f36
--- /dev/null
+++ b/cmake/Config.cmake.in
@@ -0,0 +1,4 @@
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
+check_required_components("@PROJECT_NAME@")
diff --git a/conanfile.py b/conanfile.py
new file mode 100644
index 0000000..977ee57
--- /dev/null
+++ b/conanfile.py
@@ -0,0 +1,63 @@
+import os
+from conans import ConanFile, CMake, tools
+
+
+class CnCborConan(ConanFile):
+    name = "cn-cbor"
+    version = "20200227"
+    license = "BSD"
+    url = "https://github.com/cose-wg/cn-cbor"
+    description = """A constrained node implementation of CBOR in C"""
+    topics = ("cn-cbor")
+    settings = "os", "compiler", "build_type", "arch"
+    options = {
+        "shared": [True, False],
+    }
+    default_options = {
+        "shared": False,
+    }
+    generators = "cmake"
+
+    _cmake = None
+
+    @property
+    def _source_subfolder(self):
+        return "source_subfolder"
+
+    @property
+    def _build_subfolder(self):
+        return "build_subfolder"
+
+    def source(self):
+        self.run(
+            "git clone -b complete git@github.com:jimsch/cn-cbor.git")
+        os.rename("cn-cbor", self._source_subfolder)
+
+    def configure(self):
+        del self.settings.compiler.libcxx
+        del self.settings.compiler.cppstd
+
+    def _configure_cmake(self):
+        if not self._cmake:
+            self._cmake = CMake(self)
+        self._cmake.definitions["build_tests"] = False
+        self._cmake.definitions["build_docs"] = False
+        self._cmake.definitions["coveralls"] = False
+        self._cmake.configure(
+            source_folder=self._source_subfolder, build_folder=self._build_subfolder)
+
+        return self._cmake
+
+    def build(self):
+        cmake = self._configure_cmake()
+        cmake.build()
+
+    def package(self):
+        cmake = self._configure_cmake()
+        cmake.install()
+
+    def package_info(self):
+        self.cpp_info.libs = tools.collect_libs(self)
+        self.cpp_info.name = "cn-cbor"
+        if self.settings.os == "Linux":
+            self.cpp_info.system_libs = ["m"]
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
deleted file mode 100644
index 898676a..0000000
--- a/include/CMakeLists.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-install ( DIRECTORY ../include DESTINATION .
-          PATTERN CMakeLists.txt EXCLUDE )
diff --git a/include/cn-cbor/cn-cbor.h b/include/cn-cbor/cn-cbor.h
index 187a55c..0416bd2 100644
--- a/include/cn-cbor/cn-cbor.h
+++ b/include/cn-cbor/cn-cbor.h
@@ -8,6 +8,18 @@
 #ifndef CN_CBOR_H
 #define CN_CBOR_H
 
+#ifndef MYLIB_EXPORT
+#if defined (_WIN32) 
+#if defined(CN_CBOR_IS_DLL)
+#define  MYLIB_EXPORT __declspec(dllimport)
+#else
+#define MYLIB_EXPORT
+#endif /* CN_CBOR_IS_DLL */
+#else /* defined (_WIN32) */
+#define MYLIB_EXPORT
+#endif 
+#endif
+
 #ifdef  __cplusplus
 extern "C" {
 #endif
@@ -17,7 +29,12 @@
 
 #include <stdbool.h>
 #include <stdint.h>
+#ifdef _MSC_VER
+#include <WinSock2.h>
+typedef signed long ssize_t;
+#else
 #include <unistd.h>
+#endif
 
 /**
  * All of the different kinds of CBOR values.
@@ -89,19 +106,35 @@
     /** CN_CBOR_TEXT */
     const char* str;
     /** CN_CBOR_INT */
+#ifdef _MSC_VER
+	int64_t sint;
+#else
     long sint;
+#endif
     /** CN_CBOR_UINT */
+#ifdef _MSC_VER
+	uint64_t uint;
+#else
     unsigned long uint;
+#endif
     /** CN_CBOR_DOUBLE */
     double dbl;
     /** CN_CBOR_FLOAT */
     float f;
     /** for use during parsing */
-    unsigned long count;
+#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 */
@@ -149,6 +182,7 @@
  *
  * @todo: turn into a function to make the type safety more clear?
  */
+MYLIB_EXPORT
 extern const char *cn_cbor_error_str[];
 
 /**
@@ -223,6 +257,7 @@
  * @param[out] errp         Error, if NULL is returned
  * @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);
 
 /**
@@ -232,6 +267,7 @@
  * @param[in]  key          The string to look up in the map
  * @return                  The matching value, or NULL if the key is not found
  */
+MYLIB_EXPORT
 cn_cbor* cn_cbor_mapget_string(const cn_cbor* cb, const char* key);
 
 /**
@@ -241,6 +277,7 @@
  * @param[in]  key          The int to look up in the map
  * @return                  The matching value, or NULL if the key is not found
  */
+MYLIB_EXPORT
 cn_cbor* cn_cbor_mapget_int(const cn_cbor* cb, int key);
 
 /**
@@ -250,6 +287,7 @@
  * @param[in]  idx          The array index
  * @return                  The matching value, or NULL if the index is invalid
  */
+MYLIB_EXPORT
 cn_cbor* cn_cbor_index(const cn_cbor* cb, unsigned int idx);
 
 /**
@@ -260,15 +298,19 @@
  * @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)
  */
+MYLIB_EXPORT
 void cn_cbor_free(cn_cbor* cb CBOR_CONTEXT);
 
 /**
  * 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
  */
@@ -284,6 +326,7 @@
  * @param[out]  errp         Error, if NULL is returned
  * @return                   The created map, or NULL on error
  */
+MYLIB_EXPORT
 cn_cbor* cn_cbor_map_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp);
 
 /**
@@ -296,6 +339,7 @@
  * @param[out]  errp         Error, if NULL is returned
  * @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);
@@ -313,6 +357,7 @@
  * @param[out]  errp         Error, if NULL is returned
  * @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);
@@ -325,6 +370,7 @@
  * @param[out]  errp         Error, if NULL is returned
  * @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);
@@ -365,6 +411,7 @@
  * @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);
@@ -380,6 +427,7 @@
  * @param[out]  errp         Error
  * @return                   True on success
  */
+MYLIB_EXPORT
 bool cn_cbor_mapput_int(cn_cbor* cb_map,
                         int64_t key, cn_cbor* cb_value
                         CBOR_CONTEXT,
@@ -399,6 +447,7 @@
  * @param[out]  errp         Error
  * @return                   True on success
  */
+MYLIB_EXPORT
 bool cn_cbor_mapput_string(cn_cbor* cb_map,
                            const char* key, cn_cbor* cb_value
                            CBOR_CONTEXT,
@@ -411,6 +460,7 @@
  * @param[out]  errp         Error, if NULL is returned
  * @return                   The created object, or NULL on error
  */
+MYLIB_EXPORT
 cn_cbor* cn_cbor_array_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp);
 
 /**
@@ -421,10 +471,26 @@
  * @param[out]  errp      Error
  * @return                True on success
  */
+MYLIB_EXPORT
 bool cn_cbor_array_append(cn_cbor* cb_array,
                           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
deleted file mode 100644
index babe95c..0000000
--- a/src/CMakeLists.txt
+++ /dev/null
@@ -1,53 +0,0 @@
-#
-#
-# compiling/installing sources for cn-cbor
-
-set ( cbor_srcs
-      cn-cbor.c
-      cn-create.c
-      cn-encoder.c
-      cn-error.c
-      cn-get.c
-)
-
-if (align_reads)
-  add_definitions(-DCBOR_ALIGN_READS)
-endif()
-if (use_context)
-  add_definitions(-DUSE_CBOR_CONTEXT)
-endif()
-add_library ( cn-cbor SHARED ${cbor_srcs} )
-target_include_directories ( cn-cbor PUBLIC ../include )
-target_include_directories ( cn-cbor PRIVATE ../src )
-
-install ( TARGETS cn-cbor
-          LIBRARY DESTINATION lib
-          ARCHIVE DESTINATION lib
-          RUNTIME DESTINATION bin)
-
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake)
-if (coveralls)
-    include(Coveralls)
-    coveralls_turn_on_coverage()
-
-    set(COVERAGE_SRCS "")
-    foreach (S ${cbor_srcs})
-      get_filename_component(S_ABS ${S} ABSOLUTE)
-      list (APPEND COVERAGE_SRCS ${S_ABS})
-    endforeach()
-
-    # Create the coveralls target.
-    coveralls_setup(
-        "${COVERAGE_SRCS}"
-        ${coveralls_send}                 # If we should upload.
-    )
-
-    #add_dependencies(coveralls, all)
-endif()
-
-add_custom_target(size
-  COMMAND echo "${CMAKE_BINARY_DIR}/src/CMakeFiles/cn-cbor.dir/cn-cbor.c.o"
-  COMMAND size "${CMAKE_BINARY_DIR}/src/CMakeFiles/cn-cbor.dir/cn-cbor.c.o"
-  COMMAND size -m "${CMAKE_BINARY_DIR}/src/CMakeFiles/cn-cbor.dir/cn-cbor.c.o"
-  DEPENDS cn-cbor
-COMMENT "Output the size of the parse routine")
diff --git a/src/cbor.h b/src/cbor.h
index 1859f09..6329477 100644
--- a/src/cbor.h
+++ b/src/cbor.h
@@ -1,6 +1,10 @@
 #ifndef CBOR_PROTOCOL_H__
 #define CBOR_PROTOCOL_H__
 
+#ifdef _MSC_VER
+#define inline _inline
+#endif
+
 /* The 8 major types */
 #define MT_UNSIGNED 0
 #define MT_NEGATIVE 1
diff --git a/src/cn-cbor.c b/src/cn-cbor.c
index 9093537..7da5f88 100644
--- a/src/cn-cbor.c
+++ b/src/cn-cbor.c
@@ -13,15 +13,22 @@
 #include <string.h>
 #include <assert.h>
 #include <math.h>
+#ifdef _MSC_VER
+#include <WinSock2.h>  // needed for ntohl on Windows
+#else
 #include <arpa/inet.h> // needed for ntohl (e.g.) on Linux
 
+#include "dll-export.h"
+#endif // _MSC_VER
+
 #include "cn-cbor/cn-cbor.h"
 #include "cbor.h"
 
 #define CN_CBOR_FAIL(code) do { pb->err = code;  goto fail; } while(0)
 
+MYLIB_EXPORT
 void cn_cbor_free(cn_cbor* cb CBOR_CONTEXT) {
-  cn_cbor* p = cb;
+  cn_cbor* p = (cn_cbor*) cb;
   assert(!p || !p->parent);
   while (p) {
     cn_cbor* p1;
@@ -173,7 +180,7 @@
     break;
   case MT_BYTES: case MT_TEXT:
     cb->v.str = (char *) pos;
-    cb->length = val;
+    cb->length = (size_t) val;
     TAKE(pos, ebuf, val, ;);
     break;
   case MT_MAP:
@@ -205,7 +212,7 @@
     case AI_4:
 #ifndef CBOR_NO_FLOAT
       cb->type = CN_CBOR_DOUBLE;
-      u32.u = val;
+      u32.u = (uint32_t) val;
       cb->v.dbl = u32.f;
 #else /*  CBOR_NO_FLOAT */
       CN_CBOR_FAIL(CN_CBOR_ERR_FLOAT_NOT_SUPPORTED);
@@ -253,6 +260,7 @@
   return 0;
 }
 
+MYLIB_EXPORT
 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;
diff --git a/src/cn-create.c b/src/cn-create.c
index 4ddce3b..c9ab816 100644
--- a/src/cn-create.c
+++ b/src/cn-create.c
@@ -8,6 +8,7 @@
 #include <string.h>
 #include <stdlib.h>
 
+#include "dll-export.h"
 #include "cn-cbor/cn-cbor.h"
 #include "cbor.h"
 
@@ -16,6 +17,7 @@
   (v) = CN_CALLOC_CONTEXT(); \
   if (!(v)) { if (errp) {errp->err = CN_CBOR_ERR_OUT_OF_MEMORY;} return NULL; }
 
+MYLIB_EXPORT
 cn_cbor* cn_cbor_map_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp)
 {
   cn_cbor* ret;
@@ -27,6 +29,7 @@
   return ret;
 }
 
+MYLIB_EXPORT
 cn_cbor* cn_cbor_data_create(const uint8_t* data, int len
                              CBOR_CONTEXT,
                              cn_cbor_errback *errp)
@@ -41,6 +44,7 @@
   return ret;
 }
 
+MYLIB_EXPORT
 cn_cbor* cn_cbor_string_create(const char* data
                                CBOR_CONTEXT,
                                cn_cbor_errback *errp)
@@ -55,6 +59,7 @@
   return ret;
 }
 
+MYLIB_EXPORT
 cn_cbor* cn_cbor_int_create(int64_t value
                             CBOR_CONTEXT,
                             cn_cbor_errback *errp)
@@ -119,6 +124,7 @@
   return true;
 }
 
+MYLIB_EXPORT
 bool cn_cbor_map_put(cn_cbor* cb_map,
                      cn_cbor *cb_key, cn_cbor *cb_value,
                      cn_cbor_errback *errp)
@@ -133,6 +139,7 @@
   return _append_kv(cb_map, cb_key, cb_value);
 }
 
+MYLIB_EXPORT
 bool cn_cbor_mapput_int(cn_cbor* cb_map,
                         int64_t key, cn_cbor* cb_value
                         CBOR_CONTEXT,
@@ -152,6 +159,7 @@
   return _append_kv(cb_map, cb_key, cb_value);
 }
 
+MYLIB_EXPORT
 bool cn_cbor_mapput_string(cn_cbor* cb_map,
                            const char* key, cn_cbor* cb_value
                            CBOR_CONTEXT,
@@ -171,6 +179,7 @@
   return _append_kv(cb_map, cb_key, cb_value);
 }
 
+MYLIB_EXPORT
 cn_cbor* cn_cbor_array_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp)
 {
   cn_cbor* ret;
@@ -182,6 +191,7 @@
   return ret;
 }
 
+MYLIB_EXPORT
 bool cn_cbor_array_append(cn_cbor* cb_array,
                           cn_cbor* cb_value,
                           cn_cbor_errback *errp)
diff --git a/src/cn-encoder.c b/src/cn-encoder.c
index ffaf3e8..18de686 100644
--- a/src/cn-encoder.c
+++ b/src/cn-encoder.c
@@ -8,12 +8,20 @@
 } /* Duh. */
 #endif
 
+#ifdef _MSC_VER
+#include <WinSock2.h>
+#define inline _inline
+#else
 #include <arpa/inet.h>
+#endif
 #include <string.h>
+#ifndef _MSC_VER
 #include <strings.h>
+#endif
 #include <stdbool.h>
 #include <assert.h>
 
+#include "dll-export.h"
 #include "cn-cbor/cn-cbor.h"
 #include "cbor.h"
 
@@ -35,22 +43,30 @@
   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)); \
+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) \
-ws->buf[ws->offset++] = (b); \
+if(ws->buf) { \
+  ws->buf[ws->offset++] = (b); \
+} else { \
+  ws->offset++; \
+}
 
 #define write_byte_ensured(b) \
 ensure_writable(1); \
-write_byte(b); \
+write_byte(b);
 
 static uint8_t _xlate[] = {
   IB_FALSE,    /* CN_CBOR_FALSE */
@@ -89,7 +105,7 @@
 
   if (val < 24) {
     ensure_writable(1);
-    write_byte(ib | val);
+    write_byte(ib | (uint8_t) val);
   } else if (val < 256) {
     ensure_writable(2);
     write_byte(ib | 24);
@@ -178,7 +194,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)
@@ -194,17 +210,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;
@@ -249,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;
 
@@ -293,7 +319,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,
@@ -302,6 +334,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/src/cn-error.c b/src/cn-error.c
index 4953cc9..ad48746 100644
--- a/src/cn-error.c
+++ b/src/cn-error.c
@@ -1,3 +1,6 @@
+#include "dll-export.h"
+
+MYLIB_EXPORT
 const char *cn_cbor_error_str[] = {
  "CN_CBOR_NO_ERROR",
  "CN_CBOR_ERR_OUT_OF_DATA",
diff --git a/src/cn-get.c b/src/cn-get.c
index 79d3d72..4b2ee13 100644
--- a/src/cn-get.c
+++ b/src/cn-get.c
@@ -2,8 +2,11 @@
 #include <string.h>
 #include <assert.h>
 
+#include "dll-export.h"
+
 #include "cn-cbor/cn-cbor.h"
 
+MYLIB_EXPORT
 cn_cbor* cn_cbor_mapget_int(const cn_cbor* cb, int key) {
   cn_cbor* cp;
   assert(cb);
@@ -26,6 +29,7 @@
   return NULL;
 }
 
+MYLIB_EXPORT
 cn_cbor* cn_cbor_mapget_string(const cn_cbor* cb, const char* key) {
   cn_cbor *cp;
   int keylen;
@@ -49,6 +53,7 @@
   return NULL;
 }
 
+MYLIB_EXPORT
 cn_cbor* cn_cbor_index(const cn_cbor* cb, unsigned int idx) {
   cn_cbor *cp;
   unsigned int i = 0;
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/src/dll-export.h b/src/dll-export.h
new file mode 100644
index 0000000..3d0c928
--- /dev/null
+++ b/src/dll-export.h
@@ -0,0 +1,23 @@
+// Contents of DLLDefines.h
+#ifndef _cn_cbor_DLLDEFINES_H_
+#define _cn_cbor_DLLDEFINES_H_
+
+/* Cmake will define cn_cbor_EXPORTS on Windows when it
+configures to build a shared library. If you are going to use
+another build system on windows or create the visual studio
+projects by hand you need to define cn_cbor_EXPORTS when
+building a DLL on windows.
+*/
+// We are using the Visual Studio Compiler and building Shared libraries
+
+#if defined (_WIN32) 
+#if defined(CN_CBOR_IS_DLL)
+    #define  MYLIB_EXPORT __declspec(dllexport)
+#else
+    #define MYLIB_EXPORT
+#endif /* cn_cbor_EXPORTS */
+#else /* defined (_WIN32) */
+ #define MYLIB_EXPORT
+#endif
+
+#endif /* _cn_cbor_DLLDEFINES_H_ */
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 3181a8d..18eaa47 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,33 +1,32 @@
 #
-#
 # Compiling/running tests
 
-if (use_context)
+if(use_context)
   add_definitions(-DUSE_CBOR_CONTEXT)
 endif()
 
-set ( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dist_dir}/test )
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${dist_dir}/test)
 
-function (create_test name)
-  add_executable ( ${name}_test ${name}_test.c )
-  target_link_libraries ( ${name}_test PRIVATE cn-cbor )
-  target_include_directories ( ${name}_test PRIVATE ../include )
-  add_test ( NAME ${name} COMMAND ${name}_test )
+function(create_test name)
+  add_executable(${name}_test ${name}_test.c)
+  target_link_libraries(${name}_test PRIVATE cn-cbor)
+  target_include_directories(${name}_test PRIVATE ../include)
+  add_test(NAME ${name} COMMAND ${name}_test)
 endfunction()
 
-create_test ( cbor )
-include ( CTest )
+create_test(cbor)
+include(CTest)
 
-if (APPLE)
+if(APPLE)
   # difftest uses Apple-specific memory tests
-  add_executable (cn-test test.c )
-  target_include_directories ( cn-test PRIVATE ../include )
-  target_link_libraries ( cn-test PRIVATE cn-cbor )
+  add_executable(cn-test test.c)
+  target_link_libraries(cn-test PRIVATE cn-cbor)
 
   configure_file(cases.cbor cases.cbor COPYONLY)
   configure_file(expected.out expected.out COPYONLY)
 
-  add_custom_target(difftest
+  add_custom_target(
+    difftest
     COMMAND env MallocStackLogging=true ./cn-test >new.out
     COMMAND diff new.out expected.out
     DEPENDS cn-test
diff --git a/test/cbor_test.c b/test/cbor_test.c
index eafea5d..3888723 100644
--- a/test/cbor_test.c
+++ b/test/cbor_test.c
@@ -1,12 +1,22 @@
 /*
  * Copyright (c) 2015 SPUDlib authors.  See LICENSE file.
  */
+
+#ifdef _MSC_VER
+#define _CRT_SECURE_NO_WARNINGS
+#define _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+
 #include <stdlib.h>
 #include <stdint.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <assert.h>
 #include <string.h>
+#ifdef _MSC_VER
+#include "winsock2.h"
+#endif
 
 #include "cn-cbor/cn-cbor.h"
 
@@ -43,7 +53,13 @@
     b->sz  = len / 2;
     b->ptr = malloc(b->sz);
     for (i=0; i<b->sz; i++) {
+#ifdef _MSC_VER
+		unsigned int iX;
+		sscanf(inp+(2*i), "%02hx", &iX);
+		b->ptr[i] = (byte)iX;
+#else
         sscanf(inp+(2*i), "%02hhx", &b->ptr[i]);
+#endif
     }
     return true;
 }
@@ -116,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));
@@ -125,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);
@@ -164,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));
@@ -174,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);
@@ -195,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);
@@ -258,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);
@@ -446,6 +473,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);
 }
diff --git a/test/ctest.h b/test/ctest.h
index 75fda66..c971c55 100644
--- a/test/ctest.h
+++ b/test/ctest.h
@@ -16,6 +16,14 @@
 #ifndef CTEST_H
 #define CTEST_H
 
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#pragma section(".ctest")
+
+#include <io.h>
+#define isatty _isatty
+#endif
+
 #ifndef UNUSED_PARAM
   /**
    * \def UNUSED_PARAM(p);
@@ -47,11 +55,19 @@
 #define __CTEST_MAGIC (0xdeadbeef)
 #ifdef __APPLE__
 #define __Test_Section __attribute__ ((unused,section ("__DATA, .ctest")))
+#define MS__Test_Section
+#else
+#ifdef _MSC_VER
+#define __Test_Section
+#define MS__Test_Section __declspec(allocate(".ctest"))
 #else
 #define __Test_Section __attribute__ ((unused,section (".ctest")))
+#define MS__Test_Section
+#endif
 #endif
 
 #define __CTEST_STRUCT(sname, tname, _skip, __data, __setup, __teardown) \
+	MS__Test_Section \
     struct ctest __TNAME(sname, tname) __Test_Section = { \
         .ssname=#sname, \
         .ttname=#tname, \
@@ -138,9 +154,13 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
+#ifndef _MSC_VER
 #include <sys/time.h>
+#endif
 #include <inttypes.h>
+#ifndef _MSC_VER
 #include <unistd.h>
+#endif
 #include <stdint.h>
 #include <stdlib.h>
 
@@ -306,6 +326,27 @@
     return strncmp(suite_name, t->ssname, strlen(suite_name)) == 0;
 }
 
+#ifdef _MSC_VER
+int gettimeofday(struct timeval * tp, struct timezone * tzp)
+{
+	// Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's
+	static const uint64_t EPOCH = ((uint64_t)116444736000000000ULL);
+
+	SYSTEMTIME  system_time;
+	FILETIME    file_time;
+	uint64_t    time;
+
+	GetSystemTime(&system_time);
+	SystemTimeToFileTime(&system_time, &file_time);
+	time = ((uint64_t)file_time.dwLowDateTime);
+	time += ((uint64_t)file_time.dwHighDateTime) << 32;
+
+	tp->tv_sec = (long)((time - EPOCH) / 10000000L);
+	tp->tv_usec = (long)(system_time.wMilliseconds * 1000);
+	return 0;
+}
+#endif
+
 static uint64_t getCurrentTime() {
     struct timeval now;
     gettimeofday(&now, NULL);
@@ -377,6 +418,7 @@
     }
 
     color_output = isatty(1);
+
     uint64_t t1 = getCurrentTime();
 
     struct ctest* ctest_begin = &__TNAME(suite, test);