oj 3.16.0 → 3.17.3

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 (137) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +107 -0
  3. data/README.md +0 -16
  4. data/ext/oj/cache.c +4 -2
  5. data/ext/oj/cache.h +3 -2
  6. data/ext/oj/compat.c +3 -3
  7. data/ext/oj/custom.c +17 -11
  8. data/ext/oj/dump.c +624 -90
  9. data/ext/oj/dump.h +9 -2
  10. data/ext/oj/dump_compat.c +15 -9
  11. data/ext/oj/dump_leaf.c +1 -1
  12. data/ext/oj/dump_object.c +32 -17
  13. data/ext/oj/dump_strict.c +20 -14
  14. data/ext/oj/extconf.rb +11 -9
  15. data/ext/oj/fast.c +50 -32
  16. data/ext/oj/intern.c +24 -7
  17. data/ext/oj/mimic_json.c +17 -11
  18. data/ext/oj/object.c +21 -13
  19. data/ext/oj/oj.c +387 -140
  20. data/ext/oj/oj.h +59 -55
  21. data/ext/oj/parse.c +248 -47
  22. data/ext/oj/parser.c +179 -89
  23. data/ext/oj/parser.h +4 -2
  24. data/ext/oj/rails.c +64 -42
  25. data/ext/oj/reader.c +1 -1
  26. data/ext/oj/rxclass.c +1 -1
  27. data/ext/oj/rxclass.h +1 -1
  28. data/ext/oj/safe.c +230 -0
  29. data/ext/oj/safe.h +79 -0
  30. data/ext/oj/saj.c +15 -10
  31. data/ext/oj/scp.c +3 -6
  32. data/ext/oj/simd.h +219 -0
  33. data/ext/oj/sparse.c +6 -3
  34. data/ext/oj/stream_writer.c +38 -28
  35. data/ext/oj/strict.c +2 -4
  36. data/ext/oj/string_writer.c +54 -22
  37. data/ext/oj/usual.c +57 -35
  38. data/ext/oj/usual.h +1 -0
  39. data/ext/oj/val_stack.c +13 -2
  40. data/ext/oj/wab.c +5 -4
  41. data/lib/oj/mimic.rb +1 -5
  42. data/lib/oj/schandler.rb +5 -4
  43. data/lib/oj/version.rb +1 -1
  44. data/pages/Encoding.md +1 -1
  45. metadata +36 -100
  46. data/test/_test_active.rb +0 -75
  47. data/test/_test_active_mimic.rb +0 -95
  48. data/test/_test_mimic_rails.rb +0 -123
  49. data/test/activerecord/result_test.rb +0 -31
  50. data/test/activesupport6/abstract_unit.rb +0 -44
  51. data/test/activesupport6/decoding_test.rb +0 -133
  52. data/test/activesupport6/encoding_test.rb +0 -507
  53. data/test/activesupport6/encoding_test_cases.rb +0 -98
  54. data/test/activesupport6/test_common.rb +0 -17
  55. data/test/activesupport6/test_helper.rb +0 -163
  56. data/test/activesupport6/time_zone_test_helpers.rb +0 -39
  57. data/test/activesupport7/abstract_unit.rb +0 -49
  58. data/test/activesupport7/decoding_test.rb +0 -125
  59. data/test/activesupport7/encoding_test.rb +0 -486
  60. data/test/activesupport7/encoding_test_cases.rb +0 -104
  61. data/test/activesupport7/time_zone_test_helpers.rb +0 -47
  62. data/test/files.rb +0 -29
  63. data/test/foo.rb +0 -14
  64. data/test/helper.rb +0 -39
  65. data/test/isolated/shared.rb +0 -309
  66. data/test/isolated/test_mimic_after.rb +0 -13
  67. data/test/isolated/test_mimic_alone.rb +0 -12
  68. data/test/isolated/test_mimic_as_json.rb +0 -45
  69. data/test/isolated/test_mimic_before.rb +0 -13
  70. data/test/isolated/test_mimic_define.rb +0 -28
  71. data/test/isolated/test_mimic_rails_after.rb +0 -22
  72. data/test/isolated/test_mimic_rails_before.rb +0 -21
  73. data/test/isolated/test_mimic_redefine.rb +0 -15
  74. data/test/json_gem/json_addition_test.rb +0 -216
  75. data/test/json_gem/json_common_interface_test.rb +0 -155
  76. data/test/json_gem/json_encoding_test.rb +0 -107
  77. data/test/json_gem/json_ext_parser_test.rb +0 -21
  78. data/test/json_gem/json_fixtures_test.rb +0 -36
  79. data/test/json_gem/json_generator_test.rb +0 -407
  80. data/test/json_gem/json_generic_object_test.rb +0 -90
  81. data/test/json_gem/json_parser_test.rb +0 -477
  82. data/test/json_gem/json_string_matching_test.rb +0 -42
  83. data/test/json_gem/test_helper.rb +0 -30
  84. data/test/mem.rb +0 -34
  85. data/test/perf.rb +0 -102
  86. data/test/perf_compat.rb +0 -128
  87. data/test/perf_dump.rb +0 -50
  88. data/test/perf_fast.rb +0 -162
  89. data/test/perf_file.rb +0 -62
  90. data/test/perf_object.rb +0 -134
  91. data/test/perf_once.rb +0 -59
  92. data/test/perf_parser.rb +0 -183
  93. data/test/perf_saj.rb +0 -101
  94. data/test/perf_scp.rb +0 -140
  95. data/test/perf_simple.rb +0 -289
  96. data/test/perf_strict.rb +0 -137
  97. data/test/perf_wab.rb +0 -129
  98. data/test/prec.rb +0 -23
  99. data/test/sample/change.rb +0 -13
  100. data/test/sample/dir.rb +0 -18
  101. data/test/sample/doc.rb +0 -35
  102. data/test/sample/file.rb +0 -47
  103. data/test/sample/group.rb +0 -15
  104. data/test/sample/hasprops.rb +0 -15
  105. data/test/sample/layer.rb +0 -11
  106. data/test/sample/line.rb +0 -20
  107. data/test/sample/oval.rb +0 -10
  108. data/test/sample/rect.rb +0 -9
  109. data/test/sample/shape.rb +0 -34
  110. data/test/sample/text.rb +0 -19
  111. data/test/sample.rb +0 -54
  112. data/test/sample_json.rb +0 -37
  113. data/test/test_compat.rb +0 -567
  114. data/test/test_custom.rb +0 -554
  115. data/test/test_debian.rb +0 -50
  116. data/test/test_fast.rb +0 -526
  117. data/test/test_file.rb +0 -250
  118. data/test/test_gc.rb +0 -60
  119. data/test/test_generate.rb +0 -21
  120. data/test/test_hash.rb +0 -39
  121. data/test/test_integer_range.rb +0 -72
  122. data/test/test_null.rb +0 -376
  123. data/test/test_object.rb +0 -1016
  124. data/test/test_parser.rb +0 -11
  125. data/test/test_parser_debug.rb +0 -27
  126. data/test/test_parser_saj.rb +0 -337
  127. data/test/test_parser_usual.rb +0 -217
  128. data/test/test_rails.rb +0 -35
  129. data/test/test_saj.rb +0 -188
  130. data/test/test_scp.rb +0 -431
  131. data/test/test_strict.rb +0 -431
  132. data/test/test_various.rb +0 -801
  133. data/test/test_wab.rb +0 -311
  134. data/test/test_writer.rb +0 -380
  135. data/test/tests.rb +0 -33
  136. data/test/tests_mimic.rb +0 -23
  137. data/test/tests_mimic_addition.rb +0 -16
