json 1.8.3 → 2.5.1

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.
Files changed (93) hide show
  1. checksums.yaml +5 -5
  2. data/{CHANGES → CHANGES.md} +241 -90
  3. data/Gemfile +10 -6
  4. data/{COPYING-json-jruby → LICENSE} +5 -6
  5. data/{README.rdoc → README.md} +201 -134
  6. data/VERSION +1 -1
  7. data/ext/json/ext/fbuffer/fbuffer.h +0 -3
  8. data/ext/json/ext/generator/generator.c +264 -104
  9. data/ext/json/ext/generator/generator.h +12 -4
  10. data/ext/json/ext/parser/extconf.rb +28 -0
  11. data/ext/json/ext/parser/parser.c +425 -462
  12. data/ext/json/ext/parser/parser.h +5 -5
  13. data/ext/json/ext/parser/parser.rl +181 -181
  14. data/ext/json/extconf.rb +1 -1
  15. data/json.gemspec +0 -0
  16. data/lib/json.rb +550 -29
  17. data/lib/json/add/bigdecimal.rb +3 -2
  18. data/lib/json/add/complex.rb +4 -4
  19. data/lib/json/add/core.rb +1 -0
  20. data/lib/json/add/date.rb +1 -1
  21. data/lib/json/add/date_time.rb +1 -1
  22. data/lib/json/add/exception.rb +1 -1
  23. data/lib/json/add/ostruct.rb +3 -3
  24. data/lib/json/add/range.rb +1 -1
  25. data/lib/json/add/rational.rb +3 -3
  26. data/lib/json/add/regexp.rb +3 -3
  27. data/lib/json/add/set.rb +29 -0
  28. data/lib/json/add/struct.rb +1 -1
  29. data/lib/json/add/symbol.rb +1 -1
  30. data/lib/json/add/time.rb +1 -1
  31. data/lib/json/common.rb +381 -162
  32. data/lib/json/ext.rb +0 -6
  33. data/lib/json/generic_object.rb +5 -4
  34. data/lib/json/pure.rb +2 -8
  35. data/lib/json/pure/generator.rb +83 -126
  36. data/lib/json/pure/parser.rb +62 -84
  37. data/lib/json/version.rb +2 -1
  38. data/tests/fixtures/fail29.json +1 -0
  39. data/tests/fixtures/fail30.json +1 -0
  40. data/tests/fixtures/fail31.json +1 -0
  41. data/tests/fixtures/fail32.json +1 -0
  42. data/tests/fixtures/obsolete_fail1.json +1 -0
  43. data/tests/{test_json_addition.rb → json_addition_test.rb} +28 -25
  44. data/tests/json_common_interface_test.rb +169 -0
  45. data/tests/json_encoding_test.rb +107 -0
  46. data/tests/json_ext_parser_test.rb +15 -0
  47. data/tests/{test_json_fixtures.rb → json_fixtures_test.rb} +13 -8
  48. data/tests/{test_json_generate.rb → json_generator_test.rb} +109 -47
  49. data/tests/{test_json_generic_object.rb → json_generic_object_test.rb} +15 -8
  50. data/tests/json_parser_test.rb +497 -0
  51. data/tests/json_string_matching_test.rb +38 -0
  52. data/tests/lib/core_assertions.rb +763 -0
  53. data/tests/lib/envutil.rb +365 -0
  54. data/tests/lib/find_executable.rb +22 -0
  55. data/tests/lib/helper.rb +4 -0
  56. data/tests/ractor_test.rb +30 -0
  57. data/tests/test_helper.rb +17 -0
  58. metadata +48 -76
  59. data/.gitignore +0 -16
  60. data/.travis.yml +0 -26
  61. data/COPYING +0 -58
  62. data/GPL +0 -340
  63. data/README-json-jruby.markdown +0 -33
  64. data/Rakefile +0 -412
  65. data/TODO +0 -1
  66. data/data/example.json +0 -1
  67. data/data/index.html +0 -38
  68. data/data/prototype.js +0 -4184
  69. data/diagrams/.keep +0 -0
  70. data/install.rb +0 -23
  71. data/java/src/json/ext/ByteListTranscoder.java +0 -167
  72. data/java/src/json/ext/Generator.java +0 -444
  73. data/java/src/json/ext/GeneratorMethods.java +0 -232
  74. data/java/src/json/ext/GeneratorService.java +0 -43
  75. data/java/src/json/ext/GeneratorState.java +0 -543
  76. data/java/src/json/ext/OptionsReader.java +0 -114
  77. data/java/src/json/ext/Parser.java +0 -2645
  78. data/java/src/json/ext/Parser.rl +0 -969
  79. data/java/src/json/ext/ParserService.java +0 -35
  80. data/java/src/json/ext/RuntimeInfo.java +0 -121
  81. data/java/src/json/ext/StringDecoder.java +0 -167
  82. data/java/src/json/ext/StringEncoder.java +0 -106
  83. data/java/src/json/ext/Utils.java +0 -89
  84. data/json-java.gemspec +0 -23
  85. data/json_pure.gemspec +0 -40
  86. data/tests/fixtures/fail1.json +0 -1
  87. data/tests/setup_variant.rb +0 -11
  88. data/tests/test_json.rb +0 -553
  89. data/tests/test_json_encoding.rb +0 -65
  90. data/tests/test_json_string_matching.rb +0 -39
  91. data/tests/test_json_unicode.rb +0 -72
  92. data/tools/fuzz.rb +0 -139
  93. data/tools/server.rb +0 -62
