mirror of
https://github.com/DaveGamble/cJSON.git
synced 2024-12-27 14:14:07 +08:00
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).
This commit is contained in:
parent
c6d868cf06
commit
b4151361de
70
cJSON.c
70
cJSON.c
@ -32,9 +32,9 @@
|
||||
#include <ctype.h>
|
||||
#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. */
|
||||
|
1
cJSON.h
1
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user