static int test3(void) { size_t i; int ret; char err[512] = { 0 }; const char in_str[] = "{ \"a\": 1, \"b\": 2.500000, " "\"c\": \"hi there\", \"d\": { \"a\": 0 }, " "\"e\": false, \"f\": [ { \"a\": 1 }, " "{ \"a\": 2 } ], \"x\" : 5, \"y\" : 1.5 }"; int expected_array_val[] = { 1, 2, 6 }; struct json_object* jo = NULL; struct bob *my_bob = NULL; struct abbie* final_abbie; jo = parse_json_string(in_str, err, sizeof(err)); if (err[0]) { fprintf(stderr, "parse_json_string error: %s\n", err); ret = EXIT_FAILURE; goto done; } my_bob = JORM_FROMJSON_bob(jo); if (!my_bob) { fprintf(stderr, "JORM_FROMJSON: OOM\n"); ret = EXIT_FAILURE; goto done; } ret = 0; EXPECT_NONZERO(my_bob->a == 1); EXPECT_NONZERO(my_bob->b == 2.5); EXPECT_ZERO(my_bob->extra_data); final_abbie = JORM_ARRAY_APPEND_abbie(&my_bob->f); EXPECT_NOT_EQUAL(final_abbie, NULL); final_abbie->a = 6; for (i = 0; i < sizeof(expected_array_val) / sizeof(expected_array_val[0]); ++i) { EXPECT_EQUAL(my_bob->f[i]->a, expected_array_val[i]); } EXPECT_EQUAL(my_bob->g->x, 5); EXPECT_EQUAL(my_bob->g->y, 1.5); done: if (jo) { json_object_put(jo); jo = NULL; } if (my_bob) { JORM_FREE_bob(my_bob); my_bob = NULL; } return ret; }
// Allow object keys to be without quotation, // but then restrict to ([a-zA-Z0-9_])+ bool JSON::parse_json_key() { const char* begin; JSON_VAL v; u_char c; mark_pos(); c = peek(); if (c == '"') { return parse_json_string(true); } begin = pos; c = peek(); if (c == 0) { error(SYNTAX_ERROR, "Got EOS when expecting an object key."); return false; } else if (is_word(c) == false) { error(SYNTAX_ERROR, "Expected an object key, which can be a double-quoted (\") string or a simple string (only alphanumeric characters and underscore, separated by whitespace) that doesn't need to be quoted."); return false; } for (;;) { c = peek(); // Allow the key to be delimited by control characters and the object key-value separator ':' if (c <= ' ' || c == ':') { break; } else if (is_word(c) == false) { error(SYNTAX_ERROR, "Object key need to be quoted, or consist entirely of alphanumeric characters and underscores."); return false; } next(); } v.str.start = begin; v.str.length = pos - begin; return callback(JSON_KEY, &v, level); }
bool JSON::parse_json_value() { int c; c = skip_to_token(); if (c == -1) { return false; } // Must start with object or array if (level == 0) { switch (c) { case '{': if (parse_json_object() == false) { return false; } c = skip_to_token(); if (c > 0) { mark_pos(); error(SYNTAX_ERROR, "Only one top level object/array is allowed."); return false; } else if (c < 0) { return false; } return true; case '[': if (parse_json_array() == false) { return false; } c = skip_to_token(); if (c > 0) { mark_pos(); error(SYNTAX_ERROR, "Only one top level object/array is allowed."); return false; } else if (c < 0) { return false; } return true; case 0: error(SYNTAX_ERROR, "EOS was encountered before any json declarations"); return false; default: error(SYNTAX_ERROR, "Json must start with an object or an array."); return false; } } else { // level > 0 switch (c) { case '{': return parse_json_object(); case '[': return parse_json_array(); case '"': return parse_json_string(); case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return parse_json_number(); case 't': return parse_json_symbol("true", JSON_TRUE); case 'f': return parse_json_symbol("false", JSON_FALSE); case 'n': return parse_json_symbol("null", JSON_NULL); case 0: error(SYNTAX_ERROR, "EOS was encountered when expecting a json value."); return false; default: error(SYNTAX_ERROR, "Could not parse as a json value (did you forget to quote your strings?)."); return false; } } }
/* ECMA-262 5.1 Edition 15.12.1.2 */ static HRESULT parse_json_value(json_parse_ctx_t *ctx, jsval_t *r) { HRESULT hres; switch(skip_spaces(ctx)) { /* JSONNullLiteral */ case 'n': if(!is_keyword(ctx, nullW)) break; *r = jsval_null(); return S_OK; /* JSONBooleanLiteral */ case 't': if(!is_keyword(ctx, trueW)) break; *r = jsval_bool(TRUE); return S_OK; case 'f': if(!is_keyword(ctx, falseW)) break; *r = jsval_bool(FALSE); return S_OK; /* JSONObject */ case '{': { WCHAR *prop_name; jsdisp_t *obj; jsval_t val; hres = create_object(ctx->ctx, NULL, &obj); if(FAILED(hres)) return hres; ctx->ptr++; if(skip_spaces(ctx) == '}') { ctx->ptr++; *r = jsval_obj(obj); return S_OK; } while(1) { if(*ctx->ptr != '"') break; hres = parse_json_string(ctx, &prop_name); if(FAILED(hres)) break; if(skip_spaces(ctx) != ':') { FIXME("missing ':'\n"); heap_free(prop_name); break; } ctx->ptr++; hres = parse_json_value(ctx, &val); if(SUCCEEDED(hres)) { hres = jsdisp_propput_name(obj, prop_name, val); jsval_release(val); } heap_free(prop_name); if(FAILED(hres)) break; if(skip_spaces(ctx) == '}') { ctx->ptr++; *r = jsval_obj(obj); return S_OK; } if(*ctx->ptr++ != ',') { FIXME("expected ','\n"); break; } skip_spaces(ctx); } jsdisp_release(obj); break; } /* JSONString */ case '"': { WCHAR *string; jsstr_t *str; hres = parse_json_string(ctx, &string); if(FAILED(hres)) return hres; /* FIXME: avoid reallocation */ str = jsstr_alloc(string); heap_free(string); if(!str) return E_OUTOFMEMORY; *r = jsval_string(str); return S_OK; } /* JSONArray */ case '[': { jsdisp_t *array; unsigned i = 0; jsval_t val; hres = create_array(ctx->ctx, 0, &array); if(FAILED(hres)) return hres; ctx->ptr++; if(skip_spaces(ctx) == ']') { ctx->ptr++; *r = jsval_obj(array); return S_OK; } while(1) { hres = parse_json_value(ctx, &val); if(FAILED(hres)) break; hres = jsdisp_propput_idx(array, i, val); jsval_release(val); if(FAILED(hres)) break; if(skip_spaces(ctx) == ']') { ctx->ptr++; *r = jsval_obj(array); return S_OK; } if(*ctx->ptr != ',') { FIXME("expected ','\n"); break; } ctx->ptr++; i++; } jsdisp_release(array); break; } /* JSONNumber */ default: { int sign = 1; double n; if(*ctx->ptr == '-') { sign = -1; ctx->ptr++; skip_spaces(ctx); } if(!isdigitW(*ctx->ptr)) break; if(*ctx->ptr == '0') { ctx->ptr++; n = 0; if(is_identifier_char(*ctx->ptr)) break; }else { hres = parse_decimal(&ctx->ptr, ctx->end, &n); if(FAILED(hres)) return hres; } *r = jsval_number(sign*n); return S_OK; } } FIXME("Syntax error at %s\n", debugstr_w(ctx->ptr)); return E_FAIL; }
static int test5(void) { int ret; char acc[512] = { 0 }, err[512] = { 0 }; struct json_object *jo = NULL; const char in_str[] = "{ \"a\": \"1\", \"b\": 2.500000, " "\"c\": 5.0, \"d\": { \"a\": false }, " "\"e\": false, \"f\": [ { \"a\": 1 }, " "{ \"a\": 2 } ], \"x\" : 5, \"y\" : 1 }"; const char in_str2[] = "{ \"d\": false, \"f\" : 1 }"; const char in_str3[] = "{ \"f\" : [ { \"a\" : 2.5 }, 1 ] }"; jo = parse_json_string(in_str, err, sizeof(err)); if (err[0]) { fprintf(stderr, "parse_json_string error: %s\n", err); ret = EXIT_FAILURE; goto done; } JORM_TYCHECK_bob(jo, acc, sizeof(acc), err, sizeof(err)); EXPECT_ZERO(strcmp(err, "WARNING: ignoring field \"a\" because " "it has type string, but it should have type int.\n" "WARNING: ignoring field \"c\" because it has type double, " "but it should have type string.\n" "WARNING: ignoring field \"d/a\" because it has type boolean, " "but it should have type int.\n" "WARNING: ignoring field \"y\" because it has type int, " "but it should have type double.\n")); acc[0] = '\0'; err[0] = '\0'; json_object_put(jo); jo = parse_json_string(in_str2, err, sizeof(err)); if (err[0]) { fprintf(stderr, "parse_json_string2 error: %s\n", err); ret = EXIT_FAILURE; goto done; } JORM_TYCHECK_bob(jo, acc, sizeof(acc), err, sizeof(err)); EXPECT_ZERO(strcmp(err, "WARNING: ignoring field \"d\" because " "it has type boolean, but it should have type object.\n" "WARNING: ignoring field \"f\" because it has type " "int, but it should have type array.\n")); acc[0] = '\0'; err[0] = '\0'; json_object_put(jo); jo = parse_json_string(in_str3, err, sizeof(err)); if (err[0]) { fprintf(stderr, "parse_json_string3 error: %s\n", err); ret = EXIT_FAILURE; goto done; } JORM_TYCHECK_bob(jo, acc, sizeof(acc), err, sizeof(err)); EXPECT_ZERO(strcmp(err, "WARNING: ignoring field \"f[0]/a\" because " "it has type double, but it should have type int.\n" "WARNING: ignoring field \"f[1]\" because " "it has type array, but it should have type int.\n")); ret = 0; done: if (jo) json_object_put(jo); return 0; }