IOT-1583: Updating cJSON version to remove /W4 warnings.
authorPawel Winogrodzki <pawelwi@microsoft.com>
Wed, 29 Mar 2017 19:24:38 +0000 (12:24 -0700)
committerDave Thaler <dthaler@microsoft.com>
Thu, 6 Apr 2017 18:10:49 +0000 (18:10 +0000)
The code is updated to commit b0db7a6308f8948dd4a68f06b787cb425ce7254d
from the main cJSON repo: https://github.com/DaveGamble/cJSON.

Change-Id: I43b2bae1fa4fde5eee12f7d74990d5263f4ec51b
Signed-off-by: Pawel Winogrodzki <pawelwi@microsoft.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/18381
Tested-by: jenkins-iotivity <jenkins@iotivity.org>
Reviewed-by: Dan Mihai <Daniel.Mihai@microsoft.com>
Reviewed-by: Dave Thaler <dthaler@microsoft.com>
14 files changed:
bridging/plugins/hue_plugin/SConscript
build_common/android/SConscript
build_common/external_libs.scons
build_common/linux/SConscript
extlibs/android/gradle/SConscript
extlibs/android/sdk/SConscript
extlibs/arduino/SConscript
extlibs/cjson/README-cJSON.txt
extlibs/cjson/SConscript
extlibs/cjson/cJSON.c
extlibs/cjson/cJSON.h
resource/csdk/security/tool/SConscript
service/coap-http-proxy/SConscript
service/simulator/ramlparser/SConscript

index 01d7f5d..7c75284 100644 (file)
@@ -32,8 +32,6 @@ bridging_path = os.path.join(src_dir, 'bridging')
 
 hue_env = env.Clone()
 
-SConscript('#/extlibs/cjson/SConscript')
-
 print "Reading Hue Plugin script"
 
 ######################################################################
index a2e8a1f..034bdf6 100644 (file)
@@ -7,7 +7,6 @@ import subprocess
 
 Import('env')
 
-SConscript('../external_libs.scons')
 help_vars = Variables()
 if not env.get('ANDROID_NDK'):
     SConscript('../../extlibs/android/ndk/SConscript')
index 22a6c1a..c43a29e 100644 (file)
@@ -138,6 +138,9 @@ SConscript('tools/UnpackAll.py')
 # tinycbor build/fetch
 SConscript(os.path.join(env.get('SRC_DIR'), 'extlibs', 'tinycbor', 'SConscript'))
 
+#cJSON lib
+SConscript(os.path.join(env.get('SRC_DIR'), 'extlibs', 'cjson', 'SConscript'))
+
 with_ra = env.get('WITH_RA')
 if with_ra:
        SConscript(os.path.join(env.get('SRC_DIR'), 'extlibs', 'raxmpp', 'SConscript'))
index eeea809..198118f 100644 (file)
@@ -8,7 +8,6 @@ Import('env')
 
 print "Reading linux configuration script"
 
-SConscript('../external_libs.scons')
 help_vars = Variables()
 if env.get('BUILD_JAVA') == True:
     if not env.get('ANDROID_GRADLE'):
index 9cece4b..208f223 100644 (file)
@@ -4,12 +4,10 @@ Import('env')
 
 env = env.Clone()
 ndk_env = env.Clone()
-SConscript('../../../build_common/external_libs.scons')
 
 target_os = env.get('TARGET_OS')
 host_os = sys.platform
 print host_os
-SConscript('../../../build_common/external_libs.scons')
 ######################################################################
 # Build flags
 ######################################################################
index 7b7b1ba..a06adf6 100644 (file)
@@ -13,7 +13,6 @@ target_os = env.get('TARGET_OS')
 src_dir = env.get('SRC_DIR')
 
 SConscript(src_dir + '/build_common/tools/UnpackAll.py')
-SConscript(src_dir + '/build_common/external_libs.scons')
 
 # Download
 if target_os == 'android':
index 879fe2c..fcd5cb7 100644 (file)
@@ -14,7 +14,6 @@ target_os = env.get('TARGET_OS')
 src_dir = env.get('SRC_DIR')
 
 SConscript(src_dir + '/build_common/tools/UnpackAll.py')
-SConscript(src_dir + '/build_common/external_libs.scons')
 
 # Download
 if target_os == 'arduino':
index 7e3a0b9..64ed9f8 100644 (file)
@@ -1,10 +1,9 @@
 This dependency comes from: https://github.com/DaveGamble/cJSON.git. The
 cJSON.c and cJSON.h files are copied from that repo.
 
-Commit ID from when files were last copied: 11fd27ade73c5049295a58eb0587e283241d0e70
-Release tag when files were last copied (if applicable): v1.0.1
+Commit ID from when files were last copied: b0db7a6308f8948dd4a68f06b787cb425ce7254d
+Release tag when files were last copied (if applicable):
 
 With the following changes:
-* git revert 679004914fceb1c418545fb33c707fb454cbc4bb (Define a boolean type)
-  * Causes a build break on Arduino because it declares 'bool' to be 'int'
+* b0db7a6 cJSON_ParseWidthOpts: Fix -Wmissing-field-initializers
 
index 7329925..8365b70 100644 (file)
 
 Import('env')
 
-libcjson = env.StaticLibrary('cjson', ['cJSON.c'], OBJPREFIX='libcjson_')
-env.InstallTarget(libcjson, 'cjson');
+cjson_env = env.Clone()
+
+if cjson_env.get('TARGET_OS') in ['windows', 'msys_nt']:
+    # Macro needed for Windows builds to avoid __declspec(dllexport) and __declspec(dllimport) for cJSON APIs.
+    cjson_env.AppendUnique(CPPDEFINES = ['CJSON_HIDE_SYMBOLS'])
+    if cjson_env['CC'] == 'cl':
+        cjson_env.AppendUnique(CCFLAGS = ['/W4', '/WX'])
+
+libcjson = cjson_env.StaticLibrary('cjson', ['cJSON.c'], OBJPREFIX='libcjson_')
+cjson_env.InstallTarget(libcjson, 'cjson');
 
index 079027c..75f900d 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2009 Dave Gamble
+  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
 
   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
 /* cJSON */
 /* JSON parser in C. */
 
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+
 #include <string.h>
 #include <stdio.h>
 #include <math.h>
 #include <float.h>
 #include <limits.h>
 #include <ctype.h>
-#include "cJSON.h"
 
-/* Determine the number of bits that an integer has using the preprocessor */
-#if INT_MAX == 32767
-    /* 16 bits */
-    #define INTEGER_SIZE 0x0010
-#elif INT_MAX == 2147483647
-    /* 32 bits */
-    #define INTEGER_SIZE 0x0100
-#elif INT_MAX == 9223372036854775807
-    /* 64 bits */
-    #define INTEGER_SIZE 0x1000
-#else
-    #error "Failed to determine the size of an integer"
+#ifdef __GNUC__
+#pragma GCC visibility pop
 #endif
 
-static const char *global_ep = NULL;
+#include "cJSON.h"
+
+/* define our own boolean type */
+#define true ((cJSON_bool)1)
+#define false ((cJSON_bool)0)
+
+typedef struct {
+    const unsigned char *json;
+    size_t position;
+} error;
+static error global_error = { NULL, 0 };
+
+CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
+{
+    return (const char*) (global_error.json + global_error.position);
+}
+
+/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
+#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 4) || (CJSON_VERSION_PATCH != 5)
+    #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
+#endif
 
-const char *cJSON_GetErrorPtr(void)
+CJSON_PUBLIC(const char*) cJSON_Version(void)
 {
-    return global_ep;
+    static char version[15];
+    sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
+
+    return version;
 }
 
 /* case insensitive strcmp */
-static int cJSON_strcasecmp(const char *s1, const char *s2)
+static int cJSON_strcasecmp(const unsigned char *string1, const unsigned char *string2)
 {
-    if (!s1)
+    if (string1 == NULL)
     {
-        return (s1 == s2) ? 0 : 1; /* both NULL? */
+        if (string2 == NULL)
+        {
+            /* both NULL */
+            return 0;
+        }
+
+        return 1;
     }
-    if (!s2)
+
+    if (string2 == NULL)
     {
         return 1;
     }
-    for(; tolower(*(const unsigned char *)s1) == tolower(*(const unsigned char *)s2); ++s1, ++s2)
+
+    for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
     {
-        if (*s1 == '\0')
+        if (*string1 == '\0')
         {
             return 0;
         }
     }
 
-    return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
+    return tolower(string1[0]) - tolower(string2[0]);
 }
 
-static void *(*cJSON_malloc)(size_t sz) = malloc;
-static void (*cJSON_free)(void *ptr) = free;
+typedef struct internal_hooks
+{
+    void *(*allocate)(size_t size);
+    void (*deallocate)(void *pointer);
+    void *(*reallocate)(void *pointer, size_t size);
+} internal_hooks;
+
+static internal_hooks global_hooks = { malloc, free, realloc };
 
-static char* cJSON_strdup(const char* str)
+static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
 {
-    size_t len = 0;
-    char *copy = NULL;
+    size_t length = 0;
+    unsigned char *copy = NULL;
+
+    if (string == NULL)
+    {
+        return NULL;
+    }
 
-    len = strlen(str) + 1;
-    if (!(copy = (char*)cJSON_malloc(len)))
+    length = strlen((const char*)string) + sizeof("");
+    if (!(copy = (unsigned char*)hooks->allocate(length)))
     {
         return NULL;
     }
-    memcpy(copy, str, len);
+    memcpy(copy, string, length);
 
     return copy;
 }
 
-void cJSON_InitHooks(cJSON_Hooks* hooks)
+CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
 {
-    if (!hooks)
+    if (hooks == NULL)
     {
         /* Reset hooks */
-        cJSON_malloc = malloc;
-        cJSON_free = free;
+        global_hooks.allocate = malloc;
+        global_hooks.deallocate = free;
+        global_hooks.reallocate = realloc;
         return;
     }
 
-    cJSON_malloc = (hooks->malloc_fn) ? hooks->malloc_fn : malloc;
-    cJSON_free = (hooks->free_fn) ? hooks->free_fn : free;
+    global_hooks.allocate = malloc;
+    if (hooks->malloc_fn != NULL)
+    {
+        global_hooks.allocate = hooks->malloc_fn;
+    }
+
+    global_hooks.deallocate = free;
+    if (hooks->free_fn != NULL)
+    {
+        global_hooks.deallocate = hooks->free_fn;
+    }
+
+    /* use realloc only if both free and malloc are used */
+    global_hooks.reallocate = NULL;
+    if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
+    {
+        global_hooks.reallocate = realloc;
+    }
 }
 
 /* Internal constructor. */
