oj 3.13.13 → 3.13.16

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c59bab43c76d548574059f41aab7b1604fa74161b59bbc0e958a0919e1cdabe
4
- data.tar.gz: 8b60a10bb54b6a03f9a23b1db561a6402d1710c942f01d1f175582a08c566a9c
3
+ metadata.gz: d07b4081b5dda88146594adba591542d11106f1c1eadcf7c56e38358d0ee0af3
4
+ data.tar.gz: 6bdc82c3812f45a8ae9d72ec0b2f43ee223d95ac250399fc8dae8daf34cd3b49
5
5
  SHA512:
6
- metadata.gz: 70ea6740a38970443000f03b67a5222fd450529f6d5d8edbb613feb277ecbeb27350784de26204b962a7815b4bf9cae821cfc8753be6f23ca845d118dfa6465b
7
- data.tar.gz: 57d7f8b7f7f3d4e2ac37949e820d392840c0d3f36ff35be55c5ba0ba589a6656bf572de39c0f82482d23aa992bb3c8b9a634c106c753c077be8ef994c61c251f
6
+ metadata.gz: 4358aa15b7956a5b577163e43fbdc0512212a218124878ceedc2932483f27acabed2d2b92eb888c8e54601f4f4aaf3dce3b959a36effbea989e7e7ea8956d1c1
7
+ data.tar.gz: 1e1710bce62aadfbcc1196357d2e692892b75cc18c982fb6f53c2e35782d9bd2256cb3b6ab98951691430f23e8c2d8db26987a95dcba29f87b472729613b8d2d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 3.13.16 - 2022-07-06
4
+
5
+ - Added line and column as optional arguments to the Oj::Parser.saj parser.
6
+
7
+ ## 3.13.15 - 2022-07-03
8
+
9
+ - Fixed issue dumping NaN value in object mode.
10
+
11
+ ## 3.13.14 - 2022-06-03
12
+
13
+ - Double fclose() due to bad merger fixed by tonobo.
14
+
3
15
  ## 3.13.13 - 2022-05-20
4
16
 
5
17
  - Fixed flooding stdout with debug output when dumping.
data/ext/oj/compat.c CHANGED
@@ -54,7 +54,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
54
54
  } else {
55
55
  rb_hash_aset(parent->val, rkey, rstr);
56
56
  }
57
- if (Yes == pi->options.trace) {
57
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
58
58
  oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
59
59
  }
60
60
  }
@@ -68,7 +68,7 @@ static VALUE start_hash(ParseInfo pi) {
68
68
  } else {
69
69
  h = rb_hash_new();
70
70
  }
71
- if (Yes == pi->options.trace) {
71
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
72
72
  oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
73
73
  }
74
74
  return h;
@@ -93,7 +93,7 @@ static void end_hash(struct _parseInfo *pi) {
93
93
  parent->classname = 0;
94
94
  }
95
95
  }
96
- if (Yes == pi->options.trace) {
96
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
97
97
  oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
98
98
  }
99
99
  }
@@ -110,14 +110,14 @@ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig
110
110
  }
111
111
  }
112
112
  pi->stack.head->val = rstr;
113
- if (Yes == pi->options.trace) {
113
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
114
114
  oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
115
115
  }
116
116
  }
117
117
 
118
118
  static void add_num(ParseInfo pi, NumInfo ni) {
119
119
  pi->stack.head->val = oj_num_as_value(ni);
120
- if (Yes == pi->options.trace) {
120
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
121
121
  oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
122
122
  }
123
123
  }
@@ -138,7 +138,7 @@ static void hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) {
138
138
  } else {
139
139
  rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), rval);
140
140
  }
141
- if (Yes == pi->options.trace) {
141
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
142
142
  oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
143
143
  }
144
144
  }
@@ -157,7 +157,7 @@ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
157
157
  } else {
158
158
  rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), value);
159
159
  }
160
- if (Yes == pi->options.trace) {
160
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
161
161
  oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
162
162
  }
163
163
  }
