/* * Copyright (c) 2023 Egor Tensin * This file is part of the "cimple" project. * For details, see https://github.com/egor-tensin/cimple. * Distributed under the MIT License. */ #include "json.h" #include "buf.h" #include "log.h" #include "net.h" #include #include #include #include #include #include #define libjson_errno(fn) \ do { \ log_err("JSON: %s failed\n", fn); \ } while (0) void libjson_free(struct json_object *obj) { json_object_put(obj); } static const char *libjson_to_string_internal(struct json_object *obj, int flags) { const char *result = json_object_to_json_string_ext(obj, flags); if (!result) { libjson_errno("json_object_to_json_string"); return NULL; } return result; } const char *libjson_to_string(struct json_object *obj) { return libjson_to_string_internal(obj, JSON_C_TO_STRING_SPACED); } const char *libjson_to_string_pretty(struct json_object *obj) { return libjson_to_string_internal(obj, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY); } struct json_object *libjson_from_string(const char *src) { enum json_tokener_error error; struct json_object *result = json_tokener_parse_verbose(src, &error); if (!result) { libjson_errno("json_tokener_parse_verbose"); log_err("JSON: parsing failed: %s\n", json_tokener_error_desc(error)); return NULL; } return result; } int libjson_clone(const struct json_object *obj, const char *key, struct json_object **_value) { int ret = 0; struct json_object *old_value = NULL; ret = libjson_get(obj, key, &old_value); if (ret < 0) return ret; struct json_object *new_value = NULL; ret = json_object_deep_copy(old_value, &new_value, NULL); if (ret < 0) return ret; *_value = new_value; return ret; } int libjson_send(struct json_object *obj, int fd) { int ret = 0; const char *str = libjson_to_string(obj); if (!str) return -1; struct buf *buf = NULL; ret = buf_create_from_string(&buf, str); if (ret < 0) return ret; ret = net_send_buf(fd, buf); buf_destroy(buf); return ret; } struct json_object *libjson_recv(int fd) { struct json_object *result = NULL; int ret = 0; struct buf *buf = NULL; ret = net_recv_buf(fd, &buf); if (ret < 0) return NULL; result = libjson_from_string((const char *)buf_get_data(buf)); if (!result) goto destroy_buf; destroy_buf: free((void *)buf_get_data(buf)); buf_destroy(buf); return result; } int libjson_new_object(struct json_object **_obj) { struct json_object *obj = json_object_new_object(); if (!obj) { libjson_errno("json_object_new_object"); return -1; } *_obj = obj; return 0; } int libjson_new_array(struct json_object **_arr) { struct json_object *arr = json_object_new_array(); if (!arr) { libjson_errno("json_object_new_array"); return -1; } *_arr = arr; return 0; } int libjson_has(const struct json_object *obj, const char *key) { return json_object_object_get_ex(obj, key, NULL); } int libjson_get(const struct json_object *obj, const char *key, struct json_object **value) { if (!libjson_has(obj, key)) { log_err("JSON: key is missing: %s\n", key); return -1; } return json_object_object_get_ex(obj, key, value); } int libjson_get_string(const struct json_object *obj, const char *key, const char **_value) { struct json_object *value = NULL; int ret = libjson_get(obj, key, &value); if (ret < 0) return ret; if (!json_object_is_type(value, json_type_string)) { log_err("JSON: key is not a string: %s\n", key); return -1; } *_value = json_object_get_string(value); return 0; } int libjson_get_int(const struct json_object *obj, const char *key, int64_t *_value) { struct json_object *value = NULL; int ret = libjson_get(obj, key, &value); if (ret < 0) return ret; if (!json_object_is_type(value, json_type_int)) { log_err("JSON: key is not an integer: %s\n", key); return -1; } errno = 0; int64_t tmp = json_object_get_int64(value); if (errno) { log_err("JSON: failed to parse integer from key: %s\n", key); return -1; } *_value = tmp; return 0; } static int libjson_set_internal(struct json_object *obj, const char *key, struct json_object *value, unsigned flags) { int ret = 0; ret = json_object_object_add_ex(obj, key, value, flags); if (ret < 0) { libjson_errno("json_object_object_add_ex"); return ret; } return 0; } static int libjson_set_string_internal(struct json_object *obj, const char *key, const char *_value, unsigned flags) { struct json_object *value = json_object_new_string(_value); if (!value) { libjson_errno("json_object_new_string"); return -1; } int ret = libjson_set_internal(obj, key, value, flags); if (ret < 0) goto free_value; return ret; free_value: json_object_put(value); return ret; } static int libjson_set_int_internal(struct json_object *obj, const char *key, int64_t _value, unsigned flags) { struct json_object *value = json_object_new_int64(_value); if (!value) { libjson_errno("json_object_new_int"); return -1; } int ret = libjson_set_internal(obj, key, value, flags); if (ret < 0) goto free_value; return ret; free_value: json_object_put(value); return ret; } int libjson_set(struct json_object *obj, const char *key, struct json_object *value) { return libjson_set_internal(obj, key, value, 0); } int libjson_set_string(struct json_object *obj, const char *key, const char *value) { return libjson_set_string_internal(obj, key, value, 0); } int libjson_set_int(struct json_object *obj, const char *key, int64_t value) { return libjson_set_int_internal(obj, key, value, 0); } #ifndef JSON_C_OBJECT_ADD_CONSTANT_KEY #define JSON_C_OBJECT_ADD_CONSTANT_KEY JSON_C_OBJECT_KEY_IS_CONSTANT #endif static const unsigned json_const_key_flags = JSON_C_OBJECT_ADD_CONSTANT_KEY; int libjson_set_const_key(struct json_object *obj, const char *key, struct json_object *value) { return libjson_set_internal(obj, key, value, json_const_key_flags); } int libjson_set_string_const_key(struct json_object *obj, const char *key, const char *value) { return libjson_set_string_internal(obj, key, value, json_const_key_flags); } int libjson_set_int_const_key(struct json_object *obj, const char *key, int64_t value) { return libjson_set_int_internal(obj, key, value, json_const_key_flags); } int libjson_append(struct json_object *arr, struct json_object *elem) { int ret = json_object_array_add(arr, elem); if (ret < 0) { libjson_errno("json_object_array_add"); return ret; } return ret; }