data/ext/oj/parser.c CHANGED
@@ -75,7 +75,7 @@ enum {
75
75
 
76
76
  /*
77
77
  0123456789abcdef0123456789abcdef */
78
- static const char value_map[257] = "\
78
+ static const char value_map[258] = "\
79
79
  X........ab..a..................\
80
80
  a.i..........f..ghhhhhhhhh......\
81
81
  ...........................k.m..\
@@ -85,7 +85,7 @@ a.i..........f..ghhhhhhhhh......\
85
85
  ................................\
86
86
  ................................v";
87
87
 
88
- static const char null_map[257] = "\
88
+ static const char null_map[258] = "\
89
89
  ................................\
90
90
  ............o...................\
91
91
  ................................\
@@ -95,7 +95,7 @@ static const char null_map[257] = "\
95
95
  ................................\
96
96
  ................................N";
97
97
 
98
- static const char true_map[257] = "\
98
+ static const char true_map[258] = "\
99
99
  ................................\
100
100
  ............o...................\
101
101
  ................................\
@@ -105,7 +105,7 @@ static const char true_map[257] = "\
105
105
  ................................\
106
106
  ................................T";
107
107
 
108
- static const char false_map[257] = "\
108
+ static const char false_map[258] = "\
109
109
  ................................\
110
110
  ............o...................\
111
111
  ................................\
@@ -115,7 +115,7 @@ static const char false_map[257] = "\
115
115
  ................................\
116
116
  ................................F";
117
117
 
118
- static const char comma_map[257] = "\
118
+ static const char comma_map[258] = "\
119
119
  .........ab..a..................\
120
120
  a.i..........f..ghhhhhhhhh......\
121
121
  ...........................k....\
@@ -125,7 +125,7 @@ a.i..........f..ghhhhhhhhh......\
125
125
  ................................\
126
126
  ................................,";
127
127
 
128
- static const char after_map[257] = "\
128
+ static const char after_map[258] = "\
129
129
  X........ab..a..................\
130
130
  a...........o...................\
131
131
  .............................m..\
@@ -135,7 +135,7 @@ a...........o...................\
135
135
  ................................\
136
136
  ................................a";
137
137
 
138
- static const char key1_map[257] = "\
138
+ static const char key1_map[258] = "\
139
139
  .........ab..a..................\
140
140
  a.p.............................\
141
141
  ................................\
@@ -145,7 +145,7 @@ a.p.............................\
145
145
  ................................\
146
146
  ................................K";
147
147
 
148
- static const char key_map[257] = "\
148
+ static const char key_map[258] = "\
149
149
  .........ab..a..................\
150
150
  a.p.............................\
151
151
  ................................\
@@ -155,7 +155,7 @@ a.p.............................\
155
155
  ................................\
156
156
  ................................k";
157
157
 
158
- static const char colon_map[257] = "\
158
+ static const char colon_map[258] = "\
159
159
  .........ab..a..................\
160
160
  a.........................q.....\
161
161
  ................................\
@@ -165,7 +165,7 @@ a.........................q.....\
165
165
  ................................\
166
166
  ................................:";
167
167
 
168
- static const char neg_map[257] = "\
168
+ static const char neg_map[258] = "\
169
169
  ................................\
170
170
  ................O---------......\
171
171
  ................................\
@@ -175,7 +175,7 @@ static const char neg_map[257] = "\
175
175
  ................................\
176
176
  ................................-";
177
177
 
178
- static const char zero_map[257] = "\
178
+ static const char zero_map[258] = "\
179
179
  .........rs..r..................\
180
180
  r...........u.t.................\
181
181
  .............................H..\
@@ -185,7 +185,7 @@ r...........u.t.................\
185
185
  ................................\
186
186
  ................................0";
187
187
 
188
- static const char digit_map[257] = "\
188
+ static const char digit_map[258] = "\
189
189
  .........rs..r..................\
190
190
  r...........u.t.NNNNNNNNNN......\
191
191
  .....w.......................H..\
@@ -195,7 +195,7 @@ r...........u.t.NNNNNNNNNN......\
195
195
  ................................\
196
196
  ................................d";
197
197
 
198
- static const char dot_map[257] = "\
198
+ static const char dot_map[258] = "\
199
199
  ................................\
200
200
  ................vvvvvvvvvv......\
201
201
  ................................\
@@ -205,7 +205,7 @@ static const char dot_map[257] = "\
205
205
  ................................\
206
206
  .................................";
207
207
 
208
- static const char frac_map[257] = "\
208
+ static const char frac_map[258] = "\
209
209
  .........rs..r..................\
210
210
  r...........u...vvvvvvvvvv......\
211
211
  .....w.......................H..\
@@ -215,7 +215,7 @@ r...........u...vvvvvvvvvv......\
215
215
  ................................\
216
216
  ................................f";
217
217
 
218
- static const char exp_sign_map[257] = "\
218
+ static const char exp_sign_map[258] = "\
219
219
  ................................\
220
220
  ...........x.x..yyyyyyyyyy......\
221
221
  ................................\
@@ -225,7 +225,7 @@ static const char exp_sign_map[257] = "\
225
225
  ................................\
226
226
  ................................x";
227
227
 
228
- static const char exp_zero_map[257] = "\
228
+ static const char exp_zero_map[258] = "\
229
229
  ................................\
230
230
  ................yyyyyyyyyy......\
231
231
  ................................\
@@ -235,7 +235,7 @@ static const char exp_zero_map[257] = "\
235
235
  ................................\
236
236
  ................................z";
237
237
 
238
- static const char exp_map[257] = "\
238
+ static const char exp_map[258] = "\
239
239
  .........rs..r..................\
240
240
  r...........u...yyyyyyyyyy......\
241
241
  .............................H..\
@@ -245,7 +245,7 @@ r...........u...yyyyyyyyyy......\
245
245
  ................................\
246
246
  ................................X";
247
247
 
248
- static const char big_digit_map[257] = "\
248
+ static const char big_digit_map[258] = "\
249
249
  .........rs..r..................\
250
250
  r...........u.D.CCCCCCCCCC......\
251
251
  .....J.......................H..\
@@ -255,7 +255,7 @@ r...........u.D.CCCCCCCCCC......\
255
255
  ................................\
256
256
  ................................D";
257
257
 
258
- static const char big_dot_map[257] = "\
258
+ static const char big_dot_map[258] = "\
259
259
  ................................\
260
260
  ................IIIIIIIIII......\
261
261
  ................................\
@@ -265,7 +265,7 @@ static const char big_dot_map[257] = "\
265
265
  ................................\
266
266
  ................................o";
267
267
 
268
- static const char big_frac_map[257] = "\
268
+ static const char big_frac_map[258] = "\
269
269
  .........rs..r..................\
270
270
  r...........u...IIIIIIIIII......\
271
271
  .....J.......................H..\
@@ -275,7 +275,7 @@ r...........u...IIIIIIIIII......\
275
275
  ................................\
276
276
  ................................g";
277
277
 
278
- static const char big_exp_sign_map[257] = "\
278
+ static const char big_exp_sign_map[258] = "\
279
279
  ................................\
280
280
  ...........K.K..LLLLLLLLLL......\
281
281
  ................................\
@@ -285,7 +285,7 @@ static const char big_exp_sign_map[257] = "\
285
285
  ................................\
286
286
  ................................B";
287
287
 
288
- static const char big_exp_zero_map[257] = "\
288
+ static const char big_exp_zero_map[258] = "\
289
289
  ................................\
290
290
  ................LLLLLLLLLL......\
291
291
  ................................\
@@ -295,7 +295,7 @@ static const char big_exp_zero_map[257] = "\
295
295
  ................................\
296
296
  ................................Z";
297
297
 
298
- static const char big_exp_map[257] = "\
298
+ static const char big_exp_map[258] = "\
299
299
  .........rs..r..................\
300
300
  r...........u...LLLLLLLLLL......\
301
301
  .............................H..\
@@ -305,7 +305,7 @@ r...........u...LLLLLLLLLL......\
305
305
  ................................\
306
306
  ................................Y";
307
307
 
308
- static const char string_map[257] = "\
308
+ static const char string_map[258] = "\
309
309
  ................................\
310
310
  RRzRRRRRRRRRRRRRRRRRRRRRRRRRRRRR\
311
311
  RRRRRRRRRRRRRRRRRRRRRRRRRRRRARRR\
@@ -315,7 +315,7 @@ RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR\
315
315
  MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\
316
316
  PPPPPPPPPPPPPPPPQQQQQQQQ........s";
317
317
 
318
- static const char esc_map[257] = "\
318
+ static const char esc_map[258] = "\
319
319
  ................................\
320
320
  ..B............B................\
321
321
  ............................B...\
@@ -325,7 +325,7 @@ static const char esc_map[257] = "\
325
325
  ................................\
326
326
  ................................~";
327
327
 
328
- static const char esc_byte_map[257] = "\
328
+ static const char esc_byte_map[258] = "\
329
329
  ................................\
330
330
  ..\"............/................\
331
331
  ............................\\...\
@@ -335,7 +335,7 @@ static const char esc_byte_map[257] = "\
335
335
  ................................\
336
336
  ................................b";
337
337
 
338
- static const char u_map[257] = "\
338
+ static const char u_map[258] = "\
339
339
  ................................\
340
340
  ................EEEEEEEEEE......\
341
341
  .EEEEEE.........................\
@@ -345,7 +345,7 @@ static const char u_map[257] = "\
345
345
  ................................\
346
346
  ................................u";
347
347
 
348
- static const char utf_map[257] = "\
348
+ static const char utf_map[258] = "\
349
349
  ................................\
350
350
  ................................\
351
351
  ................................\
@@ -355,7 +355,7 @@ SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS\
355
355
  ................................\
356
356
  ................................8";
357
357
 
358
- static const char space_map[257] = "\
358
+ static const char space_map[258] = "\
359
359
  .........ab..a..................\
360
360
  a...............................\
361
361
  ................................\
@@ -365,7 +365,7 @@ a...............................\
365
365
  ................................\
366
366
  ................................S";
367
367
 
368
- static const char trail_map[257] = "\
368
+ static const char trail_map[258] = "\
369
369
  .........ab..a..................\
370
370
  a...............................\
371
371
  ................................\
@@ -375,7 +375,7 @@ a...............................\
375
375
  ................................\
376
376
  ................................R";
377
377
 
378
- static const byte hex_map[256] = "\
378
+ static const byte hex_map[257] = "\
379
379
  ................................\
380
380
  ................\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09......\
381
381
  .\x0a\x0b\x0c\x0d\x0e\x0f.........................\
@@ -594,7 +594,7 @@ static void big_change(ojParser p) {
594
594
  }
595
595
  }
