static struct json_node *json_parse_elements(json_parser_t p) { struct json_node *n1 = json_parse_value(p); struct json_node *m0, *m1; if (!n1) return 0; m0 = m1 = json_new_node(p, json_node_list); m1->u.link[0] = n1; while (look_ch(p) == ',') { struct json_node *n2, *m2; move_ch(p); n2 = json_parse_value(p); if (!n2) { json_remove_node(m0); return 0; } m2 = json_new_node(p, json_node_list); m2->u.link[0] = n2; m1->u.link[1] = m2; m1 = m2; } return m0; }
static int json_parse_object_tail(struct json_parser* parser) { for (;;) { skip_white_space(parser); switch (peek(parser)) { // Finished when we reach the final closing brace case '}': skip(parser); return JSON_PARSE_SUCCESS; case '"': // Key skip(parser); json_parse_string_tail(parser); // Sep skip_white_space(parser); skip_char(parser, ':'); // Value json_parse_value(parser); // Comma? break; default: return JSON_PARSE_FAIL; } } }
/****************************************************************************** * * * Function: json_parse_array * * * * Purpose: Parses JSON array value * * * * Parameters: start - [IN] the JSON data without leading whitespace * * error - [OUT] the parsing error message (can be NULL) * * * * Return value: The number of characters parsed. On error 0 is returned and * * error parameter (if not NULL) contains allocated error * * message. * * * * Author: Andris Zeila * * * ******************************************************************************/ static int json_parse_array(const char *start, char **error) { const char *ptr = start; int len; ptr++; SKIP_WHITESPACE(ptr); if (']' != *ptr) { while (1) { /* json_parse_value strips leading whitespace, so we don't have to do it here */ if (0 == (len = json_parse_value(ptr, error))) return 0; ptr += len; SKIP_WHITESPACE(ptr); if (',' != *ptr) break; ptr++; } /* no closing ], failing */ if (']' != *ptr) return json_error("invalid array format, expected closing character ']'", ptr, error); } return ptr - start + 1; }
static JSON *json_parse_array(struct lexer *lx) { JSON *v = malloc(sizeof *v); v->type = j_array; v->value = NULL; v->next = NULL; JSON *tail = NULL; if(!lx_expect(lx, '[')) { json_error("line %d: %s", lx_lineno(lx), lx_text(lx)); return NULL; } if(lx_sym(lx) != ']') { do { JSON *value = json_parse_value(lx); if(!value) return NULL; if(v->value) { assert(tail); tail->next = value; } else { v->value = value; } tail = value; } while(lx_accept(lx, ',')); } if(!lx_expect(lx, ']')) { json_error("line %d: %s", lx_lineno(lx), lx_text(lx)); return NULL; } return v; }
struct json_node *json_parser_parse(json_parser_t p, const char *json_str) { int c; struct json_node *n; p->buf = json_str; p->cp = p->buf; p->err_msg = 0; p->parse_level = 0; p->max_level = 1000; n = json_parse_value(p); if (!n) return 0; if (p->err_msg) { json_remove_node(n); return 0; } c = look_ch(p); if (c != 0) { p->err_msg = "extra characters"; json_remove_node(n); return 0; } return n; }
/****************************************************************************** * * * Function: json_parse_object * * * * Purpose: Parses JSON object * * * * Parameters: start - [IN] the JSON data * * error - [OUT] the parsing error message (can be NULL) * * * * Return value: The number of characters parsed. On error 0 is returned and * * error parameter (if not NULL) contains allocated error * * message. * * * * Author: Andris Zeila * * * ******************************************************************************/ static int json_parse_object(const char *start, char **error) { const char *ptr = start; int len; /* parse object name */ SKIP_WHITESPACE(ptr); /* not an object, failing */ if ('{' != *ptr) return json_error("invalid object format, expected opening character '{'", ptr, error); ptr++; SKIP_WHITESPACE(ptr); if ('}' != *ptr) { while (1) { if ('"' != *ptr) return json_error("invalid object name", ptr, error); /* cannot parse object name, failing */ if (0 == (len = json_parse_string(ptr, error))) return 0; ptr += len; /* parse name:value separator */ SKIP_WHITESPACE(ptr); if (':' != *ptr) return json_error("invalid object name/value separator", ptr, error); ptr++; if (0 == (len = json_parse_value(ptr, error))) return 0; ptr += len; SKIP_WHITESPACE(ptr); if (',' != *ptr) break; ptr++; SKIP_WHITESPACE(ptr); } /* object is not properly closed, failing */ if ('}' != *ptr) return json_error("invalid object format, expected closing character '}'", ptr, error); } return ptr - start + 1; }
struct json_val *json_parse_base(struct read_state *state) { if (read_state_left(state) >= 2) { if (*state->read == 0xfe) state->read += 2;//Eat any BOMs } if (!eat_whitespace(state)) return 0; return json_parse_value(state); }
static void * json_parse_list(const char *s, const char **endp, const json_deserializer_t *jd, void *opaque, const char **failp, const char **failmsg) { const char *s2; void *r; while(*s > 0 && *s < 33) s++; if(*s != '[') return NOT_THIS_TYPE; s++; r = jd->jd_create_list(opaque); while(*s > 0 && *s < 33) s++; if(*s != ']') { while(1) { s2 = json_parse_value(s, r, NULL, jd, opaque, failp, failmsg); if(s2 == NULL) { jd->jd_destroy_obj(opaque, r); return NULL; } s = s2; while(*s > 0 && *s < 33) s++; if(*s == ']') break; if(*s != ',') { jd->jd_destroy_obj(opaque, r); *failmsg = "Expected ','"; *failp = s; return NULL; } s++; } } s++; *endp = s; return r; }
struct json_val *json_parse_array(struct read_state *state) { struct json_val *value; char ch; int i; value = malloc(sizeof(*value)); value->type = JSON_ARRAY; value->length = 0; value->array = 0; if (*state->read++ != '[') { json_error_print(state, "Internal error parsing array\n"); goto fail; } if(!eat_whitespace(state)) { json_error_print(state, "Unexpected end of file parsing array\n"); goto fail; } ch = *state->read++; if (ch == ']') { //pass } else { read_state_put_back(state); do { value->length++; value->array = realloc(value->object, value->length * sizeof(*value->object)); value->array[value->length-1] = json_parse_value(state); if (value->array[value->length-1] == 0) goto fail; if (!eat_whitespace(state)) { json_error_print(state, "Unexpected end of file parsing array\n"); goto fail; } ch = *state->read++; if (ch != ']' && ch != ',') { json_error_print(state, "Unexpected character found parsing array\n"); goto fail; } if (!eat_whitespace(state) && ch != ']') { json_error_print(state, "Unexpected end of file parsing array\n"); goto fail; } } while (ch == ','); } return value; fail: json_free_value(value); return 0; }
static struct json_field json_parse_object_field(struct read_state *state) { struct json_field ret = {0,0}; if (!eat_whitespace(state)) { json_error_print(state, "Unexpected end of file parsing object field key\n"); goto fail; } ret.key = json_parse_value(state); if (ret.key == 0) goto fail; if (ret.key->type != JSON_STRING) { json_error_print(state, "Objected field key must be of type string\n"); goto fail; } ; if (!eat_whitespace(state)) { json_error_print(state, "Unexpected end of file parsing object field\n"); goto fail; } if (*state->read++ != ':') { json_error_print(state, "Didn't find expected ':' reading object\n"); goto fail; } if (!eat_whitespace(state)) { json_error_print(state, "Unexpected end of file parsing object field value\n"); goto fail; } ret.value = json_parse_value(state); if (ret.value == 0) goto fail; return ret; fail: free(ret.key); ret.key == 0; return ret; }
int json_parse(const json_char* source, struct json_callbacks* callbacks) { struct json_parser parser; parser.line = 0; parser.col = 0; parser.callbacks = callbacks; parser.source = strdup(source); parser.position = parser.source; jmp_buf buffer; parser.buffer = &buffer; if (setjmp(buffer)) { callbacks->on_error(parser.line, parser.col, parser.source); return JSON_PARSE_FAIL; } return json_parse_value(&parser); }
struct json_value_s* json_parse(const void* src, size_t src_size) { struct json_parse_state_s state; void* allocation; if (0 == src || 2 > src_size) { // absolute minimum valid json is either "{}" or "[]" return 0; } state.src = src; state.size = src_size; state.offset = 0; state.dom_size = 0; state.data_size = 0; if (json_get_value_size(&state)) { // parsing value's size failed (most likely an invalid JSON DOM!) return 0; } // our total allocation is the combination of the dom and data sizes (we // first encode the structure of the JSON, and then the data referenced by // the JSON values) allocation = malloc(state.dom_size + state.data_size); if (0 == allocation) { // malloc failed! return 0; } // reset offset so we can reuse it state.offset = 0; state.dom = allocation; state.data = state.dom + state.dom_size; state.dom += sizeof(struct json_value_s); if (json_parse_value(&state, (struct json_value_s* )allocation)) { // really bad chi here free(allocation); return 0; } return allocation; }
static JSON *json_parse_object(struct lexer *lx) { Hash_Tbl *h = ht_create (16); JSON *v = malloc(sizeof *v); v->type = j_object; v->value = h; v->next = NULL; if(!lx_expect(lx, '{')) { json_error("line %d: %s", lx_lineno(lx), lx_text(lx)); free(v); return NULL; } if(lx_sym(lx) != '}') { do { char *key; JSON *value; lx_accept(lx, LX_STRING); key = strdup(lx_text(lx)); lx_accept(lx, ':'); value = json_parse_value(lx); if(!value) { free(key); free(v); return NULL; } ht_put (h, key, value); free(key); } while(lx_accept(lx, ',')); } if(!lx_expect(lx, '}')) { json_error("line %d: %s", lx_lineno(lx), lx_text(lx)); free(v); return NULL; } return v; }
static int json_parse_array_tail(struct json_parser* parser) { for (;;) { if (peek(parser) == ']') { skip(parser); return JSON_PARSE_SUCCESS; } int more = 0; do { json_parse_value(parser); skip_white_space(parser); if (peek(parser) == ',') { skip(parser); more = 1; } } while (more); } }
static struct json_node *json_parse_pair(json_parser_t p) { struct json_node *s = json_parse_string(p); struct json_node *v, *n; if (!s) return 0; if (look_ch(p) != ':') { p->err_msg = "missing :"; json_remove_node(s); return 0; } move_ch(p); v = json_parse_value(p); if (!v) { json_remove_node(s); return 0; } n = json_new_node(p, json_node_pair); n->u.link[0] = s; n->u.link[1] = v; return n; }
static int json_parse_object(struct json_parse_state_s* state, struct json_object_s* object) { size_t elements = 0; struct json_object_element_s* previous = 0; if ('{' != state->src[state->offset]) { // expected object to begin with leading '{' return 1; } // skip leading '{' state->offset++; if (json_skip_whitespace(state)) { // consumed the whole buffer when we expected a value! return 1; } if ('}' != state->src[state->offset]) { // we have at least one element as we definitely don't have // an empty object { }! elements++; } // reset elements elements = 0; while (state->offset < state->size) { struct json_object_element_s* element = 0; struct json_string_s* string = 0; struct json_value_s* value = 0; if (json_skip_whitespace(state)) { // reached end of buffer before object was complete! return 1; } if ('}' == state->src[state->offset]) { // skip trailing '}' state->offset++; // finished the object! break; } // if we parsed at least one element previously, grok for a comma if (0 < elements) { if (',' != state->src[state->offset]) { // expected a comma where there was none! return 1; } // skip comma state->offset++; if (json_skip_whitespace(state)) { // reached end of buffer before object was complete! return 1; } } element = (struct json_object_element_s* )state->dom; state->dom += sizeof(struct json_object_element_s); if (0 == previous) { // this is our first element, so record it in our object object->start = element; } else { previous->next = element; } previous = element; string = (struct json_string_s* )state->dom; state->dom += sizeof(struct json_string_s); element->name = string; if (json_parse_string(state, string)) { // string parsing failed! return 1; } if (json_skip_whitespace(state)) { // reached end of buffer before object was complete! return 1; } if (':' != state->src[state->offset]) { // colon seperating name/value pair was missing! return 1; } // skip colon state->offset++; if (json_skip_whitespace(state)) { // reached end of buffer before object was complete! return 1; } value = (struct json_value_s* )state->dom; state->dom += sizeof(struct json_value_s); element->value = value; if (json_parse_value(state, value)) { // value parsing failed! return 1; } // successfully parsed a name/value pair! elements++; } // if we had at least one element, end the linked list if (previous) { previous->next = 0; } if (0 == elements) { object->start = 0; } object->length = elements; return 0; }
int json_parse_array( json_task_t *task, json_object_t *parent ) { char ch; json_object_t node, * append = NULL; node.next = parent; node.key = NULL; node.key_len = 0; if( !task->callback ) { if( !task->root ) { append = task->root = json_create_array(); } else { append = parent->value.p = json_create_array(); } } task->status = STS_ARRAY_START; while(( ch = *(task->str + task->count) )) { task->count ++; if( ch == ' ' || ch == '\n' || ch == '\t' ) { continue; } switch( task->status ) { case STS_ARRAY_START: if( ch == ']' ) { return 0; } else { /* 这里需要将计数减一,因为 json_parse_value 需要根据这一个字符判断 value 类型 */ task->count --; node.value.s = task->str + task->count; if( json_parse_value( task, &node ) != 0 ) { if( node.value_type == JSON_OBJECT || node.value_type == JSON_ARRAY ) { json_delete_object(node.value.p); } return -1; } // WARNING: value_len 可能发生溢出 node.value_len = task->str + task->count - node.value.s; // 对 value 进行处理 switch(node.value_type) { case JSON_STRING: // 去除字符串两端的引号 node.value.s += 1; node.value_len -= 2; break; case JSON_DOUBLE: // TODO 在解析测试用例时,atof 与 atoll 使解析时间延长了几乎一半 // 移除对数值的默认解析可以显著提升性能 node.value.d = atof(node.value.s); break; case JSON_LONGLONG: node.value.l = atoll(node.value.s); break; case JSON_ARRAY: case JSON_OBJECT: break; } // 需要放在 node.key_len ++ 之前以便正确输出数组下标 if( task->callback ) { task->callback( task, &node ); } if( !task->callback ) { switch( node.value_type ) { case JSON_ARRAY: case JSON_OBJECT: case JSON_STRING: append = json_append(append, node.key, node.key_len, node.value_type, node.value.p, node.value_len); break; default: append = json_append(append, node.key, node.key_len, node.value_type, &node.value, node.value_len); } } node.key_len ++; task->status = STS_ARRAY_COMMA; } break; case STS_ARRAY_COMMA: if( ch == ',' ) { task->status = STS_ARRAY_START; } else if( ch == ']' ) { return 0; } else { task->err_msg = "expect ',' or ']'"; return -1; } break; default: task->err_msg = "unknown status"; return -1; } } task->err_msg = "unexpect EOF"; return -1; }
int json_parse_object( json_task_t *task, json_object_t *parent ) { char ch; json_object_t node, * append = NULL; node.next = parent; node.key = NULL; node.key_len = 0; if( !task->callback ) { if( !task->root ) { append = task->root = json_create_object(); } else { append = parent->value.p = json_create_object(); } } task->status = STS_OBJECT_START; while(( ch = *(task->str + task->count) )) { task->count ++; if( ch == ' ' || ch == '\n' || ch == '\t' ) { continue; } switch( task->status ) { case STS_OBJECT_START: if( ch == '"' ) { node.key = task->str + task->count; if( json_parse_string( task ) != 0 ) { return -1; } // WARNING: key_len 可能发生溢出 node.key_len = task->str + task->count - node.key - 1; task->status = STS_OBJECT_COLON; } else if( ch == '}' ) { // 空对象 {},忽略 return 0; } else { task->err_msg = "expect '\"' or '}'"; return -1; } break; case STS_OBJECT_COLON: if( ch == ':' ) { task->status = STS_OBJECT_VALUE; } else { task->err_msg = "expect ':'"; return -1; } break; case STS_OBJECT_VALUE: /* 这里需要将计数减一,因为 json_parse_value 需要根据这一个字符判断 value 类型 */ task->count --; node.value.s = task->str + task->count; if( json_parse_value( task, &node ) != 0 ) { if( node.value_type == JSON_OBJECT || node.value_type == JSON_ARRAY ) { json_delete_object(node.value.p); } return -1; } // WARNING: value_len 可能发生溢出 node.value_len = task->str + task->count - node.value.s; task->status = STS_OBJECT_COMMA; break; case STS_OBJECT_COMMA: if( ( ch == ',' || ch == '}' ) ) { // 对 value 进行处理 switch(node.value_type) { case JSON_STRING: // 去除字符串两端的引号 node.value.s += 1; node.value_len -= 2; break; case JSON_DOUBLE: node.value.d = atof(node.value.s); break; case JSON_LONGLONG: node.value.l = atoll(node.value.s); break; case JSON_ARRAY: case JSON_OBJECT: break; } if( task->callback ) { task->callback( task, &node ); } if( !task->callback ) { switch( node.value_type ) { case JSON_ARRAY: case JSON_OBJECT: case JSON_STRING: append = json_append(append, node.key, node.key_len, node.value_type, node.value.p, node.value_len); break; default: append = json_append(append, node.key, node.key_len, node.value_type, &node.value, node.value_len); } } } if( ch == ',' ) { task->status = STS_OBJECT_START; } else if( ch == '}' ) { return 0; } else { task->err_msg = "expect ',' or '}'"; return -1; } break; default: task->err_msg = "unknown status"; return -1; } } task->err_msg = "unexpect EOF"; return -1; }
static guint json_parse_array (JsonParser *parser, JsonScanner *scanner, JsonNode **node) { JsonParserPrivate *priv = parser->priv; JsonNode *old_current; JsonArray *array; guint token; gint idx; old_current = priv->current_node; priv->current_node = json_node_new (JSON_NODE_ARRAY); array = json_array_new (); token = json_scanner_get_next_token (scanner); g_assert (token == G_TOKEN_LEFT_BRACE); g_signal_emit (parser, parser_signals[ARRAY_START], 0); idx = 0; while (token != G_TOKEN_RIGHT_BRACE) { guint next_token = json_scanner_peek_next_token (scanner); JsonNode *element = NULL; /* parse the element */ switch (next_token) { case G_TOKEN_LEFT_BRACE: token = json_parse_array (parser, scanner, &element); break; case G_TOKEN_LEFT_CURLY: token = json_parse_object (parser, scanner, &element); break; case G_TOKEN_INT: case G_TOKEN_FLOAT: case G_TOKEN_STRING: case '-': case JSON_TOKEN_TRUE: case JSON_TOKEN_FALSE: case JSON_TOKEN_NULL: token = json_scanner_get_next_token (scanner); token = json_parse_value (parser, scanner, token, &element); break; case G_TOKEN_RIGHT_BRACE: goto array_done; default: if (next_token != G_TOKEN_RIGHT_BRACE) token = G_TOKEN_RIGHT_BRACE; break; } if (token != G_TOKEN_NONE || element == NULL) { /* the json_parse_* functions will have set the error code */ json_array_unref (array); json_node_free (priv->current_node); priv->current_node = old_current; return token; } next_token = json_scanner_peek_next_token (scanner); if (next_token == G_TOKEN_COMMA) { token = json_scanner_get_next_token (scanner); next_token = json_scanner_peek_next_token (scanner); /* look for trailing commas */ if (next_token == G_TOKEN_RIGHT_BRACE) { json_array_unref (array); json_node_free (priv->current_node); json_node_free (element); priv->current_node = old_current; return G_TOKEN_RIGHT_BRACE; } } json_node_set_parent (element, priv->current_node); json_array_add_element (array, element); g_signal_emit (parser, parser_signals[ARRAY_ELEMENT], 0, array, idx); token = next_token; } array_done: json_scanner_get_next_token (scanner); json_node_take_array (priv->current_node, array); json_node_set_parent (priv->current_node, old_current); g_signal_emit (parser, parser_signals[ARRAY_END], 0, array); if (node != NULL && *node == NULL) *node = priv->current_node; priv->current_node = old_current; return G_TOKEN_NONE; }
static guint json_parse_object (JsonParser *parser, JsonScanner *scanner, JsonNode **node) { JsonParserPrivate *priv = parser->priv; JsonObject *object; JsonNode *old_current; guint token; old_current = priv->current_node; priv->current_node = json_node_new (JSON_NODE_OBJECT); object = json_object_new (); token = json_scanner_get_next_token (scanner); g_assert (token == G_TOKEN_LEFT_CURLY); g_signal_emit (parser, parser_signals[OBJECT_START], 0); while (token != G_TOKEN_RIGHT_CURLY) { guint next_token = json_scanner_peek_next_token (scanner); JsonNode *member = NULL; gchar *name; /* we need to abort here because empty objects do not * have member names */ if (next_token == G_TOKEN_RIGHT_CURLY) break; /* parse the member's name */ if (next_token != G_TOKEN_STRING) { json_object_unref (object); json_node_free (priv->current_node); priv->current_node = old_current; return G_TOKEN_STRING; } /* member name */ token = json_scanner_get_next_token (scanner); name = g_strdup (scanner->value.v_string); /* a colon separates names from values */ next_token = json_scanner_peek_next_token (scanner); if (next_token != ':') { g_free (name); json_object_unref (object); json_node_free (priv->current_node); priv->current_node = old_current; return ':'; } /* we swallow the ':' */ token = json_scanner_get_next_token (scanner); g_assert (token == ':'); next_token = json_scanner_peek_next_token (scanner); /* parse the member's value */ switch (next_token) { case G_TOKEN_LEFT_BRACE: token = json_parse_array (parser, scanner, &member); break; case G_TOKEN_LEFT_CURLY: token = json_parse_object (parser, scanner, &member); break; case G_TOKEN_INT: case G_TOKEN_FLOAT: case G_TOKEN_STRING: case '-': case JSON_TOKEN_TRUE: case JSON_TOKEN_FALSE: case JSON_TOKEN_NULL: token = json_scanner_get_next_token (scanner); token = json_parse_value (parser, scanner, token, &member); break; default: /* once a member name is defined we need a value */ token = G_TOKEN_SYMBOL; break; } if (token != G_TOKEN_NONE || member == NULL) { /* the json_parse_* functions will have set the error code */ g_free (name); json_object_unref (object); json_node_free (priv->current_node); priv->current_node = old_current; return token; } next_token = json_scanner_peek_next_token (scanner); if (next_token == G_TOKEN_COMMA) { token = json_scanner_get_next_token (scanner); next_token = json_scanner_peek_next_token (scanner); /* look for trailing commas */ if (next_token == G_TOKEN_RIGHT_CURLY) { json_object_unref (object); json_node_free (member); json_node_free (priv->current_node); priv->current_node = old_current; return G_TOKEN_RIGHT_BRACE; } } else if (next_token == G_TOKEN_STRING) { json_object_unref (object); json_node_free (member); json_node_free (priv->current_node); priv->current_node = old_current; return G_TOKEN_COMMA; } json_node_set_parent (member, priv->current_node); json_object_set_member (object, name, member); g_signal_emit (parser, parser_signals[OBJECT_MEMBER], 0, object, name); g_free (name); token = next_token; } json_scanner_get_next_token (scanner); json_node_take_object (priv->current_node, object); json_node_set_parent (priv->current_node, old_current); g_signal_emit (parser, parser_signals[OBJECT_END], 0, object); if (node != NULL && *node == NULL) *node = priv->current_node; priv->current_node = old_current; return G_TOKEN_NONE; }
static guint json_parse_statement (JsonParser *parser, JsonScanner *scanner) { JsonParserPrivate *priv = parser->priv; guint token; token = json_scanner_peek_next_token (scanner); switch (token) { case G_TOKEN_LEFT_CURLY: JSON_NOTE (PARSER, "Statement is object declaration"); return json_parse_object (parser, scanner, &priv->root); case G_TOKEN_LEFT_BRACE: JSON_NOTE (PARSER, "Statement is array declaration"); return json_parse_array (parser, scanner, &priv->root); /* some web APIs are not only passing the data structures: they are * also passing an assigment, which makes parsing horribly complicated * only because web developers are lazy, and writing "var foo = " is * evidently too much to request from them. */ case JSON_TOKEN_VAR: { guint next_token; gchar *name; JSON_NOTE (PARSER, "Statement is an assignment"); /* swallow the 'var' token... */ token = json_scanner_get_next_token (scanner); /* ... swallow the variable name... */ next_token = json_scanner_get_next_token (scanner); if (next_token != G_TOKEN_IDENTIFIER) { priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD; return G_TOKEN_IDENTIFIER; } name = g_strdup (scanner->value.v_identifier); /* ... and finally swallow the '=' */ next_token = json_scanner_get_next_token (scanner); if (next_token != '=') { priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD; g_free (name); return '='; } priv->has_assignment = TRUE; priv->variable_name = name; token = json_parse_statement (parser, scanner); /* remove the trailing semi-colon */ next_token = json_scanner_peek_next_token (scanner); if (next_token == ';') { token = json_scanner_get_next_token (scanner); return G_TOKEN_NONE; } return token; } break; case JSON_TOKEN_NULL: case JSON_TOKEN_TRUE: case JSON_TOKEN_FALSE: case '-': case G_TOKEN_INT: case G_TOKEN_FLOAT: case G_TOKEN_STRING: case G_TOKEN_IDENTIFIER: JSON_NOTE (PARSER, "Statement is a value"); token = json_scanner_get_next_token (scanner); return json_parse_value (parser, scanner, token, &priv->root); default: JSON_NOTE (PARSER, "Unknown statement"); json_scanner_get_next_token (scanner); priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD; return G_TOKEN_SYMBOL; } }
static guint json_parse_statement (JsonParser *parser, JsonScanner *scanner) { JsonParserPrivate *priv = parser->priv; guint token; token = json_scanner_peek_next_token (scanner); switch (token) { case G_TOKEN_LEFT_CURLY: return json_parse_object (parser, scanner, &priv->root); case G_TOKEN_LEFT_BRACE: return json_parse_array (parser, scanner, &priv->root); /* some web APIs are not only passing the data structures: they are * also passing an assigment, which makes parsing horribly complicated * only because web developers are lazy, and writing "var foo = " is * evidently too much to request from them. */ case JSON_TOKEN_VAR: { guint next_token; gchar *name; /* swallow the 'var' token... */ token = json_scanner_get_next_token (scanner); /* ... swallow the variable name... */ next_token = json_scanner_get_next_token (scanner); if (next_token != G_TOKEN_IDENTIFIER) return G_TOKEN_IDENTIFIER; name = g_strdup (scanner->value.v_identifier); /* ... and finally swallow the '=' */ next_token = json_scanner_get_next_token (scanner); if (next_token != '=') return '='; priv->has_assignment = TRUE; priv->variable_name = name; token = json_parse_statement (parser, scanner); /* remove the trailing semi-colon */ next_token = json_scanner_peek_next_token (scanner); if (next_token == ';') { token = json_scanner_get_next_token (scanner); return G_TOKEN_NONE; } return token; } break; case JSON_TOKEN_NULL: priv->root = priv->current_node = json_node_new (JSON_NODE_NULL); json_scanner_get_next_token (scanner); return G_TOKEN_NONE; case JSON_TOKEN_TRUE: case JSON_TOKEN_FALSE: priv->root = priv->current_node = json_node_new (JSON_NODE_VALUE); json_node_set_boolean (priv->current_node, token == JSON_TOKEN_TRUE ? TRUE : FALSE); json_scanner_get_next_token (scanner); return G_TOKEN_NONE; case '-': { guint next_token; token = json_scanner_get_next_token (scanner); next_token = json_scanner_peek_next_token (scanner); if (next_token == G_TOKEN_INT || next_token == G_TOKEN_FLOAT) { priv->root = priv->current_node = json_node_new (JSON_NODE_VALUE); token = json_scanner_get_next_token (scanner); switch (token) { case G_TOKEN_INT: json_node_set_int (priv->current_node, scanner->value.v_int64 * -1); break; case G_TOKEN_FLOAT: json_node_set_double (priv->current_node, scanner->value.v_float * -1.0); break; default: return G_TOKEN_INT; } json_scanner_get_next_token (scanner); return G_TOKEN_NONE; } else return G_TOKEN_INT; } break; case G_TOKEN_INT: case G_TOKEN_FLOAT: case G_TOKEN_STRING: token = json_scanner_get_next_token (scanner); return json_parse_value (parser, scanner, token, &priv->root); default: json_scanner_get_next_token (scanner); return G_TOKEN_SYMBOL; } }
static guint json_parse_array (JsonParser *parser, JsonScanner *scanner, JsonNode **node) { JsonParserPrivate *priv = parser->priv; JsonNode *old_current; JsonArray *array; guint token; gint idx; old_current = priv->current_node; priv->current_node = json_node_init_array (json_node_alloc (), NULL); array = json_array_new (); token = json_scanner_get_next_token (scanner); g_assert (token == G_TOKEN_LEFT_BRACE); g_signal_emit (parser, parser_signals[ARRAY_START], 0); idx = 0; while (token != G_TOKEN_RIGHT_BRACE) { guint next_token = json_scanner_peek_next_token (scanner); JsonNode *element = NULL; /* parse the element */ switch (next_token) { case G_TOKEN_LEFT_BRACE: JSON_NOTE (PARSER, "Nested array at index %d", idx); token = json_parse_array (parser, scanner, &element); break; case G_TOKEN_LEFT_CURLY: JSON_NOTE (PARSER, "Nested object at index %d", idx); token = json_parse_object (parser, scanner, &element); break; case G_TOKEN_RIGHT_BRACE: goto array_done; default: token = json_scanner_get_next_token (scanner); token = json_parse_value (parser, scanner, token, &element); break; } if (token != G_TOKEN_NONE || element == NULL) { /* the json_parse_* functions will have set the error code */ json_array_unref (array); json_node_free (priv->current_node); priv->current_node = old_current; return token; } next_token = json_scanner_peek_next_token (scanner); if (next_token == G_TOKEN_COMMA) { token = json_scanner_get_next_token (scanner); next_token = json_scanner_peek_next_token (scanner); /* look for trailing commas */ if (next_token == G_TOKEN_RIGHT_BRACE) { priv->error_code = JSON_PARSER_ERROR_TRAILING_COMMA; json_array_unref (array); json_node_free (priv->current_node); json_node_free (element); priv->current_node = old_current; return G_TOKEN_RIGHT_BRACE; } } JSON_NOTE (PARSER, "Array element %d completed", idx + 1); json_node_set_parent (element, priv->current_node); json_array_add_element (array, element); g_signal_emit (parser, parser_signals[ARRAY_ELEMENT], 0, array, idx); token = next_token; } array_done: json_scanner_get_next_token (scanner); json_node_take_array (priv->current_node, array); json_node_set_parent (priv->current_node, old_current); g_signal_emit (parser, parser_signals[ARRAY_END], 0, array); if (node != NULL && *node == NULL) *node = priv->current_node; priv->current_node = old_current; return G_TOKEN_NONE; }
static void json_parse_array(struct json_parse_state_s *state, struct json_array_s *array) { size_t elements = 0; int allow_comma = 0; struct json_array_element_s *previous = 0; // skip leading '[' state->offset++; (void)json_skip_all_skippables(state); // reset elements elements = 0; while (state->offset < state->size) { struct json_array_element_s *element = 0; struct json_value_s *value = 0; (void)json_skip_all_skippables(state); if (']' == state->src[state->offset]) { // skip trailing ']' state->offset++; // finished the array! break; } // if we parsed at least one element previously, grok for a comma if (allow_comma) { if (',' == state->src[state->offset]) { // skip comma state->offset++; allow_comma = 0; continue; } } element = (struct json_array_element_s *)state->dom; state->dom += sizeof(struct json_array_element_s); if (0 == previous) { // this is our first element, so record it in our array array->start = element; } else { previous->next = element; } previous = element; value = (struct json_value_s *)state->dom; state->dom += sizeof(struct json_value_s); element->value = value; json_parse_value(state, /* is_global_object = */ 0, value); // successfully parsed an array element! elements++; allow_comma = 1; } // end the linked list if (previous) { previous->next = 0; } if (0 == elements) { array->start = 0; } array->length = elements; }
static void json_parse_object(struct json_parse_state_s *state, int is_global_object, struct json_object_s *object) { size_t elements = 0; int allow_comma = 0; struct json_object_element_s *previous = 0; if (!is_global_object) { // skip leading '{' state->offset++; } (void)json_skip_all_skippables(state); // reset elements elements = 0; while (state->offset < state->size) { struct json_object_element_s *element = 0; struct json_string_s *string = 0; struct json_value_s *value = 0; if (!is_global_object) { (void)json_skip_all_skippables(state); if ('}' == state->src[state->offset]) { // skip trailing '}' state->offset++; // finished the object! break; } } else { if (json_skip_all_skippables(state)) { // global object ends when the file ends! break; } } // if we parsed at least one element previously, grok for a comma if (allow_comma) { if (',' == state->src[state->offset]) { // skip comma state->offset++; allow_comma = 0; continue; } } element = (struct json_object_element_s *)state->dom; state->dom += sizeof(struct json_object_element_s); if (0 == previous) { // this is our first element, so record it in our object object->start = element; } else { previous->next = element; } previous = element; string = (struct json_string_s *)state->dom; state->dom += sizeof(struct json_string_s); element->name = string; (void)json_parse_key(state, string); (void)json_skip_all_skippables(state); // skip colon or equals state->offset++; (void)json_skip_all_skippables(state); value = (struct json_value_s *)state->dom; state->dom += sizeof(struct json_value_s); element->value = value; json_parse_value(state, /* is_global_object = */ 0, value); // successfully parsed a name/value pair! elements++; allow_comma = 1; } // if we had at least one element, end the linked list if (previous) { previous->next = 0; } if (0 == elements) { object->start = 0; } object->length = elements; }
static int json_parse_array(struct json_parse_state_s* state, struct json_array_s* array) { size_t elements = 0; struct json_array_element_s* previous = 0; if ('[' != state->src[state->offset]) { // expected object to begin with leading '[' return 1; } // skip leading '[' state->offset++; if (json_skip_whitespace(state)) { // consumed the whole buffer when we expected a value! return 1; } // reset elements elements = 0; while (state->offset < state->size) { struct json_array_element_s* element = 0; struct json_value_s* value = 0; if (json_skip_whitespace(state)) { // reached end of buffer before array was complete! return 1; } if (']' == state->src[state->offset]) { // skip trailing ']' state->offset++; // finished the array! break; } // if we parsed at least one element previously, grok for a comma if (0 < elements) { if (',' != state->src[state->offset]) { // expected a comma where there was none! return 1; } // skip comma state->offset++; if (json_skip_whitespace(state)) { // reached end of buffer before array was complete! return 1; } } element = (struct json_array_element_s* )state->dom; state->dom += sizeof(struct json_array_element_s); if (0 == previous) { // this is our first element, so record it in our array array->start = element; } else { previous->next = element; } previous = element; value = (struct json_value_s* )state->dom; state->dom += sizeof(struct json_value_s); element->value = value; if (json_parse_value(state, value)) { // value parsing failed! return 1; } // successfully parsed an array element! elements++; } // end the linked list if (previous) { previous->next = 0; } if (0 == elements) { array->start = 0; } array->length = elements; return 0; }
static void * json_parse_map(const char *s, const char **endp, const json_deserializer_t *jd, void *opaque, const char **failp, const char **failmsg) { char *name; const char *s2; void *r; while(*s > 0 && *s < 33) s++; if(*s != '{') return NOT_THIS_TYPE; s++; r = jd->jd_create_map(opaque); while(*s > 0 && *s < 33) s++; if(*s != '}') { while(1) { name = json_parse_string(s, &s2, failp, failmsg); if(name == NOT_THIS_TYPE) { *failmsg = "Expected string"; *failp = s; return NULL; } if(name == NULL) return NULL; s = s2; while(*s > 0 && *s < 33) s++; if(*s != ':') { jd->jd_destroy_obj(opaque, r); free(name); *failmsg = "Expected ':'"; *failp = s; return NULL; } s++; s2 = json_parse_value(s, r, name, jd, opaque, failp, failmsg); free(name); if(s2 == NULL) { jd->jd_destroy_obj(opaque, r); return NULL; } s = s2; while(*s > 0 && *s < 33) s++; if(*s == '}') break; if(*s != ',') { jd->jd_destroy_obj(opaque, r); *failmsg = "Expected ','"; *failp = s; return NULL; } s++; } } s++; *endp = s; return r; }
struct json_value_s *json_parse_ex(const void *src, size_t src_size, size_t flags_bitset, struct json_parse_result_s *result) { struct json_parse_state_s state; void *allocation; if (result) { result->error = json_parse_error_none; result->error_offset = 0; result->error_line_no = 0; result->error_row_no = 0; } if (0 == src) { // invalid src pointer was null! return 0; } else if (!(json_parse_flags_allow_global_object & flags_bitset) && src_size < 2) { // absolute minimum valid json is either "{}" or "[]" return 0; } state.src = src; state.size = src_size; state.offset = 0; state.line_no = 1; state.line_offset = 0; state.error = json_parse_error_none; state.dom_size = 0; state.data_size = 0; state.flags_bitset = flags_bitset; if (json_get_value_size( &state, /* is_global_object = */ ( json_parse_flags_allow_global_object & state.flags_bitset))) { // parsing value's size failed (most likely an invalid JSON DOM!) if (result) { result->error = state.error; result->error_offset = state.offset; result->error_line_no = state.line_no; result->error_row_no = state.offset - state.line_offset; } return 0; } // our total allocation is the combination of the dom and data sizes (we // first encode the structure of the JSON, and then the data referenced by // the JSON values) allocation = malloc(state.dom_size + state.data_size); if (0 == allocation) { // malloc failed! return 0; } // reset offset so we can reuse it state.offset = 0; state.dom = allocation; state.data = state.dom + state.dom_size; state.dom += sizeof(struct json_value_s); json_parse_value( &state, /* is_global_object = */ ( json_parse_flags_allow_global_object & state.flags_bitset), (struct json_value_s *)allocation); return allocation; }
static guint json_parse_object (JsonParser *parser, JsonScanner *scanner, JsonNode **node) { JsonParserPrivate *priv = parser->priv; JsonObject *object; JsonNode *old_current; guint token; old_current = priv->current_node; priv->current_node = json_node_init_object (json_node_alloc (), NULL); object = json_object_new (); token = json_scanner_get_next_token (scanner); g_assert (token == G_TOKEN_LEFT_CURLY); g_signal_emit (parser, parser_signals[OBJECT_START], 0); while (token != G_TOKEN_RIGHT_CURLY) { guint next_token = json_scanner_peek_next_token (scanner); JsonNode *member = NULL; gchar *name; /* we need to abort here because empty objects do not * have member names */ if (next_token == G_TOKEN_RIGHT_CURLY) break; /* parse the member's name */ if (next_token != G_TOKEN_STRING) { JSON_NOTE (PARSER, "Missing object member name"); priv->error_code = JSON_PARSER_ERROR_INVALID_BAREWORD; json_object_unref (object); json_node_free (priv->current_node); priv->current_node = old_current; return G_TOKEN_STRING; } /* member name */ token = json_scanner_get_next_token (scanner); name = g_strdup (scanner->value.v_string); if (name == NULL || *name == '\0') { JSON_NOTE (PARSER, "Empty object member name"); priv->error_code = JSON_PARSER_ERROR_EMPTY_MEMBER_NAME; json_object_unref (object); json_node_free (priv->current_node); priv->current_node = old_current; return G_TOKEN_STRING; } JSON_NOTE (PARSER, "Object member '%s'", name); /* a colon separates names from values */ next_token = json_scanner_peek_next_token (scanner); if (next_token != ':') { JSON_NOTE (PARSER, "Missing object member name separator"); priv->error_code = JSON_PARSER_ERROR_MISSING_COLON; g_free (name); json_object_unref (object); json_node_free (priv->current_node); priv->current_node = old_current; return ':'; } /* we swallow the ':' */ token = json_scanner_get_next_token (scanner); g_assert (token == ':'); next_token = json_scanner_peek_next_token (scanner); /* parse the member's value */ switch (next_token) { case G_TOKEN_LEFT_BRACE: JSON_NOTE (PARSER, "Nested array at member %s", name); token = json_parse_array (parser, scanner, &member); break; case G_TOKEN_LEFT_CURLY: JSON_NOTE (PARSER, "Nested object at member %s", name); token = json_parse_object (parser, scanner, &member); break; default: /* once a member name is defined we need a value */ token = json_scanner_get_next_token (scanner); token = json_parse_value (parser, scanner, token, &member); break; } if (token != G_TOKEN_NONE || member == NULL) { /* the json_parse_* functions will have set the error code */ g_free (name); json_object_unref (object); json_node_free (priv->current_node); priv->current_node = old_current; return token; } next_token = json_scanner_peek_next_token (scanner); if (next_token == G_TOKEN_COMMA) { token = json_scanner_get_next_token (scanner); next_token = json_scanner_peek_next_token (scanner); /* look for trailing commas */ if (next_token == G_TOKEN_RIGHT_CURLY) { priv->error_code = JSON_PARSER_ERROR_TRAILING_COMMA; json_object_unref (object); json_node_free (member); json_node_free (priv->current_node); priv->current_node = old_current; return G_TOKEN_RIGHT_BRACE; } } else if (next_token == G_TOKEN_STRING) { priv->error_code = JSON_PARSER_ERROR_MISSING_COMMA; json_object_unref (object); json_node_free (member); json_node_free (priv->current_node); priv->current_node = old_current; return G_TOKEN_COMMA; } JSON_NOTE (PARSER, "Object member '%s' completed", name); json_node_set_parent (member, priv->current_node); json_object_set_member (object, name, member); g_signal_emit (parser, parser_signals[OBJECT_MEMBER], 0, object, name); g_free (name); token = next_token; } json_scanner_get_next_token (scanner); json_node_take_object (priv->current_node, object); json_node_set_parent (priv->current_node, old_current); g_signal_emit (parser, parser_signals[OBJECT_END], 0, object); if (node != NULL && *node == NULL) *node = priv->current_node; priv->current_node = old_current; return G_TOKEN_NONE; }