@@ -166,7 +166,7 @@ static VALUE start_array(ParseInfo pi) {
166
166
  if (Qnil != pi->options.array_class) {
167
167
  return rb_class_new_instance(0, NULL, pi->options.array_class);
168
168
  }
169
- if (Yes == pi->options.trace) {
169
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
170
170
  oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
171
171
  }
172
172
  return rb_ary_new();
@@ -184,7 +184,7 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
184
184
  } else {
185
185
  rb_ary_push(parent->val, rval);
186
186
  }
187
- if (Yes == pi->options.trace) {
187
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
188
188
  oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
189
189
  }
190
190
  }
@@ -201,7 +201,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
201
201
  }
202
202
  }
203
203
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
204
- if (Yes == pi->options.trace) {
204
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
205
205
  oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
206
206
  }
207
207
  }
data/ext/oj/custom.c CHANGED
@@ -959,7 +959,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
959
959
  break;
960
960
  default: break;
961
961
  }
962
- if (Yes == pi->options.trace) {
962
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
963
963
  oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
964
964
  }
965
965
  }
@@ -978,7 +978,7 @@ static void end_hash(struct _parseInfo *pi) {
978
978
  }
979
979
  parent->clas = Qundef;
980
980
  }
981
- if (Yes == pi->options.trace) {
981
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
982
982
  oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
983
983
  }
984
984
  }
@@ -1032,7 +1032,7 @@ static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
1032
1032
  break;
1033
1033
  default: break;
1034
1034
  }
1035
- if (Yes == pi->options.trace) {
1035
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
1036
1036
  oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
1037
1037
  }
1038
1038
  }
@@ -1045,7 +1045,7 @@ static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
1045
1045
  case T_HASH: rb_hash_aset(parent->val, oj_calc_hash_key(pi, kval), value); break;
1046
1046
  default: break;
1047
1047
  }
1048
- if (Yes == pi->options.trace) {
1048
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
1049
1049
  oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
1050
1050
  }
1051
1051
  }
@@ -1055,7 +1055,7 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
1055
1055
  volatile VALUE rval = oj_num_as_value(ni);
1056
1056
 
1057
1057
  rb_ary_push(parent->val, rval);
1058
- if (Yes == pi->options.trace) {
1058
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
1059
1059
  oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
1060
1060
  }
1061
1061
  }
@@ -1072,7 +1072,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
1072
1072
  }
1073
1073
  }
1074
1074
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
1075
- if (Yes == pi->options.trace) {
1075
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
1076
1076
  oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
1077
1077
  }
1078
1078
  }
data/ext/oj/dump.c CHANGED
@@ -32,6 +32,7 @@ static const char nan_val[] = NAN_VAL;
32
32
  typedef unsigned long ulong;
33
33
 
34
34
  static size_t hibit_friendly_size(const uint8_t *str, size_t len);
35
+ static size_t slash_friendly_size(const uint8_t *str, size_t len);
35
36
  static size_t xss_friendly_size(const uint8_t *str, size_t len);
36
37
  static size_t ascii_friendly_size(const uint8_t *str, size_t len);
37
38
 
@@ -59,6 +60,17 @@ static char hibit_friendly_chars[256] = "\
59
60
  11111111111111111111111111111111\
60
61
  11111111111111111111111111111111";
61
62
 
63
+ // JSON standard but escape forward slashes `/`
64
+ static char slash_friendly_chars[256] = "\
65
+ 66666666222622666666666666666666\
66
+ 11211111111111121111111111111111\
67
+ 11111111111111111111111111112111\
68
+ 11111111111111111111111111111111\
69
+ 11111111111111111111111111111111\
70
+ 11111111111111111111111111111111\
71
+ 11111111111111111111111111111111\
72
+ 11111111111111111111111111111111";
73
+
62
74
  // High bit set characters are always encoded as unicode. Worse case is 3
63
75
  // bytes per character in the output. That makes this conservative.