-static cJSON *cJSON_New_Item(void)
+static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
 {
-    cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
+    cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
     if (node)
     {
         memset(node, '\0', sizeof(cJSON));
@@ -120,1512 +172,1485 @@ static cJSON *cJSON_New_Item(void)
 }
 
 /* Delete a cJSON structure. */
-void cJSON_Delete(cJSON *c)
+CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
 {
     cJSON *next = NULL;
-    while (c)
+    while (item != NULL)
     {
-        next = c->next;
-        if (!(c->type & cJSON_IsReference) && c->child)
+        next = item->next;
+        if (!(item->type & cJSON_IsReference) && (item->child != NULL))
         {
-            cJSON_Delete(c->child);
+            cJSON_Delete(item->child);
         }
-        if (!(c->type & cJSON_IsReference) && c->valuestring)
+        if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
         {
-            cJSON_free(c->valuestring);
+            global_hooks.deallocate(item->valuestring);
         }
-        if (!(c->type & cJSON_StringIsConst) && c->string)
+        if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
         {
-            cJSON_free(c->string);
+            global_hooks.deallocate(item->string);
         }
-        cJSON_free(c);
-        c = next;
+        global_hooks.deallocate(item);
+        item = next;
     }
 }
 
+typedef struct
+{
+    const unsigned char *content;
+    size_t length;
+    size_t offset;
+} parse_buffer;
+
+/* check if the given size is left to read in a given parse buffer (starting with 1) */
+#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
+#define cannot_read(buffer, size) (!can_read(buffer, size))
+/* check if the buffer can be accessed at the given index (starting with 0) */
+#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
+#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
+/* get a pointer to the buffer at the position */
+#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
+
 /* Parse the input text to generate a number, and populate the result into item. */
-static const char *parse_number(cJSON *item, const char *num)
+static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
 {
-    double n = 0;
-    double sign = 1;
-    double scale = 0;
-    int subscale = 0;
-    int signsubscale = 1;
+    double number = 0;
+    unsigned char *after_end = NULL;
+    unsigned char number_c_string[64];
+    size_t i = 0;
+
+    if ((input_buffer == NULL) || (input_buffer->content == NULL))
+    {
+        return false;
+    }
+
+    /* copy the number into a temporary buffer and zero terminate the string
+     * because the number in the input buffer is not necessariliy zero terminated
+     * and strtod only works with zero terminated strings */
+    for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
+    {
+        switch (buffer_at_offset(input_buffer)[i])
+        {
+            case '0':
+            case '1':
+            case '2':
+            case '3':
+            case '4':
+            case '5':
+            case '6':
+            case '7':
+            case '8':
+            case '9':
+            case '+':
+            case '-':
+            case 'e':
+            case 'E':
+            case '.':
+                break;
 
-    /* Has sign? */
-    if (*num == '-')
-    {
-        sign = -1;
-        num++;
+            default:
+                goto loop_end;
+        }
+
+        number_c_string[i] = buffer_at_offset(input_buffer)[i];
     }
-    /* is zero */
-    if (*num == '0')
+    loop_end:
+    number_c_string[i] = '\0';
+
+
+    number = strtod((const char*)number_c_string, (char**)&after_end);
+    if (number_c_string == after_end)
     {
-        num++;
+        return false; /* parse_error */
     }
-    /* Number? */
-    if ((*num >= '1') && (*num <= '9'))
+
+    item->valuedouble = number;
+
+    /* use saturation in case of overflow */
+    if (number >= INT_MAX)
     {
-        do
-        {
-            n = (n * 10.0) + (*num++ - '0');
-        }
-        while ((*num >= '0') && (*num<='9'));
+        item->valueint = INT_MAX;
     }
-    /* Fractional part? */
-    if ((*num == '.') && (num[1] >= '0') && (num[1] <= '9'))
+    else if (number <= INT_MIN)
     {
-        num++;
-        do
-        {
-            n = (n  *10.0) + (*num++ - '0');
-            scale--;
-        } while ((*num >= '0') && (*num <= '9'));
+        item->valueint = INT_MIN;
     }
-    /* Exponent? */
-    if ((*num == 'e') || (*num == 'E'))
+    else
     {
-        num++;
-        /* With sign? */
-        if (*num == '+')
-        {
-            num++;
-        }
-        else if (*num == '-')
-        {
-            signsubscale = -1;
-            num++;
-        }
-        /* Number? */
-        while ((*num>='0') && (*num<='9'))
-        {
-            subscale = (subscale * 10) + (*num++ - '0');
-        }
+        item->valueint = (int)number;
     }
 
-    /* number = +/- number.fraction * 10^+/- exponent */
-    n = sign * n * pow(10.0, (scale + subscale * signsubscale));
-
-    item->valuedouble = n;
-    item->valueint = (int)n;
     item->type = cJSON_Number;
 
-    return num;
+    input_buffer->offset += (size_t)(after_end - number_c_string);
+    return true;
 }
 
-/* calculate the next largest power of 2 */
-static int pow2gt (int x)
+/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
+CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
 {
-    --x;
-
-    x |= x >> 1;
-    x |= x >> 2;
-    x |= x >> 4;
-#if INTEGER_SIZE & 0x1110 /* at least 16 bit */
-    x |= x >> 8;
-#endif
-#if INTEGER_SIZE & 0x1100 /* at least 32 bit */
-    x |= x >> 16;
-#endif
-#if INT_SIZE & 0x1000 /* 64 bit */
-    x |= x >> 32;
-#endif
+    if (number >= INT_MAX)
+    {
+        object->valueint = INT_MAX;
+    }
+    else if (number <= INT_MIN)
+    {
+        object->valueint = INT_MIN;
+    }
+    else
+    {
+        object->valueint = (int)number;
+    }
 
-    return x + 1;
+    return object->valuedouble = number;
 }
 
 typedef struct
 {
-    char *buffer;
-    int length;
-    int offset;
+    unsigned char *buffer;
+    size_t length;
+    size_t offset;
+    cJSON_bool noalloc;
 } printbuffer;
 
 /* realloc printbuffer if necessary to have at least "needed" bytes more */
-static char* ensure(printbuffer *p, int needed)
+static unsigned char* ensure(printbuffer * const p, size_t needed, const internal_hooks * const hooks)
 {
-    char *newbuffer = NULL;
-    int newsize = 0;
-    if (!p || !p->buffer)
+    unsigned char *newbuffer = NULL;
+    size_t newsize = 0;
+
+    if ((p == NULL) || (p->buffer == NULL))
+    {
+        return NULL;
+    }
+
+    if ((p->length > 0) && (p->offset >= p->length))
+    {
+        /* make sure that offset is valid */
+        return NULL;
+    }
+
+    if (needed > INT_MAX)
     {
+        /* sizes bigger than INT_MAX are currently not supported */
         return NULL;
     }
-    needed += p->offset;
+
+    needed += p->offset + 1;
     if (needed <= p->length)
     {
         return p->buffer + p->offset;
     }
 
-    newsize = pow2gt(needed);
-    newbuffer = (char*)cJSON_malloc(newsize);
-    if (!newbuffer)
+    if (p->noalloc) {
+        return NULL;
+    }
+
+    /* calculate new buffer size */
+    if (newsize > (INT_MAX / 2))
+    {
+        /* overflow of int, use INT_MAX if possible */
+        if (needed <= INT_MAX)
+        {
+            newsize = INT_MAX;
+        }
+        else
+        {
+            return NULL;
+        }
+    }
+    else
     {
-        cJSON_free(p->buffer);
-        p->length = 0;
-        p->buffer = NULL;
+        newsize = needed * 2;
+    }
 
-        return NULL;
+    if (hooks->reallocate != NULL)
+    {
+        /* reallocate with realloc if available */
+        newbuffer = (unsigned char*)hooks->reallocate(p->buffer, newsize);
     }
-    if (newbuffer)
+    else
     {
-        memcpy(newbuffer, p->buffer, p->length);
+        /* otherwise reallocate manually */
+        newbuffer = (unsigned char*)hooks->allocate(newsize);
+        if (!newbuffer)
+        {
+            hooks->deallocate(p->buffer);
+            p->length = 0;
+            p->buffer = NULL;
+
+            return NULL;
+        }
+        if (newbuffer)
+        {
+            memcpy(newbuffer, p->buffer, p->offset + 1);
+        }
+        hooks->deallocate(p->buffer);
     }
-    cJSON_free(p->buffer);
     p->length = newsize;
     p->buffer = newbuffer;
 
     return newbuffer + p->offset;
 }
 
-/* calculate the new length of the string in a printbuffer */
-static int update(const printbuffer *p)
+/* calculate the new length of the string in a printbuffer and update the offset */
+static void update_offset(printbuffer * const buffer)
+{
+    const unsigned char *buffer_pointer = NULL;
+    if ((buffer == NULL) || (buffer->buffer == NULL))
+    {
+        return;
+    }
+    buffer_pointer = buffer->buffer + buffer->offset;
+
+    buffer->offset += strlen((const char*)buffer_pointer);
+}
+
+/* Removes trailing zeroes from the end of a printed number */
+static cJSON_bool trim_trailing_zeroes(printbuffer * const buffer)
 {
-    char *str = NULL;
-    if (!p || !p->buffer)
+    size_t offset = 0;
+    unsigned char *content = NULL;
+
+    if ((buffer == NULL) || (buffer->buffer == NULL) || (buffer->offset < 1))
+    {
+        return false;
+    }
+
+    offset = buffer->offset - 1;
+    content = buffer->buffer;
+
+    while ((offset > 0) && (content[offset] == '0'))
+    {
+        offset--;
+    }
+    if ((offset > 0) && (content[offset] == '.'))
     {
-        return 0;
+        offset--;
     }
-    str = p->buffer + p->offset;
 
-    return p->offset + strlen(str);
+    offset++;
+    content[offset] = '\0';
+
+    buffer->offset = offset;
+
+    return true;
 }
 
 /* Render the number nicely from the given item into a string. */
-static char *print_number(const cJSON *item, printbuffer *p)
+static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer, const internal_hooks * const hooks)
 {
-    char *str = NULL;
+    unsigned char *output_pointer = NULL;
     double d = item->valuedouble;
-    /* special case for 0. */
-    if (d == 0)
+    int length = 0;
+    cJSON_bool trim_zeroes = true; /* should at the end be removed? */
+
+    if (output_buffer == NULL)
     {
-        if (p)
-        {
-            str = ensure(p, 2);
-        }
-        else
-        {
-            str = (char*)cJSON_malloc(2);
-        }
-        if (str)
-        {
-            strcpy(str,"0");
-        }
+        return false;
     }
-    /* value is an int */
-    else if ((fabs(((double)item->valueint) - d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN))
+
+    /* This is a nice tradeoff. */
+    output_pointer = ensure(output_buffer, 64, hooks);
+    if (output_pointer == NULL)
     {
-        if (p)
-        {
-            str = ensure(p, 21);
-        }
-        else
+        return false;
+    }
+
+    /* This checks for NaN and Infinity */
+    if ((d * 0) != 0)
+    {
+        length = sprintf((char*)output_pointer, "null");
+    }
+    else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60))
+    {
+        /* integer */
+        length = sprintf((char*)output_pointer, "%.0f", d);
+        trim_zeroes = false; /* don't remove zeroes for "big integers" */
+    }
+    else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9))
+    {
+        length = sprintf((char*)output_pointer, "%e", d);
+        trim_zeroes = false; /* don't remove zeroes in engineering notation */
+    }
+    else
+    {
+        length = sprintf((char*)output_pointer, "%f", d);
+    }
+
+    /* sprintf failed */
+    if (length < 0)
+    {
+        return false;
+    }
+
+    output_buffer->offset += (size_t)length;
+
+    if (trim_zeroes)
+    {
+        return trim_trailing_zeroes(output_buffer);
+    }
+
+    return true;
+}
+
+/* parse 4 digit hexadecimal number */
+static unsigned parse_hex4(const unsigned char * const input)
+{
+    unsigned int h = 0;
+    size_t i = 0;
+
+    for (i = 0; i < 4; i++)
+    {
+        /* parse digit */
+        if ((input[i] >= '0') && (input[i] <= '9'))
         {
-            /* 2^64+1 can be represented in 21 chars. */
-            str = (char*)cJSON_malloc(21);
+            h += (unsigned int) input[i] - '0';
         }
-        if (str)
+        else if ((input[i] >= 'A') && (input[i] <= 'F'))
         {
-            sprintf(str, "%d", item->valueint);
+            h += (unsigned int) 10 + input[i] - 'A';
         }
-    }
-    /* value is a floating point number */
-    else
-    {
-        if (p)
+        else if ((input[i] >= 'a') && (input[i] <= 'f'))
         {
-            /* This is a nice tradeoff. */
-            str = ensure(p, 64);
+            h += (unsigned int) 10 + input[i] - 'a';
         }
-        else
+        else /* invalid */
         {
-            /* This is a nice tradeoff. */
-            str=(char*)cJSON_malloc(64);
+            return 0;
         }
-        if (str)
+
+        if (i < 3)
         {
-            /* This checks for NaN and Infinity */
-            if ((d * 0) != 0)
-            {
-                sprintf(str, "null");
-            }
-            else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60))
-            {
-                sprintf(str, "%.0f", d);
-            }
-            else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9))
-            {
-                sprintf(str, "%e", d);
-            }
-            else
-            {
-                sprintf(str, "%f", d);
-            }
+            /* shift left to make place for the next nibble */
+            h = h << 4;
         }
     }
-    return str;
+
+    return h;
 }
 
