diff options
| author | Wilmer van der Gaast <wilmer@gaast.net> | 2014-02-13 08:48:37 +0000 | 
|---|---|---|
| committer | Wilmer van der Gaast <wilmer@gaast.net> | 2014-02-13 08:48:37 +0000 | 
| commit | 7a80925eabe969ffc1e8e24c2ad31c80c33ab3cd (patch) | |
| tree | e070eccc63ed1819f999e9464d3fb6fb7a302cc3 /lib | |
| parent | e76cf264de6caaca24fa308cab78e770fc4a6508 (diff) | |
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...
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/json.c | 391 | ||||
| -rw-r--r-- | lib/json.h | 101 | ||||
| -rw-r--r-- | lib/oauth2.c | 2 | 
3 files changed, 391 insertions, 103 deletions
| @@ -1,7 +1,6 @@ - -/* vim: set et ts=3 sw=3 ft=c: +/* vim: set et ts=3 sw=3 sts=3 ft=c:   * - * Copyright (C) 2012 James McLaughlin et al.  All rights reserved. + * Copyright (C) 2012, 2013, 2014 James McLaughlin et al.  All rights reserved.   * https://github.com/udp/json-parser   *   * Redistribution and use in source and binary forms, with or without @@ -28,6 +27,8 @@   * SUCH DAMAGE.   */ +#include <glib.h> +  #include "json.h"  #ifdef _MSC_VER @@ -42,44 +43,53 @@     const struct _json_value json_value_none = { 0 };  #endif -#include <glib.h> -#include <stdlib.h>  #include <stdio.h>  #include <string.h>  #include <ctype.h> +#include <math.h>  typedef unsigned short json_uchar;  static unsigned char hex_value (json_char c)  { -   if (c >= 'A' && c <= 'F') -      return (c - 'A') + 10; - -   if (c >= 'a' && c <= 'f') -      return (c - 'a') + 10; - -   if (c >= '0' && c <= '9') +   if (isdigit(c))        return c - '0'; -   return 0xFF; +   switch (c) { +      case 'a': case 'A': return 0x0A; +      case 'b': case 'B': return 0x0B; +      case 'c': case 'C': return 0x0C; +      case 'd': case 'D': return 0x0D; +      case 'e': case 'E': return 0x0E; +      case 'f': case 'F': return 0x0F; +      default: return 0xFF; +   }  }  typedef struct  { -   json_settings settings; -   int first_pass; -     unsigned long used_memory;     unsigned int uint_max;     unsigned long ulong_max; +   json_settings settings; +   int first_pass; +  } json_state; -static void * json_alloc (json_state * state, unsigned long size, int zero) +static void * default_alloc (size_t size, int zero, void * user_data) +{ +   return zero ? calloc (1, size) : malloc (size); +} + +static void default_free (void * ptr, void * user_data)  { -   void * mem; +   free (ptr); +} +static void * json_alloc (json_state * state, unsigned long size, int zero) +{     if ((state->ulong_max - state->used_memory) < size)        return 0; @@ -89,10 +99,7 @@ static void * json_alloc (json_state * state, unsigned long size, int zero)        return 0;     } -   if (! (mem = zero ? calloc (size, 1) : malloc (size))) -      return 0; - -   return mem; +   return state->settings.mem_alloc (size, zero, state->settings.user_data);  }  static int new_value @@ -119,6 +126,7 @@ static int new_value                 return 0;              } +            value->u.array.length = 0;              break;           case json_object: @@ -133,6 +141,7 @@ static int new_value              value->_reserved.object_mem = (*(char **) &value->u.object.values) + values_size; +            value->u.object.length = 0;              break;           case json_string: @@ -143,14 +152,13 @@ static int new_value                 return 0;              } +            value->u.string.length = 0;              break;           default:              break;        }; -      value->u.array.length = 0; -        return 1;     } @@ -183,25 +191,58 @@ static int new_value  #define string_add(b)  \     do { if (!state.first_pass) string [string_length] = b;  ++ string_length; } while (0); -const static int -   flag_next = 1, flag_reproc = 2, flag_need_comma = 4, flag_seek_value = 8, flag_exponent = 16, -   flag_got_exponent_sign = 32, flag_escaped = 64, flag_string = 128, flag_need_colon = 256, -   flag_done = 512; - -json_value * json_parse_ex (json_settings * settings, const json_char * json, char * error_buf) +static const long +   flag_next             = 1 << 0, +   flag_reproc           = 1 << 1, +   flag_need_comma       = 1 << 2, +   flag_seek_value       = 1 << 3,  +   flag_escaped          = 1 << 4, +   flag_string           = 1 << 5, +   flag_need_colon       = 1 << 6, +   flag_done             = 1 << 7, +   flag_num_negative     = 1 << 8, +   flag_num_zero         = 1 << 9, +   flag_num_e            = 1 << 10, +   flag_num_e_got_sign   = 1 << 11, +   flag_num_e_negative   = 1 << 12, +   flag_line_comment     = 1 << 13, +   flag_block_comment    = 1 << 14; + +json_value * json_parse_ex (json_settings * settings, +                            const json_char * json, +                            size_t length, +                            char * error_buf)  { -   json_char error [128]; +   json_char error [json_error_max];     unsigned int cur_line; -   const json_char * cur_line_begin, * i; +   const json_char * cur_line_begin, * i, * end;     json_value * top, * root, * alloc = 0; -   json_state state; -   int flags; +   json_state state = { 0 }; +   long flags; +   long num_digits = 0, num_e = 0; +   json_int_t num_fraction = 0; + +   /* Skip UTF-8 BOM +    */ +   if (length >= 3 && ((unsigned char) json [0]) == 0xEF +                   && ((unsigned char) json [1]) == 0xBB +                   && ((unsigned char) json [2]) == 0xBF) +   { +      json += 3; +      length -= 3; +   }     error[0] = '\0'; +   end = (json + length); -   memset (&state, 0, sizeof (json_state));     memcpy (&state.settings, settings, sizeof (json_settings)); +   if (!state.settings.mem_alloc) +      state.settings.mem_alloc = default_alloc; + +   if (!state.settings.mem_free) +      state.settings.mem_free = default_free; +     memset (&state.uint_max, 0xFF, sizeof (state.uint_max));     memset (&state.ulong_max, 0xFF, sizeof (state.ulong_max)); @@ -223,24 +264,8 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch        for (i = json ;; ++ i)        { -         json_char b = *i; - -         if (flags & flag_done) -         { -            if (!b) -               break; - -            switch (b) -            { -               whitespace: -                  continue; - -               default: -                  sprintf (error, "%d:%d: Trailing garbage: `%c`", cur_line, e_off, b); -                  goto e_failed; -            }; -         } - +         json_char b = (i == end ? 0 : *i); +                    if (flags & flag_string)           {              if (!b) @@ -264,7 +289,8 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch                    case 't':  string_add ('\t');  break;                    case 'u': -                    if ((uc_b1 = hex_value (*++ i)) == 0xFF || (uc_b2 = hex_value (*++ i)) == 0xFF +                    if (end - i < 4 ||  +                        (uc_b1 = hex_value (*++ i)) == 0xFF || (uc_b2 = hex_value (*++ i)) == 0xFF                            || (uc_b3 = hex_value (*++ i)) == 0xFF || (uc_b4 = hex_value (*++ i)) == 0xFF)                      {                          sprintf (error, "Invalid character value `%c` (at %d:%d)", b, cur_line, e_off); @@ -343,6 +369,9 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch                          top->u.object.values [top->u.object.length].name                             = (json_char *) top->_reserved.object_mem; +                        top->u.object.values [top->u.object.length].name_length +                           = string_length; +                          (*(json_char **) &top->_reserved.object_mem) += string_length + 1;                       } @@ -360,6 +389,83 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch              }           } +         if (state.settings.settings & json_enable_comments) +         { +            if (flags & (flag_line_comment | flag_block_comment)) +            { +               if (flags & flag_line_comment) +               { +                  if (b == '\r' || b == '\n' || !b) +                  { +                     flags &= ~ flag_line_comment; +                     -- i;  /* so null can be reproc'd */ +                  } + +                  continue; +               } + +               if (flags & flag_block_comment) +               { +                  if (!b) +                  {  sprintf (error, "%d:%d: Unexpected EOF in block comment", cur_line, e_off); +                     goto e_failed; +                  } + +                  if (b == '*' && i < (end - 1) && i [1] == '/') +                  { +                     flags &= ~ flag_block_comment; +                     ++ i;  /* skip closing sequence */ +                  } + +                  continue; +               } +            } +            else if (b == '/') +            { +               if (! (flags & (flag_seek_value | flag_done)) && top->type != json_object) +               { +                  sprintf (error, "%d:%d: Comment not allowed here", cur_line, e_off); +                  goto e_failed; +               } + +               if (++ i == end) +               {  sprintf (error, "%d:%d: EOF unexpected", cur_line, e_off); +                  goto e_failed; +               } + +               switch (b = *i) +               { +                  case '/': +                     flags |= flag_line_comment; +                     continue; + +                  case '*': +                     flags |= flag_block_comment; +                     continue; + +                  default: +                     sprintf (error, "%d:%d: Unexpected `%c` in comment opening sequence", cur_line, e_off, b); +                     goto e_failed; +               }; +            } +         } + +         if (flags & flag_done) +         { +            if (!b) +               break; + +            switch (b) +            { +               whitespace: +                  continue; + +               default: +                  sprintf (error, "%d:%d: Trailing garbage: `%c`", cur_line, e_off, b); +                  goto e_failed; +            }; +         } +           if (flags & flag_seek_value)           {              switch (b) @@ -371,7 +477,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch                    if (top->type == json_array)                       flags = (flags & ~ (flag_need_comma | flag_seek_value)) | flag_next; -                  else if (!state.settings.settings & json_relaxed_commas) +                  else                    {  sprintf (error, "%d:%d: Unexpected ]", cur_line, e_off);                       goto e_failed;                    } @@ -437,7 +543,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch                       case 't': -                        if (*(++ i) != 'r' || *(++ i) != 'u' || *(++ i) != 'e') +                        if ((end - i) < 3 || *(++ i) != 'r' || *(++ i) != 'u' || *(++ i) != 'e')                             goto e_unknown_value;                          if (!new_value (&state, &top, &root, &alloc, json_boolean)) @@ -450,7 +556,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch                       case 'f': -                        if (*(++ i) != 'a' || *(++ i) != 'l' || *(++ i) != 's' || *(++ i) != 'e') +                        if ((end - i) < 4 || *(++ i) != 'a' || *(++ i) != 'l' || *(++ i) != 's' || *(++ i) != 'e')                             goto e_unknown_value;                          if (!new_value (&state, &top, &root, &alloc, json_boolean)) @@ -461,7 +567,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch                       case 'n': -                        if (*(++ i) != 'u' || *(++ i) != 'l' || *(++ i) != 'l') +                        if ((end - i) < 3 || *(++ i) != 'u' || *(++ i) != 'l' || *(++ i) != 'l')                             goto e_unknown_value;                          if (!new_value (&state, &top, &root, &alloc, json_null)) @@ -477,17 +583,40 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch                             if (!new_value (&state, &top, &root, &alloc, json_integer))                                goto e_alloc_failure; -                           flags &= ~ (flag_exponent | flag_got_exponent_sign); - -                           if (state.first_pass) -                              continue; - -                           if (top->type == json_double) -                              top->u.dbl = g_ascii_strtod (i, (json_char **) &i); -                           else -                              top->u.integer = g_ascii_strtoll (i, (json_char **) &i, 10); - -                           flags |= flag_next | flag_reproc; +                           if (!state.first_pass) +                           { +                              while (isdigit (b) || b == '+' || b == '-' +                                        || b == 'e' || b == 'E' || b == '.') +                              { +                                 if ( (++ i) == end) +                                 { +                                    b = 0; +                                    break; +                                 } + +                                 b = *i; +                              } + +                              flags |= flag_next | flag_reproc; +                              break; +                           } + +                           flags &= ~ (flag_num_negative | flag_num_e | +                                        flag_num_e_got_sign | flag_num_e_negative | +                                           flag_num_zero); + +                           num_digits = 0; +                           num_fraction = 0; +                           num_e = 0; + +                           if (b != '-') +                           { +                              flags |= flag_reproc; +                              break; +                           } + +                           flags |= flag_num_negative; +                           continue;                          }                          else                          {  sprintf (error, "%d:%d: Unexpected %c when seeking value", cur_line, e_off, b); @@ -509,7 +638,7 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch                    case '"': -                     if (flags & flag_need_comma && (!state.settings.settings & json_relaxed_commas)) +                     if (flags & flag_need_comma)                       {                          sprintf (error, "%d:%d: Expected , before \"", cur_line, e_off);                          goto e_failed; @@ -547,32 +676,108 @@ json_value * json_parse_ex (json_settings * settings, const json_char * json, ch              case json_double:                 if (isdigit (b)) -                  continue; - -               if (b == 'e' || b == 'E')                 { -                  if (!(flags & flag_exponent)) +                  ++ num_digits; + +                  if (top->type == json_integer || flags & flag_num_e)                    { -                     flags |= flag_exponent; -                     top->type = json_double; +                     if (! (flags & flag_num_e)) +                     { +                        if (flags & flag_num_zero) +                        {  sprintf (error, "%d:%d: Unexpected `0` before `%c`", cur_line, e_off, b); +                           goto e_failed; +                        } +                        if (num_digits == 1 && b == '0') +                           flags |= flag_num_zero; +                     } +                     else +                     { +                        flags |= flag_num_e_got_sign; +                        num_e = (num_e * 10) + (b - '0'); +                        continue; +                     } + +                     top->u.integer = (top->u.integer * 10) + (b - '0');                       continue;                    } + +                  num_fraction = (num_fraction * 10) + (b - '0'); +                  continue;                 } -               else if (b == '+' || b == '-') + +               if (b == '+' || b == '-')                 { -                  if (flags & flag_exponent && !(flags & flag_got_exponent_sign)) +                  if ( (flags & flag_num_e) && !(flags & flag_num_e_got_sign))                    { -                     flags |= flag_got_exponent_sign; +                     flags |= flag_num_e_got_sign; + +                     if (b == '-') +                        flags |= flag_num_e_negative; +                       continue;                    }                 }                 else if (b == '.' && top->type == json_integer)                 { +                  if (!num_digits) +                  {  sprintf (error, "%d:%d: Expected digit before `.`", cur_line, e_off); +                     goto e_failed; +                  } +                    top->type = json_double; +                  top->u.dbl = (double) top->u.integer; + +                  num_digits = 0;                    continue;                 } +               if (! (flags & flag_num_e)) +               { +                  if (top->type == json_double) +                  { +                     if (!num_digits) +                     {  sprintf (error, "%d:%d: Expected digit after `.`", cur_line, e_off); +                        goto e_failed; +                     } + +                     top->u.dbl += ((double) num_fraction) / (pow (10, (double) num_digits)); +                  } + +                  if (b == 'e' || b == 'E') +                  { +                     flags |= flag_num_e; + +                     if (top->type == json_integer) +                     { +                        top->type = json_double; +                        top->u.dbl = (double) top->u.integer; +                     } + +                     num_digits = 0; +                     flags &= ~ flag_num_zero; + +                     continue; +                  } +               } +               else +               { +                  if (!num_digits) +                  {  sprintf (error, "%d:%d: Expected digit after `e`", cur_line, e_off); +                     goto e_failed; +                  } + +                  top->u.dbl *= pow (10, (double) (flags & flag_num_e_negative ? - num_e : num_e)); +               } + +               if (flags & flag_num_negative) +               { +                  if (top->type == json_integer) +                     top->u.integer = - top->u.integer; +                  else +                     top->u.dbl = - top->u.dbl; +               } +                 flags |= flag_next | flag_reproc;                 break; @@ -672,25 +877,23 @@ e_failed:     while (alloc)     {        top = alloc->_reserved.next_alloc; -      free (alloc); +      state.settings.mem_free (alloc, state.settings.user_data);        alloc = top;     }     if (!state.first_pass) -      json_value_free (root); +      json_value_free_ex (&state.settings, root);     return 0;  } -json_value * json_parse (const json_char * json) +json_value * json_parse (const json_char * json, size_t length)  { -   json_settings settings; -   memset (&settings, 0, sizeof (json_settings)); - -   return json_parse_ex (&settings, json, 0); +   json_settings settings = { 0 }; +   return json_parse_ex (&settings, json, length, 0);  } -void json_value_free (json_value * value) +void json_value_free_ex (json_settings * settings, json_value * value)  {     json_value * cur_value; @@ -707,7 +910,7 @@ void json_value_free (json_value * value)              if (!value->u.array.length)              { -               free (value->u.array.values); +               settings->mem_free (value->u.array.values, settings->user_data);                 break;              } @@ -718,7 +921,7 @@ void json_value_free (json_value * value)              if (!value->u.object.length)              { -               free (value->u.object.values); +               settings->mem_free (value->u.object.values, settings->user_data);                 break;              } @@ -727,7 +930,7 @@ void json_value_free (json_value * value)           case json_string: -            free (value->u.string.ptr); +            settings->mem_free (value->u.string.ptr, settings->user_data);              break;           default: @@ -736,8 +939,14 @@ void json_value_free (json_value * value)        cur_value = value;        value = value->parent; -      free (cur_value); +      settings->mem_free (cur_value, settings->user_data);     }  } +void json_value_free (json_value * value) +{ +   json_settings settings = { 0 }; +   settings.mem_free = default_free; +   json_value_free_ex (&settings, value); +} @@ -1,7 +1,7 @@ -/* vim: set et ts=3 sw=3 ft=c: +/* vim: set et ts=3 sw=3 sts=3 ft=c:   * - * Copyright (C) 2012 James McLaughlin et al.  All rights reserved. + * Copyright (C) 2012, 2013, 2014 James McLaughlin et al.  All rights reserved.   * https://github.com/udp/json-parser   *   * Redistribution and use in source and binary forms, with or without @@ -35,6 +35,17 @@     #define json_char char  #endif +#ifndef json_int_t +   #ifndef _MSC_VER +      #include <inttypes.h> +      #define json_int_t int64_t +   #else +      #define json_int_t __int64 +   #endif +#endif + +#include <stdlib.h> +  #ifdef __cplusplus     #include <string.h> @@ -49,9 +60,17 @@ typedef struct     unsigned long max_memory;     int settings; +   /* Custom allocator support (leave null to use malloc/free) +    */ + +   void * (* mem_alloc) (size_t, int zero, void * user_data); +   void (* mem_free) (void *, void * user_data); + +   void * user_data;  /* will be passed to mem_alloc and mem_free */ +  } json_settings; -#define json_relaxed_commas 1 +#define json_enable_comments  0x01  typedef enum  { @@ -77,7 +96,7 @@ typedef struct _json_value     union     {        int boolean; -      long long integer; +      json_int_t integer;        double dbl;        struct @@ -94,10 +113,21 @@ typedef struct _json_value           struct           {              json_char * name; +            unsigned int name_length; +              struct _json_value * value;           } * values; +         #if defined(__cplusplus) && __cplusplus >= 201103L +         decltype(values) begin () const +         {  return values; +         } +         decltype(values) end () const +         {  return values + length; +         } +         #endif +        } object;        struct @@ -105,6 +135,15 @@ typedef struct _json_value           unsigned int length;           struct _json_value ** values; +         #if defined(__cplusplus) && __cplusplus >= 201103L +         decltype(values) begin () const +         {  return values; +         } +         decltype(values) end () const +         {  return values + length; +         } +         #endif +        } array;     } u; @@ -162,27 +201,67 @@ typedef struct _json_value              };           } -         inline operator long () const -         {  return u.integer; +         inline operator json_int_t () const +         {   +            switch (type) +            { +               case json_integer: +                  return u.integer; + +               case json_double: +                  return (json_int_t) u.dbl; + +               default: +                  return 0; +            };           }           inline operator bool () const -         {  return u.boolean != 0; +         {   +            if (type != json_boolean) +               return false; + +            return u.boolean != 0; +         } + +         inline operator double () const +         {   +            switch (type) +            { +               case json_integer: +                  return (double) u.integer; + +               case json_double: +                  return u.dbl; + +               default: +                  return 0; +            };           }     #endif  } json_value; -json_value * json_parse -   (const json_char * json); +json_value * json_parse (const json_char * json, +                         size_t length); -json_value * json_parse_ex -   (json_settings * settings, const json_char * json, char * error); +#define json_error_max 128 +json_value * json_parse_ex (json_settings * settings, +                            const json_char * json, +                            size_t length, +                            char * error);  void json_value_free (json_value *); +/* Not usually necessary, unless you used a custom mem_alloc and now want to + * use a custom mem_free. + */ +void json_value_free_ex (json_settings * settings, +                         json_value *); + +  #ifdef __cplusplus     } /* extern "C" */  #endif diff --git a/lib/oauth2.c b/lib/oauth2.c index 7ebe4e50..b66197ba 100644 --- a/lib/oauth2.c +++ b/lib/oauth2.c @@ -153,7 +153,7 @@ static void oauth2_access_token_done( struct http_request *req )  	if( content_type && ( strstr( content_type, "application/json" ) ||  	                      strstr( content_type, "text/javascript" ) ) )  	{ -		json_value *js = json_parse( req->reply_body ); +		json_value *js = json_parse( req->reply_body, req->body_size );  		if( js && js->type == json_object )  		{  			JSON_O_FOREACH( js, k, v ) | 
