json 1.8.3 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of json might be problematic. Click here for more details.

Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +3 -10
  4. data/{CHANGES → CHANGES.md} +183 -90
  5. data/Gemfile +11 -5
  6. data/{README-json-jruby.markdown → README-json-jruby.md} +0 -0
  7. data/{README.rdoc → README.md} +147 -113
  8. data/Rakefile +32 -36
  9. data/VERSION +1 -1
  10. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  11. data/ext/json/ext/generator/generator.c +46 -61
  12. data/ext/json/ext/generator/generator.h +7 -2
  13. data/ext/json/ext/parser/extconf.rb +3 -0
  14. data/ext/json/ext/parser/parser.c +353 -460
  15. data/ext/json/ext/parser/parser.h +4 -5
  16. data/ext/json/ext/parser/parser.rl +111 -181
  17. data/ext/json/extconf.rb +0 -1
  18. data/java/src/json/ext/ByteListTranscoder.java +1 -2
  19. data/java/src/json/ext/Generator.java +11 -12
  20. data/java/src/json/ext/GeneratorMethods.java +1 -2
  21. data/java/src/json/ext/GeneratorService.java +1 -2
  22. data/java/src/json/ext/GeneratorState.java +3 -56
  23. data/java/src/json/ext/OptionsReader.java +2 -3
  24. data/java/src/json/ext/Parser.java +135 -418
  25. data/java/src/json/ext/Parser.rl +48 -124
  26. data/java/src/json/ext/ParserService.java +1 -2
  27. data/java/src/json/ext/RuntimeInfo.java +1 -6
  28. data/java/src/json/ext/StringDecoder.java +1 -2
  29. data/java/src/json/ext/StringEncoder.java +5 -0
  30. data/java/src/json/ext/Utils.java +1 -2
  31. data/json-java.gemspec +15 -0
  32. data/json.gemspec +0 -0
  33. data/json_pure.gemspec +24 -26
  34. data/lib/json/add/bigdecimal.rb +1 -0
  35. data/lib/json/add/complex.rb +2 -1
  36. data/lib/json/add/core.rb +1 -0
  37. data/lib/json/add/date.rb +1 -1
  38. data/lib/json/add/date_time.rb +1 -1
  39. data/lib/json/add/exception.rb +1 -1
  40. data/lib/json/add/ostruct.rb +2 -2
  41. data/lib/json/add/range.rb +1 -1
  42. data/lib/json/add/rational.rb +1 -0
  43. data/lib/json/add/regexp.rb +1 -1
  44. data/lib/json/add/struct.rb +1 -1
  45. data/lib/json/add/symbol.rb +1 -1
  46. data/lib/json/add/time.rb +1 -1
  47. data/lib/json/common.rb +24 -52
  48. data/lib/json/ext.rb +0 -6
  49. data/lib/json/generic_object.rb +5 -4
  50. data/lib/json/pure/generator.rb +61 -125
  51. data/lib/json/pure/parser.rb +33 -81
  52. data/lib/json/pure.rb +2 -8
  53. data/lib/json/version.rb +2 -1
  54. data/lib/json.rb +1 -0
  55. data/references/rfc7159.txt +899 -0
  56. data/tests/fixtures/obsolete_fail1.json +1 -0
  57. data/tests/{test_json_addition.rb → json_addition_test.rb} +22 -25
  58. data/tests/json_common_interface_test.rb +126 -0
  59. data/tests/json_encoding_test.rb +107 -0
  60. data/tests/json_ext_parser_test.rb +15 -0
  61. data/tests/{test_json_fixtures.rb → json_fixtures_test.rb} +5 -8
  62. data/tests/{test_json_generate.rb → json_generator_test.rb} +79 -39
  63. data/tests/{test_json_generic_object.rb → json_generic_object_test.rb} +15 -8
  64. data/tests/json_parser_test.rb +471 -0
  65. data/tests/json_string_matching_test.rb +38 -0
  66. data/tests/{setup_variant.rb → test_helper.rb} +10 -0
  67. data/tools/diff.sh +18 -0
  68. data/tools/fuzz.rb +1 -9
  69. metadata +28 -43
  70. data/COPYING +0 -58
  71. data/COPYING-json-jruby +0 -57
  72. data/GPL +0 -340
  73. data/TODO +0 -1
  74. data/tests/fixtures/fail1.json +0 -1
  75. data/tests/test_json.rb +0 -553
  76. data/tests/test_json_encoding.rb +0 -65
  77. data/tests/test_json_string_matching.rb +0 -39
  78. data/tests/test_json_unicode.rb +0 -72