64
76
  static char ascii_friendly_chars[256] = "\
@@ -143,6 +155,10 @@ inline static size_t hibit_friendly_size(const uint8_t *str, size_t len) {
143
155
  return calculate_string_size(str, len, hibit_friendly_chars);
144
156
  }
145
157
 
158
+ inline static size_t slash_friendly_size(const uint8_t *str, size_t len) {
159
+ return calculate_string_size(str, len, slash_friendly_chars);
160
+ }
161
+
146
162
  inline static size_t ascii_friendly_size(const uint8_t *str, size_t len) {
147
163
  return calculate_string_size(str, len, ascii_friendly_chars);
148
164
  }
@@ -365,7 +381,6 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
365
381
  long long sec;
366
382
  long long nsec;
367
383
 
368
- #ifdef HAVE_RB_TIME_TIMESPEC
369
384
  // rb_time_timespec as well as rb_time_timeeval have a bug that causes an
370
385
  // exception to be raised if a time is before 1970 on 32 bit systems so
371
386
  // check the timespec size and use the ruby calls if a 32 bit system.
@@ -378,10 +393,6 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
378
393
  sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
379
394
  nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
380
395
  }
381
- #else
382
- sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
383
- nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
384
- #endif
385
396
 
386
397
  *b-- = '\0';
