diff --git a/include/wjwriter.h b/include/wjwriter.h index a4a8b48..d2f4e0d 100644 --- a/include/wjwriter.h +++ b/include/wjwriter.h @@ -42,6 +42,19 @@ typedef struct { */ int base; + /* + If set to TRUE (enabled by default) then any character that can not be + encoded as a UTF8 character will be written as \xXX where XX are a hex + representation of the value. + + This can be disabled since it is non-standard JSON and will cause parse + errors with some parsers. + + If disabled then any invalid characters will not be written to the + document. + */ + XplBool escapeInvalidChars; + struct { void *data; WJWriteCallback cb; @@ -115,6 +128,12 @@ EXPORT XplBool WJWRawValue(char *name, char *value, XplBool done, WJWriter doc EXPORT size_t WJWFileCallback(char *buffer, size_t length, void *data); #define WJWOpenFILEDocument(pretty, file) _WJWOpenDocument((pretty), WJWFileCallback, (file), 0) +/* + An alternative method of opening a JSON document for writing, which will + provide a proper callback for allocating and writing to a memory allocation. +*/ +EXPORT WJWriter WJWOpenMemDocument(XplBool pretty, char **mem); + #ifdef __cplusplus } #endif diff --git a/src/wjwriter/wjwriter.c b/src/wjwriter/wjwriter.c index 34d4de8..d8e72e0 100644 --- a/src/wjwriter/wjwriter.c +++ b/src/wjwriter/wjwriter.c @@ -267,10 +267,11 @@ EXPORT WJWriter _WJWOpenDocument(XplBool pretty, WJWriteCallback callback, void The first value after opening a document should not be preceded by a comma. skipcomma will be reset after reading that first value. */ - doc->public.pretty = pretty; - doc->public.base = 10; - doc->skipcomma = TRUE; - doc->skipbreak = TRUE; + doc->public.pretty = pretty; + doc->public.escapeInvalidChars = TRUE; + doc->public.base = 10; + doc->skipcomma = TRUE; + doc->skipbreak = TRUE; return((WJWriter) doc); } @@ -336,6 +337,39 @@ EXPORT size_t WJWFileCallback(char *buffer, size_t length, void *data) return(0); } +static size_t WJWMemCallback(char *buffer, size_t length, void *data) +{ + char **mem = data; + size_t l; + + if (mem) { + if (!*mem) { + *mem = MemMallocWait(length + 1); + memcpy(*mem, buffer, length); + (*mem)[length] = '\0'; + } else { + l = strlen(*mem); + + *mem = MemReallocWait(*mem, l + length + 1); + memcpy(*mem + l, buffer, length); + (*mem)[l + length] = '\0'; + } + + return(length); + } + + return(0); +} + +EXPORT WJWriter WJWOpenMemDocument(XplBool pretty, char **mem) +{ + if (!mem) { + return(NULL); + } + + return(_WJWOpenDocument(pretty, WJWMemCallback, mem, 0)); +} + /* Verify that str points to a valid UTF8 character, and return the length of that character in bytes. If the value is not a full valid UTF8 character @@ -440,8 +474,9 @@ static XplBool WJWriteString(char *value, size_t length, XplBool done, WJIWriter e += (l - 1); } else if (l == 1) { /* - *e is valid UTF8 but is not a printable character, and will be escaped before - being sent, using the JSON-standard "\u00xx" form + *e is valid UTF8 but is not a printable character, and + will be escaped before being sent, using the + JSON-standard "\u00xx" form */ char unicodeHex[sizeof("\\u0000")]; @@ -454,15 +489,18 @@ static XplBool WJWriteString(char *value, size_t length, XplBool done, WJIWriter } else if (l < 0) { /* *e is not valid UTF8 data, and must be escaped before - being sent. But JSON-standard does not give us a mechanism - so we chose "\xhh" format because of its almost universal comprehension. + being sent. But JSON-standard does not give us a + mechanism so we chose "\xhh" format because of its + almost universal comprehension. */ char nonUnicodeHex[sizeof("\\x00")]; WJWrite(doc, v, e - v); - sprintf(nonUnicodeHex, "\\x%02x", (unsigned char) *e); - WJWrite(doc, nonUnicodeHex, sizeof(nonUnicodeHex)-1); + if (doc->public.escapeInvalidChars) { + sprintf(nonUnicodeHex, "\\x%02x", (unsigned char) *e); + WJWrite(doc, nonUnicodeHex, sizeof(nonUnicodeHex)-1); + } v = e + 1; }