596
596
 
597
- static void parse(ojParser p, const byte *json) {
597
+ static void parse(ojParser p, const byte *json, bool more) {
598
598
  const byte *start;
599
599
  const byte *b = json;
600
600
  int i;
@@ -635,6 +635,9 @@ static void parse(ojParser p, const byte *json) {
635
635
  if ('"' == *b) {
636
636
  p->map = colon_map;
637
637
  break;
638
+ } else if ('\0' == *b && !more) {
639
+ parse_error(p, "quoted string not terminated");
640
+ break;
638
641
  }
639
642
  b--;
640
643
  p->map = string_map;
@@ -659,6 +662,9 @@ static void parse(ojParser p, const byte *json) {
659
662
  p->funcs[p->stack[p->depth]].add_str(p);
660
663
  p->map = (0 == p->depth) ? value_map : after_map;
661
664
  break;
665
+ } else if ('\0' == *b && !more) {
666
+ parse_error(p, "quoted string not terminated");
667
+ break;
662
668
  }
663
669
  b--;
664
670
  p->map = string_map;
@@ -668,6 +674,10 @@ static void parse(ojParser p, const byte *json) {
668
674
  p->cur = b - json;
669
675
  p->funcs[p->stack[p->depth]].open_object(p);
670
676
  p->depth++;
677
+ if ((int)sizeof(p->stack) <= p->depth) {
678
+ parse_error(p, "too deeply nested");
679
+ break;
680
+ }
671
681
  p->stack[p->depth] = OBJECT_FUN;
672
682
  p->map = key1_map;
673
683
  break;
@@ -690,6 +700,10 @@ static void parse(ojParser p, const byte *json) {
690
700
  p->cur = b - json;
691
701
  p->funcs[p->stack[p->depth]].open_array(p);
692
702
  p->depth++;
703
+ if ((int)sizeof(p->stack) <= p->depth) {
704
+ parse_error(p, "too deeply nested");
705
+ break;
706
+ }
693
707
  p->stack[p->depth] = ARRAY_FUN;
694
708
  p->map = value_map;
695
709
  break;
@@ -1114,9 +1128,6 @@ static void parse(ojParser p, const byte *json) {
1114
1128
  p->map = trail_map;
1115
1129
  }
1116
1130
  }
1117
- if (0 < p->depth) {
1118
- parse_error(p, "parse error, not closed");
1119
- }
1120
1131
  if (0 == p->depth) {
1121
1132
  switch (p->map[256]) {
1122
1133
  case '0':
@@ -1164,10 +1175,23 @@ static void parser_mark(void *ptr) {
1164
1175
  }
1165
1176
  }
1166
1177
 
1178
+ const rb_data_type_t oj_parser_type = {
1179
+ "Oj/parser",
1180
+ {
1181
+ parser_mark,
1182
+ parser_free,
1183
+ NULL,
1184
+ },
1185
+ 0,
1186
+ 0,
1187
+ };
1188
+
1167
1189
  extern void oj_set_parser_validator(ojParser p);
1168
1190
  extern void oj_set_parser_saj(ojParser p);
1169
1191
  extern void oj_set_parser_usual(ojParser p);
1170
1192
  extern void oj_set_parser_debug(ojParser p);
1193
+ extern void oj_set_parser_safe(ojParser p, VALUE options);
1194
+ extern void oj_safe_init(VALUE parser_class);
1171
1195
 
1172
1196
  static int opt_cb(VALUE rkey, VALUE value, VALUE ptr) {
1173
1197
  ojParser p = (ojParser)ptr;
@@ -1255,7 +1279,7 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
1255
1279
  rb_hash_foreach(ropts, opt_cb, (VALUE)p);
1256
1280
  }
1257
1281
  }
1258
- return Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
1282
+ return TypedData_Wrap_Struct(parser_class, &oj_parser_type, p);
1259
1283
  }
1260
1284
 
1261
1285
  // Create a new parser without setting the delegate. The parser is
@@ -1275,7 +1299,7 @@ VALUE oj_parser_new(void) {
1275
1299
  buf_init(&p->buf);
1276
1300
  p->map = value_map;
1277
1301
 
1278
- return Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
1302
+ return TypedData_Wrap_Struct(parser_class, &oj_parser_type, p);
1279
1303
  }
1280
1304
 
1281
1305
  // Set set the options from a hash (ropts).
@@ -1294,53 +1318,41 @@ void oj_parser_set_option(ojParser p, VALUE ropts) {
1294
1318
  * - no options
1295
1319
  *
1296
1320
  * - *:saj*
1297
- * - _cache_keys=_ sets the value of the _cache_keys_ flag.
1298
- * - _cache_keys_ returns the value of the _cache_keys_ flag.
1299
- * - _cache_strings=_ sets the value of the _cache_strings_ to an positive integer less than 35. Strings shorter than
1300
- * that length are cached.
1301
- * - _cache_strings_ returns the value of the _cache_strings_ integer value.
1302
- * - _handler=_ sets the SAJ handler
1303
- * - _handler_ returns the SAJ handler
1321
+ * - _cache_keys_ is a flag indicating hash keys should be cached.
1322
+ * - _cache_strings_ is a positive integer less than 35. Strings shorter than that length are cached.
1323
+ * - _handler_ is the SAJ handler
1304
1324
  *
1305
1325
  * - *:usual*
1306
- * - _cache_keys=_ sets the value of the _cache_keys_ flag.
1307
- * - _cache_keys_ returns the value of the _cache_keys_ flag.
1308
- * - _cache_strings=_ sets the value of the _cache_strings_ to a positive integer less than 35. Strings shorter than
1309
- * that length are cached.
1310
- * - _cache_strings_ returns the value of the _cache_strings_ integer value.
1311
- * - _cache_expunge=_ sets the value of the _cache_expunge_ where 0 never expunges, 1 expunges slowly, 2 expunges
1312
- * faster, and 3 or higher expunges agressively.
1313
- * - _cache_expunge_ returns the value of the _cache_expunge_ integer value.
1314
- * - _capacity=_ sets the capacity of the parser. The parser grows automatically but can be updated directly with this
1315
- * call.
1316
- * - _capacity_ returns the current capacity of the parser's internal stack.
1317
- * - _create_id_ returns the value _create_id_ or _nil_ if there is no _create_id_.
1318
- * - _create_id=_ sets the value _create_id_ or if _nil_ unsets it. Parsed JSON objects that include the specified
1319
- * element use the element value as the name of the class to create an object from instead of a Hash.
1320
- * - _decimal=_ sets the approach to how decimals are parser. If _:auto_ then the decimals with significant digits are
1321
- * 16 or less are Floats and long ones are BigDecimal. _:ruby_ uses a call to Ruby to convert a string to a Float.
1322
- * _:float_ always generates a Float. _:bigdecimal_ always results in a BigDecimal.
1323
- * - _decimal_ returns the value of the decimal conversion option which can be :auto (default), :ruby, :float, or
1324
- * :bigdecimal.
1325
- * - _ignore_json_create_ returns the value of the _ignore_json_create_ flag.
1326
- * - _ignore_json_create=_ sets the value of the _ignore_json_create_ flag. When set the class json_create method is
1327
- * ignored on parsing in favor of creating an instance and populating directly.
1328
- * - _missing_class_ return the value of the _missing_class_ indicator.
1329
- * - _missing_class=_ sets the value of the _missing_class_ flag. Valid values are _:auto_ which creates any missing
1330
- * classes on parse, :ignore which ignores and continues as a Hash (default), and :raise which raises an exception if
1331
- * the class is not found.
1332
- * - _omit_null=_ sets the _omit_null_ flag. If true then null values in a map or object are omitted from the
1333
- * resulting Hash or Object.
1334
- * - _omit_null_ returns the value of the _omit_null_ flag.
1335
- * - _symbol_keys=_ sets the flag that indicates Hash keys should be parsed to Symbols versus Strings.
1336
- * - _symbol_keys_ returns the value of the _symbol_keys_ flag.
1326
+ * - _cache_keys_ is a flag indicating hash keys should be cached.
1327
+ * - _cache_strings_ is a positive integer less than 35. Strings shorter than that length are cached.
1328
+ * - _cache_expunge_ dictates when the cache will be expunged where 0 never expunges,
1329
+ * 1 expunges slowly, 2 expunges faster, and 3 or higher expunges agressively.
1330
+ * - _capacity_ is the capacity of the parser's internal stack. The parser grows automatically
1331
+ * but can be updated directly with this call.
1332
+ * - _create_id_ if non-nil is the key that is used to specify the type of object to create
1333
+ * when parsing. Parsed JSON objects that include the specified element use the element
1334
+ * value as the name of the class to create an object from instead of a Hash.
1335
+ * - _decimal_ is the approach to how decimals are parsed. If _:auto_ then
1336
+ * the decimals with significant digits are 16 or less are Floats and long
1337
+ * ones are BigDecimal. _:ruby_ uses a call to Ruby to convert a string to a Float.
1338
+ * _:float_ always generates a Float. _:bigdecimal_ always results in a BigDecimal.
1339
+ * - _ignore_json_create_ is a flag that when set the class json_create method is
1340
+ * ignored on parsing in favor of creating an instance and populating directly.
1341
+ * - _missing_class_ is an indicator that determines how unknown class names are handled.
1342
+ * Valid values are _:auto_ which creates any missing classes on parse, :ignore which ignores
1343
+ * and continues as a Hash (default), and :raise which raises an exception if the class is not found.
1344
+ * - _omit_null_ is a flag that if true then null values in a map or object are omitted
1345
+ * from the resulting Hash or Object.
1346
+ * - _symbol_keys_ is a flag that indicates Hash keys should be parsed to Symbols versus Strings.
1337
1347
  */
1338
1348
  static VALUE parser_missing(int argc, VALUE *argv, VALUE self) {
1339
- ojParser p = (ojParser)DATA_PTR(self);
1349
+ ojParser p;
1340
1350
  const char *key = NULL;
1341
1351
  volatile VALUE rkey = *argv;
1342
1352
  volatile VALUE rv = Qnil;
1343
1353
 
1354
+ TypedData_Get_Struct(self, struct _ojParser, &oj_parser_type, p);
1355
+
1344
1356
  #if HAVE_RB_EXT_RACTOR_SAFE
1345
1357
  // This doesn't seem to do anything.
1346
1358
  rb_ext_ractor_safe(true);
@@ -1358,6 +1370,34 @@ static VALUE parser_missing(int argc, VALUE *argv, VALUE self) {
1358
1370
  return p->option(p, key, rv);
1359
1371
  }
1360
1372
 
1373
+ static void validate_primitives_are_complete(ojParser p) {
1374
+ if (0 >= p->ri) {
1375
+ return;
1376
+ }
1377
+
1378
+ switch (p->map[256]) {
1379
+ case 'N': parse_error(p, "expected null"); break;
1380
+ case 'F': parse_error(p, "expected false"); break;
1381
+ case 'T': parse_error(p, "expected true"); break;
1382
+ }
1383
+ }
1384
+
1385
+ static void validate_non_primitives_are_complete(ojParser p) {
1386
+ if (0 >= p->depth) {
1387
+ return;
1388
+ }
1389
+ if (OBJECT_FUN == p->stack[p->depth]) {
1390
+ parse_error(p, "Object is not closed");
1391
+ } else {
1392
+ parse_error(p, "Array is not closed");
1393
+ }
1394
+ }
1395
+
1396
+ static void validate_document_end(ojParser p) {
1397
+ validate_primitives_are_complete(p);
1398
+ validate_non_primitives_are_complete(p);
1399
+ }
1400
+
1361
1401
  /* Document-method: parse(json)
1362
1402
  * call-seq: parse(json)
1363
1403
  *
@@ -1366,12 +1406,21 @@ static VALUE parser_missing(int argc, VALUE *argv, VALUE self) {
1366
1406
  * Returns the result according to the delegate of the parser.
1367
1407
  */
1368
1408
  static VALUE parser_parse(VALUE self, VALUE json) {
1369
- ojParser p = (ojParser)DATA_PTR(self);
1370
- const byte *ptr = (const byte *)StringValuePtr(json);
1409
+ ojParser p;
1410
+ int frozen = OBJ_FROZEN(json);
1411
+ const byte *ptr;
1412
+
1413
+ if (!frozen) {
1414
+ rb_str_freeze(json);
1415
+ }
1416
+ ptr = (const byte *)StringValuePtr(json);
1417
+
1418
+ TypedData_Get_Struct(self, struct _ojParser, &oj_parser_type, p);
1371
1419
 
1372
1420
  parser_reset(p);
1373
1421
  p->start(p);
1374
- parse(p, ptr);
1422
+ parse(p, ptr, false);
1423
+ validate_document_end(p);
1375
1424
 
1376
1425
  return p->result(p);
1377
1426
  }
@@ -1382,14 +1431,22 @@ static VALUE load_rescue(VALUE self, VALUE x) {
1382
1431
  }
1383
1432
 
1384
1433
  static VALUE load(VALUE self) {
1385
- ojParser p = (ojParser)DATA_PTR(self);
1434
+ ojParser p;
1386
1435
  volatile VALUE rbuf = rb_str_new2("");
1387
1436
 
1437
+ TypedData_Get_Struct(self, struct _ojParser, &oj_parser_type, p);
1438
+
1388
1439
  p->start(p);
1389
1440
  while (true) {
1390
1441
  rb_funcall(p->reader, oj_readpartial_id, 2, INT2NUM(16385), rbuf);
1391
1442
  if (0 < RSTRING_LEN(rbuf)) {
1392
- parse(p, (byte *)StringValuePtr(rbuf));
1443
+ parse(p, (byte *)StringValuePtr(rbuf), true);
1444
+ }
1445
+ if (Qtrue == rb_funcall(p->reader, oj_eofq_id, 0)) {
1446
+ if (0 < p->depth) {
1447
+ parse_error(p, "parse error, not closed");
1448
+ }
1449
+ break;
1393
1450
  }
1394
1451
  }
1395
1452
  return Qtrue;
@@ -1403,7 +1460,9 @@ static VALUE load(VALUE self) {
1403
1460
  * Returns the result according to the delegate of the parser.
1404
1461
  */
1405
1462
  static VALUE parser_load(VALUE self, VALUE reader) {
1406
- ojParser p = (ojParser)DATA_PTR(self);
1463
+ ojParser p;
1464
+
1465
+ TypedData_Get_Struct(self, struct _ojParser, &oj_parser_type, p);
1407
1466
 
1408
1467
  parser_reset(p);
1409
1468
  p->reader = reader;
@@ -1420,10 +1479,12 @@ static VALUE parser_load(VALUE self, VALUE reader) {
1420
1479
  * Returns the result according to the delegate of the parser.
1421
1480
  */
1422
1481
  static VALUE parser_file(VALUE self, VALUE filename) {
1423
- ojParser p = (ojParser)DATA_PTR(self);
1482
+ ojParser p;
1424
1483
  const char *path;
1425
1484
  int fd;
1426
1485
 
1486
+ TypedData_Get_Struct(self, struct _ojParser, &oj_parser_type, p);
1487
+
1427
1488
  path = StringValuePtr(filename);
1428
1489
 
1429
1490
  parser_reset(p);
@@ -1449,7 +1510,7 @@ static VALUE parser_file(VALUE self, VALUE filename) {
1449
1510
  while (true) {
1450
1511
  if (0 < (rsize = read(fd, buf, size))) {
1451
1512
  buf[rsize] = '\0';
1452
- parse(p, buf);
1513
+ parse(p, buf, true);
1453
1514
  }
1454
1515
  if (rsize <= 0) {
1455
1516
  if (0 != rsize) {
@@ -1467,7 +1528,9 @@ static VALUE parser_file(VALUE self, VALUE filename) {
1467
1528
  * Returns the current state of the just_one [_Boolean_] option.
1468
1529
  */
1469
1530
  static VALUE parser_just_one(VALUE self) {
1470
- ojParser p = (ojParser)DATA_PTR(self);
1531
+ ojParser p;
1532
+
1533
+ TypedData_Get_Struct(self, struct _ojParser, &oj_parser_type, p);
1471
1534
 
1472
1535
  return p->just_one ? Qtrue : Qfalse;
1473
1536
  }
@@ -1481,7 +1544,9 @@ static VALUE parser_just_one(VALUE self) {
1481
1544
  * Returns the current state of the just_one [_Boolean_] option.
1482
1545
  */
1483
1546
  static VALUE parser_just_one_set(VALUE self, VALUE v) {
1484
- ojParser p = (ojParser)DATA_PTR(self);
1547
+ ojParser p;
1548
+
1549
+ TypedData_Get_Struct(self, struct _ojParser, &oj_parser_type, p);
1485
1550
 
1486
1551
  p->just_one = (Qtrue == v);
1487
1552
 
@@ -1505,7 +1570,7 @@ static VALUE parser_usual(VALUE self) {
1505
1570
  buf_init(&p->buf);
1506
1571
  p->map = value_map;
1507
1572
  oj_set_parser_usual(p);
1508
- usual_parser = Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
1573
+ usual_parser = TypedData_Wrap_Struct(parser_class, &oj_parser_type, p);
1509
1574
  rb_gc_register_address(&usual_parser);
1510
1575
  }
1511
1576
  return usual_parser;
@@ -1528,7 +1593,7 @@ static VALUE parser_saj(VALUE self) {
1528
1593
  buf_init(&p->buf);
1529
1594
  p->map = value_map;
1530
1595
  oj_set_parser_saj(p);
1531
- saj_parser = Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
1596
+ saj_parser = TypedData_Wrap_Struct(parser_class, &oj_parser_type, p);
1532
1597
  rb_gc_register_address(&saj_parser);
1533
1598
  }
1534
1599
  return saj_parser;
@@ -1550,12 +1615,34 @@ static VALUE parser_validate(VALUE self) {
1550
1615
  buf_init(&p->buf);
1551
1616
  p->map = value_map;
1552
1617
  oj_set_parser_validator(p);
1553
- validate_parser = Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
1618
+ validate_parser = TypedData_Wrap_Struct(parser_class, &oj_parser_type, p);
1554
1619
  rb_gc_register_address(&validate_parser);
1555
1620
  }
1556
1621
  return validate_parser;
1557
1622
  }
1558
1623
 
1624
+ static VALUE parser_safe(int argc, VALUE *argv, VALUE self) {
1625
+ VALUE options;
1626
+
1627
+ if (1 == argc) {
1628
+ options = argv[0];
1629
+
1630
+ Check_Type(options, T_HASH);
1631
+ } else {
1632
+ options = rb_hash_new();
1633
+ }
1634
+
1635
+ ojParser p = OJ_R_ALLOC(struct _ojParser);
1636
+
1637
+ memset(p, 0, sizeof(struct _ojParser));
1638
+ buf_init(&p->key);
1639
+ buf_init(&p->buf);
1640
+ p->map = value_map;
1641
+ oj_set_parser_safe(p, options);
1642
+
1643
+ return TypedData_Wrap_Struct(parser_class, &oj_parser_type, p);
1644
+ }
1645
+
1559
1646
  /* Document-class: Oj::Parser
1560
1647
  *
1561
1648
  * A reusable parser that makes use of named delegates to determine the
@@ -1583,4 +1670,7 @@ void oj_parser_init(void) {
1583
1670
  rb_define_module_function(parser_class, "usual", parser_usual, 0);
1584
1671
  rb_define_module_function(parser_class, "saj", parser_saj, 0);
1585
1672
  rb_define_module_function(parser_class, "validate", parser_validate, 0);
1673
+ rb_define_module_function(parser_class, "safe", parser_safe, -1);
1674
+
1675
+ oj_safe_init(parser_class);
1586
1676
  }
data/ext/oj/parser.h CHANGED
@@ -32,9 +32,9 @@ typedef struct _num {
32
32
  long double dub;
33
33
  int64_t fixnum; // holds all digits
34
34
  uint32_t len;
35
- int16_t div; // 10^div
35
+ int16_t div; // 10^div
36
36
  int16_t exp;
37
- uint8_t shift; // shift of fixnum to get decimal
37
+ uint8_t shift; // shift of fixnum to get decimal
38
38
  bool neg;
39
39
  bool exp_neg;
40
40
  // for numbers as strings, reuse buf
@@ -42,6 +42,8 @@ typedef struct _num {
42
42
 
43
43
  struct _ojParser;
44
44
 
45
+ extern const rb_data_type_t oj_parser_type;
46
+
45
47
  typedef struct _funcs {
46
48
  void (*add_null)(struct _ojParser *p);
47
49
  void (*add_true)(struct _ojParser *p);