From b4151361de7a9a8b8fc786ed7d3c324488bcd261 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Sat, 19 Mar 2016 18:41:44 +0000 Subject: [PATCH] Allow for global/local error pointers. If you supply a return_parse_end to cJSON_ParseWithOpts, then that will store the error pointer (if parsing fails). --- cJSON.c | 70 ++++++++++++++++++++++++++++----------------------------- cJSON.h | 1 + 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/cJSON.c b/cJSON.c index 67a4aba..b051f32 100644 --- a/cJSON.c +++ b/cJSON.c @@ -32,9 +32,9 @@ #include #include "cJSON.h" -static const char *ep; +static const char *global_ep; -const char *cJSON_GetErrorPtr(void) {return ep;} +const char *cJSON_GetErrorPtr(void) {return global_ep;} static int cJSON_strcasecmp(const char *s1,const char *s2) { @@ -190,10 +190,10 @@ static unsigned parse_hex4(const char *str) /* 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) +static const char *parse_string(cJSON *item,const char *str,const char **ep) { const char *ptr=str+1,*end_ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; - if (*str!='\"') {ep=str;return 0;} /* not a string! */ + if (*str!='\"') {*ep=str;return 0;} /* not a string! */ while (*end_ptr!='\"' && *end_ptr && ++len) if (*end_ptr++ == '\\') end_ptr++; /* Skip escaped quotes. */ @@ -218,16 +218,16 @@ static const char *parse_string(cJSON *item,const char *str) case 't': *ptr2++='\t'; break; case 'u': /* transcode utf16 to utf8. */ uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */ - if (ptr >= end_ptr) {ep=str;return 0;} /* invalid */ + if (ptr >= end_ptr) {*ep=str;return 0;} /* invalid */ - if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) {ep=str;return 0;} /* check for invalid. */ + if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) {*ep=str;return 0;} /* check for invalid. */ if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */ { - if (ptr+6 > end_ptr) {ep=str;return 0;} /* invalid */ - if (ptr[1]!='\\' || ptr[2]!='u') {ep=str;return 0;} /* missing second-half of surrogate. */ + if (ptr+6 > end_ptr) {*ep=str;return 0;} /* invalid */ + if (ptr[1]!='\\' || ptr[2]!='u') {*ep=str;return 0;} /* missing second-half of surrogate. */ uc2=parse_hex4(ptr+3);ptr+=6; - if (uc2<0xDC00 || uc2>0xDFFF) {ep=str;return 0;} /* invalid second-half of surrogate. */ + if (uc2<0xDC00 || uc2>0xDFFF) {*ep=str;return 0;} /* invalid second-half of surrogate. */ uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); } @@ -313,11 +313,11 @@ static char *print_string_ptr(const char *str,printbuffer *p) 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 const char *parse_value(cJSON *item,const char *value,const char **ep); static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p); -static const char *parse_array(cJSON *item,const char *value); +static const char *parse_array(cJSON *item,const char *value,const char **ep); static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p); -static const char *parse_object(cJSON *item,const char *value); +static const char *parse_object(cJSON *item,const char *value,const char **ep); static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p); /* Utility to jump whitespace and cr/lf */ @@ -326,16 +326,16 @@ static const char *skip(const char *in) {while (in && *in && (unsigned char)*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; + const char *end=0,**ep=return_parse_end?return_parse_end:&global_ep; cJSON *c=cJSON_New_Item(); - ep=0; + *ep=0; if (!c) return 0; /* memory fail */ - end=parse_value(c,skip(value)); + end=parse_value(c,skip(value),ep); if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ /* 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 (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; } @@ -357,18 +357,18 @@ char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt) /* Parser core - when encountering text, process appropriately. */ -static const char *parse_value(cJSON *item,const char *value) +static const char *parse_value(cJSON *item,const char *value,const char **ep) { 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=='\"') { return parse_string(item,value,ep); } 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); } + if (*value=='[') { return parse_array(item,value,ep); } + if (*value=='{') { return parse_object(item,value,ep); } - ep=value;return 0; /* failure. */ + *ep=value;return 0; /* failure. */ } /* Render a value to text. */ @@ -406,10 +406,10 @@ static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p) } /* Build an array from input text. */ -static const char *parse_array(cJSON *item,const char *value) +static const char *parse_array(cJSON *item,const char *value,const char **ep) { cJSON *child; - if (*value!='[') {ep=value;return 0;} /* not an array! */ + if (*value!='[') {*ep=value;return 0;} /* not an array! */ item->type=cJSON_Array; value=skip(value+1); @@ -417,7 +417,7 @@ static const char *parse_array(cJSON *item,const char *value) 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. */ + value=skip(parse_value(child,skip(value),ep)); /* skip any spacing, get the value. */ if (!value) return 0; while (*value==',') @@ -425,12 +425,12 @@ static const char *parse_array(cJSON *item,const char *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))); + value=skip(parse_value(child,skip(value+1),ep)); if (!value) return 0; /* memory fail */ } if (*value==']') return value+1; /* end of array */ - ep=value;return 0; /* malformed. */ + *ep=value;return 0; /* malformed. */ } /* Render an array to text */ @@ -514,10 +514,10 @@ static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p) } /* Build an object from the text. */ -static const char *parse_object(cJSON *item,const char *value) +static const char *parse_object(cJSON *item,const char *value,const char **ep) { cJSON *child; - if (*value!='{') {ep=value;return 0;} /* not an object! */ + if (*value!='{') {*ep=value;return 0;} /* not an object! */ item->type=cJSON_Object; value=skip(value+1); @@ -525,11 +525,11 @@ static const char *parse_object(cJSON *item,const char *value) item->child=child=cJSON_New_Item(); if (!item->child) return 0; - value=skip(parse_string(child,skip(value))); + value=skip(parse_string(child,skip(value),ep)); if (!value) return 0; child->string=child->valuestring;child->valuestring=0; - if (*value!=':') {ep=value;return 0;} /* fail! */ - value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ + if (*value!=':') {*ep=value;return 0;} /* fail! */ + value=skip(parse_value(child,skip(value+1),ep)); /* skip any spacing, get the value. */ if (!value) return 0; while (*value==',') @@ -537,16 +537,16 @@ static const char *parse_object(cJSON *item,const char *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))); + value=skip(parse_string(child,skip(value+1),ep)); if (!value) return 0; child->string=child->valuestring;child->valuestring=0; - if (*value!=':') {ep=value;return 0;} /* fail! */ - value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ + if (*value!=':') {*ep=value;return 0;} /* fail! */ + value=skip(parse_value(child,skip(value+1),ep)); /* skip any spacing, get the value. */ if (!value) return 0; } if (*value=='}') return value+1; /* end of array */ - ep=value;return 0; /* malformed. */ + *ep=value;return 0; /* malformed. */ } /* Render an object to text. */ diff --git a/cJSON.h b/cJSON.h index 36b5f90..3a587cb 100644 --- a/cJSON.h +++ b/cJSON.h @@ -126,6 +126,7 @@ need to be released. With recurse!=0, it will duplicate any children connected t 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); extern void cJSON_Minify(char *json); -- GitLab