oj 3.13.11 → 3.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +74 -0
  3. data/README.md +4 -2
  4. data/ext/oj/buf.h +11 -6
  5. data/ext/oj/cache.c +25 -24
  6. data/ext/oj/cache8.c +10 -9
  7. data/ext/oj/circarray.c +8 -6
  8. data/ext/oj/circarray.h +2 -2
  9. data/ext/oj/code.c +17 -24
  10. data/ext/oj/code.h +2 -2
  11. data/ext/oj/compat.c +17 -44
  12. data/ext/oj/custom.c +70 -141
  13. data/ext/oj/debug.c +3 -9
  14. data/ext/oj/dump.c +128 -118
  15. data/ext/oj/dump.h +12 -8
  16. data/ext/oj/dump_compat.c +564 -641
  17. data/ext/oj/dump_leaf.c +17 -63
  18. data/ext/oj/dump_object.c +70 -199
  19. data/ext/oj/dump_strict.c +22 -46
  20. data/ext/oj/encoder.c +1 -1
  21. data/ext/oj/err.c +2 -13
  22. data/ext/oj/err.h +9 -12
  23. data/ext/oj/extconf.rb +14 -5
  24. data/ext/oj/fast.c +75 -103
  25. data/ext/oj/intern.c +52 -50
  26. data/ext/oj/intern.h +4 -8
  27. data/ext/oj/mem.c +318 -0
  28. data/ext/oj/mem.h +53 -0
  29. data/ext/oj/mimic_json.c +75 -47
  30. data/ext/oj/object.c +49 -66
  31. data/ext/oj/odd.c +89 -67
  32. data/ext/oj/odd.h +15 -15
  33. data/ext/oj/oj.c +140 -99
  34. data/ext/oj/oj.h +80 -51
  35. data/ext/oj/parse.c +162 -184
  36. data/ext/oj/parse.h +7 -10
  37. data/ext/oj/parser.c +89 -34
  38. data/ext/oj/parser.h +18 -7
  39. data/ext/oj/rails.c +82 -146
  40. data/ext/oj/rails.h +1 -1
  41. data/ext/oj/reader.c +11 -12
  42. data/ext/oj/reader.h +4 -2
  43. data/ext/oj/resolve.c +3 -4
  44. data/ext/oj/rxclass.c +6 -5
  45. data/ext/oj/rxclass.h +1 -1
  46. data/ext/oj/saj.c +20 -31
  47. data/ext/oj/saj2.c +329 -93
  48. data/ext/oj/saj2.h +23 -0
  49. data/ext/oj/scp.c +3 -14
  50. data/ext/oj/sparse.c +26 -70
  51. data/ext/oj/stream_writer.c +12 -22
  52. data/ext/oj/strict.c +20 -52
  53. data/ext/oj/string_writer.c +21 -21
  54. data/ext/oj/trace.h +31 -4
  55. data/ext/oj/usual.c +105 -150
  56. data/ext/oj/usual.h +68 -0
  57. data/ext/oj/util.h +1 -1
  58. data/ext/oj/val_stack.c +1 -1
  59. data/ext/oj/val_stack.h +8 -7
  60. data/ext/oj/validate.c +21 -26
  61. data/ext/oj/wab.c +31 -68
  62. data/lib/oj/active_support_helper.rb +0 -1
  63. data/lib/oj/bag.rb +7 -1
  64. data/lib/oj/easy_hash.rb +4 -5
  65. data/lib/oj/error.rb +0 -1
  66. data/lib/oj/json.rb +4 -2
  67. data/lib/oj/mimic.rb +4 -2
  68. data/lib/oj/saj.rb +20 -6
  69. data/lib/oj/state.rb +9 -6
  70. data/lib/oj/version.rb +1 -2
  71. data/lib/oj.rb +2 -0
  72. data/pages/Compatibility.md +1 -1
  73. data/pages/InstallOptions.md +20 -0
  74. data/pages/Options.md +10 -0
  75. data/test/_test_active.rb +8 -9
  76. data/test/_test_active_mimic.rb +7 -8
  77. data/test/_test_mimic_rails.rb +17 -20
  78. data/test/activerecord/result_test.rb +5 -6
  79. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  80. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  81. data/test/{activesupport5 → activesupport7}/encoding_test.rb +20 -34
  82. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  83. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  84. data/test/files.rb +15 -15
  85. data/test/foo.rb +9 -71
  86. data/test/helper.rb +11 -8
  87. data/test/isolated/shared.rb +3 -2
  88. data/test/json_gem/json_addition_test.rb +2 -2
  89. data/test/json_gem/json_common_interface_test.rb +4 -4
  90. data/test/json_gem/json_encoding_test.rb +0 -0
  91. data/test/json_gem/json_ext_parser_test.rb +1 -0
  92. data/test/json_gem/json_fixtures_test.rb +3 -2
  93. data/test/json_gem/json_generator_test.rb +48 -36
  94. data/test/json_gem/json_generic_object_test.rb +11 -11
  95. data/test/json_gem/json_parser_test.rb +54 -47
  96. data/test/json_gem/json_string_matching_test.rb +9 -9
  97. data/test/json_gem/test_helper.rb +7 -3
  98. data/test/mem.rb +13 -12
  99. data/test/perf.rb +21 -26
  100. data/test/perf_compat.rb +31 -33
  101. data/test/perf_dump.rb +50 -0
  102. data/test/perf_fast.rb +80 -82
  103. data/test/perf_file.rb +27 -29
  104. data/test/perf_object.rb +65 -69
  105. data/test/perf_once.rb +12 -11
  106. data/test/perf_parser.rb +42 -48
  107. data/test/perf_saj.rb +46 -54
  108. data/test/perf_scp.rb +57 -69
  109. data/test/perf_simple.rb +41 -39
  110. data/test/perf_strict.rb +68 -70
  111. data/test/perf_wab.rb +67 -69
  112. data/test/prec.rb +3 -3
  113. data/test/sample/change.rb +0 -1
  114. data/test/sample/dir.rb +0 -1
  115. data/test/sample/doc.rb +0 -1
  116. data/test/sample/file.rb +0 -1
  117. data/test/sample/group.rb +0 -1
  118. data/test/sample/hasprops.rb +0 -1
  119. data/test/sample/layer.rb +0 -1
  120. data/test/sample/rect.rb +0 -1
  121. data/test/sample/shape.rb +0 -1
  122. data/test/sample/text.rb +0 -1
  123. data/test/sample.rb +16 -16
  124. data/test/sample_json.rb +8 -8
  125. data/test/test_compat.rb +76 -42
  126. data/test/test_custom.rb +72 -51
  127. data/test/test_debian.rb +7 -10
  128. data/test/test_fast.rb +86 -90
  129. data/test/test_file.rb +41 -30
  130. data/test/test_gc.rb +16 -5
  131. data/test/test_generate.rb +5 -5
  132. data/test/test_hash.rb +4 -4
  133. data/test/test_integer_range.rb +9 -9
  134. data/test/test_null.rb +20 -20
  135. data/test/test_object.rb +85 -96
  136. data/test/test_parser.rb +6 -22
  137. data/test/test_parser_debug.rb +27 -0
  138. data/test/test_parser_saj.rb +115 -23
  139. data/test/test_parser_usual.rb +6 -6
  140. data/test/test_rails.rb +2 -2
  141. data/test/test_saj.rb +10 -8
  142. data/test/test_scp.rb +37 -39
  143. data/test/test_strict.rb +30 -32
  144. data/test/test_various.rb +147 -99
  145. data/test/test_wab.rb +48 -44
  146. data/test/test_writer.rb +47 -47
  147. data/test/tests.rb +13 -4
  148. data/test/tests_mimic.rb +12 -3
  149. data/test/tests_mimic_addition.rb +12 -3
  150. metadata +33 -144
  151. data/test/activesupport4/decoding_test.rb +0 -108
  152. data/test/activesupport4/encoding_test.rb +0 -531
  153. data/test/activesupport4/test_helper.rb +0 -41
  154. data/test/activesupport5/test_helper.rb +0 -72
  155. data/test/bar.rb +0 -16
  156. data/test/baz.rb +0 -16
  157. data/test/bug.rb +0 -16
  158. data/test/zoo.rb +0 -13
