diff --git a/Makefile b/Makefile
index f3ff00b3..60f2debf 100644
--- a/Makefile
+++ b/Makefile
@@ -93,18 +93,6 @@ TINYCBOR_SOURCES = \
 	src/cbortojson.c \
 	src/cborvalidation.c \
 #
-# if open_memstream is unavailable on the system, try to implement our own
-# version using funopen or fopencookie
-ifeq ($(open_memstream-pass),)
-  ifeq ($(funopen-pass)$(fopencookie-pass),)
-    CFLAGS += -DWITHOUT_OPEN_MEMSTREAM
-    ifeq ($(wildcard .config),.config)
-        $(warning warning: funopen and fopencookie unavailable, open_memstream can not be implemented and conversion to JSON will not work properly!)
-    endif
-  else
-    TINYCBOR_SOURCES += src/open_memstream.c
-  endif
-endif
 endif
 
 # json2cbor depends on an external library (cjson)
diff --git a/Makefile.configure b/Makefile.configure
index c2f51eea..e68d277b 100644
--- a/Makefile.configure
+++ b/Makefile.configure
@@ -1,9 +1,8 @@
-ALLTESTS = open_memstream funopen fopencookie gc_sections \
+ALLTESTS = funopen fopencookie gc_sections \
 	   system-cjson cjson freestanding
 MAKEFILE := $(lastword $(MAKEFILE_LIST))
 OUT :=
 
-PROGRAM-open_memstream = extern int open_memstream(); int main() { return open_memstream(); }
 PROGRAM-funopen = extern int funopen(); int main() { return funopen(); }
 PROGRAM-fopencookie = extern int fopencookie(); int main() { return fopencookie(); }
 PROGRAM-gc_sections = int main() {}
diff --git a/Makefile.nmake b/Makefile.nmake
index 04b58ab4..13f27845 100644
--- a/Makefile.nmake
+++ b/Makefile.nmake
@@ -5,6 +5,7 @@ TINYCBOR_SOURCES = \
 	src\cborerrorstrings.c \
 	src\cborencoder.c \
 	src\cborencoder_close_container_checked.c \
+	src\cbortojson.c \
 	src\cborparser.c \
 	src\cborparser_dup_string.c \
 	src\cborpretty.c \
@@ -14,6 +15,7 @@ TINYCBOR_OBJS = \
 	src\cborerrorstrings.obj \
 	src\cborencoder.obj \
 	src\cborencoder_close_container_checked.obj \
+	src\cbortojson.obj \
 	src\cborparser.obj \
 	src\cborparser_dup_string.obj \
 	src\cborpretty.obj \
diff --git a/src/cborjson.h b/src/cborjson.h
index 8ff27b92..4a861eaa 100644
--- a/src/cborjson.h
+++ b/src/cborjson.h
@@ -47,6 +47,7 @@ enum CborToJsonFlags
     CborConvertDefaultFlags = 0
 };
 
