]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/libopensrf/osrf_json_parser.c
Patch from Scott McKellar to clean up const-iness and simplify the parser internals
[OpenSRF.git] / src / libopensrf / osrf_json_parser.c
1 /*
2 Copyright (C) 2006  Georgia Public Library Service 
3 Bill Erickson <billserickson@gmail.com>
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 */
15
16 #include <opensrf/osrf_json.h>
17 #include <opensrf/osrf_json_utils.h>
18 #include <ctype.h>
19
20
21 /* if the client sets a global error handler, this will point to it */
22 static void (*jsonClientErrorCallback) (const char*) = NULL;
23
24 /* these are the handlers for our internal parser */
25 static const jsonParserHandler jsonInternalParserHandler = {
26         _jsonHandleStartObject,
27         _jsonHandleObjectKey,
28         _jsonHandleEndObject,
29         _jsonHandleStartArray,
30         _jsonHandleEndArray,
31         _jsonHandleNull,
32         _jsonHandleString,
33         _jsonHandleBool,
34         _jsonHandleNumber,
35         _jsonHandleError
36 };
37
38 static jsonParserContext staticContext;
39 static int staticContextInUse = 0;       // boolean
40
41 static jsonInternalParser staticParser;
42 static int staticParserInUse = 0;        // boolean
43
44 jsonParserContext* jsonNewParser( const jsonParserHandler* handler, void* userData) {
45         jsonParserContext* ctx;
46
47         // Use the static instance of jsonParserContext,
48         // if it's available
49         
50         if( staticContextInUse )
51                 OSRF_MALLOC(ctx, sizeof(jsonParserContext));
52         else {
53                 ctx = &staticContext;
54                 staticContextInUse = 1;
55         }
56
57         ctx->stateStack                 = osrfNewList();
58         ctx->buffer                                     = buffer_init(512);
59         ctx->utfbuf                                     = buffer_init(5);
60         ctx->handler                            = handler;
61         ctx->state                                      = 0;
62         ctx->index                                      = 0;
63         ctx->chunksize                          = 0;
64         ctx->flags                                      = 0;
65         ctx->chunk                                      = NULL;
66         ctx->userData                           = userData;
67         return ctx;
68 }
69
70 void jsonParserFree( jsonParserContext* ctx ) {
71         if(!ctx) return;
72         buffer_free(ctx->buffer);
73         buffer_free(ctx->utfbuf);
74         osrfListFree(ctx->stateStack);
75
76         // if the jsonParserContext was allocated
77         // dynamically, then free it
78         
79         if( &staticContext == ctx )
80                 staticContextInUse = 0;
81         else
82                 free(ctx);
83 }
84
85
86 void jsonSetGlobalErrorHandler(void (*errorHandler) (const char*)) {
87         jsonClientErrorCallback = errorHandler;
88 }
89
90
91 int _jsonParserError( jsonParserContext* ctx, char* err, ... ) {
92         if( ctx->handler->handleError ) {
93                 VA_LIST_TO_STRING(err);
94                 int pre = ctx->index - 15;
95                 int post= ctx->index + 15;
96                 while( pre < 0 ) pre++;
97                 while( post >= ctx->chunksize ) post--;
98                 int l = post - pre;
99                 char buf[l];
100                 snprintf(buf, sizeof(buf), ctx->chunk + pre);
101                 ctx->handler->handleError( ctx->userData, 
102                         "*JSON Parser Error\n - char  = %c\n "
103                         "- index = %d\n - near  => %s\n - %s", 
104                         ctx->chunk[ctx->index], ctx->index, buf, VA_BUF );
105         }
106         JSON_STATE_SET(ctx, JSON_STATE_IS_INVALID);
107         return -1;
108 }
109
110
111 int _jsonParserHandleUnicode( jsonParserContext* ctx ) {
112
113         /* collect as many of the utf characters as we can in this chunk */
114         JSON_CACHE_DATA(ctx, ctx->utfbuf, 4);
115
116         /* we ran off the end of the chunk */
117         if( ctx->utfbuf->n_used < 4 ) {
118                 JSON_STATE_SET(ctx, JSON_STATE_IN_UTF);
119                 return 1;
120         }
121
122         ctx->index--; /* push it back to index of the final utf char */
123
124         /* ----------------------------------------------------------------------- */
125         /* We have all of the escaped unicode data.  Write it to the buffer */
126         /* The following chunk is used with permission from 
127          * json-c http://oss.metaparadigm.com/json-c/ 
128          */
129         #define hexdigit(x) ( ((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
130         unsigned char utf_out[4];
131         memset(utf_out, 0, sizeof(utf_out));
132         char* buf = ctx->utfbuf->buf;
133
134         unsigned int ucs_char =
135                 (hexdigit(buf[0] ) << 12) +
136                 (hexdigit(buf[1]) << 8) +
137                 (hexdigit(buf[2]) << 4) +
138                 hexdigit(buf[3]);
139
140         if (ucs_char < 0x80) {
141                 utf_out[0] = ucs_char;
142                 OSRF_BUFFER_ADD(ctx->buffer, (char*)utf_out);
143
144         } else if (ucs_char < 0x800) {
145                 utf_out[0] = 0xc0 | (ucs_char >> 6);
146                 utf_out[1] = 0x80 | (ucs_char & 0x3f);
147                 OSRF_BUFFER_ADD(ctx->buffer, (char*)utf_out);
148
149         } else {
150                 utf_out[0] = 0xe0 | (ucs_char >> 12);
151                 utf_out[1] = 0x80 | ((ucs_char >> 6) & 0x3f);
152                 utf_out[2] = 0x80 | (ucs_char & 0x3f);
153                 OSRF_BUFFER_ADD(ctx->buffer, (char*)utf_out);
154         }
155         /* ----------------------------------------------------------------------- */
156         /* ----------------------------------------------------------------------- */
157
158         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_UTF);
159         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_ESCAPE);
160         OSRF_BUFFER_RESET(ctx->utfbuf);
161         return 0;
162 }
163
164
165
166 /* type : 0=null, 1=true, 2=false */
167 int _jsonParserHandleMatch( jsonParserContext* ctx, int type ) {
168
169         switch(type) {
170
171                 case 0: /* JSON null */
172
173                         /* first see if we have it all first */
174                         if( ctx->chunksize > (ctx->index + 3) ) {
175                                 if( strncasecmp(ctx->chunk + ctx->index, "null", 4) ) 
176                                         return _jsonParserError(ctx, "Invalid JSON 'null' sequence");
177                                 if( ctx->handler->handleNull ) 
178                                         ctx->handler->handleNull(ctx->userData);
179                                 ctx->index += 4;
180                                 break;
181                         }
182
183                         JSON_CACHE_DATA(ctx, ctx->buffer, 4);
184                         if( ctx->buffer->n_used < 4 ) {
185                                 JSON_STATE_SET(ctx, JSON_STATE_IN_NULL);
186                                 return 1;
187                         } 
188
189                         if( strncasecmp(ctx->buffer->buf, "null", 4) ) 
190                                 return _jsonParserError(ctx, "Invalid JSON 'null' sequence");
191                         if( ctx->handler->handleNull ) 
192                                 ctx->handler->handleNull(ctx->userData);
193                         break;
194
195                 case 1: /* JSON true */
196
197                         /* see if we have it all first */
198                         if( ctx->chunksize > (ctx->index + 3) ) {
199                                 if( strncasecmp(ctx->chunk + ctx->index, "true", 4) ) 
200                                         return _jsonParserError(ctx, "Invalid JSON 'true' sequence");
201                                 if( ctx->handler->handleBool ) 
202                                         ctx->handler->handleBool(ctx->userData, 1);
203                                 ctx->index += 4;
204                                 break;
205                         }
206
207                         JSON_CACHE_DATA(ctx, ctx->buffer, 4);
208                         if( ctx->buffer->n_used < 4 ) {
209                                 JSON_STATE_SET(ctx, JSON_STATE_IN_TRUE);
210                                 return 1;
211                         } 
212                         if( strncasecmp( ctx->buffer->buf, "true", 4 ) ) {
213                                 return _jsonParserError(ctx, "Invalid JSON 'true' sequence");
214                         }
215                         if( ctx->handler->handleBool ) 
216                                 ctx->handler->handleBool(ctx->userData, 1);
217                         break;
218
219                 case 2: /* JSON false */
220
221                         /* see if we have it all first */
222                         if( ctx->chunksize > (ctx->index + 4) ) {
223                                 if( strncasecmp(ctx->chunk + ctx->index, "false", 5) ) 
224                                         return _jsonParserError(ctx, "Invalid JSON 'false' sequence");
225                                 if( ctx->handler->handleBool ) 
226                                         ctx->handler->handleBool(ctx->userData, 0);
227                                 ctx->index += 5;
228                                 break;
229                         }
230
231                         JSON_CACHE_DATA(ctx, ctx->buffer, 5);
232                         if( ctx->buffer->n_used < 5 ) {
233                                 JSON_STATE_SET(ctx, JSON_STATE_IN_FALSE);
234                                 return 1;
235                         }
236                         if( strncasecmp( ctx->buffer->buf, "false", 5 ) ) 
237                                 return _jsonParserError(ctx, "Invalid JSON 'false' sequence");
238                         if( ctx->handler->handleBool ) 
239                                 ctx->handler->handleBool(ctx->userData, 0);
240                         break;
241
242                 default: 
243                         fprintf(stderr, "Invalid type flag\n");
244                         return -1;
245
246         }
247
248         ctx->index--; /* set it back to the index of the final sequence character */
249         OSRF_BUFFER_RESET(ctx->buffer);
250         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_NULL);
251         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_TRUE);
252         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_FALSE);
253
254         return 0;
255 }
256
257
258 int _jsonParserHandleString( jsonParserContext* ctx ) {
259
260         char c = ctx->chunk[ctx->index];
261
262         if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_ESCAPE) ) {
263
264                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_UTF) ) {
265
266                         return _jsonParserHandleUnicode( ctx );
267                                                 
268                 } else {
269
270                         switch(c) {
271
272                                 /* handle all of the escape chars */
273                                 case '\\': OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\\' ); break;
274                                 case '"'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\"' ); break;
275                                 case 't'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\t' ); break;
276                                 case 'b'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\b' ); break;
277                                 case 'f'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\f' ); break;
278                                 case 'r'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\r' ); break;
279                                 case 'n'        : OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\n' ); break;
280                                 case 'u'        : 
281                                         ctx->index++; /* progress to the first utf char */
282                                         return _jsonParserHandleUnicode( ctx );
283                                 default : OSRF_BUFFER_ADD_CHAR( ctx->buffer, c );
284                         }
285                 }
286
287                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_ESCAPE);
288                 return 0;
289
290         } else {
291
292                 switch(c) {
293
294                         case '"'        : /* this string is ending */
295                                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_KEY) ) {
296
297                                         /* object key */
298                                         if(ctx->handler->handleObjectKey) {
299                                                 ctx->handler->handleObjectKey( 
300                                                         ctx->userData, ctx->buffer->buf);
301                                         }
302
303                                 } else { /* regular json string */
304
305                                         if(ctx->handler->handleString) {
306                                                 ctx->handler->handleString( 
307                                                         ctx->userData, ctx->buffer->buf );
308                                         }
309
310                                 }
311
312                                 OSRF_BUFFER_RESET(ctx->buffer); /* flush the buffer and states */
313                                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_STRING);
314                                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_KEY);
315                                 break;
316
317                         case '\\' : JSON_STATE_SET(ctx, JSON_STATE_IN_ESCAPE); break;
318                         default  : OSRF_BUFFER_ADD_CHAR( ctx->buffer, c );
319                 }
320         }
321         return 0;
322 }
323
324
325 int _jsonParserHandleNumber( jsonParserContext* ctx ) {
326         char c = ctx->chunk[ctx->index];
327
328         do {
329                 OSRF_BUFFER_ADD_CHAR(ctx->buffer, c);
330                 c = ctx->chunk[++(ctx->index)];
331         } while( strchr(JSON_NUMBER_CHARS, c) && ctx->index < ctx->chunksize );
332
333         /* if we're run off the end of the chunk and we're not parsing the last chunk,
334          * save the number and the state */
335         if( ctx->index >= ctx->chunksize && 
336                         ! JSON_PARSE_FLAG_CHECK(ctx, JSON_PARSE_LAST_CHUNK) ) {
337                 JSON_STATE_SET(ctx, JSON_STATE_IN_NUMBER);
338                 return 1;
339         }
340
341         /* make me more strict */
342         char* err = NULL;
343         double d = strtod(ctx->buffer->buf, &err);
344         if(err && err[0] != '\0') 
345                 return _jsonParserError(ctx, "Invalid number sequence");
346         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_NUMBER);
347         OSRF_BUFFER_RESET(ctx->buffer);
348         if(ctx->handler->handleNumber)
349                 ctx->handler->handleNumber( ctx->userData, d );
350         ctx->index--; /* scooch back to the first non-digit number */
351         return 0;
352 }
353
354
355
356
357 int jsonParseChunk( jsonParserContext* ctx, const char* data, int datalen, int flags ) {
358
359         if( !( ctx && ctx->handler && data && datalen > 0 )) return -1;
360         ctx->chunksize  = datalen;
361         ctx->chunk              = data;
362         ctx->flags              = flags;
363         char c;
364
365         if( JSON_STATE_CHECK(ctx, JSON_STATE_IS_INVALID) )
366                 return _jsonParserError( ctx, "JSON Parser cannot continue after an error" );
367
368         if( JSON_STATE_CHECK(ctx, JSON_STATE_IS_DONE) )
369                 return _jsonParserError( ctx, "Extra content at end of JSON data" );
370
371         for( ctx->index = 0; (ctx->index < ctx->chunksize) && 
372                                 (c = ctx->chunk[ctx->index]); ctx->index++ ) {
373
374                 /* middle of parsing a string */
375                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_STRING)) {
376                         if( _jsonParserHandleString(ctx) == -1 )
377                                 return -1;
378                         continue;
379                 }
380
381                 /* middle of parsing a number */
382                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_NUMBER) ) {
383                         if( _jsonParserHandleNumber(ctx) == -1 )
384                                 return -1;
385                         continue;
386                 }
387
388
389 #ifdef OSRF_JSON_ALLOW_COMMENTS
390                 /* we just saw a bare '/' character */
391                 if( JSON_STATE_CHECK(ctx, JSON_STATE_START_COMMENT) ) {
392                         if(c == '*') {
393                                 JSON_STATE_REMOVE(ctx, JSON_STATE_START_COMMENT);
394                                 JSON_STATE_SET(ctx, JSON_STATE_IN_COMMENT);
395                                 continue;
396                         } else {
397                                 return _jsonParserError( ctx, "Invalid comment initializer" );
398                         }
399                 }
400
401                 /* we're currently in the middle of a comment block */
402                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_COMMENT) ) {
403                         if(c == '*') {
404                                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_COMMENT);
405                                 JSON_STATE_SET(ctx, JSON_STATE_END_COMMENT);
406                                 continue;
407                         } else {
408                                 continue;
409                         }
410                 }
411
412                 /* we're in a comment, and we just saw a '*' character */
413                 if( JSON_STATE_CHECK(ctx, JSON_STATE_END_COMMENT) ) {
414                         if( c == '/' ) { /* comment is finished */
415                                 JSON_STATE_REMOVE(ctx, JSON_STATE_END_COMMENT);
416                                 continue;
417                         } else {
418                                 /* looks like this isn't the end of the comment after all */
419                                 JSON_STATE_SET(ctx, JSON_STATE_IN_COMMENT);
420                                 JSON_STATE_REMOVE(ctx, JSON_STATE_END_COMMENT);
421                         }
422                 }
423 #endif
424
425                 /* if we're in the middle of parsing a null/true/false sequence */
426                 if( JSON_STATE_CHECK(ctx, (JSON_STATE_IN_NULL | 
427                                         JSON_STATE_IN_TRUE | JSON_STATE_IN_FALSE)) ) {
428
429                         int type = (JSON_STATE_CHECK(ctx, JSON_STATE_IN_NULL)) ? 0 :
430                                 (JSON_STATE_CHECK(ctx, JSON_STATE_IN_TRUE)) ? 1 : 2;
431
432                         if( _jsonParserHandleMatch( ctx, type ) == -1 ) 
433                                 return -1;
434                         continue;
435                 }
436
437                 JSON_EAT_WS(ctx);
438
439                 /* handle all of the top level characters */
440                 switch(c) {
441
442                         case '{' : /* starting an object */
443                                 if( ctx->handler->handleStartObject) 
444                                         ctx->handler->handleStartObject( ctx->userData );
445                                 JSON_STATE_PUSH(ctx, JSON_STATE_IN_OBJECT);
446                                 JSON_STATE_SET(ctx, JSON_STATE_IN_KEY);
447                                 break;
448
449                         case '}' : /* ending an object */
450                                 if( ctx->handler->handleEndObject) 
451                                         ctx->handler->handleEndObject( ctx->userData ); 
452                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_KEY);
453                                 JSON_STATE_POP(ctx);
454                                 if( JSON_STATE_PEEK(ctx) == NULL )
455                                         JSON_STATE_SET(ctx, JSON_STATE_IS_DONE);
456                                 break;
457
458                         case '[' : /* starting an array */
459                                 if( ctx->handler->handleStartArray )
460                                         ctx->handler->handleStartArray( ctx->userData );
461                                 JSON_STATE_PUSH(ctx, JSON_STATE_IN_ARRAY);
462                                 break;
463
464                         case ']': /* ending an array */
465                                 if( ctx->handler->handleEndArray )
466                                         ctx->handler->handleEndArray( ctx->userData );
467                                 JSON_STATE_POP(ctx);
468                                 if( JSON_STATE_PEEK(ctx) == NULL )
469                                         JSON_STATE_SET(ctx, JSON_STATE_IS_DONE);
470                                 break;
471                                 
472                         case ':' : /* done with the object key */
473                                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_KEY);
474                                 break;
475
476                         case ',' : /* after object or array item */
477                                 if( JSON_STATE_CHECK_STACK(ctx, JSON_STATE_IN_OBJECT) )
478                                         JSON_STATE_SET(ctx, JSON_STATE_IN_KEY);
479                                 break;
480
481                         case 'n' :
482                         case 'N' : /* null */
483                                 if( _jsonParserHandleMatch( ctx, 0 ) == -1)
484                                         return -1;
485                                 break;
486
487                         case 't' :
488                         case 'T' :
489                                 if( _jsonParserHandleMatch( ctx, 1 ) == -1 )
490                                         return -1;
491                                 break;
492
493                         case 'f' :
494                         case 'F' :
495                                 if( _jsonParserHandleMatch( ctx, 2 ) == -1)
496                                         return -1;
497                                 break;
498
499                         case '"' : 
500                                 JSON_STATE_SET(ctx, JSON_STATE_IN_STRING);
501                                 break;
502
503 #ifdef OSRF_JSON_ALLOW_COMMENTS
504                         case '/' :
505                                 JSON_STATE_SET(ctx, JSON_STATE_START_COMMENT);
506                                 break;
507 #endif
508
509                         default:
510                                 if( strchr(JSON_NUMBER_CHARS, c) ) {
511                                         if( _jsonParserHandleNumber( ctx ) == -1 )
512                                                 return -1;
513                                 } else {
514                                         return _jsonParserError( ctx, "Invalid Token" );
515                                 }
516                 }
517         }
518
519         return 0;
520 }
521
522
523 jsonInternalParser* _jsonNewInternalParser() {
524         jsonInternalParser* p;
525
526         // Use the static instance of jsonInternalParser,
527         // if it's available
528         
529         if( staticParserInUse )
530                 OSRF_MALLOC(p, sizeof(jsonInternalParser));
531         else {
532                 p = &staticParser;
533                 staticParserInUse = 1;
534         }
535
536         p->ctx = jsonNewParser( &jsonInternalParserHandler, p );
537         p->obj          = NULL;
538         p->current  = NULL;
539         p->lastkey      = NULL;
540         p->handleError = NULL;
541         return p;
542 }
543
544 void _jsonInternalParserFree(jsonInternalParser* p) {
545         if(!p) return;
546         jsonParserFree(p->ctx);
547         free(p->lastkey);
548
549         // if the jsonInternalParser was allocated
550         // dynamically, then free it
551         
552         if( &staticParser == p )
553                 staticParserInUse = 0;
554         else
555                 free(p);
556 }
557
558 static jsonObject* _jsonParseStringImpl(const char* str, void (*errorHandler) (const char*) ) {
559         jsonInternalParser* parser = _jsonNewInternalParser();
560         parser->handleError = errorHandler;
561         jsonParseChunk( parser->ctx, str, strlen(str),  JSON_PARSE_LAST_CHUNK );
562         jsonObject* obj = parser->obj;
563         _jsonInternalParserFree(parser);
564         return obj;
565 }
566
567 jsonObject* jsonParseStringHandleError( 
568                 void (*errorHandler) (const char*), char* str, ... ) {
569         if(!str) return NULL;
570         VA_LIST_TO_STRING(str);
571         return _jsonParseStringImpl(VA_BUF, errorHandler);
572 }
573
574 jsonObject* jsonParseString( const char* str ) {
575         if(!str) return NULL;
576         jsonObject* obj =  _jsonParseStringImpl(str, NULL);
577         jsonObject* obj2 = jsonObjectDecodeClass(obj);
578         jsonObjectFree(obj);
579         return obj2;
580 }
581
582 jsonObject* jsonParseStringRaw( const char* str ) {
583         if(!str) return NULL;
584         return _jsonParseStringImpl(str, NULL);
585 }
586
587 jsonObject* jsonParseStringFmt( const char* str, ... ) {
588         if(!str) return NULL;
589         VA_LIST_TO_STRING(str);
590         return _jsonParseStringImpl(VA_BUF, NULL);
591 }
592
593
594 #define JSON_SHOVE_ITEM(ctx,type)  \
595         jsonInternalParser* p = (jsonInternalParser*) ctx;\
596         _jsonInsertParserItem(p, jsonNewObjectType(type));
597
598 void _jsonHandleStartObject(void* ctx) { JSON_SHOVE_ITEM(ctx, JSON_HASH); }
599 void _jsonHandleStartArray(void* ctx) { JSON_SHOVE_ITEM(ctx, JSON_ARRAY); }
600 void _jsonHandleNull(void* ctx) { JSON_SHOVE_ITEM(ctx, JSON_NULL); }
601
602 void _jsonHandleObjectKey(void* ctx, char* key) {
603         jsonInternalParser* p = (jsonInternalParser*) ctx;
604         free(p->lastkey);
605         p->lastkey = strdup(key);
606 }
607
608 void _jsonHandleEndObject(void* ctx) {
609         jsonInternalParser* p = (jsonInternalParser*) ctx;
610         p->current = p->current->parent;
611 }
612
613 void _jsonHandleEndArray(void* ctx) {
614         jsonInternalParser* p = (jsonInternalParser*) ctx;
615         p->current = p->current->parent;
616 }
617
618 void _jsonHandleString(void* ctx, char* string) {
619         jsonInternalParser* p = (jsonInternalParser*) ctx;
620         _jsonInsertParserItem(p, jsonNewObject(string));
621 }
622
623 void _jsonHandleBool(void* ctx, int boolval) {
624         jsonInternalParser* p = (jsonInternalParser*) ctx;
625         jsonObject* obj = jsonNewObjectType(JSON_BOOL);
626         obj->value.b = boolval;
627         _jsonInsertParserItem(p, obj);
628 }
629
630 void _jsonHandleNumber(void* ctx, double num) {
631         jsonInternalParser* p = (jsonInternalParser*) ctx;
632         _jsonInsertParserItem(p, jsonNewNumberObject(num));
633 }
634
635 void _jsonHandleError(void* ctx, char* str, ...) {
636         jsonInternalParser* p = (jsonInternalParser*) ctx;
637         VA_LIST_TO_STRING(str);
638
639         if( p->handleError ) 
640                 p->handleError(VA_BUF);
641         else 
642                 if( jsonClientErrorCallback ) 
643                         jsonClientErrorCallback(VA_BUF);
644
645         else fprintf(stderr, "%s\n", VA_BUF);
646         jsonObjectFree(p->obj);
647         p->obj = NULL;
648 }
649
650
651 void _jsonInsertParserItem( jsonInternalParser* p, jsonObject* newo ) {
652
653         if( !p->obj ) {
654
655                 /* new parser, set the new object to our object */
656                 p->obj = p->current = newo;
657
658         } else {
659
660                 /* insert the new object into the current container object */
661                 switch(p->current->type) { 
662                         case JSON_HASH  : jsonObjectSetKey(p->current, p->lastkey, newo);  break;
663                         case JSON_ARRAY: jsonObjectPush(p->current, newo); break;
664                         default: fprintf(stderr, "%s:%d -> how?\n", JSON_LOG_MARK); 
665                 } 
666
667                 /* if the new object is a container object, make it our current container */
668                 if( newo->type == JSON_ARRAY || newo->type == JSON_HASH )
669                         p->current = newo;      
670         }
671 }
672
673