-/* parse 4 digit hexadecimal number */
-static unsigned parse_hex4(const char *str)
+/* converts a UTF-16 literal to UTF-8
+ * A literal can be one or two sequences of the form \uXXXX */
+static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
 {
-    unsigned h = 0;
-    /* first digit */
-    if ((*str >= '0') && (*str <= '9'))
-    {
-        h += (*str) - '0';
-    }
-    else if ((*str >= 'A') && (*str <= 'F'))
-    {
-        h += 10 + (*str) - 'A';
-    }
-    else if ((*str >= 'a') && (*str <= 'f'))
-    {
-        h += 10 + (*str) - 'a';
-    }
-    else /* invalid */
+    long unsigned int codepoint = 0;
+    unsigned int first_code = 0;
+    const unsigned char *first_sequence = input_pointer;
+    unsigned char utf8_length = 0;
+    unsigned char utf8_position = 0;
+    unsigned char sequence_length = 0;
+    unsigned char first_byte_mark = 0;
+
+    if ((input_end - first_sequence) < 6)
     {
-        return 0;
+        /* input ends unexpectedly */
+        goto fail;
     }
 
+    /* get the first utf16 sequence */
+    first_code = parse_hex4(first_sequence + 2);
 
-    /* second digit */
-    h = h << 4;
-    str++;
-    if ((*str >= '0') && (*str <= '9'))
-    {
-        h += (*str) - '0';
-    }
-    else if ((*str >= 'A') && (*str <= 'F'))
+    /* check that the code is valid */
+    if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
     {
-        h += 10 + (*str) - 'A';
+        goto fail;
     }
-    else if ((*str >= 'a') && (*str <= 'f'))
+
+    /* UTF16 surrogate pair */
+    if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
     {
-        h += 10 + (*str) - 'a';
+        const unsigned char *second_sequence = first_sequence + 6;
+        unsigned int second_code = 0;
+        sequence_length = 12; /* \uXXXX\uXXXX */
+
+        if ((input_end - second_sequence) < 6)
+        {
+            /* input ends unexpectedly */
+            goto fail;
+        }
+
+        if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
+        {
+            /* missing second half of the surrogate pair */
+            goto fail;
+        }
+
+        /* get the second utf16 sequence */
+        second_code = parse_hex4(second_sequence + 2);
+        /* check that the code is valid */
+        if ((second_code < 0xDC00) || (second_code > 0xDFFF))
+        {
+            /* invalid second half of the surrogate pair */
+            goto fail;
+        }
+
+
+        /* calculate the unicode codepoint from the surrogate pair */
+        codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
     }
-    else /* invalid */
+    else
     {
-        return 0;
+        sequence_length = 6; /* \uXXXX */
+        codepoint = first_code;
     }
 
-    /* third digit */
-    h = h << 4;
-    str++;
-    if ((*str >= '0') && (*str <= '9'))
+    /* encode as UTF-8
+     * takes at maximum 4 bytes to encode:
+     * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+    if (codepoint < 0x80)
     {
-        h += (*str) - '0';
+        /* normal ascii, encoding 0xxxxxxx */
+        utf8_length = 1;
     }
-    else if ((*str >= 'A') && (*str <= 'F'))
+    else if (codepoint < 0x800)
     {
-        h += 10 + (*str) - 'A';
+        /* two bytes, encoding 110xxxxx 10xxxxxx */
+        utf8_length = 2;
+        first_byte_mark = 0xC0; /* 11000000 */
     }
-    else if ((*str >= 'a') && (*str <= 'f'))
+    else if (codepoint < 0x10000)
     {
-        h += 10 + (*str) - 'a';
+        /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
+        utf8_length = 3;
+        first_byte_mark = 0xE0; /* 11100000 */
     }
-    else /* invalid */
+    else if (codepoint <= 0x10FFFF)
     {
-        return 0;
+        /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
+        utf8_length = 4;
+        first_byte_mark = 0xF0; /* 11110000 */
     }
-
-    /* fourth digit */
-    h = h << 4;
-    str++;
-    if ((*str >= '0') && (*str <= '9'))
+    else
     {
-        h += (*str) - '0';
+        /* invalid unicode codepoint */
+        goto fail;
     }
-    else if ((*str >= 'A') && (*str <= 'F'))
+
+    /* encode as utf8 */
+    for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
     {
-        h += 10 + (*str) - 'A';
+        /* 10xxxxxx */
+        (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
+        codepoint >>= 6;
     }
-    else if ((*str >= 'a') && (*str <= 'f'))
+    /* encode first byte */
+    if (utf8_length > 1)
     {
-        h += 10 + (*str) - 'a';
+        (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
     }
-    else /* invalid */
+    else
     {
-        return 0;
+        (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
     }
 
-    return h;
-}
+    *output_pointer += utf8_length;
 
-/* first bytes of UTF8 encoding for a given length in bytes */
-static const unsigned char firstByteMark[7] =
-{
-    0x00, /* should never happen */
-    0x00, /* 0xxxxxxx */
-    0xC0, /* 110xxxxx */
-    0xE0, /* 1110xxxx */
-    0xF0, /* 11110xxx */
-    0xF8,
-    0xFC
-};
+    return sequence_length;
+
+fail:
+    return 0;
+}
 
-/* Parse the input text into an unescaped cstring, and populate item. */
-static const char *parse_string(cJSON *item, const char *str, const char **ep)
+/* Parse the input text into an unescaped cinput, and populate item. */
+static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer, const internal_hooks * const hooks)
 {
-    const char *ptr = str + 1;
-    const char *end_ptr =str + 1;
-    char *ptr2 = NULL;
-    char *out = NULL;
-    int len = 0;
-    unsigned uc = 0;
-    unsigned uc2 = 0;
+    const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
+    const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
+    unsigned char *output_pointer = NULL;
+    unsigned char *output = NULL;
 
-    /* not a string! */
-    if (*str != '\"')
+    /* not a string */
+    if (buffer_at_offset(input_buffer)[0] != '\"')
     {
-        *ep = str;
-        return NULL;
+        goto fail;
     }
 
-    while ((*end_ptr != '\"') && *end_ptr && ++len)
     {
-        if (*end_ptr++ == '\\')
+        /* calculate approximate size of the output (overestimate) */
+        size_t allocation_length = 0;
+        size_t skipped_bytes = 0;
+        while ((*input_end != '\"') && ((size_t)(input_end - input_buffer->content) < input_buffer->length))
         {
-            if (*end_ptr == '\0')
+            /* is escape sequence */
+            if (input_end[0] == '\\')
             {
-                /* prevent buffer overflow when last input character is a backslash */
-                return NULL;
+                if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
+                {
+                    /* prevent buffer overflow when last input character is a backslash */
+                    goto fail;
+                }
+                skipped_bytes++;
+                input_end++;
             }
-            /* Skip escaped quotes. */
-            end_ptr++;
+            input_end++;
+        }
+        if (*input_end != '\"')
+        {
+            goto fail; /* string ended unexpectedly */
         }
-    }
 
-    /* This is at most how long we need for the string, roughly. */
-    out = (char*)cJSON_malloc(len + 1);
-    if (!out)
-    {
-        return NULL;
+        /* This is at most how much we need for the output */
+        allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
+        output = (unsigned char*)hooks->allocate(allocation_length + sizeof(""));
+        if (output == NULL)
+        {
+            goto fail; /* allocation failure */
+        }
     }
-    item->valuestring = out; /* assign here so out will be deleted during cJSON_Delete() later */
-    item->type = cJSON_String;
 
-    ptr = str + 1;
-    ptr2 = out;
+    output_pointer = output;
     /* loop through the string literal */
-    while (ptr < end_ptr)
+    while (input_pointer < input_end)
     {
-        if (*ptr != '\\')
+        if (*input_pointer != '\\')
         {
-            *ptr2++ = *ptr++;
+            *output_pointer++ = *input_pointer++;
         }
         /* escape sequence */
         else
         {
-            ptr++;
-            switch (*ptr)
+            unsigned char sequence_length = 2;
+            if ((input_end - input_pointer) < 1)
+            {
+                goto fail;
+            }
+
+            switch (input_pointer[1])
             {
                 case 'b':
-                    *ptr2++ = '\b';
+                    *output_pointer++ = '\b';
                     break;
                 case 'f':
-                    *ptr2++ = '\f';
+                    *output_pointer++ = '\f';
                     break;
                 case 'n':
-                    *ptr2++ = '\n';
+                    *output_pointer++ = '\n';
                     break;
                 case 'r':
-                    *ptr2++ = '\r';
+                    *output_pointer++ = '\r';
                     break;
                 case 't':
-                    *ptr2++ = '\t';
+                    *output_pointer++ = '\t';
                     break;
                 case '\"':
                 case '\\':
                 case '/':
-                    *ptr2++ = *ptr;
+                    *output_pointer++ = input_pointer[1];
                     break;
-                case 'u':
-                    /* transcode utf16 to utf8. See RFC2781 and RFC3629. */
-                    uc = parse_hex4(ptr + 1); /* get the unicode char. */
-                    ptr += 4;
-                    if (ptr >= end_ptr)
-                    {
-                        /* invalid */
-                        *ep = str;
-                        return NULL;
-                    }
-                    /* check for invalid. */
-                    if (((uc >= 0xDC00) && (uc <= 0xDFFF)) || (uc == 0))
-                    {
-                        *ep = str;
-                        return NULL;
-                    }
-
-                    /* UTF16 surrogate pairs. */
-                    if ((uc >= 0xD800) && (uc<=0xDBFF))
-                    {
-                        if ((ptr + 6) > end_ptr)
-                        {
-                            /* invalid */
-                            *ep = str;
-                            return NULL;
-                        }
-                        if ((ptr[1] != '\\') || (ptr[2] != 'u'))
-                        {
-                            /* missing second-half of surrogate. */
-                            *ep = str;
-                            return NULL;
-                        }
-                        uc2 = parse_hex4(ptr + 3);
-                        ptr += 6; /* \uXXXX */
-                        if ((uc2 < 0xDC00) || (uc2 > 0xDFFF))
-                        {
-                            /* invalid second-half of surrogate. */
-                            *ep = str;
-                            return NULL;
-                        }
-                        /* calculate unicode codepoint from the surrogate pair */
-                        uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF));
-                    }
 
-                    /* encode as UTF8
-                     * takes at maximum 4 bytes to encode:
-                     * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
-                    len = 4;
-                    if (uc < 0x80)
-                    {
-                        /* normal ascii, encoding 0xxxxxxx */
-                        len = 1;
-                    }
-                    else if (uc < 0x800)
-                    {
-                        /* two bytes, encoding 110xxxxx 10xxxxxx */
-                        len = 2;
-                    }
-                    else if (uc < 0x10000)
+                /* UTF-16 literal */
+                case 'u':
+                    sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
+                    if (sequence_length == 0)
                     {
-                        /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
-                        len = 3;
+                        /* failed to convert UTF16-literal to UTF-8 */
+                        goto fail;
                     }
-                    ptr2 += len;
-
-                    switch (len) {
-                        case 4:
-                            /* 10xxxxxx */
-                            *--ptr2 = ((uc | 0x80) & 0xBF);
-                            uc >>= 6;
-                        case 3:
-                            /* 10xxxxxx */
-                            *--ptr2 = ((uc | 0x80) & 0xBF);
-                            uc >>= 6;
-                        case 2:
-                            /* 10xxxxxx */
-                            *--ptr2 = ((uc | 0x80) & 0xBF);
-                            uc >>= 6;
-                        case 1:
-                            /* depending on the length in bytes this determines the
-                             * encoding ofthe first UTF8 byte */
-                            *--ptr2 = (uc | firstByteMark[len]);
-                    }
-                    ptr2 += len;
                     break;
+
                 default:
-                    *ep = str;
-                    return NULL;
+                    goto fail;
             }
-            ptr++;
+            input_pointer += sequence_length;
         }
     }
-    *ptr2 = '\0';
-    if (*ptr == '\"')
+
+    /* zero terminate the output */
+    *output_pointer = '\0';
+
+    item->type = cJSON_String;
+    item->valuestring = (char*)output;
+
+    input_buffer->offset = (size_t) (input_end - input_buffer->content);
+    input_buffer->offset++;
+
+    return true;
+
+fail:
+    if (output != NULL)
+    {
+        hooks->deallocate(output);
+    }
+
+    if (input_pointer != NULL)
     {
-        ptr++;
+        input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
     }
 
-    return ptr;
+    return false;
 }
 
 /* Render the cstring provided to an escaped version that can be printed. */
