LP#1243841 - Quiet additional Make warnings and some code cleanup.
[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                                         /* ----------------------------------------------------------------------- */
482                                         /* ----------------------------------------------------------------------- */
483                                         /* The following chunk was borrowed with permission from 
484                                                 json-c http://oss.metaparadigm.com/json-c/ */
485                                         unsigned char utf_out[3] = { '\0', '\0', '\0' };
486
487                                         #define hexdigit(x) ( ((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
488
489                                         unsigned int ucs_char =
490                                                 (hexdigit(string[*index] ) << 12) +
491                                                 (hexdigit(string[*index + 1]) << 8) +
492                                                 (hexdigit(string[*index + 2]) << 4) +
493                                                 hexdigit(string[*index + 3]);
494         
495                                         if (ucs_char < 0x80) {
496                                                 utf_out[0] = ucs_char;
497                                                 buffer_add(buf, (char*) utf_out);
498
499                                         } else if (ucs_char < 0x800) {
500                                                 utf_out[0] = 0xc0 | (ucs_char >> 6);
501                                                 utf_out[1] = 0x80 | (ucs_char & 0x3f);
502                                                 buffer_add(buf, (char*) utf_out);
503
504                                         } else {
505                                                 utf_out[0] = 0xe0 | (ucs_char >> 12);
506                                                 utf_out[1] = 0x80 | ((ucs_char >> 6) & 0x3f);
507                                                 utf_out[2] = 0x80 | (ucs_char & 0x3f);
508                                                 buffer_add(buf, (char*) utf_out);
509                                         }
510                                         /* ----------------------------------------------------------------------- */
511                                         /* ----------------------------------------------------------------------- */
512
513                                         (*index) += 3;
514                                         in_escape = 0;
515
516                                 } else {
517
518                                         buffer_add_char(buf, c);
519                                 }
520
521                                 break;
522
523                         default:
524                                 buffer_add_char(buf, c);
525                 }
526
527                 (*index)++;
528                 if(done) break;
529         }
530
531         jsonObjectSetString(obj, buf->buf);
532         buffer_free(buf);
533         return 0;
534 }
535
536
537 void json_eat_ws(char* string, unsigned long* index, int eat_all, int current_strlen) {
538         if( ! string || ! index ) return;
539         if(*index >= current_strlen)
540                 return;
541
542         if( eat_all ) { /* removes newlines, etc */
543                 while(string[*index] == ' '     || 
544                                 string[*index] == '\n'  ||
545                                 string[*index] == '\t') 
546                         (*index)++;
547         }
548
549         else    
550                 while(string[*index] == ' ') (*index)++;
551 }
552
553
554 /* index should be at the '*' character at the beginning of the comment.
555  * when done, index will point to the first character after the final /
556  */
557 int json_eat_comment(char* string, unsigned long* index, char** buffer, int parse_class, int current_strlen) {
558         if( ! string || ! index || *index >= current_strlen ) return -1;
559         
560
561         if(string[*index] != '*' && string[*index] != '/' )
562                 return json_handle_error(string, index, 
563                         "json_eat_comment(): invalid character after /");
564
565         /* chop out any // style comments */
566         if(string[*index] == '/') {
567                 (*index)++;
568                 char c = string[*index];
569                 while(*index < current_strlen) {
570                         (*index)++;
571                         if(c == '\n') 
572                                 return 0;
573                         c = string[*index];
574                 }
575                 return 0;
576         }
577
578         (*index)++;
579
580         int on_star                     = 0; /* true if we just saw a '*' character */
581
582         /* we're just past the '*' */
583         if(!parse_class) { /* we're not concerned with class hints */
584                 while(*index < current_strlen) {
585                         if(string[*index] == '/') {
586                                 if(on_star) {
587                                         (*index)++;
588                                         return 0;
589                                 }
590                         }
591
592                         if(string[*index] == '*') on_star = 1;
593                         else on_star = 0;
594
595                         (*index)++;
596                 }
597                 return 0;
598         }
599
600
601
602         growing_buffer* buf = buffer_init(64);
603
604         int first_dash          = 0;
605         int second_dash = 0;
606
607         int in_hint                     = 0;
608         int done                                = 0;
609
610         /*--S hint--*/   /* <-- Hints  look like this */
611         /*--E hint--*/
612
613         while(*index < current_strlen) {
614                 char c = string[*index];
615
616                 switch(c) {
617
618                         case '-':
619                                 on_star = 0;
620                                 if(first_dash)  second_dash = 1;
621                                 else                                            first_dash = 1;
622                                 break;
623
624                         case 'S':
625                                 on_star = 0;
626                                 if(second_dash && !in_hint) {
627                                         (*index)++;
628                                         json_eat_ws(string, index, 1, current_strlen);
629                                         (*index)--; /* this will get incremented at the bottom of the loop */
630                                         in_hint = 1;
631                                         break;
632                                 } 
633
634                                 if(second_dash && in_hint) {
635                                         buffer_add_char(buf, c);
636                                         break;
637                                 }
638
639                         case 'E':
640                                 on_star = 0;
641                                 if(second_dash && !in_hint) {
642                                         (*index)++;
643                                         json_eat_ws(string, index, 1, current_strlen);
644                                         (*index)--; /* this will get incremented at the bottom of the loop */
645                                         in_hint = 1;
646                                         break;
647                                 }
648
649                                 if(second_dash && in_hint) {
650                                         buffer_add_char(buf, c);
651                                         break;
652                                 }
653
654                         case '*':
655                                 on_star = 1;
656                                 break;
657
658                         case '/':
659                                 if(on_star) 
660                                         done = 1;
661                                 else
662                                 on_star = 0;
663                                 break;
664
665                         default:
666                                 on_star = 0;
667                                 if(in_hint)
668                                         buffer_add_char(buf, c);
669                 }
670
671                 (*index)++;
672                 if(done) break;
673         }
674
675         if( buf->n_used > 0 && buffer)
676                 *buffer = buffer_data(buf);
677
678         buffer_free(buf);
679         return 0;
680 }
681
682 int json_handle_error(char* string, unsigned long* index, char* err_msg) {
683
684         char buf[60];
685         osrf_clearbuf(buf, sizeof(buf));
686
687         if(*index > 30)
688                 strncpy( buf, string + (*index - 30), sizeof(buf) - 1 );
689         else
690                 strncpy( buf, string, sizeof(buf) - 1 );
691
692         buf[ sizeof(buf) - 1 ] = '\0';
693
694         fprintf(stderr, 
695                         "\nError parsing json string at charracter %c "
696                         "(code %d) and index %ld\nString length: %d\nMsg:\t%s\nNear:\t%s\nFull String:\t%s\n", 
697                         string[*index], string[*index], *index, current_strlen, err_msg, buf, string );
698
699         return -1;
700 }
701
702 char* legacy_jsonObjectToJSON( const jsonObject* obj ) {
703
704         if(obj == NULL) return strdup("null");
705
706         growing_buffer* buf = buffer_init(64);
707
708         /* add class hints if we have a class name */
709         if(obj->classname) {
710                 buffer_add(buf,"/*--S ");
711                 buffer_add(buf,obj->classname);
712                 buffer_add(buf, "--*/");
713         }
714
715         switch( obj->type ) {
716
717                 case JSON_BOOL: 
718                         if(obj->value.b) buffer_add(buf, "true"); 
719                         else buffer_add(buf, "false"); 
720                         break;
721
722                 case JSON_NUMBER: {
723                         buffer_add(buf, obj->value.s);
724                         break;
725                 }
726
727                 case JSON_NULL:
728                         buffer_add(buf, "null");
729                         break;
730
731                 case JSON_STRING:
732                         buffer_add(buf, "\"");
733                         char* data = obj->value.s;
734                         int len = strlen(data);
735                         
736                         char* output = uescape(data, len, 1);
737                         buffer_add(buf, output);
738                         free(output);
739                         buffer_add(buf, "\"");
740                         break;
741
742                 case JSON_ARRAY:
743                         buffer_add(buf, "[");
744                         int i;
745                         for( i = 0; i!= obj->size; i++ ) {
746                                 const jsonObject* x = jsonObjectGetIndex(obj,i);
747                                 char* data = legacy_jsonObjectToJSON(x);
748                                 buffer_add(buf, data);
749                                 free(data);
750                                 if(i != obj->size - 1)
751                                         buffer_add(buf, ",");
752                         }
753                         buffer_add(buf, "]");
754                         break;  
755
756                 case JSON_HASH:
757         
758                         buffer_add(buf, "{");
759                         jsonIterator* itr = jsonNewIterator(obj);
760                         jsonObject* tmp;
761         
762                         while( (tmp = jsonIteratorNext(itr)) ) {
763
764                                 buffer_add(buf, "\"");
765
766                                 const char* key = itr->key;
767                                 int len = strlen(key);
768                                 char* output = uescape(key, len, 1);
769                                 buffer_add(buf, output);
770                                 free(output);
771
772                                 buffer_add(buf, "\":");
773                                 char* data =  legacy_jsonObjectToJSON(tmp);
774                                 buffer_add(buf, data);
775                                 if(jsonIteratorHasNext(itr))
776                                         buffer_add(buf, ",");
777                                 free(data);
778                         }
779
780                         jsonIteratorFree(itr);
781                         buffer_add(buf, "}");
782                         break;
783                 
784                         default:
785                                 fprintf(stderr, "Unknown object type %d\n", obj->type);
786                                 break;
787                                 
788         }
789
790         /* close out the object hint */
791         if(obj->classname) {
792                 buffer_add(buf, "/*--E ");
793                 buffer_add(buf, obj->classname);
794                 buffer_add(buf, "--*/");
795         }
796
797         char* data = buffer_data(buf);
798         buffer_free(buf);
799         return data;
800 }
801
802
803
804 static jsonObjectNode* makeNode(jsonObject* obj, unsigned long index, char* key) {
805     jsonObjectNode* node = safe_malloc(sizeof(jsonObjectNode));
806     node->item = obj;
807     node->index = index;
808     node->key = key;
809     return node;
810 }
811
812 jsonObjectIterator* jsonNewObjectIterator(const jsonObject* obj) {
813         if(!obj) return NULL;
814         jsonObjectIterator* itr = safe_malloc(sizeof(jsonObjectIterator));
815     itr->iterator = jsonNewIterator(obj);
816         itr->obj = obj;
817     itr->done = 0;
818     itr->current = NULL;
819         return itr;
820 }
821
822 jsonObjectNode* jsonObjectIteratorNext( jsonObjectIterator* itr ) {
823         if(itr == NULL || itr->done) return NULL;
824
825     if(itr->current) free(itr->current);
826     jsonObject* next = jsonIteratorNext(itr->iterator);
827     if(next == NULL) {
828         itr->current = NULL;
829         itr->done = 1;
830         return NULL;
831     }
832     /* Lp 1243841: Remove compiler const warning. */
833     char *k = (char *) itr->iterator->key;
834     itr->current = makeNode(next, itr->iterator->index, k);
835     return itr->current;
836 }
837
838 void jsonObjectIteratorFree(jsonObjectIterator* iter) { 
839     if(iter->current) free(iter->current);
840     jsonIteratorFree(iter->iterator);
841         free(iter);
842 }
843
844 int jsonObjectIteratorHasNext(const jsonObjectIterator* itr) {
845         return (itr && itr->current);
846 }
847
848