+CBOR_API CborError cbor_value_to_json_stream(CborStreamFunction stream, void* token, CborValue *it, int flags);
 CBOR_API CborError cbor_value_to_json_advance(FILE *out, CborValue *value, int flags);
 CBOR_INLINE_API CborError cbor_value_to_json(FILE *out, const CborValue *value, int flags)
 {
diff --git a/src/cbortojson.c b/src/cbortojson.c
index 4b11d319..e5627dc1 100644
--- a/src/cbortojson.c
+++ b/src/cbortojson.c
@@ -39,6 +39,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdarg.h>
 
 /**
  * \defgroup CborToJson Converting CBOR to JSON
@@ -146,7 +147,7 @@
  * the keys for the metadata clash with existing keys in the JSON map.
  */
 
-extern FILE *open_memstream(char **bufptr, size_t *sizeptr);
+#define IF_NO_ERROR(e, proc) do { if(!e) { e = proc; } } while(0)
 
 enum ConversionStatusFlags {
     TypeWasNotNative            = 0x100,    /* anything but strings, boolean, null, arrays and maps */
@@ -165,7 +166,7 @@ typedef struct ConversionStatus {
     int flags;
 } ConversionStatus;
 
-static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType type, ConversionStatus *status);
+static CborError value_to_json(CborStreamFunction stream, void *token, CborValue *it, int flags, CborType type, ConversionStatus *status);
 
 static CborError dump_bytestring_base16(char **result, CborValue *it)
 {
@@ -290,7 +291,7 @@ static CborError dump_bytestring_base64url(char **result, CborValue *it)
     return generic_dump_base64(result, it, alphabet);
 }
 
-static CborError add_value_metadata(FILE *out, CborType type, const ConversionStatus *status)
+static CborError add_value_metadata(CborStreamFunction stream, void *out, CborType type, const ConversionStatus *status)
 {
     int flags = status->flags;
     if (flags & TypeWasTagged) {
@@ -298,8 +299,8 @@ static CborError add_value_metadata(FILE *out, CborType type, const ConversionSt
         type = flags & FinalTypeMask;
         flags &= ~(FinalTypeMask | TypeWasTagged);
 
-        if (fprintf(out, "\"tag\":\"%" PRIu64 "\"%s", status->lastTag,
-                    flags & ~TypeWasTagged ? "," : "") < 0)
+        if (stream(out, "\"tag\":\"%" PRIu64 "\"%s", status->lastTag,
+                    flags & ~TypeWasTagged ? "," : ""))
             return CborErrorIO;
     }
 
@@ -307,21 +308,21 @@ static CborError add_value_metadata(FILE *out, CborType type, const ConversionSt
         return CborNoError;
 
     /* print at least the type */
-    if (fprintf(out, "\"t\":%d", type) < 0)
+    if (stream(out, "\"t\":%d", type))
         return CborErrorIO;
 
     if (flags & NumberWasNaN)
-        if (fprintf(out, ",\"v\":\"nan\"") < 0)
+        if (stream(out, ",\"v\":\"nan\""))
             return CborErrorIO;
     if (flags & NumberWasInfinite)
-        if (fprintf(out, ",\"v\":\"%sinf\"", flags & NumberWasNegative ? "-" : "") < 0)
+        if (stream(out, ",\"v\":\"%sinf\"", flags & NumberWasNegative ? "-" : ""))
             return CborErrorIO;
     if (flags & NumberPrecisionWasLost)
-        if (fprintf(out, ",\"v\":\"%c%" PRIx64 "\"", flags & NumberWasNegative ? '-' : '+',
-                    status->originalNumber) < 0)
+        if (stream(out, ",\"v\":\"%c%" PRIx64 "\"", flags & NumberWasNegative ? '-' : '+',
+                    status->originalNumber))
             return CborErrorIO;
     if (type == CborSimpleType)
-        if (fprintf(out, ",\"v\":%d", (int)status->originalNumber) < 0)
+        if (stream(out, ",\"v\":%d", (int)status->originalNumber))
             return CborErrorIO;
     return CborNoError;
 }
@@ -341,7 +342,7 @@ static CborError find_tagged_type(CborValue *it, CborTag *tag, CborType *type)
     return err;
 }
 
-static CborError tagged_value_to_json(FILE *out, CborValue *it, int flags, ConversionStatus *status)
+static CborError tagged_value_to_json(CborStreamFunction stream, void *out, CborValue *it, int flags, ConversionStatus *status)
 {
     CborTag tag;
     CborError err;
@@ -352,20 +353,20 @@ static CborError tagged_value_to_json(FILE *out, CborValue *it, int flags, Conve
         if (err)
             return err;
 
-        if (fprintf(out, "{\"tag%" PRIu64 "\":", tag) < 0)
+        if (stream(out, "{\"tag%" PRIu64 "\":", tag))
             return CborErrorIO;
 
         CborType type = cbor_value_get_type(it);
-        err = value_to_json(out, it, flags, type, status);
+        err = value_to_json(stream, out, it, flags, type, status);
         if (err)
             return err;
         if (flags & CborConvertAddMetadata && status->flags) {
-            if (fprintf(out, ",\"tag%" PRIu64 "$cbor\":{", tag) < 0 ||
-                    add_value_metadata(out, type, status) != CborNoError ||
-                    fputc('}', out) < 0)
+            if (stream(out, ",\"tag%" PRIu64 "$cbor\":{", tag) ||
+                    add_value_metadata(stream, out, type, status) != CborNoError ||
+                    stream(out, "%c", '}'))
                 return CborErrorIO;
         }
-        if (fputc('}', out) < 0)
+        if (stream(out, "%c", '}'))
             return CborErrorIO;
         status->flags = TypeWasNotNative | CborTagType;
         return CborNoError;
@@ -393,109 +394,117 @@ static CborError tagged_value_to_json(FILE *out, CborValue *it, int flags, Conve
         }
         if (err)
             return err;
-        err = fprintf(out, "\"%s%s\"", pre, str) < 0 ? CborErrorIO : CborNoError;
+        err = stream(out, "\"%s%s\"", pre, str);
         free(str);
         status->flags = TypeWasNotNative | TypeWasTagged | CborByteStringType;
         return err;
     }
 
     /* no special handling */
-    err = value_to_json(out, it, flags, type, status);
+    err = value_to_json(stream, out, it, flags, type, status);
     status->flags |= TypeWasTagged | type;
     return err;
 }
 
-static CborError stringify_map_key(char **key, CborValue *it, int flags, CborType type)
-{
-    (void)flags;    /* unused */
-    (void)type;     /* unused */
-#ifdef WITHOUT_OPEN_MEMSTREAM
-    (void)key;      /* unused */
-    (void)it;       /* unused */
-    return CborErrorJsonNotImplemented;
-#else
-    size_t size;
-
-    FILE *memstream = open_memstream(key, &size);
-    if (memstream == NULL)
-        return CborErrorOutOfMemory;        /* could also be EMFILE, but it's unlikely */
-    CborError err = cbor_value_to_pretty_advance(memstream, it);
-
-    if (unlikely(fclose(memstream) < 0 || *key == NULL))
-        return CborErrorInternalError;
-    return err;
-#endif
-}
-
-static CborError array_to_json(FILE *out, CborValue *it, int flags, ConversionStatus *status)
+static CborError array_to_json(CborStreamFunction stream, void *out, CborValue *it, int flags, ConversionStatus *status)
 {
     const char *comma = "";
     while (!cbor_value_at_end(it)) {
-        if (fprintf(out, "%s", comma) < 0)
+        if (stream(out, "%s", comma))
             return CborErrorIO;
         comma = ",";
 
-        CborError err = value_to_json(out, it, flags, cbor_value_get_type(it), status);
+        CborError err = value_to_json(stream, out, it, flags, cbor_value_get_type(it), status);
         if (err)
             return err;
     }
     return CborNoError;
 }
 
-static CborError map_to_json(FILE *out, CborValue *it, int flags, ConversionStatus *status)
+static CborError put_string_to_stream(CborStreamFunction stream, void* out, CborValue *it)
+{
+    char *string = NULL;
+    size_t n = 0;
+    CborError err = cbor_value_dup_text_string(it, &string, &n, it);
+    if (err)
+        return err;
+
+    err = stream(out, "%s", string);
+    free(string);
+
+    return err;
+}
+
+static CborError map_to_json(CborStreamFunction stream, void *out, CborValue *it, int flags, ConversionStatus *status)
 {
     const char *comma = "";
-    CborError err;
+    CborError err = CborNoError;
     while (!cbor_value_at_end(it)) {
-        char *key;
-        if (fprintf(out, "%s", comma) < 0)
+        /* Remember the iterator position for re-read the key value */
+        CborValue it_key = *it;
+
+        if (stream(out, "%s", comma))
             return CborErrorIO;
         comma = ",";
 
+        /* first, print the key */
         CborType keyType = cbor_value_get_type(it);
         if (likely(keyType == CborTextStringType)) {
-            size_t n = 0;
-            err = cbor_value_dup_text_string(it, &key, &n, it);
+            IF_NO_ERROR(err, stream(out, "\""));
+            IF_NO_ERROR(err, put_string_to_stream(stream, out, it) );
+            IF_NO_ERROR(err, stream(out, "\":"));
+
+            if (err)
+                return CborErrorIO;
         } else if (flags & CborConvertStringifyMapKeys) {
-            err = stringify_map_key(&key, it, flags, keyType);
+            IF_NO_ERROR(err, stream(out, "\""));
+            IF_NO_ERROR(err, cbor_value_to_pretty_stream(stream, out, it, CborPrettyDefaultFlags));
+            IF_NO_ERROR(err, stream(out, "\":"));
+            if (err)
+                return err;
         } else {
             return CborErrorJsonObjectKeyNotString;
         }
-        if (err)
-            return err;
-
-        /* first, print the key */
-        if (fprintf(out, "\"%s\":", key) < 0) {
-            free(key);
-            return CborErrorIO;
-        }
 
         /* then, print the value */
         CborType valueType = cbor_value_get_type(it);
-        err = value_to_json(out, it, flags, valueType, status);
+        err = value_to_json(stream, out, it, flags, valueType, status);
 
         /* finally, print any metadata we may have */
         if (flags & CborConvertAddMetadata) {
             if (!err && keyType != CborTextStringType) {
-                if (fprintf(out, ",\"%s$keycbordump\":true", key) < 0)
+                /* Might be read the key again in the next if-clause, keep this. */
+                CborValue tmpval = it_key;
+                IF_NO_ERROR(err, stream(out, ",\""));
+                IF_NO_ERROR(err, cbor_value_to_pretty_stream(stream, out, &tmpval, CborPrettyDefaultFlags));
+                IF_NO_ERROR(err, stream(out, "$keycbordump\":true"));
+
+                if(err)
                     err = CborErrorIO;
             }
             if (!err && status->flags) {
-                if (fprintf(out, ",\"%s$cbor\":{", key) < 0 ||
-                        add_value_metadata(out, valueType, status) != CborNoError ||
-                        fputc('}', out) < 0)
+                IF_NO_ERROR(err, stream(out, ",\""));
+                if (keyType == CborTextStringType) {
+                    IF_NO_ERROR(err, put_string_to_stream(stream, out, &it_key));
+                } else {
+                    IF_NO_ERROR(err, cbor_value_to_pretty_stream(stream, out, &it_key, CborPrettyDefaultFlags));
+                }
+                IF_NO_ERROR(err, stream(out, "$cbor\":{"));
+                IF_NO_ERROR(err, add_value_metadata(stream, out, valueType, status));
+                IF_NO_ERROR(err, stream(out, "%c", '}'));
+
+                if(err)
                     err = CborErrorIO;
             }
         }
 
-        free(key);
         if (err)
             return err;
     }
     return CborNoError;
 }
 
-static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType type, ConversionStatus *status)
+static CborError value_to_json(CborStreamFunction stream, void *out, CborValue *it, int flags, CborType type, ConversionStatus *status)
 {
     CborError err;
     status->flags = 0;
@@ -510,18 +519,18 @@ static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType typ
             it->ptr = recursed.ptr;
             return err;       /* parse error */
         }
-        if (fputc(type == CborArrayType ? '[' : '{', out) < 0)
+        if (stream(out, "%c", (type == CborArrayType ? '[' : '{') ))
             return CborErrorIO;
 
         err = (type == CborArrayType) ?
-                  array_to_json(out, &recursed, flags, status) :
-                  map_to_json(out, &recursed, flags, status);
+                  array_to_json(stream, out, &recursed, flags, status) :
+                  map_to_json(stream, out, &recursed, flags, status);
         if (err) {
             it->ptr = recursed.ptr;
             return err;       /* parse error */
         }
 
-        if (fputc(type == CborArrayType ? ']' : '}', out) < 0)
+        if (stream(out, "%c", (type == CborArrayType ? ']' : '}') ))
             return CborErrorIO;
         err = cbor_value_leave_container(it, &recursed);
         if (err)
@@ -549,7 +558,7 @@ static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType typ
                 status->originalNumber = val;
             }
         }
