2 * Copyright (c) 2010 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Portions Copyright (c) 2010 Apple Inc. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 heim_base2json(heim_object_t obj
,
42 void (*out
)(const char *, void *), void *ctx
);
45 heim_base2json(heim_object_t obj
,
46 void (*out
)(const char *, void *), void *ctx
)
48 heim_tid_t type
= heim_get_tid(obj
);
49 __block
int fail
= 0, needcomma
= 0;
54 heim_array_iterate(obj
, ^(heim_object_t sub
) {
57 fail
|= heim_base2json(sub
, out
, ctx
);
65 heim_dict_iterate(obj
, ^(heim_object_t key
, heim_object_t value
) {
68 fail
|= heim_base2json(key
, out
, ctx
);
70 fail
|= heim_base2json(value
, out
, ctx
);
78 out(heim_string_get_utf8(obj
), ctx
);
82 case HEIM_TID_NUMBER
: {
84 snprintf(num
, sizeof(num
), "%d", heim_number_get_int(obj
));
92 out(heim_bool_val(obj
) ? "true" : "false", ctx
);
107 unsigned long lineno
;
109 const uint8_t *pstart
;
116 parse_value(struct parse_ctx
*ctx
);
119 white_spaces(struct parse_ctx
*ctx
)
121 while (ctx
->p
< ctx
->pend
) {
123 if (c
== ' ' || c
== '\t' || c
== '\r') {
125 } else if (c
== '\n') {
137 return ('0' <= n
&& n
<= '9');
141 parse_number(struct parse_ctx
*ctx
)
143 int number
= 0, neg
= 1;
145 if (ctx
->p
>= ctx
->pend
)
148 if (*ctx
->p
== '-') {
153 while (ctx
->p
< ctx
->pend
) {
154 if (is_number(*ctx
->p
)) {
155 number
= (number
* 10) + (*ctx
->p
- '0');
162 return heim_number_create(number
* neg
);
166 parse_string(struct parse_ctx
*ctx
)
168 const uint8_t *start
;
171 heim_assert(*ctx
->p
== '"', "string doesnt' start with \"");
174 while (ctx
->p
< ctx
->pend
) {
175 if (*ctx
->p
== '\n') {
177 } else if (*ctx
->p
== '\\') {
178 if (ctx
->p
+ 1 == ctx
->pend
)
182 } else if (*ctx
->p
== '"') {
187 p
= p0
= malloc(ctx
->p
- start
);
190 while (start
< ctx
->p
) {
191 if (*start
== '\\') {
193 /* XXX validate qouted char */
197 o
= heim_string_create_with_bytes(p0
, p
- p0
);
200 o
= heim_string_create_with_bytes(start
, ctx
->p
- start
);
209 ctx
->error
= heim_error_create(EINVAL
, "ran out of string");
214 parse_pair(heim_dict_t dict
, struct parse_ctx
*ctx
)
219 if (white_spaces(ctx
))
225 key
= parse_string(ctx
);
229 if (white_spaces(ctx
))
232 if (*ctx
->p
!= ':') {
239 if (white_spaces(ctx
)) {
244 value
= parse_value(ctx
);
249 heim_dict_set_value(dict
, key
, value
);
253 if (white_spaces(ctx
))
256 if (*ctx
->p
== '}') {
259 } else if (*ctx
->p
== ',') {
267 parse_dict(struct parse_ctx
*ctx
)
269 heim_dict_t dict
= heim_dict_create(11);
272 heim_assert(*ctx
->p
== '{', "string doesn't start with {");
275 while ((ret
= parse_pair(dict
, ctx
)) > 0)
285 parse_item(heim_array_t array
, struct parse_ctx
*ctx
)
289 if (white_spaces(ctx
))
295 value
= parse_value(ctx
);
299 heim_array_append_value(array
, value
);
302 if (white_spaces(ctx
))
305 if (*ctx
->p
== ']') {
308 } else if (*ctx
->p
== ',') {
316 parse_array(struct parse_ctx
*ctx
)
318 heim_array_t array
= heim_array_create();
321 heim_assert(*ctx
->p
== '[', "array doesn't start with [");
324 while ((ret
= parse_item(array
, ctx
)) > 0)
334 parse_value(struct parse_ctx
*ctx
)
338 if (white_spaces(ctx
))
341 if (*ctx
->p
== '"') {
342 return parse_string(ctx
);
343 } else if (*ctx
->p
== '{') {
344 return parse_dict(ctx
);
345 } else if (*ctx
->p
== '[') {
346 return parse_array(ctx
);
347 } else if (is_number(*ctx
->p
) || *ctx
->p
== '-') {
348 return parse_number(ctx
);
351 len
= ctx
->pend
- ctx
->p
;
353 if (len
>= 4 && memcmp(ctx
->p
, "null", 4) == 0) {
355 return heim_null_create();
356 } else if (len
>= 4 && strncasecmp((char *)ctx
->p
, "true", 4) == 0) {
358 return heim_bool_create(1);
359 } else if (len
>= 5 && strncasecmp((char *)ctx
->p
, "false", 5) == 0) {
361 return heim_bool_create(0);
364 ctx
->error
= heim_error_create(EINVAL
, "unknown char %c at %lu line %lu",
366 (unsigned long)(ctx
->p
- ctx
->pstart
),
373 heim_json_create(const char *string
, heim_error_t
*error
)
375 return heim_json_create_with_bytes(string
, strlen(string
), error
);
379 heim_json_create_with_bytes(const void *data
, size_t length
, heim_error_t
*error
)
381 struct parse_ctx ctx
;
387 ctx
.pend
= ((uint8_t *)data
) + length
;
390 o
= parse_value(&ctx
);
392 if (o
== NULL
&& error
) {
394 } else if (ctx
.error
) {
395 heim_release(ctx
.error
);