data/ext/oj/compat.c CHANGED
@@ -6,13 +6,14 @@
6
6
  #include "encode.h"
7
7
  #include "err.h"
8
8
  #include "intern.h"
9
+ #include "mem.h"
9
10
  #include "oj.h"
10
11
  #include "parse.h"
11
12
  #include "resolve.h"
12
13
  #include "trace.h"
13
14
 
14
15
  static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
15
- const char * key = kval->key;
16
+ const char *key = kval->key;
16
17
  int klen = kval->klen;
17
18
  Val parent = stack_peek(&pi->stack);
18
19
  volatile VALUE rkey = kval->key_val;
@@ -30,7 +31,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
30
31
  if (Yes == pi->options.sym_key) {
31
32
  rkey = ID2SYM(rb_intern3(key, klen, oj_utf8_encoding));
32
33
  } else {
33
- rkey = rb_utf8_str_new(key, klen);
34
+ rkey = rb_utf8_str_new(key, klen);
34
35
  }
35
36
  } else if (Yes == pi->options.sym_key) {
36
37
  rkey = oj_sym_intern(key, klen);
@@ -54,9 +55,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
54
55
  } else {
55
56
  rb_hash_aset(parent->val, rkey, rstr);
56
57
  }
57
- if (Yes == pi->options.trace) {
58
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
59
- }
58
+ TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rstr);
60
59
  }
