]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/libopensrf/osrf_legacy_json.c
40215d58d98b1b5be2b46fae6e3e65f1787c474f
[OpenSRF.git] / src / libopensrf / osrf_legacy_json.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
17 #include <opensrf/osrf_legacy_json.h>
18
19 /* keep a copy of the length of the current json string so we don't 
20  * have to calculate it in each function
21  */
22 int current_strlen; 
23
24
25 jsonObject* legacy_jsonParseString( const char* string) {
26         return json_parse_string( (char*) string );
27 }
28
29 jsonObject* legacy_jsonParseStringFmt( const char* string, ... ) {
30         VA_LIST_TO_STRING(string);
31         return json_parse_string( VA_BUF );
32 }
33
34
35 jsonObject* json_parse_string(char* string) {
36
37         if(string == NULL) return NULL;
38
39         current_strlen = strlen(string);
40
41         if(current_strlen == 0) 
42                 return NULL;
43
44         unsigned long index = 0;
45
46         json_eat_ws(string, &index, 1, current_strlen); /* remove leading whitespace */
47         if(index == current_strlen) return NULL;
48
49         jsonObject* obj = jsonNewObject(NULL);
50
51         int status = _json_parse_string(string, &index, obj, current_strlen);
52         if(!status) return obj;
53
54         if(status == -2) {
55                 jsonObjectFree(obj);
56                 return NULL;
57         }
58
59         return NULL;
60 }
61
62
63 int _json_parse_string(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
64         if( !string || !index || *index >= current_strlen) return -2;
65
66         int status = 0; /* return code from parsing routines */
67         char* classname = NULL; /* object class hint */
68         json_eat_ws(string, index, 1, current_strlen); /* remove leading whitespace */
69
70         char c = string[*index];
71
72         /* remove any leading comments */
73         if( c == '/' ) { 
74
75                 while(1) {
76                         (*index)++; /* move to second comment char */
77                         status = json_eat_comment(string, index, &classname, 1, current_strlen);
78                         if(status) return status;
79
80                         json_eat_ws(string, index, 1, current_strlen);
81                         c = string[*index];
82                         if(c != '/')
83                                 break;
84                 }
85         }
86
87         json_eat_ws(string, index, 1, current_strlen); /* remove leading whitespace */
88
89         if(*index >= current_strlen)
90                 return -2;
91
92         switch(c) {
93                                 
94                 /* json string */
95                 case '"': 
96                         (*index)++;
97                         status = json_parse_json_string(string, index, obj, current_strlen);
98                         break;
99
100                 /* json array */
101                 case '[':
102                         (*index)++;
103                         status = json_parse_json_array(string, index, obj, current_strlen);
104                         break;
105
106                 /* json object */
107                 case '{':
108                         (*index)++;
109                         status = json_parse_json_object(string, index, obj, current_strlen);
110                         break;
111
112                 /* NULL */
113                 case 'n':
114                 case 'N':
115                         status = json_parse_json_null(string, index, obj, current_strlen);
116                         break;
117                         
118
119                 /* true, false */
120                 case 'f':
121                 case 'F':
122                 case 't':
123                 case 'T':
124                         status = json_parse_json_bool(string, index, obj, current_strlen);
125                         break;
126
127                 default:
128                         if(isdigit(c) || c == '.' || c == '-') { /* are we a number? */
129                                 status = json_parse_json_number(string, index, obj, current_strlen);
130                                 if(status) return status;
131                                 break;
132                         }
133
134                         (*index)--;
135                         /* we should never get here */
136                         return json_handle_error(string, index, "_json_parse_string() final switch clause");
137         }       
138
139         if(status) return status;
140
141         json_eat_ws(string, index, 1, current_strlen);
142
143         if( *index < current_strlen ) {
144                 /* remove any trailing comments */
145                 c = string[*index];
146                 if( c == '/' ) { 
147                         (*index)++;
148                         status = json_eat_comment(string, index, NULL, 0, current_strlen);
149                         if(status) return status;
150                 }
151         }
152
153         if(classname){
154                 jsonObjectSetClass(obj, classname);
155                 free(classname);
156         }
157
158         return 0;
159 }
160
161
162 int json_parse_json_null(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
163
164         if(*index >= (current_strlen - 3)) {
165                 return json_handle_error(string, index, 
166                         "_parse_json_null(): invalid null" );
167         }
168
169         if(!strncasecmp(string + (*index), "null", 4)) {
170                 (*index) += 4;
171                 obj->type = JSON_NULL;
172                 return 0;
173         } else {
174                 return json_handle_error(string, index,
175                         "_parse_json_null(): invalid null" );
176         }
177 }
178
179 /* should be at the first character of the bool at this point */
180 int json_parse_json_bool(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
181         if( ! string || ! obj || *index >= current_strlen ) return -1;
182
183         char* ret = "json_parse_json_bool(): truncated bool";
184
185         if( *index >= (current_strlen - 5))
186                 return json_handle_error(string, index, ret);
187         
188         if(!strncasecmp( string + (*index), "false", 5)) {
189                 (*index) += 5;
190                 obj->value.b = 0;
191                 obj->type = JSON_BOOL;
192                 return 0;
193         }
194
195         if( *index >= (current_strlen - 4))
196                 return json_handle_error(string, index, ret);
197
198         if(!strncasecmp( string + (*index), "true", 4)) {
199                 (*index) += 4;
200                 obj->value.b = 1;
201                 obj->type = JSON_BOOL;
202                 return 0;
203         }
204
205         return json_handle_error(string, index, ret);
206 }
207
208
209 /* expecting the first character of the number */
210 int json_parse_json_number(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
211         if( ! string || ! obj || *index >= current_strlen ) return -1;
212
213         growing_buffer* buf = buffer_init(64);
214         char c = string[*index];
215
216         int done = 0;
217         int dot_seen = 0;
218
219         /* negative number? */
220         if(c == '-') { buffer_add(buf, "-"); (*index)++; }
221
222         c = string[*index];
223
224         while(*index < current_strlen) {
225
226                 if(isdigit(c)) {
227                         buffer_add_char(buf, c);
228                 }
229
230                 else if( c == '.' ) {
231                         if(dot_seen) {
232                                 buffer_free(buf);
233                                 return json_handle_error(string, index, 
234                                         "json_parse_json_number(): malformed json number");
235                         }
236                         dot_seen = 1;
237                         buffer_add_char(buf, c);
238                 } else {
239                         done = 1; break;
240                 }
241
242                 (*index)++;
243                 c = string[*index];
244                 if(done) break;
245         }
246
247         obj->type = JSON_NUMBER;
248         obj->value.s = buffer_release(buf);
249         return 0;
250 }
251
252 /* index should point to the character directly following the '['.  when done
253  * index will point to the character directly following the ']' character
254  */
255 int json_parse_json_array(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
256
257         if( ! string || ! obj || ! index || *index >= current_strlen ) return -1;
258
259         int status = 0;
260         int in_parse = 0; /* true if this array already contains one item */
261         obj->type = JSON_ARRAY;
262         int set = 0;
263         int done = 0;
264
265         while(*index < current_strlen) {
266
267                 json_eat_ws(string, index, 1, current_strlen);
268
269                 if(string[*index] == ']') {
270                         (*index)++;
271                         done = 1;
272                         break;
273                 }
274
275                 if(in_parse) {
276                         json_eat_ws(string, index, 1, current_strlen);
277                         if(string[*index] != ',') {
278                                 return json_handle_error(string, index,
279                                         "json_parse_json_array(): array item not followed by a ','");
280                         }
281                         (*index)++;
282                         json_eat_ws(string, index, 1, current_strlen);
283                 }
284
285                 jsonObject* item = jsonNewObject(NULL);
286
287                 #ifndef STRICT_JSON_READ
288                 if(*index < current_strlen) {
289                         if(string[*index] == ',' || string[*index] == ']') {
290                                 status = 0;
291                                 set = 1;
292                         }
293                 }
294                 if(!set) status = _json_parse_string(string, index, item, current_strlen);
295
296                 #else
297                 status = _json_parse_string(string, index, item, current_strlen);
298                 #endif
299
300                 if(status) { jsonObjectFree(item); return status; }
301                 jsonObjectPush(obj, item);
302                 in_parse = 1;
303                 set = 0;
304         }
305
306         if(!done)
307                 return json_handle_error(string, index,
308                         "json_parse_json_array(): array not closed");
309
310         return 0;
311 }
312
313
314 /* index should point to the character directly following the '{'.  when done
315  * index will point to the character directly following the '}'
316  */
317 int json_parse_json_object(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
318         if( ! string || !obj || ! index || *index >= current_strlen ) return -1;
319
320         obj->type = JSON_HASH;
321         int status;
322         int in_parse = 0; /* true if we've already added one item to this object */
323         int set = 0;
324         int done = 0;
325
326         while(*index < current_strlen) {
327
328                 json_eat_ws(string, index, 1, current_strlen);
329
330                 if(string[*index] == '}') {
331                         (*index)++;
332                         done = 1;
333                         break;
334                 }
335
336                 if(in_parse) {
337                         if(string[*index] != ',') {
338                                 return json_handle_error(string, index,
339                                         "json_parse_json_object(): object missing ',' between elements" );
340                         }
341                         (*index)++;
342                         json_eat_ws(string, index, 1, current_strlen);
343                 }
344
345                 /* first we grab the hash key */
346                 jsonObject* key_obj = jsonNewObject(NULL);
347                 status = _json_parse_string(string, index, key_obj, current_strlen);
348                 if(status) return status;
349
350                 if(key_obj->type != JSON_STRING) {
351                         return json_handle_error(string, index, 
352                                 "_json_parse_json_object(): hash key not a string");
353                 }
354
355                 char* key = key_obj->value.s;
356
357                 json_eat_ws(string, index, 1, current_strlen);
358
359                 if(string[*index] != ':') {
360                         return json_handle_error(string, index, 
361                                 "json_parse_json_object(): hash key not followed by ':' character");
362                 }
363
364                 (*index)++;
365
366                 /* now grab the value object */
367                 json_eat_ws(string, index, 1, current_strlen);
368                 jsonObject* value_obj = jsonNewObject(NULL);
369
370 #ifndef STRICT_JSON_READ
371                 if(*index < current_strlen) {
372                         if(string[*index] == ',' || string[*index] == '}') {
373                                 status = 0;
374                                 set = 1;
375                         }
376                 }
377                 if(!set)
378                         status = _json_parse_string(string, index, value_obj, current_strlen);
379
380 #else
381                  status = _json_parse_string(string, index, value_obj, current_strlen);
382 #endif
383
384                 if(status) return status;
385
386                 /* put the data into the object and continue */
387                 jsonObjectSetKey(obj, key, value_obj);
388                 jsonObjectFree(key_obj);
389                 in_parse = 1;
390                 set = 0;
391         }
392
393         if(!done)
394                 return json_handle_error(string, index,
395                         "json_parse_json_object(): object not closed");
396
397         return 0;
398 }
399
400
401
402 /* when done, index will point to the character after the closing quote */
403 int json_parse_json_string(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
404         if( ! string || ! index || *index >= current_strlen ) return -1;
405
406         int in_escape = 0;      
407         int done = 0;
408         growing_buffer* buf = buffer_init(64);
409
410         while(*index < current_strlen) {
411
412                 char c = string[*index]; 
413
414                 switch(c) {
415
416                         case '\\':
417                                 if(in_escape) {
418                                         buffer_add(buf, "\\");
419                                         in_escape = 0;
420                                 } else 
421                                         in_escape = 1;
422                                 break;
423
424                         case '"':
425                                 if(in_escape) {
426                                         buffer_add(buf, "\"");
427                                         in_escape = 0;
428                                 } else 
429                                         done = 1;
430                                 break;
431
432                         case 't':
433                                 if(in_escape) {
434                                         buffer_add(buf,"\t");
435                                         in_escape = 0;
436                                 } else 
437                                         buffer_add_char(buf, c);
438                                 break;
439
440                         case 'b':
441                                 if(in_escape) {
442                                         buffer_add(buf,"\b");
443                                         in_escape = 0;
444                                 } else 
445                                         buffer_add_char(buf, c);
446                                 break;
447
448                         case 'f':
449                                 if(in_escape) {
450                                         buffer_add(buf,"\f");
451                                         in_escape = 0;
452                                 } else 
453                                         buffer_add_char(buf, c);
454                                 break;
455
456                         case 'r':
457                                 if(in_escape) {
458                                         buffer_add(buf,"\r");
459                                         in_escape = 0;
460                                 } else 
461                                         buffer_add_char(buf, c);
462                                 break;
463
464                         case 'n':
465                                 if(in_escape) {
466                                         buffer_add(buf,"\n");
467                                         in_escape = 0;
468                                 } else 
469                                         buffer_add_char(buf, c);
470                                 break;
471
472                         case 'u':
473                                 if(in_escape) {
474                                         (*index)++;
475
476                                         if(*index >= (current_strlen - 4)) {
477                                                 buffer_free(buf);
478                                                 return json_handle_error(string, index,
479                                                         "json_parse_json_string(): truncated escaped unicode"); }
480
481                                         char buff[5];
482                                         osrf_clearbuf(buff, sizeof(buff));
483                                         memcpy(buff, string + (*index), 4);
484
485
486                                         /* ----------------------------------------------------------------------- */
487                                         /* ----------------------------------------------------------------------- */
488                                         /* The following chunk was borrowed with permission from 
489                                                 json-c http://oss.metaparadigm.com/json-c/ */
490                                         unsigned char utf_out[3];
491                                         memset(utf_out, 0, sizeof(utf_out));
492
493                                         #define hexdigit(x) ( ((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
494
495                                         unsigned int ucs_char =
496                                                 (hexdigit(string[*index] ) << 12) +
497                                                 (hexdigit(string[*index + 1]) << 8) +
498                                                 (hexdigit(string[*index + 2]) << 4) +
499                                                 hexdigit(string[*index + 3]);
500         
501                                         if (ucs_char < 0x80) {
502                                                 utf_out[0] = ucs_char;
503                                                 buffer_add(buf, (char*) utf_out);
504
505                                         } else if (ucs_char < 0x800) {
506                                                 utf_out[0] = 0xc0 | (ucs_char >> 6);
507                                                 utf_out[1] = 0x80 | (ucs_char & 0x3f);
508                                                 buffer_add(buf, (char*) utf_out);
509
510                                         } else {
511                                                 utf_out[0] = 0xe0 | (ucs_char >> 12);
512                                                 utf_out[1] = 0x80 | ((ucs_char >> 6) & 0x3f);
513                                                 utf_out[2] = 0x80 | (ucs_char & 0x3f);
514                                                 buffer_add(buf, (char*) utf_out);
515                                         }
516                                         /* ----------------------------------------------------------------------- */
517                                         /* ----------------------------------------------------------------------- */
518
519                                         (*index) += 3;
520                                         in_escape = 0;
521
522                                 } else {
523
524                                         buffer_add_char(buf, c);
525                                 }
526
527                                 break;
528
529                         default:
530                                 buffer_add_char(buf, c);
531                 }
532
533                 (*index)++;
534                 if(done) break;
535         }
536
537         jsonObjectSetString(obj, buf->buf);
538         buffer_free(buf);
539         return 0;
540 }
541
542
543 void json_eat_ws(char* string, unsigned long* index, int eat_all, int current_strlen) {
544         if( ! string || ! index ) return;
545         if(*index >= current_strlen)
546                 return;
547
548         if( eat_all ) { /* removes newlines, etc */
549                 while(string[*index] == ' '     || 
550                                 string[*index] == '\n'  ||
551                                 string[*index] == '\t') 
552                         (*index)++;
553         }
554
555         else    
556                 while(string[*index] == ' ') (*index)++;
557 }
558
559
560 /* index should be at the '*' character at the beginning of the comment.
561  * when done, index will point to the first character after the final /
562  */
563 int json_eat_comment(char* string, unsigned long* index, char** buffer, int parse_class, int current_strlen) {
564         if( ! string || ! index || *index >= current_strlen ) return -1;
565         
566
567         if(string[*index] != '*' && string[*index] != '/' )
568                 return json_handle_error(string, index, 
569                         "json_eat_comment(): invalid character after /");
570
571         /* chop out any // style comments */
572         if(string[*index] == '/') {
573                 (*index)++;
574                 char c = string[*index];
575                 while(*index < current_strlen) {
576                         (*index)++;
577                         if(c == '\n') 
578                                 return 0;
579                         c = string[*index];
580                 }
581                 return 0;
582         }
583
584         (*index)++;
585
586         int on_star                     = 0; /* true if we just saw a '*' character */
587
588         /* we're just past the '*' */
589         if(!parse_class) { /* we're not concerned with class hints */
590                 while(*index < current_strlen) {
591                         if(string[*index] == '/') {
592                                 if(on_star) {
593                                         (*index)++;
594                                         return 0;
595                                 }
596                         }
597
598                         if(string[*index] == '*') on_star = 1;
599                         else on_star = 0;
600
601                         (*index)++;
602                 }
603                 return 0;
604         }
605
606
607
608         growing_buffer* buf = buffer_init(64);
609
610         int first_dash          = 0;
611         int second_dash = 0;
612         int third_dash          = 0;
613         int fourth_dash = 0;
614
615         int in_hint                     = 0;
616         int done                                = 0;
617
618         /*--S hint--*/   /* <-- Hints  look like this */
619         /*--E hint--*/
620
621         while(*index < current_strlen) {
622                 char c = string[*index];
623
624                 switch(c) {
625
626                         case '-':
627                                 on_star = 0;
628                                 if(third_dash)                  fourth_dash = 1;
629                                 else if(in_hint)                third_dash      = 1;
630                                 else if(first_dash)     second_dash = 1;
631                                 else                                            first_dash = 1;
632                                 break;
633
634                         case 'S':
635                                 on_star = 0;
636                                 if(second_dash && !in_hint) {
637                                         (*index)++;
638                                         json_eat_ws(string, index, 1, current_strlen);
639                                         (*index)--; /* this will get incremented at the bottom of the loop */
640                                         in_hint = 1;
641                                         break;
642                                 } 
643
644                                 if(second_dash && in_hint) {
645                                         buffer_add_char(buf, c);
646                                         break;
647                                 }
648
649                         case 'E':
650                                 on_star = 0;
651                                 if(second_dash && !in_hint) {
652                                         (*index)++;
653                                         json_eat_ws(string, index, 1, current_strlen);
654                                         (*index)--; /* this will get incremented at the bottom of the loop */
655                                         in_hint = 1;
656                                         break;
657                                 }
658
659                                 if(second_dash && in_hint) {
660                                         buffer_add_char(buf, c);
661                                         break;
662                                 }
663
664                         case '*':
665                                 on_star = 1;
666                                 break;
667
668                         case '/':
669                                 if(on_star) 
670                                         done = 1;
671                                 else
672                                 on_star = 0;
673                                 break;
674
675                         default:
676                                 on_star = 0;
677                                 if(in_hint)
678                                         buffer_add_char(buf, c);
679                 }
680
681                 (*index)++;
682                 if(done) break;
683         }
684
685         if( buf->n_used > 0 && buffer)
686                 *buffer = buffer_data(buf);
687
688         buffer_free(buf);
689         return 0;
690 }
691
692 int json_handle_error(char* string, unsigned long* index, char* err_msg) {
693
694         char buf[60];
695         osrf_clearbuf(buf, sizeof(buf));
696
697         if(*index > 30)
698                 strncpy( buf, string + (*index - 30), 59 );
699         else
700                 strncpy( buf, string, 59 );
701
702         fprintf(stderr, 
703                         "\nError parsing json string at charracter %c "
704                         "(code %d) and index %ld\nString length: %d\nMsg:\t%s\nNear:\t%s\nFull String:\t%s\n", 
705                         string[*index], string[*index], *index, current_strlen, err_msg, buf, string );
706
707         return -1;
708 }
709
710
711 jsonObject* legacy_jsonParseFile( const char* filename ) {
712         return json_parse_file( filename );
713 }
714         
715 jsonObject* json_parse_file(const char* filename) {
716         if(!filename) return NULL;
717         char* data = file_to_string(filename);
718         jsonObject* o = json_parse_string(data);
719         free(data);
720         return o;
721 }
722
723
724
725 char* legacy_jsonObjectToJSON( const jsonObject* obj ) {
726
727         if(obj == NULL) return strdup("null");
728
729         growing_buffer* buf = buffer_init(64);
730
731         /* add class hints if we have a class name */
732         if(obj->classname) {
733                 buffer_add(buf,"/*--S ");
734                 buffer_add(buf,obj->classname);
735                 buffer_add(buf, "--*/");
736         }
737
738         switch( obj->type ) {
739
740                 case JSON_BOOL: 
741                         if(obj->value.b) buffer_add(buf, "true"); 
742                         else buffer_add(buf, "false"); 
743                         break;
744
745                 case JSON_NUMBER: {
746                         buffer_add(buf, obj->value.s);
747                         break;
748                 }
749
750                 case JSON_NULL:
751                         buffer_add(buf, "null");
752                         break;
753
754                 case JSON_STRING:
755                         buffer_add(buf, "\"");
756                         char* data = obj->value.s;
757                         int len = strlen(data);
758                         
759                         char* output = uescape(data, len, 1);
760                         buffer_add(buf, output);
761                         free(output);
762                         buffer_add(buf, "\"");
763                         break;
764
765                 case JSON_ARRAY:
766                         buffer_add(buf, "[");
767                         int i;
768                         for( i = 0; i!= obj->size; i++ ) {
769                                 const jsonObject* x = jsonObjectGetIndex(obj,i);
770                                 char* data = legacy_jsonObjectToJSON(x);
771                                 buffer_add(buf, data);
772                                 free(data);
773                                 if(i != obj->size - 1)
774                                         buffer_add(buf, ",");
775                         }
776                         buffer_add(buf, "]");
777                         break;  
778
779                 case JSON_HASH:
780         
781                         buffer_add(buf, "{");
782                         jsonIterator* itr = jsonNewIterator(obj);
783                         jsonObject* tmp;
784         
785                         while( (tmp = jsonIteratorNext(itr)) ) {
786
787                                 buffer_add(buf, "\"");
788
789                                 char* key = itr->key;
790                                 int len = strlen(key);
791                                 char* output = uescape(key, len, 1);
792                                 buffer_add(buf, output);
793                                 free(output);
794
795                                 buffer_add(buf, "\":");
796                                 char* data =  legacy_jsonObjectToJSON(tmp);
797                                 buffer_add(buf, data);
798                                 if(jsonIteratorHasNext(itr))
799                                         buffer_add(buf, ",");
800                                 free(data);
801                         }
802
803                         jsonIteratorFree(itr);
804                         buffer_add(buf, "}");
805                         break;
806                 
807                         default:
808                                 fprintf(stderr, "Unknown object type %d\n", obj->type);
809                                 break;
810                                 
811         }
812
813         /* close out the object hint */
814         if(obj->classname) {
815                 buffer_add(buf, "/*--E ");
816                 buffer_add(buf, obj->classname);
817                 buffer_add(buf, "--*/");
818         }
819
820         char* data = buffer_data(buf);
821         buffer_free(buf);
822         return data;
823 }
824
825
826
827 static jsonObjectNode* makeNode(jsonObject* obj, unsigned long index, char* key) {
828     jsonObjectNode* node = safe_malloc(sizeof(jsonObjectNode));
829     node->item = obj;
830     node->index = index;
831     node->key = key;
832     return node;
833 }
834
835 jsonObjectIterator* jsonNewObjectIterator(const jsonObject* obj) {
836         if(!obj) return NULL;
837         jsonObjectIterator* itr = safe_malloc(sizeof(jsonObjectIterator));
838     itr->iterator = jsonNewIterator(obj);
839         itr->obj = obj;
840     itr->done = 0;
841     itr->current = NULL;
842         return itr;
843 }
844
845 jsonObjectNode* jsonObjectIteratorNext( jsonObjectIterator* itr ) {
846         if(itr == NULL || itr->done) return NULL;
847
848     if(itr->current) free(itr->current);
849     jsonObject* next = jsonIteratorNext(itr->iterator);
850     if(next == NULL) {
851         itr->current = NULL;
852         itr->done = 1;
853         return NULL;
854     }
855     itr->current = makeNode(next, itr->iterator->index, itr->iterator->key);
856     return itr->current;
857 }
858
859 void jsonObjectIteratorFree(jsonObjectIterator* iter) { 
860     if(iter->current) free(iter->current);
861     jsonIteratorFree(iter->iterator);
862         free(iter);
863 }
864
865 int jsonObjectIteratorHasNext(const jsonObjectIterator* itr) {
866         return (itr && itr->current);
867 }
868
869