#define JSON_PRIVATE #include #include #include #include #include "internal.h" inline static void adjust_siblings(struct json *json, struct json *src) { if (json->prev) json->prev->next = src; if (json->next) json->next->prev = src; } 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); 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; adjust_siblings(e, src); json_clear(e); free(e); return; } } add_children(dest, src); } 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_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; } struct json *json_set(struct json *dest, const char *key, struct json *src) { if (!dest || !key || !src) return NULL; json_detach(src); add_to_object(dest, strdup(key), src); return src; } struct json *json_get_mut(struct json *json, const char *key) { if (!json_is_object(json) || !key) return NULL; json_foreach(j, json) { if (strcmp(j->key, key) == 0) return j; } return NULL; } struct json *json_get_sized_mut(struct json *json, size_t count, const char key[count]) { if (!json_is_object(json) || !key) return NULL; json_foreach(j, json) { if (strncmp(j->key, key, count) == 0) return j; } return NULL; } const struct json *json_get_const(const struct json *obj, const char *key) { return json_get_mut((struct json *) obj, key); } const struct json *json_get_sized_const(const struct json *obj, size_t count, const char key[count]) { return json_get_sized_mut((struct json *) obj, count, key); } struct json *json_detach_key(struct json *json, const char *key) { struct json *tmp = json_get(json, key); json_detach(tmp); return tmp; } struct json *json_swap_key(struct json *json, const char *key, struct json *src) { if (!json_is_object(json) || !key) return NULL; json_detach(src); json_foreach(j, json) { if (strcmp(j->key, key)) { json->children->items[j->index] = src; src->index = j->index; adjust_siblings(j, src); return j; } } return NULL; } void json_delete_key(struct json *json, const char *key) { struct json *tmp = json_detach_key(json, key); json_delete(tmp); } struct json *json_detach_key_sized(struct json *json, size_t len, const char key[len]) { struct json *tmp = json_get_sized(json, len, key); json_detach(tmp); return tmp; } void json_delete_key_sized(struct json *json, size_t len, const char key[len]) { struct json *tmp = json_detach_key_sized(json, len, key); json_delete(tmp); } struct json *json_swap_key_sized(struct json *json, size_t len, const char key[len], struct json *src) { if (!json_is_object(json) || !key) return NULL; json_detach(src); json_foreach(j, json) { if (strncmp(j->key, key, len)) { json->children->items[j->index] = src; src->index = j->index; adjust_siblings(j, src); return j; } } return NULL; }