-        if (fprintf(out, "%.0f", num) < 0)  /* this number has no fraction, so no decimal points please */
+        if (stream(out, "%.0f", num))  /* this number has no fraction, so no decimal points please */
             return CborErrorIO;
         break;
     }
@@ -566,39 +575,39 @@ static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType typ
         }
         if (err)
             return err;
-        err = (fprintf(out, "\"%s\"", str) < 0) ? CborErrorIO : CborNoError;
+        err = (stream(out, "\"%s\"", str));
         free(str);
         return err;
     }
 
     case CborTagType:
-        return tagged_value_to_json(out, it, flags, status);
+        return tagged_value_to_json(stream, out, it, flags, status);
 
     case CborSimpleType: {
         uint8_t simple_type;
         cbor_value_get_simple_type(it, &simple_type);  /* can't fail */
         status->flags = TypeWasNotNative;
         status->originalNumber = simple_type;
-        if (fprintf(out, "\"simple(%" PRIu8 ")\"", simple_type) < 0)
+        if (stream(out, "\"simple(%" PRIu8 ")\"", simple_type))
             return CborErrorIO;
         break;
     }
 
     case CborNullType:
-        if (fprintf(out, "null") < 0)
+        if (stream(out, "null"))
             return CborErrorIO;
         break;
 
     case CborUndefinedType:
         status->flags = TypeWasNotNative;