61
60
  }
62
61
 
@@ -68,9 +67,7 @@ static VALUE start_hash(ParseInfo pi) {
68
67
  } else {
69
68
  h = rb_hash_new();
70
69
  }
71
- if (Yes == pi->options.trace) {
72
- oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
73
- }
70
+ TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
74
71
  return h;
75
72
  }
76
73
 
@@ -89,13 +86,11 @@ static void end_hash(struct _parseInfo *pi) {
89
86
  }
90
87
  }
91
88
  if (0 != parent->classname) {
92
- xfree((char *)parent->classname);
89
+ OJ_R_FREE((char *)parent->classname);
93
90
  parent->classname = 0;
94
91
  }
95
92
  }
96
- if (Yes == pi->options.trace) {
97
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
98
- }
93
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
99
94
  }
100
95
 
101
96
  static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
@@ -110,37 +105,27 @@ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig
110
105
  }
111
106
  }
112
107
  pi->stack.head->val = rstr;
113
- if (Yes == pi->options.trace) {
114
- oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
115
- }
108
+ TRACE_PARSE_CALL(pi->options.trace, "add_string", pi, rstr);
116
109
  }
117
110
 
118
111
  static void add_num(ParseInfo pi, NumInfo ni) {
119
112
  pi->stack.head->val = oj_num_as_value(ni);
120
- if (Yes == pi->options.trace) {
121
- oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
122
- }
113
+ TRACE_PARSE_CALL(pi->options.trace, "add_number", pi, pi->stack.head->val);
123
114
  }
124
115
 
125
116
  static void hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) {
126
117
  volatile VALUE rval = oj_num_as_value(ni);
127
118
 
128
- if (!oj_use_hash_alt && rb_cHash != rb_obj_class(parent->val)) {
119
+ if (rb_cHash != rb_obj_class(parent->val)) {
129
120
  // The rb_hash_set would still work but the unit tests for the
130
121
  // json gem require the less efficient []= method be called to set
131
122
  // values. Even using the store method to set the values will fail
132
123
  // the unit tests.
133
- rb_funcall(stack_peek(&pi->stack)->val,
134
- rb_intern("[]="),
135
- 2,
136
- oj_calc_hash_key(pi, parent),
137
- rval);
124
+ rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, oj_calc_hash_key(pi, parent), rval);
138
125
  } else {
139
126
  rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), rval);
140
127
  }
141
- if (Yes == pi->options.trace) {
142
- oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
143
- }
128
+ TRACE_PARSE_CALL(pi->options.trace, "set_number", pi, rval);
144
129
  }
145
130
 
146
131
  static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
@@ -149,26 +134,18 @@ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
149
134
  // json gem require the less efficient []= method be called to set
150
135
  // values. Even using the store method to set the values will fail
151
136
  // the unit tests.
152
- rb_funcall(stack_peek(&pi->stack)->val,
153
- rb_intern("[]="),
154
- 2,
155
- oj_calc_hash_key(pi, parent),
156
- value);
137
+ rb_funcall(stack_peek(&pi->stack)->val, rb_intern("[]="), 2, oj_calc_hash_key(pi, parent), value);
157
138
  } else {
158
139
  rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), value);
159
140
  }
160
- if (Yes == pi->options.trace) {
161
- oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
162
- }
141
+ TRACE_PARSE_CALL(pi->options.trace, "set_value", pi, value);
163
142
  }
164
143
 
165
144
  static VALUE start_array(ParseInfo pi) {
166
145
  if (Qnil != pi->options.array_class) {
167
146
  return rb_class_new_instance(0, NULL, pi->options.array_class);
168
147
  }
169
- if (Yes == pi->options.trace) {
170
- oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
171
- }
148
+ TRACE_PARSE_IN(pi->options.trace, "start_array", pi);
172
149
  return rb_ary_new();
173
150
  }
