Skip to content

Commit

Permalink
json validator implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
babongo committed Jun 29, 2010
1 parent 7b55406 commit c2f7aea
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 67 deletions.
33 changes: 33 additions & 0 deletions TODO
Expand Up @@ -8,6 +8,9 @@
- validation (light decoder) interface
- container (objects and arrays) iterators
* unit tests for new json interfaces (countinuous WIP)
- validator
- iterator
- ...
- valgrind tour

* return with error in setters (except value) when object is frozen
Expand All @@ -17,3 +20,33 @@
decide if a given name is (or isn't) fully qualified !

? json per-type getters

iterator layout:

{
u_json_it_t jit = NULL;

/* create a new iterator associated to json object jo
* (jo must have siblings, typically it's the first node of a
* container object) */

/* forward sequential scan of elements in container. */
u_json_it(u_json_first(jo), jit);
while ((cur = u_json_it_next(jit)) != NULL)
{
/* do something with 'cur' */
}


/* backwards -- starting from the 10th position -- sequential scan of
* elements in array */
u_json_it(u_json_array_get_nth(jo, 10), jit);
while ((cur = u_json_it_prev(jit)) != NULL)
{
/* do something with 'cur' */
}




}
11 changes: 8 additions & 3 deletions example/json/main.c
Expand Up @@ -10,9 +10,14 @@ int nested_object (void);

int main (void)
{
con_err_if (simple_object());
con_err_if (simple_array());
con_err_if (nested_object());
char status[U_LEXER_ERR_SZ];

//con_err_if (simple_object());
//con_err_if (simple_array());
//con_err_if (nested_object());

if (u_json_validate("{\"x\": }", status))
u_con("%s", status);

return EXIT_SUCCESS;
err:
Expand Down
150 changes: 86 additions & 64 deletions srcs/toolbox/json.c
Expand Up @@ -77,8 +77,10 @@ static void u_json_do_print (u_json_t *jo, size_t l, void *opaque);
static void u_json_do_free (u_json_t *jo, size_t l, void *opaque);
static void u_json_do_index (u_json_t *jo, size_t l, void *map);

/* Encoder. */
/* Encode/Decode/Validate. */
static int u_json_do_encode (u_json_t *jo, u_string_t *s);
static int u_json_do_parse (const char *json, u_json_t **pjo,
char status[U_LEXER_ERR_SZ]);

/* Needed by hmap_easy* because we are storing pointer data not owned by the
* hmap. */
Expand Down Expand Up @@ -284,46 +286,7 @@ int u_json_add (u_json_t *head, u_json_t *jo)
*/
int u_json_decode (const char *json, u_json_t **pjo)
{
u_json_t *jo = NULL;
u_lexer_t *jl = NULL;

dbg_return_if (json == NULL, ~0);
dbg_return_if (pjo == NULL, ~0);

/* Create a disposable lexer context associated to the supplied
* 'json' string. */
warn_err_if (u_lexer_new(json, &jl));

/* Create top level json object. */
warn_err_if (u_json_new(&jo));

/* Consume any trailing white space before starting actual parsing. */
if (u_lexer_eat_ws(jl) == -1)
U_LEXER_ERR(jl, "Empty JSON text !");

/* Launch the lexer expecting the input JSON text as a serialized object
* or array. */
if (u_json_match_object_first(jl))
warn_err_if (u_json_match_object(jl, jo));
else if (u_json_match_array_first(jl))
warn_err_if (u_json_match_array(jl, jo));
else
{
U_LEXER_ERR(jl,
"Expecting \'{\' or \'[\', found \'%c\'.", u_lexer_peek(jl));
}

/* Dispose the lexer context. */
u_lexer_free(jl);

/* Copy out the broken down tree. */
*pjo = jo;

return 0;
err:
u_json_free(jo);
u_lexer_free(jl);
return ~0;
return u_json_do_parse(json, pjo, NULL);
}

/**
Expand All @@ -341,9 +304,8 @@ int u_json_decode (const char *json, u_json_t **pjo)
*/
int u_json_validate (const char *json, char status[U_LEXER_ERR_SZ])
{
u_unused_args(json, status);
u_info("TODO");
return ~0;
/* Just try to validate the input string (do not build the tree). */
return u_json_do_parse(json, NULL, status);
}

/**
Expand Down Expand Up @@ -857,8 +819,8 @@ static int u_json_do_encode (u_json_t *jo, u_string_t *s)

static int u_json_match_value (u_lexer_t *jl, u_json_t *jo)
{
/* 'jo' can be NULL in case of a validating-only parser. */
dbg_return_if (jl == NULL, ~0);
dbg_return_if (jo == NULL, ~0);

if (u_json_match_string_first(jl))
warn_err_if (u_json_match_string(jl, jo));
Expand All @@ -875,10 +837,7 @@ static int u_json_match_value (u_lexer_t *jl, u_json_t *jo)
else if (u_json_match_null_first(jl))
warn_err_if (u_json_match_null(jl, jo));
else
{
U_LEXER_ERR(jl, "unexpected value syntax at \'%s\'",
u_lexer_lookahead(jl));
}
U_LEXER_ERR(jl, "value not found at \'%s\'", u_lexer_lookahead(jl));

return 0;
err:
Expand Down Expand Up @@ -960,8 +919,11 @@ static int u_json_match_number (u_lexer_t *jl, u_json_t *jo)
match[strlen(match) - 1] = '\0';

/* Push the matched number into the supplied json object. */
warn_err_if (u_json_set_type(jo, U_JSON_TYPE_NUMBER));
warn_err_if (u_json_set_val(jo, match));
if (jo)
{
warn_err_if (u_json_set_type(jo, U_JSON_TYPE_NUMBER));
warn_err_if (u_json_set_val(jo, match));
}

#ifdef U_JSON_LEX_DEBUG
u_con("matched number: %s", u_lexer_get_match(jl, match));
Expand Down Expand Up @@ -1085,7 +1047,8 @@ static int u_json_match_seq (u_lexer_t *jl, u_json_t *jo, int type,
/* Consume last checked char. */
U_LEXER_SKIP(jl, NULL);

warn_err_if (u_json_set_type(jo, type));
if (jo)
warn_err_if (u_json_set_type(jo, type));

#ifdef U_JSON_LEX_DEBUG
u_con("matched \'%s\' sequence", u_json_type_str(type));
Expand Down Expand Up @@ -1137,16 +1100,22 @@ static int u_json_match_array (u_lexer_t *jl, u_json_t *jo)
if (c == ']') /* break on empty array */
break;

/* Create a new object to store next array element. */
warn_err_if (u_json_new(&elem));
warn_err_if (u_json_set_type(elem, U_JSON_TYPE_UNKNOWN));
if (jo)
{
/* Create a new object to store next array element. */
warn_err_if (u_json_new(&elem));
warn_err_if (u_json_set_type(elem, U_JSON_TYPE_UNKNOWN));
}

/* Fetch new value. */
warn_err_if (u_json_match_value(jl, elem));

/* Push the fetched element to its parent array. */
warn_err_if (u_json_add(jo, elem));
elem = NULL;
if (jo)
{
/* Push the fetched element to its parent array. */
warn_err_if (u_json_add(jo, elem));
elem = NULL;
}

/* Consume any trailing white spaces. */
if (isspace(u_lexer_peek(jl)))
Expand Down Expand Up @@ -1183,7 +1152,8 @@ static int u_json_match_object (u_lexer_t *jl, u_json_t *jo)
c, u_lexer_lookahead(jl));
}

warn_err_if (u_json_set_type(jo, U_JSON_TYPE_OBJECT));
if (jo)
warn_err_if (u_json_set_type(jo, U_JSON_TYPE_OBJECT));

do {
U_LEXER_SKIP(jl, &c);
Expand Down Expand Up @@ -1222,7 +1192,6 @@ static int u_json_match_pair (u_lexer_t *jl, u_json_t *jo)
u_json_t *pair = NULL;

dbg_return_if (jl == NULL, ~0);
dbg_return_if (jo == NULL, ~0);

#ifdef U_JSON_LEX_DEBUG
u_con("PAIR");
Expand All @@ -1233,15 +1202,17 @@ static int u_json_match_pair (u_lexer_t *jl, u_json_t *jo)
warn_err_if (u_json_match_string(jl, NULL));

/* Initialize new json object to store the key/value pair. */
warn_err_if (u_json_new(&pair));
if (jo)
warn_err_if (u_json_new(&pair));

(void) u_lexer_get_match(jl, match);

/* Trim trailing '"'. */
if ((mlen = strlen(match)) >= 1)
match[mlen - 1] = '\0';

warn_err_if (u_json_set_key(pair, match));
if (jo)
warn_err_if (u_json_set_key(pair, match));

/* Consume ':' */
if ((c = u_lexer_peek(jl)) != ':')
Expand All @@ -1256,8 +1227,11 @@ static int u_json_match_pair (u_lexer_t *jl, u_json_t *jo)
warn_err_if (u_json_match_value(jl, pair));

/* Push the new value to the parent json object. */
warn_err_if (u_json_add(jo, pair));
pair = NULL;
if (jo)
{
warn_err_if (u_json_add(jo, pair));
pair = NULL;
}

return 0;
err:
Expand Down Expand Up @@ -1512,3 +1486,51 @@ static int u_json_new_atom (u_json_type_t type, const char *key,
return ~0;
}

static int u_json_do_parse (const char *json, u_json_t **pjo,
char status[U_LEXER_ERR_SZ])
{
u_json_t *jo = NULL;
u_lexer_t *jl = NULL;

dbg_return_if (json == NULL, ~0);

/* Create a disposable lexer context associated to the supplied
* 'json' string. */
warn_err_if (u_lexer_new(json, &jl));

/* When 'pjo' is NULL, assume this is a validating-only parser. */

/* Create top level json object. */
warn_err_if (pjo && u_json_new(&jo));

/* Consume any trailing white space before starting actual parsing. */
if (u_lexer_eat_ws(jl) == -1)
U_LEXER_ERR(jl, "Empty JSON text !");

/* Launch the lexer expecting the input JSON text as a serialized object
* or array. */
if (u_json_match_object_first(jl))
warn_err_if (u_json_match_object(jl, jo));
else if (u_json_match_array_first(jl))
warn_err_if (u_json_match_array(jl, jo));
else
U_LEXER_ERR(jl, "Expect \'{\' or \'[\', got \'%c\'.", u_lexer_peek(jl));

/* Dispose the lexer context. */
u_lexer_free(jl);

/* Copy out the broken down tree. */
if (pjo)
*pjo = jo;

return 0;
err:
/* Copy out the lexer error string (if requested). */
if (status)
(void) u_strlcpy(status, u_lexer_geterr(jl), U_LEXER_ERR_SZ);

u_lexer_free(jl);
u_json_free(jo);

return ~0;
}

0 comments on commit c2f7aea

Please sign in to comment.