@@ -34,13 +34,12 @@ typedef struct JSON_ParserStruct {
34
34
  char *memo;
35
35
  VALUE create_id;
36
36
  int max_nesting;
37
- int current_nesting;
38
37
  int allow_nan;
39
38
  int parsing_name;
40
39
  int symbolize_names;
41
- int quirks_mode;
42
40
  VALUE object_class;
43
41
  VALUE array_class;
42
+ VALUE decimal_class;
44
43
  int create_additions;
45
44
  VALUE match_string;
46
45
  FBuffer *fbuffer;
@@ -58,11 +57,11 @@ typedef struct JSON_ParserStruct {
58
57
 
59
58
  static UTF32 unescape_unicode(const unsigned char *p);
60
59
  static int convert_UTF32_to_UTF8(char *buf, UTF32 ch);
61
- static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result);
62
- static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result);
60
+ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
61
+ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
63
62
  static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result);
64
63
  static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result);
65
- static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result);
64
+ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
66
65
  static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd);
67
66
  static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result);
68
67
  static VALUE convert_encoding(VALUE source);
@@ -1,6 +1,28 @@
1
1
  #include "../fbuffer/fbuffer.h"
2
2
  #include "parser.h"
3
3
 
4
+ #if defined HAVE_RUBY_ENCODING_H
5
+ # define EXC_ENCODING rb_utf8_encoding(),
6
+ # ifndef HAVE_RB_ENC_RAISE
7
+ static void
8
+ enc_raise(rb_encoding *enc, VALUE exc, const char *fmt, ...)
9
+ {
10
+ va_list args;
11
+ VALUE mesg;
12
+
13
+ va_start(args, fmt);
14
+ mesg = rb_enc_vsprintf(enc, fmt, args);
15
+ va_end(args);
16
+
17
+ rb_exc_raise(rb_exc_new3(exc, mesg));
18
+ }
19
+ # define rb_enc_raise enc_raise
20
+ # endif
21
+ #else
22
+ # define EXC_ENCODING /* nothing */
23
+ # define rb_enc_raise rb_raise
24
+ #endif
25
+
4
26
  /* unicode */
5
27
 
6
28
  static const char digit_values[256] = {
@@ -65,21 +87,14 @@ static int convert_UTF32_to_UTF8(char *buf, UTF32 ch)
65
87
  return len;
66
88
  }
67
89
 
68
- #ifdef HAVE_RUBY_ENCODING_H
69
- static VALUE CEncoding_ASCII_8BIT, CEncoding_UTF_8, CEncoding_UTF_16BE,
70
- CEncoding_UTF_16LE, CEncoding_UTF_32BE, CEncoding_UTF_32LE;
71
- static ID i_encoding, i_encode;
72
- #else
73
- static ID i_iconv;
74
- #endif
75
-
76
90
  static VALUE mJSON, mExt, cParser, eParserError, eNestingError;
77
91
  static VALUE CNaN, CInfinity, CMinusInfinity;
78
92
 
79
93
  static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
80
- i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_quirks_mode,
81
- i_object_class, i_array_class, i_key_p, i_deep_const_get, i_match,
82
- i_match_string, i_aset, i_aref, i_leftshift;
94
+ i_chr, i_max_nesting, i_allow_nan, i_symbolize_names,
95
+ i_object_class, i_array_class, i_decimal_class, i_key_p,
96
+ i_deep_const_get, i_match, i_match_string, i_aset, i_aref,
97
+ i_leftshift, i_new;
83
98
 
