source: lib/json.c @ 7a80925

Last change on this file since 7a80925 was 7a80925, checked in by Wilmer van der Gaast <wilmer@…>, at 2014-02-13T08:48:37Z

Update json-parser code to git rev 11a80f389769d1f66ca7fbe64ad89c82d3ba4ba9.
Few BitlBee-specific diffs now. Annoyingly need to link to libm now for the
use of the function pow() since the lib now does its own number parsing...

  • Property mode set to 100644
File size: 26.3 KB
Line 
1/* vim: set et ts=3 sw=3 sts=3 ft=c:
2 *
3 * Copyright (C) 2012, 2013, 2014 James McLaughlin et al.  All rights reserved.
4 * https://github.com/udp/json-parser
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *   notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *   notice, this list of conditions and the following disclaimer in the
15 *   documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <glib.h>
31
32#include "json.h"
33
34#ifdef _MSC_VER
35   #ifndef _CRT_SECURE_NO_WARNINGS
36      #define _CRT_SECURE_NO_WARNINGS
37   #endif
38#endif
39
40#ifdef __cplusplus
41   const struct _json_value json_value_none; /* zero-d by ctor */
42#else
43   const struct _json_value json_value_none = { 0 };
44#endif
45
46#include <stdio.h>
47#include <string.h>
48#include <ctype.h>
49#include <math.h>
50
51typedef unsigned short json_uchar;
52
53static unsigned char hex_value (json_char c)
54{
55   if (isdigit(c))
56      return c - '0';
57
58   switch (c) {
59      case 'a': case 'A': return 0x0A;
60      case 'b': case 'B': return 0x0B;
61      case 'c': case 'C': return 0x0C;
62      case 'd': case 'D': return 0x0D;
63      case 'e': case 'E': return 0x0E;
64      case 'f': case 'F': return 0x0F;
65      default: return 0xFF;
66   }
67}
68
69typedef struct
70{
71   unsigned long used_memory;
72
73   unsigned int uint_max;
74   unsigned long ulong_max;
75
76   json_settings settings;
77   int first_pass;
78
79} json_state;
80
81static void * default_alloc (size_t size, int zero, void * user_data)
82{
83   return zero ? calloc (1, size) : malloc (size);
84}
85
86static void default_free (void * ptr, void * user_data)
87{
88   free (ptr);
89}
90
91static void * json_alloc (json_state * state, unsigned long size, int zero)
92{
93   if ((state->ulong_max - state->used_memory) < size)
94      return 0;
95
96   if (state->settings.max_memory
97         && (state->used_memory += size) > state->settings.max_memory)
98   {
99      return 0;
100   }
101
102   return state->settings.mem_alloc (size, zero, state->settings.user_data);
103}
104
105static int new_value
106   (json_state * state, json_value ** top, json_value ** root, json_value ** alloc, json_type type)
107{
108   json_value * value;
109   int values_size;
110
111   if (!state->first_pass)
112   {
113      value = *top = *alloc;
114      *alloc = (*alloc)->_reserved.next_alloc;
115
116      if (!*root)
117         *root = value;
118
119      switch (value->type)
120      {
121         case json_array:
122
123            if (! (value->u.array.values = (json_value **) json_alloc
124               (state, value->u.array.length * sizeof (json_value *), 0)) )
125            {
126               return 0;
127            }
128
129            value->u.array.length = 0;
130            break;
131
132         case json_object:
133
134            values_size = sizeof (*value->u.object.values) * value->u.object.length;
135
136            if (! ((*(void **) &value->u.object.values) = json_alloc
137                  (state, values_size + ((unsigned long) value->u.object.values), 0)) )
138            {
139               return 0;
140            }
141
142            value->_reserved.object_mem = (*(char **) &value->u.object.values) + values_size;
143
144            value->u.object.length = 0;
145            break;
146
147         case json_string:
148
149            if (! (value->u.string.ptr = (json_char *) json_alloc
150               (state, (value->u.string.length + 1) * sizeof (json_char), 0)) )
151            {
152               return 0;
153            }
154
155            value->u.string.length = 0;
156            break;
157
158         default:
159            break;
160      };
161
162      return 1;
163   }
164
165   value = (json_value *) json_alloc (state, sizeof (json_value), 1);
166
167   if (!value)
168      return 0;
169
170   if (!*root)
171      *root = value;
172
173   value->type = type;
174   value->parent = *top;
175
176   if (*alloc)
177      (*alloc)->_reserved.next_alloc = value;
178
179   *alloc = *top = value;
180
181   return 1;
182}
183
184#define e_off \
185   ((int) (i - cur_line_begin))
186
187#define whitespace \
188   case '\n': ++ cur_line;  cur_line_begin = i; \
189   case ' ': case '\t': case '\r'
190
191#define string_add(b)  \
192   do { if (!state.first_pass) string [string_length] = b;  ++ string_length; } while (0);
193
194static const long
195   flag_next             = 1 << 0,
196   flag_reproc           = 1 << 1,
197   flag_need_comma       = 1 << 2,
198   flag_seek_value       = 1 << 3, 
199   flag_escaped          = 1 << 4,
200   flag_string           = 1 << 5,
201   flag_need_colon       = 1 << 6,
202   flag_done             = 1 << 7,
203   flag_num_negative     = 1 << 8,
204   flag_num_zero         = 1 << 9,
205   flag_num_e            = 1 << 10,
206   flag_num_e_got_sign   = 1 << 11,
207   flag_num_e_negative   = 1 << 12,
208   flag_line_comment     = 1 << 13,
209   flag_block_comment    = 1 << 14;
210
211json_value * json_parse_ex (json_settings * settings,
212                            const json_char * json,
213                            size_t length,
214                            char * error_buf)
215{
216   json_char error [json_error_max];
217   unsigned int cur_line;
218   const json_char * cur_line_begin, * i, * end;
219   json_value * top, * root, * alloc = 0;
220   json_state state = { 0 };
221   long flags;
222   long num_digits = 0, num_e = 0;
223   json_int_t num_fraction = 0;
224
225   /* Skip UTF-8 BOM
226    */
227   if (length >= 3 && ((unsigned char) json [0]) == 0xEF
228                   && ((unsigned char) json [1]) == 0xBB
229                   && ((unsigned char) json [2]) == 0xBF)
230   {
231      json += 3;
232      length -= 3;
233   }
234
235   error[0] = '\0';
236   end = (json + length);
237
238   memcpy (&state.settings, settings, sizeof (json_settings));
239
240   if (!state.settings.mem_alloc)
241      state.settings.mem_alloc = default_alloc;
242
243   if (!state.settings.mem_free)
244      state.settings.mem_free = default_free;
245
246   memset (&state.uint_max, 0xFF, sizeof (state.uint_max));
247   memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max));
248
249   state.uint_max -= 8; /* limit of how much can be added before next check */
250   state.ulong_max -= 8;
251
252   for (state.first_pass = 1; state.first_pass >= 0; -- state.first_pass)
253   {
254      json_uchar uchar;
255      unsigned char uc_b1, uc_b2, uc_b3, uc_b4;
256      json_char * string = 0;
257      unsigned int string_length = 0;
258
259      top = root = 0;
260      flags = flag_seek_value;
261
262      cur_line = 1;
263      cur_line_begin = json;
264
265      for (i = json ;; ++ i)
266      {
267         json_char b = (i == end ? 0 : *i);
268         
269         if (flags & flag_string)
270         {
271            if (!b)
272            {  sprintf (error, "Unexpected EOF in string (at %d:%d)", cur_line, e_off);
273               goto e_failed;
274            }
275
276            if (string_length > state.uint_max)
277               goto e_overflow;
278
279            if (flags & flag_escaped)
280            {
281               flags &= ~ flag_escaped;
282
283               switch (b)
284               {
285                  case 'b':  string_add ('\b');  break;
286                  case 'f':  string_add ('\f');  break;
287                  case 'n':  string_add ('\n');  break;
288                  case 'r':  string_add ('\r');  break;
289                  case 't':  string_add ('\t');  break;
290                  case 'u':
291
292                    if (end - i < 4 || 
293                        (uc_b1 = hex_value (*++ i)) == 0xFF || (uc_b2 = hex_value (*++ i)) == 0xFF
294                          || (uc_b3 = hex_value (*++ i)) == 0xFF || (uc_b4 = hex_value (*++ i)) == 0xFF)
295                    {
296                        sprintf (error, "Invalid character value `%c` (at %d:%d)", b, cur_line, e_off);
297                        goto e_failed;
298                    }
299
300                    uc_b1 = uc_b1 * 16 + uc_b2;
301                    uc_b2 = uc_b3 * 16 + uc_b4;
302
303                    uchar = ((json_char) uc_b1) * 256 + uc_b2;
304
305                    if (sizeof (json_char) >= sizeof (json_uchar) || (uc_b1 == 0 && uc_b2 <= 0x7F))
306                    {
307                       string_add ((json_char) uchar);
308                       break;
309                    }
310
311                    if (uchar <= 0x7FF)
312                    {
313                        if (state.first_pass)
314                           string_length += 2;
315                        else
316                        {  string [string_length ++] = 0xC0 | ((uc_b2 & 0xC0) >> 6) | ((uc_b1 & 0x7) << 2);
317                           string [string_length ++] = 0x80 | (uc_b2 & 0x3F);
318                        }
319
320                        break;
321                    }
322
323                    if (state.first_pass)
324                       string_length += 3;
325                    else
326                    {  string [string_length ++] = 0xE0 | ((uc_b1 & 0xF0) >> 4);
327                       string [string_length ++] = 0x80 | ((uc_b1 & 0xF) << 2) | ((uc_b2 & 0xC0) >> 6);
328                       string [string_length ++] = 0x80 | (uc_b2 & 0x3F);
329                    }
330
331                    break;
332
333                  default:
334                     string_add (b);
335               };
336
337               continue;
338            }
339
340            if (b == '\\')
341            {
342               flags |= flag_escaped;
343               continue;
344            }
345
346            if (b == '"')
347            {
348               if (!state.first_pass)
349                  string [string_length] = 0;
350
351               flags &= ~ flag_string;
352               string = 0;
353
354               switch (top->type)
355               {
356                  case json_string:
357
358                     top->u.string.length = string_length;
359                     flags |= flag_next;
360
361                     break;
362
363                  case json_object:
364
365                     if (state.first_pass)
366                        (*(json_char **) &top->u.object.values) += string_length + 1;
367                     else
368                     { 
369                        top->u.object.values [top->u.object.length].name
370                           = (json_char *) top->_reserved.object_mem;
371
372                        top->u.object.values [top->u.object.length].name_length
373                           = string_length;
374
375                        (*(json_char **) &top->_reserved.object_mem) += string_length + 1;
376                     }
377
378                     flags |= flag_seek_value | flag_need_colon;
379                     continue;
380
381                  default:
382                     break;
383               };
384            }
385            else
386            {
387               string_add (b);
388               continue;
389            }
390         }
391
392         if (state.settings.settings & json_enable_comments)
393         {
394            if (flags & (flag_line_comment | flag_block_comment))
395            {
396               if (flags & flag_line_comment)
397               {
398                  if (b == '\r' || b == '\n' || !b)
399                  {
400                     flags &= ~ flag_line_comment;
401                     -- i;  /* so null can be reproc'd */
402                  }
403
404                  continue;
405               }
406
407               if (flags & flag_block_comment)
408               {
409                  if (!b)
410                  {  sprintf (error, "%d:%d: Unexpected EOF in block comment", cur_line, e_off);
411                     goto e_failed;
412                  }
413
414                  if (b == '*' && i < (end - 1) && i [1] == '/')
415                  {
416                     flags &= ~ flag_block_comment;
417                     ++ i;  /* skip closing sequence */
418                  }
419
420                  continue;
421               }
422            }
423            else if (b == '/')
424            {
425               if (! (flags & (flag_seek_value | flag_done)) && top->type != json_object)
426               {
427                  sprintf (error, "%d:%d: Comment not allowed here", cur_line, e_off);
428                  goto e_failed;
429               }
430
431               if (++ i == end)
432               {  sprintf (error, "%d:%d: EOF unexpected", cur_line, e_off);
433                  goto e_failed;
434               }
435
436               switch (b = *i)
437               {
438                  case '/':
439                     flags |= flag_line_comment;
440                     continue;
441
442                  case '*':
443                     flags |= flag_block_comment;
444                     continue;
445
446                  default:
447                     sprintf (error, "%d:%d: Unexpected `%c` in comment opening sequence", cur_line, e_off, b);
448                     goto e_failed;
449               };
450            }
451         }
452
453         if (flags & flag_done)
454         {
455            if (!b)
456               break;
457
458            switch (b)
459            {
460               whitespace:
461                  continue;
462
463               default:
464                  sprintf (error, "%d:%d: Trailing garbage: `%c`", cur_line, e_off, b);
465                  goto e_failed;
466            };
467         }
468
469         if (flags & flag_seek_value)
470         {
471            switch (b)
472            {
473               whitespace:
474                  continue;
475
476               case ']':
477
478                  if (top->type == json_array)
479                     flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next;
480                  else
481                  {  sprintf (error, "%d:%d: Unexpected ]", cur_line, e_off);
482                     goto e_failed;
483                  }
484
485                  break;
486
487               default:
488
489                  if (flags & flag_need_comma)
490                  {
491                     if (b == ',')
492                     {  flags &= ~ flag_need_comma;
493                        continue;
494                     }
495                     else
496                     {  sprintf (error, "%d:%d: Expected , before %c", cur_line, e_off, b);
497                        goto e_failed;
498                     }
499                  }
500
501                  if (flags & flag_need_colon)
502                  {
503                     if (b == ':')
504                     {  flags &= ~ flag_need_colon;
505                        continue;
506                     }
507                     else
508                     {  sprintf (error, "%d:%d: Expected : before %c", cur_line, e_off, b);
509                        goto e_failed;
510                     }
511                  }
512
513                  flags &= ~ flag_seek_value;
514
515                  switch (b)
516                  {
517                     case '{':
518
519                        if (!new_value (&state, &top, &root, &alloc, json_object))
520                           goto e_alloc_failure;
521
522                        continue;
523
524                     case '[':
525
526                        if (!new_value (&state, &top, &root, &alloc, json_array))
527                           goto e_alloc_failure;
528
529                        flags |= flag_seek_value;
530                        continue;
531
532                     case '"':
533
534                        if (!new_value (&state, &top, &root, &alloc, json_string))
535                           goto e_alloc_failure;
536
537                        flags |= flag_string;
538
539                        string = top->u.string.ptr;
540                        string_length = 0;
541
542                        continue;
543
544                     case 't':
545
546                        if ((end - i) < 3 || *(++ i) != 'r' || *(++ i) != 'u' || *(++ i) != 'e')
547                           goto e_unknown_value;
548
549                        if (!new_value (&state, &top, &root, &alloc, json_boolean))
550                           goto e_alloc_failure;
551
552                        top->u.boolean = 1;
553
554                        flags |= flag_next;
555                        break;
556
557                     case 'f':
558
559                        if ((end - i) < 4 || *(++ i) != 'a' || *(++ i) != 'l' || *(++ i) != 's' || *(++ i) != 'e')
560                           goto e_unknown_value;
561
562                        if (!new_value (&state, &top, &root, &alloc, json_boolean))
563                           goto e_alloc_failure;
564
565                        flags |= flag_next;
566                        break;
567
568                     case 'n':
569
570                        if ((end - i) < 3 || *(++ i) != 'u' || *(++ i) != 'l' || *(++ i) != 'l')
571                           goto e_unknown_value;
572
573                        if (!new_value (&state, &top, &root, &alloc, json_null))
574                           goto e_alloc_failure;
575
576                        flags |= flag_next;
577                        break;
578
579                     default:
580
581                        if (isdigit (b) || b == '-')
582                        {
583                           if (!new_value (&state, &top, &root, &alloc, json_integer))
584                              goto e_alloc_failure;
585
586                           if (!state.first_pass)
587                           {
588                              while (isdigit (b) || b == '+' || b == '-'
589                                        || b == 'e' || b == 'E' || b == '.')
590                              {
591                                 if ( (++ i) == end)
592                                 {
593                                    b = 0;
594                                    break;
595                                 }
596
597                                 b = *i;
598                              }
599
600                              flags |= flag_next | flag_reproc;
601                              break;
602                           }
603
604                           flags &= ~ (flag_num_negative | flag_num_e |
605                                        flag_num_e_got_sign | flag_num_e_negative |
606                                           flag_num_zero);
607
608                           num_digits = 0;
609                           num_fraction = 0;
610                           num_e = 0;
611
612                           if (b != '-')
613                           {
614                              flags |= flag_reproc;
615                              break;
616                           }
617
618                           flags |= flag_num_negative;
619                           continue;
620                        }
621                        else
622                        {  sprintf (error, "%d:%d: Unexpected %c when seeking value", cur_line, e_off, b);
623                           goto e_failed;
624                        }
625                  };
626            };
627         }
628         else
629         {
630            switch (top->type)
631            {
632            case json_object:
633               
634               switch (b)
635               {
636                  whitespace:
637                     continue;
638
639                  case '"':
640
641                     if (flags & flag_need_comma)
642                     {
643                        sprintf (error, "%d:%d: Expected , before \"", cur_line, e_off);
644                        goto e_failed;
645                     }
646
647                     flags |= flag_string;
648
649                     string = (json_char *) top->_reserved.object_mem;
650                     string_length = 0;
651
652                     break;
653                 
654                  case '}':
655
656                     flags = (flags & ~ flag_need_comma) | flag_next;
657                     break;
658
659                  case ',':
660
661                     if (flags & flag_need_comma)
662                     {
663                        flags &= ~ flag_need_comma;
664                        break;
665                     }
666
667                  default:
668
669                     sprintf (error, "%d:%d: Unexpected `%c` in object", cur_line, e_off, b);
670                     goto e_failed;
671               };
672
673               break;
674
675            case json_integer:
676            case json_double:
677
678               if (isdigit (b))
679               {
680                  ++ num_digits;
681
682                  if (top->type == json_integer || flags & flag_num_e)
683                  {
684                     if (! (flags & flag_num_e))
685                     {
686                        if (flags & flag_num_zero)
687                        {  sprintf (error, "%d:%d: Unexpected `0` before `%c`", cur_line, e_off, b);
688                           goto e_failed;
689                        }
690
691                        if (num_digits == 1 && b == '0')
692                           flags |= flag_num_zero;
693                     }
694                     else
695                     {
696                        flags |= flag_num_e_got_sign;
697                        num_e = (num_e * 10) + (b - '0');
698                        continue;
699                     }
700
701                     top->u.integer = (top->u.integer * 10) + (b - '0');
702                     continue;
703                  }
704
705                  num_fraction = (num_fraction * 10) + (b - '0');
706                  continue;
707               }
708
709               if (b == '+' || b == '-')
710               {
711                  if ( (flags & flag_num_e) && !(flags & flag_num_e_got_sign))
712                  {
713                     flags |= flag_num_e_got_sign;
714
715                     if (b == '-')
716                        flags |= flag_num_e_negative;
717
718                     continue;
719                  }
720               }
721               else if (b == '.' && top->type == json_integer)
722               {
723                  if (!num_digits)
724                  {  sprintf (error, "%d:%d: Expected digit before `.`", cur_line, e_off);
725                     goto e_failed;
726                  }
727
728                  top->type = json_double;
729                  top->u.dbl = (double) top->u.integer;
730
731                  num_digits = 0;
732                  continue;
733               }
734
735               if (! (flags & flag_num_e))
736               {
737                  if (top->type == json_double)
738                  {
739                     if (!num_digits)
740                     {  sprintf (error, "%d:%d: Expected digit after `.`", cur_line, e_off);
741                        goto e_failed;
742                     }
743
744                     top->u.dbl += ((double) num_fraction) / (pow (10, (double) num_digits));
745                  }
746
747                  if (b == 'e' || b == 'E')
748                  {
749                     flags |= flag_num_e;
750
751                     if (top->type == json_integer)
752                     {
753                        top->type = json_double;
754                        top->u.dbl = (double) top->u.integer;
755                     }
756
757                     num_digits = 0;
758                     flags &= ~ flag_num_zero;
759
760                     continue;
761                  }
762               }
763               else
764               {
765                  if (!num_digits)
766                  {  sprintf (error, "%d:%d: Expected digit after `e`", cur_line, e_off);
767                     goto e_failed;
768                  }
769
770                  top->u.dbl *= pow (10, (double) (flags & flag_num_e_negative ? - num_e : num_e));
771               }
772
773               if (flags & flag_num_negative)
774               {
775                  if (top->type == json_integer)
776                     top->u.integer = - top->u.integer;
777                  else
778                     top->u.dbl = - top->u.dbl;
779               }
780
781               flags |= flag_next | flag_reproc;
782               break;
783
784            default:
785               break;
786            };
787         }
788
789         if (flags & flag_reproc)
790         {
791            flags &= ~ flag_reproc;
792            -- i;
793         }
794
795         if (flags & flag_next)
796         {
797            flags = (flags & ~ flag_next) | flag_need_comma;
798
799            if (!top->parent)
800            {
801               /* root value done */
802
803               flags |= flag_done;
804               continue;
805            }
806
807            if (top->parent->type == json_array)
808               flags |= flag_seek_value;
809               
810            if (!state.first_pass)
811            {
812               json_value * parent = top->parent;
813
814               switch (parent->type)
815               {
816                  case json_object:
817
818                     parent->u.object.values
819                        [parent->u.object.length].value = top;
820
821                     break;
822
823                  case json_array:
824
825                     parent->u.array.values
826                           [parent->u.array.length] = top;
827
828                     break;
829
830                  default:
831                     break;
832               };
833            }
834
835            if ( (++ top->parent->u.array.length) > state.uint_max)
836               goto e_overflow;
837
838            top = top->parent;
839
840            continue;
841         }
842      }
843
844      alloc = root;
845   }
846
847   return root;
848
849e_unknown_value:
850
851   sprintf (error, "%d:%d: Unknown value", cur_line, e_off);
852   goto e_failed;
853
854e_alloc_failure:
855
856   strcpy (error, "Memory allocation failure");
857   goto e_failed;
858
859e_overflow:
860
861   sprintf (error, "%d:%d: Too long (caught overflow)", cur_line, e_off);
862   goto e_failed;
863
864e_failed:
865
866   if (error_buf)
867   {
868      if (*error)
869         strcpy (error_buf, error);
870      else
871         strcpy (error_buf, "Unknown error");
872   }
873
874   if (state.first_pass)
875      alloc = root;
876
877   while (alloc)
878   {
879      top = alloc->_reserved.next_alloc;
880      state.settings.mem_free (alloc, state.settings.user_data);
881      alloc = top;
882   }
883
884   if (!state.first_pass)
885      json_value_free_ex (&state.settings, root);
886
887   return 0;
888}
889
890json_value * json_parse (const json_char * json, size_t length)
891{
892   json_settings settings = { 0 };
893   return json_parse_ex (&settings, json, length, 0);
894}
895
896void json_value_free_ex (json_settings * settings, json_value * value)
897{
898   json_value * cur_value;
899
900   if (!value)
901      return;
902
903   value->parent = 0;
904
905   while (value)
906   {
907      switch (value->type)
908      {
909         case json_array:
910
911            if (!value->u.array.length)
912            {
913               settings->mem_free (value->u.array.values, settings->user_data);
914               break;
915            }
916
917            value = value->u.array.values [-- value->u.array.length];
918            continue;
919
920         case json_object:
921
922            if (!value->u.object.length)
923            {
924               settings->mem_free (value->u.object.values, settings->user_data);
925               break;
926            }
927
928            value = value->u.object.values [-- value->u.object.length].value;
929            continue;
930
931         case json_string:
932
933            settings->mem_free (value->u.string.ptr, settings->user_data);
934            break;
935
936         default:
937            break;
938      };
939
940      cur_value = value;
941      value = value->parent;
942      settings->mem_free (cur_value, settings->user_data);
943   }
944}
945
946void json_value_free (json_value * value)
947{
948   json_settings settings = { 0 };
949   settings.mem_free = default_free;
950   json_value_free_ex (&settings, value);
951}
952
Note: See TracBrowser for help on using the repository browser.