174
151
 
@@ -184,9 +161,7 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
184
161
  } else {
185
162
  rb_ary_push(parent->val, rval);
186
163
  }
187
- if (Yes == pi->options.trace) {
188
- oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
189
- }
164
+ TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, rval);
190
165
  }
191
166
 
192
167
  static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
@@ -201,9 +176,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
201
176
  }
202
177
  }
203
178
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
204
- if (Yes == pi->options.trace) {
205
- oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
206
- }
179
+ TRACE_PARSE_CALL(pi->options.trace, "append_string", pi, rstr);
207
180
  }
208
181
 
209
182
  void oj_set_compat_callbacks(ParseInfo pi) {
data/ext/oj/custom.c CHANGED
@@ -9,6 +9,7 @@
9
9
  #include "encode.h"
10
10
  #include "err.h"
11
11
  #include "intern.h"
12
+ #include "mem.h"
12
13
  #include "odd.h"
13
14
  #include "oj.h"
14
15
  #include "parse.h"
@@ -24,21 +25,21 @@ static void dump_obj_str(VALUE obj, int depth, Out out) {
24
25
  {"s", 1, Qnil},
25
26
  {NULL, 0, Qnil},
26
27
  };
27
- attrs->value = rb_funcall(obj, oj_to_s_id, 0);
28
+ attrs->value = oj_safe_string_convert(obj);
28
29
 
29
30
  oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
30
31
  }
31
32
 
32
33
  static void dump_obj_as_str(VALUE obj, int depth, Out out) {
33
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
34
- const char * str = RSTRING_PTR(rstr);
34
+ volatile VALUE rstr = oj_safe_string_convert(obj);
35
+ const char *str = RSTRING_PTR(rstr);
35
36
 
36
37
  oj_dump_cstr(str, RSTRING_LEN(rstr), 0, 0, out);
37
38
  }
38
39
 
