1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528 |
- /*
- Copyright (c) 2009 Dave Gamble
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"), to deal
- in the Software without restriction, including without limitation the rights
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- copies of the Software, and to permit persons to whom the Software is
- furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included in
- all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- THE SOFTWARE.
- */
- /* cJSON */
- /* JSON parser in C. */
- #include <string.h>
- #include <stdio.h>
- #include <math.h>
- #include <stdlib.h>
- #include <float.h>
- #include <limits.h>
- #include <ctype.h>
- #include "cJSON.h"
- static const char *ep;
- const char *cJSON_GetErrorPtr(void)
- {
- return ep;
- }
- static int cJSON_strcasecmp(const char *s1, const char *s2)
- {
- if (!s1) {
- return (s1 == s2) ? 0 : 1;
- }
- if (!s2) {
- return 1;
- }
- for (; tolower(*s1) == tolower(*s2); ++s1, ++s2) if (*s1 == 0) {
- return 0;
- }
- return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
- }
- static void *(*cJSON_malloc)(size_t sz) = malloc;
- static void (*cJSON_free)(void *ptr) = free;
- static char *cJSON_strdup(const char *str)
- {
- size_t len;
- char *copy;
- len = strlen(str) + 1;
- if (!(copy = (char *)cJSON_malloc(len))) {
- return 0;
- }
- memcpy(copy, str, len);
- return copy;
- }
- void cJSON_InitHooks(cJSON_Hooks *hooks)
- {
- if (!hooks) { /* Reset hooks */
- cJSON_malloc = malloc;
- cJSON_free = free;
- return;
- }
- cJSON_malloc = (hooks->malloc_fn) ? hooks->malloc_fn : malloc;
- cJSON_free = (hooks->free_fn) ? hooks->free_fn : free;
- }
- /* Internal constructor. */
- static cJSON *cJSON_New_Item(void)
- {
- cJSON *node = (cJSON *)cJSON_malloc(sizeof(cJSON));
- if (node) {
- memset(node, 0, sizeof(cJSON));
- }
- return node;
- }
- /* Delete a cJSON structure. */
- void cJSON_Delete(cJSON *c)
- {
- cJSON *next;
- while (c) {
- next = c->next;
- if (!(c->type & cJSON_IsReference) && c->child) {
- cJSON_Delete(c->child);
- }
- if (!(c->type & cJSON_IsReference) && c->valuestring) {
- cJSON_free(c->valuestring);
- }
- if (!(c->type & cJSON_StringIsConst) && c->string) {
- cJSON_free(c->string);
- }
- cJSON_free(c);
- c = next;
- }
- }
- /* Parse the input text to generate a number, and populate the result into item. */
- static const char *parse_number(cJSON *item, const char *num)
- {
- double n = 0, sign = 1, scale = 0;
- int subscale = 0, signsubscale = 1;
- if (*num == '-') {
- sign = -1, num++; /* Has sign? */
- }
- if (*num == '0') {
- num++; /* is zero */
- }
- if (*num >= '1' && *num <= '9') do {
- n = (n * 10.0) + (*num++ -'0');
- } while (*num >= '0' && *num <= '9'); /* Number? */
- if (*num == '.' && num[1] >= '0' && num[1] <= '9') {
- num++; /* Fractional part? */
- do {
- n = (n * 10.0) + (*num++ -'0'), scale--;
- } while (*num >= '0' && *num <= '9');
- }
- if (*num == 'e' || *num == 'E') { /* Exponent? */
- num++;
- if (*num == '+') {
- num++;
- } else if (*num == '-') {
- signsubscale = -1, num++; /* With sign? */
- }
- while (*num >= '0' && *num <= '9') {
- subscale = (subscale * 10) + (*num++ - '0'); /* Number? */
- }
- }
- n = sign * n * pow(10.0, (scale + subscale * signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
- item->valuedouble = n;
- item->valueint = (int)n;
- item->type = cJSON_Number;
- return num;
- }
- static int pow2gt(int x)
- {
- --x;
- x |= x >> 1;
- x |= x >> 2;
- x |= x >> 4;
- x |= x >> 8;
- x |= x >> 16;
- return x + 1;
- }
- typedef struct {
- char *buffer;
- int length;
- int offset;
- } printbuffer;
- static char *ensure(printbuffer *p, int needed)
- {
- char *newbuffer;
- int newsize;
- if (!p || !p->buffer) {
- return 0;
- }
- needed += p->offset;
- if (needed <= p->length) {
- return p->buffer + p->offset;
- }
- newsize = pow2gt(needed);
- newbuffer = (char *)cJSON_malloc(newsize);
- if (!newbuffer) {
- cJSON_free(p->buffer);
- p->length = 0, p->buffer = 0;
- return 0;
- }
- if (newbuffer) {
- memcpy(newbuffer, p->buffer, p->length);
- }
- cJSON_free(p->buffer);
- p->length = newsize;
- p->buffer = newbuffer;
- return newbuffer + p->offset;
- }
- static int update(printbuffer *p)
- {
- char *str;
- if (!p || !p->buffer) {
- return 0;
- }
- str = p->buffer + p->offset;
- return p->offset + strlen(str);
- }
- /* Render the number nicely from the given item into a string. */
- static char *print_number(cJSON *item, printbuffer *p)
- {
- char *str = 0;
- double d = item->valuedouble;
- if (d == 0) {
- if (p) {
- str = ensure(p, 2);
- } else {
- str = (char *)cJSON_malloc(2); /* special case for 0. */
- }
- if (str) {
- strcpy(str, "0");
- }
- } else if (fabs(((double)item->valueint) - d) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN) {
- if (p) {
- str = ensure(p, 21);
- } else {
- str = (char *)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */
- }
- if (str) {
- sprintf(str, "%d", item->valueint);
- }
- } else {
- if (p) {
- str = ensure(p, 64);
- } else {
- str = (char *)cJSON_malloc(64); /* This is a nice tradeoff. */
- }
- if (str) {
- 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);
- }
- }
- }
- return str;
- }
- static unsigned parse_hex4(const char *str)
- {
- unsigned h = 0;
- 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 {
- return 0;
- }
- h = h << 4;
- str++;
- 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 {
- return 0;
- }
- h = h << 4;
- str++;
- 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 {
- return 0;
- }
- h = h << 4;
- str++;
- 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 {
- return 0;
- }
- return h;
- }
- /* Parse the input text into an unescaped cstring, and populate item. */
- static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
- static const char *parse_string(cJSON *item, const char *str)
- {
- const char *ptr = str + 1;
- char *ptr2;
- char *out;
- int len = 0;
- unsigned uc, uc2;
- if (*str != '\"') {
- ep = str; /* not a string! */
- return 0;
- }
- while (*ptr != '\"' && *ptr && ++len) if (*ptr++ == '\\') {
- ptr++; /* Skip escaped quotes. */
- }
- out = (char *)cJSON_malloc(len + 1); /* This is how long we need for the string, roughly. */
- if (!out) {
- return 0;
- }
- ptr = str + 1;
- ptr2 = out;
- while (*ptr != '\"' && *ptr) {
- if (*ptr != '\\') {
- *ptr2++ = *ptr++;
- } else {
- ptr++;
- switch (*ptr) {
- case 'b':
- *ptr2++ = '\b';
- break;
- case 'f':
- *ptr2++ = '\f';
- break;
- case 'n':
- *ptr2++ = '\n';
- break;
- case 'r':
- *ptr2++ = '\r';
- break;
- case 't':
- *ptr2++ = '\t';
- break;
- case 'u': /* transcode utf16 to utf8. */
- uc = parse_hex4(ptr + 1);
- ptr += 4; /* get the unicode char. */
- if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0) {
- break; /* check for invalid. */
- }
- if (uc >= 0xD800 && uc <= 0xDBFF) { /* UTF16 surrogate pairs. */
- if (ptr[1] != '\\' || ptr[2] != 'u') {
- break; /* missing second-half of surrogate. */
- }
- uc2 = parse_hex4(ptr + 3);
- ptr += 6;
- if (uc2 < 0xDC00 || uc2 > 0xDFFF) {
- break; /* invalid second-half of surrogate. */
- }
- uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF));
- }
- len = 4;
- if (uc < 0x80) {
- len = 1;
- } else if (uc < 0x800) {
- len = 2;
- } else if (uc < 0x10000) {
- len = 3;
- }
- ptr2 += len;
- switch (len) {
- case 4:
- *--ptr2 = ((uc | 0x80) & 0xBF);
- uc >>= 6;
- case 3:
- *--ptr2 = ((uc | 0x80) & 0xBF);
- uc >>= 6;
- case 2:
- *--ptr2 = ((uc | 0x80) & 0xBF);
- uc >>= 6;
- case 1:
- *--ptr2 = (uc | firstByteMark[len]);
- }
- ptr2 += len;
- break;
- default:
- *ptr2++ = *ptr;
- break;
- }
- ptr++;
- }
- }
- *ptr2 = 0;
- if (*ptr == '\"') {
- ptr++;
- }
- item->valuestring = out;
- item->type = cJSON_String;
- return ptr;
- }
- /* Render the cstring provided to an escaped version that can be printed. */
- static char *print_string_ptr(const char *str, printbuffer *p)
- {
- const char *ptr;
- char *ptr2, *out;
- int len = 0, flag = 0;
- unsigned char token;
- for (ptr = str; *ptr; ptr++) {
- flag |= ((*ptr > 0 && *ptr < 32) || (*ptr == '\"') || (*ptr == '\\')) ? 1 : 0;
- }
- if (!flag) {
- len = ptr - str;
- if (p) {
- out = ensure(p, len + 3);
- } else {
- out = (char *)cJSON_malloc(len + 3);
- }
- if (!out) {
- return 0;
- }
- ptr2 = out;
- *ptr2++ = '\"';
- strcpy(ptr2, str);
- ptr2[len] = '\"';
- ptr2[len + 1] = 0;
- return out;
- }
- if (!str) {
- if (p) {
- out = ensure(p, 3);
- } else {
- out = (char *)cJSON_malloc(3);
- }
- if (!out) {
- return 0;
- }
- strcpy(out, "\"\"");
- return out;
- }
- ptr = str;
- while ((token = *ptr) && ++len) {
- if (strchr("\"\\\b\f\n\r\t", token)) {
- len++;
- } else if (token < 32) {
- len += 5;
- }
- ptr++;
- }
- if (p) {
- out = ensure(p, len + 3);
- } else {
- out = (char *)cJSON_malloc(len + 3);
- }
- if (!out) {
- return 0;
- }
- ptr2 = out;
- ptr = str;
- *ptr2++ = '\"';
- while (*ptr) {
- if ((unsigned char)*ptr > 31 && *ptr != '\"' && *ptr != '\\') {
- *ptr2++ = *ptr++;
- } else {
- *ptr2++ = '\\';
- switch (token = *ptr++) {
- case '\\':
- *ptr2++ = '\\';
- break;
- case '\"':
- *ptr2++ = '\"';
- break;
- case '\b':
- *ptr2++ = 'b';
- break;
- case '\f':
- *ptr2++ = 'f';
- break;
- case '\n':
- *ptr2++ = 'n';
- break;
- case '\r':
- *ptr2++ = 'r';
- break;
- case '\t':
- *ptr2++ = 't';
- break;
- default:
- sprintf(ptr2, "u%04x", token);
- ptr2 += 5;
- break; /* escape and print */
- }
- }
- }
- *ptr2++ = '\"';
- *ptr2++ = 0;
- return out;
- }
- /* Invote print_string_ptr (which is useful) on an item. */
- static char *print_string(cJSON *item, printbuffer *p)
- {
- return print_string_ptr(item->valuestring, p);
- }
- /* Predeclare these prototypes. */
- static const char *parse_value(cJSON *item, const char *value);
- static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p);
- static const char *parse_array(cJSON *item, const char *value);
- static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p);
- static const char *parse_object(cJSON *item, const char *value);
- static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p);
- /* Utility to jump whitespace and cr/lf */
- static const char *skip(const char *in)
- {
- while (in && *in && (unsigned char)*in <= 32) {
- in++;
- }
- return in;
- }
- /* Parse an object - create a new root, and populate. */
- cJSON *cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated)
- {
- const char *end = 0;
- cJSON *c = cJSON_New_Item();
- ep = 0;
- if (!c) {
- return 0; /* memory fail */
- }
- end = parse_value(c, skip(value));
- if (!end) {
- cJSON_Delete(c); /* parse failure. ep is set. */
- return 0;
- }
- /* 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) {
- cJSON_Delete(c);
- ep = end;
- return 0;
- }
- }
- if (return_parse_end) {
- *return_parse_end = end;
- }
- return c;
- }
- /* Default options for cJSON_Parse */
- cJSON *cJSON_Parse(const char *value)
- {
- return cJSON_ParseWithOpts(value, 0, 0);
- }
- /* Render a cJSON item/entity/structure to text. */
- char *cJSON_Print(cJSON *item)
- {
- return print_value(item, 0, 1, 0);
- }
- char *cJSON_PrintUnformatted(cJSON *item)
- {
- return print_value(item, 0, 0, 0);
- }
- char *cJSON_PrintBuffered(cJSON *item, int prebuffer, int fmt)
- {
- printbuffer p;
- p.buffer = (char *)cJSON_malloc(prebuffer);
- p.length = prebuffer;
- p.offset = 0;
- return print_value(item, 0, fmt, &p);
- return p.buffer;
- }
- /* Parser core - when encountering text, process appropriately. */
- static const char *parse_value(cJSON *item, const char *value)
- {
- if (!value) {
- return 0; /* Fail on null. */
- }
- if (!strncmp(value, "null", 4)) {
- item->type = cJSON_NULL;
- return value + 4;
- }
- if (!strncmp(value, "false", 5)) {
- item->type = cJSON_False;
- return value + 5;
- }
- if (!strncmp(value, "true", 4)) {
- item->type = cJSON_True;
- item->valueint = 1;
- return value + 4;
- }
- if (*value == '\"') {
- return parse_string(item, value);
- }
- if (*value == '-' || (*value >= '0' && *value <= '9')) {
- return parse_number(item, value);
- }
- if (*value == '[') {
- return parse_array(item, value);
- }
- if (*value == '{') {
- return parse_object(item, value);
- }
- ep = value;
- return 0; /* failure. */
- }
- /* Render a value to text. */
- static char *print_value(cJSON *item, int depth, int fmt, printbuffer *p)
- {
- char *out = 0;
- if (!item) {
- return 0;
- }
- if (p) {
- switch ((item->type) & 255) {
- 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) {
- strcpy(out, "true");
- }
- 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) & 255) {
- 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 out;
- }
- /* Build an array from input text. */
- static const char *parse_array(cJSON *item, const char *value)
- {
- cJSON *child;
- if (*value != '[') {
- ep = value; /* not an array! */
- return 0;
- }
- item->type = cJSON_Array;
- value = skip(value + 1);
- if (*value == ']') {
- return value + 1; /* empty array. */
- }
- item->child = child = cJSON_New_Item();
- if (!item->child) {
- return 0; /* memory fail */
- }
- value = skip(parse_value(child, skip(value))); /* skip any spacing, get the value. */
- if (!value) {
- return 0;
- }
- while (*value == ',') {
- cJSON *new_item;
- if (!(new_item = cJSON_New_Item())) {
- return 0; /* memory fail */
- }
- child->next = new_item;
- new_item->prev = child;
- child = new_item;
- value = skip(parse_value(child, skip(value + 1)));
- if (!value) {
- return 0; /* memory fail */
- }
- }
- if (*value == ']') {
- return value + 1; /* end of array */
- }
- ep = value;
- return 0; /* malformed. */
- }
- /* Render an array to text */
- static char *print_array(cJSON *item, int depth, int fmt, printbuffer *p)
- {
- char **entries;
- char *out = 0, *ptr, *ret;
- int len = 5;
- cJSON *child = item->child;
- int numentries = 0, i = 0, fail = 0;
- size_t tmplen = 0;
- /* How many entries in the array? */
- while (child) {
- numentries++, child = child->next;
- }
- /* Explicitly handle numentries==0 */
- if (!numentries) {
- if (p) {
- out = ensure(p, 3);
- } else {
- out = (char *)cJSON_malloc(3);
- }
- if (out) {
- strcpy(out, "[]");
- }
- return out;
- }
- if (p) {
- /* Compose the output array. */
- i = p->offset;
- ptr = ensure(p, 1);
- if (!ptr) {
- return 0;
- } *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 0;
- }*ptr++ = ',';
- if (fmt) {
- *ptr++ = ' ';
- }*ptr = 0;
- p->offset += len;
- }
- child = child->next;
- }
- ptr = ensure(p, 2);
- if (!ptr) {
- return 0;
- } *ptr++ = ']';
- *ptr = 0;
- out = (p->buffer) + i;
- } else {
- /* Allocate an array to hold the values for each */
- entries = (char **)cJSON_malloc(numentries * sizeof(char *));
- if (!entries) {
- return 0;
- }
- 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;
- }
- /* 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) {
- fail = 1;
- }
- /* Handle failure. */
- if (fail) {
- for (i = 0; i < numentries; i++) if (entries[i]) {
- cJSON_free(entries[i]);
- }
- cJSON_free(entries);
- return 0;
- }
- /* 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) {
- *ptr++ = ',';
- if (fmt) {
- *ptr++ = ' ';
- }*ptr = 0;
- }
- cJSON_free(entries[i]);
- }
- cJSON_free(entries);
- *ptr++ = ']';
- *ptr++ = 0;
- }
- return out;
- }
- /* Build an object from the text. */
- static const char *parse_object(cJSON *item, const char *value)
- {
- cJSON *child;
- if (*value != '{') {
- ep = value; /* not an object! */
- return 0;
- }
- item->type = cJSON_Object;
- value = skip(value + 1);
- if (*value == '}') {
- return value + 1; /* empty array. */
- }
- item->child = child = cJSON_New_Item();
- if (!item->child) {
- return 0;
- }
- value = skip(parse_string(child, skip(value)));
- if (!value) {
- return 0;
- }
- child->string = child->valuestring;
- child->valuestring = 0;
- if (*value != ':') {
- ep = value; /* fail! */
- return 0;
- }
- value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */
- if (!value) {
- return 0;
- }
- while (*value == ',') {
- cJSON *new_item;
- if (!(new_item = cJSON_New_Item())) {
- return 0; /* memory fail */
- }
- child->next = new_item;
- new_item->prev = child;
- child = new_item;
- value = skip(parse_string(child, skip(value + 1)));
- if (!value) {
- return 0;
- }
- child->string = child->valuestring;
- child->valuestring = 0;
- if (*value != ':') {
- ep = value; /* fail! */
- return 0;
- }
- value = skip(parse_value(child, skip(value + 1))); /* skip any spacing, get the value. */
- if (!value) {
- return 0;
- }
- }
- if (*value == '}') {
- return value + 1; /* end of array */
- }
- ep = value;
- return 0; /* malformed. */
- }
- /* Render an object to text. */
- static char *print_object(cJSON *item, int depth, int fmt, printbuffer *p)
- {
- char **entries = 0, **names = 0;
- char *out = 0, *ptr, *ret, *str;
- int len = 7, i = 0, j;
- cJSON *child = item->child;
- int numentries = 0, fail = 0;
- size_t tmplen = 0;
- /* Count the number of entries. */
- while (child) {
- numentries++, child = child->next;
- }
- /* Explicitly handle empty object case */
- if (!numentries) {
- if (p) {
- out = ensure(p, fmt ? depth + 4 : 3);
- } else {
- out = (char *)cJSON_malloc(fmt ? depth + 4 : 3);
- }
- if (!out) {
- return 0;
- }
- ptr = out;
- *ptr++ = '{';
- if (fmt) {
- *ptr++ = '\n';
- for (i = 0; i < depth - 1; i++) {
- *ptr++ = '\t';
- }
- }
- *ptr++ = '}';
- *ptr++ = 0;
- return out;
- }
- if (p) {
- /* Compose the output: */
- i = p->offset;
- len = fmt ? 2 : 1;
- ptr = ensure(p, len + 1);
- if (!ptr) {
- return 0;
- }
- *ptr++ = '{';
- if (fmt) {
- *ptr++ = '\n';
- } *ptr = 0;
- p->offset += len;
- child = item->child;
- depth++;
- while (child) {
- if (fmt) {
- ptr = ensure(p, depth);
- if (!ptr) {
- return 0;
- }
- for (j = 0; j < depth; j++) {
- *ptr++ = '\t';
- }
- p->offset += depth;
- }
- print_string_ptr(child->string, p);
- p->offset = update(p);
- len = fmt ? 2 : 1;
- ptr = ensure(p, len);
- if (!ptr) {
- return 0;
- }
- *ptr++ = ':';
- if (fmt) {
- *ptr++ = '\t';
- }
- p->offset += len;
- print_value(child, depth, fmt, p);
- p->offset = update(p);
- len = (fmt ? 1 : 0) + (child->next ? 1 : 0);
- ptr = ensure(p, len + 1);
- if (!ptr) {
- return 0;
- }
- if (child->next) {
- *ptr++ = ',';
- }
- if (fmt) {
- *ptr++ = '\n';
- }*ptr = 0;
- p->offset += len;
- child = child->next;
- }
- ptr = ensure(p, fmt ? (depth + 1) : 2);
- if (!ptr) {
- return 0;
- }
- if (fmt) for (i = 0; i < depth - 1; i++) {
- *ptr++ = '\t';
- }
- *ptr++ = '}';
- *ptr = 0;
- out = (p->buffer) + i;
- } else {
- /* Allocate space for the names and the objects */
- entries = (char **)cJSON_malloc(numentries * sizeof(char *));
- if (!entries) {
- return 0;
- }
- names = (char **)cJSON_malloc(numentries * sizeof(char *));
- if (!names) {
- cJSON_free(entries);
- return 0;
- }
- memset(entries, 0, sizeof(char *)*numentries);
- memset(names, 0, sizeof(char *)*numentries);
- /* Collect all the results into our arrays: */
- child = item->child;
- depth++;
- if (fmt) {
- len += depth;
- }
- while (child) {
- names[i] = str = print_string_ptr(child->string, 0);
- entries[i++] = ret = print_value(child, depth, fmt, 0);
- if (str && ret) {
- len += strlen(ret) + strlen(str) + 2 + (fmt ? 2 + depth : 0);
- } else {
- fail = 1;
- }
- child = child->next;
- }
- /* Try to allocate the output string */
- if (!fail) {
- out = (char *)cJSON_malloc(len);
- }
- if (!out) {
- fail = 1;
- }
- /* Handle failure */
- if (fail) {
- 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 0;
- }
- /* Compose the output: */
- *out = '{';
- ptr = out + 1;
- if (fmt) {
- *ptr++ = '\n';
- }*ptr = 0;
- for (i = 0; i < numentries; i++) {
- 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]);
- }
- cJSON_free(names);
- cJSON_free(entries);
- if (fmt) for (i = 0; i < depth - 1; i++) {
- *ptr++ = '\t';
- }
- *ptr++ = '}';
- *ptr++ = 0;
- }
- return out;
- }
- /* Get Array size/item / object item. */
- int cJSON_GetArraySize(cJSON *array)
- {
- cJSON *c = array->child;
- int i = 0;
- while (c) {
- i++, c = c->next;
- }
- return i;
- }
- cJSON *cJSON_GetArrayItem(cJSON *array, int item)
- {
- cJSON *c = array->child;
- while (c && item > 0) {
- item--, c = c->next;
- }
- return c;
- }
- cJSON *cJSON_GetObjectItem(cJSON *object, const char *string)
- {
- cJSON *c = object->child;
- while (c && cJSON_strcasecmp(c->string, string)) {
- c = c->next;
- }
- return c;
- }
- /* Utility for array list handling. */
- static void suffix_object(cJSON *prev, cJSON *item)
- {
- prev->next = item;
- item->prev = prev;
- }
- /* Utility for handling references. */
- static cJSON *create_reference(cJSON *item)
- {
- cJSON *ref = cJSON_New_Item();
- if (!ref) {
- return 0;
- }
- memcpy(ref, item, sizeof(cJSON));
- ref->string = 0;
- ref->type |= cJSON_IsReference;
- ref->next = ref->prev = 0;
- return ref;
- }
- /* Add item to array/object. */
- void cJSON_AddItemToArray(cJSON *array, cJSON *item)
- {
- cJSON *c = array->child;
- if (!item) {
- return;
- }
- if (!c) {
- array->child = item;
- } else {
- while (c && c->next) {
- c = c->next;
- }
- suffix_object(c, item);
- }
- }
- void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
- {
- if (!item) {
- return;
- }
- if (item->string) {
- cJSON_free(item->string);
- }
- item->string = cJSON_strdup(string);
- cJSON_AddItemToArray(object, item);
- }
- void cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
- {
- if (!item) {
- return;
- }
- if (!(item->type & cJSON_StringIsConst) && item->string) {
- cJSON_free(item->string);
- }
- item->string = (char *)string;
- item->type |= cJSON_StringIsConst;
- cJSON_AddItemToArray(object, item);
- }
- void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
- {
- cJSON_AddItemToArray(array, create_reference(item));
- }
- void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
- {
- cJSON_AddItemToObject(object, string, create_reference(item));
- }
- cJSON *cJSON_DetachItemFromArray(cJSON *array, int which)
- {
- cJSON *c = array->child;
- while (c && which > 0) {
- c = c->next, which--;
- }
- if (!c) {
- return 0;
- }
- if (c->prev) {
- c->prev->next = c->next;
- }
- if (c->next) {
- c->next->prev = c->prev;
- }
- if (c == array->child) {
- array->child = c->next;
- }
- c->prev = c->next = 0;
- return c;
- }
- void cJSON_DeleteItemFromArray(cJSON *array, int which)
- {
- cJSON_Delete(cJSON_DetachItemFromArray(array, which));
- }
- cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string)
- {
- int i = 0;
- cJSON *c = object->child;
- while (c && cJSON_strcasecmp(c->string, string)) {
- i++, c = c->next;
- }
- if (c) {
- return cJSON_DetachItemFromArray(object, i);
- }
- return 0;
- }
- 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 *c = array->child;
- while (c && which > 0) {
- c = c->next, which--;
- }
- if (!c) {
- cJSON_AddItemToArray(array, newitem);
- return;
- }
- newitem->next = c;
- newitem->prev = c->prev;
- c->prev = newitem;
- if (c == array->child) {
- array->child = newitem;
- } else {
- newitem->prev->next = newitem;
- }
- }
- void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
- {
- cJSON *c = array->child;
- while (c && which > 0) {
- c = c->next, which--;
- }
- if (!c) {
- return;
- }
- newitem->next = c->next;
- newitem->prev = c->prev;
- if (newitem->next) {
- newitem->next->prev = newitem;
- }
- if (c == array->child) {
- array->child = newitem;
- } else {
- newitem->prev->next = newitem;
- }
- c->next = c->prev = 0;
- cJSON_Delete(c);
- }
- void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
- {
- int i = 0;
- cJSON *c = object->child;
- while (c && cJSON_strcasecmp(c->string, string)) {
- i++, c = c->next;
- }
- if (c) {
- newitem->string = cJSON_strdup(string);
- cJSON_ReplaceItemInArray(object, i, newitem);
- }
- }
- /* Create basic types: */
- cJSON *cJSON_CreateNull(void)
- {
- cJSON *item = cJSON_New_Item();
- if (item) {
- item->type = cJSON_NULL;
- }
- return item;
- }
- cJSON *cJSON_CreateTrue(void)
- {
- cJSON *item = cJSON_New_Item();
- if (item) {
- item->type = cJSON_True;
- }
- return item;
- }
- cJSON *cJSON_CreateFalse(void)
- {
- cJSON *item = cJSON_New_Item();
- if (item) {
- item->type = cJSON_False;
- }
- return item;
- }
- cJSON *cJSON_CreateBool(int b)
- {
- cJSON *item = cJSON_New_Item();
- if (item) {
- item->type = b ? cJSON_True : cJSON_False;
- }
- return item;
- }
- cJSON *cJSON_CreateNumber(double num)
- {
- cJSON *item = cJSON_New_Item();
- if (item) {
- item->type = cJSON_Number;
- item->valuedouble = num;
- item->valueint = (int)num;
- }
- return item;
- }
- cJSON *cJSON_CreateString(const char *string)
- {
- cJSON *item = cJSON_New_Item();
- if (item) {
- item->type = cJSON_String;
- item->valuestring = cJSON_strdup(string);
- }
- return item;
- }
- cJSON *cJSON_CreateArray(void)
- {
- cJSON *item = cJSON_New_Item();
- if (item) {
- item->type = cJSON_Array;
- }
- return item;
- }
- cJSON *cJSON_CreateObject(void)
- {
- cJSON *item = cJSON_New_Item();
- if (item) {
- item->type = cJSON_Object;
- }
- return item;
- }
- /* Create Arrays: */
- cJSON *cJSON_CreateIntArray(const int *numbers, int count)
- {
- int i;
- cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
- for (i = 0; a && i < count; i++) {
- n = cJSON_CreateNumber(numbers[i]);
- if (!i) {
- a->child = n;
- } else {
- suffix_object(p, n);
- }
- p = n;
- }
- return a;
- }
- cJSON *cJSON_CreateFloatArray(const float *numbers, int count)
- {
- int i;
- cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
- for (i = 0; a && i < count; i++) {
- n = cJSON_CreateNumber(numbers[i]);
- if (!i) {
- a->child = n;
- } else {
- suffix_object(p, n);
- }
- p = n;
- }
- return a;
- }
- cJSON *cJSON_CreateDoubleArray(const double *numbers, int count)
- {
- int i;
- cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
- for (i = 0; a && i < count; i++) {
- n = cJSON_CreateNumber(numbers[i]);
- if (!i) {
- a->child = n;
- } else {
- suffix_object(p, n);
- }
- p = n;
- }
- return a;
- }
- cJSON *cJSON_CreateStringArray(const char **strings, int count)
- {
- int i;
- cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
- for (i = 0; a && i < count; i++) {
- n = cJSON_CreateString(strings[i]);
- if (!i) {
- a->child = n;
- } else {
- suffix_object(p, n);
- }
- p = n;
- }
- return a;
- }
- /* Duplication */
- cJSON *cJSON_Duplicate(cJSON *item, int recurse)
- {
- cJSON *newitem, *cptr, *nptr = 0, *newchild;
- /* Bail on bad ptr */
- if (!item) {
- return 0;
- }
- /* Create new item */
- newitem = cJSON_New_Item();
- if (!newitem) {
- return 0;
- }
- /* Copy over all vars */
- newitem->type = item->type & (~cJSON_IsReference), newitem->valueint = item->valueint, newitem->valuedouble = item->valuedouble;
- if (item->valuestring) {
- newitem->valuestring = cJSON_strdup(item->valuestring);
- if (!newitem->valuestring) {
- cJSON_Delete(newitem);
- return 0;
- }
- }
- if (item->string) {
- newitem->string = cJSON_strdup(item->string);
- if (!newitem->string) {
- cJSON_Delete(newitem);
- return 0;
- }
- }
- /* If non-recursive, then we're done! */
- if (!recurse) {
- return newitem;
- }
- /* Walk the ->next chain for the child. */
- cptr = item->child;
- while (cptr) {
- newchild = cJSON_Duplicate(cptr, 1); /* Duplicate (with recurse) each item in the ->next chain */
- if (!newchild) {
- cJSON_Delete(newitem);
- return 0;
- }
- if (nptr) {
- nptr->next = newchild, newchild->prev = nptr; /* If newitem->child already set, then crosswire ->prev and ->next and move on */
- nptr = newchild;
- } else {
- newitem->child = newchild; /* Set newitem->child and move to it */
- nptr = newchild;
- }
- cptr = cptr->next;
- }
- return newitem;
- }
- void cJSON_Minify(char *json)
- {
- char *into = json;
- while (*json) {
- if (*json == ' ') {
- json++;
- } else if (*json == '\t') {
- json++; /* Whitespace characters. */
- } else if (*json == '\r') {
- json++;
- } else if (*json == '\n') {
- json++;
- } else if (*json == '/' && json[1] == '/') while (*json && *json != '\n') {
- json++; /* double-slash comments, to end of line. */
- } else if (*json == '/' && json[1] == '*') {
- while (*json && !(*json == '*' && json[1] == '/')) {
- json++; /* multiline comments. */
- }
- json += 2;
- } else if (*json == '\"') {
- *into++ = *json++; /* string literals, which are \" sensitive. */
- while (*json && *json != '\"') {
- if (*json == '\\') {
- *into++ = *json++;
- }*into++ = *json++;
- }*into++ = *json++;
- } else {
- *into++ = *json++; /* All other characters. */
- }
- }
- *into = 0; /* and null-terminate. */
- }
|