Browse Source

Merge 816b00c1c6 into 382f9462c2

pull/715/merge
Hex052 GitHub 4 years ago
parent
commit
bebda92feb
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1235 additions and 114 deletions
  1. +14
    -3
      json-c.sym
  2. +276
    -26
      json_object.c
  3. +385
    -30
      json_object.h
  4. +2
    -2
      json_object_iterator.c
  5. +2
    -1
      json_object_iterator.h
  6. +45
    -0
      json_object_private.h
  7. +3
    -2
      json_tokener.c
  8. +3
    -3
      json_tokener.h
  9. +3
    -1
      json_types.h
  10. +3
    -3
      json_visit.c
  11. +2
    -1
      json_visit.h
  12. +5
    -3
      linkhash.c
  13. +8
    -1
      linkhash.h
  14. +4
    -0
      tests/CMakeLists.txt
  15. +4
    -2
      tests/test1.c
  16. +13
    -10
      tests/testReplaceExisting.c
  17. +6
    -5
      tests/test_deep_copy.c
  18. +154
    -0
      tests/test_null_keys_add.c
  19. +8
    -0
      tests/test_null_keys_add.expected
  20. +1
    -0
      tests/test_null_keys_add.test
  21. +100
    -0
      tests/test_null_keys_del.c
  22. +5
    -0
      tests/test_null_keys_del.expected
  23. +1
    -0
      tests/test_null_keys_del.test
  24. +139
    -0
      tests/test_null_keys_get.c
  25. +6
    -0
      tests/test_null_keys_get.expected
  26. +1
    -0
      tests/test_null_keys_get.test
  27. +18
    -0
      tests/test_null_keys_print.c
  28. +1
    -0
      tests/test_null_keys_print.expected
  29. +1
    -0
      tests/test_null_keys_print.test
  30. +2
    -1
      tests/test_object_iterator.c
  31. +1
    -1
      tests/test_parse.c
  32. +19
    -19
      tests/test_visit.c

+ 14
- 3
json-c.sym View File

@@ -3,7 +3,7 @@
* Symbol versioning for libjson-c. * Symbol versioning for libjson-c.
* All exported symbols must be listed here. * All exported symbols must be listed here.
* *
* See
* See
* https://software.intel.com/sites/default/files/m/a/1/e/dsohowto.pdf * https://software.intel.com/sites/default/files/m/a/1/e/dsohowto.pdf
*/ */


@@ -165,6 +165,17 @@ JSONC_0.15 {
} JSONC_0.14; } JSONC_0.14;


JSONC_0.16 { JSONC_0.16 {
# global:
# ...new symbols here...
global:
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;
json_c_shallow_copy_default_len;
json_object_deep_copy_len;
} JSONC_0.15; } JSONC_0.15;

+ 276
- 26
json_object.c View File

@@ -41,6 +41,7 @@
#error "The long long type isn't 64-bits" #error "The long long type isn't 64-bits"
#endif #endif