-        if (fprintf(out, "\"undefined\"") < 0)
+        if (stream(out, "\"undefined\""))
             return CborErrorIO;
         break;
 
     case CborBooleanType: {
         bool val;
         cbor_value_get_boolean(it, &val);       /* can't fail */
-        if (fprintf(out, val ? "true" : "false") < 0)
+        if (stream(out, val ? "true" : "false"))
             return CborErrorIO;
         break;
     }
@@ -630,7 +639,7 @@ static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType typ
 
         int r = fpclassify(val);
         if (r == FP_NAN || r == FP_INFINITE) {
-            if (fprintf(out, "null") < 0)
+            if (stream(out, "null"))
                 return CborErrorIO;
             status->flags |= r == FP_NAN ? NumberWasNaN :
                                            NumberWasInfinite | (val < 0 ? NumberWasNegative : 0);
@@ -638,13 +647,13 @@ static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType typ
             uint64_t ival = (uint64_t)fabs(val);
             if ((double)ival == fabs(val)) {
                 /* print as integer so we get the full precision */
-                r = fprintf(out, "%s%" PRIu64, val < 0 ? "-" : "", ival);
+                r = stream(out, "%s%" PRIu64, val < 0 ? "-" : "", ival);
                 status->flags |= TypeWasNotNative;   /* mark this integer number as a double */
             } else {
                 /* this number is definitely not a 64-bit integer */
-                r = fprintf(out, "%." DBL_DECIMAL_DIG_STR "g", val);
+                r = stream(out, "%." DBL_DECIMAL_DIG_STR "g", val);
             }
-            if (r < 0)
+            if (r)
                 return CborErrorIO;
         }
         break;