39
40
  static void bigdecimal_dump(VALUE obj, int depth, Out out) {
40
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
41
- const char * str = RSTRING_PTR(rstr);
41
+ volatile VALUE rstr = oj_safe_string_convert(obj);
42
+ const char *str = RSTRING_PTR(rstr);
42
43
  int len = (int)RSTRING_LEN(rstr);
43
44
 
44
45
  if (0 == strcasecmp("Infinity", str)) {
@@ -82,8 +83,7 @@ static VALUE complex_load(VALUE clas, VALUE args) {
82
83
  real_id = rb_intern("real");
83
84
  imag_id = rb_intern("imag");
84
85
  }
85
- return rb_complex_new(rb_hash_aref(args, rb_id2str(real_id)),
86
- rb_hash_aref(args, rb_id2str(imag_id)));
86
+ return rb_complex_new(rb_hash_aref(args, rb_id2str(real_id)), rb_hash_aref(args, rb_id2str(imag_id)));
87
87
  }
88
88
 
89
89
  static void time_dump(VALUE obj, int depth, Out out) {
@@ -246,8 +246,7 @@ static VALUE rational_load(VALUE clas, VALUE args) {
246
246
  numerator_id = rb_intern("numerator");
247
247
  denominator_id = rb_intern("denominator");
248
248
  }
249
- return rb_rational_new(rb_hash_aref(args, rb_id2str(numerator_id)),
250
- rb_hash_aref(args, rb_id2str(denominator_id)));
249
+ return rb_rational_new(rb_hash_aref(args, rb_id2str(numerator_id)), rb_hash_aref(args, rb_id2str(denominator_id)));
251
250
  }
252
251
 
253
252
  static VALUE regexp_load(VALUE clas, VALUE args) {
@@ -292,38 +291,33 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
292
291
  assure_size(out, depth * out->indent + 1);
293
292
  fill_indent(out, depth);
294
293
  } else {
295
- assure_size(out,
296
- depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
294
+ assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
297
295
  if (0 < out->opts->dump_opts.hash_size) {
298
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
299
- out->cur += out->opts->dump_opts.hash_size;
296
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
300
297
  }
301
298
  if (0 < out->opts->dump_opts.indent_size) {
302
299
  int i;
303
300
 
304
301
  for (i = depth; 0 < i; i--) {
305
- strcpy(out->cur, out->opts->dump_opts.indent_str);
306
- out->cur += out->opts->dump_opts.indent_size;
302
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
307
303
  }
308
304
  }
309
305
  }
310
306
  switch (rb_type(key)) {
311
307
  case T_STRING: oj_dump_str(key, 0, out, false); break;
312
308
  case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
313
- default: oj_dump_str(rb_funcall(key, oj_to_s_id, 0), 0, out, false); break;
309
+ default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
314
310
  }
315
311
  if (!out->opts->dump_opts.use) {
316
312
  *out->cur++ = ':';
317
313
  } else {
318
314
  assure_size(out, out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2);
319
315
  if (0 < out->opts->dump_opts.before_size) {
320
- strcpy(out->cur, out->opts->dump_opts.before_sep);
321
- out->cur += out->opts->dump_opts.before_size;
316
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
322
317
  }
323
318
  *out->cur++ = ':';
324
319
  if (0 < out->opts->dump_opts.after_size) {
325
- strcpy(out->cur, out->opts->dump_opts.after_sep);
326
- out->cur += out->opts->dump_opts.after_size;
320
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
327
321
  }
328
322
  }
329
323
  oj_dump_custom_val(value, depth, out, true);
@@ -344,8 +338,7 @@ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
344
338
  cnt = (int)RHASH_SIZE(obj);
345
339
  assure_size(out, 2);
346
340
  if (0 == cnt) {
347
- *out->cur++ = '{';
348
- *out->cur++ = '}';
341
+ APPEND_CHARS(out->cur, "{}", 2);
349
342
  } else {
350
343
  *out->cur++ = '{';
351
344
  out->depth = depth + 1;
@@ -357,19 +350,15 @@ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
357
350
  assure_size(out, depth * out->indent + 2);
358
351
  fill_indent(out, depth);
359
352
  } else {
360
- assure_size(
361
- out,
362
- depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
353
+ assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
363
354
  if (0 < out->opts->dump_opts.hash_size) {
364
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
365
- out->cur += out->opts->dump_opts.hash_size;
355
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
366
356
  }
367
357
  if (0 < out->opts->dump_opts.indent_size) {
368
358
  int i;
369
359
 
370
360
  for (i = depth; 0 < i; i--) {
371
- strcpy(out->cur, out->opts->dump_opts.indent_str);
372
- out->cur += out->opts->dump_opts.indent_size;
361
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
373
362
  }
374
363
  }
375
364
  }
@@ -379,10 +368,10 @@ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
379
368
  }
380
369
 
381
370
  static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
382
- ID * idp;
383
- AttrGetFunc * fp;
371
+ ID *idp;
372
+ AttrGetFunc *fp;
384
373
  volatile VALUE v;
385
- const char * name;
374
+ const char *name;
386
375
  size_t size;
387
376
  int d2 = depth + 1;
388
377
 
@@ -391,29 +380,24 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
391
380
  if (NULL != out->opts->create_id && Yes == out->opts->create_ok) {
392
381
  const char *classname = rb_class2name(clas);
393
382
  int clen = (int)strlen(classname);
394
- size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
383
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
395
384
 
396
385
  size = d2 * out->indent + 10 + clen + out->opts->create_id_len + sep_len;
397
386
  assure_size(out, size);
398
387
  fill_indent(out, d2);
399
388
  *out->cur++ = '"';
400
- memcpy(out->cur, out->opts->create_id, out->opts->create_id_len);
401
- out->cur += out->opts->create_id_len;
389
+ APPEND_CHARS(out->cur, out->opts->create_id, out->opts->create_id_len);
402
390
  *out->cur++ = '"';
403
391
  if (0 < out->opts->dump_opts.before_size) {
404
- strcpy(out->cur, out->opts->dump_opts.before_sep);
405
- out->cur += out->opts->dump_opts.before_size;
392
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
406
393
  }
407
394
  *out->cur++ = ':';
408
395
  if (0 < out->opts->dump_opts.after_size) {
409
- strcpy(out->cur, out->opts->dump_opts.after_sep);
410
- out->cur += out->opts->dump_opts.after_size;
396
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
411
397
  }
412
398
  *out->cur++ = '"';
413
- memcpy(out->cur, classname, clen);
414
- out->cur += clen;
415
- *out->cur++ = '"';
416
- *out->cur++ = ',';
399
+ APPEND_CHARS(out->cur, classname, clen);
400
+ APPEND_CHARS(out->cur, "\",", 2);
417
401
  }
418
402
  if (odd->raw) {
419
403
  v = rb_funcall(obj, *odd->attrs, 0);
@@ -429,12 +413,9 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
429
413
  assure_size(out, size);
430
414
  fill_indent(out, d2);
431
415
  *out->cur++ = '"';
432
- memcpy(out->cur, name, nlen);
433
- out->cur += nlen;
434
- *out->cur++ = '"';
435
- *out->cur++ = ':';
436
- memcpy(out->cur, s, len);
437
- out->cur += len;
416
+ APPEND_CHARS(out->cur, name, nlen);
417
+ APPEND_CHARS(out->cur, "\":", 2);
418
+ APPEND_CHARS(out->cur, s, len);
438
419
  *out->cur = '\0';
439
420
  }
440
421
  } else {
@@ -457,7 +438,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
457
438
  ID i;
458
439
 
459
440
  if (sizeof(nbuf) <= nlen) {
460
- if (NULL == (n2 = strdup(name))) {
441
+ if (NULL == (n2 = OJ_STRDUP(name))) {
461
442
  rb_raise(rb_eNoMemError, "for attribute name.");
462
443
  }
463
444
  } else {
@@ -474,7 +455,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
474
455
  i = rb_intern(n);
475
456
  v = rb_funcall(v, i, 0);
476
457
  if (nbuf != n2) {
477
- free(n2);
458
+ OJ_FREE(n2);
478
459
  }
479
460
  }
480
461
  fill_indent(out, d2);
@@ -496,33 +477,26 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
496
477
  oj_dump_raw_json(obj, depth, out);
497
478
  } else if (Yes == out->opts->to_json && rb_respond_to(obj, oj_to_json_id)) {
498
479
  volatile VALUE rs;
499
- const char * s;
480
+ const char *s;
500
481
  int len;
501
482
 
502
- if (Yes == out->opts->trace) {
503
- oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
504
- }
483
+ TRACE(out->opts->trace, "to_json", obj, depth + 1, TraceRubyIn);
505
484
  if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
506
485
  rs = rb_funcall(obj, oj_to_json_id, 0);
507
486
  } else {
508
487
  rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv);
509
488
  }
510
- if (Yes == out->opts->trace) {
511
- oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
512
- }
489
+ TRACE(out->opts->trace, "to_json", obj, depth + 1, TraceRubyOut);
513
490
  s = RSTRING_PTR(rs);
514
491
  len = (int)RSTRING_LEN(rs);
515
492
 
516
493
  assure_size(out, len + 1);
517
- memcpy(out->cur, s, len);
518
- out->cur += len;
494
+ APPEND_CHARS(out->cur, s, len);
519
495
  *out->cur = '\0';
520
496
  } else if (Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) {
521
497
  volatile VALUE aj;
522
498
 
523
- if (Yes == out->opts->trace) {
524
- oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
525
- }
499
+ TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyIn);
526
500
  // Some classes elect to not take an options argument so check the arity
