]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/libopensrf/osrf_json_parser.c
1. In osrf_app_session.[ch]: Create a new function
[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         if(ctx->handler->handleNumber)
353         {
354                 if( jsonIsNumeric( ctx->buffer->buf ) )
355                         ctx->handler->handleNumber( ctx->userData, ctx->buffer->buf );
356                 else {
357                         // The number string is not numeric according to JSON rules.
358                         // Scrub it into an acceptable format.
359
360                         char* scrubbed = jsonScrubNumber( ctx->buffer->buf );
361                         if( !scrubbed )
362                                 return _jsonParserError(ctx, "Invalid number sequence");
363                         else {
364                                 ctx->handler->handleNumber( ctx->userData, scrubbed );
365                                 free( scrubbed );
366                         }
367                 }
368         }
369         
370         ctx->index--; /* scooch back to the first non-digit number */
371         JSON_STATE_REMOVE(ctx, JSON_STATE_IN_NUMBER);
372         OSRF_BUFFER_RESET(ctx->buffer);
373         return 0;
374 }
375
376 int jsonParseChunk( jsonParserContext* ctx, const char* data, int datalen, int flags ) {
377
378         if( !( ctx && ctx->handler && data && datalen > 0 )) return -1;
379         ctx->chunksize  = datalen;
380         ctx->chunk              = data;
381         ctx->flags              = flags;
382         char c;
383
384         if( JSON_STATE_CHECK(ctx, JSON_STATE_IS_INVALID) )
385                 return _jsonParserError( ctx, "JSON Parser cannot continue after an error" );
386
387         if( JSON_STATE_CHECK(ctx, JSON_STATE_IS_DONE) )
388                 return _jsonParserError( ctx, "Extra content at end of JSON data" );
389
390         for( ctx->index = 0; (ctx->index < ctx->chunksize) && 
391                                 (c = ctx->chunk[ctx->index]); ctx->index++ ) {
392
393                 /* middle of parsing a string */
394                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_STRING)) {
395                         if( _jsonParserHandleString(ctx) == -1 )
396                                 return -1;
397                         continue;
398                 }
399
400                 /* middle of parsing a number */
401                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_NUMBER) ) {
402                         if( _jsonParserHandleNumber(ctx) == -1 )
403                                 return -1;
404                         continue;
405                 }
406
407
408 #ifdef OSRF_JSON_ALLOW_COMMENTS
409                 /* we just saw a bare '/' character */
410                 if( JSON_STATE_CHECK(ctx, JSON_STATE_START_COMMENT) ) {
411                         if(c == '*') {
412                                 JSON_STATE_REMOVE(ctx, JSON_STATE_START_COMMENT);
413                                 JSON_STATE_SET(ctx, JSON_STATE_IN_COMMENT);
414                                 continue;
415                         } else {
416                                 return _jsonParserError( ctx, "Invalid comment initializer" );
417                         }
418                 }
419
420                 /* we're currently in the middle of a comment block */
421                 if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_COMMENT) ) {
422                         if(c == '*') {
423                                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_COMMENT);
424                                 JSON_STATE_SET(ctx, JSON_STATE_END_COMMENT);
425                                 continue;
426                         } else {
427                                 continue;
428                         }
429                 }
430
431                 /* we're in a comment, and we just saw a '*' character */
432                 if( JSON_STATE_CHECK(ctx, JSON_STATE_END_COMMENT) ) {
433                         if( c == '/' ) { /* comment is finished */
434                                 JSON_STATE_REMOVE(ctx, JSON_STATE_END_COMMENT);
435                                 continue;
436                         } else {
437                                 /* looks like this isn't the end of the comment after all */
438                                 JSON_STATE_SET(ctx, JSON_STATE_IN_COMMENT);
439                                 JSON_STATE_REMOVE(ctx, JSON_STATE_END_COMMENT);
440                         }
441                 }
442 #endif
443
444                 /* if we're in the middle of parsing a null/true/false sequence */
445                 if( JSON_STATE_CHECK(ctx, (JSON_STATE_IN_NULL | 
446                                         JSON_STATE_IN_TRUE | JSON_STATE_IN_FALSE)) ) {
447
448                         int type = (JSON_STATE_CHECK(ctx, JSON_STATE_IN_NULL)) ? 0 :
449                                 (JSON_STATE_CHECK(ctx, JSON_STATE_IN_TRUE)) ? 1 : 2;
450
451                         if( _jsonParserHandleMatch( ctx, type ) == -1 ) 
452                                 return -1;
453                         continue;
454                 }
455
456                 JSON_EAT_WS(ctx);
457
458                 /* handle all of the top level characters */
459                 switch(c) {
460
461                         case '{' : /* starting an object */
462                                 if( ctx->handler->handleStartObject) 
463                                         ctx->handler->handleStartObject( ctx->userData );
464                                 JSON_STATE_PUSH(ctx, JSON_STATE_IN_OBJECT);
465                                 JSON_STATE_SET(ctx, JSON_STATE_IN_KEY);
466                                 break;
467
468                         case '}' : /* ending an object */
469                                 if( ctx->handler->handleEndObject) 
470                                         ctx->handler->handleEndObject( ctx->userData ); 
471                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_KEY);
472                                 JSON_STATE_POP(ctx);
473                                 if( JSON_STATE_PEEK(ctx) == NULL )
474                                         JSON_STATE_SET(ctx, JSON_STATE_IS_DONE);
475                                 break;
476
477                         case '[' : /* starting an array */
478                                 if( ctx->handler->handleStartArray )
479                                         ctx->handler->handleStartArray( ctx->userData );
480                                 JSON_STATE_PUSH(ctx, JSON_STATE_IN_ARRAY);
481                                 break;
482
483                         case ']': /* ending an array */
484                                 if( ctx->handler->handleEndArray )
485                                         ctx->handler->handleEndArray( ctx->userData );
486                                 JSON_STATE_POP(ctx);
487                                 if( JSON_STATE_PEEK(ctx) == NULL )
488                                         JSON_STATE_SET(ctx, JSON_STATE_IS_DONE);
489                                 break;
490                                 
491                         case ':' : /* done with the object key */
492                                 JSON_STATE_REMOVE(ctx, JSON_STATE_IN_KEY);
493                                 break;
494
495                         case ',' : /* after object or array item */
496                                 if( JSON_STATE_CHECK_STACK(ctx, JSON_STATE_IN_OBJECT) )
497                                         JSON_STATE_SET(ctx, JSON_STATE_IN_KEY);
498                                 break;
499
500                         case 'n' :
501                         case 'N' : /* null */
502                                 if( _jsonParserHandleMatch( ctx, 0 ) == -1)
503                                         return -1;
504                                 break;
505
506                         case 't' :
507                         case 'T' :
508                                 if( _jsonParserHandleMatch( ctx, 1 ) == -1 )
509                                         return -1;
510                                 break;
511
512                         case 'f' :
513                         case 'F' :
514                                 if( _jsonParserHandleMatch( ctx, 2 ) == -1)
515                                         return -1;
516                                 break;
517
518                         case '"' : 
519                                 JSON_STATE_SET(ctx, JSON_STATE_IN_STRING);
520                                 break;
521
522 #ifdef OSRF_JSON_ALLOW_COMMENTS
523                         case '/' :
524                                 JSON_STATE_SET(ctx, JSON_STATE_START_COMMENT);
525                                 break;
526 #endif
527
528                         default:
529                                 if( strchr(JSON_NUMBER_CHARS, c) ) {
530                                         if( _jsonParserHandleNumber( ctx ) == -1 )
531                                                 return -1;
532                                 } else {
533                                         return _jsonParserError( ctx, "Invalid Token" );
534                                 }
535                 }
536         }
537
538         return 0;
539 }
540
541
542 jsonInternalParser* _jsonNewInternalParser() {
543         jsonInternalParser* p;
544
545         // Use the static instance of jsonInternalParser,
546         // if it's available
547         
548         if( staticParserInUse )
549                 OSRF_MALLOC(p, sizeof(jsonInternalParser));
550         else {
551                 p = &staticParser;
552                 staticParserInUse = 1;
553         }
554
555         p->ctx = jsonNewParser( &jsonInternalParserHandler, p );
556         p->obj          = NULL;
557         p->current  = NULL;
558         p->lastkey      = NULL;
559         p->handleError = NULL;
560         return p;
561 }
562
563 void _jsonInternalParserFree(jsonInternalParser* p) {
564         if(!p) return;
565         jsonParserFree(p->ctx);
566         free(p->lastkey);
567
568         // if the jsonInternalParser was allocated
569         // dynamically, then free it
570         
571         if( &staticParser == p )
572                 staticParserInUse = 0;
573         else
574                 free(p);
575 }
576
577 static jsonObject* _jsonParseStringImpl(const char* str, void (*errorHandler) (const char*) ) {
578         jsonInternalParser* parser = _jsonNewInternalParser();
579         parser->handleError = errorHandler;
580         jsonParseChunk( parser->ctx, str, strlen(str),  JSON_PARSE_LAST_CHUNK );
581         jsonObject* obj = parser->obj;
582         _jsonInternalParserFree(parser);
583         return obj;
584 }
585
586 jsonObject* jsonParseStringHandleError( 
587                 void (*errorHandler) (const char*), char* str, ... ) {
588         if(!str) return NULL;
589         VA_LIST_TO_STRING(str);
590         return _jsonParseStringImpl(VA_BUF, errorHandler);
591 }
592
593 jsonObject* jsonParseString( const char* str ) {
594         if(!str) return NULL;
595         jsonObject* obj =  _jsonParseStringImpl(str, NULL);
596         jsonObject* obj2 = jsonObjectDecodeClass(obj);
597         jsonObjectFree(obj);
598         return obj2;
599 }
600
601 jsonObject* jsonParseStringRaw( const char* str ) {
602         if(!str) return NULL;
603         return _jsonParseStringImpl(str, NULL);
604 }
605
606 jsonObject* jsonParseStringFmt( const char* str, ... ) {
607         if(!str) return NULL;
608         VA_LIST_TO_STRING(str);
609         return _jsonParseStringImpl(VA_BUF, NULL);
610 }
611
612
613 #define JSON_SHOVE_ITEM(ctx,type)  \
614         jsonInternalParser* p = (jsonInternalParser*) ctx;\
615         _jsonInsertParserItem(p, jsonNewObjectType(type));
616
617 void _jsonHandleStartObject(void* ctx) { JSON_SHOVE_ITEM(ctx, JSON_HASH); }
618 void _jsonHandleStartArray(void* ctx) { JSON_SHOVE_ITEM(ctx, JSON_ARRAY); }
619 void _jsonHandleNull(void* ctx) { JSON_SHOVE_ITEM(ctx, JSON_NULL); }
620
621 void _jsonHandleObjectKey(void* ctx, char* key) {
622         jsonInternalParser* p = (jsonInternalParser*) ctx;
623         free(p->lastkey);
624         p->lastkey = strdup(key);
625 }
626
627 void _jsonHandleEndObject(void* ctx) {
628         jsonInternalParser* p = (jsonInternalParser*) ctx;
629         p->current = p->current->parent;
630 }
631
632 void _jsonHandleEndArray(void* ctx) {
633         jsonInternalParser* p = (jsonInternalParser*) ctx;
634         p->current = p->current->parent;
635 }
636
637 void _jsonHandleString(void* ctx, char* string) {
638         jsonInternalParser* p = (jsonInternalParser*) ctx;
639         _jsonInsertParserItem(p, jsonNewObject(string));
640 }
641
642 void _jsonHandleBool(void* ctx, int boolval) {
643         jsonInternalParser* p = (jsonInternalParser*) ctx;
644         jsonObject* obj = jsonNewObjectType(JSON_BOOL);
645         obj->value.b = boolval;
646         _jsonInsertParserItem(p, obj);
647 }
648
649 void _jsonHandleNumber(void* ctx, const char* numstr) {
650         jsonObject* obj = jsonNewNumberStringObject(numstr);
651         jsonInternalParser* p = (jsonInternalParser*) ctx;
652         _jsonInsertParserItem(p, obj);
653 }
654
655 void _jsonHandleError(void* ctx, char* str, ...) {
656         jsonInternalParser* p = (jsonInternalParser*) ctx;
657         VA_LIST_TO_STRING(str);
658
659         if( p->handleError ) 
660                 p->handleError(VA_BUF);
661         else 
662                 if( jsonClientErrorCallback ) 
663                         jsonClientErrorCallback(VA_BUF);
664
665         else fprintf(stderr, "%s\n", VA_BUF);
666         jsonObjectFree(p->obj);
667         p->obj = NULL;
668 }
669
670
671 void _jsonInsertParserItem( jsonInternalParser* p, jsonObject* newo ) {
672
673         if( !p->obj ) {
674
675                 /* new parser, set the new object to our object */
676                 p->obj = p->current = newo;
677
678         } else {
679
680                 /* insert the new object into the current container object */
681                 if(p->current->type == JSON_HASH)
682                         jsonObjectSetKey(p->current, p->lastkey, newo);
683                 else  // assume it's a JSON_ARRAY; if it isn't, it'll become one
684                         jsonObjectPush(p->current, newo);
685
686                 /* if the new object is a container object, make it our current container */
687                 if( newo->type == JSON_ARRAY || newo->type == JSON_HASH )
688                         p->current = newo;      
689         }
690 }
691
692