@@ -689,6 +698,40 @@ static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType typ
  * \sa cbor_value_to_json_advance(), cbor_value_to_pretty()
  */
 
+/**
+ * Converts the current CBOR type pointed by \a value to JSON and writes that
+ * to the stream by calling the \a streamFunction. If an error occurs,
+ * this function returns an error code similar to \ref CborParsing.
+ * The \a flags parameter indicates one or more of the flags from CborToJsonFlags
+ * that control the conversion.
+ *
+ * If no error ocurred, this function advances \a value to the next element.
+ *
+ * The \a streamFunction function will be called with the \a token value as the
+ * first parameter and a printf-style format string as the second, with a variable
+ * number of further parameters.
+ *
+ * \sa cbor_value_to_pretty_stream(), cbor_value_to_json_advance()
+ */
+
+CborError cbor_value_to_json_stream(CborStreamFunction streamFunction, void *token, CborValue *value, int flags)
+{
+    ConversionStatus status;
+    return value_to_json(streamFunction, token, value, flags, cbor_value_get_type(value), &status);
+}
+
+static CborError cborjson_fprintf(void *out, const char *fmt, ...)
+{
+    int n;
+
+    va_list list;
+    va_start(list, fmt);
+    n = vfprintf((FILE *)out, fmt, list);
+    va_end(list);
+
+    return n < 0 ? CborErrorIO : CborNoError;
+}
+
 /**
  * Converts the current CBOR type pointed to by \a value to JSON and writes that
  * to the \a out stream. If an error occurs, this function returns an error
@@ -702,7 +745,7 @@ static CborError value_to_json(FILE *out, CborValue *it, int flags, CborType typ
 CborError cbor_value_to_json_advance(FILE *out, CborValue *value, int flags)
 {
     ConversionStatus status;
-    return value_to_json(out, value, flags, cbor_value_get_type(value), &status);
+    return value_to_json(cborjson_fprintf, out, value, flags, cbor_value_get_type(value), &status);
 }
 
 /** @} */