527
501
  // of as_json.
528
502
  if (0 == rb_obj_method_arity(obj, oj_as_json_id)) {
@@ -530,18 +504,12 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
530
504
  } else {
531
505
  aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
532
506
  }
533
- if (Yes == out->opts->trace) {
534
- oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
535
- }
507
+ TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyOut);
536
508
  // Catch the obvious brain damaged recursive dumping.
537
509
  if (aj == obj) {
538
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
510
+ volatile VALUE rstr = oj_safe_string_convert(obj);
539
511
 
540
- oj_dump_cstr(RSTRING_PTR(rstr),
541
- (int)RSTRING_LEN(rstr),
542
- false,
543
- false,
544
- out);
512
+ oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), false, false, out);
545
513
  } else {
546
514
  oj_dump_custom_val(aj, depth, out, true);
547
515
  }
@@ -625,7 +593,7 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
625
593
  assure_size(out, 2);
626
594
  *out->cur++ = '{';
627
595
  if (Qundef != clas && NULL != out->opts->create_id && Yes == out->opts->create_ok) {
628
- size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
596
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
629
597
  const char *classname = rb_obj_classname(obj);
630
598
  size_t len = strlen(classname);
631
599
 
@@ -633,21 +601,17 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
633
601
  assure_size(out, size);
634
602
  fill_indent(out, d2);
635
603
  *out->cur++ = '"';
636
- memcpy(out->cur, out->opts->create_id, out->opts->create_id_len);
637
- out->cur += out->opts->create_id_len;
604
+ APPEND_CHARS(out->cur, out->opts->create_id, out->opts->create_id_len);
638
605
  *out->cur++ = '"';
639
606
  if (0 < out->opts->dump_opts.before_size) {
640
- strcpy(out->cur, out->opts->dump_opts.before_sep);
641
- out->cur += out->opts->dump_opts.before_size;
607
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
642
608
  }
643
609
  *out->cur++ = ':';
644
610
  if (0 < out->opts->dump_opts.after_size) {
645
- strcpy(out->cur, out->opts->dump_opts.after_sep);
646
- out->cur += out->opts->dump_opts.after_size;
611
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
647
612
  }
648
613
  *out->cur++ = '"';
649
- memcpy(out->cur, classname, len);
650
- out->cur += len;
614
+ APPEND_CHARS(out->cur, classname, len);
651
615
  *out->cur++ = '"';
652
616
  class_written = true;
653
617
  }