-static char *print_string_ptr(const char *str, printbuffer *p)
+static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer, const internal_hooks * const hooks)
 {
-    const char *ptr = NULL;
-    char *ptr2 = NULL;
-    char *out = NULL;
-    int len = 0;
-    int flag = 0;
-    unsigned char token = '\0';
+    const unsigned char *input_pointer = NULL;
+    unsigned char *output = NULL;
+    unsigned char *output_pointer = NULL;
+    size_t output_length = 0;
+    /* numbers of additional characters needed for escaping */
+    size_t escape_characters = 0;
+
+    if (output_buffer == NULL)
+    {
+        return false;
+    }
 
     /* empty string */
-    if (!str)
+    if (input == NULL)
     {
-        if (p)
+        output = ensure(output_buffer, sizeof("\"\""), hooks);
+        if (output == NULL)
         {
-            out = ensure(p, 3);
+            return false;
         }
-        else
-        {
-            out = (char*)cJSON_malloc(3);
-        }
-        if (!out)
-        {
-            return NULL;
-        }
-        strcpy(out, "\"\"");
+        strcpy((char*)output, "\"\"");
 
-        return out;
+        return true;
     }
 
     /* set "flag" to 1 if something needs to be escaped */
-    for (ptr = str; *ptr; ptr++)
+    for (input_pointer = input; *input_pointer; input_pointer++)
+    {
+        switch (*input_pointer)
+        {
+            case '\"':
+            case '\\':
+            case '\b':
+            case '\f':
+            case '\n':
+            case '\r':
+            case '\t':
+                /* one character escape sequence */
+                escape_characters++;
+                break;
+            default:
+                if (*input_pointer < 32)
+                {
+                    /* UTF-16 escape sequence uXXXX */
+                    escape_characters += 5;
+                }
+                break;
+        }
+    }
+    output_length = (size_t)(input_pointer - input) + escape_characters;
+
+    output = ensure(output_buffer, output_length + sizeof("\"\""), hooks);
+    if (output == NULL)
     {
-        flag |= (((*ptr > 0) && (*ptr < 32)) /* unprintable characters */
-                || (*ptr == '\"') /* double quote */
-                || (*ptr == '\\')) /* backslash */
-            ? 1
-            : 0;
+        return false;
     }
+
     /* no characters have to be escaped */
-    if (!flag)
+    if (escape_characters == 0)
     {
-        len = ptr - str;
-        if (p)
-        {
-            out = ensure(p, len + 3);
-        }
-        else
-        {
-            out = (char*)cJSON_malloc(len + 3);
-        }
-        if (!out)
-        {
-            return NULL;
-        }
-
-        ptr2 = out;
-        *ptr2++ = '\"';
-        strcpy(ptr2, str);
-        ptr2[len] = '\"';
-        ptr2[len + 1] = '\0';
-
-        return out;
-    }
+        output[0] = '\"';
+        memcpy(output + 1, input, output_length);
+        output[output_length + 1] = '\"';
+        output[output_length + 2] = '\0';
 
-    ptr = str;
-    /* calculate additional space that is needed for escaping */
-    while ((token = *ptr) && ++len)
-    {
-        if (strchr("\"\\\b\f\n\r\t", token))
-        {
-            len++; /* +1 for the backslash */
-        }
-        else if (token < 32)
-        {
-            len += 5; /* +5 for \uXXXX */
-        }
-        ptr++;
+        return true;
     }
 
-    if (p)
-    {
-        out = ensure(p, len + 3);
-    }
-    else
-    {
-        out = (char*)cJSON_malloc(len + 3);
-    }
-    if (!out)
-    {
-        return NULL;
-    }
-
-    ptr2 = out;
-    ptr = str;
-    *ptr2++ = '\"';
+    output[0] = '\"';
+    output_pointer = output + 1;
     /* copy the string */
-    while (*ptr)
+    for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
     {
-        if (((unsigned char)*ptr > 31) && (*ptr != '\"') && (*ptr != '\\'))
+        if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
         {
             /* normal character, copy */
-            *ptr2++ = *ptr++;
+            *output_pointer = *input_pointer;
         }
         else
         {
             /* character needs to be escaped */
-            *ptr2++ = '\\';
-            switch (token = *ptr++)
+            *output_pointer++ = '\\';
+            switch (*input_pointer)
             {
                 case '\\':
-                    *ptr2++ = '\\';
+                    *output_pointer = '\\';
                     break;
                 case '\"':
-                    *ptr2++ = '\"';
+                    *output_pointer = '\"';
                     break;
                 case '\b':
-                    *ptr2++ = 'b';
+                    *output_pointer = 'b';
                     break;
                 case '\f':
-                    *ptr2++ = 'f';
+                    *output_pointer = 'f';
                     break;
                 case '\n':
-                    *ptr2++ = 'n';
+                    *output_pointer = 'n';
                     break;
                 case '\r':
-                    *ptr2++ = 'r';
+                    *output_pointer = 'r';
                     break;
                 case '\t':
-                    *ptr2++ = 't';
+                    *output_pointer = 't';
                     break;
                 default:
                     /* escape and print as unicode codepoint */
-                    sprintf(ptr2, "u%04x", token);
-                    ptr2 += 5;
+                    sprintf((char*)output_pointer, "u%04x", *input_pointer);
+                    output_pointer += 4;
                     break;
             }
         }
     }
-    *ptr2++ = '\"';
-    *ptr2++ = '\0';
+    output[output_length + 1] = '\"';
+    output[output_length + 2] = '\0';
 
-    return out;
+    return true;
 }
 
 /* Invoke print_string_ptr (which is useful) on an item. */
-static char *print_string(const cJSON *item, printbuffer *p)
+static cJSON_bool print_string(const cJSON * const item, printbuffer * const p, const internal_hooks * const hooks)
 {
-    return print_string_ptr(item->valuestring, p);
+    return print_string_ptr((unsigned char*)item->valuestring, p, hooks);
 }
 
 /* Predeclare these prototypes. */
-static const char *parse_value(cJSON *item, const char *value, const char **ep);
-static char *print_value(const cJSON *item, int depth, int fmt, printbuffer *p);
-static const char *parse_array(cJSON *item, const char *value, const char **ep);
-static char *print_array(const cJSON *item, int depth, int fmt, printbuffer *p);
-static const char *parse_object(cJSON *item, const char *value, const char **ep);
-static char *print_object(const cJSON *item, int depth, int fmt, printbuffer *p);
+static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer, const internal_hooks * const hooks);
+static cJSON_bool print_value(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks);
+static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer, const internal_hooks * const hooks);
+static cJSON_bool print_array(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks);
+static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer, const internal_hooks * const hooks);
+static cJSON_bool print_object(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks);
 
 /* Utility to jump whitespace and cr/lf */
-static const char *skip(const char *in)
+static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
 {
-    while (in && *in && ((unsigned char)*in<=32))
+    if ((buffer == NULL) || (buffer->content == NULL))
+    {
+        return NULL;
+    }
+
+    while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
     {
-        in++;
+       buffer->offset++;
     }
 
-    return in;
+    if (buffer->offset == buffer->length)
+    {
+        buffer->offset--;
+    }
+
+    return buffer;
 }
 
 /* Parse an object - create a new root, and populate. */
-cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated)
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
 {
-    const char *end = NULL;
-    /* use global error pointer if no specific one was given */
-    const char **ep = return_parse_end ? return_parse_end : &global_ep;
-    cJSON *c = cJSON_New_Item();
-    *ep = NULL;
-    if (!c) /* memory fail */
+    parse_buffer buffer = { 0, 0, 0 };
+    cJSON *item = NULL;
+
+    /* reset error position */
+    global_error.json = NULL;
+    global_error.position = 0;
+
+    if (value == NULL)
     {
-        return NULL;
+        goto fail;
     }
 
-    end = parse_value(c, skip(value), ep);
-    if (!end)
+    buffer.content = (const unsigned char*)value;
+    buffer.length = strlen((const char*)value) + sizeof("");
+    buffer.offset = 0;
+
+    item = cJSON_New_Item(&global_hooks);
+    if (item == NULL) /* memory fail */
+    {
+        goto fail;
+    }
+
+    if (!parse_value(item, buffer_skip_whitespace(&buffer), &global_hooks))
     {
         /* parse failure. ep is set. */
-        cJSON_Delete(c);
-        return NULL;
+        goto fail;
     }
 
     /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
     if (require_null_terminated)
     {
-        end = skip(end);
-        if (*end)
+        buffer_skip_whitespace(&buffer);
+        if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
         {
-            cJSON_Delete(c);
-            *ep = end;
-            return NULL;
+            goto fail;
         }
     }
     if (return_parse_end)
     {
-        *return_parse_end = end;
+        *return_parse_end = (const char*)buffer_at_offset(&buffer);
     }
 
-    return c;
+    return item;
+
+fail:
+    if (item != NULL)
+    {
+        cJSON_Delete(item);
+    }
+
+    if (value != NULL)
+    {
+        error local_error;
+        local_error.json = (const unsigned char*)value;
+        local_error.position = 0;
+
+        if (buffer.offset < buffer.length)
+        {
+            local_error.position = buffer.offset;
+        }
+        else if (buffer.length > 0)
+        {
+            local_error.position = buffer.length - 1;
+        }
+
+        if (return_parse_end != NULL)
+        {
+            *return_parse_end = (const char*)local_error.json + local_error.position;
+        }
+        else
+        {
+            global_error = local_error;
+        }
+    }
+
+    return NULL;
 }
 
 /* Default options for cJSON_Parse */
-cJSON *cJSON_Parse(const char *value)
+CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
 {
     return cJSON_ParseWithOpts(value, 0, 0);
 }
 
+#define cjson_min(a, b) ((a < b) ? a : b)
+
+static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
+{
+    printbuffer buffer[1];
+    unsigned char *printed = NULL;
+
+    memset(buffer, 0, sizeof(buffer));
+
+    /* create buffer */
+    buffer->buffer = (unsigned char*) hooks->allocate(256);
+    if (buffer->buffer == NULL)
+    {
+        goto fail;
+    }
+
+    /* print the value */
+    if (!print_value(item, 0, format, buffer, hooks))
+    {
+        goto fail;
+    }
+    update_offset(buffer);
+
+    /* check if reallocate is available */
+    if (hooks->reallocate != NULL)
+    {
+        printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->length);
+        buffer->buffer = NULL;
+        if (printed == NULL) {
+            goto fail;
+        }
+    }
+    else /* otherwise copy the JSON over to a new buffer */
+    {
+        printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
+        if (printed == NULL)
+        {
+            goto fail;
+        }
+        memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
+        printed[buffer->offset] = '\0'; /* just to be sure */
+
+        /* free the buffer */
+        hooks->deallocate(buffer->buffer);
+    }
+
+    return printed;
+
+fail:
+    if (buffer->buffer != NULL)
+    {
+        hooks->deallocate(buffer->buffer);
+    }
+
+    if (printed != NULL)
+    {
+        hooks->deallocate(printed);
+    }
+
+    return NULL;
+}
+
 /* Render a cJSON item/entity/structure to text. */
-char *cJSON_Print(const cJSON *item)
+CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
 {
-    return print_value(item, 0, 1, 0);
+    return (char*)print(item, true, &global_hooks);
 }
 
-char *cJSON_PrintUnformatted(const cJSON *item)
+CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
 {
-    return print_value(item, 0, 0, 0);
+    return (char*)print(item, false, &global_hooks);
 }
 
-char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, int fmt)
+CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
 {
     printbuffer p;
-    p.buffer = (char*)cJSON_malloc(prebuffer);
+
+    if (prebuffer < 0)
+    {
+        return NULL;
+    }
+
+    p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
     if (!p.buffer)
     {
         return NULL;
     }
-    p.length = prebuffer;
+
+    p.length = (size_t)prebuffer;
     p.offset = 0;
+    p.noalloc = false;
 
-    return print_value(item, 0, fmt, &p);
+    if (!print_value(item, 0, fmt, &p, &global_hooks))
+    {
+        return NULL;
+    }
+
+    return (char*)p.buffer;
 }
 
+CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt)
+{
+    printbuffer p;
+
+    if (len < 0)
+    {
+        return false;
+    }
+
+    p.buffer = (unsigned char*)buf;
+    p.length = (size_t)len;
+    p.offset = 0;
+    p.noalloc = true;
+    return print_value(item, 0, fmt, &p, &global_hooks);
+}
 
 /* Parser core - when encountering text, process appropriately. */
-static const char *parse_value(cJSON *item, const char *value, const char **ep)
+static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer, const internal_hooks * const hooks)
 {
-    if (!value)
+    if ((input_buffer == NULL) || (input_buffer->content == NULL))
     {
-        /* Fail on null. */
-        return NULL;
+        return false; /* no input */
     }
 
     /* parse the different types of values */
-    if (!strncmp(value, "null", 4))
+    /* null */
+    if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
     {
         item->type = cJSON_NULL;
-        return value + 4;
+        input_buffer->offset += 4;
+        return true;
     }
-    if (!strncmp(value, "false", 5))
+    /* false */
+    if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
     {
         item->type = cJSON_False;
-        return value + 5;
+        input_buffer->offset += 5;
+        return true;
     }
-    if (!strncmp(value, "true", 4))
+    /* true */
+    if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
     {
         item->type = cJSON_True;
         item->valueint = 1;
-        return value + 4;
+        input_buffer->offset += 4;
+        return true;
     }
-    if (*value == '\"')
+    /* string */
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
     {
-        return parse_string(item, value, ep);
+        return parse_string(item, input_buffer, hooks);
     }
-    if ((*value == '-') || ((*value >= '0') && (*value <= '9')))
+    /* number */
+    if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))
     {
-        return parse_number(item, value);
+        return parse_number(item, input_buffer);
     }
-    if (*value == '[')
+    /* array */
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
     {
-        return parse_array(item, value, ep);
+        return parse_array(item, input_buffer, hooks);
     }
-    if (*value == '{')
+    /* object */
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
     {
-        return parse_object(item, value, ep);
+        return parse_object(item, input_buffer, hooks);
     }
 
-    /* failure. */
-    *ep = value;
-    return NULL;
+
+    return false;
 }
 
 /* Render a value to text. */