387
398
  if (withZone) {
@@ -467,7 +478,6 @@ void oj_dump_xml_time(VALUE obj, Out out) {
467
478
  int tzhour, tzmin;
468
479
  char tzsign = '+';
469
480
 
470
- #ifdef HAVE_RB_TIME_TIMESPEC
471
481
  if (16 <= sizeof(struct timespec)) {
472
482
  struct timespec ts = rb_time_timespec(obj);
473
483
 
@@ -477,10 +487,6 @@ void oj_dump_xml_time(VALUE obj, Out out) {
477
487
  sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
478
488
  nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
479
489
  }
480
- #else
481
- sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
482
- nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
483
- #endif
484
490
 
485
491
  assure_size(out, 36);
486
492
  if (9 > out->opts->sec_prec) {
@@ -614,7 +620,6 @@ void oj_write_obj_to_file(VALUE obj, const char *path, Options copts) {
614
620
 
615
621
  oj_out_free(&out);
616
622
 
617
- fclose(f);
618
623
  if (!ok) {
619
624
  int err = ferror(f);
620
625
  fclose(f);
@@ -757,6 +762,11 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
757
762
  cmap = ascii_friendly_chars;
758
763
  size = ascii_friendly_size((uint8_t *)str, cnt);
759
764
  break;
765
+ case SlashEsc:
766
+ has_hi = true;
767
+ cmap = slash_friendly_chars;
768
+ size = slash_friendly_size((uint8_t *)str, cnt);
769
+ break;
760
770
  case XSSEsc:
761
771
  cmap = xss_friendly_chars;
762
772
  size = xss_friendly_size((uint8_t *)str, cnt);
@@ -1131,7 +1141,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1131
1141
  } else if (isnan(d)) {
1132
1142
  if (ObjectMode == out->opts->mode) {
1133
1143
  strcpy(buf, nan_val);
1134
- cnt = sizeof(ninf_val) - 1;
1144
+ cnt = sizeof(nan_val) - 1;
1135
1145
  } else {
1136
1146
  NanDump nd = out->opts->dump_opts.nan_dump;
1137
1147
 
data/ext/oj/dump_compat.c CHANGED
@@ -444,7 +444,6 @@ time_alt(VALUE obj, int depth, Out out) {
444
444
  time_t sec;
445
445
  long long nsec;
446
446
 
447
- #ifdef HAVE_RB_TIME_TIMESPEC
448
447
  if (16 <= sizeof(struct timespec)) {
449
448
  struct timespec ts = rb_time_timespec(obj);
450
449
 
@@ -454,10 +453,6 @@ time_alt(VALUE obj, int depth, Out out) {
454
453
  sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
455
454
  nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
456
455
  }
457
- #else
458
- sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
459
- nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
460
- #endif
461
456
 
462
457
  attrs[0].num = sec;
463
458
  attrs[1].num = nsec;
data/ext/oj/dump_object.c CHANGED
@@ -315,7 +315,6 @@ static void dump_hash_class(VALUE obj, VALUE clas, int depth, Out out) {
315
315
  *out->cur = '\0';
316
316
  }
317
317
 
318
- #ifdef HAVE_RB_IVAR_FOREACH
319
318
  static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
320
319
  Out out = (Out)ov;
321
320
  int depth = out->depth;
@@ -358,7 +357,6 @@ static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
358
357
 
359
358
  return ST_CONTINUE;
360
359
  }
361
- #endif
362
360
 
363
361
  static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
364
362
  dump_hash_class(obj, rb_obj_class(obj), depth, out);
@@ -510,19 +508,8 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
510
508
  default: break;
511
509
  }
512
510
  {
513
- int cnt;
514
- #ifdef HAVE_RB_IVAR_COUNT
515
- cnt = (int)rb_ivar_count(obj);
516
- #else
517
- volatile VALUE vars = rb_funcall2(obj, oj_instance_variables_id, 0, 0);
518
- VALUE * np = RARRAY_PTR(vars);
519
- ID vid;
520
- const char * attr;
521
- int i;
522
- int first = 1;
523
-
524
- cnt = (int)RARRAY_LEN(vars);
525
- #endif
511
+ int cnt = (int)rb_ivar_count(obj);
512
+
526
513
  if (Qundef != clas && 0 < cnt) {
527
514
  *out->cur++ = ',';
528
515
  }
@@ -535,52 +522,10 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
535
522
  }
536
523
  }
537
524
  out->depth = depth + 1;
538
- #ifdef HAVE_RB_IVAR_FOREACH
539
525
  rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
540
526
  if (',' == *(out->cur - 1)) {
541
527
  out->cur--; // backup to overwrite last comma
542
528
  }
543
- #else
544
- size = d2 * out->indent + 1;
545
- for (i = cnt; 0 < i; i--, np++) {
546
- VALUE value;
547
-
548
- vid = rb_to_id(*np);
549
- attr = rb_id2name(vid);
550
- if (Yes == out->opts->ignore_under && '@' == *attr && '_' == attr[1]) {
551
- continue;
552
- }
553
- value = rb_ivar_get(obj, vid);
554
-
555
- if (dump_ignore(out->opts, value)) {
556
- continue;
557
- }
558
- if (out->omit_nil && Qnil == value) {
559
- continue;
560
- }
561
- if (first) {
562
- first = 0;
563
- } else {
564
- *out->cur++ = ',';
565
- }
566
- assure_size(out, size);
567
- fill_indent(out, d2);
568
- if ('@' == *attr) {
569
- attr++;
570
- oj_dump_cstr(attr, strlen(attr), 0, 0, out);
571
- } else {
572
- char buf[32];
573
-
574
- *buf = '~';
575
- strncpy(buf + 1, attr, sizeof(buf) - 2);
576
- buf[sizeof(buf) - 1] = '\0';
577
- oj_dump_cstr(buf, strlen(attr) + 1, 0, 0, out);
578
- }
579
- *out->cur++ = ':';
580
- oj_dump_obj_val(value, d2, out);
581
- assure_size(out, 2);
582
- }
583
- #endif
584
529
  if (rb_obj_is_kind_of(obj, rb_eException)) {
585
530
  volatile VALUE rv;
586
531
 
data/ext/oj/extconf.rb CHANGED
@@ -23,14 +23,10 @@ dflags = {
23
23
  'RSTRUCT_LEN_RETURNS_INTEGER_OBJECT' => ('ruby' == type && '2' == version[0] && '4' == version[1] && '1' >= version[2]) ? 1 : 0,
24
24
  }
25
25
 
26
- have_func('rb_time_timespec')
27
- have_func('rb_ivar_count')
28
- have_func('rb_ivar_foreach')
29
26
  # Support for compaction.
30
27
  have_func('rb_gc_mark_movable')
31
28
  have_func('stpcpy')
32
29
  have_func('pthread_mutex_init')
33
- have_func('rb_enc_associate')
34
30
  have_func('rb_enc_interned_str')
35
31
  have_func('rb_ext_ractor_safe', 'ruby.h')
36
32
  # rb_hash_bulk_insert is deep down in a header not included in normal build and that seems to fool have_func.
@@ -38,6 +34,11 @@ have_func('rb_hash_bulk_insert', 'ruby.h') unless '2' == version[0] && '6' == ve
38
34
 
39
35
  dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
40
36
 
37
+ if try_cflags('-msse4.2')
38
+ $CPPFLAGS += ' -msse4.2'
39
+ dflags['OJ_USE_SSE4_2'] = 1
40
+ end
41
+
41
42
  dflags.each do |k,v|
42
43
  if v.nil?
43
44
  $CPPFLAGS += " -D#{k}"
data/ext/oj/mimic_json.c CHANGED
@@ -388,6 +388,10 @@ static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) {
388
388
  VALUE active_hack[1];
389
389
 
390
390
  if (Qundef == state_class) {
391
+ rb_warn(
392
+ "Oj::Rails.mimic_JSON was called implicitly. "
393
+ "Call it explicitly beforehand if you want to remove this warning."
394
+ );
391
395
  oj_define_mimic_json(0, NULL, Qnil);
392
396
  }
393
397
  active_hack[0] = rb_funcall(state_class, oj_new_id, 0);
@@ -460,7 +464,7 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
460
464
  if (0 == argc) {
461
465
  rb_raise(rb_eArgError, "wrong number of arguments (0))");
462
466
  }
463
- if (1 == argc) {
467
+ if (1 == argc || Qnil == argv[1]) {
464
468
  h = rb_hash_new();
465
469
  } else {
466
470
  h = argv[1];
@@ -481,6 +485,10 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
481
485
  rb_hash_aset(h, oj_array_nl_sym, rb_str_new2("\n"));
482
486
  }
483
487
  if (Qundef == state_class) {
488
+ rb_warn(
489
+ "Oj::Rails.mimic_JSON was called implicitly. "
490
+ "Call it explicitly beforehand if you want to remove this warning."
491
+ );
484
492
  oj_define_mimic_json(0, NULL, Qnil);
485
493
  }
486
494
  rargs[1] = rb_funcall(state_class, oj_new_id, 1, h);
@@ -536,14 +544,6 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE info) {
536
544
  }
537
545
  } else if (oj_decimal_class_sym == k) {
538
546
  pi->options.compat_bigdec = (oj_bigdecimal_class == v);
539
- } else if (oj_max_nesting_sym == k) {
540
- if (Qtrue == v) {
541
- pi->max_depth = 100;
542
- } else if (Qfalse == v || Qnil == v) {
543
- pi->max_depth = 0;
544
- } else if (T_FIXNUM == rb_type(v)) {
545
- pi->max_depth = NUM2INT(v);
546
- }
547
547
  }
548
548
  return ST_CONTINUE;
549
549
  }
@@ -573,11 +573,21 @@ static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
573
573
  pi.max_depth = 100;
574
574
 
575
575
  if (Qnil != ropts) {
576
+ VALUE v;
577
+
576
578
  if (T_HASH != rb_type(ropts)) {
577
579
  rb_raise(rb_eArgError, "options must be a hash.");
578
580
  }
579
581
 
580
582
  rb_hash_foreach(ropts, parse_options_cb, (VALUE)&pi);
583
+ v = rb_hash_lookup(ropts, oj_max_nesting_sym);
584
+ if (Qtrue == v) {
585
+ pi.max_depth = 100;
586
+ } else if (Qfalse == v || Qnil == v) {
587
+ pi.max_depth = 0;
588
+ } else if (T_FIXNUM == rb_type(v)) {
589
+ pi.max_depth = NUM2INT(v);
590
+ }
581
591
  oj_parse_opt_match_string(&pi.options.str_rx, ropts);
582
592
  if (Yes == pi.options.create_ok && Yes == pi.options.sym_key) {
583
593
  rb_raise(rb_eArgError, ":symbolize_names and :create_additions can not both be true.");
data/ext/oj/object.c CHANGED
@@ -445,7 +445,7 @@ WHICH_TYPE:
445
445
  rb_class2name(rb_obj_class(parent->val)));
446
446
  return;
447
447
  }
448
- if (Yes == pi->options.trace) {
448
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
449
449
  oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
450
450
  }
451
451
  }
@@ -516,7 +516,7 @@ WHICH_TYPE:
516
516
  rb_class2name(rb_obj_class(parent->val)));
517
517
  return;
518
518
  }
519
- if (Yes == pi->options.trace) {
519
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
520
520
  oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, rval);
521
521
  }
522
522
  }
