Ignore:
Timestamp:
May 15, 2009, 1:16:34 PM (13 years ago)
Author:
charles
Message:

(trunk libT) update our copy of Jean's JSON parser

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/JSON_parser.c

    r8372 r8409  
    2828
    2929/*
    30     Callbacks, comments, Unicode handling by Jean Gressmann (jean@0x42.de), 2007-2008.
     30    Callbacks, comments, Unicode handling by Jean Gressmann (jean@0x42.de), 2007-2009.
    3131   
    3232    For the added features the license above applies also.
    3333   
    3434    Changelog:
    35         2008/10/14
    36             - Renamed states.IN to states.IT to avoid name clash which IN macro
    37               defined in windef.h (alexey.pelykh@gmail.com)
     35        2009-05-14
     36            Fixed float parsing bug related to a locale being set that didn't
     37            use '.' as decimal point character (charles@transmissionbt.com).
    3838           
    39         2008/07/19
    40             - Removed some duplicate code & debugging variable (Charles.Kerr@noaa.gov)
    41        
    42         2008/05/28
    43             - Made JSON_value structure ansi C compliant. This bug was report by
    44               trisk@acm.jhu.edu
    45        
    46         2008/05/20
    47             - Fixed bug reported by Charles.Kerr@noaa.gov where the switching
    48               from static to dynamic parse buffer did not copy the static parse
    49               buffer's content.
     39        2008-10-14
     40            Renamed states.IN to states.IT to avoid name clash which IN macro
     41            defined in windef.h (alexey.pelykh@gmail.com)
     42           
     43        2008-07-19
     44            Removed some duplicate code & debugging variable (charles@transmissionbt.com)
     45       
     46        2008-05-28
     47            Made JSON_value structure ansi C compliant. This bug was report by
     48            trisk@acm.jhu.edu
     49       
     50        2008-05-20
     51            Fixed bug reported by charles@transmissionbt.com where the switching
     52            from static to dynamic parse buffer did not copy the static parse
     53            buffer's content.
    5054*/
    5155
     
    5559#include <ctype.h>
    5660#include <float.h>
    57 #include <locale.h>
    5861#include <stddef.h>
    5962#include <stdio.h>
    6063#include <stdlib.h>
    6164#include <string.h>
     65#include <locale.h>
    6266
    6367#include "JSON_parser.h"
     
    6569
    6670#ifdef _MSC_VER
    67  #if _MSC_VER >= 1400 /* Visual Studio 2005 and up */
    68   #pragma warning(disable:4996) /* unsecure sscanf */
    69  #endif
     71#   if _MSC_VER >= 1400 /* Visual Studio 2005 and up */
     72#      pragma warning(disable:4996) // unsecure sscanf
     73#   endif
    7074#endif
    7175
     
    8589
    8690
    87 typedef struct JSON_parser_struct {
     91struct JSON_parser_struct {
    8892    JSON_parser_callback callback;
    8993    void* ctx;
     
    9498    signed char* stack;
    9599    long stack_capacity;
    96     signed char static_stack[JSON_PARSER_STACK_SIZE];
     100    char decimal_point;
    97101    char* parse_buffer;
    98102    size_t parse_buffer_capacity;
    99103    size_t parse_buffer_count;
    100104    size_t comment_begin_offset;
     105    signed char static_stack[JSON_PARSER_STACK_SIZE];
    101106    char static_parse_buffer[JSON_PARSER_PARSE_BUFFER_SIZE];
    102 } * JSON_parser;
     107};
    103108
    104109#define COUNTOF(x) (sizeof(x)/sizeof(x[0]))
    105110
    106111/*
    107     Characters are mapped into these 31 character classes. This allows for
     112    Characters are mapped into these character classes. This allows for
    108113    a significant reduction in the size of the state transition table.
    109114*/
     
    433438    jc->allow_comments = config->allow_comments != 0;
    434439    jc->handle_floats_manually = config->handle_floats_manually != 0;
     440   
     441    /* set up decimal point */
     442    jc->decimal_point = *localeconv()->decimal_point;
     443   
    435444    return jc;
    436445}
     
    456465    } while (0)
    457466
     467#define assert_is_non_container_type(jc) \
     468    assert( \
     469        jc->type == JSON_T_NULL || \
     470        jc->type == JSON_T_FALSE || \
     471        jc->type == JSON_T_TRUE || \
     472        jc->type == JSON_T_FLOAT || \
     473        jc->type == JSON_T_INTEGER || \
     474        jc->type == JSON_T_STRING)
     475   
    458476
    459477static int parse_parse_buffer(JSON_parser jc)
     
    463481       
    464482        if (jc->type != JSON_T_NONE) {
    465             assert(
    466                 jc->type == JSON_T_NULL ||
    467                 jc->type == JSON_T_FALSE ||
    468                 jc->type == JSON_T_TRUE ||
    469                 jc->type == JSON_T_FLOAT ||
    470                 jc->type == JSON_T_INTEGER ||
    471                 jc->type == JSON_T_STRING);
     483            assert_is_non_container_type(jc);
    472484       
    473485            switch(jc->type) {
     
    478490                        value.vu.str.length = jc->parse_buffer_count;
    479491                    } else {
    480                         /* the json spec requires a '.' decimal point regardless of locale */
    481                         char numeric[128];
    482                         snprintf(numeric, sizeof(numeric), "%s", setlocale(LC_NUMERIC, NULL));
    483                         setlocale(LC_NUMERIC, "POSIX" );
    484                         sscanf(jc->parse_buffer, "%Lf", &value.vu.float_value);
    485                         value.vu.float_value = strtod(jc->parse_buffer, NULL);
    486                         setlocale(LC_NUMERIC, numeric);
     492                        /*sscanf(jc->parse_buffer, "%Lf", &value.vu.float_value);*/
     493                       
     494                        /* not checking with end pointer b/c there may be trailing ws */
     495                        value.vu.float_value = strtold(jc->parse_buffer, NULL);
    487496                    }
    488497                    break;
     
    577586}
    578587
     588static int add_escaped_char_to_parse_buffer(JSON_parser jc, int next_char)
     589{
     590    jc->escaped = 0;
     591    /* remove the backslash */
     592    parse_buffer_pop_back_char(jc);
     593    switch(next_char) {
     594        case 'b':
     595            parse_buffer_push_back_char(jc, '\b');
     596            break;
     597        case 'f':
     598            parse_buffer_push_back_char(jc, '\f');
     599            break;
     600        case 'n':
     601            parse_buffer_push_back_char(jc, '\n');
     602            break;
     603        case 'r':
     604            parse_buffer_push_back_char(jc, '\r');
     605            break;
     606        case 't':
     607            parse_buffer_push_back_char(jc, '\t');
     608            break;
     609        case '"':
     610            parse_buffer_push_back_char(jc, '"');
     611            break;
     612        case '\\':
     613            parse_buffer_push_back_char(jc, '\\');
     614            break;
     615        case '/':
     616            parse_buffer_push_back_char(jc, '/');
     617            break;
     618        case 'u':
     619            parse_buffer_push_back_char(jc, '\\');
     620            parse_buffer_push_back_char(jc, 'u');
     621            break;
     622        default:
     623            return false;
     624    }
     625
     626    return true;
     627}
     628
     629#define add_char_to_parse_buffer(jc, next_char, next_class) \
     630    do { \
     631        if (jc->escaped) { \
     632            if (!add_escaped_char_to_parse_buffer(jc, next_char)) \
     633                return false; \
     634        } else if (!jc->comment) { \
     635            if ((jc->type != JSON_T_NONE) | !((next_class == C_SPACE) | (next_class == C_WHITE)) /* non-white-space */) { \
     636                parse_buffer_push_back_char(jc, (char)next_char); \
     637            } \
     638        } \
     639    } while (0)
     640   
     641
     642#define assert_type_isnt_string_null_or_bool(jc) \
     643    assert(jc->type != JSON_T_FALSE); \
     644    assert(jc->type != JSON_T_TRUE); \
     645    assert(jc->type != JSON_T_NULL); \
     646    assert(jc->type != JSON_T_STRING)
     647
    579648
    580649int
     
    604673    }
    605674   
    606     if (jc->escaped) {
    607         jc->escaped = 0;
    608         /* remove the backslash */
    609         parse_buffer_pop_back_char(jc);
    610         switch(next_char) {
    611         case 'b':
    612             parse_buffer_push_back_char(jc, '\b');
    613             break;
    614         case 'f':
    615             parse_buffer_push_back_char(jc, '\f');
    616             break;
    617         case 'n':
    618             parse_buffer_push_back_char(jc, '\n');
    619             break;
    620         case 'r':
    621             parse_buffer_push_back_char(jc, '\r');
    622             break;
    623         case 't':
    624             parse_buffer_push_back_char(jc, '\t');
    625             break;
    626         case '"':
    627             parse_buffer_push_back_char(jc, '"');
    628             break;
    629         case '\\':
    630             parse_buffer_push_back_char(jc, '\\');
    631             break;
    632         case '/':
    633             parse_buffer_push_back_char(jc, '/');
    634             break;
    635         case 'u':
    636             parse_buffer_push_back_char(jc, '\\');
    637             parse_buffer_push_back_char(jc, 'u');
    638             break;
    639         default:
    640             return false;
    641         }
    642     } else if (!jc->comment) {
    643         if (jc->type != JSON_T_NONE || !(next_class == C_SPACE || next_class == C_WHITE) /* non-white-space */) {
    644             parse_buffer_push_back_char(jc, (char)next_char);
    645         }
    646     }
    647    
    648    
     675    add_char_to_parse_buffer(jc, next_char, next_class);
    649676   
    650677/*
     
    697724/* floating point number detected by exponent*/
    698725        case DE:
    699             assert(jc->type != JSON_T_FALSE);
    700             assert(jc->type != JSON_T_TRUE);
    701             assert(jc->type != JSON_T_NULL);
    702             assert(jc->type != JSON_T_STRING);
     726            assert_type_isnt_string_null_or_bool(jc);
    703727            jc->type = JSON_T_FLOAT;
    704728            jc->state = E1;
     
    707731/* floating point number detected by fraction */
    708732        case DF:
    709             assert(jc->type != JSON_T_FALSE);
    710             assert(jc->type != JSON_T_TRUE);
    711             assert(jc->type != JSON_T_NULL);
    712             assert(jc->type != JSON_T_STRING);
     733            assert_type_isnt_string_null_or_bool(jc);
     734            if (!jc->handle_floats_manually) {
     735/*
     736    Some versions of strtod (which underlies sscanf) don't support converting
     737    C-locale formated floating point values.
     738*/           
     739                assert(jc->parse_buffer[jc->parse_buffer_count-1] == '.');
     740                jc->parse_buffer[jc->parse_buffer_count-1] = jc->decimal_point;
     741            }           
    713742            jc->type = JSON_T_FLOAT;
    714743            jc->state = FX;
Note: See TracChangeset for help on using the changeset viewer.