diff --git a/Makefile b/Makefile index 244e48fd..a9a56895 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,9 @@ UTILS_LIBNAME = libcjson_utils CJSON_TEST = cJSON_test UTILS_TEST = cJSON_test_utils +CJSON_TEST_SRC = cJSON.c test.c +UTILS_TEST_SRC = cJSON.c cJSON_Utils.c test_utils.c + LDLIBS = -lm LIBVERSION = 1.0.2 @@ -27,7 +30,7 @@ uname := $(shell sh -c 'uname -s 2>/dev/null || echo false') #library file extensions SHARED = so STATIC = a - + ## create dynamic (shared) library on Darwin (base OS for MacOSX and IOS) ifeq (Darwin, $(uname)) SHARED = dylib @@ -66,11 +69,11 @@ test: tests #tests #cJSON -$(CJSON_TEST): cJSON.c cJSON.h test.c - $(CC) $(R_CFLAGS) $^ -o $@ $(LDLIBS) -I. +$(CJSON_TEST): $(CJSON_TEST_SRC) cJSON.h + $(CC) $(R_CFLAGS) $(CJSON_TEST_SRC) -o $@ $(LDLIBS) -I. #cJSON_Utils -$(UTILS_TEST): cJSON.c cJSON.h test.c - $(CC) $(R_CFLAGS) $^ -o $@ $(LDLIBS) -I. +$(UTILS_TEST): $(UTILS_TEST_SRC) cJSON.h cJSON_Utils.h + $(CC) $(R_CFLAGS) $(UTILS_TEST_SRC) -o $@ $(LDLIBS) -I. #static libraries #cJSON diff --git a/cJSON.c b/cJSON.c index ded3c880..4e303847 100644 --- a/cJSON.c +++ b/cJSON.c @@ -244,6 +244,7 @@ typedef struct char *buffer; int length; int offset; + cjbool noalloc; } printbuffer; /* realloc printbuffer if necessary to have at least "needed" bytes more */ @@ -261,6 +262,10 @@ static char* ensure(printbuffer *p, int needed) return p->buffer + p->offset; } + if (p->noalloc) { + return NULL; + } + newsize = pow2gt(needed); newbuffer = (char*)cJSON_malloc(newsize); if (!newbuffer) @@ -883,10 +888,20 @@ char *cJSON_PrintBuffered(const cJSON *item, int prebuffer, cjbool fmt) } p.length = prebuffer; p.offset = 0; + p.noalloc = false; return print_value(item, 0, fmt, &p); } +int cJSON_PrintPreallocated(cJSON *item,char *buf, const int len, const cjbool fmt) +{ + printbuffer p; + p.buffer = buf; + p.length = len; + p.offset = 0; + p.noalloc = true; + return print_value(item,0,fmt,&p) != NULL; +} /* Parser core - when encountering text, process appropriately. */ static const char *parse_value(cJSON *item, const char *value, const char **ep) @@ -1138,7 +1153,10 @@ static char *print_array(const cJSON *item, int depth, cjbool fmt, printbuffer * child = item->child; while (child && !fail) { - print_value(child, depth + 1, fmt, p); + if (!print_value(child, depth + 1, fmt, p)) + { + return NULL; + } p->offset = update(p); if (child->next) { @@ -1435,7 +1453,10 @@ static char *print_object(const cJSON *item, int depth, cjbool fmt, printbuffer } /* print key */ - print_string_ptr(child->string, p); + if (!print_string_ptr(child->string, p)) + { + return NULL; + } p->offset = update(p); len = fmt ? 2 : 1; @@ -1452,7 +1473,10 @@ static char *print_object(const cJSON *item, int depth, cjbool fmt, printbuffer p->offset+=len; /* print value */ - print_value(child, depth, fmt, p); + if (!print_value(child, depth, fmt, p)) + { + return NULL; + }; p->offset = update(p); /* print comma if not last */ diff --git a/cJSON.h b/cJSON.h index dbbb739f..4d015c33 100644 --- a/cJSON.h +++ b/cJSON.h @@ -83,6 +83,8 @@ extern char *cJSON_Print(const cJSON *item); extern 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); +/* Render a cJSON entity to text using a buffer already allocated in memory with length buf_len */ +extern int cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const int fmt); /* Delete a cJSON entity and all subentities. */ extern void cJSON_Delete(cJSON *c); diff --git a/test.c b/test.c index e079d0a2..9b91ed5d 100644 --- a/test.c +++ b/test.c @@ -22,6 +22,7 @@ #include #include +#include #include "cJSON.h" /* Parse text to JSON, then render back to text, and print! */ @@ -83,6 +84,63 @@ struct record const char *country; }; + +/* Create a bunch of objects as demonstration. */ +int print_preallocated(cJSON *root) +{ + /* declarations */ + char *out = NULL; + char *buf = NULL; + char *buf_fail = NULL; + int len = 0; + int len_fail = 0; + + /* formatted print */ + out = cJSON_Print(root); + + /* create buffer to succeed */ + /* the extra 64 bytes are in case a floating point value is printed */ + len = strlen(out) + 64; + buf = malloc(len); + + /* create buffer to fail */ + len_fail = strlen(out); + buf_fail = malloc(len_fail); + + /* Print to buffer */ + if (cJSON_PrintPreallocated(root, buf, len, 1) != 0) { + printf("cJSON_PrintPreallocated failed!\n"); + if (strcmp(out, buf) != 0) { + printf("cJSON_PrintPreallocated not the same as cJSON_Print!\n"); + printf("cJSON_Print result:\n%s\n", out); + printf("cJSON_PrintPreallocated result:\n%s\n", buf); + } + free(out); + free(buf_fail); + free(buf); + return -1; + } + + /* success */ + printf("%s\n", buf); + + /* force it to fail */ + if (cJSON_PrintPreallocated(root, buf_fail, len_fail, 1) == 0) { + printf("cJSON_PrintPreallocated failed to show error with insufficient memory!\n"); + printf("cJSON_Print result:\n%s\n", out); + printf("cJSON_PrintPreallocated result:\n%s\n", buf_fail); + free(out); + free(buf_fail); + free(buf); + return -1; + } + + free(out); + free(buf_fail); + free(buf); + return 0; +} + /* Create a bunch of objects as demonstration. */ static void create_objects(void) { @@ -92,7 +150,6 @@ static void create_objects(void) cJSON *img = NULL; cJSON *thm = NULL; cJSON *fld = NULL; - char *out = NULL; int i = 0; /* Our "days of the week" array: */ @@ -154,21 +211,20 @@ static void create_objects(void) cJSON_AddNumberToObject(fmt, "frame rate", 24); /* Print to text */ - out = cJSON_Print(root); - /* Delete the cJSON */ + if (print_preallocated(root) != 0) { + cJSON_Delete(root); + exit(EXIT_FAILURE); + } cJSON_Delete(root); - /* print it */ - printf("%s\n",out); - /* release the string */ - free(out); /* Our "days of the week" array: */ root = cJSON_CreateStringArray(strings, 7); - out = cJSON_Print(root); + if (print_preallocated(root) != 0) { + cJSON_Delete(root); + exit(EXIT_FAILURE); + } cJSON_Delete(root); - printf("%s\n", out); - free(out); /* Our matrix: */ root = cJSON_CreateArray(); @@ -179,11 +235,11 @@ static void create_objects(void) /* cJSON_ReplaceItemInArray(root, 1, cJSON_CreateString("Replacement")); */ - out = cJSON_Print(root); + if (print_preallocated(root) != 0) { + cJSON_Delete(root); + exit(EXIT_FAILURE); + } cJSON_Delete(root); - printf("%s\n", out); - free(out); - /* Our "gallery" item: */ root = cJSON_CreateObject(); @@ -197,13 +253,13 @@ static void create_objects(void) cJSON_AddStringToObject(thm, "Width", "100"); cJSON_AddItemToObject(img, "IDs", cJSON_CreateIntArray(ids, 4)); - out = cJSON_Print(root); + if (print_preallocated(root) != 0) { + cJSON_Delete(root); + exit(EXIT_FAILURE); + } cJSON_Delete(root); - printf("%s\n", out); - free(out); /* Our array of "records": */ - root = cJSON_CreateArray(); for (i = 0; i < 2; i++) { @@ -220,17 +276,20 @@ static void create_objects(void) /* cJSON_ReplaceItemInObject(cJSON_GetArrayItem(root, 1), "City", cJSON_CreateIntArray(ids, 4)); */ - out = cJSON_Print(root); + if (print_preallocated(root) != 0) { + cJSON_Delete(root); + exit(EXIT_FAILURE); + } cJSON_Delete(root); - printf("%s\n", out); - free(out); root = cJSON_CreateObject(); cJSON_AddNumberToObject(root, "number", 1.0 / zero); - out = cJSON_Print(root); + + if (print_preallocated(root) != 0) { + cJSON_Delete(root); + exit(EXIT_FAILURE); + } cJSON_Delete(root); - printf("%s\n", out); - free(out); } int main(void)