@@ -602,13 +602,13 @@ WHICH_TYPE:
602
602
  rb_class2name(rb_obj_class(parent->val)));
603
603
  return;
604
604
  }
605
- if (Yes == pi->options.trace) {
605
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
606
606
  oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, value);
607
607
  }
608
608
  }
609
609
 
610
610
  static VALUE start_hash(ParseInfo pi) {
611
- if (Yes == pi->options.trace) {
611
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
612
612
  oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
613
613
  }
614
614
  return Qnil;
@@ -626,7 +626,7 @@ static void end_hash(ParseInfo pi) {
626
626
  oj_odd_free(oa);
627
627
  parent->odd_args = NULL;
628
628
  }
629
- if (Yes == pi->options.trace) {
629
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
630
630
  oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
631
631
  }
632
632
  }
@@ -654,7 +654,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
654
654
  }
655
655
  rval = str_to_value(pi, str, len, orig);
656
656
  rb_ary_push(stack_peek(&pi->stack)->val, rval);
657
- if (Yes == pi->options.trace) {
657
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
658
658
  oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval);
659
659
  }
660
660
  }
@@ -663,21 +663,21 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
663
663
  volatile VALUE rval = oj_num_as_value(ni);
664
664
 
665
665
  rb_ary_push(stack_peek(&pi->stack)->val, rval);
