dont entrust sprintf to encode binary packets
[heimdal.git] / base / json.c
blob3ddfb3df8104845672b35bc81001578e26991393
1 /*
2 * Copyright (c) 2010 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
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
10 * are met:
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
33 * SUCH DAMAGE.
36 #include "baselocl.h"
37 #include <ctype.h>
39 #if 0
40 int
41 heim_base2json(heim_object_t obj,
42 void (*out)(const char *, void *), void *ctx);
44 int
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;
51 switch (type) {
52 case HEIM_TID_ARRAY:
53 out("[ ", ctx);
54 heim_array_iterate(obj, ^(heim_object_t sub) {
55 if (needcomma)
56 out(", ", ctx);
57 fail |= heim_base2json(sub, out, ctx);
58 needcomma = 1;
59 });
60 out("]", ctx);
61 break;
63 case HEIM_TID_DICT:
64 out("{ ", ctx);
65 heim_dict_iterate(obj, ^(heim_object_t key, heim_object_t value) {
66 if (needcomma)
67 out(", ", ctx);
68 fail |= heim_base2json(key, out, ctx);
69 out(" = ", ctx);
70 fail |= heim_base2json(value, out, ctx);
71 needcomma = 1;
72 });
73 out("}", ctx);
74 break;
76 case HEIM_TID_STRING:
77 out("\"", ctx);
78 out(heim_string_get_utf8(obj), ctx);
79 out("\"", ctx);
80 break;
82 case HEIM_TID_NUMBER: {
83 char num[16];
84 snprintf(num, sizeof(num), "%d", heim_number_get_int(obj));
85 out(num, ctx);
86 break;
88 case HEIM_TID_NULL:
89 out("null", ctx);
90 break;
91 case HEIM_TID_BOOL:
92 out(heim_bool_val(obj) ? "true" : "false", ctx);
93 break;
94 default:
95 return 1;
97 return fail;
100 #endif
106 struct parse_ctx {
107 unsigned long lineno;
108 const uint8_t *p;
109 const uint8_t *pstart;
110 const uint8_t *pend;
111 heim_error_t error;
115 static heim_object_t
116 parse_value(struct parse_ctx *ctx);
118 static int
119 white_spaces(struct parse_ctx *ctx)
121 while (ctx->p < ctx->pend) {
122 uint8_t c = *ctx->p;
123 if (c == ' ' || c == '\t' || c == '\r') {
125 } else if (c == '\n') {
126 ctx->lineno++;
127 } else
128 return 0;
129 (ctx->p)++;
131 return -1;
134 static int
135 is_number(uint8_t n)
137 return ('0' <= n && n <= '9');
140 static heim_number_t
141 parse_number(struct parse_ctx *ctx)
143 int number = 0, neg = 1;
145 if (ctx->p >= ctx->pend)
146 return NULL;
148 if (*ctx->p == '-') {
149 neg = -1;
150 ctx->p += 1;
153 while (ctx->p < ctx->pend) {
154 if (is_number(*ctx->p)) {
155 number = (number * 10) + (*ctx->p - '0');
156 } else {
157 break;
159 ctx->p += 1;
162 return heim_number_create(number * neg);
165 static heim_string_t
166 parse_string(struct parse_ctx *ctx)
168 const uint8_t *start;
169 int quote = 0;
171 heim_assert(*ctx->p == '"', "string doesnt' start with \"");
172 start = ++ctx->p;
174 while (ctx->p < ctx->pend) {
175 if (*ctx->p == '\n') {
176 ctx->lineno++;
177 } else if (*ctx->p == '\\') {
178 if (ctx->p + 1 == ctx->pend)
179 goto out;
180 ctx->p += 1;
181 quote = 1;
182 } else if (*ctx->p == '"') {
183 heim_object_t o;
185 if (quote) {
186 char *p0, *p;
187 p = p0 = malloc(ctx->p - start);
188 if (p == NULL)
189 goto out;
190 while (start < ctx->p) {
191 if (*start == '\\') {
192 start++;
193 /* XXX validate qouted char */
195 *p++ = *start++;
197 o = heim_string_create_with_bytes(p0, p - p0);
198 free(p0);
199 } else {
200 o = heim_string_create_with_bytes(start, ctx->p - start);
202 ctx->p += 1;
204 return o;
206 ctx->p += 1;
208 out:
209 ctx->error = heim_error_create(EINVAL, "ran out of string");
210 return NULL;
213 static int
214 parse_pair(heim_dict_t dict, struct parse_ctx *ctx)
216 heim_string_t key;
217 heim_object_t value;
219 if (white_spaces(ctx))
220 return -1;
222 if (*ctx->p == '}')
223 return 0;
225 key = parse_string(ctx);
226 if (key == NULL)
227 return -1;
229 if (white_spaces(ctx))
230 return -1;
232 if (*ctx->p != ':') {
233 heim_release(key);
234 return -1;
237 ctx->p += 1;
239 if (white_spaces(ctx)) {
240 heim_release(key);
241 return -1;
244 value = parse_value(ctx);
245 if (value == NULL) {
246 heim_release(key);
247 return -1;
249 heim_dict_set_value(dict, key, value);
250 heim_release(key);
251 heim_release(value);
253 if (white_spaces(ctx))
254 return -1;
256 if (*ctx->p == '}') {
257 ctx->p++;
258 return 0;
259 } else if (*ctx->p == ',') {
260 ctx->p++;
261 return 1;
263 return -1;
266 static heim_dict_t
267 parse_dict(struct parse_ctx *ctx)
269 heim_dict_t dict = heim_dict_create(11);
270 int ret;
272 heim_assert(*ctx->p == '{', "string doesn't start with {");
273 ctx->p += 1;
275 while ((ret = parse_pair(dict, ctx)) > 0)
277 if (ret < 0) {
278 heim_release(dict);
279 return NULL;
281 return dict;
284 static int
285 parse_item(heim_array_t array, struct parse_ctx *ctx)
287 heim_object_t value;
289 if (white_spaces(ctx))
290 return -1;
292 if (*ctx->p == ']')
293 return 0;
295 value = parse_value(ctx);
296 if (value == NULL)
297 return -1;
299 heim_array_append_value(array, value);
300 heim_release(value);
302 if (white_spaces(ctx))
303 return -1;
305 if (*ctx->p == ']') {
306 ctx->p++;
307 return 0;
308 } else if (*ctx->p == ',') {
309 ctx->p++;
310 return 1;
312 return -1;
315 static heim_array_t
316 parse_array(struct parse_ctx *ctx)
318 heim_array_t array = heim_array_create();
319 int ret;
321 heim_assert(*ctx->p == '[', "array doesn't start with [");
322 ctx->p += 1;
324 while ((ret = parse_item(array, ctx)) > 0)
326 if (ret < 0) {
327 heim_release(array);
328 return NULL;
330 return array;
333 static heim_object_t
334 parse_value(struct parse_ctx *ctx)
336 size_t len;
338 if (white_spaces(ctx))
339 return NULL;
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) {
354 ctx->p += 4;
355 return heim_null_create();
356 } else if (len >= 4 && strncasecmp((char *)ctx->p, "true", 4) == 0) {
357 ctx->p += 4;
358 return heim_bool_create(1);
359 } else if (len >= 5 && strncasecmp((char *)ctx->p, "false", 5) == 0) {
360 ctx->p += 5;
361 return heim_bool_create(0);
364 ctx->error = heim_error_create(EINVAL, "unknown char %c at %lu line %lu",
365 (char)*ctx->p,
366 (unsigned long)(ctx->p - ctx->pstart),
367 ctx->lineno);
368 return NULL;
372 heim_object_t
373 heim_json_create(const char *string, heim_error_t *error)
375 return heim_json_create_with_bytes(string, strlen(string), error);
378 heim_object_t
379 heim_json_create_with_bytes(const void *data, size_t length, heim_error_t *error)
381 struct parse_ctx ctx;
382 heim_object_t o;
384 ctx.lineno = 1;
385 ctx.p = data;
386 ctx.pstart = data;
387 ctx.pend = ((uint8_t *)data) + length;
388 ctx.error = NULL;
390 o = parse_value(&ctx);
392 if (o == NULL && error) {
393 *error = ctx.error;
394 } else if (ctx.error) {
395 heim_release(ctx.error);
398 return o;