From 9aa281539d5b3cc2c4424f2d61c56ef625b04345 Mon Sep 17 00:00:00 2001 From: kanoi Date: Sat, 24 Jan 2015 13:28:55 +1100 Subject: [PATCH] ckdb - direct code a json decode replacement for breakdown() --- src/ckdb.c | 287 +++++++++++++++++++++++++++++++++-------------------- src/ckdb.h | 11 +- 2 files changed, 190 insertions(+), 108 deletions(-) diff --git a/src/ckdb.c b/src/ckdb.c index 6337d190..1158e248 100644 --- a/src/ckdb.c +++ b/src/ckdb.c @@ -1233,9 +1233,10 @@ static enum cmd_values breakdown(K_TREE **trf_root, K_STORE **trf_store, TRANSFER *transfer; K_TREE_CTX ctx[1]; K_ITEM *item; - char *cmdptr, *idptr, *next, *eq; - char *data = NULL; + char *cmdptr, *idptr, *next, *eq, *end, *was; + char *data = NULL, *tmp; bool noid = false; + size_t siz; *trf_root = NULL; *trf_store = NULL; @@ -1284,122 +1285,192 @@ static enum cmd_values breakdown(K_TREE **trf_root, K_STORE **trf_store, *trf_store = k_new_store(transfer_free); next = data; if (next && strncmp(next, JSON_TRANSFER, JSON_TRANSFER_LEN) == 0) { - json_t *json_data; - json_error_t err_val; - void *json_iter; - const char *json_key, *json_str; - json_t *json_value; - int json_typ; - size_t siz; - bool ok; - + // It's json next += JSON_TRANSFER_LEN; - json_data = json_loads(next, JSON_DISABLE_EOF_CHECK, &err_val); - if (!json_data) { - /* This REALLY shouldn't ever get an error since the input - * is a json generated string - * If that happens then dump lots of information */ - char *text = safe_text(next); - LOGERR("Json decode error from command: '%s' " - "json_err=(%d:%d:%d)%s:%s input='%s'", - cmd, err_val.line, err_val.column, - err_val.position, err_val.source, - err_val.text, text); - free(text); + was = next; + while (*next == ' ') + next++; + if (*next != JSON_BEGIN) { + LOGERR("JSON_BEGIN '%c' was: %.32s...", + JSON_BEGIN, tmp = safe_text(was)); + free(tmp); free(cmdptr); return CMD_REPLY; } - json_iter = json_object_iter(json_data); - K_WLOCK(transfer_free); - while (json_iter) { - json_key = json_object_iter_key(json_iter); - json_value = json_object_iter_value(json_iter); + next++; + // while we have a new quoted name + while (*next == JSON_STR) { + was = next; + end = ++next; + // look for the end quote + while (*end && *end != JSON_STR) { + if (*(end++) == JSON_ESC) + end++; + } + if (!*end) { + LOGERR("JSON name no trailing '%c' was: %.32s...", + JSON_STR, tmp = safe_text(was)); + free(tmp); + free(cmdptr); + return CMD_REPLY; + } + if (next == end) { + LOGERR("JSON zero length name was: %.32s...", + tmp = safe_text(was)); + free(tmp); + free(cmdptr); + return CMD_REPLY; + } + *(end++) = '\0'; + K_WLOCK(transfer_free); item = k_unlink_head(transfer_free); + K_WUNLOCK(transfer_free); DATA_TRANSFER(transfer, item); - ok = true; - json_typ = json_typeof(json_value); - switch (json_typ) { - case JSON_STRING: - json_str = json_string_value(json_value); - siz = strlen(json_str); - if (siz >= sizeof(transfer->svalue)) - transfer->mvalue = strdup(json_str); - else { - STRNCPY(transfer->svalue, json_str); - transfer->mvalue = transfer->svalue; + STRNCPY(transfer->name, next); + was = next = end; + while (*next == ' ') + next++; + // we have a name, now expect a value after it + if (*next != JSON_VALUE) { + LOGERR("JSON_VALUE '%c' '%s' was: %.32s...", + JSON_VALUE, transfer->name, + tmp = safe_text(was)); + free(tmp); + free(cmdptr); + K_WLOCK(transfer_free); + k_add_head(transfer_free, item); + K_WUNLOCK(transfer_free); + return CMD_REPLY; + } + was = ++next; + while (*next == ' ') + next++; + if (*next == JSON_STR) { + end = ++next; + // A quoted value must have a terminating quote + while (*end && *end != JSON_STR) { + if (*(end++) == JSON_ESC) + end++; } - break; - case JSON_REAL: - snprintf(transfer->svalue, - sizeof(transfer->svalue), - "%f", json_real_value(json_value)); - transfer->mvalue = transfer->svalue; - break; - case JSON_INTEGER: - snprintf(transfer->svalue, - sizeof(transfer->svalue), - "%"PRId64, - (int64_t)json_integer_value(json_value)); - transfer->mvalue = transfer->svalue; - break; - case JSON_TRUE: - case JSON_FALSE: - snprintf(transfer->svalue, - sizeof(transfer->svalue), - "%s", (json_typ == JSON_TRUE) ? - TRUE_STR : FALSE_STR); - transfer->mvalue = transfer->svalue; - break; - case JSON_ARRAY: - { - /* only one level array of strings for now (merkletree) - * ignore other data */ - size_t i, len, off, count = json_array_size(json_value); - json_t *json_element; - bool first = true; - - APPEND_REALLOC_INIT(transfer->mvalue, off, len); - for (i = 0; i < count; i++) { - json_element = json_array_get(json_value, i); - if (json_is_string(json_element)) { - json_str = json_string_value(json_element); - siz = strlen(json_str); - if (first) - first = false; - else { - APPEND_REALLOC(transfer->mvalue, - off, len, " "); - } - APPEND_REALLOC(transfer->mvalue, - off, len, json_str); - } else - LOGERR("%s() unhandled json type %d in array %s" - " in cmd %s", __func__, - json_typ, json_key, cmd); - } + if (!*end) { + LOGERR("JSON '%s' value was: %.32s...", + transfer->name, + tmp = safe_text(was)); + free(tmp); + free(cmdptr); + K_WLOCK(transfer_free); + k_add_head(transfer_free, item); + K_WUNLOCK(transfer_free); + return CMD_REPLY; } - break; - default: - LOGERR("%s() unhandled json type %d in cmd %s", - __func__, json_typ, cmd); - ok = false; - break; + if (end <= next+1) { + LOGERR("JSON '%s' zero length value " + "was: %.32s...", + transfer->name, + tmp = safe_text(was)); + free(tmp); + free(cmdptr); + K_WLOCK(transfer_free); + k_add_head(transfer_free, item); + K_WUNLOCK(transfer_free); + return CMD_REPLY; + } + siz = end - next; + end++; + } else if (*next == JSON_ARRAY) { + // Only merklehash for now + if (strcmp(transfer->name, "merklehash")) { + LOGERR("JSON '%s' can't be an array", + transfer->name); + free(cmdptr); + K_WLOCK(transfer_free); + k_add_head(transfer_free, item); + K_WUNLOCK(transfer_free); + return CMD_REPLY; + } + end = ++next; + /* No structure testing for now since we + * don't expect merklehash to get it wrong, + * and if it does, it will show up as some + * other error anyway */ + while (*end && *end != JSON_ARRAY_END) + end++; + if (end < next+1) { + LOGERR("JSON '%s' zero length value " + "was: %.32s...", + transfer->name, + tmp = safe_text(was)); + free(tmp); + free(cmdptr); + K_WLOCK(transfer_free); + k_add_head(transfer_free, item); + K_WUNLOCK(transfer_free); + return CMD_REPLY; + } + siz = end - next; + end++; + } else { + end = next; + // A non quoted value ends on SEP, END or space + while (*end && *end != JSON_SEP && + *end != JSON_END && *end != ' ') { + end++; + } + if (!*end) { + LOGERR("JSON '%s' value was: %.32s...", + transfer->name, + tmp = safe_text(was)); + free(tmp); + free(cmdptr); + K_WLOCK(transfer_free); + k_add_head(transfer_free, item); + K_WUNLOCK(transfer_free); + return CMD_REPLY; + } + if (next == end) { + LOGERR("JSON '%s' zero length value " + "was: %.32s...", + transfer->name, + tmp = safe_text(was)); + free(tmp); + free(cmdptr); + K_WLOCK(transfer_free); + k_add_head(transfer_free, item); + K_WUNLOCK(transfer_free); + return CMD_REPLY; + } + siz = end - next; } - - if (ok) - STRNCPY(transfer->name, json_key); - if (!ok || find_in_ktree(*trf_root, item, cmp_transfer, ctx)) { - if (transfer->mvalue != transfer->svalue) - FREENULL(transfer->mvalue); - k_add_head(transfer_free, item); + if (siz >= sizeof(transfer->svalue)) { + transfer->mvalue = malloc(siz+1); + STRNCPYSIZ(transfer->mvalue, next, siz+1); } else { - *trf_root = add_to_ktree(*trf_root, item, cmp_transfer); - k_add_head(*trf_store, item); + STRNCPYSIZ(transfer->svalue, next, siz+1); + transfer->mvalue = transfer->svalue; + } + *trf_root = add_to_ktree(*trf_root, item, cmp_transfer); + k_add_head(*trf_store, item); + + // find the separator then move to the next name + next = end; + while (*next == ' ') + next++; + if (*next == JSON_SEP) { + next++; + while (*next == ' ') + next++; } - json_iter = json_object_iter_next(json_data, json_iter); } - K_WUNLOCK(transfer_free); - json_decref(json_data); + if (*next != JSON_END) { + LOGERR("JSON_END '%c' was: %.32s...", + JSON_END, tmp = safe_text(next)); + free(tmp); + free(cmdptr); + K_WLOCK(transfer_free); + k_add_head(transfer_free, item); + K_WUNLOCK(transfer_free); + return CMD_REPLY; + } } else { K_WLOCK(transfer_free); while (next && *next) { @@ -1433,8 +1504,10 @@ static enum cmd_values breakdown(K_TREE **trf_root, K_STORE **trf_store, } if (ckdb_cmds[*which_cmds].createdate) { item = require_name(*trf_root, "createdate", 10, NULL, reply, sizeof(reply)); - if (!item) + if (!item) { + free(cmdptr); return CMD_REPLY; + } DATA_TRANSFER(transfer, item); txt_to_ctv("createdate", transfer->mvalue, cd, sizeof(*cd)); diff --git a/src/ckdb.h b/src/ckdb.h index 27c3a55a..f50ea45d 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -52,7 +52,7 @@ #define DB_VLOCK "1" #define DB_VERSION "0.9.6" -#define CKDB_VERSION DB_VERSION"-0.841" +#define CKDB_VERSION DB_VERSION"-0.900" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -268,6 +268,15 @@ extern bool everyone_die; #define JSON_TRANSFER "json=" #define JSON_TRANSFER_LEN (sizeof(JSON_TRANSFER)-1) +#define JSON_BEGIN '{' +// Arrays have limited support in breakdown() +#define JSON_ARRAY '[' +#define JSON_ARRAY_END ']' +#define JSON_STR '"' +#define JSON_VALUE ':' +#define JSON_SEP ',' +#define JSON_END '}' +#define JSON_ESC '\\' // Methods for sharelog (common function for all) #define STR_WORKINFO "workinfo"