diff --git a/json-c.sym b/json-c.sym index e69e18b..2d6bd86 100644 --- a/json-c.sym +++ b/json-c.sym @@ -166,12 +166,14 @@ JSONC_0.15 { JSONC_0.16 { global: - lh_string_data; - lh_string_size; - lh_string_print; + json_key_data; + json_key_size; json_object_object_add_len; json_object_object_add_ex_len; + json_object_object_add_key; json_object_object_del_len; + json_object_object_del_key; json_object_object_get_len; json_object_object_get_ex_len; + json_object_object_get_key; } JSONC_0.15; diff --git a/json_object.c b/json_object.c index e9fffab..b48b889 100644 --- a/json_object.c +++ b/json_object.c @@ -116,12 +116,6 @@ 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_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); @@ -512,7 +506,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, lh_string_data(iter.key), lh_string_size(iter.key), flags); + json_escape_str(pb, json_key_data(iter.key), json_key_size(iter.key), flags); if (flags & JSON_C_TO_STRING_SPACED) printbuf_strappend(pb, "\": "); else @@ -583,20 +577,20 @@ 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 + // Created on the stack rather than calling `json_key_new_ptr` + // or `json_key_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); + const struct json_key hashable = {.length = len, .str = {.pdata = key}}; + return json_object_object_add_key(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) +int json_object_object_add_key(struct json_object *jso, const struct json_key *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 *` */ + /** Required due to the `lh_get_hash` function wanting a `const struct json_key *` */ assert(json_object_get_type(jso) == json_type_object); @@ -619,12 +613,12 @@ int json_object_object_add_internal(struct json_object *jso, const struct lh_str { // 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 + // `json_key_data` into `key->string.idata` if it had happened // that `existing_entry` wasn't NULL. - const struct lh_string *k = + const struct json_key *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)); + ? json_key_new_ptr(json_key_size(key), json_key_data(key)) + : json_key_new_imm(json_key_size(key), json_key_data(key)); // TODO some optimization where (opts & JSON_C_OBJECT_ADD_KEY_IS_NEW) if (k == NULL) { @@ -632,7 +626,7 @@ int json_object_object_add_internal(struct json_object *jso, const struct lh_str } return lh_table_insert_w_hash(JC_OBJECT(jso)->c_object, k, val, hash, opts & ~JSON_C_OBJECT_KEY_IS_CONSTANT); - // `struct lh_string` always needs to be freed, + // `struct json_key` always needs to be freed, // so JSON_C_OBJECT_KEY_IS_CONSTANT cannot be set } else @@ -703,8 +697,8 @@ json_bool json_object_object_get_ex_len(const struct json_object *jso, const cha { case json_type_object: { - const struct lh_string hashable = {.length = len, .str = {.pdata = key}}; - return json_object_object_get_internal(jso, &hashable, value); + const struct json_key hashable = {.length = len, .str = {.pdata = key}}; + return json_object_object_get_key(jso, &hashable, value); } default: if (value != NULL) @@ -713,8 +707,8 @@ 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) +json_bool json_object_object_get_key(const struct json_object *jso, const struct json_key *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); @@ -727,11 +721,11 @@ void json_object_object_del(struct json_object *jso, const char *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); + const struct json_key hashable = {.length = len, .str = {.pdata = key}}; + json_object_object_del_key(jso, &hashable); } -int json_object_object_del_internal(struct json_object *jso, const struct lh_string *key) +int json_object_object_del_key(struct json_object *jso, const struct json_key *key) { assert(json_object_get_type(jso) == json_type_object); return lh_table_delete(JC_OBJECT(jso)->c_object, key); @@ -1721,7 +1715,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 struct lh_string *key, +int json_c_shallow_copy_default(json_object *src, json_object *parent, const struct json_key *key, size_t index, json_object **dst) { switch (src->o_type) @@ -1769,7 +1763,7 @@ int json_c_shallow_copy_default(json_object *src, json_object *parent, const str * 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 struct lh_string *key_in_parent, + const struct json_key *key_in_parent, size_t index_in_parent, struct json_object **dst, json_c_shallow_copy_fn *shallow_copy) { @@ -1802,7 +1796,7 @@ static int json_object_deep_copy_recursive(struct json_object *src, struct json_ return -1; } - if (json_object_object_add_internal(*dst, iter.key, jso, 0) < 0) + if (json_object_object_add_key(*dst, iter.key, jso, 0) < 0) { json_object_put(jso); return -1; @@ -1876,3 +1870,46 @@ static void json_abort(const char *message) fprintf(stderr, "json-c aborts with error: %s\n", message); abort(); } + +size_t json_key_size(const struct json_key *str) +{ + return (str->length > 0) ? (size_t)str->length : (size_t)(-(str->length)); +} + +const char *json_key_data(const struct json_key *str) +{ + return (str->length > 0) ? str->str.pdata : str->str.idata; +} + +struct json_key *json_key_new_ptr(const size_t length, const char *data) +{ + struct json_key *result = malloc(sizeof(struct json_key)); + if (result == NULL) + { + return NULL; + } + result->length = length; + result->str.pdata = data; + return result; +} + +struct json_key *json_key_new_imm(const size_t length, const char *data) +{ + struct json_key *result; + if (length > + SSIZE_T_MAX - (sizeof(struct json_key) - sizeof(((struct json_key *)NULL)->str)) - 1) + { + return NULL; + } + result = + malloc(sizeof(struct json_key) - sizeof(((struct json_key *)NULL)->str) + length + 1); + if (result == NULL) + { + return NULL; + } + result->length = -length; + char *unconst = _LH_UNCONST(result->str.idata); + memcpy(unconst, data, length); + unconst[length] = '\0'; + return result; +} diff --git a/json_object.h b/json_object.h index 6cf2594..771ea73 100644 --- a/json_object.h +++ b/json_object.h @@ -456,8 +456,27 @@ JSON_EXPORT int json_object_object_add_ex_len(struct json_object *obj, const cha const int len, struct json_object *const val, const unsigned opts); -/** Get the json_object associate with a given object field. - * Deprecated/discouraged: used json_object_object_get_ex instead. +/** + * @brief Add an object field to a json_object of type json_type_object + * + * The semantics are identical to `json_object_object_add_ex`, except that @p key + * contains both the data and the length. + * + * @param obj the json_object instance + * @param key the object field name (a private copy will be duplicated) + * @param val a json_object or NULL member to associate with the given field + * @param opts process-modifying options. To specify multiple options, use + * (OPT1|OPT2) + * @return On success, @c 0 is returned. + * On error, a negative value is returned. + */ +JSON_EXPORT int json_object_object_add_key(struct json_object *obj, const struct json_key *key, + struct json_object *const val, const unsigned opts); + +/** + * @brief Get the json_object associate with a given object field. + * + * @deprecated Deprecated/discouraged: used json_object_object_get_ex instead. * * This functions exactly like calling * @code json_object_object_get_len(obj, key, strlen(key)) @endcode @@ -469,8 +488,10 @@ JSON_EXPORT int json_object_object_add_ex_len(struct json_object *obj, const cha */ JSON_EXPORT struct json_object *json_object_object_get(const struct json_object *obj, const char *key); -/** Get the json_object associate with a given object field. - * Deprecated/discouraged: used json_object_object_get_ex_len instead. +/** + * @brief Get the json_object associate with a given object field. + * + * @deprecated Deprecated/discouraged: used json_object_object_get_ex_len instead. * * This returns NULL if the field is found but its value is null, or if * the field is not found, or if obj is not a json_type_object. If you @@ -496,7 +517,8 @@ JSON_EXPORT struct json_object *json_object_object_get(const struct json_object JSON_EXPORT struct json_object *json_object_object_get_len(const struct json_object *obj, const char *key, const int len); -/** Get the json_object associated with a given object field. +/** + * @brief Get the json_object associated with a given object field. * * This functions exactly like calling * @code json_object_object_get_ex_len(obj, key, strlen(key), value) @endcode @@ -513,7 +535,8 @@ JSON_EXPORT struct json_object *json_object_object_get_len(const struct json_obj JSON_EXPORT json_bool json_object_object_get_ex(const struct json_object *obj, const char *key, struct json_object **value); -/** Get the json_object associated with a given object field. +/** + * @brief Get the json_object associated with a given object field. * * This returns true if the key is found, false in all other cases (including * if obj isn't a json_type_object). @@ -536,7 +559,29 @@ JSON_EXPORT json_bool json_object_object_get_ex(const struct json_object *obj, c JSON_EXPORT json_bool json_object_object_get_ex_len(const struct json_object *obj, const char *key, const int len, struct json_object **value); -/** Delete the given json_object field +/** + * @brief Get the json_object associated with a given object field. + * + * *No* reference counts will be changed. There is no need to manually adjust + * reference counts through the json_object_put/json_object_get methods unless + * you need to have the child (value) reference maintain a different lifetime + * than the owning parent (obj). Ownership of value is retained by obj. + * + * @param obj the json_object instance + * @param key the object field name + * @param value a pointer where to store a reference to the json_object + * associated with the given field name. + * \n + * It is safe to pass a NULL value. + * @returns true if the key is found, false in all other cases (including + * if obj isn't a json_type_object) + */ +JSON_EXPORT json_bool json_object_object_get_key(const struct json_object *jso, + const struct json_key *key, + struct json_object **value); + +/** + * @brief 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 @@ -547,7 +592,8 @@ 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 +/** + * @brief 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 @@ -558,10 +604,24 @@ JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key * 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); +JSON_EXPORT 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. + * @brief 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 + */ +JSON_EXPORT int json_object_object_del_key(struct json_object *jso_base, + const struct json_key *key); + +/** + * @brief Iterate through all keys and values of an object. * * Adding keys to the object while iterating is NOT allowed. * @@ -577,14 +637,14 @@ void json_object_object_del_len(struct json_object *jso, const char *key, const (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) #define json_object_object_foreach(obj, key, val) \ - struct lh_string *key = NULL; \ + struct json_key *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 = (struct lh_string *)lh_entry_k(entry##key); \ + key = (struct json_key *)lh_entry_k(entry##key); \ val = (struct json_object *)lh_entry_v(entry##key); \ entry_next##key = entry##key->next; \ }; \ @@ -608,13 +668,14 @@ void json_object_object_del_len(struct json_object *jso, const char *key, const #endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) && (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) */ -/** Iterate through all keys and values of an object (ANSI C Safe) +/** + * @brief Iterate through all keys and values of an object (ANSI C Safe) * @param obj the json_object instance * @param iter the object iterator, use type json_object_iter */ #define json_object_object_foreachC(obj, iter) \ for (iter.entry = json_object_get_object(obj)->head; \ - (iter.entry ? (iter.key = (struct lh_string *)lh_entry_k(iter.entry), \ + (iter.entry ? (iter.key = (struct json_key *)lh_entry_k(iter.entry), \ iter.val = (struct json_object *)lh_entry_v(iter.entry), iter.entry) \ : 0); \ iter.entry = iter.entry->next) @@ -1129,7 +1190,7 @@ 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 struct lh_string *key, size_t index, json_object **dst); + const struct json_key *key, size_t index, json_object **dst); /** * The default shallow copy implementation for use with json_object_deep_copy(). @@ -1166,6 +1227,53 @@ JSON_EXPORT json_c_shallow_copy_fn json_c_shallow_copy_default; JSON_EXPORT int json_object_deep_copy(struct json_object *src, struct json_object **dst, json_c_shallow_copy_fn *shallow_copy); + +/* Json Object Keys */ + +/** + * @brief Get the length of the data stored in a `struct json_key *` + * + * @param str value to retrieve the length of + */ +JSON_EXPORT size_t json_key_size(const struct json_key *str); + +/** + * @brief Get the data from a `struct json_key *` + * + * @param str value to retrieve the data from + */ +JSON_EXPORT const char *json_key_data(const struct json_key *str); + +/** + * @brief Creates a new `struct json_key` that uses the `pdata` field. + * + * This avoids unneeded copying, for cases wher ethe key is in an area of + * memory that will not be modified or freed until after this object is freed. + * + * @param length The length of the data located at @p data + * @param data The data to include + * @return On success, a pointer to the new key is returned. + * On error, a null pointer is returned. + */ +JSON_EXPORT struct json_key *json_key_new_ptr(const size_t length, const char *data); + +/** + * @brief Creates a new `struct json_key` that uses the `idata` field. + * + * @param length The length of the data to copy into the returned value + * @param data The data to include and copy into the returned value + * @return On success, a pointer to the new key is returned. + * On error, a null pointer is returned. + */ +JSON_EXPORT struct json_key *json_key_new_imm(const size_t length, const char *data); + +/** + * @brief Frees the memory associated with a `struct json_key` + * + * @param key The data to free + */ +JSON_EXPORT void json_key_del(const struct json_key *key); + #ifdef __cplusplus } #endif diff --git a/json_object_iterator.c b/json_object_iterator.c index 0f065a4..754192a 100644 --- a/json_object_iterator.c +++ b/json_object_iterator.c @@ -104,12 +104,12 @@ void json_object_iter_next(struct json_object_iterator *iter) /** * **************************************************************************** */ -const struct lh_string *json_object_iter_peek_name(const struct json_object_iterator *iter) +const struct json_key *json_object_iter_peek_name(const struct json_object_iterator *iter) { JASSERT(NULL != iter); JASSERT(kObjectEndIterValue != iter->opaque_); - return (const struct lh_string *)(((const struct lh_entry *)iter->opaque_)->k); + return (const struct json_key *)(((const struct lh_entry *)iter->opaque_)->k); } /** diff --git a/json_object_iterator.h b/json_object_iterator.h index 8b56479..2e1f969 100644 --- a/json_object_iterator.h +++ b/json_object_iterator.h @@ -168,7 +168,7 @@ 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 struct lh_string * +JSON_EXPORT const struct json_key * json_object_iter_peek_name(const struct json_object_iterator *iter); /** Returns a pointer to the json-c instance representing the diff --git a/json_object_private.h b/json_object_private.h index 5b08dd1..6ad1044 100644 --- a/json_object_private.h +++ b/json_object_private.h @@ -98,27 +98,53 @@ struct json_object_string void _json_c_set_last_err(const char *err_fmt, ...); -/** - * @brief Add an object field to a json_object of type json_type_object - * - * The semantics are identical to json_object_object_add_ex, except that @p key - * contains both the data and the length. - * - * @param obj the json_object instance - * @param key the object field name (a private copy will be duplicated) - * @param val a json_object or NULL member to associate with the given field - * @param opts process-modifying options. To specify multiple options, use - * (OPT1|OPT2) - * @return On success, @c 0 is returned. - * On error, a negative value is returned. - */ -int json_object_object_add_internal(struct json_object *obj, const struct lh_string *key, - struct json_object *const val, const unsigned opts); /** * The characters that can make up hexadecimal numbers */ extern const char *json_hex_chars; +/** + * @brief A buffer of characters that may contain null charaters in the middle + * + * A buffer of data that can hold a normal null-terminated string + * (in which case `length` should just be equal to `strlen`) + * or a string with embedded null characters (in which case `length` reflects + * all the characters that make up the "string"). + * Either way, this struct can be treated as if it contains null characters, + * since the `length` member should always be equal to the proper size of the + * buffer and the terminating null character wouldn't be included + * (it wouldn't be counted by strlen). + */ +struct json_key +{ + /** + * @brief Stores the length of the buffer + * + * If the length is positive, then `pdata` should be used. + * Otherwise, idata should be used. + */ + ssize_t length; + union + { + /** + * @brief A pointer to data that is stored elsewhere + * + * If the data stored there will not change for the lifetime of + * the key, use `pdata` rather than `idata`. + */ + const char *pdata; + /** + * @brief Data stored inline + * + * If the data stored may be overwritten, such as if it is + * copied from the stack, this struct should be allocated with + * enough space to store the whole string (of length `len`) + * and one additional null character. + */ + const char idata[0]; + } str; +}; + #ifdef __cplusplus } #endif diff --git a/json_tokener.c b/json_tokener.c index 8fea883..185d06c 100644 --- a/json_tokener.c +++ b/json_tokener.c @@ -1106,8 +1106,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * printbuf_memappend_fast(tok->pb, case_start, str - case_start); obj_field_name = - lh_string_new_imm(tok->pb->bpos, tok->pb->buf); - // lh_string_print(obj_field_name, stdout); + json_key_new_imm(tok->pb->bpos, tok->pb->buf); saved_state = json_tokener_state_object_field_end; state = json_tokener_state_eatws; break; @@ -1155,7 +1154,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char * goto redo_char; case json_tokener_state_object_value_add: - json_object_object_add_internal(current, obj_field_name, obj, 0); + json_object_object_add_key(current, obj_field_name, obj, 0); free(obj_field_name); obj_field_name = NULL; saved_state = json_tokener_state_object_sep; diff --git a/json_tokener.h b/json_tokener.h index 9a0d411..984016a 100644 --- a/json_tokener.h +++ b/json_tokener.h @@ -17,7 +17,6 @@ #define _json_tokener_h_ #include "json_object.h" -#include "linkhash.h" #include #ifdef __cplusplus @@ -86,7 +85,7 @@ struct json_tokener_srec enum json_tokener_state state, saved_state; struct json_object *obj; struct json_object *current; - struct lh_string *obj_field_name; + struct json_key *obj_field_name; }; #define JSON_TOKENER_DEFAULT_DEPTH 32 diff --git a/json_types.h b/json_types.h index 2892ef3..a7366f1 100644 --- a/json_types.h +++ b/json_types.h @@ -33,7 +33,7 @@ struct printbuf; */ struct json_object_iter { - struct lh_string *key; + struct json_key *key; struct json_object *val; struct lh_entry *entry; }; @@ -71,6 +71,8 @@ typedef enum json_type json_type_string } json_type; +typedef struct json_key json_key; + #ifdef __cplusplus } #endif diff --git a/json_visit.c b/json_visit.c index 43f2ec0..63dc797 100644 --- a/json_visit.c +++ b/json_visit.c @@ -13,7 +13,7 @@ #include "json_visit.h" #include "linkhash.h" -static int _json_c_visit(json_object *jso, json_object *parent_jso, const struct lh_string *jso_key, +static int _json_c_visit(json_object *jso, json_object *parent_jso, const struct json_key *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 struct lh_string *jso_key, +static int _json_c_visit(json_object *jso, json_object *parent_jso, const struct json_key *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); diff --git a/json_visit.h b/json_visit.h index 21f0013..5edc7a9 100644 --- a/json_visit.h +++ b/json_visit.h @@ -13,7 +13,7 @@ extern "C" { #endif typedef int(json_c_visit_userfunc)(json_object *jso, int flags, json_object *parent_jso, - const struct lh_string *jso_key, size_t *jso_index, + const struct json_key *jso_key, size_t *jso_index, void *userarg); /** diff --git a/linkhash.c b/linkhash.c index 4bb9844..da5d641 100644 --- a/linkhash.c +++ b/linkhash.c @@ -486,62 +486,14 @@ static unsigned long lh_char_hash(const void *k) random_seed = seed; /* potentially racy */ #endif } - return hashlittle(lh_string_data((const struct lh_string *)k), - lh_string_size((const struct lh_string *)k), random_seed); + return hashlittle(json_key_data((const struct json_key *)k), + json_key_size((const struct json_key *)k), random_seed); } int lh_char_equal(const void *k1, const void *k2) { - return lh_string_size(k1) == lh_string_size(k2) && - memcmp(lh_string_data(k1), lh_string_data(k2), lh_string_size(k1)) == 0; -} - -const char *lh_string_data(const struct lh_string *str) -{ - return (str->length > 0) ? str->str.pdata : str->str.idata; -} - -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); -} - -struct lh_string *lh_string_new_ptr(const size_t length, const char *data) -{ - struct lh_string *result = malloc(sizeof(struct lh_string)); - if (result == NULL) - { - return NULL; - } - result->length = length; - result->str.pdata = data; - return result; -} - -struct lh_string *lh_string_new_imm(const size_t length, const char *data) -{ - struct lh_string *result; - if (length > - SSIZE_T_MAX - (sizeof(struct lh_string) - sizeof(((struct lh_string *)NULL)->str)) - 1) - { - return NULL; - } - result = - malloc(sizeof(struct lh_string) - sizeof(((struct lh_string *)NULL)->str) + length + 1); - if (result == NULL) - { - return NULL; - } - result->length = -length; - char *unconst = _LH_UNCONST(result->str.idata); - memcpy(unconst, data, length); - unconst[length] = '\0'; - return result; + return json_key_size(k1) == json_key_size(k2) && + memcmp(json_key_data(k1), json_key_data(k2), json_key_size(k1)) == 0; } struct lh_table *lh_table_new(int size, lh_entry_free_fn *free_fn, lh_hash_fn *hash_fn, diff --git a/linkhash.h b/linkhash.h index a8b82f2..25c980e 100644 --- a/linkhash.h +++ b/linkhash.h @@ -20,7 +20,6 @@ #define _json_c_linkhash_h_ #include "json_object.h" -#include #ifdef __cplusplus extern "C" { @@ -80,34 +79,6 @@ typedef unsigned long(lh_hash_fn)(const void *k); */ typedef int(lh_equal_fn)(const void *k1, const void *k2); -/** - * @brief A buffer of characters that may contain null charaters in the middle - * - * A buffer of data that can hold a normal null-terminated string - * (in which case `length` should just be equal to `strlen`) - * or a string with embedded null characters (in which case `length` reflects - * all the characters that make up the "string"). - * Either way, this struct can be treated as if it contains null characters, - * since the `length` member should always be equal to the proper size of the - * buffer and the terminating null character wouldn't be included - * (it wouldn't be counted by strlen). - */ -struct lh_string -{ - /** - * @brief Stores the length of the buffer - * - * If the length is positive, then `pdata` should be used. - * Otherwise, idata should be used. - */ - ssize_t length; - union - { - const char *pdata; - const char idata[0]; - } str; -}; - /** * An entry in the hash table */ @@ -193,49 +164,6 @@ typedef struct lh_table lh_table; #define lh_foreach_safe(table, entry, tmp) \ for (entry = table->head; entry && ((tmp = entry->next) || 1); entry = tmp) -/** - * @brief Get the data from a `struct lh_string *` - * - * @param str value to retrieve the data from - */ -extern const char *lh_string_data(const struct lh_string *str); - -/** - * @brief Get the length of the data stored in a `struct lh_string *` - * - * @param str value to retrieve the length of - */ -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. - * - * This avoids unneeded copying, for cases wher ethe key is in an area of - * memory that will not be modified or freed until after this object is freed. - * - * @param length The length of the data located at @p data - * @param data The data to include - * @return `NULL` on error - */ -extern struct lh_string *lh_string_new_ptr(const size_t length, const char *data); - -/** - * @brief Creates a new `struct lh_string` using the `idata` field. - * - * @param length The length of the data to copy into the returned value - * @param data The data to include and copy into the returned value - * @return `NULL` on error - */ -extern struct lh_string *lh_string_new_imm(const size_t length, const char *data); - /** * Create a new linkhash table. * diff --git a/tests/test1.c b/tests/test1.c index aa156f3..f061961 100644 --- a/tests/test1.c +++ b/tests/test1.c @@ -307,7 +307,7 @@ int main(int argc, char **argv) json_object_object_foreach(my_object, key, val) { putchar('\t'); - lh_string_print(key, stdout); + fwrite(json_key_data(key), json_key_size(key), 1, stdout); printf(": %s\n", json_object_to_json_string(val)); } printf("my_object.to_string()=%s\n", json_object_to_json_string(my_object)); diff --git a/tests/testReplaceExisting.c b/tests/testReplaceExisting.c index 5d99212..70369d3 100644 --- a/tests/testReplaceExisting.c +++ b/tests/testReplaceExisting.c @@ -24,11 +24,11 @@ int main(int argc, char **argv) int orig_count = 0; json_object_object_foreach(my_object, key0, val0) { - printf("Key at index %d is [%s] %d", orig_count, lh_string_data(key0), + printf("Key at index %d is [%s] %d", orig_count, json_key_data(key0), (val0 == NULL)); - if (strcmp(lh_string_data(key0), "deleteme") == 0) + if (strcmp(json_key_data(key0), "deleteme") == 0) { - json_object_object_del(my_object, lh_string_data(key0)); + json_object_object_del(my_object, json_key_data(key0)); printf(" (deleted)\n"); } else @@ -38,18 +38,18 @@ int main(int argc, char **argv) printf("==== replace-value first loop starting ====\n"); - const struct lh_string *original_key = NULL; + const struct json_key *original_key = NULL; orig_count = 0; json_object_object_foreach(my_object, key, val) { - printf("Key at index %d is [%s] %d\n", orig_count, lh_string_data(key), + printf("Key at index %d is [%s] %d\n", orig_count, json_key_data(key), (val == NULL)); orig_count++; - if (strcmp(lh_string_data(key), "foo2") != 0) + if (strcmp(json_key_data(key), "foo2") != 0) continue; - printf("replacing value for key [%s]\n", lh_string_data(key)); + printf("replacing value for key [%s]\n", json_key_data(key)); original_key = key; - json_object_object_add(my_object, lh_string_data(key0), + json_object_object_add(my_object, json_key_data(key0), json_object_new_string("zzz")); } @@ -59,12 +59,12 @@ int main(int argc, char **argv) int retval = 0; json_object_object_foreach(my_object, key2, val2) { - printf("Key at index %d is [%s] %d\n", new_count, lh_string_data(key2), + printf("Key at index %d is [%s] %d\n", new_count, json_key_data(key2), (val2 == NULL)); new_count++; - if (strcmp(lh_string_data(key2), "foo2") != 0) + if (strcmp(json_key_data(key2), "foo2") != 0) continue; - printf("pointer for key [%s] does %smatch\n", lh_string_data(key2), + printf("pointer for key [%s] does %smatch\n", json_key_data(key2), (key2 == original_key) ? "" : "NOT "); if (key2 != original_key) retval = 1; diff --git a/tests/test_deep_copy.c b/tests/test_deep_copy.c index b1c685e..421cb4f 100644 --- a/tests/test_deep_copy.c +++ b/tests/test_deep_copy.c @@ -93,14 +93,14 @@ int my_custom_serializer(struct json_object *jso, struct printbuf *pb, int level } json_c_shallow_copy_fn my_shallow_copy; -int my_shallow_copy(json_object *src, json_object *parent, const struct lh_string *key, - size_t index, json_object **dst) +int my_shallow_copy(json_object *src, json_object *parent, const struct json_key *key, size_t index, + json_object **dst) { int rc; rc = json_c_shallow_copy_default(src, parent, key, index, dst); if (rc < 0) return rc; - if (key != NULL && strcmp(lh_string_data(key), "with_serializer") == 0) + if (key != NULL && strcmp(json_key_data(key), "with_serializer") == 0) { printf("CALLED: my_shallow_copy on with_serializer object\n"); void *userdata = json_object_get_userdata(src); diff --git a/tests/test_null_keys_add.c b/tests/test_null_keys_add.c index a2965cd..51a21d8 100644 --- a/tests/test_null_keys_add.c +++ b/tests/test_null_keys_add.c @@ -114,8 +114,8 @@ int main(void) json_object_object_foreach(parsed, key, val) { putchar('\"'); - fwrite(lh_string_data(key), lh_string_size(key), 1, stdout); - printf("\" (%zd)\n", lh_string_size(key)); + fwrite(json_key_data(key), json_key_size(key), 1, stdout); + printf("\" (%zd)\n", json_key_size(key)); } return 1; } diff --git a/tests/test_null_keys_del.expected b/tests/test_null_keys_del.expected index 44f1682..043cd0c 100644 --- a/tests/test_null_keys_del.expected +++ b/tests/test_null_keys_del.expected @@ -1,5 +1,5 @@ Parsed input: { "biff\u0000": null, "\u0000zxcvbnm": 178 } Result is `json_type_object` -Expected keys ("biff\0" and "\0zxcvbnm") present with expected values +Expected keys ("biff\u0000" and "\u0000zxcvbnm") present with expected values Key deleted properly PASS diff --git a/tests/test_object_iterator.c b/tests/test_object_iterator.c index 9e0a178..755dd5d 100644 --- a/tests/test_object_iterator.c +++ b/tests/test_object_iterator.c @@ -31,7 +31,7 @@ int main(int atgc, char **argv) while (!json_object_iter_equal(&it, &itEnd)) { - printf("%s\n", lh_string_data(json_object_iter_peek_name(&it))); + printf("%s\n", json_key_data(json_object_iter_peek_name(&it))); printf("%s\n", json_object_to_json_string(json_object_iter_peek_value(&it))); json_object_iter_next(&it); } diff --git a/tests/test_parse.c b/tests/test_parse.c index 19238c4..df33d38 100644 --- a/tests/test_parse.c +++ b/tests/test_parse.c @@ -215,7 +215,7 @@ static void do_clear_serializer(json_object *jso) } static int clear_serializer(json_object *jso, int flags, json_object *parent_jso, - const struct lh_string *jso_key, size_t *jso_index, void *userarg) + const struct json_key *jso_key, size_t *jso_index, void *userarg) { if (jso) json_object_set_serializer(jso, NULL, NULL, NULL); diff --git a/tests/test_visit.c b/tests/test_visit.c index b226d87..fd4aba5 100644 --- a/tests/test_visit.c +++ b/tests/test_visit.c @@ -69,16 +69,16 @@ int main(void) } static int emit_object(json_object *jso, int flags, json_object *parent_jso, - const struct lh_string *jso_key, size_t *jso_index, void *userarg) + const struct json_key *jso_key, size_t *jso_index, void *userarg) { printf("flags: 0x%x, key: %s, index: %ld, value: %s\n", flags, - (jso_key ? lh_string_data(jso_key) : "(null)"), (jso_index ? (long)*jso_index : -1L), + (jso_key ? json_key_data(jso_key) : "(null)"), (jso_index ? (long)*jso_index : -1L), json_object_to_json_string(jso)); return JSON_C_VISIT_RETURN_CONTINUE; } static int skip_arrays(json_object *jso, int flags, json_object *parent_jso, - const struct lh_string *jso_key, size_t *jso_index, void *userarg) + const struct json_key *jso_key, size_t *jso_index, void *userarg) { (void)emit_object(jso, flags, parent_jso, jso_key, jso_index, userarg); if (json_object_get_type(jso) == json_type_array) @@ -87,15 +87,15 @@ static int skip_arrays(json_object *jso, int flags, json_object *parent_jso, } static int pop_and_stop(json_object *jso, int flags, json_object *parent_jso, - const struct lh_string *jso_key, size_t *jso_index, void *userarg) + const struct json_key *jso_key, size_t *jso_index, void *userarg) { (void)emit_object(jso, flags, parent_jso, jso_key, jso_index, userarg); - if (jso_key != NULL && strcmp(lh_string_data(jso_key), "subobj1") == 0) + if (jso_key != NULL && strcmp(json_key_data(jso_key), "subobj1") == 0) { printf("POP after handling subobj1\n"); return JSON_C_VISIT_RETURN_POP; } - if (jso_key != NULL && strcmp(lh_string_data(jso_key), "obj3") == 0) + if (jso_key != NULL && strcmp(json_key_data(jso_key), "obj3") == 0) { printf("STOP after handling obj3\n"); return JSON_C_VISIT_RETURN_STOP; @@ -104,10 +104,10 @@ static int pop_and_stop(json_object *jso, int flags, json_object *parent_jso, } static int err_on_subobj2(json_object *jso, int flags, json_object *parent_jso, - const struct lh_string *jso_key, size_t *jso_index, void *userarg) + const struct json_key *jso_key, size_t *jso_index, void *userarg) { (void)emit_object(jso, flags, parent_jso, jso_key, jso_index, userarg); - if (jso_key != NULL && strcmp(lh_string_data(jso_key), "subobj2") == 0) + if (jso_key != NULL && strcmp(json_key_data(jso_key), "subobj2") == 0) { printf("ERROR after handling subobj1\n"); return JSON_C_VISIT_RETURN_ERROR; @@ -116,7 +116,7 @@ static int err_on_subobj2(json_object *jso, int flags, json_object *parent_jso, } static int pop_array(json_object *jso, int flags, json_object *parent_jso, - const struct lh_string *jso_key, size_t *jso_index, void *userarg) + const struct json_key *jso_key, size_t *jso_index, void *userarg) { (void)emit_object(jso, flags, parent_jso, jso_key, jso_index, userarg); if (jso_index != NULL && (*jso_index == 0)) @@ -128,7 +128,7 @@ static int pop_array(json_object *jso, int flags, json_object *parent_jso, } static int stop_array(json_object *jso, int flags, json_object *parent_jso, - const struct lh_string *jso_key, size_t *jso_index, void *userarg) + const struct json_key *jso_key, size_t *jso_index, void *userarg) { (void)emit_object(jso, flags, parent_jso, jso_key, jso_index, userarg); if (jso_index != NULL && (*jso_index == 0)) @@ -140,10 +140,10 @@ static int stop_array(json_object *jso, int flags, json_object *parent_jso, } static int err_return(json_object *jso, int flags, json_object *parent_jso, - const struct lh_string *jso_key, size_t *jso_index, void *userarg) + const struct json_key *jso_key, size_t *jso_index, void *userarg) { printf("flags: 0x%x, key: %s, index: %ld, value: %s\n", flags, - (jso_key ? lh_string_data(jso_key) : "(null)"), (jso_index ? (long)*jso_index : -1L), + (jso_key ? json_key_data(jso_key) : "(null)"), (jso_index ? (long)*jso_index : -1L), json_object_to_json_string(jso)); return 100; }