666
- if (Yes == pi->options.trace) {
666
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
667
667
  oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
668
668
  }
669
669
  }
670
670
 
671
671
  static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
672
672
  pi->stack.head->val = str_to_value(pi, str, len, orig);
673
- if (Yes == pi->options.trace) {
673
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
674
674
  oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
675
675
  }
676
676
  }
677
677
 
678
678
  static void add_num(ParseInfo pi, NumInfo ni) {
679
679
  pi->stack.head->val = oj_num_as_value(ni);
680
- if (Yes == pi->options.trace) {
680
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
681
681
  oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val);
682
682
  }
683
683
  }
data/ext/oj/oj.c CHANGED
@@ -45,7 +45,6 @@ ID oj_hash_key_id;
45
45
  ID oj_hash_set_id;
46
46
  ID oj_hash_start_id;
47
47
  ID oj_iconv_id;
48
- ID oj_instance_variables_id;
49
48
  ID oj_json_create_id;
50
49
  ID oj_length_id;
51
50
  ID oj_new_id;
@@ -137,6 +136,7 @@ static VALUE rails_sym;
137
136
  static VALUE raise_sym;
138
137
  static VALUE ruby_sym;
139
138
  static VALUE sec_prec_sym;
139
+ static VALUE slash_sym;
140
140
  static VALUE strict_sym;
141
141
  static VALUE symbol_keys_sym;
142
142
  static VALUE time_format_sym;