-static char *print_value(const cJSON *item, int depth, int fmt, printbuffer *p)
+static cJSON_bool print_value(const cJSON * const item, const size_t depth, const cJSON_bool format,  printbuffer * const output_buffer, const internal_hooks * const hooks)
 {
-    char *out = NULL;
+    unsigned char *output = NULL;
 
-    if (!item)
+    if ((item == NULL) || (output_buffer == NULL))
     {
-        return NULL;
+        return false;
     }
-    if (p)
+
+    switch ((item->type) & 0xFF)
     {
-        switch ((item->type) & 0xFF)
+        case cJSON_NULL:
+            output = ensure(output_buffer, 5, hooks);
+            if (output == NULL)
+            {
+                return false;
+            }
+            strcpy((char*)output, "null");
+            return true;
+
+        case cJSON_False:
+            output = ensure(output_buffer, 6, hooks);
+            if (output == NULL)
+            {
+                return false;
+            }
+            strcpy((char*)output, "false");
+            return true;
+
+        case cJSON_True:
+            output = ensure(output_buffer, 5, hooks);
+            if (output == NULL)
+            {
+                return false;
+            }
+            strcpy((char*)output, "true");
+            return true;
+
+        case cJSON_Number:
+            return print_number(item, output_buffer, hooks);
+
+        case cJSON_Raw:
         {
-            case cJSON_NULL:
-                out = ensure(p, 5);
-                if (out)
-                {
-                    strcpy(out, "null");
-                }
-                break;
-            case cJSON_False:
-                out = ensure(p, 6);
-                if (out)
-                {
-                    strcpy(out, "false");
-                }
-                break;
-            case cJSON_True:
-                out = ensure(p, 5);
-                if (out)
+            size_t raw_length = 0;
+            if (item->valuestring == NULL)
+            {
+                if (!output_buffer->noalloc)
                 {
-                    strcpy(out, "true");
+                    hooks->deallocate(output_buffer->buffer);
                 }
-                break;
-            case cJSON_Number:
-                out = print_number(item, p);
-                break;
-            case cJSON_String:
-                out = print_string(item, p);
-                break;
-            case cJSON_Array:
-                out = print_array(item, depth, fmt, p);
-                break;
-            case cJSON_Object:
-                out = print_object(item, depth, fmt, p);
-                break;
-        }
-    }
-    else
-    {
-        switch ((item->type) & 0xFF)
-        {
-            case cJSON_NULL:
-                out = cJSON_strdup("null");
-                break;
-            case cJSON_False:
-                out = cJSON_strdup("false");
-                break;
-            case cJSON_True:
-                out = cJSON_strdup("true");
-                break;
-            case cJSON_Number:
-                out = print_number(item, 0);
-                break;
-            case cJSON_String:
-                out = print_string(item, 0);
-                break;
-            case cJSON_Array:
-                out = print_array(item, depth, fmt, 0);
-                break;
-            case cJSON_Object:
-                out = print_object(item, depth, fmt, 0);
-                break;
+                return false;
+            }
+
+            raw_length = strlen(item->valuestring) + sizeof("");
+            output = ensure(output_buffer, raw_length, hooks);
+            if (output == NULL)
+            {
+                return false;
+            }
+            memcpy(output, item->valuestring, raw_length);
+            return true;
         }
-    }
 
-    return out;
+        case cJSON_String:
+            return print_string(item, output_buffer, hooks);
+
+        case cJSON_Array:
+            return print_array(item, depth, format, output_buffer, hooks);
+
+        case cJSON_Object:
+            return print_object(item, depth, format, output_buffer, hooks);
+
+        default:
+            return false;
+    }
 }
 
 /* Build an array from input text. */
-static const char *parse_array(cJSON *item,const char *value,const char **ep)
+static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer, const internal_hooks * const hooks)
 {
-    cJSON *child = NULL;
-    if (*value != '[')
-    {
-        /* not an array! */
-        *ep = value;
-        return NULL;
-    }
+    cJSON *head = NULL; /* head of the linked list */
+    cJSON *current_item = NULL;
 
-    item->type = cJSON_Array;
-    value = skip(value + 1);
-    if (*value == ']')
+    if (buffer_at_offset(input_buffer)[0] != '[')
     {
-        /* empty array. */
-        return value + 1;
+        /* not an array */
+        goto fail;
     }
 
-    item->child = child = cJSON_New_Item();
-    if (!item->child)
+    input_buffer->offset++;
+    buffer_skip_whitespace(input_buffer);
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
     {
-        /* memory fail */
-        return NULL;
+        /* empty array */
+        goto success;
     }
-    /* skip any spacing, get the value. */
-    value = skip(parse_value(child, skip(value), ep));
-    if (!value)
+
+    /* check if we skipped to the end of the buffer */
+    if (cannot_access_at_index(input_buffer, 0))
     {
-        return NULL;
+        input_buffer->offset--;
+        goto fail;
     }
 
+    /* step back to character in front of the first element */
+    input_buffer->offset--;
     /* loop through the comma separated array elements */
-    while (*value == ',')
+    do
     {
-        cJSON *new_item = NULL;
-        if (!(new_item = cJSON_New_Item()))
+        /* allocate next item */
+        cJSON *new_item = cJSON_New_Item(hooks);
+        if (new_item == NULL)
         {
-            /* memory fail */
-            return NULL;
+            goto fail; /* allocation failure */
         }
-        /* add new item to end of the linked list */
-        child->next = new_item;
-        new_item->prev = child;
-        child = new_item;
 
-        /* go to the next comma */
-        value = skip(parse_value(child, skip(value + 1), ep));
-        if (!value)
+        /* attach next item to list */
+        if (head == NULL)
         {
-            /* memory fail */
-            return NULL;
+            /* start the linked list */
+            current_item = head = new_item;
+        }
+        else
+        {
+            /* add to the end and advance */
+            current_item->next = new_item;
+            new_item->prev = current_item;
+            current_item = new_item;
+        }
+
+        /* parse next value */
+        input_buffer->offset++;
+        buffer_skip_whitespace(input_buffer);
+        if (!parse_value(current_item, input_buffer, hooks))
+        {
+            goto fail; /* failed to parse value */
         }
+        buffer_skip_whitespace(input_buffer);
     }
+    while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
 
-    if (*value == ']')
+    if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
     {
-        /* end of array */
-        return value + 1;
+        goto fail; /* expected end of array */
     }
 
-    /* malformed. */
-    *ep = value;
+success:
+    item->type = cJSON_Array;
+    item->child = head;
 
-    return NULL;
+    input_buffer->offset++;
+
+    return true;
+
+fail:
+    if (head != NULL)
+    {
+        cJSON_Delete(head);
+    }
+
+    return false;
 }
 
 /* Render an array to text */