84
99
  %%{
85
100
  machine JSON_common;
@@ -117,7 +132,7 @@ static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
117
132
 
118
133
  action parse_value {
119
134
  VALUE v = Qnil;
120
- char *np = JSON_parse_value(json, fpc, pe, &v);
135
+ char *np = JSON_parse_value(json, fpc, pe, &v, current_nesting);
121
136
  if (np == NULL) {
122
137
  fhold; fbreak;
123
138
  } else {
@@ -150,14 +165,14 @@ static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
150
165
  ) @exit;
151
166
  }%%
152
167
 
153
- static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result)
168
+ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
154
169
  {
155
170
  int cs = EVIL;
156
171
  VALUE last_name = Qnil;
157
172
  VALUE object_class = json->object_class;
158
173
 
159
- if (json->max_nesting && json->current_nesting > json->max_nesting) {
160
- rb_raise(eNestingError, "nesting of %d is too deep", json->current_nesting);
174
+ if (json->max_nesting && current_nesting > json->max_nesting) {
175
+ rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
161
176
  }
162
177
 
163
178
  *result = NIL_P(object_class) ? rb_hash_new() : rb_class_new_instance(0, 0, object_class);
@@ -206,14 +221,14 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
206
221
  if (json->allow_nan) {
207
222
  *result = CNaN;
208
223
  } else {
209
- rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p - 2);
224
+ rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p - 2);
210
225
  }
211
226
  }
212
227
  action parse_infinity {
213
228
  if (json->allow_nan) {
214
229
  *result = CInfinity;
215
230
  } else {
216
- rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p - 8);
231
+ rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p - 8);
217
232
  }
218
233
  }
