Changeset 8409
- Timestamp:
- May 15, 2009, 1:16:34 PM (14 years ago)
- Location:
- trunk/libtransmission
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/libtransmission/JSON_parser.c
r8372 r8409 28 28 29 29 /* 30 Callbacks, comments, Unicode handling by Jean Gressmann (jean@0x42.de), 2007-200 8.30 Callbacks, comments, Unicode handling by Jean Gressmann (jean@0x42.de), 2007-2009. 31 31 32 32 For the added features the license above applies also. 33 33 34 34 Changelog: 35 200 8/10/1436 - Renamed states.IN to states.IT to avoid name clash which IN macro37 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). 38 38 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. 50 54 */ 51 55 … … 55 59 #include <ctype.h> 56 60 #include <float.h> 57 #include <locale.h>58 61 #include <stddef.h> 59 62 #include <stdio.h> 60 63 #include <stdlib.h> 61 64 #include <string.h> 65 #include <locale.h> 62 66 63 67 #include "JSON_parser.h" … … 65 69 66 70 #ifdef _MSC_VER 67 #if _MSC_VER >= 1400 /* Visual Studio 2005 and up */68 #pragma warning(disable:4996) /* unsecure sscanf */ 69 #endif71 # if _MSC_VER >= 1400 /* Visual Studio 2005 and up */ 72 # pragma warning(disable:4996) // unsecure sscanf 73 # endif 70 74 #endif 71 75 … … 85 89 86 90 87 typedefstruct JSON_parser_struct {91 struct JSON_parser_struct { 88 92 JSON_parser_callback callback; 89 93 void* ctx; … … 94 98 signed char* stack; 95 99 long stack_capacity; 96 signed char static_stack[JSON_PARSER_STACK_SIZE];100 char decimal_point; 97 101 char* parse_buffer; 98 102 size_t parse_buffer_capacity; 99 103 size_t parse_buffer_count; 100 104 size_t comment_begin_offset; 105 signed char static_stack[JSON_PARSER_STACK_SIZE]; 101 106 char static_parse_buffer[JSON_PARSER_PARSE_BUFFER_SIZE]; 102 } * JSON_parser;107 }; 103 108 104 109 #define COUNTOF(x) (sizeof(x)/sizeof(x[0])) 105 110 106 111 /* 107 Characters are mapped into these 31character classes. This allows for112 Characters are mapped into these character classes. This allows for 108 113 a significant reduction in the size of the state transition table. 109 114 */ … … 433 438 jc->allow_comments = config->allow_comments != 0; 434 439 jc->handle_floats_manually = config->handle_floats_manually != 0; 440 441 /* set up decimal point */ 442 jc->decimal_point = *localeconv()->decimal_point; 443 435 444 return jc; 436 445 } … … 456 465 } while (0) 457 466 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 458 476 459 477 static int parse_parse_buffer(JSON_parser jc) … … 463 481 464 482 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); 472 484 473 485 switch(jc->type) { … … 478 490 value.vu.str.length = jc->parse_buffer_count; 479 491 } 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); 487 496 } 488 497 break; … … 577 586 } 578 587 588 static 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 579 648 580 649 int … … 604 673 } 605 674 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); 649 676 650 677 /* … … 697 724 /* floating point number detected by exponent*/ 698 725 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); 703 727 jc->type = JSON_T_FLOAT; 704 728 jc->state = E1; … … 707 731 /* floating point number detected by fraction */ 708 732 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 } 713 742 jc->type = JSON_T_FLOAT; 714 743 jc->state = FX; -
trunk/libtransmission/JSON_parser.h
r7197 r8409 1 #ifndef __TRANSMISSION__2 #error only libtransmission should #include this header.3 #endif4 5 1 #ifndef JSON_PARSER_H 6 2 #define JSON_PARSER_H … … 12 8 13 9 /* Windows DLL stuff */ 14 /* 15 #ifdef _WIN32 16 # ifdef JSON_PARSER_DLL_EXPORTS 17 # define JSON_PARSER_DLL_API __declspec(dllexport) 18 # else 19 # define JSON_PARSER_DLL_API __declspec(dllimport) 20 # endif 21 #else 22 */ 23 #define JSON_PARSER_DLL_API 24 /* 25 #endif 26 */ 10 #ifdef _WIN32 11 # ifdef JSON_PARSER_DLL_EXPORTS 12 # define JSON_PARSER_DLL_API __declspec(dllexport) 13 # else 14 # define JSON_PARSER_DLL_API __declspec(dllimport) 15 # endif 16 #else 17 # define JSON_PARSER_DLL_API 18 #endif 27 19 28 #include <inttypes.h> 29 typedef int64_t JSON_int_t; 30 #define JSON_PARSER_INTEGER_SSCANF_TOKEN "%" PRId64 31 #define JSON_PARSER_INTEGER_SPRINTF_TOKEN "%" PRId64 20 /* Determine the integer type use to parse non-floating point numbers */ 21 #if __STDC_VERSION__ >= 199901L || HAVE_LONG_LONG == 1 22 typedef long long JSON_int_t; 23 #define JSON_PARSER_INTEGER_SSCANF_TOKEN "%lld" 24 #define JSON_PARSER_INTEGER_SPRINTF_TOKEN "%lld" 25 #else 26 typedef long JSON_int_t; 27 #define JSON_PARSER_INTEGER_SSCANF_TOKEN "%ld" 28 #define JSON_PARSER_INTEGER_SPRINTF_TOKEN "%ld" 29 #endif 32 30 33 31 34 32 #ifdef __cplusplus 35 33 extern "C" { 36 #endif 34 #endif 37 35 38 typedef enum 36 typedef enum 39 37 { 40 38 JSON_T_NONE = 0, … … 53 51 } JSON_type; 54 52 55 typedef struct JSON_value_struct 56 { 57 union 58 { 59 JSON_int_t integer_value; 60 53 typedef struct JSON_value_struct { 54 union { 55 JSON_int_t integer_value; 56 61 57 long double float_value; 62 63 struct 64 { 58 59 struct { 65 60 const char* value; 66 size_t 61 size_t length; 67 62 } str; 68 63 } vu; 69 64 } JSON_value; 70 65 71 /*! \brief JSON parser callback 66 typedef struct JSON_parser_struct* JSON_parser; 67 68 /*! \brief JSON parser callback 72 69 73 70 \param ctx The pointer passed to new_JSON_parser. 74 \param type An element of JSON_type but not JSON_T_NONE. 75 \param value A representation of the parsed value. This parameter is NULL 76 for 77 JSON_T_ARRAY_BEGIN, JSON_T_ARRAY_END, JSON_T_OBJECT_BEGIN, 78 JSON_T_OBJECT_END, 79 JSON_T_NULL, JSON_T_TRUE, and SON_T_FALSE. String values are always 80 returned 71 \param type An element of JSON_type but not JSON_T_NONE. 72 \param value A representation of the parsed value. This parameter is NULL for 73 JSON_T_ARRAY_BEGIN, JSON_T_ARRAY_END, JSON_T_OBJECT_BEGIN, JSON_T_OBJECT_END, 74 JSON_T_NULL, JSON_T_TRUE, and SON_T_FALSE. String values are always returned 81 75 as zero-terminated C strings. 82 76 83 77 \return Non-zero if parsing should continue, else zero. 84 */ 85 typedef int ( *JSON_parser_callback )( void* ctx, int type, 86 const struct JSON_value_struct* 87 value ); 78 */ 79 typedef int (*JSON_parser_callback)(void* ctx, int type, const struct JSON_value_struct* value); 88 80 89 81 90 /*! \brief The structure used to configure a JSON parser object 91 92 \param depth If negative, the parser can parse arbitrary levels of JSON, 93 otherwise 82 /*! \brief The structure used to configure a JSON parser object 83 84 \param depth If negative, the parser can parse arbitrary levels of JSON, otherwise 94 85 the depth is the limit 95 \param Pointer to a callback. This parameter may be NULL. In this case the 96 input is merely checked for validity. 86 \param Pointer to a callback. This parameter may be NULL. In this case the input is merely checked for validity. 97 87 \param Callback context. This parameter may be NULL. 98 \param depth. Specifies the levels of nested JSON to allow. Negative numbers 99 yield unlimited nesting. 88 \param depth. Specifies the levels of nested JSON to allow. Negative numbers yield unlimited nesting. 100 89 \param allowComments. To allow C style comments in JSON, set to non-zero. 101 \param handleFloatsManually. To decode floating point numbers manually set 102 this parameter to non-zero. 103 90 \param handleFloatsManually. To decode floating point numbers manually set this parameter to non-zero. 91 104 92 \return The parser object. 105 */ 106 typedef struct JSON_config_struct 107 { 108 JSON_parser_callback callback; 109 void* callback_ctx; 110 int depth; 111 int allow_comments; 112 int handle_floats_manually; 93 */ 94 typedef struct { 95 JSON_parser_callback callback; 96 void* callback_ctx; 97 int depth; 98 int allow_comments; 99 int handle_floats_manually; 113 100 } JSON_config; 114 101 115 102 116 /*! \brief Initializes the JSON parser configuration structure to default 117 values. 103 /*! \brief Initializes the JSON parser configuration structure to default values. 118 104 119 105 The default configuration is 120 - 127 levels of nested JSON (depends on JSON_PARSER_STACK_SIZE, see 121 json_parser.c) 106 - 127 levels of nested JSON (depends on JSON_PARSER_STACK_SIZE, see json_parser.c) 122 107 - no parsing, just checking for JSON syntax 123 108 - no comments 124 109 125 110 \param config. Used to configure the parser. 126 */ 127 JSON_PARSER_DLL_API void init_JSON_config( 128 JSON_config* config ); 111 */ 112 JSON_PARSER_DLL_API void init_JSON_config(JSON_config* config); 129 113 130 /*! \brief Create a JSON parser object 131 132 \param config. Used to configure the parser. Set to NULL to use the default 133 configuration. 114 /*! \brief Create a JSON parser object 115 116 \param config. Used to configure the parser. Set to NULL to use the default configuration. 134 117 See init_JSON_config 135 118 136 119 \return The parser object. 137 */ 138 JSON_PARSER_DLL_API extern struct JSON_parser_struct* new_JSON_parser( 139 JSON_config* config ); 120 */ 121 JSON_PARSER_DLL_API extern JSON_parser new_JSON_parser(JSON_config* config); 140 122 141 123 /*! \brief Destroy a previously created JSON parser object. */ 142 JSON_PARSER_DLL_API extern void delete_JSON_parser( 143 struct JSON_parser_struct* jc ); 124 JSON_PARSER_DLL_API extern void delete_JSON_parser(JSON_parser jc); 144 125 145 126 /*! \brief Parse a character. 146 127 147 \return Non-zero, if all characters passed to this function are part of are 148 valid JSON. 149 */ 150 JSON_PARSER_DLL_API extern int JSON_parser_char( 151 struct JSON_parser_struct* jc, 152 int 153 next_char ); 128 \return Non-zero, if all characters passed to this function are part of are valid JSON. 129 */ 130 JSON_PARSER_DLL_API extern int JSON_parser_char(JSON_parser jc, int next_char); 154 131 155 132 /*! \brief Finalize parsing. 156 133 157 134 Call this method once after all input characters have been consumed. 135 136 \return Non-zero, if all parsed characters are valid JSON, zero otherwise. 137 */ 138 JSON_PARSER_DLL_API extern int JSON_parser_done(JSON_parser jc); 158 139 159 \return Non-zero, if all parsed characters are valid JSON, zero otherwise. 160 */ 161 JSON_PARSER_DLL_API extern int JSON_parser_done( 162 struct JSON_parser_struct* jc ); 163 164 /*! \brief Determine if a given string is valid JSON white space 140 /*! \brief Determine if a given string is valid JSON white space 165 141 166 142 \return Non-zero if the string is valid, zero otherwise. 167 */ 168 JSON_PARSER_DLL_API extern int 169 JSON_parser_is_legal_white_space_string( 170 const char* s ); 143 */ 144 JSON_PARSER_DLL_API extern int JSON_parser_is_legal_white_space_string(const char* s); 171 145 172 146 173 147 #ifdef __cplusplus 174 148 } 175 #endif 176 149 #endif 150 177 151 178 152 #endif /* JSON_PARSER_H */ -
trunk/libtransmission/json.c
r8159 r8409 145 145 const unsigned char * buf = vbuf; 146 146 const void * bufend = buf + len; 147 struct JSON_config_structconfig;147 JSON_config config; 148 148 struct JSON_parser_struct * checker; 149 149 struct json_benc_data data;
Note: See TracChangeset
for help on using the changeset viewer.