-static char *print_array(const cJSON *item, int depth, int fmt, printbuffer *p)
-{
-    char **entries;
-    char *out = NULL;
-    char *ptr = NULL;
-    char *ret = NULL;
-    int len = 5;
-    cJSON *child = item->child;
-    int numentries = 0;
-    int i = 0;
-    int fail = 0;
-    size_t tmplen = 0;
-
-    /* How many entries in the array? */
-    while (child)
-    {
-        numentries++;
-        child = child->next;
-    }
+static cJSON_bool print_array(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks)
+{
+    unsigned char *output_pointer = NULL;
+    size_t length = 0;
+    cJSON *current_element = item->child;
 
-    /* Explicitly handle numentries == 0 */
-    if (!numentries)
+    if (output_buffer == NULL)
     {
-        if (p)
-        {
-            out = ensure(p, 3);
-        }
-        else
-        {
-            out = (char*)cJSON_malloc(3);
-        }
-        if (out)
-        {
-            strcpy(out,"[]");
-        }
-
-        return out;
+        return false;
     }
 
-    if (p)
+    /* Compose the output array. */
+    /* opening square bracket */
+    output_pointer = ensure(output_buffer, 1, hooks);
+    if (output_pointer == NULL)
     {
-        /* Compose the output array. */
-        /* opening square bracket */
-        i = p->offset;
-        ptr = ensure(p, 1);
-        if (!ptr)
-        {
-            return NULL;
-        }
-        *ptr = '[';
-        p->offset++;
-
-        child = item->child;
-        while (child && !fail)
-        {
-            print_value(child, depth + 1, fmt, p);
-            p->offset = update(p);
-            if (child->next)
-            {
-                len = fmt ? 2 : 1;
-                ptr = ensure(p, len + 1);
-                if (!ptr)
-                {
-                    return NULL;
-                }
-                *ptr++ = ',';
-                if(fmt)
-                {
-                    *ptr++ = ' ';
-                }
-                *ptr = '\0';
-                p->offset += len;
-            }
-            child = child->next;
-        }
-        ptr = ensure(p, 2);
-        if (!ptr)
-        {
-            return NULL;
-        }
-        *ptr++ = ']';
-        *ptr = '\0';
-        out = (p->buffer) + i;
+        return false;
     }
-    else
-    {
-        /* Allocate an array to hold the pointers to all printed values */
-        entries = (char**)cJSON_malloc(numentries * sizeof(char*));
-        if (!entries)
-        {
-            return NULL;
-        }
-        memset(entries, '\0', numentries * sizeof(char*));
 
-        /* Retrieve all the results: */
-        child = item->child;
-        while (child && !fail)
-        {
-            ret = print_value(child, depth + 1, fmt, 0);
-            entries[i++] = ret;
-            if (ret)
-            {
-                len += strlen(ret) + 2 + (fmt ? 1 : 0);
-            }
-            else
-            {
-                fail = 1;
-            }
-            child = child->next;
-        }
+    *output_pointer = '[';
+    output_buffer->offset++;
 
-        /* If we didn't fail, try to malloc the output string */
-        if (!fail)
-        {
-            out = (char*)cJSON_malloc(len);
-        }
-        /* If that fails, we fail. */
-        if (!out)
+    while (current_element != NULL)
+    {
+        if (!print_value(current_element, depth + 1, format, output_buffer, hooks))
         {
-            fail = 1;
+            return false;
         }
-
-        /* Handle failure. */
-        if (fail)
+        update_offset(output_buffer);
+        if (current_element->next)
         {
-            /* free all the entries in the array */
-            for (i = 0; i < numentries; i++)
+            length = (size_t) (format ? 2 : 1);
+            output_pointer = ensure(output_buffer, length + 1, hooks);
+            if (output_pointer == NULL)
             {
-                if (entries[i])
-                {
-                    cJSON_free(entries[i]);
-                }
+                return false;
             }
-            cJSON_free(entries);
-            return NULL;
-        }
-
-        /* Compose the output array. */
-        *out='[';
-        ptr = out + 1;
-        *ptr = '\0';
-        for (i = 0; i < numentries; i++)
-        {
-            tmplen = strlen(entries[i]);
-            memcpy(ptr, entries[i], tmplen);
-            ptr += tmplen;
-            if (i != (numentries - 1))
+            *output_pointer++ = ',';
+            if(format)
             {
-                *ptr++ = ',';
-                if(fmt)
-                {
-                    *ptr++ = ' ';
-                }
-                *ptr = '\0';
+                *output_pointer++ = ' ';
             }
-            cJSON_free(entries[i]);
+            *output_pointer = '\0';
+            output_buffer->offset += length;
         }
-        cJSON_free(entries);
-        *ptr++ = ']';
-        *ptr++ = '\0';
+        current_element = current_element->next;
     }
 
-    return out;
+    output_pointer = ensure(output_buffer, 2, hooks);
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+    *output_pointer++ = ']';
+    *output_pointer = '\0';
+
+    return true;
 }
 
 /* Build an object from the text. */
-static const char *parse_object(cJSON *item, const char *value, const char **ep)
+static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer, const internal_hooks * const hooks)
 {
-    cJSON *child = NULL;
-    if (*value != '{')
-    {
-        /* not an object! */
-        *ep = value;
-        return NULL;
-    }
-
-    item->type = cJSON_Object;
-    value = skip(value + 1);
-    if (*value == '}')
-    {
-        /* empty object. */
-        return value + 1;
-    }
+    cJSON *head = NULL; /* linked list head */
+    cJSON *current_item = NULL;
 
-    child = cJSON_New_Item();
-    item->child = child;
-    if (!item->child)
+    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
     {
-        return NULL;
-    }
-    /* parse first key */
-    value = skip(parse_string(child, skip(value), ep));
-    if (!value)
-    {
-        return NULL;
+        goto fail; /* not an object */
     }
-    /* use string as key, not value */
-    child->string = child->valuestring;
-    child->valuestring = NULL;
 
-    if (*value != ':')
+    input_buffer->offset++;
+    buffer_skip_whitespace(input_buffer);
+    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
     {
-        /* invalid object. */
-        *ep = value;
-        return NULL;
-    }
-    /* skip any spacing, get the value. */
-    value = skip(parse_value(child, skip(value + 1), ep));
-    if (!value)
-    {
-        return NULL;
+        goto success; /* empty object */
     }
 
-    while (*value == ',')
-    {
-        cJSON *new_item = NULL;
-        if (!(new_item = cJSON_New_Item()))
-        {
-            /* memory fail */
-            return NULL;
-        }
-        /* add to linked list */
-        child->next = new_item;
-        new_item->prev = child;
-
-        child = new_item;
-        value = skip(parse_string(child, skip(value + 1), ep));
-        if (!value)
-        {
-            return NULL;
-        }
-
-        /* use string as key, not value */
-        child->string = child->valuestring;
-        child->valuestring = NULL;
-
-        if (*value != ':')
-        {
-            /* invalid object. */
-            *ep = value;
-            return NULL;
-        }
-        /* skip any spacing, get the value. */
-        value = skip(parse_value(child, skip(value + 1), ep));
-        if (!value)
-        {
-            return NULL;
-        }
-    }
-    /* end of object */
-    if (*value == '}')
+    /* check if we skipped to the end of the buffer */
+    if (cannot_access_at_index(input_buffer, 0))
     {
-        return value + 1;
+        input_buffer->offset--;
+        goto fail;
     }
 
-    /* malformed */
-    *ep = value;
-    return NULL;
-}
-
-/* Render an object to text. */
-static char *print_object(const cJSON *item, int depth, int fmt, printbuffer *p)
-{
-    char **entries = NULL;
-    char **names = NULL;
-    char *out = NULL;
-    char *ptr = NULL;
-    char *ret = NULL;
-    char *str = NULL;
-    int len = 7;
-    int i = 0;
-    int j = 0;
-    cJSON *child = item->child;
-    int numentries = 0;
-    int fail = 0;
-    size_t tmplen = 0;
-
-    /* Count the number of entries. */
-    while (child)
-    {
-        numentries++;
-        child = child->next;
-    }
-
-    /* Explicitly handle empty object case */
-    if (!numentries)
+    /* step back to character in front of the first element */
+    input_buffer->offset--;
+    /* loop through the comma separated array elements */
+    do
     {
-        if (p)
+        /* allocate next item */
+        cJSON *new_item = cJSON_New_Item(hooks);
+        if (new_item == NULL)
         {
-            out = ensure(p, fmt ? depth + 4 : 3);
+            goto fail; /* allocation failure */
         }
-        else
+
+        /* attach next item to list */
+        if (head == NULL)
         {
-            out = (char*)cJSON_malloc(fmt ? depth + 4 : 3);
+            /* start the linked list */
+            current_item = head = new_item;
         }
-        if (!out)
+        else
         {
-            return NULL;
+            /* add to the end and advance */
+            current_item->next = new_item;
+            new_item->prev = current_item;
+            current_item = new_item;
         }
-        ptr = out;
-        *ptr++ = '{';
-        if (fmt) {
-            *ptr++ = '\n';
-            for (i = 0; i < depth; i++)
-            {
-                *ptr++ = '\t';
-            }
+
+        /* parse the name of the child */
+        input_buffer->offset++;
+        buffer_skip_whitespace(input_buffer);
+        if (!parse_string(current_item, input_buffer, hooks))
+        {
+            goto fail; /* faile to parse name */
         }
-        *ptr++ = '}';
-        *ptr++ = '\0';
+        buffer_skip_whitespace(input_buffer);
 
-        return out;
-    }
+        /* swap valuestring and string, because we parsed the name */
+        current_item->string = current_item->valuestring;
+        current_item->valuestring = NULL;
 
-    if (p)
-    {
-        /* Compose the output: */
-        i = p->offset;
-        len = fmt ? 2 : 1; /* fmt: {\n */
-        ptr = ensure(p, len + 1);
-        if (!ptr)
+        if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
         {
-            return NULL;
+            goto fail; /* invalid object */
         }
 
-        *ptr++ = '{';
-        if (fmt)
+        /* parse the value */
+        input_buffer->offset++;
+        buffer_skip_whitespace(input_buffer);
+        if (!parse_value(current_item, input_buffer, hooks))
         {
-            *ptr++ = '\n';
+            goto fail; /* failed to parse value */
         }
-        *ptr = '\0';
-        p->offset += len;
+        buffer_skip_whitespace(input_buffer);
+    }
+    while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
 
-        child = item->child;
-        depth++;
-        while (child)
-        {
-            if (fmt)
-            {
-                ptr = ensure(p, depth);
-                if (!ptr)
-                {
-                    return NULL;
-                }
-                for (j = 0; j < depth; j++)
-                {
-                    *ptr++ = '\t';
-                }
-                p->offset += depth;
-            }
+    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
+    {
+        goto fail; /* expected end of object */
+    }
 
-            /* print key */
-            print_string_ptr(child->string, p);
-            p->offset = update(p);
+success:
+    item->type = cJSON_Object;
+    item->child = head;
 
-            len = fmt ? 2 : 1;
-            ptr = ensure(p, len);
-            if (!ptr)
-            {
-                return NULL;
-            }
-            *ptr++ = ':';
-            if (fmt)
-            {
-                *ptr++ = '\t';
-            }
-            p->offset+=len;
+    input_buffer->offset++;
+    return true;
 
-            /* print value */
-            print_value(child, depth, fmt, p);
-            p->offset = update(p);
+fail:
+    if (head != NULL)
+    {
+        cJSON_Delete(head);
+    }
 
-            /* print comma if not last */
-            len = (fmt ? 1 : 0) + (child->next ? 1 : 0);
-            ptr = ensure(p, len + 1);
-            if (!ptr)
-            {
-                return NULL;
-            }
-            if (child->next)
-            {
-                *ptr++ = ',';
-            }
+    return false;
+}
 
-            if (fmt)
-            {
-                *ptr++ = '\n';
-            }
-            *ptr = '\0';
-            p->offset += len;
+/* Render an object to text. */
+static cJSON_bool print_object(const cJSON * const item, const size_t depth, const cJSON_bool format, printbuffer * const output_buffer, const internal_hooks * const hooks)
+{
+    unsigned char *output_pointer = NULL;
+    size_t length = 0;
+    cJSON *current_item = item->child;
 
-            child = child->next;
-        }
+    if (output_buffer == NULL)
+    {
+        return false;
+    }
 
-        ptr = ensure(p, fmt ? (depth + 1) : 2);
-        if (!ptr)
-        {
-            return NULL;
-        }
-        if (fmt)
-        {
-            for (i = 0; i < (depth - 1); i++)
-            {
-                *ptr++ = '\t';
-            }
-        }
-        *ptr++ = '}';
-        *ptr = '\0';
-        out = (p->buffer) + i;
+    /* Compose the output: */
+    length = (size_t) (format ? 2 : 1); /* fmt: {\n */
+    output_pointer = ensure(output_buffer, length + 1, hooks);
+    if (output_pointer == NULL)
+    {
+        return false;
     }
-    else
+
+    *output_pointer++ = '{';
+    if (format)
     {
-        /* Allocate space for the names and the objects */
-        entries = (char**)cJSON_malloc(numentries * sizeof(char*));
-        if (!entries)
-        {
-            return NULL;
-        }
-        names = (char**)cJSON_malloc(numentries * sizeof(char*));
-        if (!names)
-        {
-            cJSON_free(entries);
-            return NULL;
-        }
-        memset(entries, '\0', sizeof(char*) * numentries);
-        memset(names, '\0', sizeof(char*) * numentries);
+        *output_pointer++ = '\n';
+    }
+    output_buffer->offset += length;
 
-        /* Collect all the results into our arrays: */
-        child = item->child;
-        depth++;
-        if (fmt)
-        {
-            len += depth;
-        }
-        while (child && !fail)
+    while (current_item)
+    {
+        if (format)
         {
-            names[i] = str = print_string_ptr(child->string, 0); /* print key */
-            entries[i++] = ret = print_value(child, depth, fmt, 0);
-            if (str && ret)
+            size_t i;
+            output_pointer = ensure(output_buffer, depth + 1, hooks);
+            if (output_pointer == NULL)
             {
-                len += strlen(ret) + strlen(str) + 2 + (fmt ? 2 + depth : 0);
+                return false;
             }
-            else
+            for (i = 0; i < depth + 1; i++)
             {
-                fail = 1;
+                *output_pointer++ = '\t';
             }
-            child = child->next;
+            output_buffer->offset += depth + 1;
+        }
+
+        /* print key */
+        if (!print_string_ptr((unsigned char*)current_item->string, output_buffer, hooks))
+        {
+            return false;
         }
+        update_offset(output_buffer);
 
-        /* Try to allocate the output string */
-        if (!fail)
+        length = (size_t) (format ? 2 : 1);
+        output_pointer = ensure(output_buffer, length, hooks);
+        if (output_pointer == NULL)
         {
-            out = (char*)cJSON_malloc(len);
+            return false;
         }
-        if (!out)
+        *output_pointer++ = ':';
+        if (format)
         {
-            fail = 1;
+            *output_pointer++ = '\t';
         }
+        output_buffer->offset += length;
 
-        /* Handle failure */
-        if (fail)
+        /* print value */
+        if (!print_value(current_item, depth + 1, format, output_buffer, hooks))
         {
-            /* free all the printed keys and values */
-            for (i = 0; i < numentries; i++)
-            {
-                if (names[i])
-                {
-                    cJSON_free(names[i]);
-                }
-                if (entries[i])
-                {
-                    cJSON_free(entries[i]);
-                }
-            }
-            cJSON_free(names);
-            cJSON_free(entries);
-            return NULL;
+            return false;
         }
+        update_offset(output_buffer);
 
-        /* Compose the output: */
-        *out = '{';
-        ptr = out + 1;
-        if (fmt)
+        /* print comma if not last */
+        length = (size_t) ((format ? 1 : 0) + (current_item->next ? 1 : 0));
+        output_pointer = ensure(output_buffer, length + 1, hooks);
+        if (output_pointer == NULL)
         {
-            *ptr++ = '\n';
+            return false;
         }
-        *ptr = '\0';
-        for (i = 0; i < numentries; i++)
+        if (current_item->next)
         {
-            if (fmt)
-            {
-                for (j = 0; j < depth; j++)
-                {
-                    *ptr++='\t';
-                }
-            }
-            tmplen = strlen(names[i]);
-            memcpy(ptr, names[i], tmplen);
-            ptr += tmplen;
-            *ptr++ = ':';
-            if (fmt)
-            {
-                *ptr++ = '\t';
-            }
-            strcpy(ptr, entries[i]);
-            ptr += strlen(entries[i]);
-            if (i != (numentries - 1))
-            {
-                *ptr++ = ',';
-            }
-            if (fmt)
-            {
-                *ptr++ = '\n';
-            }
-            *ptr = '\0';
-            cJSON_free(names[i]);
-            cJSON_free(entries[i]);
+            *output_pointer++ = ',';
         }
 
-        cJSON_free(names);
-        cJSON_free(entries);
-        if (fmt)
+        if (format)
         {
-            for (i = 0; i < (depth - 1); i++)
-            {
-                *ptr++ = '\t';
-            }
+            *output_pointer++ = '\n';
+        }
+        *output_pointer = '\0';
+        output_buffer->offset += length;
+
+        current_item = current_item->next;
+    }
+
+    output_pointer = ensure(output_buffer, format ? (depth + 2) : 2, hooks);
+    if (output_pointer == NULL)
+    {
+        return false;
+    }
+    if (format)
+    {
+        size_t i;
+        for (i = 0; i < (depth); i++)
+        {
+            *output_pointer++ = '\t';
         }
-        *ptr++ = '}';
-        *ptr++ = '\0';
     }
+    *output_pointer++ = '}';
+    *output_pointer = '\0';
 
-    return out;
+    return true;
 }
 
 /* Get Array size/item / object item. */
-int    cJSON_GetArraySize(const cJSON *array)
+CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
 {
     cJSON *c = array->child;
-    int i = 0;
+    size_t i = 0;
     while(c)
     {
         i++;
         c = c->next;
     }
-    return i;
+
+    /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
+
+    return (int)i;
 }
 
-cJSON *cJSON_GetArrayItem(const cJSON *array, int item)
+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int item)
 {
     cJSON *c = array ? array->child : NULL;
     while (c && item > 0)
@@ -1637,17 +1662,35 @@ cJSON *cJSON_GetArrayItem(const cJSON *array, int item)
     return c;
 }
 
-cJSON *cJSON_GetObjectItem(const cJSON *object, const char *string)
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON *object, const char *string)
 {
     cJSON *c = object ? object->child : NULL;
-    while (c && cJSON_strcasecmp(c->string, string))
+    while (c && cJSON_strcasecmp((unsigned char*)c->string, (const unsigned char*)string))
     {
         c = c->next;
     }
     return c;
 }
 