@@ -405,6 +405,7 @@ static VALUE get_def_opts(VALUE self) {
405
405
  switch (oj_default_options.escape_mode) {
406
406
  case NLEsc: rb_hash_aset(opts, escape_mode_sym, newline_sym); break;
407
407
  case JSONEsc: rb_hash_aset(opts, escape_mode_sym, json_sym); break;
408
+ case SlashEsc: rb_hash_aset(opts, escape_mode_sym, slash_sym); break;
408
409
  case XSSEsc: rb_hash_aset(opts, escape_mode_sym, xss_safe_sym); break;
409
410
  case ASCIIEsc: rb_hash_aset(opts, escape_mode_sym, ascii_sym); break;
410
411
  case JXEsc: rb_hash_aset(opts, escape_mode_sym, unicode_xss_sym); break;
@@ -734,6 +735,8 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
734
735
  copts->escape_mode = NLEsc;
735
736
  } else if (json_sym == v) {
736
737
  copts->escape_mode = JSONEsc;
738
+ } else if (slash_sym == v) {
739
+ copts->escape_mode = SlashEsc;
737
740
  } else if (xss_safe_sym == v) {
738
741
  copts->escape_mode = XSSEsc;
739
742
  } else if (ascii_sym == v) {
@@ -1148,7 +1151,17 @@ static VALUE load_file(int argc, VALUE *argv, VALUE self) {
1148
1151
  }
1149
1152
  }
1150
1153
  path = StringValuePtr(*argv);
1151
- if (0 == (fd = open(path, O_RDONLY))) {
1154
+ #ifdef _WIN32
1155
+ {
1156
+ WCHAR *wide_path;
1157
+ wide_path = rb_w32_mbstr_to_wstr(CP_UTF8, path, -1, NULL);
1158
+ fd = rb_w32_wopen(wide_path, O_RDONLY);
1159
+ free(wide_path);
1160
+ }
1161
+ #else
1162
+ fd = open(path, O_RDONLY);
1163
+ #endif
1164
+ if (0 == fd) {
1152
1165
  rb_raise(rb_eIOError, "%s", strerror(errno));
1153
1166
  }
1154
1167
  switch (mode) {
@@ -1814,7 +1827,6 @@ void Init_oj(void) {
1814
1827
  oj_hash_set_id = rb_intern("hash_set");
1815
1828
  oj_hash_start_id = rb_intern("hash_start");
1816
1829
  oj_iconv_id = rb_intern("iconv");
1817
- oj_instance_variables_id = rb_intern("instance_variables");
1818
1830
  oj_json_create_id = rb_intern("json_create");
1819
1831
  oj_length_id = rb_intern("length");
1820
1832
  oj_new_id = rb_intern("new");
@@ -1977,6 +1989,8 @@ void Init_oj(void) {
1977
1989
  rb_gc_register_address(&ruby_sym);
1978
1990
  sec_prec_sym = ID2SYM(rb_intern("second_precision"));
1979
1991
  rb_gc_register_address(&sec_prec_sym);
1992
+ slash_sym = ID2SYM(rb_intern("slash"));
1993
+ rb_gc_register_address(&slash_sym);
1980
1994
  strict_sym = ID2SYM(rb_intern("strict"));
1981
1995
  rb_gc_register_address(&strict_sym);
1982
1996
  symbol_keys_sym = ID2SYM(rb_intern("symbol_keys"));
data/ext/oj/oj.h CHANGED
@@ -66,6 +66,7 @@ typedef enum { UnixTime = 'u', UnixZTime = 'z', XmlTime = 'x', RubyTime = 'r' }
66
66
  typedef enum {
67
67
  NLEsc = 'n',
68
68
  JSONEsc = 'j',
69
+ SlashEsc = 's',
69
70
  XSSEsc = 'x',
70
71
  ASCIIEsc = 'a',
71
72
  JXEsc = 'g', // json gem
@@ -346,7 +347,6 @@ extern ID oj_hash_key_id;
346
347
  extern ID oj_hash_set_id;
347
348
  extern ID oj_hash_start_id;
348
349
  extern ID oj_iconv_id;
349
- extern ID oj_instance_variables_id;
350
350
  extern ID oj_json_create_id;
351
351
  extern ID oj_length_id;
352
352
  extern ID oj_new_id;