Merge pull request #1438 from jkent/jsonparse
jsonparse: multiple improvements
This commit is contained in:
commit
a15be9e518
|
@ -71,6 +71,7 @@ enum {
|
||||||
JSON_ERROR_UNEXPECTED_ARRAY,
|
JSON_ERROR_UNEXPECTED_ARRAY,
|
||||||
JSON_ERROR_UNEXPECTED_END_OF_ARRAY,
|
JSON_ERROR_UNEXPECTED_END_OF_ARRAY,
|
||||||
JSON_ERROR_UNEXPECTED_OBJECT,
|
JSON_ERROR_UNEXPECTED_OBJECT,
|
||||||
|
JSON_ERROR_UNEXPECTED_END_OF_OBJECT,
|
||||||
JSON_ERROR_UNEXPECTED_STRING
|
JSON_ERROR_UNEXPECTED_STRING
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,14 @@ push(struct jsonparse_state *state, char c)
|
||||||
return state->depth < JSONPARSE_MAX_DEPTH;
|
return state->depth < JSONPARSE_MAX_DEPTH;
|
||||||
}
|
}
|
||||||
/*--------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------*/
|
||||||
|
static void
|
||||||
|
modify(struct jsonparse_state *state, char c)
|
||||||
|
{
|
||||||
|
if(state->depth > 0) {
|
||||||
|
state->stack[state->depth - 1] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*--------------------------------------------------------------------*/
|
||||||
static char
|
static char
|
||||||
pop(struct jsonparse_state *state)
|
pop(struct jsonparse_state *state)
|
||||||
{
|
{
|
||||||
|
@ -50,25 +58,31 @@ pop(struct jsonparse_state *state)
|
||||||
return JSON_TYPE_ERROR;
|
return JSON_TYPE_ERROR;
|
||||||
}
|
}
|
||||||
state->depth--;
|
state->depth--;
|
||||||
|
state->vtype = state->stack[state->depth];
|
||||||
return state->stack[state->depth];
|
return state->stack[state->depth];
|
||||||
}
|
}
|
||||||
/*--------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------*/
|
||||||
/* will pass by the value and store the start and length of the value for
|
/* will pass by the value and store the start and length of the value for
|
||||||
atomic types */
|
atomic types */
|
||||||
/*--------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------*/
|
||||||
static void
|
static char
|
||||||
atomic(struct jsonparse_state *state, char type)
|
atomic(struct jsonparse_state *state, char type)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
|
const char *str;
|
||||||
|
int len;
|
||||||
|
|
||||||
state->vstart = state->pos;
|
state->vstart = state->pos;
|
||||||
state->vtype = type;
|
|
||||||
if(type == JSON_TYPE_STRING || type == JSON_TYPE_PAIR_NAME) {
|
if(type == JSON_TYPE_STRING || type == JSON_TYPE_PAIR_NAME) {
|
||||||
while((c = state->json[state->pos++]) && c != '"') {
|
while((c = state->json[state->pos++]) && c != '"') {
|
||||||
if(c == '\\') {
|
if(c == '\\') {
|
||||||
state->pos++; /* skip current char */
|
state->pos++; /* skip current char */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (c != '"') {
|
||||||
|
state->error = JSON_ERROR_SYNTAX;
|
||||||
|
return JSON_TYPE_ERROR;
|
||||||
|
}
|
||||||
state->vlen = state->pos - state->vstart - 1;
|
state->vlen = state->pos - state->vstart - 1;
|
||||||
} else if(type == JSON_TYPE_NUMBER) {
|
} else if(type == JSON_TYPE_NUMBER) {
|
||||||
do {
|
do {
|
||||||
|
@ -82,8 +96,31 @@ atomic(struct jsonparse_state *state, char type)
|
||||||
/* need to back one step since first char is already gone */
|
/* need to back one step since first char is already gone */
|
||||||
state->vstart--;
|
state->vstart--;
|
||||||
state->vlen = state->pos - state->vstart;
|
state->vlen = state->pos - state->vstart;
|
||||||
|
} else if(type == JSON_TYPE_NULL || type == JSON_TYPE_TRUE || type == JSON_TYPE_FALSE) {
|
||||||
|
state->vstart--;
|
||||||
|
switch (type) {
|
||||||
|
case JSON_TYPE_NULL: str = "null"; break;
|
||||||
|
case JSON_TYPE_TRUE: str = "true"; break;
|
||||||
|
case JSON_TYPE_FALSE: str = "false"; break;
|
||||||
|
default: str = ""; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((c = state->json[state->pos]) && c != ' ' && c != ',' && c != ']' && c != '}') {
|
||||||
|
state->pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
state->vlen = state->pos - state->vstart;
|
||||||
|
len = strlen(str);
|
||||||
|
len = state->vlen > len ? state->vlen : len;
|
||||||
|
|
||||||
|
if (strncmp(str, &state->json[state->vstart], len) != 0) {
|
||||||
|
state->error = JSON_ERROR_SYNTAX;
|
||||||
|
return JSON_TYPE_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* no other types for now... */
|
|
||||||
|
state->vtype = type;
|
||||||
|
return state->vtype;
|
||||||
}
|
}
|
||||||
/*--------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------*/
|
||||||
static void
|
static void
|
||||||
|
@ -97,6 +134,17 @@ skip_ws(struct jsonparse_state *state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*--------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------*/
|
||||||
|
static int
|
||||||
|
is_atomic(struct jsonparse_state *state)
|
||||||
|
{
|
||||||
|
char v = state->vtype;
|
||||||
|
if(v == 'N' || v == '"' || v == '0' || v == 'n' || v == 't' || v == 'f') {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*--------------------------------------------------------------------*/
|
||||||
void
|
void
|
||||||
jsonparse_setup(struct jsonparse_state *state, const char *json, int len)
|
jsonparse_setup(struct jsonparse_state *state, const char *json, int len)
|
||||||
{
|
{
|
||||||
|
@ -105,6 +153,7 @@ jsonparse_setup(struct jsonparse_state *state, const char *json, int len)
|
||||||
state->pos = 0;
|
state->pos = 0;
|
||||||
state->depth = 0;
|
state->depth = 0;
|
||||||
state->error = 0;
|
state->error = 0;
|
||||||
|
state->vtype = 0;
|
||||||
state->stack[0] = 0;
|
state->stack[0] = 0;
|
||||||
}
|
}
|
||||||
/*--------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------*/
|
||||||
|
@ -113,31 +162,33 @@ jsonparse_next(struct jsonparse_state *state)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
char s;
|
char s;
|
||||||
|
char v;
|
||||||
|
|
||||||
skip_ws(state);
|
skip_ws(state);
|
||||||
c = state->json[state->pos];
|
c = state->json[state->pos];
|
||||||
s = jsonparse_get_type(state);
|
s = jsonparse_get_type(state);
|
||||||
|
v = state->vtype;
|
||||||
state->pos++;
|
state->pos++;
|
||||||
|
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case '{':
|
case '{':
|
||||||
push(state, c);
|
if((s == 0 && v == 0) || s == '[' || s == ':') {
|
||||||
|
push(state, c);
|
||||||
|
} else {
|
||||||
|
state->error = JSON_ERROR_UNEXPECTED_OBJECT;
|
||||||
|
return JSON_TYPE_ERROR;
|
||||||
|
}
|
||||||
return c;
|
return c;
|
||||||
case '}':
|
case '}':
|
||||||
if(s == ':' && state->vtype != 0) {
|
if((s == ':' && v != ',' && v != 0 ) || (s == '{' && v == 0)) {
|
||||||
/* printf("Popping vtype: '%c'\n", state->vtype); */
|
|
||||||
pop(state);
|
|
||||||
s = jsonparse_get_type(state);
|
|
||||||
}
|
|
||||||
if(s == '{') {
|
|
||||||
pop(state);
|
pop(state);
|
||||||
} else {
|
} else {
|
||||||
state->error = JSON_ERROR_SYNTAX;
|
state->error = JSON_ERROR_UNEXPECTED_END_OF_OBJECT;
|
||||||
return JSON_TYPE_ERROR;
|
return JSON_TYPE_ERROR;
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
case ']':
|
case ']':
|
||||||
if(s == '[') {
|
if(s == '[' && v != ',') {
|
||||||
pop(state);
|
pop(state);
|
||||||
} else {
|
} else {
|
||||||
state->error = JSON_ERROR_UNEXPECTED_END_OF_ARRAY;
|
state->error = JSON_ERROR_UNEXPECTED_END_OF_ARRAY;
|
||||||
|
@ -145,41 +196,67 @@ jsonparse_next(struct jsonparse_state *state)
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
case ':':
|
case ':':
|
||||||
push(state, c);
|
if(s == '{' && v == 'N') {
|
||||||
return c;
|
modify(state, ':');
|
||||||
|
state->vtype = 0;
|
||||||
|
} else {
|
||||||
|
state->error = JSON_ERROR_SYNTAX;
|
||||||
|
return JSON_TYPE_ERROR;
|
||||||
|
}
|
||||||
|
return jsonparse_next(state);
|
||||||
case ',':
|
case ',':
|
||||||
/* if x:y ... , */
|
if(s == ':' && v != 0) {
|
||||||
if(s == ':' && state->vtype != 0) {
|
modify(state, '{');
|
||||||
pop(state);
|
state->vtype = c;
|
||||||
} else if(s == '[') {
|
} else if(s == '[') {
|
||||||
/* ok! */
|
state->vtype = c;
|
||||||
} else {
|
} else {
|
||||||
state->error = JSON_ERROR_SYNTAX;
|
state->error = JSON_ERROR_SYNTAX;
|
||||||
return JSON_TYPE_ERROR;
|
return JSON_TYPE_ERROR;
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
case '"':
|
case '"':
|
||||||
if(s == '{' || s == '[' || s == ':') {
|
if((s == 0 && v == 0) || s == '{' || s == '[' || s == ':') {
|
||||||
atomic(state, c = (s == '{' ? JSON_TYPE_PAIR_NAME : c));
|
return atomic(state, c = (s == '{' ? JSON_TYPE_PAIR_NAME : c));
|
||||||
} else {
|
} else {
|
||||||
state->error = JSON_ERROR_UNEXPECTED_STRING;
|
state->error = JSON_ERROR_UNEXPECTED_STRING;
|
||||||
return JSON_TYPE_ERROR;
|
return JSON_TYPE_ERROR;
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
case '[':
|
case '[':
|
||||||
if(s == '{' || s == '[' || s == ':') {
|
if((s == 0 && v == 0) || s == '[' || s == ':') {
|
||||||
push(state, c);
|
push(state, c);
|
||||||
} else {
|
} else {
|
||||||
state->error = JSON_ERROR_UNEXPECTED_ARRAY;
|
state->error = JSON_ERROR_UNEXPECTED_ARRAY;
|
||||||
return JSON_TYPE_ERROR;
|
return JSON_TYPE_ERROR;
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
|
case 0:
|
||||||
|
if(v == 0 || state->depth > 0) {
|
||||||
|
state->error = JSON_ERROR_SYNTAX;
|
||||||
|
}
|
||||||
|
return JSON_TYPE_ERROR;
|
||||||
default:
|
default:
|
||||||
if(s == ':' || s == '[') {
|
if(s == 0 || s == ':' || s == '[') {
|
||||||
if(c <= '9' && c >= '0') {
|
if (v != 0 && v != ',') {
|
||||||
atomic(state, JSON_TYPE_NUMBER);
|
state->error = JSON_ERROR_SYNTAX;
|
||||||
return JSON_TYPE_NUMBER;
|
return JSON_TYPE_ERROR;
|
||||||
}
|
}
|
||||||
|
if(c == '-' || (c <= '9' && c >= '0')) {
|
||||||
|
return atomic(state, JSON_TYPE_NUMBER);
|
||||||
|
} else if(c == 'n') {
|
||||||
|
return atomic(state, JSON_TYPE_NULL);
|
||||||
|
} else if(c == 't') {
|
||||||
|
return atomic(state, JSON_TYPE_TRUE);
|
||||||
|
} else if(c == 'f') {
|
||||||
|
return atomic(state, JSON_TYPE_FALSE);
|
||||||
|
} else {
|
||||||
|
state->error = JSON_ERROR_SYNTAX;
|
||||||
|
return JSON_TYPE_ERROR;
|
||||||
|
}
|
||||||
|
} else if(s == '{') {
|
||||||
|
state->error = JSON_ERROR_SYNTAX;
|
||||||
|
return JSON_TYPE_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -192,16 +269,31 @@ jsonparse_next(struct jsonparse_state *state)
|
||||||
int
|
int
|
||||||
jsonparse_copy_value(struct jsonparse_state *state, char *str, int size)
|
jsonparse_copy_value(struct jsonparse_state *state, char *str, int size)
|
||||||
{
|
{
|
||||||
int i;
|
int i, o;
|
||||||
|
char c;
|
||||||
|
|
||||||
if(state->vtype == 0) {
|
if(!is_atomic(state)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
size = size <= state->vlen ? (size - 1) : state->vlen;
|
for(i = 0, o = 0; i < state->vlen && o < size - 1; i++) {
|
||||||
for(i = 0; i < size; i++) {
|
c = state->json[state->vstart + i];
|
||||||
str[i] = state->json[state->vstart + i];
|
if(c == '\\') {
|
||||||
|
i++;
|
||||||
|
switch(state->json[state->vstart + i]) {
|
||||||
|
case '"': str[o++] = '"'; break;
|
||||||
|
case '\\': str[o++] = '\\'; break;
|
||||||
|
case '/': str[o++] = '/'; break;
|
||||||
|
case 'b': str[o++] = '\b'; break;
|
||||||
|
case 'f': str[o++] = '\f'; break;
|
||||||
|
case 'n': str[o++] = '\n'; break;
|
||||||
|
case 'r': str[o++] = '\r'; break;
|
||||||
|
case 't': str[o++] = '\t'; break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
str[o++] = c;
|
||||||
}
|
}
|
||||||
str[i] = 0;
|
str[o] = 0;
|
||||||
return state->vtype;
|
return state->vtype;
|
||||||
}
|
}
|
||||||
/*--------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------*/
|
||||||
|
@ -228,7 +320,7 @@ jsonparse_get_value_as_long(struct jsonparse_state *state)
|
||||||
int
|
int
|
||||||
jsonparse_strcmp_value(struct jsonparse_state *state, const char *str)
|
jsonparse_strcmp_value(struct jsonparse_state *state, const char *str)
|
||||||
{
|
{
|
||||||
if(state->vtype == 0) {
|
if(!is_atomic(state)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return strncmp(str, &state->json[state->vstart], state->vlen);
|
return strncmp(str, &state->json[state->vstart], state->vlen);
|
||||||
|
|
Loading…
Reference in a new issue