@@ -3,7 +3,7 @@ | |||
* Symbol versioning for libjson-c. | |||
* All exported symbols must be listed here. | |||
* | |||
* See | |||
* See | |||
* https://software.intel.com/sites/default/files/m/a/1/e/dsohowto.pdf | |||
*/ | |||
@@ -166,8 +166,12 @@ JSONC_0.15 { | |||
JSONC_0.16 { | |||
global: | |||
lh_string_data; | |||
lh_string_size; | |||
lh_string_print; | |||
json_object_object_add_len; | |||
json_object_object_add_ex_len; | |||
json_object_object_del_len; | |||
json_object_object_get_len; | |||
json_object_object_get_ex_len; | |||
} JSONC_0.15; |
@@ -116,6 +116,14 @@ static inline const struct json_object_string *JC_STRING_C(const struct json_obj | |||
static inline struct json_object *json_object_new(enum json_type o_type, size_t alloc_size, | |||
json_object_to_json_string_fn *to_json_string); | |||
static int json_object_object_add_internal(struct json_object *jso, const struct lh_string *key, | |||
struct json_object *const val, const unsigned opts); | |||
static int json_object_object_del_internal(struct json_object *jso_base, | |||
const struct lh_string *key); | |||
static json_bool json_object_object_get_internal(const struct json_object *jso, | |||
const struct lh_string *key, | |||
struct json_object **value); | |||
static void json_object_object_delete(struct json_object *jso_base); | |||
static void json_object_string_delete(struct json_object *jso); | |||
static void json_object_array_delete(struct json_object *jso); | |||
@@ -506,7 +514,7 @@ static int json_object_object_to_json_string(struct json_object *jso, struct pri | |||
printbuf_strappend(pb, " "); | |||
indent(pb, level + 1, flags); | |||
printbuf_strappend(pb, "\""); | |||
json_escape_str(pb, iter.key, strlen(iter.key), flags); | |||
json_escape_str(pb, lh_string_data(iter.key), lh_string_size(iter.key), flags); | |||
if (flags & JSON_C_TO_STRING_SPACED) | |||
printbuf_strappend(pb, "\": "); | |||
else | |||
@@ -576,12 +584,21 @@ int json_object_object_add_ex(struct json_object *jso, const char *const key, | |||
int json_object_object_add_ex_len(struct json_object *jso, const char *const key, const int len, | |||
struct json_object *const val, const unsigned opts) | |||
{ | |||
// Created on the stack rather than calling `lh_string_new_ptr` | |||
// or `lh_string_new_imm` since this saves copying `key` if it turns | |||
// out the value already exists in the hash table | |||
const struct lh_string hashable = {.length = len, .str = {.pdata = key}}; | |||
return json_object_object_add_internal(jso, &hashable, val, opts); | |||
} | |||
int json_object_object_add_internal(struct json_object *jso, const struct lh_string *key, | |||
struct json_object *const val, const unsigned opts) | |||
{ | |||
struct json_object *existing_value; | |||
struct lh_entry *existing_entry; | |||
unsigned long hash; | |||
/** Required due to the `lh_get_hash` function wanting a `const struct lh_string *` */ | |||
const struct lh_string hashable = {.length = len, .str = {.pdata = key}}; | |||
assert(json_object_get_type(jso) == json_type_object); | |||
@@ -594,7 +611,7 @@ int json_object_object_add_ex_len(struct json_object *jso, const char *const key | |||
// We lookup the entry and replace the value, rather than just deleting | |||
// and re-adding it, so the existing key remains valid. | |||
hash = lh_get_hash(JC_OBJECT(jso)->c_object, (const void *)&hashable); | |||
hash = lh_get_hash(JC_OBJECT(jso)->c_object, key); | |||
existing_entry = | |||
(opts & JSON_C_OBJECT_ADD_KEY_IS_NEW) | |||
? NULL | |||
@@ -602,9 +619,15 @@ int json_object_object_add_ex_len(struct json_object *jso, const char *const key | |||
if (existing_entry == NULL) | |||
{ | |||
const struct lh_string *k = (opts & JSON_C_OBJECT_KEY_IS_CONSTANT) | |||
? lh_string_new_ptr(len, key) | |||
: lh_string_new_imm(len, key); | |||
// need to copy `key` because the caller might have created it | |||
// on the stack, which would be more efficient than copying | |||
// `lh_string_data` into `key->string.idata` if it had happened | |||
// that `existing_entry` wasn't NULL. | |||
const struct lh_string *k = | |||
(opts & JSON_C_OBJECT_KEY_IS_CONSTANT) | |||
? lh_string_new_ptr(lh_string_size(key), lh_string_data(key)) | |||
: lh_string_new_imm(lh_string_size(key), lh_string_data(key)); | |||
// TODO some optimization where (opts & JSON_C_OBJECT_ADD_KEY_IS_NEW) | |||
if (k == NULL) | |||
{ | |||
return -1; | |||
@@ -681,8 +704,10 @@ json_bool json_object_object_get_ex_len(const struct json_object *jso, const cha | |||
switch (jso->o_type) | |||
{ | |||
case json_type_object: | |||
return lh_table_lookup_ex(JC_OBJECT_C(jso)->c_object, (const void *)key, | |||
(void **)value); | |||
{ | |||
const struct lh_string hashable = {.length = len, .str = {.pdata = key}}; | |||
return json_object_object_get_internal(jso, &hashable, value); | |||
} | |||
default: | |||
if (value != NULL) | |||
*value = NULL; | |||
@@ -690,10 +715,28 @@ json_bool json_object_object_get_ex_len(const struct json_object *jso, const cha | |||
} | |||
} | |||
json_bool json_object_object_get_internal(const struct json_object *jso, | |||
const struct lh_string *key, struct json_object **value) | |||
{ | |||
assert(json_object_get_type(jso) == json_type_object); | |||
return lh_table_lookup_ex(JC_OBJECT_C(jso)->c_object, key, (void **)value); | |||
} | |||
void json_object_object_del(struct json_object *jso, const char *key) | |||
{ | |||
json_object_object_del_len(jso, key, strlen(key)); | |||
} | |||
void json_object_object_del_len(struct json_object *jso, const char *key, const int len) | |||
{ | |||
const struct lh_string hashable = {.length = len, .str = {.pdata = key}}; | |||
json_object_object_del_internal(jso, &hashable); | |||
} | |||
int json_object_object_del_internal(struct json_object *jso, const struct lh_string *key) | |||
{ | |||
assert(json_object_get_type(jso) == json_type_object); | |||
lh_table_delete(JC_OBJECT(jso)->c_object, key); | |||
return lh_table_delete(JC_OBJECT(jso)->c_object, key); | |||
} | |||
/* json_object_boolean */ | |||
@@ -1680,7 +1723,7 @@ static int json_object_copy_serializer_data(struct json_object *src, struct json | |||
* | |||
* This always returns -1 or 1. It will never return 2 since it does not copy the serializer. | |||
*/ | |||
int json_c_shallow_copy_default(json_object *src, json_object *parent, const char *key, | |||
int json_c_shallow_copy_default(json_object *src, json_object *parent, const struct lh_string *key, | |||
size_t index, json_object **dst) | |||
{ | |||
switch (src->o_type) | |||
@@ -1728,8 +1771,8 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const cha | |||
* Note: caller is responsible for freeing *dst if this fails and returns -1. | |||
*/ | |||
static int json_object_deep_copy_recursive(struct json_object *src, struct json_object *parent, | |||
const char *key_in_parent, size_t index_in_parent, | |||
struct json_object **dst, | |||
const struct lh_string *key_in_parent, | |||
size_t index_in_parent, struct json_object **dst, | |||
json_c_shallow_copy_fn *shallow_copy) | |||
{ | |||
struct json_object_iter iter; | |||
@@ -1761,7 +1804,7 @@ static int json_object_deep_copy_recursive(struct json_object *src, struct json_ | |||
return -1; | |||
} | |||
if (json_object_object_add(*dst, iter.key, jso) < 0) | |||
if (json_object_object_add_internal(*dst, iter.key, jso, 0) < 0) | |||
{ | |||
json_object_put(jso); | |||
return -1; | |||
@@ -547,6 +547,19 @@ JSON_EXPORT json_bool json_object_object_get_ex_len(const struct json_object *ob | |||
*/ | |||
JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key); | |||
/** Delete the given json_object field | |||
* | |||
* The reference count will be decremented for the deleted object. If there | |||
* are no more owners of the value represented by this key, then the value is | |||
* freed. Otherwise, the reference to the value will remain in memory. | |||
* | |||
* @param obj the json_object instance | |||
* @param key the object field name, | |||
* which is not terminated by a NULL ( @c '\0' ) character | |||
* @param len the length of @p key | |||
*/ | |||
void json_object_object_del_len(struct json_object *jso, const char *key, const int len); | |||
/** | |||
* Iterate through all keys and values of an object. | |||
* | |||
@@ -560,17 +573,18 @@ JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key | |||
* @param val the local name for the json_object* object variable defined in | |||
* the body | |||
*/ | |||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) | |||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) && \ | |||
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) | |||
#define json_object_object_foreach(obj, key, val) \ | |||
char *key = NULL; \ | |||
struct lh_string *key = NULL; \ | |||
struct json_object *val __attribute__((__unused__)) = NULL; \ | |||
for (struct lh_entry *entry##key = json_object_get_object(obj)->head, \ | |||
*entry_next##key = NULL; \ | |||
({ \ | |||
if (entry##key) \ | |||
{ \ | |||
key = (char *)lh_entry_k(entry##key); \ | |||
key = (struct lh_string *)lh_entry_k(entry##key); \ | |||
val = (struct json_object *)lh_entry_v(entry##key); \ | |||
entry_next##key = entry##key->next; \ | |||
}; \ | |||
@@ -600,7 +614,7 @@ JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key | |||
*/ | |||
#define json_object_object_foreachC(obj, iter) \ | |||
for (iter.entry = json_object_get_object(obj)->head; \ | |||
(iter.entry ? (iter.key = (char *)lh_entry_k(iter.entry), \ | |||
(iter.entry ? (iter.key = (struct lh_string *)lh_entry_k(iter.entry), \ | |||
iter.val = (struct json_object *)lh_entry_v(iter.entry), iter.entry) \ | |||
: 0); \ | |||
iter.entry = iter.entry->next) | |||
@@ -746,7 +760,7 @@ JSON_EXPORT struct json_object *json_object_new_boolean(json_bool b); | |||
* The type is coerced to a json_bool if the passed object is not a json_bool. | |||
* integer and double objects will return 0 if there value is zero | |||
* or 1 otherwise. If the passed object is a string it will return | |||
* 1 if it has a non zero length. | |||
* 1 if it has a non zero length. | |||
* If any other object type is passed 0 will be returned, even non-empty | |||
* json_type_array and json_type_object objects. | |||
* | |||
@@ -1114,8 +1128,8 @@ JSON_EXPORT int json_object_equal(struct json_object *obj1, struct json_object * | |||
* | |||
* @return On success 1 or 2, -1 on errors | |||
*/ | |||
typedef int(json_c_shallow_copy_fn)(json_object *src, json_object *parent, const char *key, | |||
size_t index, json_object **dst); | |||
typedef int(json_c_shallow_copy_fn)(json_object *src, json_object *parent, | |||
const struct lh_string *key, size_t index, json_object **dst); | |||
/** | |||
* The default shallow copy implementation for use with json_object_deep_copy(). | |||
@@ -104,12 +104,12 @@ void json_object_iter_next(struct json_object_iterator *iter) | |||
/** | |||
* **************************************************************************** | |||
*/ | |||
const char *json_object_iter_peek_name(const struct json_object_iterator *iter) | |||
const struct lh_string *json_object_iter_peek_name(const struct json_object_iterator *iter) | |||
{ | |||
JASSERT(NULL != iter); | |||
JASSERT(kObjectEndIterValue != iter->opaque_); | |||
return (const char *)(((const struct lh_entry *)iter->opaque_)->k); | |||
return (const struct lh_string *)(((const struct lh_entry *)iter->opaque_)->k); | |||
} | |||
/** | |||
@@ -168,7 +168,8 @@ JSON_EXPORT void json_object_iter_next(struct json_object_iterator *iter); | |||
* deleted or modified, and MUST NOT be modified or | |||
* freed by the user. | |||
*/ | |||
JSON_EXPORT const char *json_object_iter_peek_name(const struct json_object_iterator *iter); | |||
JSON_EXPORT const struct lh_string * | |||
json_object_iter_peek_name(const struct json_object_iterator *iter); | |||
/** Returns a pointer to the json-c instance representing the | |||
* value of the referenced name/value pair, without altering | |||
@@ -33,7 +33,7 @@ struct printbuf; | |||
*/ | |||
struct json_object_iter | |||
{ | |||
char *key; | |||
struct lh_string *key; | |||
struct json_object *val; | |||
struct lh_entry *entry; | |||
}; | |||
@@ -13,7 +13,7 @@ | |||
#include "json_visit.h" | |||
#include "linkhash.h" | |||
static int _json_c_visit(json_object *jso, json_object *parent_jso, const char *jso_key, | |||
static int _json_c_visit(json_object *jso, json_object *parent_jso, const struct lh_string *jso_key, | |||
size_t *jso_index, json_c_visit_userfunc *userfunc, void *userarg); | |||
int json_c_visit(json_object *jso, int future_flags, json_c_visit_userfunc *userfunc, void *userarg) | |||
@@ -28,7 +28,7 @@ int json_c_visit(json_object *jso, int future_flags, json_c_visit_userfunc *user | |||
default: return JSON_C_VISIT_RETURN_ERROR; | |||
} | |||
} | |||
static int _json_c_visit(json_object *jso, json_object *parent_jso, const char *jso_key, | |||
static int _json_c_visit(json_object *jso, json_object *parent_jso, const struct lh_string *jso_key, | |||
size_t *jso_index, json_c_visit_userfunc *userfunc, void *userarg) | |||
{ | |||
int userret = userfunc(jso, 0, parent_jso, jso_key, jso_index, userarg); | |||
@@ -13,7 +13,8 @@ extern "C" { | |||
#endif | |||
typedef int(json_c_visit_userfunc)(json_object *jso, int flags, json_object *parent_jso, | |||
const char *jso_key, size_t *jso_index, void *userarg); | |||
const struct lh_string *jso_key, size_t *jso_index, | |||
void *userarg); | |||
/** | |||
* Visit each object in the JSON hierarchy starting at jso. | |||
@@ -506,6 +506,11 @@ size_t lh_string_size(const struct lh_string *str) | |||
return (str->length > 0) ? (size_t)str->length : (size_t)(-(str->length)); | |||
} | |||
size_t lh_string_print(const struct lh_string *key, FILE *stream) | |||
{ | |||
return fwrite(lh_string_data(key), lh_string_size(key), 1, stream); | |||
} | |||
const struct lh_string *lh_string_new_ptr(const size_t length, const char *data) | |||
{ | |||
struct lh_string *result = malloc(sizeof(struct lh_string)); | |||
@@ -535,7 +540,7 @@ const struct lh_string *lh_string_new_imm(const size_t length, const char *data) | |||
result->length = -length; | |||
char *unconst = _LH_UNCONST(result->str.idata); | |||
memcpy(unconst, data, length); | |||
unconst = '\0'; | |||
unconst[length] = '\0'; | |||
return result; | |||
} | |||
@@ -20,6 +20,7 @@ | |||
#define _json_c_linkhash_h_ | |||
#include "json_object.h" | |||
#include <stdio.h> | |||
#ifdef __cplusplus | |||
extern "C" { | |||
@@ -206,6 +207,14 @@ extern const char *lh_string_data(const struct lh_string *str); | |||
*/ | |||
extern size_t lh_string_size(const struct lh_string *str); | |||
/** | |||
* @brief Print a `struct lh_string` to a given stream | |||
* | |||
* @param str value to print | |||
* @param stream Stream to write data to | |||
*/ | |||
extern size_t lh_string_print(const struct lh_string *str, FILE *stream); | |||
/** | |||
* @brief Creates a new `struct lh_string` using the `pdata` field. | |||
* | |||