@@ -731,19 +695,17 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
731
695
  } else {
732
696
  size = d2 * out->indent + 2;
733
697
  }
698
+ assure_size(out, size * cnt);
734
699
  cnt--;
735
700
  for (i = 0; i <= cnt; i++) {
736
- assure_size(out, size);
737
701
  if (out->opts->dump_opts.use) {
738
702
  if (0 < out->opts->dump_opts.array_size) {
739
- strcpy(out->cur, out->opts->dump_opts.array_nl);
740
- out->cur += out->opts->dump_opts.array_size;
703
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
741
704
  }
742
705
  if (0 < out->opts->dump_opts.indent_size) {
743
706
  int i;
744
707
  for (i = d2; 0 < i; i--) {
745
- strcpy(out->cur, out->opts->dump_opts.indent_str);
746
- out->cur += out->opts->dump_opts.indent_size;
708
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
747
709
  }
748
710
  }
749
711
  } else {
@@ -758,15 +720,13 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
758
720
  assure_size(out, size);
759
721
  if (out->opts->dump_opts.use) {
760
722
  if (0 < out->opts->dump_opts.array_size) {
761
- strcpy(out->cur, out->opts->dump_opts.array_nl);
762
- out->cur += out->opts->dump_opts.array_size;
723
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
763
724
  }
764
725
  if (0 < out->opts->dump_opts.indent_size) {
765
726
  int i;
766
727
 
767
728
  for (i = depth; 0 < i; i--) {
768
- strcpy(out->cur, out->opts->dump_opts.indent_str);
769
- out->cur += out->opts->dump_opts.indent_size;
729
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
770
730
  }
771
731
  }
772
732
  } else {
@@ -800,8 +760,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
800
760
  *out->cur++ = '"';
801
761
  oj_dump_custom_val(rb_funcall(obj, oj_begin_id, 0), d3, out, false);
802
762
  assure_size(out, 3);
803
- *out->cur++ = '.';
804
- *out->cur++ = '.';
763
+ APPEND_CHARS(out->cur, "..", 2);
805
764
  if (Qtrue == rb_funcall(obj, oj_exclude_end_id, 0)) {
806
765
  *out->cur++ = '.';
807
766
  }
@@ -844,10 +803,8 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
844
803
  assure_size(out, size + len + 3);
845
804
  fill_indent(out, d3);
846
805
  *out->cur++ = '"';
847
- memcpy(out->cur, name, len);
848
- out->cur += len;
849
- *out->cur++ = '"';
850
- *out->cur++ = ':';
806
+ APPEND_CHARS(out->cur, name, len);
807
+ APPEND_CHARS(out->cur, "\":", 2);
851
808
  oj_dump_custom_val(v, d3, out, true);
852
809
  *out->cur++ = ',';
853
810
  }
@@ -912,9 +869,7 @@ static DumpFunc custom_funcs[] = {
912
869
  void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
913
870
  int type = rb_type(obj);
914
871
 
915
- if (Yes == out->opts->trace) {
916
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
917
- }
872
+ TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
918
873
  if (MAX_DEPTH < depth) {
919
874
  rb_raise(rb_eNoMemError, "Too deeply nested.\n");
920
875
  }
@@ -923,22 +878,18 @@ void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
923
878
 
924
879
  if (NULL != f) {
925
880
  f(obj, depth, out, true);
926
- if (Yes == out->opts->trace) {
927
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
928
- }
881
+ TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
929
882
  return;
930
883
  }
931
884
  }
932
885
  oj_dump_nil(Qnil, depth, out, false);
933
- if (Yes == out->opts->trace) {
934
- oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
935
- }
886
+ TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
936
887
  }
937
888
 
938
889
  ///// load functions /////
939
890
 
940
891
  static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
941
- const char * key = kval->key;
892
+ const char *key = kval->key;
942
893
  int klen = kval->klen;
943
894
  Val parent = stack_peek(&pi->stack);
944
895
  volatile VALUE rkey = kval->key_val;
@@ -955,14 +906,14 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
955
906
  }