-int cJSON_HasObjectItem(const cJSON *object,const char *string)
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
+{
+    cJSON *current_element = NULL;
+
+    if ((object == NULL) || (string == NULL))
+    {
+        return NULL;
+    }
+
+    current_element = object->child;
+    while ((current_element != NULL) && (strcmp(string, current_element->string) != 0))
+    {
+        current_element = current_element->next;
+    }
+
+    return current_element;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
 {
     return cJSON_GetObjectItem(object, string) ? 1 : 0;
 }
@@ -1660,9 +1703,9 @@ static void suffix_object(cJSON *prev, cJSON *item)
 }
 
 /* Utility for handling references. */
-static cJSON *create_reference(const cJSON *item)
+static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
 {
-    cJSON *ref = cJSON_New_Item();
+    cJSON *ref = cJSON_New_Item(hooks);
     if (!ref)
     {
         return NULL;
@@ -1675,14 +1718,18 @@ static cJSON *create_reference(const cJSON *item)
 }
 
 /* Add item to array/object. */
-void   cJSON_AddItemToArray(cJSON *array, cJSON *item)
+CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item)
 {
-    cJSON *c = array->child;
-    if (!item)
+    cJSON *child = NULL;
+
+    if ((item == NULL) || (array == NULL))
     {
         return;
     }
-    if (!c)
+
+    child = array->child;
+
+    if (child == NULL)
     {
         /* list is empty, start new one */
         array->child = item;
@@ -1690,33 +1737,31 @@ void   cJSON_AddItemToArray(cJSON *array, cJSON *item)
     else
     {
         /* append to the end */
-        while (c->next)
+        while (child->next)
         {
-            c = c->next;
+            child = child->next;
         }
-        suffix_object(c, item);
+        suffix_object(child, item);
     }
 }
 
-void   cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
+CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
 {
-    if (!item)
-    {
-        return;
-    }
-
-    /* free old key and set new one */
-    if (item->string)
-    {
-        cJSON_free(item->string);
-    }
-    item->string = cJSON_strdup(string);
-
-    cJSON_AddItemToArray(object,item);
+    /* call cJSON_AddItemToObjectCS for code reuse */
+    cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string, &global_hooks), item);
+    /* remove cJSON_StringIsConst flag */
+    item->type &= ~cJSON_StringIsConst;
 }
 
+#if defined (__clang__) || ((__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+    #pragma GCC diagnostic push
+#endif
+#ifdef __GNUC__
+#pragma GCC diagnostic ignored "-Wcast-qual"
+#endif
+
 /* Add an item to an object with constant string as key */
-void   cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
+CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
 {
     if (!item)
     {
@@ -1724,24 +1769,27 @@ void   cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
     }
     if (!(item->type & cJSON_StringIsConst) && item->string)
     {
-        cJSON_free(item->string);
+        global_hooks.deallocate(item->string);
     }
     item->string = (char*)string;
     item->type |= cJSON_StringIsConst;
     cJSON_AddItemToArray(object, item);
 }
+#if defined (__clang__) || ((__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
+    #pragma GCC diagnostic pop
+#endif
 
-void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
+CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
 {
-    cJSON_AddItemToArray(array, create_reference(item));
+    cJSON_AddItemToArray(array, create_reference(item, &global_hooks));
 }
 
-void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
+CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
 {
-    cJSON_AddItemToObject(object, string, create_reference(item));
+    cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks));
 }
 
-cJSON *cJSON_DetachItemFromArray(cJSON *array, int which)
+static cJSON *DetachItemFromArray(cJSON *array, size_t which)
 {
     cJSON *c = array->child;
     while (c && (which > 0))
@@ -1772,36 +1820,45 @@ cJSON *cJSON_DetachItemFromArray(cJSON *array, int which)
 
     return c;
 }
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
+{
+    if (which < 0)
+    {
+        return NULL;
+    }
+
+    return DetachItemFromArray(array, (size_t)which);
+}
 
-void cJSON_DeleteItemFromArray(cJSON *array, int which)
+CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
 {
     cJSON_Delete(cJSON_DetachItemFromArray(array, which));
 }
 
-cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string)
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
 {
-    int i = 0;
+    size_t i = 0;
     cJSON *c = object->child;
-    while (c && cJSON_strcasecmp(c->string,string))
+    while (c && cJSON_strcasecmp((unsigned char*)c->string, (const unsigned char*)string))
     {
         i++;
         c = c->next;
     }
     if (c)
     {
-        return cJSON_DetachItemFromArray(object, i);
+        return DetachItemFromArray(object, i);
     }
 
     return NULL;
 }
 
-void cJSON_DeleteItemFromObject(cJSON *object, const char *string)
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
 {
     cJSON_Delete(cJSON_DetachItemFromObject(object, string));
 }
 
 /* Replace array/object items with new ones. */
-void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
+CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
 {
     cJSON *c = array->child;
     while (c && (which > 0))
@@ -1827,7 +1884,7 @@ void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
     }
 }
 
-void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
+static void ReplaceItemInArray(cJSON *array, size_t which, cJSON *newitem)
 {
     cJSON *c = array->child;
     while (c && (which > 0))
@@ -1856,12 +1913,21 @@ void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
     c->next = c->prev = NULL;
     cJSON_Delete(c);
 }
+CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
+{
+    if (which < 0)
+    {
+        return;
+    }
+
+    ReplaceItemInArray(array, (size_t)which, newitem);
+}
 
-void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
+CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
 {
-    int i = 0;
+    size_t i = 0;
     cJSON *c = object->child;
-    while(c && cJSON_strcasecmp(c->string, string))
+    while(c && cJSON_strcasecmp((unsigned char*)c->string, (const unsigned char*)string))
     {
         i++;
         c = c->next;
@@ -1871,18 +1937,18 @@ void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem
         /* free the old string if not const */
         if (!(newitem->type & cJSON_StringIsConst) && newitem->string)
         {
-             cJSON_free(newitem->string);
+             global_hooks.deallocate(newitem->string);
         }
 
-        newitem->string = cJSON_strdup(string);
-        cJSON_ReplaceItemInArray(object, i, newitem);
+        newitem->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
+        ReplaceItemInArray(object, i, newitem);
     }
 }
 
 /* Create basic types: */