@@ -34,13 +34,13 @@ 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;
40
+ int freeze;
42
41
  VALUE object_class;
43
42
  VALUE array_class;
43
+ VALUE decimal_class;
44
44
  int create_additions;
45
45
  VALUE match_string;
46
46
  FBuffer *fbuffer;
@@ -58,11 +58,11 @@ typedef struct JSON_ParserStruct {
58
58
 
59
59
  static UTF32 unescape_unicode(const unsigned char *p);
60
60
  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);
61
+ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
62
+ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
63
63
  static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result);
64
64
  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);
65
+ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting);
66
66
  static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd);
67
67
  static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result);
68
68
  static VALUE convert_encoding(VALUE source);
@@ -1,9 +1,31 @@
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
- static const char digit_values[256] = {
28
+ static const signed char digit_values[256] = {
7
29
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
8
30
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
9
31
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
@@ -22,7 +44,7 @@ static const char digit_values[256] = {
22
44
 
23
45
  static UTF32 unescape_unicode(const unsigned char *p)
24
46
  {
25
- char b;
47
+ signed char b;
26
48
  UTF32 result = 0;
27
49
  b = digit_values[p[0]];
28
50
  if (b < 0) return UNI_REPLACEMENT_CHAR;
@@ -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, i_try_convert, i_freeze, i_uminus;
83
98
 
84
99
  %%{
85
100
  machine JSON_common;
@@ -117,11 +132,12 @@ 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 {
124
139
  if (NIL_P(json->object_class)) {
140
+ OBJ_FREEZE(last_name);
125
141
  rb_hash_aset(*result, last_name, v);
126
142
  } else {
127
143
  rb_funcall(*result, i_aset, 2, last_name, v);
@@ -150,14 +166,14 @@ static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
150
166
  ) @exit;
151
167
  }%%
152
168
 
153
- static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result)
169
+ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
154
170
  {
155
171
  int cs = EVIL;
156
172
  VALUE last_name = Qnil;
157
173
  VALUE object_class = json->object_class;
158
174
 
159
- if (json->max_nesting && json->current_nesting > json->max_nesting) {
160
- rb_raise(eNestingError, "nesting of %d is too deep", json->current_nesting);
175
+ if (json->max_nesting && current_nesting > json->max_nesting) {
176
+ rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
161
177
  }
162
178
 
163
179
  *result = NIL_P(object_class) ? rb_hash_new() : rb_class_new_instance(0, 0, object_class);
@@ -206,14 +222,14 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
206
222
  if (json->allow_nan) {
207
223
  *result = CNaN;
208
224
  } else {
209
- rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p - 2);
225
+ rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p - 2);
210
226
  }
211
227
  }
212
228
  action parse_infinity {
213
229
  if (json->allow_nan) {
214
230
  *result = CInfinity;
215
231
  } else {
216
- rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p - 8);
232
+ rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p - 8);
217
233
  }
218
234
  }
219
235
  action parse_string {
@@ -223,13 +239,13 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
223
239
 
224
240
  action parse_number {
225
241
  char *np;
226
- if(pe > fpc + 9 - json->quirks_mode && !strncmp(MinusInfinity, fpc, 9)) {
242
+ if(pe > fpc + 8 && !strncmp(MinusInfinity, fpc, 9)) {
227
243
  if (json->allow_nan) {
228
244
  *result = CMinusInfinity;
229
245
  fexec p + 10;
230
246
  fhold; fbreak;
231
247
  } else {
232
- rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p);
248
+ rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p);
233
249
  }
234
250
  }
235
251
  np = JSON_parse_float(json, fpc, pe, result);
@@ -241,23 +257,19 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
241
257
 
242
258
  action parse_array {
243
259
  char *np;
244
- json->current_nesting++;
245
- np = JSON_parse_array(json, fpc, pe, result);
246
- json->current_nesting--;
260
+ np = JSON_parse_array(json, fpc, pe, result, current_nesting + 1);
247
261
  if (np == NULL) { fhold; fbreak; } else fexec np;
248
262
  }
249
263
 
250
264
  action parse_object {
251
265
  char *np;
252
- json->current_nesting++;
253
- np = JSON_parse_object(json, fpc, pe, result);
254
- json->current_nesting--;
266
+ np = JSON_parse_object(json, fpc, pe, result, current_nesting + 1);
255
267
  if (np == NULL) { fhold; fbreak; } else fexec np;
256
268
  }
257
269
 
258
270
  action exit { fhold; fbreak; }
259
271
 
260
- main := (
272
+ main := ignore* (
261
273
  Vnull @parse_null |
262
274
  Vfalse @parse_false |
263
275
  Vtrue @parse_true |
@@ -267,16 +279,20 @@ main := (
267
279
  begin_string >parse_string |
268
280
  begin_array >parse_array |
269
281
  begin_object >parse_object
270
- ) %*exit;
282
+ ) ignore* %*exit;
271
283
  }%%
272
284
 
273
- static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result)
285
+ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
274
286
  {
275
287
  int cs = EVIL;
276
288
 
277
289
  %% write init;
278
290
  %% write exec;
279
291
 
292
+ if (json->freeze) {
293
+ OBJ_FREEZE(*result);
294
+ }
295
+
280
296
  if (cs >= JSON_value_first_final) {
281
297
  return p;
282
298
  } else {
@@ -337,11 +353,46 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
337
353
  %% write exec;
338
354
 
339
355
  if (cs >= JSON_float_first_final) {
356
+ VALUE mod = Qnil;
357
+ ID method_id = 0;
358
+ if (rb_respond_to(json->decimal_class, i_try_convert)) {
359
+ mod = json->decimal_class;
360
+ method_id = i_try_convert;
361
+ } else if (rb_respond_to(json->decimal_class, i_new)) {
362
+ mod = json->decimal_class;
363
+ method_id = i_new;
364
+ } else if (RB_TYPE_P(json->decimal_class, T_CLASS)) {
365
+ VALUE name = rb_class_name(json->decimal_class);
366
+ const char *name_cstr = RSTRING_PTR(name);
367
+ const char *last_colon = strrchr(name_cstr, ':');
368
+ if (last_colon) {
369
+ const char *mod_path_end = last_colon - 1;
370
+ VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr);
371
+ mod = rb_path_to_class(mod_path);
372
+
373
+ const char *method_name_beg = last_colon + 1;
374
+ long before_len = method_name_beg - name_cstr;
375
+ long len = RSTRING_LEN(name) - before_len;
376
+ VALUE method_name = rb_str_substr(name, before_len, len);
377
+ method_id = SYM2ID(rb_str_intern(method_name));
378
+ } else {
379
+ mod = rb_mKernel;
380
+ method_id = SYM2ID(rb_str_intern(name));
381
+ }
382
+ }
383
+
340
384
  long len = p - json->memo;
341
385
  fbuffer_clear(json->fbuffer);
342
386
  fbuffer_append(json->fbuffer, json->memo, len);
343
387
  fbuffer_append_char(json->fbuffer, '\0');
344
- *result = rb_float_new(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
388
+
389
+ if (method_id) {
390
+ VALUE text = rb_str_new2(FBUFFER_PTR(json->fbuffer));
391
+ *result = rb_funcallv(mod, method_id, 1, &text);
392
+ } else {
393
+ *result = DBL2NUM(rb_cstr_to_dbl(FBUFFER_PTR(json->fbuffer), 1));
394
+ }
395
+
345
396
  return p + 1;
346
397
  } else {
347
398
  return NULL;
@@ -357,7 +408,7 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
357
408
 
358
409
  action parse_value {
359
410
  VALUE v = Qnil;
360
- char *np = JSON_parse_value(json, fpc, pe, &v);
411
+ char *np = JSON_parse_value(json, fpc, pe, &v, current_nesting);
361
412
  if (np == NULL) {
362
413
  fhold; fbreak;
363
414
  } else {
@@ -380,13 +431,13 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
380
431
  end_array @exit;
381
432
  }%%
382
433
 
383
- static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result)
434
+ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting)
384
435
  {
385
436
  int cs = EVIL;
386
437
  VALUE array_class = json->array_class;
387
438
 
388
- if (json->max_nesting && json->current_nesting > json->max_nesting) {
389
- rb_raise(eNestingError, "nesting of %d is too deep", json->current_nesting);
439
+ if (json->max_nesting && current_nesting > json->max_nesting) {
440
+ rb_raise(eNestingError, "nesting of %d is too deep", current_nesting);
390
441
  }
391
442
  *result = NIL_P(array_class) ? rb_ary_new() : rb_class_new_instance(0, 0, array_class);
392
443
 
@@ -396,7 +447,7 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul
396
447
  if(cs >= JSON_array_first_final) {
397
448
  return p + 1;
398
449
  } else {
399
- rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p);
450
+ rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p);
400
451
  return NULL;
401
452
  }
402
453
  }
@@ -436,13 +487,21 @@ static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)
436
487
  break;
437
488
  case 'u':
438
489
  if (pe > stringEnd - 4) {
439
- return Qnil;
490
+ rb_enc_raise(
491
+ EXC_ENCODING eParserError,
492
+ "%u: incomplete unicode character escape sequence at '%s'", __LINE__, p
493
+ );
440
494
  } else {
441
495
  UTF32 ch = unescape_unicode((unsigned char *) ++pe);
442
496
  pe += 3;
443
497
  if (UNI_SUR_HIGH_START == (ch & 0xFC00)) {
444
498
  pe++;
445
- if (pe > stringEnd - 6) return Qnil;
499
+ if (pe > stringEnd - 6) {
500
+ rb_enc_raise(
501
+ EXC_ENCODING eParserError,
502
+ "%u: incomplete surrogate pair at '%s'", __LINE__, p
503
+ );
504
+ }
446
505
  if (pe[0] == '\\' && pe[1] == 'u') {
447
506
  UTF32 sur = unescape_unicode((unsigned char *) pe + 2);
448
507
  ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
@@ -528,6 +587,23 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
528
587
 
529
588
  if (json->symbolize_names && json->parsing_name) {
530
589
  *result = rb_str_intern(*result);
590
+ } else if (RB_TYPE_P(*result, T_STRING)) {
591
+ # if STR_UMINUS_DEDUPE_FROZEN
592
+ if (json->freeze) {
593
+ // Starting from MRI 2.8 it is preferable to freeze the string
594
+ // before deduplication so that it can be interned directly
595
+ // otherwise it would be duplicated first which is wasteful.
596
+ *result = rb_funcall(rb_str_freeze(*result), i_uminus, 0);
597
+ }
598
+ # elif STR_UMINUS_DEDUPE
599
+ if (json->freeze) {
600
+ // MRI 2.5 and older do not deduplicate strings that are already
601
+ // frozen.
602
+ *result = rb_funcall(*result, i_uminus, 0);
603
+ }
604
+ # else
605
+ rb_str_resize(*result, RSTRING_LEN(*result));
606
+ # endif
531
607
  }
532
608
  if (cs >= JSON_string_first_final) {
533
609
  return p + 1;
@@ -550,41 +626,16 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
550
626
 
551
627
  static VALUE convert_encoding(VALUE source)
552
628
  {
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
629
  #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);
630
+ rb_encoding *enc = rb_enc_get(source);
631
+ if (enc == rb_ascii8bit_encoding()) {
632
+ if (OBJ_FROZEN(source)) {
633
+ source = rb_str_dup(source);
587
634
  }
635
+ FORCE_UTF8(source);
636
+ } else {
637
+ source = rb_str_conv_enc(source, rb_enc_get(source), rb_utf8_encoding());
638
+ }
588
639
  #endif
589
640
  return source;
590
641
  }
@@ -607,8 +658,9 @@ static VALUE convert_encoding(VALUE source)
607
658
  * defiance of RFC 4627 to be parsed by the Parser. This option defaults to
608
659
  * false.
609
660
  * * *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.
661
+ * (keys) in a JSON object. Otherwise strings are returned, which is
662
+ * also the default. It's not possible to use this option in
663
+ * conjunction with the *create_additions* option.
612
664
  * * *create_additions*: If set to false, the Parser doesn't create
613
665
  * additions even if a matching class and create_id was found. This option
614
666
  * defaults to false.
@@ -623,12 +675,18 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
623
675
  if (json->Vsource) {
624
676
  rb_raise(rb_eTypeError, "already initialized instance");
625
677
  }
678
+ #ifdef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
679
+ rb_scan_args(argc, argv, "1:", &source, &opts);
680
+ #else
626
681
  rb_scan_args(argc, argv, "11", &source, &opts);
682
+ #endif
627
683
  if (!NIL_P(opts)) {
684
+ #ifndef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
628
685
  opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
629
686
  if (NIL_P(opts)) {
630
687
  rb_raise(rb_eArgError, "opts needs to be like a hash");
631
688
  } else {
689
+ #endif
632
690
  VALUE tmp = ID2SYM(i_max_nesting);
633
691
  if (option_given_p(opts, tmp)) {
634
692
  VALUE max_nesting = rb_hash_aref(opts, tmp);
@@ -653,12 +711,11 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
653
711
  } else {
654
712
  json->symbolize_names = 0;
655
713
  }
656
- tmp = ID2SYM(i_quirks_mode);
714
+ tmp = ID2SYM(i_freeze);
657
715
  if (option_given_p(opts, tmp)) {
658
- VALUE quirks_mode = rb_hash_aref(opts, tmp);
659
- json->quirks_mode = RTEST(quirks_mode) ? 1 : 0;
716
+ json->freeze = RTEST(rb_hash_aref(opts, tmp)) ? 1 : 0;
660
717
  } else {
661
- json->quirks_mode = 0;
718
+ json->freeze = 0;
662
719
  }
663
720
  tmp = ID2SYM(i_create_additions);
664
721
  if (option_given_p(opts, tmp)) {
@@ -666,6 +723,11 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
666
723
  } else {
667
724
  json->create_additions = 0;
668
725
  }
726
+ if (json->symbolize_names && json->create_additions) {
727
+ rb_raise(rb_eArgError,
728
+ "options :symbolize_names and :create_additions cannot be "
729
+ " used in conjunction");
730
+ }
669
731
  tmp = ID2SYM(i_create_id);
670
732
  if (option_given_p(opts, tmp)) {
671
733
  json->create_id = rb_hash_aref(opts, tmp);
@@ -684,6 +746,12 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
684
746
  } else {
685
747
  json->array_class = Qnil;
686
748
  }
749
+ tmp = ID2SYM(i_decimal_class);
750
+ if (option_given_p(opts, tmp)) {
751
+ json->decimal_class = rb_hash_aref(opts, tmp);
752
+ } else {
753
+ json->decimal_class = Qnil;
754
+ }
687
755
  tmp = ID2SYM(i_match_string);
688
756
  if (option_given_p(opts, tmp)) {
689
757
  VALUE match_string = rb_hash_aref(opts, tmp);
@@ -691,20 +759,19 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
691
759
  } else {
692
760
  json->match_string = Qnil;
693
761
  }
762
+ #ifndef HAVE_RB_SCAN_ARGS_OPTIONAL_HASH
694
763
  }
764
+ #endif
695
765
  } else {
696
766
  json->max_nesting = 100;
697
767
  json->allow_nan = 0;
698
- json->create_additions = 1;
768
+ json->create_additions = 0;
699
769
  json->create_id = rb_funcall(mJSON, i_create_id, 0);
700
770
  json->object_class = Qnil;
701
771
  json->array_class = Qnil;
772
+ json->decimal_class = Qnil;
702
773
  }
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;
774
+ source = convert_encoding(StringValue(source));
708
775
  StringValue(source);
709
776
  json->len = RSTRING_LEN(source);
710
777
  json->source = RSTRING_PTR(source);;
@@ -719,56 +786,8 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
719
786
 
720
787
  include JSON_common;
721
788
 
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
789
  action parse_value {
771
- char *np = JSON_parse_value(json, fpc, pe, &result);
790
+ char *np = JSON_parse_value(json, fpc, pe, &result, 0);
772
791
  if (np == NULL) { fhold; fbreak; } else fexec np;
773
792
  }
774
793
 
@@ -777,26 +796,6 @@ static VALUE cParser_parse_strict(VALUE self)
777
796
  ) ignore*;
778
797
  }%%
779
798
 
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
799
  /*
801
800
  * call-seq: parse()
802
801
  *
@@ -805,12 +804,21 @@ static VALUE cParser_parse_quirks_mode(VALUE self)
805
804
  */
806
805
  static VALUE cParser_parse(VALUE self)
807
806
  {
807
+ char *p, *pe;
808
+ int cs = EVIL;
809
+ VALUE result = Qnil;
808
810
  GET_PARSER;
809
811
 
810
- if (json->quirks_mode) {
811
- return cParser_parse_quirks_mode(self);
812
+ %% write init;
813
+ p = json->source;
814
+ pe = p + json->len;
815
+ %% write exec;
816
+
817
+ if (cs >= JSON_first_final && p == pe) {
818
+ return result;
812
819
  } else {
813
- return cParser_parse_strict(self);
820
+ rb_enc_raise(EXC_ENCODING eParserError, "%u: unexpected token at '%s'", __LINE__, p);
821
+ return Qnil;
814
822
  }
815
823
  }
816
824
 
@@ -821,6 +829,7 @@ static void JSON_mark(void *ptr)
821
829
  rb_gc_mark_maybe(json->create_id);
822
830
  rb_gc_mark_maybe(json->object_class);
823
831
  rb_gc_mark_maybe(json->array_class);
832
+ rb_gc_mark_maybe(json->decimal_class);
824
833
  rb_gc_mark_maybe(json->match_string);
825
834
  }
826
835
 
@@ -868,35 +877,34 @@ static VALUE cParser_source(VALUE self)
868
877
  return rb_str_dup(json->Vsource);
869
878
  }
870
879
 
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
880
  void Init_parser(void)
884
881
  {
882
+ #ifdef HAVE_RB_EXT_RACTOR_SAFE
883
+ rb_ext_ractor_safe(true);
884
+ #endif
885
+
886
+ #undef rb_intern
885
887
  rb_require("json/common");
886
888
  mJSON = rb_define_module("JSON");
887
889
  mExt = rb_define_module_under(mJSON, "Ext");
888
890
  cParser = rb_define_class_under(mExt, "Parser", rb_cObject);
889
891
  eParserError = rb_path2class("JSON::ParserError");
890
892
  eNestingError = rb_path2class("JSON::NestingError");
893
+ rb_gc_register_mark_object(eParserError);
894
+ rb_gc_register_mark_object(eNestingError);
891
895
  rb_define_alloc_func(cParser, cJSON_parser_s_allocate);
892
896
  rb_define_method(cParser, "initialize", cParser_initialize, -1);
893
897
  rb_define_method(cParser, "parse", cParser_parse, 0);
894
898
  rb_define_method(cParser, "source", cParser_source, 0);
895
- rb_define_method(cParser, "quirks_mode?", cParser_quirks_mode_p, 0);
896
899
 
897
900
  CNaN = rb_const_get(mJSON, rb_intern("NaN"));
901
+ rb_gc_register_mark_object(CNaN);
902
+
898
903
  CInfinity = rb_const_get(mJSON, rb_intern("Infinity"));
904
+ rb_gc_register_mark_object(CInfinity);
905
+
899
906
  CMinusInfinity = rb_const_get(mJSON, rb_intern("MinusInfinity"));
907
+ rb_gc_register_mark_object(CMinusInfinity);
900
908
 
901
909
  i_json_creatable_p = rb_intern("json_creatable?");
902
910
  i_json_create = rb_intern("json_create");
@@ -906,9 +914,9 @@ void Init_parser(void)
906
914
  i_max_nesting = rb_intern("max_nesting");
907
915
  i_allow_nan = rb_intern("allow_nan");
908
916
  i_symbolize_names = rb_intern("symbolize_names");
909
- i_quirks_mode = rb_intern("quirks_mode");
910
917
  i_object_class = rb_intern("object_class");
911
918
  i_array_class = rb_intern("array_class");
919
+ i_decimal_class = rb_intern("decimal_class");
912
920
  i_match = rb_intern("match");
913
921
  i_match_string = rb_intern("match_string");
914
922
  i_key_p = rb_intern("key?");
@@ -916,18 +924,10 @@ void Init_parser(void)
916
924
  i_aset = rb_intern("[]=");
917
925
  i_aref = rb_intern("[]");
918
926
  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
927
+ i_new = rb_intern("new");
928
+ i_try_convert = rb_intern("try_convert");
929
+ i_freeze = rb_intern("freeze");
930
+ i_uminus = rb_intern("-@");
931
931
  }
932
932
 
933
933
  /*