956
907
  }
957
908
  } else {
958
- volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
959
- //volatile VALUE rstr = rb_utf8_str_new(str, len);
909
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
910
+ // volatile VALUE rstr = rb_utf8_str_new(str, len);
960
911
 
961
912
  if (Qundef == rkey) {
962
913
  if (Yes == pi->options.sym_key) {
963
914
  rkey = ID2SYM(rb_intern3(key, klen, oj_utf8_encoding));
964
915
  } else {
965
- rkey = rb_utf8_str_new(key, klen);
916
+ rkey = rb_utf8_str_new(key, klen);
966
917
  }
967
918
  }
968
919
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
@@ -986,9 +937,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
986
937
  break;
987
938
  default: break;
988
939
  }
989
- if (Yes == pi->options.trace) {
990
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
991
- }
940
+ TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rstr);
992
941
  }
993
942
  }
994
943
 
@@ -1005,9 +954,7 @@ static void end_hash(struct _parseInfo *pi) {
1005
954
  }
1006
955
  parent->clas = Qundef;
1007
956
  }
1008
- if (Yes == pi->options.trace) {
1009
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
1010
- }
957
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
1011
958
  }
1012
959
 
1013
960
  static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
@@ -1035,20 +982,10 @@ static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
1035
982
  // match the expected value.
1036
983
  parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
1037
984
  } else if (ni->has_exp) {
1038
- int64_t t = (int64_t)(ni->i + ni->exp);
1039
- struct _timeInfo ti;
1040
- VALUE args[8];
1041
-
1042
- sec_as_time(t, &ti);
1043
-
1044
- args[0] = LONG2NUM(ti.year);
1045
- args[1] = LONG2NUM(ti.mon);
1046
- args[2] = LONG2NUM(ti.day);
1047
- args[3] = LONG2NUM(ti.hour);
1048
- args[4] = LONG2NUM(ti.min);
1049
- args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
1050
- args[6] = LONG2NUM(ni->exp);
1051
- parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
985
+ struct timespec ts;
986
+ ts.tv_sec = ni->i;
987
+ ts.tv_nsec = nsec;
988
+ parent->val = rb_time_timespec_new(&ts, (int)ni->exp);
1052
989
  } else {
1053
990
  parent->val = rb_time_nano_new(ni->i, (long)nsec);
1054
991
  }
@@ -1059,9 +996,7 @@ static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
1059
996
  break;
1060
997
  default: break;
1061
998
  }
1062
- if (Yes == pi->options.trace) {
1063
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
1064
- }
999
+ TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rval);
1065
1000
  }
1066
1001
 
1067
1002
  static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
@@ -1072,9 +1007,7 @@ static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
1072
1007
  case T_HASH: rb_hash_aset(parent->val, oj_calc_hash_key(pi, kval), value); break;
1073
1008
  default: break;
1074
1009
  }
1075
- if (Yes == pi->options.trace) {
1076
- oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
1077
- }
1010
+ TRACE_PARSE_CALL(pi->options.trace, "set_value", pi, value);
1078
1011
  }
1079
1012
 
1080
1013
  static void array_append_num(ParseInfo pi, NumInfo ni) {
@@ -1082,9 +1015,7 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
1082
1015
  volatile VALUE rval = oj_num_as_value(ni);
1083
1016
 
1084
1017
  rb_ary_push(parent->val, rval);
1085
- if (Yes == pi->options.trace) {
1086
- oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
1087
- }
1018
+ TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, rval);
1088
1019
  }
1089
1020
 
1090
1021
  static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
@@ -1099,9 +1030,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
1099
1030
  }
1100
1031
  }
1101
1032
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
1102
- if (Yes == pi->options.trace) {
1103
- oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
1104
- }
1033
+ TRACE_PARSE_CALL(pi->options.trace, "append_string", pi, rstr);
1105
1034
  }
1106
1035
 
1107
1036
  void oj_set_custom_callbacks(ParseInfo pi) {