219
234
  action parse_string {
@@ -223,13 +238,13 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
223
238
 
224
239
  action parse_number {
225
240
  char *np;
226
- if(pe > fpc + 9 - json->quirks_mode && !strncmp(MinusInfinity, fpc, 9)) {
241
+ if(pe > fpc + 8 && !strncmp(MinusInfinity, fpc, 9)) {
227
242
  if (json->allow_nan) {
228
243
  *result = CMinusInfinity;
229
244
  fexec p + 10;
230
245
  fhold; fbreak;
231
246
  } else {
232
- rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p);
247
+ rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p);
233
248
  }
234
249
  }
235
250
  np = JSON_parse_float(json, fpc, pe, result);
@@ -241,23 +256,19 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
241
256
 
242
257
  action parse_array {
243
258
  char *np;
244
- json->current_nesting++;
245
- np = JSON_parse_array(json, fpc, pe, result);
246
- json->current_nesting--;
259
+ np = JSON_parse_array(json, fpc, pe, result, current_nesting + 1);
247
260
  if (np == NULL) { fhold; fbreak; } else fexec np;
248
261
  }
249
262
 
250
263
  action parse_object {
251
264
  char *np;
252
- json->current_nesting++;
253
- np = JSON_parse_object(json, fpc, pe, result);
254
- json->current_nesting--;
265
+ np = JSON_parse_object(json, fpc, pe, result, current_nesting + 1);
255
266
  if (np == NULL) { fhold; fbreak; } else fexec np;
256
267
  }
257
268
 
258
269
  action exit { fhold; fbreak; }
259
270
 
260
- main := (
271
+ main := ignore* (
261
272
  Vnull @parse_null |
262
273
  Vfalse @parse_false |
263
274
  Vtrue @parse_true |
@@ -267,10 +278,10 @@ main := (
267
278
  begin_string >parse_string |
268
279
  begin_array >parse_array |
269
280
  begin_object >parse_object
270
- ) %*exit;
281
+ ) ignore* %*exit;
271
282
  }%%
272
283
 
273
- static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result)
284
+ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
274
285
  {
275
286
  int cs = EVIL;
276
287
 
@@ -341,7 +352,13 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
341
352
  fbuffer_clear(json->fbuffer);
342
353
  fbuffer_append(json->fbuffer, json->memo, len);
343
354
  fbuffer_append_char(json->fbuffer, '\0');
344
- *result = rb_float_new(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
355
+ if (NIL_P(json->decimal_class)) {
356
+ *result = rb_float_new(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
357
+ } else {
358
+ VALUE text;
359
+ text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
360
+ *result = rb_funcall(json->decimal_class, i_new, 1, text);
361
+ }
345
362
  return p + 1;
346
363
  } else {
347
364
  return NULL;
@@ -357,7 +374,7 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
357
374
 
358
375
  action parse_value {
359
376
  VALUE v = Qnil;
360
- char *np = JSON_parse_value(json, fpc, pe, &v);
377
+ char *np = JSON_parse_value(json, fpc, pe, &v, current_nesting);
361
378
  if (np == NULL) {
362
379
  fhold; fbreak;
363
380
  } else {
@@ -380,13 +397,13 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
380
397
  end_array @exit;
381
398
  }%%
382
399
 
383
- static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result)
400
+ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
384
401
  {
385
402
  int cs = EVIL;
386
403
  VALUE array_class = json->array_class;
387
404
 
388
- if (json->max_nesting && json->current_nesting > json->max_nesting) {
389
- rb_raise(eNestingError, "nesting of %d is too deep", json->current_nesting);
405
+ if (json->max_nesting && current_nesting > json->max_nesting) {
406
+ rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
390
407
  }
391
408
  *result = NIL_P(array_class) ? rb_ary_new() : rb_class_new_instance(0, 0, array_class);
392
409
 
@@ -396,7 +413,7 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul
396
413
  if(cs >= JSON_array_first_final) {
397
414
  return p + 1;
398
415
  } else {
399
- rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p);
416
+ rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p);
400
417
  return NULL;
401
418
  }
402
419
  }
@@ -436,13 +453,21 @@ static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)
436
453
  break;
437
454
  case 'u':
438
455
  if (pe > stringEnd - 4) {
439
- return Qnil;
456
+ rb_enc_raise(
457
+ EXC_ENCODING eParserError,
458
+ "%u: incomplete unicode character escape sequence at '%s'", __LINE__, p
459
+ );
440
460
  } else {
441
461
  UTF32 ch = unescape_unicode((unsigned char *) ++pe);
442
462
  pe += 3;
443
463
  if (UNI_SUR_HIGH_START == (ch & 0xFC00)) {
444
464
  pe++;
445
- if (pe > stringEnd - 6) return Qnil;
465
+ if (pe > stringEnd - 6) {
466
+ rb_enc_raise(
467
+ EXC_ENCODING eParserError,
468
+ "%u: incomplete surrogate pair at '%s'", __LINE__, p
469
+ );
470
+ }
446
471
  if (pe[0] == '\\' && pe[1] == 'u') {
447
472
  UTF32 sur = unescape_unicode((unsigned char *) pe + 2);
448
473
  ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
@@ -528,6 +553,8 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
528
553
 
529
554
  if (json->symbolize_names && json->parsing_name) {
530
555
  *result = rb_str_intern(*result);
556
+ } else {
557
+ rb_str_resize(*result, RSTRING_LEN(*result));
531
558
  }
532
559
  if (cs >= JSON_string_first_final) {
533
560
  return p + 1;
@@ -550,41 +577,16 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
550
577
 
551
578
  static VALUE convert_encoding(VALUE source)
552
579
  {
553
- char *ptr = RSTRING_PTR(source);
554
- long len = RSTRING_LEN(source);
555
- if (len < 2) {
556
- rb_raise(eParserError, "A JSON text must at least contain two octets!");
557
- }
558
580
  #ifdef HAVE_RUBY_ENCODING_H
559
- {
560
- VALUE encoding = rb_funcall(source, i_encoding, 0);
561
- if (encoding == CEncoding_ASCII_8BIT) {
562
- if (len >= 4 && ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 0) {
563
- source = rb_funcall(source, i_encode, 2, CEncoding_UTF_8, CEncoding_UTF_32BE);
564
- } else if (len >= 4 && ptr[0] == 0 && ptr[2] == 0) {
565
- source = rb_funcall(source, i_encode, 2, CEncoding_UTF_8, CEncoding_UTF_16BE);
566
- } else if (len >= 4 && ptr[1] == 0 && ptr[2] == 0 && ptr[3] == 0) {
567
- source = rb_funcall(source, i_encode, 2, CEncoding_UTF_8, CEncoding_UTF_32LE);
568
- } else if (len >= 4 && ptr[1] == 0 && ptr[3] == 0) {
569
- source = rb_funcall(source, i_encode, 2, CEncoding_UTF_8, CEncoding_UTF_16LE);
570
- } else {
571
- source = rb_str_dup(source);
572
- FORCE_UTF8(source);
573
- }
574
- } else {
575
- source = rb_funcall(source, i_encode, 1, CEncoding_UTF_8);
576
- }
577
- }
578
- #else
579
- if (len >= 4 && ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 0) {
580
- source = rb_funcall(mJSON, i_iconv, 3, rb_str_new2("utf-8"), rb_str_new2("utf-32be"), source);
581
- } else if (len >= 4 && ptr[0] == 0 && ptr[2] == 0) {
582
- source = rb_funcall(mJSON, i_iconv, 3, rb_str_new2("utf-8"), rb_str_new2("utf-16be"), source);
583
- } else if (len >= 4 && ptr[1] == 0 && ptr[2] == 0 && ptr[3] == 0) {
584
- source = rb_funcall(mJSON, i_iconv, 3, rb_str_new2("utf-8"), rb_str_new2("utf-32le"), source);
585
- } else if (len >= 4 && ptr[1] == 0 && ptr[3] == 0) {
586
- source = rb_funcall(mJSON, i_iconv, 3, rb_str_new2("utf-8"), rb_str_new2("utf-16le"), source);
581
+ rb_encoding *enc = rb_enc_get(source);
582
+ if (enc == rb_ascii8bit_encoding()) {
583
+ if (OBJ_FROZEN(source)) {
584
+ source = rb_str_dup(source);
587
585
  }
586
+ FORCE_UTF8(source);
587
+ } else {
588
+ source = rb_str_conv_enc(source, rb_enc_get(source), rb_utf8_encoding());
589
+ }
588
590
  #endif
589
591
  return source;
590
592
  }
@@ -607,8 +609,9 @@ static VALUE convert_encoding(VALUE source)
607
609
  * defiance of RFC 4627 to be parsed by the Parser. This option defaults to
608
610
  * false.
609
611
  * * *symbolize_names*: If set to true, returns symbols for the names
610
- * (keys) in a JSON object. Otherwise strings are returned, which is also
611
- * the default.
612
+ * (keys) in a JSON object. Otherwise strings are returned, which is
613
+ * also the default. It's not possible to use this option in
614
+ * conjunction with the *create_additions* option.
612
615
  * * *create_additions*: If set to false, the Parser doesn't create
613
616
  * additions even if a matching class and create_id was found. This option
614
617
  * defaults to false.
@@ -623,12 +626,18 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
623
626
  if (json->Vsource) {
624
627
  rb_raise(rb_eTypeError, "already initialized instance");
625
628
  }
629
+ #ifdef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
630
+ rb_scan_args(argc, argv, "1:", &source, &opts);
631
+ #else
626
632
  rb_scan_args(argc, argv, "11", &source, &opts);
633
+ #endif
627
634
  if (!NIL_P(opts)) {
635
+ #ifndef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
628
636
  opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
629
637
  if (NIL_P(opts)) {
630
638
  rb_raise(rb_eArgError, "opts needs to be like a hash");
631
639
  } else {
640
+ #endif
632
641
  VALUE tmp = ID2SYM(i_max_nesting);
633
642
  if (option_given_p(opts, tmp)) {
634
643
  VALUE max_nesting = rb_hash_aref(opts, tmp);
@@ -653,19 +662,17 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
653
662
  } else {
654
663
  json->symbolize_names = 0;
655
664
  }
656
- tmp = ID2SYM(i_quirks_mode);
657
- if (option_given_p(opts, tmp)) {
658
- VALUE quirks_mode = rb_hash_aref(opts, tmp);
659
- json->quirks_mode = RTEST(quirks_mode) ? 1 : 0;
660
- } else {
661
- json->quirks_mode = 0;
662
- }
663
665
  tmp = ID2SYM(i_create_additions);
664
666
  if (option_given_p(opts, tmp)) {
665
667
  json->create_additions = RTEST(rb_hash_aref(opts, tmp));
666
668
  } else {
667
669
  json->create_additions = 0;
668
670
  }
671
+ if (json->symbolize_names && json->create_additions) {
672
+ rb_raise(rb_eArgError,
673
+ "options :symbolize_names and :create_additions cannot be "
674
+ " used in conjunction");
675
+ }
669
676
  tmp = ID2SYM(i_create_id);
670
677
  if (option_given_p(opts, tmp)) {
671
678
  json->create_id = rb_hash_aref(opts, tmp);
@@ -684,6 +691,12 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
684
691
  } else {
685
692
  json->array_class = Qnil;
686
693
  }
694
+ tmp = ID2SYM(i_decimal_class);
695
+ if (option_given_p(opts, tmp)) {
696
+ json->decimal_class = rb_hash_aref(opts, tmp);
697
+ } else {
698
+ json->decimal_class = Qnil;
699
+ }
687
700
  tmp = ID2SYM(i_match_string);
688
701
  if (option_given_p(opts, tmp)) {
689
702
  VALUE match_string = rb_hash_aref(opts, tmp);
@@ -691,7 +704,9 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
691
704
  } else {
692
705
  json->match_string = Qnil;
693
706
  }
707
+ #ifndef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
694
708
  }
709
+ #endif
695
710
  } else {
696
711
  json->max_nesting = 100;
697
712
  json->allow_nan = 0;
@@ -699,12 +714,9 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
699
714
  json->create_id = rb_funcall(mJSON, i_create_id, 0);
700
715
  json->object_class = Qnil;
701
716
  json->array_class = Qnil;
717
+ json->decimal_class = Qnil;
702
718
  }
703
- source = rb_convert_type(source, T_STRING, "String", "to_str");
704
- if (!json->quirks_mode) {
705
- source = convert_encoding(StringValue(source));
706
- }
707
- json->current_nesting = 0;
719
+ source = convert_encoding(StringValue(source));
708
720
  StringValue(source);
709
721
  json->len = RSTRING_LEN(source);
710
722
  json->source = RSTRING_PTR(source);;
@@ -719,56 +731,8 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
719
731
 
720
732
  include JSON_common;
721
733
 
722
- action parse_object {
723
- char *np;
724
- json->current_nesting = 1;
725
- np = JSON_parse_object(json, fpc, pe, &result);
726
- if (np == NULL) { fhold; fbreak; } else fexec np;
727
- }
728
-
729
- action parse_array {
730
- char *np;
731
- json->current_nesting = 1;
732
- np = JSON_parse_array(json, fpc, pe, &result);
733
- if (np == NULL) { fhold; fbreak; } else fexec np;
734
- }
735
-
736
- main := ignore* (
737
- begin_object >parse_object |
738
- begin_array >parse_array
739
- ) ignore*;
740
- }%%
741
-
742
- static VALUE cParser_parse_strict(VALUE self)
743
- {
744
- char *p, *pe;
745
- int cs = EVIL;
746
- VALUE result = Qnil;
747
- GET_PARSER;
748
-
749
- %% write init;
750
- p = json->source;
751
- pe = p + json->len;
752
- %% write exec;
753
-
754
- if (cs >= JSON_first_final && p == pe) {
755
- return result;
756
- } else {
757
- rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p);
758
- return Qnil;
759
- }
760
- }
761
-
762
-
763
- %%{
764
- machine JSON_quirks_mode;
765
-
766
- write data;
767
-
768
- include JSON_common;
769
-
770
734
  action parse_value {
771
- char *np = JSON_parse_value(json, fpc, pe, &result);
735
+ char *np = JSON_parse_value(json, fpc, pe, &result, 0);
772
736
  if (np == NULL) { fhold; fbreak; } else fexec np;
773
737
  }
774
738
 
@@ -777,26 +741,6 @@ static VALUE cParser_parse_strict(VALUE self)
777
741
  ) ignore*;
778
742
  }%%
779
743
 
780
- static VALUE cParser_parse_quirks_mode(VALUE self)
781
- {
782
- char *p, *pe;
783
- int cs = EVIL;
784
- VALUE result = Qnil;
785
- GET_PARSER;
786
-
787
- %% write init;
788
- p = json->source;
789
- pe = p + json->len;
790
- %% write exec;
791
-
792
- if (cs >= JSON_quirks_mode_first_final && p == pe) {
793
- return result;
794
- } else {
795
- rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p);
796
- return Qnil;
797
- }
798
- }
799
-
800
744
  /*
801
745
  * call-seq: parse()
802
746
  *
@@ -805,12 +749,21 @@ static VALUE cParser_parse_quirks_mode(VALUE self)
805
749
  */
806
750
  static VALUE cParser_parse(VALUE self)
807
751
  {
752
+ char *p, *pe;
753
+ int cs = EVIL;
754
+ VALUE result = Qnil;
808
755
  GET_PARSER;
809
756
 
810
- if (json->quirks_mode) {
811
- return cParser_parse_quirks_mode(self);
757
+ %% write init;
758
+ p = json->source;
759
+ pe = p + json->len;
760
+ %% write exec;
761
+
762
+ if (cs >= JSON_first_final && p == pe) {
763
+ return result;
812
764
  } else {
813
- return cParser_parse_strict(self);
765
+ rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p);
766
+ return Qnil;
814
767
  }
815
768
  }
816
769
 
@@ -821,6 +774,7 @@ static void JSON_mark(void *ptr)
821
774
  rb_gc_mark_maybe(json->create_id);
822
775
  rb_gc_mark_maybe(json->object_class);
823
776
  rb_gc_mark_maybe(json->array_class);
777
+ rb_gc_mark_maybe(json->decimal_class);
824
778
  rb_gc_mark_maybe(json->match_string);
825
779
  }
826
780
 
@@ -868,18 +822,6 @@ static VALUE cParser_source(VALUE self)
868
822
  return rb_str_dup(json->Vsource);
869
823
  }
