Skip to content

Commit 178a4b0

Browse files
committed
Merge pull request json-c#21 from kdopen/add_iterator
Add new iterator implementation and some NULL-pointer safety
2 parents 7502b37 + bcfd1f5 commit 178a4b0

8 files changed

+522
-9
lines changed

debug.h

+26-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*
44
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
55
* Michael Clark <[email protected]>
6+
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
67
*
78
* This library is free software; you can redistribute it and/or modify
89
* it under the terms of the MIT license. See COPYING for details.
@@ -12,6 +13,8 @@
1213
#ifndef _DEBUG_H_
1314
#define _DEBUG_H_
1415

16+
#include <stdlib.h>
17+
1518
#ifdef __cplusplus
1619
extern "C" {
1720
#endif
@@ -25,21 +28,40 @@ extern void mc_debug(const char *msg, ...);
2528
extern void mc_error(const char *msg, ...);
2629
extern void mc_info(const char *msg, ...);
2730

31+
#ifndef __STRING
32+
#define __STRING(x) #x
33+
#endif
34+
35+
#ifndef PARSER_BROKEN_FIXED
36+
37+
#define JASSERT(cond) do {} while(0)
38+
39+
#else
40+
41+
#define JASSERT(cond) do { \
42+
if (!(cond)) { \
43+
mc_error("cjson assert failure %s:%d : cond \"" __STRING(cond) "failed\n", __FILE__, __LINE__); \
44+
*(int *)0 = 1;\
45+
abort(); \
46+
}\
47+
} while(0)
48+
49+
#endif
50+
51+
#define MC_ABORT(x, ...) mc_abort(x, ##__VA_ARGS__)
52+
#define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__)
53+
2854
#ifdef MC_MAINTAINER_MODE
2955
#define MC_SET_DEBUG(x) mc_set_debug(x)
3056
#define MC_GET_DEBUG() mc_get_debug()
3157
#define MC_SET_SYSLOG(x) mc_set_syslog(x)
32-
#define MC_ABORT(x, ...) mc_abort(x, ##__VA_ARGS__)
3358
#define MC_DEBUG(x, ...) mc_debug(x, ##__VA_ARGS__)
34-
#define MC_ERROR(x, ...) mc_error(x, ##__VA_ARGS__)
3559
#define MC_INFO(x, ...) mc_info(x, ##__VA_ARGS__)
3660
#else
3761
#define MC_SET_DEBUG(x) if (0) mc_set_debug(x)
3862
#define MC_GET_DEBUG() (0)
3963
#define MC_SET_SYSLOG(x) if (0) mc_set_syslog(x)
40-
#define MC_ABORT(x, ...) if (0) mc_abort(x, ##__VA_ARGS__)
4164
#define MC_DEBUG(x, ...) if (0) mc_debug(x, ##__VA_ARGS__)
42-
#define MC_ERROR(x, ...) if (0) mc_error(x, ##__VA_ARGS__)
4365
#define MC_INFO(x, ...) if (0) mc_info(x, ##__VA_ARGS__)
4466
#endif
4567

json.h

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*
44
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
55
* Michael Clark <[email protected]>
6+
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
67
*
78
* This library is free software; you can redistribute it and/or modify
89
* it under the terms of the MIT license. See COPYING for details.
@@ -23,6 +24,7 @@ extern "C" {
2324
#include "json_util.h"
2425
#include "json_object.h"
2526
#include "json_tokener.h"
27+
#include "json_object_iterator.h"
2628

2729
#ifdef __cplusplus
2830
}

json_object.c

+21-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*
44
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
55
* Michael Clark <[email protected]>
6+
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
67
*
78
* This library is free software; you can redistribute it and/or modify
89
* it under the terms of the MIT license. See COPYING for details.
@@ -24,11 +25,13 @@
2425
#include "json_object.h"
2526
#include "json_object_private.h"
2627
#include "json_util.h"
28+
#include "json_tokener.h"
2729

2830
#if !HAVE_STRNDUP
2931
char* strndup(const char* str, size_t n);
3032
#endif /* !HAVE_STRNDUP */
3133

