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