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/rails.c CHANGED
@@ -140,7 +140,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
140
140
  volatile VALUE v;
141
141
  int cnt;
142
142
  int i;
143
- int len;
143
+ size_t len;
144
144
  const char *name;
145
145
 
146
146
  #ifdef RSTRUCT_LEN
@@ -161,7 +161,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
161
161
  volatile VALUE s = rb_sym2str(RARRAY_AREF(ma, i));
162
162
 
163
163
  name = RSTRING_PTR(s);
164
- len = (int)RSTRING_LEN(s);
164
+ len = RSTRING_LEN(s);
165
165
  assure_size(out, size + sep_len + 6);
166
166
  if (0 < i) {
167
167
  *out->cur++ = ',';
@@ -205,11 +205,11 @@ static void dump_bigdecimal(VALUE obj, int depth, Out out, bool as_ok) {
205
205
  if ('I' == *str || 'N' == *str || ('-' == *str && 'I' == str[1])) {
206
206
  oj_dump_nil(Qnil, depth, out, false);
207
207
  } else if (out->opts->int_range_max != 0 || out->opts->int_range_min != 0) {
208
- oj_dump_cstr(str, (int)RSTRING_LEN(rstr), 0, 0, out);
208
+ oj_dump_cstr(str, RSTRING_LEN(rstr), 0, 0, out);
209
209
  } else if (Yes == out->opts->bigdec_as_num) {
210
- oj_dump_raw(str, (int)RSTRING_LEN(rstr), out);
210
+ oj_dump_raw(str, RSTRING_LEN(rstr), out);
211
211
  } else {
212
- oj_dump_cstr(str, (int)RSTRING_LEN(rstr), 0, 0, out);
212
+ oj_dump_cstr(str, RSTRING_LEN(rstr), 0, 0, out);
213
213
  }
214
214
  }
215
215
 
@@ -330,14 +330,14 @@ static void dump_timewithzone(VALUE obj, int depth, Out out, bool as_ok) {
330
330
  static void dump_to_s(VALUE obj, int depth, Out out, bool as_ok) {
331
331
  volatile VALUE rstr = oj_safe_string_convert(obj);
332
332
 
333
- oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
333
+ oj_dump_cstr(RSTRING_PTR(rstr), RSTRING_LEN(rstr), 0, 0, out);
334
334
  }
335
335
 
336
336
  static ID parameters_id = 0;
337
337
 
338
338
  typedef struct _strLen {
339
339
  const char *str;
340
- int len;
340
+ size_t len;
341
341
  } *StrLen;
342
342
 
343
343
  static void dump_actioncontroller_parameters(VALUE obj, int depth, Out out, bool as_ok) {
@@ -352,10 +352,10 @@ static StrLen columns_array(VALUE rcols, int *ccnt) {
352
352
  volatile VALUE v;
353
353
  StrLen cp;
354
354
  StrLen cols;
355
- int i;
356
- int cnt = (int)RARRAY_LEN(rcols);
355
+ size_t i;
356
+ size_t cnt = RARRAY_LEN(rcols);
357
357
 
358
- *ccnt = cnt;
358
+ *ccnt = (int)cnt;
359
359
  cols = OJ_R_ALLOC_N(struct _strLen, cnt);
360
360
  for (i = 0, cp = cols; i < cnt; i++, cp++) {
361
361
  v = RARRAY_AREF(rcols, i);
@@ -363,7 +363,7 @@ static StrLen columns_array(VALUE rcols, int *ccnt) {
363
363
  v = oj_safe_string_convert(v);
364
364
  }
365
365
  cp->str = StringValuePtr(v);
366
- cp->len = (int)RSTRING_LEN(v);
366
+ cp->len = RSTRING_LEN(v);
367
367
  }
368
368
  return cols;
369
369
  }
@@ -424,7 +424,8 @@ static void dump_activerecord_result(VALUE obj, int depth, Out out, bool as_ok)
424
424
  volatile VALUE rows;
425
425
  StrLen cols;
426
426
  int ccnt = 0;
427
- int i, rcnt;
427
+ size_t i;
428
+ size_t rcnt;
428
429
  size_t size;
429
430
  int d2 = depth + 1;
430
431
 
@@ -435,7 +436,7 @@ static void dump_activerecord_result(VALUE obj, int depth, Out out, bool as_ok)
435
436
  out->argc = 0;
436
437
  cols = columns_array(rb_ivar_get(obj, columns_id), &ccnt);
437
438
  rows = rb_ivar_get(obj, rows_id);
438
- rcnt = (int)RARRAY_LEN(rows);
439
+ rcnt = RARRAY_LEN(rows);
439
440
  assure_size(out, 2);
440
441
  *out->cur++ = '[';
441
442
  if (out->opts->dump_opts.use) {
@@ -639,6 +640,17 @@ static void encoder_mark(void *ptr) {
639
640
  }
640
641
  }
641
642
 
643
+ static const rb_data_type_t oj_encoder_type = {
644
+ "Oj/encoder",
645
+ {
646
+ encoder_mark,
647
+ encoder_free,
648
+ NULL,
649
+ },
650
+ 0,
651
+ 0,
652
+ };
653
+
642
654
  /* Document-method: new
643
655
  * call-seq: new(options=nil)
644
656
  *
@@ -649,14 +661,16 @@ static VALUE encoder_new(int argc, VALUE *argv, VALUE self) {
649
661
  Encoder e = OJ_R_ALLOC(struct _encoder);
650
662
 
651
663
  e->opts = oj_default_options;
652
- e->arg = Qnil;
653
664
  copy_opts(&ropts, &e->ropts);
654
665
 
655
666
  if (1 <= argc && Qnil != *argv) {
656
- oj_parse_options(*argv, &e->opts);
657
667
  e->arg = *argv;
668
+ } else {
669
+ e->arg = rb_hash_new();
658
670
  }
659
- return Data_Wrap_Struct(encoder_class, encoder_mark, encoder_free, e);
671
+ oj_parse_options(e->arg, &e->opts);
672
+
673
+ return TypedData_Wrap_Struct(encoder_class, &oj_encoder_type, e);
660
674
  }
661
675
 
662
676
  static VALUE resolve_classpath(const char *name) {
@@ -748,7 +762,8 @@ static void optimize(int argc, VALUE *argv, ROptTable rot, bool on) {
748
762
  * - *classes* [_Class_] a list of classes to optimize
749
763
  */
750
764
  static VALUE encoder_optimize(int argc, VALUE *argv, VALUE self) {
751
- Encoder e = (Encoder)DATA_PTR(self);
765
+ Encoder e;
766
+ TypedData_Get_Struct(self, struct _encoder, &oj_encoder_type, e);
752
767
 
753
768
  optimize(argc, argv, &e->ropts, true);
754
769
 
@@ -804,7 +819,8 @@ rails_mimic_json(VALUE self) {
804
819
  * - *classes* [_Class_] a list of classes to deoptimize
805
820
  */
806
821
  static VALUE encoder_deoptimize(int argc, VALUE *argv, VALUE self) {
807
- Encoder e = (Encoder)DATA_PTR(self);
822
+ Encoder e;
823
+ TypedData_Get_Struct(self, struct _encoder, &oj_encoder_type, e);
808
824
 
809
825
  optimize(argc, argv, &e->ropts, false);
810
826
 
@@ -833,8 +849,11 @@ static VALUE rails_deoptimize(int argc, VALUE *argv, VALUE self) {
833
849
  * @return true if the class is being optimized for rails and false otherwise
834
850
  */
835
851
  static VALUE encoder_optimized(VALUE self, VALUE clas) {
836
- Encoder e = (Encoder)DATA_PTR(self);
837
- ROpt ro = oj_rails_get_opt(&e->ropts, clas);
852
+ Encoder e;
853
+ ROpt ro;
854
+
855
+ TypedData_Get_Struct(self, struct _encoder, &oj_encoder_type, e);
856
+ ro = oj_rails_get_opt(&e->ropts, clas);
838
857
 
839
858
  if (NULL == ro) {
840
859
  return Qfalse;
@@ -901,7 +920,7 @@ static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *a
901
920
  if (Yes == copts.circular) {
902
921
  oj_cache8_new(&out.circ_cache);
903
922
  }
904
- // dump_rails_val(*argv, 0, &out, true);
923
+
905
924
  rb_protect(protect_dump, (VALUE)&oo, &line);
906
925
 
907
926
  if (0 == line) {
@@ -917,8 +936,7 @@ static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *a
917
936
  if (0 == out.buf) {
918
937
  rb_raise(rb_eNoMemError, "Not enough memory.");
919
938
  }
920
- rstr = rb_str_new2(out.buf);
921
- rstr = oj_encode(rstr);
939
+ rstr = rb_utf8_str_new_cstr(out.buf);
922
940
  }
923
941
  if (Yes == copts.circular) {
924
942
  oj_cache8_delete(out.circ_cache);
@@ -940,7 +958,8 @@ static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *a
940
958
  * Returns encoded object as a JSON string.
941
959
  */
942
960
  static VALUE encoder_encode(VALUE self, VALUE obj) {
943
- Encoder e = (Encoder)DATA_PTR(self);
961
+ Encoder e;
962
+ TypedData_Get_Struct(self, struct _encoder, &oj_encoder_type, e);
944
963
 
945
964
  if (Qnil != e->arg) {
946
965
  VALUE argv[1] = {e->arg};
@@ -1084,6 +1103,8 @@ static VALUE rails_set_decoder(VALUE self) {
1084
1103
  } else {
1085
1104
  json_error = rb_define_class_under(json, "JSONError", rb_eStandardError);
1086
1105
  }
1106
+
1107
+ rb_global_variable(&oj_json_parser_error_class);
1087
1108
  if (rb_const_defined_at(json, rb_intern("ParserError"))) {
1088
1109
  oj_json_parser_error_class = rb_const_get(json, rb_intern("ParserError"));
1089
1110
  } else {
@@ -1155,7 +1176,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1155
1176
  char buf[64];
1156
1177
  char *b;
1157
1178
  double d = rb_num2dbl(obj);
1158
- int cnt = 0;
1179
+ size_t cnt = 0;
1159
1180
 
1160
1181
  if (0.0 == d) {
1161
1182
  b = buf;
@@ -1176,7 +1197,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1176
1197
  volatile VALUE rstr = oj_safe_string_convert(obj);
1177
1198
 
1178
1199
  strcpy(buf, RSTRING_PTR(rstr));
1179
- cnt = (int)RSTRING_LEN(rstr);
1200
+ cnt = RSTRING_LEN(rstr);
1180
1201
  }
1181
1202
  }
1182
1203
  assure_size(out, cnt);
@@ -1188,7 +1209,8 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1188
1209
 
1189
1210
  static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
1190
1211
  size_t size;
1191
- int i, cnt;
1212
+ size_t i;
1213
+ size_t cnt;
1192
1214
  int d2 = depth + 1;
1193
1215
 
1194
1216
  if (Yes == out->opts->circular) {
@@ -1197,12 +1219,11 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
1197
1219
  return;
1198
1220
  }
1199
1221
  }
1200
- // if (!oj_rails_array_opt && as_ok && 0 < out->argc && rb_respond_to(a, oj_as_json_id)) {
1201
- if (as_ok && 0 < out->argc && rb_respond_to(a, oj_as_json_id)) {
1222
+ if (!oj_rails_array_opt && as_ok && rb_respond_to(a, oj_as_json_id)) {
1202
1223
  dump_as_json(a, depth, out, false);
1203
1224
  return;
1204
1225
  }
1205
- cnt = (int)RARRAY_LEN(a);
1226
+ cnt = RARRAY_LEN(a);
1206
1227
  *out->cur++ = '[';
1207
1228
  size = 2;
1208
1229
  assure_size(out, size);
@@ -1265,18 +1286,19 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
1265
1286
  if (out->omit_nil && Qnil == value) {
1266
1287
  return ST_CONTINUE;
1267
1288
  }
1268
- if (rtype != T_STRING && rtype != T_SYMBOL) {
1269
- key = oj_safe_string_convert(key);
1270
- rtype = rb_type(key);
1289
+ if (NULL != out->opts->dump_opts.only || NULL != out->opts->dump_opts.except) {
1290
+ if (oj_key_skip(key, out->opts->dump_opts.only, out->opts->dump_opts.except)) {
1291
+ return ST_CONTINUE;
1292
+ }
1271
1293
  }
1272
1294
  if (!out->opts->dump_opts.use) {
1273
1295
  size = depth * out->indent + 1;
1274
1296
  assure_size(out, size);
1275
1297
  fill_indent(out, depth);
1276
- if (rtype == T_STRING) {
1277
- oj_dump_str(key, 0, out, false);
1278
- } else {
1279
- oj_dump_sym(key, 0, out, false);
1298
+ switch (rtype) {
1299
+ case T_STRING: oj_dump_str(key, 0, out, false); break;
1300
+ case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
1301
+ default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
1280
1302
  }
1281
1303
  *out->cur++ = ':';
1282
1304
  } else {
@@ -1291,10 +1313,10 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
1291
1313
  APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1292
1314
  }
1293
1315
  }
1294
- if (rtype == T_STRING) {
1295
- oj_dump_str(key, 0, out, false);
1296
- } else {
1297
- oj_dump_sym(key, 0, out, false);
1316
+ switch (rtype) {
1317
+ case T_STRING: oj_dump_str(key, 0, out, false); break;
1318
+ case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
1319
+ default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
1298
1320
  }
1299
1321
  size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
1300
1322
  assure_size(out, size);
@@ -1323,7 +1345,7 @@ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
1323
1345
  return;
1324
1346
  }
1325
1347
  }
1326
- if ((!oj_rails_hash_opt || 0 < out->argc) && as_ok && rb_respond_to(obj, oj_as_json_id)) {
1348
+ if (!oj_rails_hash_opt && as_ok && rb_respond_to(obj, oj_as_json_id)) {
1327
1349
  dump_as_json(obj, depth, out, false);
1328
1350
  return;
1329
1351
  }
data/ext/oj/reader.c CHANGED
@@ -101,7 +101,7 @@ int oj_reader_read(Reader reader) {
101
101
  } else {
102
102
  shift = reader->pro - reader->head - 1; // leave one character so we can backup one
103
103
  }
104
- if (0 >= shift) { /* no space left so allocate more */
104
+ if (0 >= shift) { /* no space left so allocate more */
105
105
  const char *old = reader->head;
106
106
  size_t size = reader->end - reader->head + BUF_PAD;
107
107
 
data/ext/oj/rxclass.c CHANGED
@@ -96,7 +96,7 @@ int oj_rxclass_append(RxClass rc, const char *expr, VALUE clas) {
96
96
  }
97
97
 
98
98
  VALUE
99
- oj_rxclass_match(RxClass rc, const char *str, int len) {
99
+ oj_rxclass_match(RxClass rc, const char *str, size_t len) {
100
100
  RxC rxc;
101
101
  char buf[4096];
102
102
 
data/ext/oj/rxclass.h CHANGED
@@ -19,7 +19,7 @@ typedef struct _rxClass {
19
19
  extern void oj_rxclass_init(RxClass rc);
20
20
  extern void oj_rxclass_cleanup(RxClass rc);
21
21
  extern int oj_rxclass_append(RxClass rc, const char *expr, VALUE clas);
22
- extern VALUE oj_rxclass_match(RxClass rc, const char *str, int len);
22
+ extern VALUE oj_rxclass_match(RxClass rc, const char *str, size_t len);
23
23
  extern void oj_rxclass_copy(RxClass src, RxClass dest);
24
24
  extern void oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas);
25
25
 
data/ext/oj/safe.c ADDED
@@ -0,0 +1,230 @@
1
+
2
+ #include "safe.h"
3
+
4
+ static VALUE max_hash_size_sym, max_array_size_sym, max_depth_sym, max_total_elements_sym, max_hash_size_error_class,
5
+ max_array_size_error_class, max_depth_error_class, max_total_elements_error_class;
6
+
7
+ static void check_object_size(safe_T safe) {
8
+ if (NIL_P(safe->max_hash_size)) {
9
+ return;
10
+ }
11
+
12
+ struct _usual usual = safe->usual;
13
+ Col current_object_location = usual.ctail - 1;
14
+
15
+ long int number_of_items_in_stack = usual.vtail - usual.vhead;
16
+ long int number_of_items_in_hash = (number_of_items_in_stack - current_object_location->vi - 1) / 2;
17
+
18
+ if (safe->max_hash_size > number_of_items_in_hash) {
19
+ return;
20
+ }
21
+
22
+ rb_raise(max_hash_size_error_class, "Too many object items!");
23
+ }
24
+
25
+ static void check_array_size(safe_T safe) {
26
+ if (NIL_P(safe->max_array_size)) {
27
+ return;
28
+ }
29
+
30
+ struct _usual usual = safe->usual;
31
+ Col current_object_location = usual.ctail - 1;
32
+
33
+ long int number_of_items_in_stack = usual.vtail - usual.vhead;
34
+ long int number_of_items_in_array = number_of_items_in_stack - current_object_location->vi - 1;
35
+
36
+ if (safe->max_array_size > number_of_items_in_array) {
37
+ return;
38
+ }
39
+
40
+ rb_raise(max_array_size_error_class, "Too many array items!");
41
+ }
42
+
43
+ static void check_max_depth(safe_T safe, ojParser p) {
44
+ if (NIL_P(safe->max_depth) || safe->max_depth >= (p->depth + 1)) {
45
+ return;
46
+ }
47
+
48
+ rb_raise(max_depth_error_class, "JSON is too deep!");
49
+ }
50
+
51
+ static void check_max_total_elements(safe_T safe) {
52
+ /*
53
+ * We check if `max_total_elements` is greater than `current_elements_count`
54
+ * (instead of greater than or equal) because top-level elements (e.g., [],
55
+ * null, true) are not counted. As a result, `current_elements_count`
56
+ * always holds one less than the actual total.
57
+ */
58
+ if (NIL_P(safe->max_total_elements) || safe->max_total_elements > safe->current_elements_count) {
59
+ return;
60
+ }
61
+
62
+ rb_raise(max_total_elements_error_class, "Too many elements!");
63
+ }
64
+
65
+ static void safe_start(ojParser p) {
66
+ safe_T safe = (safe_T)p->ctx;
67
+
68
+ safe->current_hash_size = 0;
69
+ safe->current_array_size = 0;
70
+ safe->current_elements_count = 0;
71
+
72
+ safe->delegated_start_func(p);
73
+ }
74
+
75
+ static void safe_open_object(ojParser p) {
76
+ safe_T safe = (safe_T)p->ctx;
77
+
78
+ safe->current_hash_size++;
79
+ safe->current_elements_count++;
80
+
81
+ check_array_size(safe);
82
+ check_max_depth(safe, p);
83
+ check_max_total_elements(safe);
84
+
85
+ safe->delegated_open_object_func(p);
86
+ }
87
+
88
+ static void safe_open_array(ojParser p) {
89
+ safe_T safe = (safe_T)p->ctx;
90
+
91
+ safe->current_array_size++;
92
+ safe->current_elements_count++;
93
+
94
+ check_array_size(safe);
95
+ check_max_depth(safe, p);
96
+ check_max_total_elements(safe);
97
+
98
+ safe->delegated_open_array_func(p);
99
+ }
100
+
101
+ DEFINE_DELEGATED_FUNCTION(add_null);
102
+ DEFINE_DELEGATED_FUNCTION(add_true);
103
+ DEFINE_DELEGATED_FUNCTION(add_false);
104
+ DEFINE_DELEGATED_FUNCTION(add_int);
105
+ DEFINE_DELEGATED_FUNCTION(add_float);
106
+ DEFINE_DELEGATED_FUNCTION(add_big);
107
+ DEFINE_DELEGATED_FUNCTION(add_str);
108
+
109
+ static void safe_open_object_key(ojParser p) {
110
+ safe_T safe = (safe_T)p->ctx;
111
+
112
+ safe->current_hash_size++;
113
+ safe->current_elements_count += 2;
114
+
115
+ check_object_size(safe);
116
+ check_max_depth(safe, p);
117
+ check_max_total_elements(safe);
118
+
119
+ safe->delegated_open_object_key_func(p);
120
+ }
121
+
122
+ static void safe_open_array_key(ojParser p) {
123
+ safe_T safe = (safe_T)p->ctx;
124
+
125
+ safe->current_array_size++;
126
+ safe->current_elements_count += 2;
127
+
128
+ check_object_size(safe);
129
+ check_max_depth(safe, p);
130
+ check_max_total_elements(safe);
131
+
132
+ safe->delegated_open_array_key_func(p);
133
+ }
134
+
135
+ DEFINE_DELEGATED_OBJECT_FUNCTION(add_null);
136
+ DEFINE_DELEGATED_OBJECT_FUNCTION(add_true);
137
+ DEFINE_DELEGATED_OBJECT_FUNCTION(add_false);
138
+ DEFINE_DELEGATED_OBJECT_FUNCTION(add_int);
139
+ DEFINE_DELEGATED_OBJECT_FUNCTION(add_float);
140
+ DEFINE_DELEGATED_OBJECT_FUNCTION(add_big);
141
+ DEFINE_DELEGATED_OBJECT_FUNCTION(add_str);
142
+
143
+ void oj_init_safe_parser(ojParser p, safe_T safe, VALUE options) {
144
+ // Safe parser inherits all members of usual parser
145
+ oj_init_usual(p, &safe->usual);
146
+
147
+ safe->delegated_start_func = p->start;
148
+ p->start = safe_start;
149
+
150
+ Funcs f;
151
+
152
+ // Array parser functions
153
+ f = &p->funcs[ARRAY_FUN];
154
+ safe->delegated_open_object_func = f->open_object;
155
+ f->open_object = safe_open_object;
156
+ safe->delegated_open_array_func = f->open_array;
157
+ f->open_array = safe_open_array;
158
+ // The following overrides are done for counting objects
159
+ safe->delegated_add_null_func = f->add_null;
160
+ f->add_null = safe_add_null;
161
+ safe->delegated_add_true_func = f->add_true;
162
+ f->add_true = safe_add_true;
163
+ safe->delegated_add_false_func = f->add_false;
164
+ f->add_false = safe_add_false;
165
+ safe->delegated_add_int_func = f->add_int;
166
+ f->add_int = safe_add_int;
167
+ safe->delegated_add_float_func = f->add_float;
168
+ f->add_float = safe_add_float;
169
+ safe->delegated_add_big_func = f->add_big;
170
+ f->add_big = safe_add_big;
171
+ safe->delegated_add_str_func = f->add_str;
172
+ f->add_str = safe_add_str;
173
+
174
+ // Object parser functions
175
+ f = &p->funcs[OBJECT_FUN];
176
+ safe->delegated_open_object_key_func = f->open_object;
177
+ f->open_object = safe_open_object_key;
178
+ safe->delegated_open_array_key_func = f->open_array;
179
+ f->open_array = safe_open_array_key;
180
+ // The following overrides are done for counting objects
181
+ safe->delegated_add_null_key_func = f->add_null;
182
+ f->add_null = safe_add_null_key;
183
+ safe->delegated_add_true_key_func = f->add_true;
184
+ f->add_true = safe_add_true_key;
185
+ safe->delegated_add_false_key_func = f->add_false;
186
+ f->add_false = safe_add_false_key;
187
+ safe->delegated_add_int_key_func = f->add_int;
188
+ f->add_int = safe_add_int_key;
189
+ safe->delegated_add_float_key_func = f->add_float;
190
+ f->add_float = safe_add_float_key;
191
+ safe->delegated_add_big_key_func = f->add_big;
192
+ f->add_big = safe_add_big_key;
193
+ safe->delegated_add_str_key_func = f->add_str;
194
+ f->add_str = safe_add_str_key;
195
+
196
+ SET_CONFIG(max_hash_size);
197
+ SET_CONFIG(max_array_size);
198
+ SET_CONFIG(max_depth);
199
+ SET_CONFIG(max_total_elements);
200
+ }
201
+
202
+ void oj_set_parser_safe(ojParser p, VALUE options) {
203
+ safe_T s = OJ_R_ALLOC(struct _safe_S);
204
+
205
+ oj_init_safe_parser(p, s, options);
206
+ }
207
+
208
+ void oj_safe_init(VALUE parser_class) {
209
+ VALUE validation_error_class = rb_define_class_under(parser_class, "ValidationError", rb_eRuntimeError);
210
+
211
+ max_hash_size_error_class = rb_define_class_under(parser_class, "HashSizeError", validation_error_class);
212
+ max_array_size_error_class = rb_define_class_under(parser_class, "ArraySizeError", validation_error_class);
213
+ max_depth_error_class = rb_define_class_under(parser_class, "DepthError", validation_error_class);
214
+ max_total_elements_error_class = rb_define_class_under(parser_class, "TotalElementsError", validation_error_class);
215
+
216
+ rb_gc_register_address(&max_hash_size_error_class);
217
+ rb_gc_register_address(&max_array_size_error_class);
218
+ rb_gc_register_address(&max_depth_error_class);
219
+ rb_gc_register_address(&max_total_elements_error_class);
220
+
221
+ max_hash_size_sym = ID2SYM(rb_intern("max_hash_size"));
222
+ max_array_size_sym = ID2SYM(rb_intern("max_array_size"));
223
+ max_depth_sym = ID2SYM(rb_intern("max_depth"));
224
+ max_total_elements_sym = ID2SYM(rb_intern("max_total_elements"));
225
+
226
+ rb_gc_register_address(&max_hash_size_sym);
227
+ rb_gc_register_address(&max_array_size_sym);
228
+ rb_gc_register_address(&max_depth_sym);
229
+ rb_gc_register_address(&max_total_elements_sym);
230
+ }
data/ext/oj/safe.h ADDED
@@ -0,0 +1,79 @@
1
+ #include <ruby.h>
2
+
3
+ #include "parser.h"
4
+ #include "usual.h"
5
+
6
+ #define SET_CONFIG(config_name) \
7
+ do { \
8
+ VALUE rb_##config_name = rb_hash_aref(options, config_name##_sym); \
9
+ \
10
+ if (RB_INTEGER_TYPE_P(rb_##config_name)) { \
11
+ safe->config_name = NUM2LONG(rb_##config_name); \
12
+ } else if (!NIL_P(rb_##config_name)) { \
13
+ rb_raise(rb_eArgError, "Incorrect value provided for `" #config_name "`"); \
14
+ } else { \
15
+ safe->config_name = Qnil; \
16
+ } \
17
+ } while (0);
18
+
19
+ #define DEFINE_DELEGATED_FUNCTION(function_name) \
20
+ static void safe_##function_name(ojParser p) { \
21
+ safe_T safe = (safe_T)p->ctx; \
22
+ \
23
+ safe->current_elements_count++; \
24
+ \
25
+ check_array_size(safe); \
26
+ check_max_total_elements(safe); \
27
+ \
28
+ safe->delegated_##function_name##_func(p); \
29
+ }
30
+
31
+ #define DEFINE_DELEGATED_OBJECT_FUNCTION(function_name) \
32
+ static void safe_##function_name##_key(ojParser p) { \
33
+ safe_T safe = (safe_T)p->ctx; \
34
+ \
35
+ safe->current_elements_count += 2; \
36
+ \
37
+ check_object_size(safe); \
38
+ check_max_total_elements(safe); \
39
+ \
40
+ safe->delegated_##function_name##_key_func(p); \
41
+ }
42
+
43
+ typedef struct _safe_S {
44
+ struct _usual usual;
45
+
46
+ long int max_hash_size;
47
+ long int max_array_size;
48
+ long int max_depth;
49
+ long int max_total_elements;
50
+ long int max_json_size_bytes;
51
+
52
+ long int current_hash_size;
53
+ long int current_array_size;
54
+ long int current_elements_count;
55
+
56
+ void (*delegated_start_func)(struct _ojParser *p);
57
+
58
+ // Array functions
59
+ void (*delegated_open_object_func)(struct _ojParser *p);
60
+ void (*delegated_open_array_func)(struct _ojParser *p);
61
+ void (*delegated_add_null_func)(struct _ojParser *p);
62
+ void (*delegated_add_true_func)(struct _ojParser *p);
63
+ void (*delegated_add_false_func)(struct _ojParser *p);
64
+ void (*delegated_add_int_func)(struct _ojParser *p);
65
+ void (*delegated_add_float_func)(struct _ojParser *p);
66
+ void (*delegated_add_big_func)(struct _ojParser *p);
67
+ void (*delegated_add_str_func)(struct _ojParser *p);
68
+
69
+ // Object functions
70
+ void (*delegated_open_object_key_func)(struct _ojParser *p);
71
+ void (*delegated_open_array_key_func)(struct _ojParser *p);
72
+ void (*delegated_add_null_key_func)(struct _ojParser *p);
73
+ void (*delegated_add_true_key_func)(struct _ojParser *p);
74
+ void (*delegated_add_false_key_func)(struct _ojParser *p);
75
+ void (*delegated_add_int_key_func)(struct _ojParser *p);
76
+ void (*delegated_add_float_key_func)(struct _ojParser *p);
77
+ void (*delegated_add_big_key_func)(struct _ojParser *p);
78
+ void (*delegated_add_str_key_func)(struct _ojParser *p);
79
+ } *safe_T;