870
824
 
871
- /*
872
- * call-seq: quirks_mode?()
873
- *
874
- * Returns a true, if this parser is in quirks_mode, false otherwise.
875
- */
876
- static VALUE cParser_quirks_mode_p(VALUE self)
877
- {
878
- GET_PARSER;
879
- return json->quirks_mode ? Qtrue : Qfalse;
880
- }
881
-
882
-
883
825
  void Init_parser(void)
884
826
  {
885
827
  rb_require("json/common");
@@ -892,7 +834,6 @@ void Init_parser(void)
892
834
  rb_define_method(cParser, "initialize", cParser_initialize, -1);
893
835
  rb_define_method(cParser, "parse", cParser_parse, 0);
894
836
  rb_define_method(cParser, "source", cParser_source, 0);
895
- rb_define_method(cParser, "quirks_mode?", cParser_quirks_mode_p, 0);
896
837
 
897
838
  CNaN = rb_const_get(mJSON, rb_intern("NaN"));
898
839
  CInfinity = rb_const_get(mJSON, rb_intern("Infinity"));
@@ -906,9 +847,9 @@ void Init_parser(void)
906
847
  i_max_nesting = rb_intern("max_nesting");
907
848
  i_allow_nan = rb_intern("allow_nan");
908
849
  i_symbolize_names = rb_intern("symbolize_names");
909
- i_quirks_mode = rb_intern("quirks_mode");
910
850
  i_object_class = rb_intern("object_class");
911
851
  i_array_class = rb_intern("array_class");
852
+ i_decimal_class = rb_intern("decimal_class");
912
853
  i_match = rb_intern("match");
913
854
  i_match_string = rb_intern("match_string");
914
855
  i_key_p = rb_intern("key?");
@@ -916,18 +857,7 @@ void Init_parser(void)
916
857
  i_aset = rb_intern("[]=");
917
858
  i_aref = rb_intern("[]");
918
859
  i_leftshift = rb_intern("<<");
919
- #ifdef HAVE_RUBY_ENCODING_H
920
- CEncoding_UTF_8 = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-8"));
921
- CEncoding_UTF_16BE = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-16be"));
922
- CEncoding_UTF_16LE = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-16le"));
923
- CEncoding_UTF_32BE = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-32be"));
924
- CEncoding_UTF_32LE = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-32le"));
925
- CEncoding_ASCII_8BIT = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("ascii-8bit"));
926
- i_encoding = rb_intern("encoding");
927
- i_encode = rb_intern("encode");
928
- #else
929
- i_iconv = rb_intern("iconv");
930
- #endif
860
+ i_new = rb_intern("new");
931
861
  }