34+
// Don't define this. It's not thread-safe.
3235
/* #define REFCOUNT_DEBUG 1 */
3336

3437
const char *json_number_chars = "0123456789.+-eE";
@@ -260,8 +263,24 @@ void json_object_object_add(struct json_object* jso, const char *key,
260263

261264
struct json_object* json_object_object_get(struct json_object* jso, const char *key)
262265
{
263-
if(!jso) return NULL;
264-
return (struct json_object*) lh_table_lookup(jso->o.c_object, key);
266+
struct json_object *result;
267+
json_object_object_get_ex(jso, key, &result);
268+
return result;
269+
}
270+
271+
json_bool json_object_object_get_ex(struct json_object* jso, const char *key, struct json_object **value)
272+
{
273+
if (NULL == jso) return FALSE;
274+
275+
switch(jso->o_type) {
276+
case json_type_object:
277+
return lh_table_lookup_ex(jso->o.c_object, (void*)key, (void**)value);
278+
default:
279+
if (value != NULL) {
280+
*value = NULL;
281+
}
282+
return FALSE;
283+
}
265284
}
266285

267286
void json_object_object_del(struct json_object* jso, const char *key)

json_object.h

+24
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*
44
* Copyright (c) 2004, 2005 Metaparadigm Pte. Ltd.
55
* Michael Clark <[email protected]>
6+
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
67
*
78
* This library is free software; you can redistribute it and/or modify
89
* 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,
172173
* @param obj the json_object instance
173174
* @param key the object field name
174175
* @returns the json_object associated with the given field name
176+
* @deprecated Please use json_object_object_get_ex
175177
*/
176178
extern struct json_object* json_object_object_get(struct json_object* obj,
177179
const char *key);
178180

181+
/** Get the json_object associated with a given object field.
182+
*
183+
* This returns true if the key is found, false in all other cases (including
184+
* if obj isn't a json_type_object).
185+
*
186+
* *No* reference counts will be changed. There is no need to manually adjust
187+
* reference counts through the json_object_put/json_object_get methods unless
188+
* you need to have the child (value) reference maintain a different lifetime
189+
* than the owning parent (obj). Ownership of value is retained by obj.
190+
*
191+
* @param obj the json_object instance
192+
* @param key the object field name
193+
* @param value a pointer where to store a reference to the json_object
194+
* associated with the given field name.
195+
*
196+
* It is safe to pass a NULL value.
197+
* @returns whether or not the key exists
198+
*/
199+
extern json_bool json_object_object_get_ex(struct json_object* obj,
200+
const char *key,
201+
struct json_object **value);
202+
179203
/** Delete the given json_object field
180204
*
181205
* The reference count will be decremented for the deleted object. If there

json_object_iterator.c

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/**
2+
*******************************************************************************
3+
* @file cjson_object_iterator.c
4+
*
5+
* Copyright (c) 2009 Hewlett-Packard Development Company, L.P.
6+
*
7+
* This library is free software; you can redistribute it and/or modify
8+
* it under the terms of the MIT license. See COPYING for details.
9+
*
10+
* @brief cjson forces clients to use its private data
11+
* structures for JSON Object iteration. This API
12+
* implementation corrects that by abstracting the
13+
* private cjson details.
14+
*
15+
*******************************************************************************
16+
*/
17+
18+
#include <stddef.h>
19+
#include <stdbool.h>
20+
21+
#include "json.h"
22+
#include "json_object_private.h"
23+
24+
#include "json_object_iterator.h"
25+
26+
/**
27+
* How It Works
28+
*
29+
* For each JSON Object, cjson maintains a linked list of zero
30+
* or more lh_entry (link-hash entry) structures inside the
31+
* Object's link-hash table (lh_table).
32+
*
33+
* Each lh_entry structure on the JSON Object's linked list
34+
* represents a single name/value pair. The "next" field of the
35+
* last lh_entry in the list is set to NULL, which terminates
36+
* the list.
37+
*
38+
* We represent a valid iterator that refers to an actual
39+
* name/value pair via a pointer to the pair's lh_entry
40+
* structure set as the iterator's opaque_ field.
41+
*
42+
* We follow cjson's current pair list representation by
43+
* representing a valid "end" iterator (one that refers past the
44+
* last pair) with a NULL value in the iterator's opaque_ field.
45+
*
46+
* A JSON Object without any pairs in it will have the "head"
47+
* field of its lh_table structure set to NULL. For such an
48+
* object, json_object_iter_begin will return an iterator with
49+
* the opaque_ field set to NULL, which is equivalent to the
50+
* "end" iterator.
51+
*
52+
* When iterating, we simply update the iterator's opaque_ field
53+
* to point to the next lh_entry structure in the linked list.
54+
* opaque_ will become NULL once we iterate past the last pair
55+
* in the list, which makes the iterator equivalent to the "end"
56+
* iterator.
57+
*/
58+
59+
/// Our current representation of the "end" iterator;
60+
///
61+
/// @note May not always be NULL
62+
static const void* kObjectEndIterValue = NULL;
63+
64+
/**
65+
* ****************************************************************************
66+
*/
67+
struct json_object_iterator
68+
json_object_iter_begin(struct json_object* obj)
69+
{
70+
struct json_object_iterator iter;
71+
struct lh_table* pTable;
72+
73+
/// @note json_object_get_object will return NULL if passed NULL
74+
/// or a non-json_type_object instance
75+
pTable = json_object_get_object(obj);
76+
JASSERT(NULL != pTable);
77+
78+
/// @note For a pair-less Object, head is NULL, which matches our
79+
/// definition of the "end" iterator
80+
iter.opaque_ = pTable->head;
81+
return iter;
82+
}
83+
84+
/**
85+
* ****************************************************************************
86+
*/
87+
struct json_object_iterator
88+
json_object_iter_end(const struct json_object* obj)
89+
{
90+
struct json_object_iterator iter;
91+
92+
JASSERT(NULL != obj);
93+
JASSERT(json_object_is_type(obj, json_type_object));
94+
95+
iter.opaque_ = kObjectEndIterValue;
96+
97+
return iter;
98+
}
99+
100+
/**
101+
* ****************************************************************************
102+
*/
103+
void
104+
json_object_iter_next(struct json_object_iterator* iter)
105+
{
106+
JASSERT(NULL != iter);
107+
JASSERT(kObjectEndIterValue != iter->opaque_);
108+
109+
iter->opaque_ = ((struct lh_entry *)iter->opaque_)->next;
110+
}
111+
112+
113+
/**
114+
* ****************************************************************************
115+
*/
116+
const char*
117+
json_object_iter_peek_name(const struct json_object_iterator* iter)
118+
{
119+
JASSERT(NULL != iter);
120+
JASSERT(kObjectEndIterValue != iter->opaque_);
121+
122+
return (const char*)(((struct lh_entry *)iter->opaque_)->k);
123+
}
124+
125+
126+
/**
127+
* ****************************************************************************
128+
*/
129+
struct json_object*
130+
json_object_iter_peek_value(const struct json_object_iterator* iter)
131+
{
132+
JASSERT(NULL != iter);
133+
JASSERT(kObjectEndIterValue != iter->opaque_);
134+
135+
return (struct json_object*)(((struct lh_entry *)iter->opaque_)->v);
136+
}
137+
138+
139+
/**
140+
* ****************************************************************************
141+
*/
142+
bool
143+
json_object_iter_equal(const struct json_object_iterator* iter1,
144+
const struct json_object_iterator* iter2)
145+
{
146+
JASSERT(NULL != iter1);
147+
JASSERT(NULL != iter2);
148+
149+
return (iter1->opaque_ == iter2->opaque_);
150+
}
151+
152+
153+
/**
154+
* ****************************************************************************
155+
*/
156+
struct json_object_iterator
157+
json_object_iter_init_default(void)
158+
{
159+
struct json_object_iterator iter;
160+
161+
/**
162+
* @note Make this a negative, invalid value, such that
163+
* accidental access to it would likely be trapped by the
164+
* hardware as an invalid address.
165+
*/
166+
iter.opaque_ = NULL;
167+
168+
return iter;
169+
}

0 commit comments

Comments
 (0)