Add new iterator implementation and some NULL-pointer safetytags/json-c-0.10-20120530
@@ -3,6 +3,7 @@ | |||
* | |||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. | |||
* Michael Clark <michael@metaparadigm.com> | |||
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P. | |||
* | |||
* This library is free software; you can redistribute it and/or modify | |||
* it under the terms of the MIT license. See COPYING for details. | |||
@@ -12,6 +13,8 @@ | |||
#ifndef _DEBUG_H_ | |||
#define _DEBUG_H_ | |||
#include <stdlib.h> | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
@@ -25,21 +28,40 @@ extern void mc_debug(const char *msg, ...); | |||
extern void mc_error(const char *msg, ...); | |||
extern void mc_info(const char *msg, ...); | |||
#ifndef __STRING | |||
#define __STRING(x) #x | |||
#endif | |||
#ifndef PARSER_BROKEN_FIXED | |||
#define JASSERT(cond) do {} while(0) | |||
#else | |||
#define JASSERT(cond) do { \ | |||
if (!(cond)) { \ | |||
mc_error("cjson assert failure %s:%d : cond \"" __STRING(cond) "failed\n", __FILE__, __LINE__); \ | |||
*(int *)0 = 1;\ | |||
abort(); \ | |||
}\ | |||
} while(0) | |||
#endif | |||
#define MC_ABORT(x, ...) mc_abort(x, ##__VA_ARGS__) | |||
#define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__) | |||
#ifdef MC_MAINTAINER_MODE | |||
#define MC_SET_DEBUG(x) mc_set_debug(x) | |||
#define MC_GET_DEBUG() mc_get_debug() | |||
#define MC_SET_SYSLOG(x) mc_set_syslog(x) | |||
#define MC_ABORT(x, ...) mc_abort(x, ##__VA_ARGS__) | |||
#define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__) | |||
#define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__) | |||
#define MC_INFO(x, ...) mc_info(x, ##__VA_ARGS__) | |||
#else | |||
#define MC_SET_DEBUG(x) if (0) mc_set_debug(x) | |||
#define MC_GET_DEBUG() (0) | |||
#define MC_SET_SYSLOG(x) if (0) mc_set_syslog(x) | |||
#define MC_ABORT(x, ...) if (0) mc_abort(x, ##__VA_ARGS__) | |||
#define MC_DEBUG(x, ...) if (0) mc_debug(x, ##__VA_ARGS__) | |||
#define MC_ERROR(x, ...) if (0) mc_error(x, ##__VA_ARGS__) | |||
#define MC_INFO(x, ...) if (0) mc_info(x, ##__VA_ARGS__) | |||
#endif | |||
@@ -3,6 +3,7 @@ | |||
* | |||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. | |||
* Michael Clark <michael@metaparadigm.com> | |||
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P. | |||
* | |||
* This library is free software; you can redistribute it and/or modify | |||
* it under the terms of the MIT license. See COPYING for details. | |||
@@ -23,6 +24,7 @@ extern "C" { | |||
#include "json_util.h" | |||
#include "json_object.h" | |||
#include "json_tokener.h" | |||
#include "json_object_iterator.h" | |||
#ifdef __cplusplus | |||
} | |||
@@ -3,6 +3,7 @@ | |||
* | |||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. | |||
* Michael Clark <michael@metaparadigm.com> | |||
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P. | |||
* | |||
* This library is free software; you can redistribute it and/or modify | |||
* it under the terms of the MIT license. See COPYING for details. | |||
@@ -24,11 +25,13 @@ | |||
#include "json_object.h" | |||
#include "json_object_private.h" | |||
#include "json_util.h" | |||
#include "json_tokener.h" | |||
#if !HAVE_STRNDUP | |||
char* strndup(const char* str, size_t n); | |||
#endif /* !HAVE_STRNDUP */ | |||
// Don't define this. It's not thread-safe. | |||
/* #define REFCOUNT_DEBUG 1 */ | |||
const char *json_number_chars = "0123456789.+-eE"; | |||
@@ -260,8 +263,24 @@ void json_object_object_add(struct json_object* jso, const char *key, | |||
struct json_object* json_object_object_get(struct json_object* jso, const char *key) | |||
{ | |||
if(!jso) return NULL; | |||
return (struct json_object*) lh_table_lookup(jso->o.c_object, key); | |||
struct json_object *result; | |||
json_object_object_get_ex(jso, key, &result); | |||
return result; | |||
} | |||
json_bool json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value) | |||
{ | |||
if (NULL == jso) return FALSE; | |||
switch(jso->o_type) { | |||
case json_type_object: | |||
return lh_table_lookup_ex(jso->o.c_object, (void*)key, (void**)value); | |||
default: | |||
if (value != NULL) { | |||
*value = NULL; | |||
} | |||
return FALSE; | |||
} | |||
} | |||
void json_object_object_del(struct json_object* jso, const char *key) | |||
@@ -3,6 +3,7 @@ | |||
* | |||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. | |||
* Michael Clark <michael@metaparadigm.com> | |||
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P. | |||
* | |||
* This library is free software; you can redistribute it and/or modify | |||
* it under the terms of the MIT license. See COPYING for details. | |||
@@ -172,10 +173,33 @@ extern void json_object_object_add(struct json_object* obj, const char *key, | |||
* @param obj the json_object instance | |||
* @param key the object field name | |||
* @returns the json_object associated with the given field name | |||
* @deprecated Please use json_object_object_get_ex | |||
*/ | |||
extern struct json_object* json_object_object_get(struct json_object* obj, | |||
const char *key); | |||
/** 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). | |||
* | |||
* *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. | |||
* | |||
* It is safe to pass a NULL value. | |||
* @returns whether or not the key exists | |||
*/ | |||
extern json_bool json_object_object_get_ex(struct json_object* obj, | |||
const char *key, | |||
struct json_object **value); | |||
/** Delete the given json_object field | |||
* | |||
* The reference count will be decremented for the deleted object. If there | |||
@@ -0,0 +1,169 @@ | |||
/** | |||
******************************************************************************* | |||
* @file cjson_object_iterator.c | |||
* | |||
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P. | |||
* | |||
* This library is free software; you can redistribute it and/or modify | |||
* it under the terms of the MIT license. See COPYING for details. | |||
* | |||
* @brief cjson forces clients to use its private data | |||
* structures for JSON Object iteration. This API | |||
* implementation corrects that by abstracting the | |||
* private cjson details. | |||
* | |||
******************************************************************************* | |||
*/ | |||
#include <stddef.h> | |||
#include <stdbool.h> | |||
#include "json.h" | |||
#include "json_object_private.h" | |||
#include "json_object_iterator.h" | |||
/** | |||
* How It Works | |||
* | |||
* For each JSON Object, cjson maintains a linked list of zero | |||
* or more lh_entry (link-hash entry) structures inside the | |||
* Object's link-hash table (lh_table). | |||
* | |||
* Each lh_entry structure on the JSON Object's linked list | |||
* represents a single name/value pair. The "next" field of the | |||
* last lh_entry in the list is set to NULL, which terminates | |||
* the list. | |||
* | |||
* We represent a valid iterator that refers to an actual | |||
* name/value pair via a pointer to the pair's lh_entry | |||
* structure set as the iterator's opaque_ field. | |||
* | |||
* We follow cjson's current pair list representation by | |||
* representing a valid "end" iterator (one that refers past the | |||
* last pair) with a NULL value in the iterator's opaque_ field. | |||
* | |||
* A JSON Object without any pairs in it will have the "head" | |||
* field of its lh_table structure set to NULL. For such an | |||
* object, json_object_iter_begin will return an iterator with | |||
* the opaque_ field set to NULL, which is equivalent to the | |||
* "end" iterator. | |||
* | |||
* When iterating, we simply update the iterator's opaque_ field | |||
* to point to the next lh_entry structure in the linked list. | |||
* opaque_ will become NULL once we iterate past the last pair | |||
* in the list, which makes the iterator equivalent to the "end" | |||
* iterator. | |||
*/ | |||
/// Our current representation of the "end" iterator; | |||
/// | |||
/// @note May not always be NULL | |||
static const void* kObjectEndIterValue = NULL; | |||
/** | |||
* **************************************************************************** | |||
*/ | |||
struct json_object_iterator | |||
json_object_iter_begin(struct json_object* obj) | |||
{ | |||
struct json_object_iterator iter; | |||
struct lh_table* pTable; | |||
/// @note json_object_get_object will return NULL if passed NULL | |||
/// or a non-json_type_object instance | |||
pTable = json_object_get_object(obj); | |||
JASSERT(NULL != pTable); | |||
/// @note For a pair-less Object, head is NULL, which matches our | |||
/// definition of the "end" iterator | |||
iter.opaque_ = pTable->head; | |||
return iter; | |||
} | |||
/** | |||
* **************************************************************************** | |||
*/ | |||
struct json_object_iterator | |||
json_object_iter_end(const struct json_object* obj) | |||
{ | |||
struct json_object_iterator iter; | |||
JASSERT(NULL != obj); | |||
JASSERT(json_object_is_type(obj, json_type_object)); | |||
iter.opaque_ = kObjectEndIterValue; | |||
return iter; | |||
} | |||
/** | |||
* **************************************************************************** | |||
*/ | |||
void | |||
json_object_iter_next(struct json_object_iterator* iter) | |||
{ | |||
JASSERT(NULL != iter); | |||
JASSERT(kObjectEndIterValue != iter->opaque_); | |||
iter->opaque_ = ((struct lh_entry *)iter->opaque_)->next; | |||
} | |||
/** | |||
* **************************************************************************** | |||
*/ | |||
const char* | |||
json_object_iter_peek_name(const struct json_object_iterator* iter) | |||
{ | |||
JASSERT(NULL != iter); | |||
JASSERT(kObjectEndIterValue != iter->opaque_); | |||
return (const char*)(((struct lh_entry *)iter->opaque_)->k); | |||
} | |||
/** | |||
* **************************************************************************** | |||
*/ | |||
struct json_object* | |||
json_object_iter_peek_value(const struct json_object_iterator* iter) | |||
{ | |||
JASSERT(NULL != iter); | |||
JASSERT(kObjectEndIterValue != iter->opaque_); | |||
return (struct json_object*)(((struct lh_entry *)iter->opaque_)->v); | |||
} | |||
/** | |||
* **************************************************************************** | |||
*/ | |||
bool | |||
json_object_iter_equal(const struct json_object_iterator* iter1, | |||
const struct json_object_iterator* iter2) | |||
{ | |||
JASSERT(NULL != iter1); | |||
JASSERT(NULL != iter2); | |||
return (iter1->opaque_ == iter2->opaque_); | |||
} | |||
/** | |||
* **************************************************************************** | |||
*/ | |||
struct json_object_iterator | |||
json_object_iter_init_default(void) | |||
{ | |||
struct json_object_iterator iter; | |||
/** | |||
* @note Make this a negative, invalid value, such that | |||
* accidental access to it would likely be trapped by the | |||
* hardware as an invalid address. | |||
*/ | |||
iter.opaque_ = NULL; | |||
return iter; | |||
} |
@@ -0,0 +1,254 @@ | |||
/** | |||
******************************************************************************* | |||
* @file json_object_iterator.h | |||
* | |||
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P. | |||
* | |||
* This library is free software; you can redistribute it and/or modify | |||
* it under the terms of the MIT license. See COPYING for details. | |||
* | |||
* @brief cjson forces clients to use its private data | |||
* structures for JSON Object iteration. This API | |||
* corrects that by abstracting the private cjson | |||
* details. | |||
* | |||
* The intention is to add this API (and its | |||
* implementation) to Palm's version of the cjson | |||
* library, at which point it can be removed from the | |||
* Wireless System Framework library implementation. | |||
* | |||
* API attributes: | |||
* * Thread-safe: NO | |||
* * Re-entrant: NO | |||
* | |||
******************************************************************************* | |||
*/ | |||
#ifndef JSON_OBJECT_ITERATOR_H | |||
#define JSON_OBJECT_ITERATOR_H | |||
#include <stddef.h> | |||
#include <stdbool.h> | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
/** | |||
* Forward declaration for the opaque iterator information. | |||
*/ | |||
struct json_object_iter_info_; | |||
/** | |||
* The opaque iterator that references a name/value pair within | |||
* a JSON Object intance or the "end" iterator value. | |||
*/ | |||
struct json_object_iterator { | |||
const void* opaque_; | |||
}; | |||
/** | |||
* forward declaration of cjson's JSON value instance structure | |||
*/ | |||
struct json_object; | |||
/** | |||
* Initializes an iterator structure to a "default" value that | |||
* is convenient for initializing an iterator variable to a | |||
* default state (e.g., initialization list in a class' | |||
* constructor). | |||
* | |||
* @code | |||
* struct json_object_iterator iter = json_object_iter_init_default(); | |||
* MyClass() : iter_(json_object_iter_init_default()) | |||
* @endcode | |||
* | |||
* @note The initialized value doesn't reference any specific | |||
* pair, is considered an invalid iterator, and MUST NOT | |||
* be passed to any cjson API that expects a valid | |||
* iterator. | |||
* | |||
* @note User and internal code MUST NOT make any assumptions | |||
* about and dependencies on the value of the "default" | |||
* iterator value. | |||
* | |||
* @return json_object_iterator | |||
*/ | |||
struct json_object_iterator | |||
json_object_iter_init_default(void); | |||
/** Retrieves an iterator to the first pair of the JSON Object. | |||
* | |||
* @note WARNING: Any modification of the underlying pair | |||
* invalidates all iterators to that pair. | |||
* | |||
* @param obj JSON Object instance (MUST be of type | |||
* json_type_object) | |||
* | |||
* @return json_object_iterator If the JSON Object has at | |||
* least one pair, on return, the iterator refers | |||
* to the first pair. If the JSON Object doesn't | |||
* have any pairs, the returned iterator is | |||
* equivalent to the "end" iterator for the same | |||
* JSON Object instance. | |||
* | |||
* @code | |||
* struct json_object_iterator it; | |||
* struct json_object_iterator itEnd; | |||
* struct json_object* obj = json_tokener_parse( | |||
* "{'first':'george', 'age':100}"); | |||
* json_object_iter_begin(obj, &it); | |||
* json_object_iter_end(obj, &itEnd); | |||
* while (!json_object_iter_equal(&it, &itEnd)) { | |||
* printf("%s\n", | |||
* json_object_iter_peek_name(&it)); | |||
* json_object_iter_next(&it); | |||
* } | |||
* | |||
* struct json_object* obj = json_tokener_parse( | |||
* "{'first':'george', 'age':100}"); | |||
* struct json_object_iterator it; | |||
* bool iterable = json_object_iter_begin(&it); | |||
* if (iterable) { | |||
* do { | |||
* printf("%s\n", json_object_iter_peek_name(&it)); | |||
* } while (json_object_iter_next(&it)); | |||
* } | |||
* @endcode | |||
*/ | |||
struct json_object_iterator | |||
json_object_iter_begin(struct json_object* obj); | |||
/** Retrieves the iterator that represents the position beyond the | |||
* last pair of the given JSON Object instance. | |||
* | |||
* @note WARNING: Do NOT write code that assumes that the "end" | |||
* iterator value is NULL, even if it is so in a | |||
* particular instance of the implementation. | |||
* | |||
* @note The reason we do not (and MUST NOT) provide | |||
* "json_object_iter_is_end(json_object_iterator* iter)" | |||
* type of API is because it would limit the underlying | |||
* representation of name/value containment (or force us | |||
* to add additional, otherwise unnecessary, fields to | |||
* the iterator structure). The "end" iterator and the | |||
* equality test method, on the other hand, permit us to | |||
* cleanly abstract pretty much any reasonable underlying | |||
* representation without burdening the iterator | |||
* structure with unnecessary data. | |||
* | |||
* @note For performance reasons, memoize the "end" iterator prior | |||
* to any loop. | |||
* | |||
* @param obj JSON Object instance (MUST be of type | |||
* json_type_object) | |||
* | |||
* @return json_object_iterator On return, the iterator refers | |||
* to the "end" of the Object instance's pairs | |||
* (i.e., NOT the last pair, but "beyond the last | |||
* pair" value) | |||
*/ | |||
struct json_object_iterator | |||
json_object_iter_end(const struct json_object* obj); | |||
/** Returns an iterator to the next pair, if any | |||
* | |||
* @note WARNING: Any modification of the underlying pair | |||
* invalidates all iterators to that pair. | |||
* | |||
* @param iter Iterator that references a name/value pair; | |||
* | |||
* @param iter [IN/OUT] Pointer to iterator that references a | |||
* name/value pair; MUST be a valid, non-end iterator. | |||
* WARNING: bad things will happen if invalid or "end" | |||
* iterator is passed. Upon return will contain the | |||
* reference to the next pair if there is one; if there | |||
* are no more pairs, will contain the "end" iterator | |||
* value, which may be compared against the return value | |||
* of json_object_iter_end() for the same JSON Object | |||
* instance. | |||
*/ | |||
void | |||
json_object_iter_next(struct json_object_iterator* iter); | |||
/** Returns a const pointer to the name of the pair referenced | |||
* by the given iterator. | |||
* | |||
* @param iter pointer to iterator that references a name/value | |||
* pair; MUST be a valid, non-end iterator. | |||
* WARNING: bad things will happen if invalid or | |||
* "end" iterator is passed. | |||
* | |||
* @return const char* Pointer to the name of the rerferenced | |||
* name/value pair. The name memory belongs to the | |||
* name/value pair, will be freed when the pair is | |||
* deleted or modified, and MUST NOT be modified or | |||
* freed by the user. | |||
*/ | |||
const char* | |||
json_object_iter_peek_name(const struct json_object_iterator* iter); | |||
/** Returns a pointer to the cjson instance representing the | |||
* value of the referenced name/value pair, without altering | |||
* the instance's reference count. | |||
* | |||
* @param iter pointer to iterator that references a name/value | |||
* pair; MUST be a valid, non-end iterator. | |||
* WARNING: bad things will happen if invalid or | |||
* "end" iterator is passed. | |||
* | |||
* @return struct json_object* Pointer to the cjson value | |||
* instance of the referenced name/value pair; the | |||
* value's reference count is not changed by this | |||
* function: if you plan to hold on to this cjson node, | |||
* take a look at json_object_get() and | |||
* json_object_put(). IMPORTANT: cjson API represents | |||
* the JSON Null value as a NULL json_object instance | |||
* pointer. | |||
*/ | |||
struct json_object* | |||
json_object_iter_peek_value(const struct json_object_iterator* iter); | |||
/** Tests two iterators for equality. Typically used to test | |||
* for end of iteration by comparing an iterator to the | |||
* corresponding "end" iterator (that was derived from the same | |||
* JSON Object instance). | |||
* | |||
* @note The reason we do not (and MUST NOT) provide | |||
* "json_object_iter_is_end(json_object_iterator* iter)" | |||
* type of API is because it would limit the underlying | |||
* representation of name/value containment (or force us | |||
* to add additional, otherwise unnecessary, fields to | |||
* the iterator structure). The equality test method, on | |||
* the other hand, permits us to cleanly abstract pretty | |||
* much any reasonable underlying representation. | |||
* | |||
* @param iter1 Pointer to first valid, non-NULL iterator | |||
* @param iter2 POinter to second valid, non-NULL iterator | |||
* | |||
* @note WARNING: if a NULL iterator pointer or an uninitialized | |||
* or invalid iterator, or iterators derived from | |||
* different JSON Object instances are passed, bad things | |||
* will happen! | |||
* | |||
* @return bool non-zero if iterators are equal (i.e., both | |||
* reference the same name/value pair or are both at | |||
* "end"); zero if they are not equal. | |||
*/ | |||
bool | |||
json_object_iter_equal(const struct json_object_iterator* iter1, | |||
const struct json_object_iterator* iter2); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif // JSON_OBJECT_ITERATOR_H |
@@ -3,6 +3,7 @@ | |||
* | |||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. | |||
* Michael Clark <michael@metaparadigm.com> | |||
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P. | |||
* | |||
* This library is free software; you can redistribute it and/or modify | |||
* it under the terms of the MIT license. See COPYING for details. | |||
@@ -174,11 +175,21 @@ struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k) | |||
const void* lh_table_lookup(struct lh_table *t, const void *k) | |||
{ | |||
struct lh_entry *e = lh_table_lookup_entry(t, k); | |||
if(e) return e->v; | |||
return NULL; | |||
void *result; | |||
lh_table_lookup_ex(t, k, &result); | |||
return result; | |||
} | |||
json_bool lh_table_lookup_ex(struct lh_table* t, const void* k, void **v) | |||
{ | |||
struct lh_entry *e = lh_table_lookup_entry(t, k); | |||
if (e != NULL) { | |||
if (v != NULL) *v = (void *)e->v; | |||
return TRUE; /* key found */ | |||
} | |||
if (v != NULL) *v = NULL; | |||
return FALSE; /* key not found */ | |||
} | |||
int lh_table_delete_entry(struct lh_table *t, struct lh_entry *e) | |||
{ | |||
@@ -3,6 +3,7 @@ | |||
* | |||
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd. | |||
* Michael Clark <michael@metaparadigm.com> | |||
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P. | |||
* | |||
* This library is free software; you can redistribute it and/or modify | |||
* it under the terms of the MIT license. See COPYING for details. | |||
@@ -12,6 +13,8 @@ | |||
#ifndef _linkhash_h_ | |||
#define _linkhash_h_ | |||
#include "json_object.h" | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
@@ -241,9 +244,18 @@ extern struct lh_entry* lh_table_lookup_entry(struct lh_table *t, const void *k) | |||
* @param t the table to lookup | |||
* @param k a pointer to the key to lookup | |||
* @return a pointer to the found value or NULL if it does not exist. | |||
* @deprecated Use lh_table_lookup_ex instead. | |||
*/ | |||
extern const void* lh_table_lookup(struct lh_table *t, const void *k); | |||
/** | |||
* Lookup a record in the table | |||
* @param t the table to lookup | |||
* @param k a pointer to the key to lookup | |||
* @param v a pointer to a where to store the found value (set to NULL if it doesn't exist). | |||
* @return whether or not the key was found | |||
*/ | |||
extern json_bool lh_table_lookup_ex(struct lh_table *t, const void *k, void **v); | |||
/** | |||
* Delete a record from the table. | |||