diff --git a/src/open_memstream.c b/src/open_memstream.c
deleted file mode 100644
index 33653784..00000000
--- a/src/open_memstream.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 Intel Corporation
-**
-** Permission is hereby granted, free of charge, to any person obtaining a copy
-** of this software and associated documentation files (the "Software"), to deal
-** in the Software without restriction, including without limitation the rights
-** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-** copies of the Software, and to permit persons to whom the Software is
-** furnished to do so, subject to the following conditions:
-**
-** The above copyright notice and this permission notice shall be included in
-** all copies or substantial portions of the Software.
-**
-** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-** THE SOFTWARE.
-**
-****************************************************************************/
-
-#define _BSD_SOURCE 1
-#define _DEFAULT_SOURCE 1
-#define _GNU_SOURCE 1
-
-#include <sys/types.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#if defined(__unix__) || defined(__APPLE__)
-#  include <unistd.h>
-#endif
-#ifdef __APPLE__
-typedef int RetType;
-typedef int LenType;
-#elif __linux__
-typedef ssize_t RetType;
-typedef size_t LenType;
-#else
-#  error "Cannot implement open_memstream!"
-#endif
-
-#include "compilersupport_p.h"
-
-struct Buffer
-{
-    char **ptr;
-    size_t *len;
-    size_t alloc;
-};
-
-static RetType write_to_buffer(void *cookie, const char *data, LenType len)
-{
-    struct Buffer *b = (struct Buffer *)cookie;
-    char *ptr = *b->ptr;
-    size_t newsize;
-
-    errno = EFBIG;
-    if (unlikely(add_check_overflow(*b->len, len, &newsize)))
-        return -1;
-
-    if (newsize >= b->alloc) { // NB! one extra byte is needed to avoid buffer overflow at close_buffer
-        // make room
-        size_t newalloc = newsize + newsize / 2 + 1;    // give 50% more room
-        ptr = realloc(ptr, newalloc);
-        if (ptr == NULL)
-            return -1;
-        b->alloc = newalloc;
-        *b->ptr = ptr;
-    }
-
-    memcpy(ptr + *b->len, data, len);
-    *b->len = newsize;
-    return len;
-}
-
-static int close_buffer(void *cookie)
-{
-    struct Buffer *b = (struct Buffer *)cookie;
-    if (*b->ptr)
-        (*b->ptr)[*b->len] = '\0';
-    free(b);
-    return 0;
-}
-
-FILE *open_memstream(char **bufptr, size_t *lenptr)
-{
-    struct Buffer *b = (struct Buffer *)malloc(sizeof(struct Buffer));
-    if (b == NULL)
-        return NULL;
-    b->alloc = 0;
-    b->len = lenptr;
-    b->ptr = bufptr;
-    *bufptr = NULL;
-    *lenptr = 0;
-
-#ifdef __APPLE__
-    return funopen(b, NULL, write_to_buffer, NULL, close_buffer);
-#elif __linux__
-    static const cookie_io_functions_t vtable = {
-        NULL,
-        write_to_buffer,
-        NULL,
-        close_buffer
-    };
-    return fopencookie(b, "w", vtable);
-#endif
-}
-
diff --git a/tests/tests.pro b/tests/tests.pro
index 6036f0f9..03b94d97 100644
--- a/tests/tests.pro
+++ b/tests/tests.pro
@@ -1,3 +1,2 @@
 TEMPLATE = subdirs
 SUBDIRS = parser encoder c90 cpp tojson
-msvc: SUBDIRS -= tojson
diff --git a/tests/tojson/tst_tojson.cpp b/tests/tojson/tst_tojson.cpp
index 8bf24efb..d1e0e23c 100644
--- a/tests/tojson/tst_tojson.cpp
+++ b/tests/tojson/tst_tojson.cpp
@@ -27,7 +27,25 @@
 #include "cborjson.h"
 #include <locale.h>
 
-extern "C" FILE *open_memstream(char **bufptr, size_t *sizeptr);
+static CborError qstring_stream(void *out, const char *fmt, ...)
+{
+    int n;
+
+    QString* qstr = (QString*)out;
+
+    QString str;
+
+    va_list list;
+    va_start(list, fmt);
+    str.vsprintf(fmt, list);
+    va_end(list);
+
+    qstr->append(str);
+    n = str.length();
+
+    return n < 0 ? CborErrorIO : CborNoError;
+}
+
 
 class tst_ToJson : public QObject
 {
@@ -197,15 +215,11 @@ void addEmptyContainersData()
 
 CborError parseOne(CborValue *it, QString *parsed, int flags)
 {
-    char *buffer;
-    size_t size;
+    QString buffer;
+    CborError err = cbor_value_to_json_stream(qstring_stream, &buffer, it, flags);
 
-    FILE *f = open_memstream(&buffer, &size);
-    CborError err = cbor_value_to_json_advance(f, it, flags);
-    fclose(f);
+    *parsed = buffer;
 
-    *parsed = QString::fromLatin1(buffer);
-    free(buffer);
     return err;
 }