-cJSON *cJSON_CreateNull(void)
+CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
 {
-    cJSON *item = cJSON_New_Item();
+    cJSON *item = cJSON_New_Item(&global_hooks);
     if(item)
     {
         item->type = cJSON_NULL;
@@ -1891,9 +1957,9 @@ cJSON *cJSON_CreateNull(void)
     return item;
 }
 
-cJSON *cJSON_CreateTrue(void)
+CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
 {
-    cJSON *item = cJSON_New_Item();
+    cJSON *item = cJSON_New_Item(&global_hooks);
     if(item)
     {
         item->type = cJSON_True;
@@ -1902,9 +1968,9 @@ cJSON *cJSON_CreateTrue(void)
     return item;
 }
 
-cJSON *cJSON_CreateFalse(void)
+CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
 {
-    cJSON *item = cJSON_New_Item();
+    cJSON *item = cJSON_New_Item(&global_hooks);
     if(item)
     {
         item->type = cJSON_False;
@@ -1913,9 +1979,9 @@ cJSON *cJSON_CreateFalse(void)
     return item;
 }
 
-cJSON *cJSON_CreateBool(int b)
+CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b)
 {
-    cJSON *item = cJSON_New_Item();
+    cJSON *item = cJSON_New_Item(&global_hooks);
     if(item)
     {
         item->type = b ? cJSON_True : cJSON_False;
@@ -1924,26 +1990,56 @@ cJSON *cJSON_CreateBool(int b)
     return item;
 }
 
-cJSON *cJSON_CreateNumber(double num)
+CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
 {
-    cJSON *item = cJSON_New_Item();
+    cJSON *item = cJSON_New_Item(&global_hooks);
     if(item)
     {
         item->type = cJSON_Number;
         item->valuedouble = num;
-        item->valueint = (int)num;
+
+        /* use saturation in case of overflow */
+        if (num >= INT_MAX)
+        {
+            item->valueint = INT_MAX;
+        }
+        else if (num <= INT_MIN)
+        {
+            item->valueint = INT_MIN;
+        }
+        else
+        {
+            item->valueint = (int)num;
+        }
     }
 
     return item;
 }
 
-cJSON *cJSON_CreateString(const char *string)
+CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
 {
-    cJSON *item = cJSON_New_Item();
+    cJSON *item = cJSON_New_Item(&global_hooks);
     if(item)
     {
         item->type = cJSON_String;
-        item->valuestring = cJSON_strdup(string);
+        item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
+        if(!item->valuestring)
+        {
+            cJSON_Delete(item);
+            return NULL;
+        }
+    }
+
+    return item;
+}
+
+CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
+{
+    cJSON *item = cJSON_New_Item(&global_hooks);
+    if(item)
+    {
+        item->type = cJSON_Raw;
+        item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
         if(!item->valuestring)
         {
             cJSON_Delete(item);
@@ -1954,9 +2050,9 @@ cJSON *cJSON_CreateString(const char *string)
     return item;
 }
 
-cJSON *cJSON_CreateArray(void)
+CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
 {
-    cJSON *item = cJSON_New_Item();
+    cJSON *item = cJSON_New_Item(&global_hooks);
     if(item)
     {
         item->type=cJSON_Array;
@@ -1965,9 +2061,9 @@ cJSON *cJSON_CreateArray(void)
     return item;
 }
 
-cJSON *cJSON_CreateObject(void)
+CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
 {
-    cJSON *item = cJSON_New_Item();
+    cJSON *item = cJSON_New_Item(&global_hooks);
     if (item)
     {
         item->type = cJSON_Object;
@@ -1977,13 +2073,20 @@ cJSON *cJSON_CreateObject(void)
 }
 
 /* Create Arrays: */
-cJSON *cJSON_CreateIntArray(const int *numbers, int count)
+CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
 {
-    int i = 0;
+    size_t i = 0;
     cJSON *n = NULL;
     cJSON *p = NULL;
-    cJSON *a = cJSON_CreateArray();
-    for(i = 0; a && (i < count); i++)
+    cJSON *a = NULL;
+
+    if (count < 0)
+    {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+    for(i = 0; a && (i < (size_t)count); i++)
     {
         n = cJSON_CreateNumber(numbers[i]);
         if (!n)
@@ -2005,15 +2108,23 @@ cJSON *cJSON_CreateIntArray(const int *numbers, int count)
     return a;
 }
 
-cJSON *cJSON_CreateFloatArray(const float *numbers, int count)
+CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
 {
-    int i = 0;
+    size_t i = 0;
     cJSON *n = NULL;
     cJSON *p = NULL;
-    cJSON *a = cJSON_CreateArray();
-    for(i = 0; a && (i < count); i++)
+    cJSON *a = NULL;
+
+    if (count < 0)
     {
-        n = cJSON_CreateNumber(numbers[i]);
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for(i = 0; a && (i < (size_t)count); i++)
+    {
+        n = cJSON_CreateNumber((double)numbers[i]);
         if(!n)
         {
             cJSON_Delete(a);
@@ -2033,13 +2144,21 @@ cJSON *cJSON_CreateFloatArray(const float *numbers, int count)
     return a;
 }
 
-cJSON *cJSON_CreateDoubleArray(const double *numbers, int count)
+CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
 {
-    int i = 0;
+    size_t i = 0;
     cJSON *n = NULL;
     cJSON *p = NULL;
-    cJSON *a = cJSON_CreateArray();
-    for(i = 0;a && (i < count); i++)
+    cJSON *a = NULL;
+
+    if (count < 0)
+    {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for(i = 0;a && (i < (size_t)count); i++)
     {
         n = cJSON_CreateNumber(numbers[i]);
         if(!n)
@@ -2061,13 +2180,21 @@ cJSON *cJSON_CreateDoubleArray(const double *numbers, int count)
     return a;
 }
 
-cJSON *cJSON_CreateStringArray(const char **strings, int count)
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count)
 {
-    int i = 0;
+    size_t i = 0;
     cJSON *n = NULL;
     cJSON *p = NULL;
-    cJSON *a = cJSON_CreateArray();
-    for (i = 0; a && (i < count); i++)
+    cJSON *a = NULL;
+
+    if (count < 0)
+    {
+        return NULL;
+    }
+
+    a = cJSON_CreateArray();
+
+    for (i = 0; a && (i < (size_t)count); i++)
     {
         n = cJSON_CreateString(strings[i]);
         if(!n)
@@ -2090,23 +2217,23 @@ cJSON *cJSON_CreateStringArray(const char **strings, int count)
 }
 
 /* Duplication */
-cJSON *cJSON_Duplicate(const cJSON *item, int recurse)
+CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
 {
     cJSON *newitem = NULL;
-    cJSON *cptr = NULL;
-    cJSON *nptr = NULL;
+    cJSON *child = NULL;
+    cJSON *next = NULL;
     cJSON *newchild = NULL;
 
     /* Bail on bad ptr */
     if (!item)
     {
-        return NULL;
+        goto fail;
     }
     /* Create new item */
-    newitem = cJSON_New_Item();
+    newitem = cJSON_New_Item(&global_hooks);
     if (!newitem)
     {
-        return NULL;
+        goto fail;
     }
     /* Copy over all vars */
     newitem->type = item->type & (~cJSON_IsReference);
@@ -2114,20 +2241,18 @@ cJSON *cJSON_Duplicate(const cJSON *item, int recurse)
     newitem->valuedouble = item->valuedouble;
     if (item->valuestring)
     {
-        newitem->valuestring = cJSON_strdup(item->valuestring);
+        newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
         if (!newitem->valuestring)
         {
-            cJSON_Delete(newitem);
-            return NULL;
+            goto fail;
         }
     }
     if (item->string)
     {
-        newitem->string = cJSON_strdup(item->string);
+        newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
         if (!newitem->string)
         {
-            cJSON_Delete(newitem);
-            return NULL;
+            goto fail;
         }
     }
     /* If non-recursive, then we're done! */
@@ -2136,36 +2261,44 @@ cJSON *cJSON_Duplicate(const cJSON *item, int recurse)
         return newitem;
     }
     /* Walk the ->next chain for the child. */
-    cptr = item->child;
-    while (cptr)
+    child = item->child;
+    while (child != NULL)
     {
-        newchild = cJSON_Duplicate(cptr, 1); /* Duplicate (with recurse) each item in the ->next chain */
+        newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
         if (!newchild)
         {
-            cJSON_Delete(newitem);
-            return NULL;
+            goto fail;
         }
-        if (nptr)
+        if (next != NULL)
         {
             /* If newitem->child already set, then crosswire ->prev and ->next and move on */
-            nptr->next = newchild;
-            newchild->prev = nptr;
-            nptr = newchild;
+            next->next = newchild;
+            newchild->prev = next;
+            next = newchild;
         }
         else
         {
             /* Set newitem->child and move to it */
-            newitem->child = newchild; nptr = newchild;
+            newitem->child = newchild;
+            next = newchild;
         }
-        cptr = cptr->next;
+        child = child->next;
     }
 
     return newitem;
+
+fail:
+    if (newitem != NULL)
+    {
+        cJSON_Delete(newitem);
+    }
+
+    return NULL;
 }
 
-void cJSON_Minify(char *json)
+CJSON_PUBLIC(void) cJSON_Minify(char *json)
 {
-    char *into = json;
+    unsigned char *into = (unsigned char*)json;
     while (*json)
     {
         if (*json == ' ')
@@ -2205,24 +2338,124 @@ void cJSON_Minify(char *json)
         else if (*json == '\"')
         {
             /* string literals, which are \" sensitive. */
-            *into++ = *json++;
+            *into++ = (unsigned char)*json++;
             while (*json && (*json != '\"'))
             {
                 if (*json == '\\')
                 {
-                    *into++=*json++;
+                    *into++ = (unsigned char)*json++;
                 }
-                *into++ = *json++;
+                *into++ = (unsigned char)*json++;
             }
-            *into++ = *json++;
+            *into++ = (unsigned char)*json++;
         }
         else
         {
             /* All other characters. */
-            *into++ = *json++;
+            *into++ = (unsigned char)*json++;
         }
     }
 
     /* and null-terminate. */
     *into = '\0';
 }
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Invalid;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_False;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xff) == cJSON_True;
+}
+
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & (cJSON_True | cJSON_False)) != 0;
+}
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_NULL;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Number;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_String;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Array;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Object;
+}
+
+CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
+{
+    if (item == NULL)
+    {
+        return false;
+    }
+
+    return (item->type & 0xFF) == cJSON_Raw;
+}
index dbbb739..56e6c60 100644 (file)
@@ -1,5 +1,5 @@
 /*
-  Copyright (c) 2009 Dave Gamble
+  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
 
   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal
@@ -28,9 +28,15 @@ extern "C"
 {
 #endif
 
+/* project version */
+#define CJSON_VERSION_MAJOR 1
+#define CJSON_VERSION_MINOR 4
+#define CJSON_VERSION_PATCH 5
+
 #include <stddef.h>
 
 /* cJSON Types: */
+#define cJSON_Invalid (0)
 #define cJSON_False  (1 << 0)
 #define cJSON_True   (1 << 1)
 #define cJSON_NULL   (1 << 2)
@@ -38,6 +44,7 @@ extern "C"
 #define cJSON_String (1 << 4)
 #define cJSON_Array  (1 << 5)
 #define cJSON_Object (1 << 6)
+#define cJSON_Raw    (1 << 7) /* raw json */
 
 #define cJSON_IsReference 256
 #define cJSON_StringIsConst 512
@@ -54,7 +61,7 @@ typedef struct cJSON
     /* The type of the item, as above. */
     int type;
 
-    /* The item's string, if type==cJSON_String */
+    /* The item's string, if type==cJSON_String  and type == cJSON_Raw */
     char *valuestring;
     /* The item's number, if type==cJSON_Number */
     int valueint;
@@ -71,77 +78,140 @@ typedef struct cJSON_Hooks
       void (*free_fn)(void *ptr);
 } cJSON_Hooks;
 
+typedef int cJSON_bool;
+
+#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32))
+#define __WINDOWS__
+#endif
+#ifdef __WINDOWS__
+
+/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention.  For windows you have 2 define options:
+
+CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols
+CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols
+
+For *nix builds that support visibility attribute, you can define similar behavior by 
+
+setting default visibility to hidden by adding
+-fvisibility=hidden (for gcc)
+or
+-xldscope=hidden (for sun cc)
+to CFLAGS
+
+then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does
+
+*/
+
+#if defined(CJSON_HIDE_SYMBOLS)
+#define CJSON_PUBLIC(type)   type __stdcall
+#elif defined(CJSON_EXPORT_SYMBOLS)
+#define CJSON_PUBLIC(type)   __declspec(dllexport) type __stdcall
+#else
+#define CJSON_PUBLIC(type)   __declspec(dllimport) type __stdcall
+#endif
+#else /* !WIN32 */
+#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY)
+#define CJSON_PUBLIC(type)   __attribute__((visibility("default"))) type
+#else
+#define CJSON_PUBLIC(type) type
+#endif
+#endif
+
+/* returns the version of cJSON as a string */
+CJSON_PUBLIC(const char*) cJSON_Version(void);
+
 /* Supply malloc, realloc and free functions to cJSON */
-extern void cJSON_InitHooks(cJSON_Hooks* hooks);
+CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks);
 
 
 /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
-extern cJSON *cJSON_Parse(const char *value);
+CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
 /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
-extern char  *cJSON_Print(const cJSON *item);
+CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);
 /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
-extern char  *cJSON_PrintUnformatted(const cJSON *item);
+CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);
 /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
-extern char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, int fmt);
+CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
+/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */
+/* NOTE: If you are printing numbers, the buffer hat to be 63 bytes bigger then the printed JSON (worst case) */
+CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
 /* Delete a cJSON entity and all subentities. */
-extern void   cJSON_Delete(cJSON *c);
+CJSON_PUBLIC(void) cJSON_Delete(cJSON *c);
 
 /* Returns the number of items in an array (or object). */
-extern int       cJSON_GetArraySize(const cJSON *array);
+CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);
 /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
-extern cJSON *cJSON_GetArrayItem(const cJSON *array, int item);
+CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int item);
 /* Get item "string" from object. Case insensitive. */
-extern cJSON *cJSON_GetObjectItem(const cJSON *object, const char *string);
-extern int cJSON_HasObjectItem(const cJSON *object, const char *string);
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON *object, const char *string);
+CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string);
+CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string);
 /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
-extern const char *cJSON_GetErrorPtr(void);
+CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void);
+
+/* These functions check the type of an item */
+CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
+CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);
 
 /* These calls create a cJSON item of the appropriate type. */
-extern cJSON *cJSON_CreateNull(void);
-extern cJSON *cJSON_CreateTrue(void);
-extern cJSON *cJSON_CreateFalse(void);
-extern cJSON *cJSON_CreateBool(int b);
-extern cJSON *cJSON_CreateNumber(double num);
-extern cJSON *cJSON_CreateString(const char *string);
-extern cJSON *cJSON_CreateArray(void);
-extern cJSON *cJSON_CreateObject(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
+CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
+CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
+/* raw json */
+CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
+CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
+CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
 
 /* These utilities create an Array of count items. */
-extern cJSON *cJSON_CreateIntArray(const int *numbers, int count);
-extern cJSON *cJSON_CreateFloatArray(const float *numbers, int count);
-extern cJSON *cJSON_CreateDoubleArray(const double *numbers, int count);
-extern cJSON *cJSON_CreateStringArray(const char **strings, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
+CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);
 
 /* Append item to the specified array/object. */
-extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
-extern void    cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
-extern void    cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);        /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
+CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item);
+CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);
+/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object.
+ * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before
+ * writing to `item->string` */
+CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item);
 /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
-extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
-extern void    cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
+CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item);
 
 /* Remove/Detatch items from Arrays/Objects. */
-extern cJSON *cJSON_DetachItemFromArray(cJSON *array, int which);
-extern void   cJSON_DeleteItemFromArray(cJSON *array, int which);
-extern cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string);
-extern void   cJSON_DeleteItemFromObject(cJSON *object, const char *string);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which);
+CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string);
+CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string);
 
 /* Update array items. */
-extern void cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
-extern void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
-extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
+CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */
+CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
+CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
 
 /* Duplicate a cJSON item */
-extern cJSON *cJSON_Duplicate(const cJSON *item, int recurse);
+CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse);
 /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
 need to be released. With recurse!=0, it will duplicate any children connected to the item.
 The item->next and ->prev pointers are always zero on return from Duplicate. */
 
 /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
 /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */
-extern cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated);
+CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
 
-extern void cJSON_Minify(char *json);
+CJSON_PUBLIC(void) cJSON_Minify(char *json);
 
 /* Macros for creating things quickly. */
 #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull())
@@ -150,13 +220,16 @@ extern void cJSON_Minify(char *json);
 #define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
 #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
 #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
+#define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s))
 
 /* When assigning an integer value, it needs to be propagated to valuedouble too. */
-#define cJSON_SetIntValue(object,val) ((object) ? (object)->valueint = (object)->valuedouble = (val) : (val))
-#define cJSON_SetNumberValue(object,val) ((object) ? (object)->valueint = (object)->valuedouble = (val) : (val))
+#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number))
+/* helper for the cJSON_SetNumberValue macro */
+CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number);
+#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number))
 
 /* Macro for iterating over an array */
-#define cJSON_ArrayForEach(pos, head) for(pos = (head)->child; pos != NULL; pos = pos->next)
+#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next)
 
 #ifdef __cplusplus
 }
index a4cd300..8c0289a 100644 (file)
@@ -50,7 +50,9 @@ tools_env.PrependUnique(CPPPATH = ['#/extlibs/cjson',
 tools_env.AppendUnique(CXXFLAGS = ['-O2', '-g', '-Wall', '-Wextra', '-std=c++0x'])
 tools_env.AppendUnique(RPATH = [tools_env.get('BUILD_DIR')])
 
-SConscript('#/extlibs/cjson/SConscript')
+if target_os in ['windows', 'msys_nt']:
+    # Macro needed for Windows builds to avoid __declspec(dllexport) and __declspec(dllimport) for cJSON APIs.
+    tools_env.AppendUnique(CPPDEFINES = ['CJSON_HIDE_SYMBOLS'])
 
 if target_os in ['msys_nt', 'windows']:
     # octbstack.dll doesn't export all the functions called by this app, so use static LIBs instead.
index d1407b8..65419f6 100644 (file)
@@ -54,7 +54,6 @@ if with_upstream_libcoap == '1':
     env.AppendUnique(CPPPATH = ['#extlibs/libcoap/libcoap/include'])
 else:
     env.AppendUnique(CPPPATH = ['#resource/csdk/connectivity/lib/libcoap-4.1.1/include'])
-SConscript('#/extlibs/cjson/SConscript')
 
 local_env.PrependUnique(LIBS = ['cjson', 'oc', 'octbstack', 'oc_logger', 'connectivity_abstraction', 'coap'])
 if target_os not in ['windows']:
index 1cee926..59ff637 100755 (executable)
@@ -24,7 +24,6 @@ lib_env = env.Clone()
 SConscript('#service/third_party_libs.scons', 'lib_env')
 raml_env = lib_env.Clone()
 
-SConscript('#/extlibs/cjson/SConscript')
 SConscript('#/extlibs/yaml/SConscript')
 ######################################################################
 # Build flags