#include #include #include #include #include "internal.h" //inline static size_t hash(const char *key) { //if (!key) //return 0; //size_t ret = 5381; //for (const char *p = key; *p != '\0'; p++) { //ret = ((ret << 5) + ret) + *p; //} //return ret; //} void add_to_object(struct json *dest, char *key, struct json *src) { assert(dest->type == JSON_OBJECT); assert(key); assert(src); src->key = (free(src->key), key); //src->index = hash(src->key) % dest->children->maxitems; for (size_t i = 0; i < dest->children->nitems; i++) { struct json *e = dest->children->items[i]; if (strcmp(e->key, key) == 0) { src->index = e->index; dest->children->items[i] = src; src->parent = dest; src->prev = e->prev; src->next = e->next; if (e->prev) e->prev->next = src; if (e->next) e->next->prev = src; json_clear(e); free(e); return; } } add_children(dest, src); } struct json *json_new_object(void) { struct json *json = json_new(); json->type = JSON_OBJECT; init_children(json); return json; } enum json_parse_result parse_object(struct json **json_out, struct raw_json *raw, size_t depth) { assert(raw->data[raw->index] == '{'); enum json_parse_result ret = JSON_PARSE_OK; struct json *json = NULL; struct json *obj = NULL; char *key = NULL; bool empty = true; if (depth++ > 9) { ret = JSON_PARSE_MAX_DEPTH_ERR; goto err; } json = json_new_object(); if (!json) return JSON_OOM; do { raw->index++; skip_ws(raw); if (raw->data[raw->index] == '}') { if (empty) { break; } ret = JSON_PARSE_EXPECTED_VALUE_ERR; goto err; } if (raw->data[raw->index] != '"') { ret = JSON_PARSE_OBJECT_INVALID_KEY_ERR; goto err; } ret = parse_raw_string(&key, raw); if (ret != JSON_PARSE_OK) { goto err; } skip_ws(raw); if (raw->data[raw->index] != ':') { ret = JSON_PARSE_OBJECT_EXPECTED_VALUE_ERR; goto err; } raw->index++; skip_ws(raw); ret = parse_value(&obj, raw, depth); if (ret != JSON_PARSE_OK) { goto err; } add_to_object(json, key, obj); empty = false; skip_ws(raw); obj = NULL; key = NULL; } while (raw->index < raw->size && raw->data[raw->index] == ','); if (raw->data[raw->index] != '}') { ret = JSON_PARSE_INVALID_TOKEN_ERR; goto err; } raw->index++; *json_out = json; goto end; err: json_clear(json); json_clear(obj); end: return ret; } bool json_object_add(struct json *dest, const char *key, struct json *src) { if (!dest || !key || !src) return false; add_to_object(dest, strdup(key), src); return true; } struct json *json_object_get(const struct json *obj, const char *key) { if (obj->type != JSON_OBJECT) return NULL; struct json *j = NULL; json_foreach(j, obj) { if (strcmp(j->key, key) == 0) break; } return j; } struct json *json_object_getn(const struct json *obj, const char *key, size_t n) { if (obj->type != JSON_OBJECT) return NULL; struct json *j = NULL; json_foreach(j, obj) { if (strncmp(j->key, key, n) == 0) break; } return j; } struct json *json_object_add_object(struct json *dest, const char *key) { struct json *obj = json_new_object(); json_object_add(dest, key, obj); return obj; } struct json *json_object_add_array(struct json *dest, const char *key) { struct json *array = json_new_array(); json_object_add(dest, key, array); return array; } struct json *json_object_add_number(struct json *dest, const char *key, double num) { struct json *number = json_new_number(num); json_object_add(dest, key, number); return number; } struct json *json_object_add_string(struct json *dest, const char *key, const char *string) { struct json *str = json_new_string_copy(string); json_object_add(dest, key, str); return str; } struct json *json_object_add_bool(struct json *dest, const char *key, bool boolean) { struct json *b = json_new_bool(boolean); json_object_add(dest, key, b); return b; } struct json *json_object_add_null(struct json *dest, const char *key) { struct json *n = json_new_null(); json_object_add(dest, key, n); return n; } struct json *json_object_detach(struct json *json, const char *key) { struct json *tmp = json_object_get(json, key); json_detach(tmp); return tmp; } void json_object_delete(struct json *json, const char *key) { struct json *tmp = json_object_detach(json, key); json_delete(tmp); }