|
@@ -124,9 +124,10 @@ typedef struct internal_configuration
|
|
cJSON_bool format;
|
|
cJSON_bool format;
|
|
cJSON_bool allow_data_after_json;
|
|
cJSON_bool allow_data_after_json;
|
|
cJSON_bool case_sensitive;
|
|
cJSON_bool case_sensitive;
|
|
- void *(*allocate)(size_t size);
|
|
|
|
- void (*deallocate)(void *pointer);
|
|
|
|
- void *(*reallocate)(void *pointer, size_t size);
|
|
|
|
|
|
+ cJSON_Allocators allocators;
|
|
|
|
+ void *userdata;
|
|
|
|
+
|
|
|
|
+
|
|
} internal_configuration;
|
|
} internal_configuration;
|
|
|
|
|
|
#if defined(_MSC_VER)
|
|
#if defined(_MSC_VER)
|
|
@@ -139,24 +140,45 @@ static void internal_free(void *pointer)
|
|
{
|
|
{
|
|
free(pointer);
|
|
free(pointer);
|
|
}
|
|
}
|
|
-static void *internal_realloc(void *pointer, size_t size)
|
|
|
|
-{
|
|
|
|
- return realloc(pointer, size);
|
|
|
|
-}
|
|
|
|
#else
|
|
#else
|
|
#define internal_malloc malloc
|
|
#define internal_malloc malloc
|
|
#define internal_free free
|
|
#define internal_free free
|
|
-#define internal_realloc realloc
|
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+/* old style allocators for cJSON_InitHooks */
|
|
|
|
+static cJSON_Hooks global_allocators = {
|
|
|
|
+ internal_malloc,
|
|
|
|
+ internal_free
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/* wrappers around global old style allocators */
|
|
|
|
+static void *global_allocate_wrapper(size_t size, void *userdata)
|
|
|
|
+{
|
|
|
|
+ (void)userdata;
|
|
|
|
+ return global_allocators.malloc_fn(size);
|
|
|
|
+}
|
|
|
|
+static void *global_reallocate_wrapper(void *pointer, size_t size, void *userdata)
|
|
|
|
+{
|
|
|
|
+ (void)userdata;
|
|
|
|
+ return realloc(pointer, size);
|
|
|
|
+}
|
|
|
|
+static void global_deallocate_wrapper(void *pointer, void *userdata)
|
|
|
|
+{
|
|
|
|
+ (void)userdata;
|
|
|
|
+ global_allocators.free_fn(pointer);
|
|
|
|
+}
|
|
|
|
+
|
|
#define default_configuration {\
|
|
#define default_configuration {\
|
|
256, /* default buffer size */\
|
|
256, /* default buffer size */\
|
|
true, /* enable formatting by default */\
|
|
true, /* enable formatting by default */\
|
|
true, /* allow data after the JSON by default */\
|
|
true, /* allow data after the JSON by default */\
|
|
true, /* case sensitive by default */\
|
|
true, /* case sensitive by default */\
|
|
- internal_malloc,\
|
|
|
|
- internal_free,\
|
|
|
|
- internal_realloc\
|
|
|
|
|
|
+ {\
|
|
|
|
+ global_allocate_wrapper,\
|
|
|
|
+ global_deallocate_wrapper,\
|
|
|
|
+ global_reallocate_wrapper\
|
|
|
|
+ },\
|
|
|
|
+ NULL /* no userdata */\
|
|
}
|
|
}
|
|
|
|
|
|
static internal_configuration global_configuration = default_configuration;
|
|
static internal_configuration global_configuration = default_configuration;
|
|
@@ -172,7 +194,7 @@ static unsigned char* custom_strdup(const unsigned char* string, const internal_
|
|
}
|
|
}
|
|
|
|
|
|
length = strlen((const char*)string) + sizeof("");
|
|
length = strlen((const char*)string) + sizeof("");
|
|
- copy = (unsigned char*)configuration->allocate(length);
|
|
|
|
|
|
+ copy = (unsigned char*)configuration->allocators.allocate(length, configuration->userdata);
|
|
if (copy == NULL)
|
|
if (copy == NULL)
|
|
{
|
|
{
|
|
return NULL;
|
|
return NULL;
|
|
@@ -184,39 +206,45 @@ static unsigned char* custom_strdup(const unsigned char* string, const internal_
|
|
|
|
|
|
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
|
|
CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
|
|
{
|
|
{
|
|
|
|
+ /* set the wrappers in the global configuration */
|
|
|
|
+ global_configuration.userdata = NULL;
|
|
|
|
+ global_configuration.allocators.allocate = global_allocate_wrapper;
|
|
|
|
+ global_configuration.allocators.deallocate = global_deallocate_wrapper;
|
|
|
|
+ global_configuration.allocators.reallocate = global_reallocate_wrapper;
|
|
|
|
+
|
|
if (hooks == NULL)
|
|
if (hooks == NULL)
|
|
{
|
|
{
|
|
- /* Reset hooks */
|
|
|
|
- global_configuration.allocate = malloc;
|
|
|
|
- global_configuration.deallocate = free;
|
|
|
|
- global_configuration.reallocate = realloc;
|
|
|
|
|
|
+ /* reset global allocators */
|
|
|
|
+ global_allocators.malloc_fn = internal_malloc;
|
|
|
|
+ global_allocators.free_fn = internal_free;
|
|
|
|
+
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
- global_configuration.allocate = malloc;
|
|
|
|
|
|
+ global_allocators.malloc_fn = internal_malloc;
|
|
if (hooks->malloc_fn != NULL)
|
|
if (hooks->malloc_fn != NULL)
|
|
{
|
|
{
|
|
- global_configuration.allocate = hooks->malloc_fn;
|
|
|
|
|
|
+ global_allocators.malloc_fn = hooks->malloc_fn;
|
|
}
|
|
}
|
|
|
|
|
|
- global_configuration.deallocate = free;
|
|
|
|
|
|
+ global_allocators.free_fn = internal_free;
|
|
if (hooks->free_fn != NULL)
|
|
if (hooks->free_fn != NULL)
|
|
{
|
|
{
|
|
- global_configuration.deallocate = hooks->free_fn;
|
|
|
|
|
|
+ global_allocators.free_fn = hooks->free_fn;
|
|
}
|
|
}
|
|
|
|
|
|
/* use realloc only if both free and malloc are used */
|
|
/* use realloc only if both free and malloc are used */
|
|
- global_configuration.reallocate = NULL;
|
|
|
|
- if ((global_configuration.allocate == malloc) && (global_configuration.deallocate == free))
|
|
|
|
|
|
+ global_configuration.allocators.reallocate = NULL;
|
|
|
|
+ if ((hooks->malloc_fn == malloc) && (hooks->free_fn == free))
|
|
{
|
|
{
|
|
- global_configuration.reallocate = realloc;
|
|
|
|
|
|
+ global_configuration.allocators.reallocate = global_reallocate_wrapper;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/* Internal constructor. */
|
|
/* Internal constructor. */
|
|
static cJSON *create_item(const internal_configuration * const configuration)
|
|
static cJSON *create_item(const internal_configuration * const configuration)
|
|
{
|
|
{
|
|
- cJSON* node = (cJSON*)configuration->allocate(sizeof(cJSON));
|
|
|
|
|
|
+ cJSON* node = (cJSON*)configuration->allocators.allocate(sizeof(cJSON), configuration->userdata);
|
|
if (node)
|
|
if (node)
|
|
{
|
|
{
|
|
memset(node, '\0', sizeof(cJSON));
|
|
memset(node, '\0', sizeof(cJSON));
|
|
@@ -238,13 +266,13 @@ static void delete_item(cJSON *item, const internal_configuration * const config
|
|
}
|
|
}
|
|
if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
|
|
if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
|
|
{
|
|
{
|
|
- configuration->deallocate(item->valuestring);
|
|
|
|
|
|
+ configuration->allocators.deallocate(item->valuestring, configuration->userdata);
|
|
}
|
|
}
|
|
if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
|
|
if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
|
|
{
|
|
{
|
|
- configuration->deallocate(item->string);
|
|
|
|
|
|
+ configuration->allocators.deallocate(item->string, configuration->userdata);
|
|
}
|
|
}
|
|
- configuration->deallocate(item);
|
|
|
|
|
|
+ configuration->allocators.deallocate(item, configuration->userdata);
|
|
item = next;
|
|
item = next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -429,13 +457,13 @@ static unsigned char* ensure(printbuffer * const p, size_t needed)
|
|
newsize = needed * 2;
|
|
newsize = needed * 2;
|
|
}
|
|
}
|
|
|
|
|
|
- if (p->configuration.reallocate != NULL)
|
|
|
|
|
|
+ if (*p->configuration.allocators.reallocate != NULL)
|
|
{
|
|
{
|
|
/* reallocate with realloc if available */
|
|
/* reallocate with realloc if available */
|
|
- newbuffer = (unsigned char*)p->configuration.reallocate(p->buffer, newsize);
|
|
|
|
|
|
+ newbuffer = (unsigned char*)p->configuration.allocators.reallocate(p->buffer, newsize, p->configuration.userdata);
|
|
if (newbuffer == NULL)
|
|
if (newbuffer == NULL)
|
|
{
|
|
{
|
|
- p->configuration.deallocate(p->buffer);
|
|
|
|
|
|
+ p->configuration.allocators.deallocate(p->buffer, p->configuration.userdata);
|
|
p->length = 0;
|
|
p->length = 0;
|
|
p->buffer = NULL;
|
|
p->buffer = NULL;
|
|
|
|
|
|
@@ -445,10 +473,10 @@ static unsigned char* ensure(printbuffer * const p, size_t needed)
|
|
else
|
|
else
|
|
{
|
|
{
|
|
/* otherwise reallocate manually */
|
|
/* otherwise reallocate manually */
|
|
- newbuffer = (unsigned char*)p->configuration.allocate(newsize);
|
|
|
|
|
|
+ newbuffer = (unsigned char*)p->configuration.allocators.allocate(newsize, p->configuration.userdata);
|
|
if (!newbuffer)
|
|
if (!newbuffer)
|
|
{
|
|
{
|
|
- p->configuration.deallocate(p->buffer);
|
|
|
|
|
|
+ p->configuration.allocators.deallocate(p->buffer, p->configuration.userdata);
|
|
p->length = 0;
|
|
p->length = 0;
|
|
p->buffer = NULL;
|
|
p->buffer = NULL;
|
|
|
|
|
|
@@ -458,7 +486,7 @@ static unsigned char* ensure(printbuffer * const p, size_t needed)
|
|
{
|
|
{
|
|
memcpy(newbuffer, p->buffer, p->offset + 1);
|
|
memcpy(newbuffer, p->buffer, p->offset + 1);
|
|
}
|
|
}
|
|
- p->configuration.deallocate(p->buffer);
|
|
|
|
|
|
+ p->configuration.allocators.deallocate(p->buffer, p->configuration.userdata);
|
|
}
|
|
}
|
|
p->length = newsize;
|
|
p->length = newsize;
|
|
p->buffer = newbuffer;
|
|
p->buffer = newbuffer;
|
|
@@ -750,7 +778,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu
|
|
|
|
|
|
/* This is at most how much we need for the output */
|
|
/* This is at most how much we need for the output */
|
|
allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
|
|
allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
|
|
- output = (unsigned char*)input_buffer->configuration.allocate(allocation_length + sizeof(""));
|
|
|
|
|
|
+ output = (unsigned char*)input_buffer->configuration.allocators.allocate(allocation_length + sizeof(""), input_buffer->configuration.userdata);
|
|
if (output == NULL)
|
|
if (output == NULL)
|
|
{
|
|
{
|
|
goto fail; /* allocation failure */
|
|
goto fail; /* allocation failure */
|
|
@@ -828,7 +856,7 @@ static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_bu
|
|
fail:
|
|
fail:
|
|
if (output != NULL)
|
|
if (output != NULL)
|
|
{
|
|
{
|
|
- input_buffer->configuration.deallocate(output);
|
|
|
|
|
|
+ input_buffer->configuration.allocators.deallocate(output, input_buffer->configuration.userdata);
|
|
}
|
|
}
|
|
|
|
|
|
if (input_pointer != NULL)
|
|
if (input_pointer != NULL)
|
|
@@ -1119,7 +1147,7 @@ static unsigned char *print(const cJSON * const item, const internal_configurati
|
|
memset(buffer, 0, sizeof(buffer));
|
|
memset(buffer, 0, sizeof(buffer));
|
|
|
|
|
|
/* create buffer */
|
|
/* create buffer */
|
|
- buffer->buffer = (unsigned char*) configuration->allocate(configuration->buffer_size);
|
|
|
|
|
|
+ buffer->buffer = (unsigned char*)configuration->allocators.allocate(configuration->buffer_size, configuration->userdata);
|
|
buffer->length = configuration->buffer_size;
|
|
buffer->length = configuration->buffer_size;
|
|
buffer->configuration = *configuration;
|
|
buffer->configuration = *configuration;
|
|
if (buffer->buffer == NULL)
|
|
if (buffer->buffer == NULL)
|
|
@@ -1137,9 +1165,9 @@ static unsigned char *print(const cJSON * const item, const internal_configurati
|
|
/* Reallocate the buffer so that it only uses as much as it needs.
|
|
/* Reallocate the buffer so that it only uses as much as it needs.
|
|
This can save up to 50% because ensure increases the buffer size by a factor of 2 */
|
|
This can save up to 50% because ensure increases the buffer size by a factor of 2 */
|
|
/* check if reallocate is available */
|
|
/* check if reallocate is available */
|
|
- if (configuration->reallocate != NULL)
|
|
|
|
|
|
+ if (configuration->allocators.reallocate != NULL)
|
|
{
|
|
{
|
|
- printed = (unsigned char*) configuration->reallocate(buffer->buffer, buffer->offset + 1);
|
|
|
|
|
|
+ printed = (unsigned char*)configuration->allocators.reallocate(buffer->buffer, buffer->offset + 1, configuration->userdata);
|
|
buffer->buffer = NULL;
|
|
buffer->buffer = NULL;
|
|
if (printed == NULL) {
|
|
if (printed == NULL) {
|
|
goto fail;
|
|
goto fail;
|
|
@@ -1147,7 +1175,7 @@ static unsigned char *print(const cJSON * const item, const internal_configurati
|
|
}
|
|
}
|
|
else /* otherwise copy the JSON over to a new buffer */
|
|
else /* otherwise copy the JSON over to a new buffer */
|
|
{
|
|
{
|
|
- printed = (unsigned char*) configuration->allocate(buffer->offset + 1);
|
|
|
|
|
|
+ printed = (unsigned char*)configuration->allocators.allocate(buffer->offset + 1, configuration->userdata);
|
|
if (printed == NULL)
|
|
if (printed == NULL)
|
|
{
|
|
{
|
|
goto fail;
|
|
goto fail;
|
|
@@ -1156,7 +1184,7 @@ static unsigned char *print(const cJSON * const item, const internal_configurati
|
|
printed[buffer->offset] = '\0'; /* just to be sure */
|
|
printed[buffer->offset] = '\0'; /* just to be sure */
|
|
|
|
|
|
/* free the buffer */
|
|
/* free the buffer */
|
|
- configuration->deallocate(buffer->buffer);
|
|
|
|
|
|
+ configuration->allocators.deallocate(buffer->buffer, configuration->userdata);
|
|
}
|
|
}
|
|
|
|
|
|
return printed;
|
|
return printed;
|
|
@@ -1164,12 +1192,12 @@ static unsigned char *print(const cJSON * const item, const internal_configurati
|
|
fail:
|
|
fail:
|
|
if (buffer->buffer != NULL)
|
|
if (buffer->buffer != NULL)
|
|
{
|
|
{
|
|
- configuration->deallocate(buffer->buffer);
|
|
|
|
|
|
+ configuration->allocators.deallocate(buffer->buffer, configuration->userdata);
|
|
}
|
|
}
|
|
|
|
|
|
if (printed != NULL)
|
|
if (printed != NULL)
|
|
{
|
|
{
|
|
- configuration->deallocate(printed);
|
|
|
|
|
|
+ configuration->allocators.deallocate(printed, configuration->userdata);
|
|
}
|
|
}
|
|
|
|
|
|
return NULL;
|
|
return NULL;
|
|
@@ -1205,7 +1233,7 @@ CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON
|
|
|
|
|
|
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)
|
|
CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)
|
|
{
|
|
{
|
|
- printbuffer p = { 0, 0, 0, 0, 0, default_configuration};
|
|
|
|
|
|
+ printbuffer p = { 0, 0, 0, 0, 0, default_configuration };
|
|
|
|
|
|
if ((length < 0) || (buffer == NULL))
|
|
if ((length < 0) || (buffer == NULL))
|
|
{
|
|
{
|
|
@@ -1350,7 +1378,7 @@ static cJSON_bool print_value(const cJSON * const item, printbuffer * const outp
|
|
{
|
|
{
|
|
if (!output_buffer->noalloc)
|
|
if (!output_buffer->noalloc)
|
|
{
|
|
{
|
|
- output_buffer->configuration.deallocate(output_buffer->buffer);
|
|
|
|
|
|
+ output_buffer->configuration.allocators.deallocate(output_buffer->buffer, output_buffer->configuration.userdata);
|
|
}
|
|
}
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
@@ -1958,7 +1986,7 @@ static cJSON_bool add_item_to_object(cJSON * const object, const char * const st
|
|
|
|
|
|
if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
|
|
if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
|
|
{
|
|
{
|
|
- configuration->deallocate(item->string);
|
|
|
|
|
|
+ configuration->allocators.deallocate(item->string, configuration->userdata);
|
|
}
|
|
}
|
|
|
|
|
|
if (constant_key)
|
|
if (constant_key)
|
|
@@ -2965,10 +2993,10 @@ CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * cons
|
|
|
|
|
|
CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
|
|
CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
|
|
{
|
|
{
|
|
- return global_configuration.allocate(size);
|
|
|
|
|
|
+ return global_configuration.allocators.allocate(size, global_configuration.userdata);
|
|
}
|
|
}
|
|
|
|
|
|
CJSON_PUBLIC(void) cJSON_free(void *object)
|
|
CJSON_PUBLIC(void) cJSON_free(void *object)
|
|
{
|
|
{
|
|
- global_configuration.deallocate(object);
|
|
|
|
|
|
+ global_configuration.allocators.deallocate(object, global_configuration.userdata);
|
|
}
|
|
}
|