#include <limits.h>
#ifndef SSIZE_T_MAX #ifndef SSIZE_T_MAX
#if SIZEOF_SSIZE_T == SIZEOF_INT #if SIZEOF_SSIZE_T == SIZEOF_INT
#define SSIZE_T_MAX INT_MAX #define SSIZE_T_MAX INT_MAX
@@ -520,7 +521,7 @@ static int json_object_object_to_json_string(struct json_object *jso, struct pri
printbuf_strappend(pb, " "); printbuf_strappend(pb, " ");
indent(pb, level + 1, flags); indent(pb, level + 1, flags);
printbuf_strappend(pb, "\""); printbuf_strappend(pb, "\"");
json_escape_str(pb, iter.key, strlen(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) if (flags & JSON_C_TO_STRING_SPACED)
printbuf_strappend(pb, "\": "); printbuf_strappend(pb, "\": ");
else else
@@ -585,43 +586,85 @@ struct lh_table *json_object_get_object(const struct json_object *jso)
int json_object_object_add_ex(struct json_object *jso, const char *const key, int json_object_object_add_ex(struct json_object *jso, const char *const key,
struct json_object *const val, const unsigned opts) struct json_object *const val, const unsigned opts)
{ {
struct json_object *existing_value = NULL;
return json_object_object_add_ex_len(jso, key, strlen(key), val, opts);
}

int json_object_object_add_ex_len(struct json_object *jso, const char *const key, const size_t len,
struct json_object *const val, const unsigned opts)
{
// 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
struct json_key hashable = {len, {key}};
return json_object_object_add_key(jso, &hashable, val, 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; struct lh_entry *existing_entry;
unsigned long hash; unsigned long hash;
/** Required due to the `lh_get_hash` function wanting a `const struct json_key *` */


assert(json_object_get_type(jso) == json_type_object); assert(json_object_get_type(jso) == json_type_object);


// The caller must avoid creating loops in the object tree, but do a
// quick check anyway to make sure we're not creating a trivial loop.
if (jso == val)
{
return -1;
}

// We lookup the entry and replace the value, rather than just deleting // We lookup the entry and replace the value, rather than just deleting
// and re-adding it, so the existing key remains valid. // and re-adding it, so the existing key remains valid.
hash = lh_get_hash(JC_OBJECT(jso)->c_object, (const void *)key);
hash = lh_get_hash(JC_OBJECT(jso)->c_object, key);
existing_entry = existing_entry =
(opts & JSON_C_OBJECT_ADD_KEY_IS_NEW) (opts & JSON_C_OBJECT_ADD_KEY_IS_NEW)
? NULL ? NULL
: lh_table_lookup_entry_w_hash(JC_OBJECT(jso)->c_object, (const void *)key, hash); : lh_table_lookup_entry_w_hash(JC_OBJECT(jso)->c_object, (const void *)key, hash);


// The caller must avoid creating loops in the object tree, but do a
// quick check anyway to make sure we're not creating a trivial loop.
if (jso == val)
return -1;

if (!existing_entry)
if (existing_entry == NULL)
{ {
const void *const k =
(opts & JSON_C_OBJECT_KEY_IS_CONSTANT) ? (const void *)key : strdup(key);
// need to copy `key` because the caller might have created it
// on the stack, which would be more efficient than copying
// `json_key_data` into `key->string.idata` if it had happened
// that `existing_entry` wasn't NULL.
const struct json_key *k =
(opts & JSON_C_OBJECT_KEY_IS_CONSTANT)
? 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) if (k == NULL)
{
return -1; return -1;
return lh_table_insert_w_hash(JC_OBJECT(jso)->c_object, k, val, hash, opts);
}
return lh_table_insert_w_hash(JC_OBJECT(jso)->c_object, k, val, hash,
opts & ~JSON_C_OBJECT_KEY_IS_CONSTANT);
// `struct json_key` always needs to be freed,
// so JSON_C_OBJECT_KEY_IS_CONSTANT cannot be set
}
else
{
existing_value = (json_object *)lh_entry_v(existing_entry);
if (existing_value)
{
json_object_put(existing_value);
}
existing_entry->v = val;
return 0;
} }
existing_value = (json_object *)lh_entry_v(existing_entry);
if (existing_value)
json_object_put(existing_value);
existing_entry->v = val;
return 0;
} }


int json_object_object_add(struct json_object *jso, const char *key, struct json_object *val) int json_object_object_add(struct json_object *jso, const char *key, struct json_object *val)
{ {
return json_object_object_add_ex(jso, key, val, 0);
return json_object_object_add_ex_len(jso, key, strlen(key), val, 0);
}

int json_object_object_add_len(struct json_object *jso, const char *key, const size_t len,
struct json_object *val)
{
return json_object_object_add_ex_len(jso, key, len, val, 0);
} }


int json_object_object_length(const struct json_object *jso) int json_object_object_length(const struct json_object *jso)
@@ -638,12 +681,26 @@ size_t json_c_object_sizeof(void)
struct json_object *json_object_object_get(const struct json_object *jso, const char *key) struct json_object *json_object_object_get(const struct json_object *jso, const char *key)
{ {
struct json_object *result = NULL; struct json_object *result = NULL;
json_object_object_get_ex(jso, key, &result);
json_object_object_get_ex_len(jso, key, strlen(key), &result);
return result;
}

struct json_object *json_object_object_get_len(const struct json_object *jso, const char *key,
const size_t len)
{
struct json_object *result = NULL;
json_object_object_get_ex_len(jso, key, len, &result);
return result; return result;
} }


json_bool json_object_object_get_ex(const struct json_object *jso, const char *key, json_bool json_object_object_get_ex(const struct json_object *jso, const char *key,
struct json_object **value) struct json_object **value)
{
return json_object_object_get_ex_len(jso, key, strlen(key), value);
}

json_bool json_object_object_get_ex_len(const struct json_object *jso, const char *key,
const size_t len, struct json_object **value)
{ {
if (value != NULL) if (value != NULL)
*value = NULL; *value = NULL;
@@ -654,8 +711,10 @@ json_bool json_object_object_get_ex(const struct json_object *jso, const char *k
switch (jso->o_type) switch (jso->o_type)
{ {
case json_type_object: case json_type_object:
return lh_table_lookup_ex(JC_OBJECT_C(jso)->c_object, (const void *)key,
(void **)value);
{
const struct json_key hashable = {len, {key}};
return json_object_object_get_key(jso, &hashable, value);
}
default: default:
if (value != NULL) if (value != NULL)
*value = NULL; *value = NULL;
@@ -663,10 +722,28 @@ json_bool json_object_object_get_ex(const struct json_object *jso, const char *k
} }
} }


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);
}

void json_object_object_del(struct json_object *jso, const char *key) 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 size_t len)
{
const struct json_key hashable = {len, {key}};
json_object_object_del_key(jso, &hashable);
}

int json_object_object_del_key(struct json_object *jso, const struct json_key *key)
{ {
assert(json_object_get_type(jso) == json_type_object); 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 */ /* json_object_boolean */
@@ -1153,7 +1230,7 @@ static int _json_object_userdata_to_json_string(struct json_object *jso, struct
int json_object_userdata_to_json_string(struct json_object *jso, struct printbuf *pb, int level, int json_object_userdata_to_json_string(struct json_object *jso, struct printbuf *pb, int level,
int flags) int flags)
{ {
int userdata_len = strlen((const char *)jso->_userdata);
size_t userdata_len = strlen((const char *)jso->_userdata);
printbuf_memappend(pb, (const char *)jso->_userdata, userdata_len); printbuf_memappend(pb, (const char *)jso->_userdata, userdata_len);
return userdata_len; return userdata_len;
} }
@@ -1658,6 +1735,28 @@ static int json_object_copy_serializer_data(struct json_object *src, struct json
*/ */
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 char *key,
size_t index, json_object **dst) size_t index, json_object **dst)
{
if (key == NULL)
{
return json_c_shallow_copy_default_len(src, parent, NULL, index, dst);
}
else
{
const struct json_key nkey = {strlen(key), {key}};
return json_c_shallow_copy_default_len(src, parent, &nkey, index, dst);
}
}

/**
* The default shallow copy implementation. Simply creates a new object of the same
* type but does *not* copy over _userdata nor retain any custom serializer.
* If custom serializers are in use, json_object_deep_copy() must be passed a shallow copy
* implementation that is aware of how to copy them.
*
* This always returns -1 or 1. It will never return 2 since it does not copy the serializer.
*/
int json_c_shallow_copy_default_len(json_object *src, json_object *parent,
const struct json_key *key, size_t index, json_object **dst)
{ {
switch (src->o_type) switch (src->o_type)
{ {
@@ -1733,14 +1832,15 @@ static int json_object_deep_copy_recursive(struct json_object *src, struct json_
/* This handles the `json_type_null` case */ /* This handles the `json_type_null` case */
if (!iter.val) if (!iter.val)
jso = NULL; jso = NULL;
else if (json_object_deep_copy_recursive(iter.val, src, iter.key, UINT_MAX, &jso,
shallow_copy) < 0)
else if (json_object_deep_copy_recursive(iter.val, src,
json_key_data(iter.key), UINT_MAX,
&jso, shallow_copy) < 0)
{ {
json_object_put(jso); json_object_put(jso);
return -1; return -1;
} }


if (json_object_object_add(*dst, iter.key, jso) < 0)
if (json_object_object_add_key(*dst, iter.key, jso, 0) < 0)
{ {
json_object_put(jso); json_object_put(jso);
return -1; return -1;
@@ -1783,6 +1883,89 @@ static int json_object_deep_copy_recursive(struct json_object *src, struct json_
return 0; return 0;
} }


/*
* The actual guts of json_object_deep_copy(), with a few additional args
* needed so we can keep track of where we are within the object tree.
*
* Note: caller is responsible for freeing *dst if this fails and returns -1.
*/
static int json_object_deep_copy_recursive_len(struct json_object *src, struct json_object *parent,
const struct json_key *key_in_parent,
size_t index_in_parent, struct json_object **dst,
json_c_shallow_copy_fn_len *shallow_copy)
{
struct json_object_iter iter;
size_t src_array_len, ii;

int shallow_copy_rc = 0;
shallow_copy_rc = shallow_copy(src, parent, key_in_parent, index_in_parent, dst);
/* -1=error, 1=object created ok, 2=userdata set */
if (shallow_copy_rc < 1)
{
errno = EINVAL;
return -1;
}
assert(*dst != NULL);

switch (src->o_type)
{
case json_type_object:
json_object_object_foreachC(src, iter)
{
struct json_object *jso = NULL;
/* This handles the `json_type_null` case */
if (!iter.val)
jso = NULL;
else if (json_object_deep_copy_recursive_len(
iter.val, src, iter.key, UINT_MAX, &jso, shallow_copy) < 0)
{
json_object_put(jso);
return -1;
}

if (json_object_object_add_key(*dst, iter.key, jso, 0) < 0)
{
json_object_put(jso);
return -1;
}
}
break;

case json_type_array:
src_array_len = json_object_array_length(src);
for (ii = 0; ii < src_array_len; ii++)
{
struct json_object *jso = NULL;
struct json_object *jso1 = json_object_array_get_idx(src, ii);
/* This handles the `json_type_null` case */
if (!jso1)
jso = NULL;
else if (json_object_deep_copy_recursive_len(jso1, src, NULL, ii, &jso,
shallow_copy) < 0)
{
json_object_put(jso);
return -1;
}

if (json_object_array_add(*dst, jso) < 0)
{
json_object_put(jso);
return -1;
}
}
break;

default:
break;
/* else, nothing to do, shallow_copy already did. */
}

if (shallow_copy_rc != 2)
return json_object_copy_serializer_data(src, *dst);

return 0;
}

int json_object_deep_copy(struct json_object *src, struct json_object **dst, int json_object_deep_copy(struct json_object *src, struct json_object **dst,
json_c_shallow_copy_fn *shallow_copy) json_c_shallow_copy_fn *shallow_copy)
{ {
@@ -1808,9 +1991,76 @@ int json_object_deep_copy(struct json_object *src, struct json_object **dst,
return rc; return rc;
} }


int json_object_deep_copy_len(struct json_object *src, struct json_object **dst,
json_c_shallow_copy_fn_len *shallow_copy)
{
int rc;

/* Check if arguments are sane ; *dst must not point to a non-NULL object */
if (!src || !dst || *dst)
{
errno = EINVAL;
return -1;
}

if (shallow_copy == NULL)
shallow_copy = json_c_shallow_copy_default_len;

rc = json_object_deep_copy_recursive_len(src, NULL, NULL, UINT_MAX, dst, shallow_copy);
if (rc < 0)
{
json_object_put(*dst);
*dst = NULL;
}

return rc;
}

static void json_abort(const char *message) static void json_abort(const char *message)
{ {
if (message != NULL) if (message != NULL)
fprintf(stderr, "json-c aborts with error: %s\n", message); fprintf(stderr, "json-c aborts with error: %s\n", message);
abort(); 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 = (ssize_t)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 = -((ssize_t)length);
memcpy(result->str.idata, data, length);
result->str.idata[length] = '\0';
return result;
}

+ 385
- 30
json_object.h View File

@@ -357,7 +357,8 @@ JSON_EXPORT int json_object_object_length(const struct json_object *obj);
*/ */
JSON_C_CONST_FUNCTION(JSON_EXPORT size_t json_c_object_sizeof(void)); JSON_C_CONST_FUNCTION(JSON_EXPORT size_t json_c_object_sizeof(void));


/** Add an object field to a json_object of type json_type_object
/**
* @brief Add an object field to a json_object of type json_type_object
* *
* The reference count of `val` will *not* be incremented, in effect * The reference count of `val` will *not* be incremented, in effect
* transferring ownership that object to `obj`, and thus `val` will be * transferring ownership that object to `obj`, and thus `val` will be
@@ -385,7 +386,39 @@ JSON_C_CONST_FUNCTION(JSON_EXPORT size_t json_c_object_sizeof(void));
JSON_EXPORT int json_object_object_add(struct json_object *obj, const char *key, JSON_EXPORT int json_object_object_add(struct json_object *obj, const char *key,
struct json_object *val); struct json_object *val);


/** Add an object field to a json_object of type json_type_object
/**
* @brief Add an object field to a json_object of type json_type_object
*
* The reference count of `val` will *not* be incremented, in effect
* transferring ownership that object to `obj`, and thus `val` will be
* freed when `obj` is. (i.e. through `json_object_put(obj)`)
*
* If you want to retain a reference to the added object, independent
* of the lifetime of obj, you must increment the refcount with
* `json_object_get(val)` (and later release it with json_object_put()).
*
* Since ownership transfers to `obj`, you must make sure
* that you do in fact have ownership over `val`. For instance,
* json_object_new_object() will give you ownership until you transfer it,
* whereas json_object_object_get() does not.
*
* Any previous object stored under `key` in `obj` will have its refcount
* decremented, and be freed normally if that drops to zero.
*
* @param obj the json_object instance
* @param key the object field name (a private copy will be duplicated),
* which is not terminated by a NULL ( @c '\0' ) character
* @param len the length of @p key
* @param val a json_object or NULL member to associate with the given field
*
* @return On success, @c 0 is returned.
* On error, a negative value is returned.
*/
JSON_EXPORT int json_object_object_add_len(struct json_object *obj, const char *key,
const size_t len, struct json_object *val);

/**
* @brief Add an object field to a json_object of type json_type_object
* *
* The semantics are identical to json_object_object_add, except that an * The semantics are identical to json_object_object_add, except that an
* additional flag fields gives you more control over some detail aspects * additional flag fields gives you more control over some detail aspects
@@ -397,12 +430,72 @@ JSON_EXPORT int json_object_object_add(struct json_object *obj, const char *key,
* @param val a json_object or NULL member to associate with the given field * @param val a json_object or NULL member to associate with the given field
* @param opts process-modifying options. To specify multiple options, use * @param opts process-modifying options. To specify multiple options, use
* (OPT1|OPT2) * (OPT1|OPT2)
*
* @return On success, @c 0 is returned.
* On error, a negative value is returned.
*/ */
JSON_EXPORT int json_object_object_add_ex(struct json_object *obj, const char *const key, JSON_EXPORT int json_object_object_add_ex(struct json_object *obj, const char *const key,
struct json_object *const val, const unsigned opts); 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, except that an
* additional flag fields gives you more control over some detail aspects
* of processing. See the description of JSON_C_OBJECT_ADD_* flags for more
* details.
*
* @param obj the json_object instance
* @param key the object field name (a private copy will be duplicated),
* which is not terminated by a NULL ( @c '\0' ) character
* @param len the length of @p key
* @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_ex_len(struct json_object *obj, const char *const key,
const size_t len, struct json_object *const val,
const unsigned opts);

/**
* @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
*
* @param obj the json_object instance
* @param key the object field name
* @returns the json_object associated with the given field name
* @see json_object_object_get_len()
*/
JSON_EXPORT struct json_object *json_object_object_get(const struct json_object *obj,
const char *key);
/**
* @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 * 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 * the field is not found, or if obj is not a json_type_object. If you
@@ -419,13 +512,35 @@ JSON_EXPORT int json_object_object_add_ex(struct json_object *obj, const char *c
* or transfer ownership to prevent a memory leak). * or transfer ownership to prevent a memory leak).
* *
* @param obj the json_object instance * @param obj the json_object instance
* @param key the object field name
* @param key the object field name,
* which is not terminated by a NULL ( @c '\0' ) character
* @param len the length of @p key
* @returns the json_object associated with the given field name * @returns the json_object associated with the given field name
*/ */
JSON_EXPORT struct json_object *json_object_object_get(const struct json_object *obj,
const char *key);


/** Get the json_object associated with a given object field.
JSON_EXPORT struct json_object *json_object_object_get_len(const struct json_object *obj,
const char *key, const size_t len);

/**
* @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
*
* @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 whether or not the key exists
* @see json_object_object_get_ex_len()
*/
JSON_EXPORT json_bool json_object_object_get_ex(const struct json_object *obj, const char *key,
struct json_object **value);

/**
* @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 * This returns true if the key is found, false in all other cases (including
* if obj isn't a json_type_object). * if obj isn't a json_type_object).
@@ -436,17 +551,41 @@ JSON_EXPORT struct json_object *json_object_object_get(const struct json_object
* than the owning parent (obj). Ownership of value is retained by obj. * than the owning parent (obj). Ownership of value is retained by obj.
* *
* @param obj the json_object instance * @param obj the json_object instance
* @param key the object field name
* @param key the object field name,
* which is not terminated by a NULL ( @c '\0' ) character
* @param len the length of @p key
* @param value a pointer where to store a reference to the json_object * @param value a pointer where to store a reference to the json_object
* associated with the given field name. * associated with the given field name.
*
* \n
* It is safe to pass a NULL value. * It is safe to pass a NULL value.
* @returns whether or not the key exists * @returns whether or not the key exists
*/ */
JSON_EXPORT json_bool json_object_object_get_ex(const struct json_object *obj, const char *key,
struct json_object **value);
JSON_EXPORT json_bool json_object_object_get_ex_len(const struct json_object *obj, const char *key,
const size_t len, struct json_object **value);

/**
* @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);


/** 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 * 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 * are no more owners of the value represented by this key, then the value is
@@ -458,7 +597,81 @@ JSON_EXPORT json_bool json_object_object_get_ex(const struct json_object *obj, c
JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key); JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key);


/** /**
* 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,
* which is not terminated by a NULL ( @c '\0' ) character
* @param len the length of @p key
*/
JSON_EXPORT void json_object_object_del_len(struct json_object *jso, const char *key,
const size_t len);

/**
* @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 *obj, 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.
*
* Deleting an existing key, or replacing an existing key with a
* new value IS allowed.
*
* @param obj the json_object instance
* @param key the local name for the `char *` key variable defined in the body
* @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)

#define json_object_object_foreach(obj, key, val) \
const char *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 = json_key_data((struct json_key *)lh_entry_k(entry##key)); \
val = (struct json_object *)lh_entry_v(entry##key); \
entry_next##key = entry##key->next; \
}; \
entry##key; \
}); \
entry##key = entry_next##key)

#else /* ANSI C or MSC */

#define json_object_object_foreach(obj, key, val) \
const char *key = NULL; \
struct json_object *val = NULL; \
struct lh_entry *entry##key; \
struct lh_entry *entry_next##key = NULL; \
for (entry##key = json_object_get_object(obj)->head; \
(entry##key ? (key = json_key_data((struct json_key *)lh_entry_k(entry##key)), \
val = (struct json_object *)lh_entry_v(entry##key), \
entry_next##key = entry##key->next, entry##key) \
: 0); \
entry##key = entry_next##key)

#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) && (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) */
/**
* @brief Iterate through all keys and values of an object.
* *
* Adding keys to the object while iterating is NOT allowed. * Adding keys to the object while iterating is NOT allowed.
* *
@@ -466,21 +679,22 @@ JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key
* new value IS allowed. * new value IS allowed.
* *
* @param obj the json_object instance * @param obj the json_object instance
* @param key the local name for the char* key variable defined in the body
* @param val the local name for the json_object* object variable defined in
* @param key the local name for the `struct json_key *` key variable defined in the body
* @param val the local name for the `json_object *` object variable defined in
* the body * 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; \
#define json_object_object_foreach_len(obj, key, val) \
struct json_key *key = NULL; \
struct json_object *val __attribute__((__unused__)) = NULL; \ struct json_object *val __attribute__((__unused__)) = NULL; \
for (struct lh_entry *entry##key = json_object_get_object(obj)->head, \ for (struct lh_entry *entry##key = json_object_get_object(obj)->head, \
*entry_next##key = NULL; \ *entry_next##key = NULL; \
({ \ ({ \
if (entry##key) \ if (entry##key) \
{ \ { \
key = (char *)lh_entry_k(entry##key); \
key = (struct json_key *)lh_entry_k(entry##key); \
val = (struct json_object *)lh_entry_v(entry##key); \ val = (struct json_object *)lh_entry_v(entry##key); \
entry_next##key = entry##key->next; \ entry_next##key = entry##key->next; \
}; \ }; \
@@ -490,13 +704,13 @@ JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key


#else /* ANSI C or MSC */ #else /* ANSI C or MSC */


#define json_object_object_foreach(obj, key, val) \
char *key = NULL; \
#define json_object_object_foreach_len(obj, key, val) \
struct json_key *key = NULL; \
struct json_object *val = NULL; \ struct json_object *val = NULL; \
struct lh_entry *entry##key; \ struct lh_entry *entry##key; \
struct lh_entry *entry_next##key = NULL; \ struct lh_entry *entry_next##key = NULL; \
for (entry##key = json_object_get_object(obj)->head; \ for (entry##key = json_object_get_object(obj)->head; \
(entry##key ? (key = (char *)lh_entry_k(entry##key), \
(entry##key ? (key = (struct json_key *)lh_entry_k(entry##key), \
val = (struct json_object *)lh_entry_v(entry##key), \ val = (struct json_object *)lh_entry_v(entry##key), \
entry_next##key = entry##key->next, entry##key) \ entry_next##key = entry##key->next, entry##key) \
: 0); \ : 0); \
@@ -504,13 +718,14 @@ JSON_EXPORT void json_object_object_del(struct json_object *obj, const char *key


#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) && (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) */ #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 obj the json_object instance
* @param iter the object iterator, use type json_object_iter * @param iter the object iterator, use type json_object_iter
*/ */
#define json_object_object_foreachC(obj, iter) \ #define json_object_object_foreachC(obj, iter) \
for (iter.entry = json_object_get_object(obj)->head; \ for (iter.entry = json_object_get_object(obj)->head; \
(iter.entry ? (iter.key = (char *)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) \ iter.val = (struct json_object *)lh_entry_v(iter.entry), iter.entry) \
: 0); \ : 0); \
iter.entry = iter.entry->next) iter.entry = iter.entry->next)
@@ -656,7 +871,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. * 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 * 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 * 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 * If any other object type is passed 0 will be returned, even non-empty
* json_type_array and json_type_object objects. * json_type_array and json_type_object objects.
* *
@@ -1011,7 +1226,11 @@ JSON_EXPORT struct json_object *json_object_new_null(void);
JSON_EXPORT int json_object_equal(struct json_object *obj1, struct json_object *obj2); JSON_EXPORT int json_object_equal(struct json_object *obj1, struct json_object *obj2);


/** /**
* Perform a shallow copy of src into *dst as part of an overall json_object_deep_copy().
* @deprecated This type is provided for backward-compatability only.
* It is reccomended to use `json_c_shallow_copy_fn_len` instead, and
* properly handle copying of keys with embedded NULL (<c>'\0'</c>) characters.
*
* @brief Perform a shallow copy of src into *dst as part of an overall json_object_deep_copy().
* *
* If src is part of a containing object or array, parent will be non-NULL, * If src is part of a containing object or array, parent will be non-NULL,
* and key or index will be provided. * and key or index will be provided.
@@ -1022,13 +1241,51 @@ JSON_EXPORT int json_object_equal(struct json_object *obj1, struct json_object *
* json_object_deep_copy that it should not attempt to use the standard userdata * json_object_deep_copy that it should not attempt to use the standard userdata
* copy function. * copy function.
* *
* @param src The source object to be copied
* @param parent The the parent of the current object
* @param key The key that <p>src</p> has in <p>parent</p>, if <p>parent</p>
* is an object
* @param index The index that <p>src</p> can be found at in <p>parent</p>,
* if <p>parent</p> is an array
* @param dst The destination object
*
* @return On success 1 or 2, -1 on errors * @return On success 1 or 2, -1 on errors
*
* @since 0.13
*
* @see json_c_shallow_copy_fn_len
*
*/ */
typedef int(json_c_shallow_copy_fn)(json_object *src, json_object *parent, const char *key, typedef int(json_c_shallow_copy_fn)(json_object *src, json_object *parent, const char *key,
size_t index, json_object **dst); size_t index, json_object **dst);


/** /**
* The default shallow copy implementation for use with json_object_deep_copy().
* @brief Perform a shallow copy of src into *dst as part of an overall json_object_deep_copy().
*
* If src is part of a containing object or array, parent will be non-NULL,
* and key or index will be provided.
* When shallow_copy is called *dst will be NULL, and must be non-NULL when it returns.
* src will never be NULL.
*
* If shallow_copy sets the serializer on an object, return 2 to indicate to
* json_object_deep_copy that it should not attempt to use the standard userdata
* copy function.
*
* @since 0.16
*
* @return On success 1 or 2, -1 on errors
*/
typedef int(json_c_shallow_copy_fn_len)(json_object *src, json_object *parent,
const struct json_key *key, size_t index,
json_object **dst);

/**
* @deprecated This type is provided for backward-compatability only.
* It is reccomended to use `json_c_shallow_copy_fn_len` instead, and
* properly handle copying of keys with embedded NULL (<c>'\0'</c>) characters.
*
* @brief The default shallow copy implementation for use with json_object_deep_copy().
*
* This simply calls the appropriate json_object_new_<type>() function and * This simply calls the appropriate json_object_new_<type>() function and
* copies over the serializer function (_to_json_string internal field of * copies over the serializer function (_to_json_string internal field of
* the json_object structure) but not any _userdata or _user_delete values. * the json_object structure) but not any _userdata or _user_delete values.
@@ -1037,12 +1294,38 @@ typedef int(json_c_shallow_copy_fn)(json_object *src, json_object *parent, const
* your own custom serializer, you can call this first to create the new object * your own custom serializer, you can call this first to create the new object
* before customizing it with json_object_set_serializer(). * before customizing it with json_object_set_serializer().
* *
* @since 0.13
*
* @return 1 on success, -1 on errors, but never 2. * @return 1 on success, -1 on errors, but never 2.
*
* @see json_c_shallow_copy_fn_len
*/ */
JSON_EXPORT json_c_shallow_copy_fn json_c_shallow_copy_default; JSON_EXPORT json_c_shallow_copy_fn json_c_shallow_copy_default;


/** /**
* Copy the contents of the JSON object.
* @brief The default shallow copy implementation for use with json_object_deep_copy().
*
* This simply calls the appropriate json_object_new_<type>() function and
* copies over the serializer function (_to_json_string internal field of
* the json_object structure) but not any _userdata or _user_delete values.
*
* If you're writing a custom shallow_copy function, perhaps because you're using
* your own custom serializer, you can call this first to create the new object
* before customizing it with json_object_set_serializer().
*
* @since 0.16
*
* @return 1 on success, -1 on errors, but never 2.
*/
JSON_EXPORT json_c_shallow_copy_fn_len json_c_shallow_copy_default_len;

/**
* @deprecated This function is provided for backward-compatability only.
* It is reccomended to use `json_object_deep_copy_len` instead, as it will
* properly handle copying of keys with embedded NULL (<c>'\0'</c>) characters.
*
* @brief Copy the contents of the JSON object.
*
* The destination object must be initialized to NULL, * The destination object must be initialized to NULL,
* to make sure this function won't overwrite an existing JSON object. * to make sure this function won't overwrite an existing JSON object.
* *
@@ -1056,12 +1339,84 @@ JSON_EXPORT json_c_shallow_copy_fn json_c_shallow_copy_default;
* when custom serializers are in use. See also * when custom serializers are in use. See also
* json_object set_serializer. * json_object set_serializer.
* *
* @since 0.13
*
* @returns 0 if the copy went well, -1 if an error occured during copy * @returns 0 if the copy went well, -1 if an error occured during copy
* or if the destination pointer is non-NULL * or if the destination pointer is non-NULL
*/ */

JSON_EXPORT int json_object_deep_copy(struct json_object *src, struct json_object **dst, JSON_EXPORT int json_object_deep_copy(struct json_object *src, struct json_object **dst,
json_c_shallow_copy_fn *shallow_copy); json_c_shallow_copy_fn *shallow_copy);

/**
* @brief Copy the contents of the JSON object.
*
* The destination object must be initialized to NULL,
* to make sure this function won't overwrite an existing JSON object.
*
* This does roughly the same thing as
* `json_tokener_parse(json_object_get_string(src))`.
*
* @param src source JSON object whose contents will be copied
* @param dst pointer to the destination object where the contents of `src`;
* make sure this pointer is initialized to NULL
* @param shallow_copy an optional function to copy individual objects, needed
* when custom serializers are in use. See also
* json_object set_serializer.
*
* @since 0.16
*
* @returns 0 if the copy went well, -1 if an error occured during copy
* or if the destination pointer is non-NULL
*/
JSON_EXPORT int json_object_deep_copy_len(struct json_object *src, struct json_object **dst,
json_c_shallow_copy_fn_len *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 #ifdef __cplusplus
} }
#endif #endif


+ 2
- 2
json_object_iterator.c View File

@@ -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 json_key *json_object_iter_peek_name(const struct json_object_iterator *iter)
{ {
JASSERT(NULL != iter); JASSERT(NULL != iter);
JASSERT(kObjectEndIterValue != iter->opaque_); JASSERT(kObjectEndIterValue != iter->opaque_);


return (const char *)(((const struct lh_entry *)iter->opaque_)->k);
return (const struct json_key *)(((const struct lh_entry *)iter->opaque_)->k);
} }


/** /**


+ 2
- 1
json_object_iterator.h View File

@@ -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 * deleted or modified, and MUST NOT be modified or
* freed by the user. * freed by the user.
*/ */
JSON_EXPORT const char *json_object_iter_peek_name(const struct json_object_iterator *iter);
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 /** Returns a pointer to the json-c instance representing the
* value of the referenced name/value pair, without altering * value of the referenced name/value pair, without altering


+ 45
- 0
json_object_private.h View File

@@ -98,8 +98,53 @@ struct json_object_string


void _json_c_set_last_err(const char *err_fmt, ...); void _json_c_set_last_err(const char *err_fmt, ...);


/**
* The characters that can make up hexadecimal numbers
*/
extern const char *json_hex_chars; 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.
*/
char idata[0];
} str;
};

#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif


+ 3
- 2
json_tokener.c View File

@@ -1131,7 +1131,8 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *
{ {
printbuf_memappend_fast(tok->pb, case_start, printbuf_memappend_fast(tok->pb, case_start,
str - case_start); str - case_start);
obj_field_name = strdup(tok->pb->buf);
obj_field_name =
json_key_new_imm(tok->pb->bpos, tok->pb->buf);
saved_state = json_tokener_state_object_field_end; saved_state = json_tokener_state_object_field_end;
state = json_tokener_state_eatws; state = json_tokener_state_eatws;
break; break;
@@ -1179,7 +1180,7 @@ struct json_object *json_tokener_parse_ex(struct json_tokener *tok, const char *
goto redo_char; goto redo_char;


case json_tokener_state_object_value_add: case json_tokener_state_object_value_add:
json_object_object_add(current, obj_field_name, obj);
json_object_object_add_key(current, obj_field_name, obj, 0);
free(obj_field_name); free(obj_field_name);
obj_field_name = NULL; obj_field_name = NULL;
saved_state = json_tokener_state_object_sep; saved_state = json_tokener_state_object_sep;


+ 3
- 3
json_tokener.h View File

@@ -85,7 +85,7 @@ struct json_tokener_srec
enum json_tokener_state state, saved_state; enum json_tokener_state state, saved_state;
struct json_object *obj; struct json_object *obj;
struct json_object *current; struct json_object *current;
char *obj_field_name;
struct json_key *obj_field_name;
}; };


#define JSON_TOKENER_DEFAULT_DEPTH 32 #define JSON_TOKENER_DEFAULT_DEPTH 32
@@ -215,7 +215,7 @@ JSON_EXPORT struct json_tokener *json_tokener_new_ex(int depth);
JSON_EXPORT void json_tokener_free(struct json_tokener *tok); JSON_EXPORT void json_tokener_free(struct json_tokener *tok);


/** /**
* Reset the state of a json_tokener, to prepare to parse a
* Reset the state of a json_tokener, to prepare to parse a
* brand new JSON object. * brand new JSON object.
*/ */
JSON_EXPORT void json_tokener_reset(struct json_tokener *tok); JSON_EXPORT void json_tokener_reset(struct json_tokener *tok);
@@ -279,7 +279,7 @@ JSON_EXPORT void json_tokener_set_flags(struct json_tokener *tok, int flags);
* the length of the last len parameter passed in. * the length of the last len parameter passed in.
* *
* The tokener does \b not maintain an internal buffer so the caller is * The tokener does \b not maintain an internal buffer so the caller is
* responsible for a subsequent call to json_tokener_parse_ex with an
* responsible for a subsequent call to json_tokener_parse_ex with an
* appropriate str parameter starting with the extra characters. * appropriate str parameter starting with the extra characters.
* *
* This interface is presently not 64-bit clean due to the int len argument * This interface is presently not 64-bit clean due to the int len argument


+ 3
- 1
json_types.h View File

@@ -33,7 +33,7 @@ struct printbuf;
*/ */
struct json_object_iter struct json_object_iter
{ {
char *key;
struct json_key *key;
struct json_object *val; struct json_object *val;
struct lh_entry *entry; struct lh_entry *entry;
}; };
@@ -71,6 +71,8 @@ typedef enum json_type
json_type_string json_type_string
} json_type; } json_type;


typedef struct json_key json_key;

#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif


+ 3
- 3
json_visit.c View File

@@ -13,7 +13,7 @@
#include "json_visit.h" #include "json_visit.h"
#include "linkhash.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 json_key *jso_key,
size_t *jso_index, json_c_visit_userfunc *userfunc, void *userarg); 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) 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; 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 json_key *jso_key,
size_t *jso_index, json_c_visit_userfunc *userfunc, void *userarg) size_t *jso_index, json_c_visit_userfunc *userfunc, void *userarg)
{ {
int userret = userfunc(jso, 0, parent_jso, jso_key, jso_index, userarg); int userret = userfunc(jso, 0, parent_jso, jso_key, jso_index, userarg);
@@ -57,7 +57,7 @@ static int _json_c_visit(json_object *jso, json_object *parent_jso, const char *


case json_type_object: case json_type_object:
{ {
json_object_object_foreach(jso, key, child)
json_object_object_foreach_len(jso, key, child)
{ {
userret = _json_c_visit(child, jso, key, NULL, userfunc, userarg); userret = _json_c_visit(child, jso, key, NULL, userfunc, userarg);
if (userret == JSON_C_VISIT_RETURN_POP) if (userret == JSON_C_VISIT_RETURN_POP)


+ 2
- 1
json_visit.h View File

@@ -13,7 +13,8 @@ extern "C" {
#endif #endif


typedef int(json_c_visit_userfunc)(json_object *jso, int flags, json_object *parent_jso, 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 json_key *jso_key, size_t *jso_index,
void *userarg);


/** /**
* Visit each object in the JSON hierarchy starting at jso. * Visit each object in the JSON hierarchy starting at jso.


+ 5
- 3
linkhash.c View File

@@ -30,6 +30,7 @@
#endif #endif


#include "linkhash.h" #include "linkhash.h"
#include "math_compat.h"
#include "random_seed.h" #include "random_seed.h"


/* hash functions */ /* hash functions */
@@ -485,13 +486,14 @@ static unsigned long lh_char_hash(const void *k)
random_seed = seed; /* potentially racy */ random_seed = seed; /* potentially racy */
#endif #endif
} }
return hashlittle((const char *)k, strlen((const char *)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) int lh_char_equal(const void *k1, const void *k2)
{ {
return (strcmp((const char *)k1, (const char *)k2) == 0);
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, struct lh_table *lh_table_new(int size, lh_entry_free_fn *free_fn, lh_hash_fn *hash_fn,


+ 8
- 1
linkhash.h View File

@@ -137,7 +137,14 @@ struct lh_table
* A pointer onto the function responsible for freeing an entry. * A pointer onto the function responsible for freeing an entry.
*/ */
lh_entry_free_fn *free_fn; lh_entry_free_fn *free_fn;
/**
* A function that is capable of hashing entries in this table
*/
lh_hash_fn *hash_fn; lh_hash_fn *hash_fn;
/**
* A function that is capable of determining if entries in this table
* are equal
*/
lh_equal_fn *equal_fn; lh_equal_fn *equal_fn;
}; };
typedef struct lh_table lh_table; typedef struct lh_table lh_table;
@@ -311,7 +318,7 @@ int lh_table_resize(struct lh_table *t, int new_size);
/** /**
* @deprecated Don't use this outside of linkhash.h: * @deprecated Don't use this outside of linkhash.h:
*/ */
#if (defined(AIX_CC) || (defined(_MSC_VER) && (_MSC_VER <= 1800)) )
#if (defined(AIX_CC) || (defined(_MSC_VER) && (_MSC_VER <= 1800)))
/* VS2010 can't handle inline funcs, so skip it there */ /* VS2010 can't handle inline funcs, so skip it there */
#define _LH_INLINE #define _LH_INLINE
#else #else


+ 4
- 0
tests/CMakeLists.txt View File

@@ -26,6 +26,10 @@ set(ALL_TEST_NAMES
test_int_add test_int_add
test_locale test_locale
test_null test_null
test_null_keys_add
test_null_keys_get
test_null_keys_del
test_null_keys_print
test_parse test_parse
test_parse_int64 test_parse_int64
test_printbuf test_printbuf


+ 4
- 2
tests/test1.c View File

@@ -304,9 +304,11 @@ int main(int argc, char **argv)


/*json_object_object_add(my_object, "arr", my_array);*/ /*json_object_object_add(my_object, "arr", my_array);*/
printf("my_object=\n"); printf("my_object=\n");
json_object_object_foreach(my_object, key, val)
json_object_object_foreach_len(my_object, key, val)
{ {
printf("\t%s: %s\n", key, json_object_to_json_string(val));
putchar('\t');
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)); printf("my_object.to_string()=%s\n", json_object_to_json_string(my_object));




+ 13
- 10
tests/testReplaceExisting.c View File

@@ -37,30 +37,33 @@ int main(int argc, char **argv)


printf("==== replace-value first loop starting ====\n"); printf("==== replace-value first loop starting ====\n");


const char *original_key = NULL;
const struct json_key *original_key = NULL;
orig_count = 0; orig_count = 0;
json_object_object_foreach(my_object, key, val)
json_object_object_foreach_len(my_object, key, val)
{ {
printf("Key at index %d is [%s] %d\n", orig_count, key, (val == NULL));
printf("Key at index %d is [%s] %d\n", orig_count, json_key_data(key),
(val == NULL));
orig_count++; orig_count++;
if (strcmp(key, "foo2") != 0)
if (strcmp(json_key_data(key), "foo2") != 0)
continue; continue;
printf("replacing value for key [%s]\n", key);
printf("replacing value for key [%s]\n", json_key_data(key));
original_key = key; original_key = key;
json_object_object_add(my_object, key, json_object_new_string("zzz"));
json_object_object_add(my_object, json_key_data(key),
json_object_new_string("zzz"));
} }


printf("==== second loop starting ====\n"); printf("==== second loop starting ====\n");


int new_count = 0; int new_count = 0;
int retval = 0; int retval = 0;
json_object_object_foreach(my_object, key2, val2)
json_object_object_foreach_len(my_object, key2, val2)
{ {
printf("Key at index %d is [%s] %d\n", new_count, key2, (val2 == NULL));
printf("Key at index %d is [%s] %d\n", new_count, json_key_data(key2),
(val2 == NULL));
new_count++; new_count++;
if (strcmp(key2, "foo2") != 0)
if (strcmp(json_key_data(key2), "foo2") != 0)
continue; continue;
printf("pointer for key [%s] does %smatch\n", key2,
printf("pointer for key [%s] does %smatch\n", json_key_data(key2),
(key2 == original_key) ? "" : "NOT "); (key2 == original_key) ? "" : "NOT ");
if (key2 != original_key) if (key2 != original_key)
retval = 1; retval = 1;


+ 6
- 5
tests/test_deep_copy.c View File

@@ -92,15 +92,16 @@ int my_custom_serializer(struct json_object *jso, struct printbuf *pb, int level
return 0; return 0;
} }


json_c_shallow_copy_fn my_shallow_copy;
int my_shallow_copy(json_object *src, json_object *parent, const char *key, size_t index,
json_c_shallow_copy_fn_len my_shallow_copy;
int my_shallow_copy(json_object *src, json_object *parent, const struct json_key *key, size_t index,
json_object **dst) json_object **dst)
{ {
int rc; int rc;
rc = json_c_shallow_copy_default(src, parent, key, index, dst);
rc = json_c_shallow_copy_default_len(src, parent, key, index, dst);
if (rc < 0) if (rc < 0)
return rc; return rc;
if (key != NULL && strcmp(key, "with_serializer") == 0)
if (key != NULL && json_key_size(key) == 15 &&
strcmp(json_key_data(key), "with_serializer") == 0)
{ {
printf("CALLED: my_shallow_copy on with_serializer object\n"); printf("CALLED: my_shallow_copy on with_serializer object\n");
void *userdata = json_object_get_userdata(src); void *userdata = json_object_get_userdata(src);
@@ -199,7 +200,7 @@ int main(int argc, char **argv)
dst1 = NULL; dst1 = NULL;
/* With a custom serializer in use, a custom shallow_copy function must also be used */ /* With a custom serializer in use, a custom shallow_copy function must also be used */
assert(-1 == json_object_deep_copy(src1, &dst1, NULL)); assert(-1 == json_object_deep_copy(src1, &dst1, NULL));
assert(0 == json_object_deep_copy(src1, &dst1, my_shallow_copy));
assert(0 == json_object_deep_copy_len(src1, &dst1, my_shallow_copy));


json_object *dest_with_serializer = json_object_object_get(dst1, "with_serializer"); json_object *dest_with_serializer = json_object_object_get(dst1, "with_serializer");
assert(dest_with_serializer != NULL); assert(dest_with_serializer != NULL);


+ 154
- 0
tests/test_null_keys_add.c View File

@@ -0,0 +1,154 @@
/*
* Tests if binary strings are supported.
*/

#include "config.h"
#include <stdio.h>
#include <string.h>

#include "json_inttypes.h"
#include "json_object.h"
#include "json_tokener.h"
#include "linkhash.h"

int main(void)
{
/* this test has embedded null characters in the key and value.
* check that it's still included after deserializing. */
const char *input = "{ \"foo\": 14.5, \"bar\": [] }";
const char *foo_key = "foo";
const char *foo_value = "14.5";
const char *bar_key = "bar";

const char *toadd_key = "foo\0bar";
const int toadd_key_len = 7;
const char *toadd_key_printable = "foo\\0bar";
const char *toadd_value = "qwerty\0asdf";
const int toadd_value_len = 12;
const char *toadd_value_printable = "qwerty\\0asdf";

struct json_object *parsed = json_tokener_parse(input);

printf("Parsed input: %s\n", input);
printf("Result is ");
if (parsed == NULL)
{
printf("NULL (error!)\n");
return 1; // Error somewhere
}
else if (!json_object_is_type(parsed, json_type_object))
{
printf("not `json_type_object` (error!)\n");
return 1; // Error somewhere
}
else
{
printf("`json_type_object`\n");
}

// Check nothing odd happened in parsing
if (json_object_object_length(parsed) != 2)
{
printf("Should contain two fields (has %d) (error!)",
json_object_object_length(parsed));
return 1;
}
json_bool key_present = json_object_object_get_ex(parsed, foo_key, NULL);
if (!key_present)
{
printf("Should contain key \"%s\", but does not (error!)", foo_key);
return 1;
}
key_present = json_object_object_get_ex(parsed, bar_key, NULL);
if (!key_present)
{
printf("Should contain key \"%s\", but does not (error!)", bar_key);
return 1;
}

// Check the previous keys are still the same present
struct json_object *foo = json_object_object_get(parsed, foo_key);
if (!json_object_is_type(foo, json_type_double))
{
printf("Key \"%s\" should be `json_type_double` (%d) but was %d (error!)\n",
foo_key, (int)json_type_double, json_object_get_type(foo));
return 1;
}
else
{
printf("Key \"%s\" parsed as right type\n", foo_key);
}
struct json_object *bar = json_object_object_get(parsed, bar_key);
if (!json_object_is_type(bar, json_type_array))
{
printf("Key \"%s\" should be `json_type_array` (%d) but was %d (error!)\n", bar_key,
(int)json_type_array, json_object_get_type(bar));
return 1;
}
else
{
printf("Key \"%s\" parsed as right type\n", bar_key);
}

// Add the new key
struct json_object *new_str = json_object_new_string_len(toadd_value, toadd_value_len);
if (json_object_object_add_ex_len(parsed, toadd_key, toadd_key_len, new_str,
JSON_C_OBJECT_KEY_IS_CONSTANT) != 0)
{
printf("An error occured adding the key \"%s\" (error!)\n", toadd_key_printable);
return 1;
}

// Check the new key was actually added
if (json_object_object_length(parsed) != 3)
{
printf("Should contain three fields after adding new key (has %d) (error!)",
json_object_object_length(parsed));
return 1;
}
else if (json_object_object_get_len(parsed, toadd_key, toadd_key_len) != new_str)
{
printf("Have three keys, but don't have the right value in \"%s\" (error!)\n",
toadd_key_printable);
printf("Keys :\n");
json_object_object_foreach_len(parsed, key, val)
{
putchar('\"');
fwrite(json_key_data(key), json_key_size(key), 1, stdout);
printf("\" (%zd)\n", json_key_size(key));
}
return 1;
}
else
{
printf("Added the key \"%s\" successfully\n", toadd_key_printable);
}

// Check the previous keys are still the same present
foo = json_object_object_get(parsed, foo_key);
if (!json_object_is_type(foo, json_type_double))
{
printf("Key \"%s\" should be `json_type_double` (%d) but was %d (error!)\n",
foo_key, (int)json_type_double, json_object_get_type(foo));
return 1;
}
else
{
printf("Key \"%s\" is still the same\n", foo_key);
}
bar = json_object_object_get(parsed, bar_key);
if (!json_object_is_type(bar, json_type_array))
{
printf("Key \"%s\" should be `json_type_array` (%d) but was %d (error!)\n", bar_key,
(int)json_type_array, json_object_get_type(bar));
return 1;
}
else
{
printf("Key \"%s\" is still the same\n", bar_key);
}

json_object_put(parsed);
printf("PASS\n");
return 0;
}

+ 8
- 0
tests/test_null_keys_add.expected View File

@@ -0,0 +1,8 @@
Parsed input: { "foo": 14.5, "bar": [] }
Result is `json_type_object`
Key "foo" parsed as right type
Key "bar" parsed as right type
Added the key "foo\0bar" successfully
Key "foo" is still the same
Key "bar" is still the same
PASS

+ 1
- 0
tests/test_null_keys_add.test View File

@@ -0,0 +1 @@
test_basic.test

+ 100
- 0
tests/test_null_keys_del.c View File

@@ -0,0 +1,100 @@
/*
* Tests if binary strings are supported.
*/

#include "config.h"
#include <stdio.h>
#include <string.h>

#include "json_inttypes.h"
#include "json_object.h"
#include "json_tokener.h"

int main(void)
{
/* this test has embedded null characters in the key and value.
* check that it's still included after deserializing. */
const char *input = "{ \"biff\\u0000\": null, \"\\u0000zxcvbnm\": 178 }";
const char *expected_biff = "biff\0";
const int expected_biff_len = 5;
const char *expected_biff_printable = "biff\\u0000";
const char *expected_zxcv = "\0zxcvbnm";
const int expected_zxcv_len = 8;
const char *expected_zxcv_printable = "\\u0000zxcvbnm";

struct json_object *parsed = json_tokener_parse(input);
struct json_object *val;
json_bool key_present;

printf("Parsed input: %s\n", input);
printf("Result is ");
if (parsed == NULL)
{
printf("NULL (error!)\n");
return 1; // Error somewhere
}
else if (!json_object_is_type(parsed, json_type_object))
{
printf("not `json_type_object` (error!)\n");
return 1; // Error somewhere
}
else
{
printf("`json_type_object`\n");
}

// Check nothing odd happened in parsing
if (json_object_object_length(parsed) != 2)
{
printf("Should contain two fields (has %d) (error!)",
json_object_object_length(parsed));
return 1;
}

key_present = json_object_object_get_ex_len(parsed, expected_biff, expected_biff_len, &val);
if (!key_present || !json_object_is_type(val, json_type_null))
{
printf("The key \"%s\" should be present and should be NULL (error!)\n",
expected_biff_printable);
return 1;
}
key_present = json_object_object_get_ex_len(parsed, expected_zxcv, expected_zxcv_len, &val);
if (!key_present || !json_object_is_type(val, json_type_int) ||
json_object_get_int(val) != 178)
{
printf("The key \"%s\" should be present and should be 178 (error!)\n",
expected_zxcv_printable);
return 1;
}
printf("Expected keys (\"%s\" and \"%s\") present with expected values\n",
expected_biff_printable, expected_zxcv_printable);

// Delete one key
json_object_object_del_len(parsed, expected_zxcv, expected_zxcv_len);

// Check it is gone
if (json_object_object_length(parsed) != 1)
{
printf("Should contain only one field (has %d) (error!)",
json_object_object_length(parsed));
return 1;
}
key_present = json_object_object_get_ex_len(parsed, expected_biff, expected_biff_len, &val);
if (!key_present || !json_object_is_type(val, json_type_null))
{
printf("The key \"%s\" should be present and should be NULL (error!)\n",
expected_biff_printable);
return 1;
}
key_present = json_object_object_get_ex_len(parsed, expected_zxcv, expected_zxcv_len, &val);
if (key_present)
{
printf("The key \"%s\" should not be present (error!)\n", expected_zxcv_printable);
return 1;
}
printf("Key deleted properly\n");

json_object_put(parsed);
printf("PASS\n");
return 0;
}

+ 5
- 0
tests/test_null_keys_del.expected View File

@@ -0,0 +1,5 @@
Parsed input: { "biff\u0000": null, "\u0000zxcvbnm": 178 }
Result is `json_type_object`
Expected keys ("biff\u0000" and "\u0000zxcvbnm") present with expected values
Key deleted properly
PASS

+ 1
- 0
tests/test_null_keys_del.test View File

@@ -0,0 +1 @@
test_basic.test

+ 139
- 0
tests/test_null_keys_get.c View File

@@ -0,0 +1,139 @@
/*
* Tests if binary strings are supported.
*/

#include "config.h"
#include <stdio.h>
#include <string.h>

#include "json_inttypes.h"
#include "json_object.h"
#include "json_tokener.h"

int main(void)
{
/* this test has embedded null characters in the key and value.
* check that it's still included after deserializing. */
const char *input = "{ \"foo\\u0000bar\": \"qwerty\\u0000asdf\" }";
const char *expected_key = "foo\0bar";
const int expected_key_len = 7;
const char *expected_key_printable = "foo\\0bar";
const char *expected_value = "qwerty\0asdf";
const int expected_value_len = 11;
const char *expected_value_printable = "qwerty\\0asdf";

struct json_object *parsed = json_tokener_parse(input);

printf("Parsed input: %s\n", input);
printf("Result is ");
if (parsed == NULL)
{
printf("NULL (error!)\n");
return 1; // Error somewhere
}
else if (!json_object_is_type(parsed, json_type_object))
{
printf("not `json_type_object` (error!)\n");
return 1; // Error somewhere
}
else
{
printf("`json_type_object`\n");
}

// Check nothing odd happened in parsing
if (json_object_object_length(parsed) != 1)
{
printf("Should contain only one field (has %d) (error!)",
json_object_object_length(parsed));
return 1;
}
json_bool key_present = json_object_object_get_ex(parsed, expected_key, NULL);
if (key_present)
{
printf("The key \"%s\" should not be present when calling "
"`json_object_object_get_ex` "
"(the real key contains a NUL character). (error!)\n",
expected_key);
return 1;
}

// Check the key is present
struct json_object *string;
key_present = json_object_object_get_ex_len(parsed, expected_key, 7, &string);
if (!key_present)
{
printf("The key \"%s\" should be present when calling "
"`json_object_object_get_ex_len` (error!)\n",
expected_key_printable);
return 1;
}
else if (string == NULL)
{
printf("The key \"%s\" was present when calling "
"`json_object_object_get_ex_len`, but got NULL (error!)\n",
expected_key_printable);
return 1;
}
struct json_object *from_get_len = json_object_object_get_len(parsed, expected_key, 7);
if (string != from_get_len)
{
printf("The value returned from `json_object_object_get_len` should be the "
"same as the one from `json_object_object_get_ex_len` (error!)\n"
"Got %p from `json_object_object_get_ex_len` but %p from "
"`json_object_object_get_len`\n",
string, from_get_len);
return 1;
}
else
{
printf("Key was present and same for "
"`json_object_object_get_ex_len` and `json_object_object_get_len`\n");
}

// Check the value is right
if (!json_object_is_type(string, json_type_string))
{
printf(
"Value is wrong type, expected `json_type_string` (%d) but got %d (error!)\n",
json_type_string, json_object_get_type(string));
return 1;
}
else
{
printf("Value is right type, `json_type_string`\n");
}
const int actual_value_len = json_object_get_string_len(string);
const char *actual_value = json_object_get_string(string);
if (actual_value_len != expected_value_len)
{
printf("Value is wrong length, expected %d but got %d (error!)\n",
expected_value_len, actual_value_len);
return 1;
}
else if (memcmp(expected_value, actual_value, actual_value_len) != 0)
{
printf("Expected \"%s\" but got \"", expected_value_printable);
for (int i = 0; i < actual_value_len; ++i)
{
if (actual_value[i] == '\0')
{
puts("\\0");
}
else
{
putchar(actual_value[i]);
}
}
printf("\"\n");
return 1;
}
else
{
printf("Expected value matches actual\n");
}

json_object_put(parsed);
printf("PASS\n");
return 0;
}

+ 6
- 0
tests/test_null_keys_get.expected View File

@@ -0,0 +1,6 @@
Parsed input: { "foo\u0000bar": "qwerty\u0000asdf" }
Result is `json_type_object`
Key was present and same for `json_object_object_get_ex_len` and `json_object_object_get_len`
Value is right type, `json_type_string`
Expected value matches actual
PASS

+ 1
- 0
tests/test_null_keys_get.test View File

@@ -0,0 +1 @@
test_basic.test

+ 18
- 0
tests/test_null_keys_print.c View File

@@ -0,0 +1,18 @@
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "json.h"
#include "parse_flags.h"

int main(int argc, char **argv)
{
struct json_object *new_obj;

new_obj = json_tokener_parse("{ \"foo\\u0000bar\": \"qwerty\\u0000asdf\" }");
printf("new_obj.to_string()=%s\n", json_object_to_json_string(new_obj));
json_object_put(new_obj);

return EXIT_SUCCESS;
}

+ 1
- 0
tests/test_null_keys_print.expected View File

@@ -0,0 +1 @@
new_obj.to_string()={ "foo\u0000bar": "qwerty\u0000asdf" }

+ 1
- 0
tests/test_null_keys_print.test View File

@@ -0,0 +1 @@
test_basic.test

+ 2
- 1
tests/test_object_iterator.c View File

@@ -6,6 +6,7 @@
#include "json_object.h" #include "json_object.h"
#include "json_object_iterator.h" #include "json_object_iterator.h"
#include "json_tokener.h" #include "json_tokener.h"
#include "linkhash.h"


int main(int atgc, char **argv) int main(int atgc, char **argv)
{ {
@@ -30,7 +31,7 @@ int main(int atgc, char **argv)


while (!json_object_iter_equal(&it, &itEnd)) while (!json_object_iter_equal(&it, &itEnd))
{ {
printf("%s\n", 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))); printf("%s\n", json_object_to_json_string(json_object_iter_peek_value(&it)));
json_object_iter_next(&it); json_object_iter_next(&it);
} }


+ 1
- 1
tests/test_parse.c View File

@@ -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, static int clear_serializer(json_object *jso, int flags, json_object *parent_jso,
const char *jso_key, size_t *jso_index, void *userarg)
const struct json_key *jso_key, size_t *jso_index, void *userarg)
{ {
if (jso) if (jso)
json_object_set_serializer(jso, NULL, NULL, NULL); json_object_set_serializer(jso, NULL, NULL, NULL);


+ 19
- 19
tests/test_visit.c View File

@@ -68,17 +68,17 @@ int main(void)
return 0; return 0;
} }


static int emit_object(json_object *jso, int flags, json_object *parent_jso, const char *jso_key,
size_t *jso_index, void *userarg)
static int emit_object(json_object *jso, int flags, json_object *parent_jso,
const struct json_key *jso_key, size_t *jso_index, void *userarg)
{ {
printf("flags: 0x%x, key: %s, index: %ld, value: %s\n", flags, printf("flags: 0x%x, key: %s, index: %ld, value: %s\n", flags,
(jso_key ? 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)); json_object_to_json_string(jso));
return JSON_C_VISIT_RETURN_CONTINUE; return JSON_C_VISIT_RETURN_CONTINUE;
} }


static int skip_arrays(json_object *jso, int flags, json_object *parent_jso, const char *jso_key,
size_t *jso_index, void *userarg)
static int skip_arrays(json_object *jso, int flags, json_object *parent_jso,
const struct json_key *jso_key, size_t *jso_index, void *userarg)
{ {
(void)emit_object(jso, flags, parent_jso, jso_key, jso_index, userarg); (void)emit_object(jso, flags, parent_jso, jso_key, jso_index, userarg);
if (json_object_get_type(jso) == json_type_array) if (json_object_get_type(jso) == json_type_array)
@@ -86,16 +86,16 @@ static int skip_arrays(json_object *jso, int flags, json_object *parent_jso, con
return JSON_C_VISIT_RETURN_CONTINUE; return JSON_C_VISIT_RETURN_CONTINUE;
} }


static int pop_and_stop(json_object *jso, int flags, json_object *parent_jso, const char *jso_key,
size_t *jso_index, void *userarg)
static int pop_and_stop(json_object *jso, int flags, json_object *parent_jso,
const struct json_key *jso_key, size_t *jso_index, void *userarg)
{ {
(void)emit_object(jso, flags, parent_jso, jso_key, jso_index, userarg); (void)emit_object(jso, flags, parent_jso, jso_key, jso_index, userarg);
if (jso_key != NULL && strcmp(jso_key, "subobj1") == 0)
if (jso_key != NULL && strcmp(json_key_data(jso_key), "subobj1") == 0)
{ {
printf("POP after handling subobj1\n"); printf("POP after handling subobj1\n");
return JSON_C_VISIT_RETURN_POP; return JSON_C_VISIT_RETURN_POP;
} }
if (jso_key != NULL && strcmp(jso_key, "obj3") == 0)
if (jso_key != NULL && strcmp(json_key_data(jso_key), "obj3") == 0)
{ {
printf("STOP after handling obj3\n"); printf("STOP after handling obj3\n");
return JSON_C_VISIT_RETURN_STOP; return JSON_C_VISIT_RETURN_STOP;
@@ -103,11 +103,11 @@ static int pop_and_stop(json_object *jso, int flags, json_object *parent_jso, co
return JSON_C_VISIT_RETURN_CONTINUE; return JSON_C_VISIT_RETURN_CONTINUE;
} }


static int err_on_subobj2(json_object *jso, int flags, json_object *parent_jso, const char *jso_key,
size_t *jso_index, void *userarg)
static int err_on_subobj2(json_object *jso, int flags, json_object *parent_jso,
const struct json_key *jso_key, size_t *jso_index, void *userarg)
{ {
(void)emit_object(jso, flags, parent_jso, jso_key, jso_index, userarg); (void)emit_object(jso, flags, parent_jso, jso_key, jso_index, userarg);
if (jso_key != NULL && strcmp(jso_key, "subobj2") == 0)
if (jso_key != NULL && strcmp(json_key_data(jso_key), "subobj2") == 0)
{ {
printf("ERROR after handling subobj1\n"); printf("ERROR after handling subobj1\n");
return JSON_C_VISIT_RETURN_ERROR; return JSON_C_VISIT_RETURN_ERROR;
@@ -115,8 +115,8 @@ static int err_on_subobj2(json_object *jso, int flags, json_object *parent_jso,
return JSON_C_VISIT_RETURN_CONTINUE; return JSON_C_VISIT_RETURN_CONTINUE;
} }


static int pop_array(json_object *jso, int flags, json_object *parent_jso, const char *jso_key,
size_t *jso_index, void *userarg)
static int pop_array(json_object *jso, int flags, json_object *parent_jso,
const struct json_key *jso_key, size_t *jso_index, void *userarg)
{ {
(void)emit_object(jso, flags, parent_jso, jso_key, jso_index, userarg); (void)emit_object(jso, flags, parent_jso, jso_key, jso_index, userarg);
if (jso_index != NULL && (*jso_index == 0)) if (jso_index != NULL && (*jso_index == 0))
@@ -127,8 +127,8 @@ static int pop_array(json_object *jso, int flags, json_object *parent_jso, const
return JSON_C_VISIT_RETURN_CONTINUE; return JSON_C_VISIT_RETURN_CONTINUE;
} }


static int stop_array(json_object *jso, int flags, json_object *parent_jso, const char *jso_key,
size_t *jso_index, void *userarg)
static int stop_array(json_object *jso, int flags, json_object *parent_jso,
const struct json_key *jso_key, size_t *jso_index, void *userarg)
{ {
(void)emit_object(jso, flags, parent_jso, jso_key, jso_index, userarg); (void)emit_object(jso, flags, parent_jso, jso_key, jso_index, userarg);
if (jso_index != NULL && (*jso_index == 0)) if (jso_index != NULL && (*jso_index == 0))
@@ -139,11 +139,11 @@ static int stop_array(json_object *jso, int flags, json_object *parent_jso, cons
return JSON_C_VISIT_RETURN_CONTINUE; return JSON_C_VISIT_RETURN_CONTINUE;
} }


static int err_return(json_object *jso, int flags, json_object *parent_jso, const char *jso_key,
size_t *jso_index, void *userarg)
static int err_return(json_object *jso, int flags, json_object *parent_jso,
const struct json_key *jso_key, size_t *jso_index, void *userarg)
{ {
printf("flags: 0x%x, key: %s, index: %ld, value: %s\n", flags, printf("flags: 0x%x, key: %s, index: %ld, value: %s\n", flags,
(jso_key ? 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)); json_object_to_json_string(jso));
return 100; return 100;
} }

Loading…
Cancel
Save