diff options
Diffstat (limited to 'lib/dtree_utils.c')
-rw-r--r-- | lib/dtree_utils.c | 264 |
1 files changed, 171 insertions, 93 deletions
diff --git a/lib/dtree_utils.c b/lib/dtree_utils.c index 082ece3..3d1c394 100644 --- a/lib/dtree_utils.c +++ b/lib/dtree_utils.c @@ -1,129 +1,207 @@ #include <dtree/dtree.h> #include <stdio.h> +#include <malloc.h> #include <stdlib.h> -void pk_string_trim(char *src, char *dst); +#include "jsmn.h" -dt_err dtree_decode_json(dtree *(*data), const char *json_data) -{ - enum parse_state { - VALUE, HASH, LIST, WAITING - }; - -#define BUF_SIZE 256 - - /* Save some space for a token */ - const char *delims = ",:"; - char *parse; - char curr_key[BUF_SIZE]; - char curr_val[BUF_SIZE]; - dtree *root, *curr_root; - enum parse_state state = WAITING; +#define DTREE_TOK_BOOLEAN (1 << 1) +#define DTREE_TOK_NUMERICAL (1 << 2) +#define DTREE_TOK_LITERAL (1 << 3) - /* Prepare environment for parsing */ - char json_buf[REAL_STRLEN(json_data)]; - strcpy(json_buf, json_data); - /* Setup root dtree node */ - dtree_malloc(&root); - curr_root = root; +char *tok_to_str(jsmntype_t *tok) +{ + switch(*tok) { + case JSMN_UNDEFINED: return "UNDEFINED"; + case JSMN_OBJECT: return "OBJECT"; + case JSMN_ARRAY: return "ARRAY"; + case JSMN_STRING: return "STRING"; + case JSMN_PRIMITIVE: return "PRIMITIVE"; + default: return "UNKNOWN"; + } +} - /* Read in the first token */ - parse = strtok(json_buf, delims); - while(parse != NULL) { +int digest_payload(const char *token) +{ + char* end; + size_t len = strlen(token); - char tok[strlen(parse) + 1]; - memset(tok, 0, strlen(parse) + 1); + if(len == strlen("true") || len == strlen("false")) + if(strcmp(token, "true") == 0 || strcmp(token, "false") == 0) + return DTREE_TOK_BOOLEAN; - pk_string_trim(parse, tok); + /* It could still be a number! */ + strtol(token, &end, 10); + if (!*end) return DTREE_TOK_NUMERICAL; - /* Open a new hash context */ - if(tok[0] == '{') { + return DTREE_TOK_LITERAL; +} - dtree *new_root; - dtree_addlist(curr_root, &new_root); - curr_root = new_root; +dt_err dtree_decode_json(dtree *(*data), const char *json_data, size_t len) +{ + jsmn_parser parse; + jsmn_init(&parse); - printf("Creating new hash context...\n"); - state = HASH; - } + // FIXME: Variable amount of tokens? + jsmntok_t *tokens = malloc(sizeof(jsmntok_t) * len); + memset(tokens, 0, sizeof(jsmntok_t) * len); - /* Open a new list context - finishing a PAIR - Back to waiting */ - if(tok[0] == '[') { - printf("Creating new hash context...\n"); - state = LIST; - } + int ret = jsmn_parse(&parse, json_data, strlen(json_data), tokens, sizeof(tokens) / sizeof(tokens[0])); - /* If we're in a hash & waiting for a key */ - if(state == HASH) { - if(tok[0] == '{') strcpy(curr_key, tok + 1); - else strcpy(curr_key, tok); + jsmntok_t tok; + unsigned int idx = 0; - printf("Current Key: %s\n", curr_key); - state = VALUE; - goto END; - } + /** Prepare dtree nodes */ + dtree *root, *curr; + dtree_malloc(&root); + curr = root; - /* We already had a key - finishing up the pair */ - if(state == VALUE) { - strcpy(curr_val, tok); - printf("Current Val: %s\n", curr_val); + struct bounds { + int low, high; + }; - /* Copy pair into dtree structure */ - dtree *parent, *key, *val; - dtree_addlist(curr_root, &parent); + struct pair { + short state; +#define TOK_PAIR_KEYED 1 +#define TOK_PAIR_VALUED 2 + char key[1024]; + union value { + char string[1024]; + unsigned long num; + } value; + }; - /* Make the "parent" node into the pair parent */ - dtree_addpair(parent, &key, &val); - dtree_addliteral(key, curr_key); - dtree_addliteral(val, curr_val); + /* Save some space to store token bounds */ + struct bounds *bounds = malloc(sizeof(struct bounds) * len); + memset(bounds, 0, sizeof(struct bounds) * len); + int focused = -1; - /* Add the parent */ + struct pair c_pair; + memset(&c_pair, 0, sizeof(struct pair)); - /* Blank current pair data */ - memset(curr_key, 0, BUF_SIZE); - memset(curr_val, 0, BUF_SIZE); + while(tok = tokens[idx++], tok.type != NULL) { - state = HASH; - goto END; - } + size_t tok_len = (size_t) tok.end - tok.start; + char token[tok_len]; + memset(token, 0, tok_len); + memcpy(token, json_data + tok.start, tok_len); - if(state == LIST) { - dtree *child; - dtree_addlist(curr_root, &child); - dtree_addliteral(child, tok); + /** Check if we need to move the boundry scope (again) */ + if(focused > 0 && tok.end >= bounds[focused].high) { + focused--; - size_t chs = strlen(tok); - dtree *parent; + /* Because of how our root node is a VALUE node, we need the parents parent */ + dtree *parent, *pair_parent; + dtree_parent(root, curr, &parent); + dtree_parent(root, parent, &pair_parent); - dtree_parent(root, curr_root, &parent); - if(tok[chs] == ']') { - curr_root = parent; - state = HASH; - } + /* Assign the new root node - old scope restored */ + curr = pair_parent; } - printf(" Recognised token: %s\n", tok); - END: - parse = strtok(NULL, delims); - } + switch(tok.type) { + + /** + * When we encounter a new json object, shift our "focus" over by one so we can + * record in what range this object is going to accumilate tokens. + * + * We then create a new child node under the current root node and switch the + * curr root pointer over to that child. + * + * When we reach the end of the token scope, we need to re-reference the parent as + * current root and switch over our boundry scope as well. This is done before the + * parsing switch statement. + */ + case JSMN_OBJECT: + { + focused++; + bounds[focused].low = tok.start; + bounds[focused].high = tok.end; + + /** + * Most of the time, we will create a new object under the key of + * a pair. This is the case, when the c_pair state buffer has been + * set to KEYED. In this case we allocate a new pair node for key + * and value and set that value to the new root. + */ + if(c_pair.state == TOK_PAIR_KEYED) { + + /* Create pair nodes & new_root which becomes curr */ + dtree *pair, *key, *val; + dtree_addlist(curr, &pair); + dtree_addpair(pair, &key, &val); + + /* Assign key and new_root as a value of the pair */ + dtree_addliteral(key, c_pair.key); + + /* Move curr root pointer */ + curr = val; + + /* Blank c_pair data for next tokens */ + memset(&c_pair, 0, sizeof(struct pair)); + + } + + /* Skip to next token */ + continue; + } - return SUCCESS; -} + case JSMN_STRING: + { + /** + * Here we need to check if we are adding a string as a key + * or as a value. This is simply done by checking for the existance + * of a key in the c_pair (current pair) variable. + * + * We know the token positions so we can manualy copy from the json stream + */ + if(c_pair.state == 0) { + memcpy(c_pair.key, json_data + tok.start, (size_t) tok.end - tok.start); + c_pair.state = TOK_PAIR_KEYED; + + } else if(c_pair.state == TOK_PAIR_KEYED){ + + /** Create a PAIR node under current root */ + dtree *pair, *key, *val; + dtree_addlist(curr, &pair); + dtree_addpair(pair, &key, &val); + + /* Key is always literal */ + dtree_addliteral(key, c_pair.key); + + /* Parse payload and asign to value node */ + switch(digest_payload(token)) { + case DTREE_TOK_LITERAL: + dtree_addliteral(val, token); + break; + + case DTREE_TOK_NUMERICAL: + dtree_addnumeral(val, atol(token)); + break; + + default: continue; + } + + /* Blank c_pair data for next tokens */ + memset(&c_pair, 0, sizeof(struct pair)); + } + + /* Skip to next token */ + continue; + } -/************************************************************/ -void pk_string_trim(char *src, char *dst) -{ - int s, d=0; - for (s=0; src[s] != 0; s++) - if (src[s] != ' ') { - dst[d] = src[s]; - d++; + default: + continue; } - dst[d] = 0; + } + + /* Switch over data pointer and return */ + (*data) = root; + return SUCCESS; }
\ No newline at end of file |