932
862
 
933
863
  /*
data/ext/json/extconf.rb CHANGED
@@ -1,3 +1,2 @@
1
1
  require 'mkmf'
2
2
  create_makefile('json')
3
-
@@ -1,8 +1,7 @@
1
1
  /*
2
2
  * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
3
3
  *
4
- * Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
5
- * for details.
4
+ * Distributed under the Ruby license: https://www.ruby-lang.org/en/about/license.txt
6
5
  */
7
6
  package json.ext;
8
7
 
@@ -1,8 +1,7 @@
1
1
  /*
2
2
  * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
3
3
  *
4
- * Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
5
- * for details.
4
+ * Distributed under the Ruby license: https://www.ruby-lang.org/en/about/license.txt
6
5
  */
7
6
  package json.ext;
8
7
 
@@ -173,9 +172,7 @@ public final class Generator {
173
172
  result = RubyString.newString(session.getRuntime(), buffer);
174
173
  ThreadContext context = session.getContext();
175
174
  RuntimeInfo info = session.getInfo();
176
- if (info.encodingsSupported()) {
177
- result.force_encoding(context, info.utf8.get());
178
- }
175
+ result.force_encoding(context, info.utf8.get());
179
176
  return result;
180
177
  }
181
178
 
@@ -382,8 +379,7 @@ public final class Generator {
382
379
  RuntimeInfo info = session.getInfo();
383
380
  RubyString src;
384
381
 
385
- if (info.encodingsSupported() &&
386
- object.encoding(session.getContext()) != info.utf8.get()) {
382
+ if (object.encoding(session.getContext()) != info.utf8.get()) {
387
383
  src = (RubyString)object.encode(session.getContext(),
388
384
  info.utf8.get());
389
385
  } else {
@@ -428,11 +424,14 @@ public final class Generator {
428
424
  new Handler<IRubyObject>() {
429
425
  @Override
430
426
  RubyString generateNew(Session session, IRubyObject object) {
431
- IRubyObject result =
432
- object.callMethod(session.getContext(), "to_json",
433
- new IRubyObject[] {session.getState()});
434
- if (result instanceof RubyString) return (RubyString)result;
435
- throw session.getRuntime().newTypeError("to_json must return a String");
427
+ if (object.respondsTo("to_json")) {
428
+ IRubyObject result = object.callMethod(session.getContext(), "to_json",
429
+ new IRubyObject[] {session.getState()});
430
+ if (result instanceof RubyString) return (RubyString)result;
431
+ throw session.getRuntime().newTypeError("to_json must return a String");
432
+ } else {
433
+ return OBJECT_HANDLER.generateNew(session, object);
434
+ }
436
435
  }
437
436
 
438
437
  @Override
@@ -1,8 +1,7 @@
1
1
  /*
2
2
  * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
3
3
  *
4
- * Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
5
- * for details.
4
+ * Distributed under the Ruby license: https://www.ruby-lang.org/en/about/license.txt
6
5
  */
7
6
  package json.ext;
8
7
 
@@ -1,8 +1,7 @@
1
1
  /*
2
2
  * This code is copyrighted work by Daniel Luz <dev at mernen dot com>.
3
3
  *
4
- * Distributed under the Ruby and GPLv2 licenses; see COPYING and GPL files
5
- * for details.
4
+ * Distributed under the Ruby license: https://www.ruby-lang.org/en/about/license.txt
6
5
  */
7
6
  package json.ext;
8
7