oj 3.11.5 → 3.16.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (168) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1421 -0
  3. data/README.md +19 -5
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +20 -6
  6. data/ext/oj/cache.c +329 -0
  7. data/ext/oj/cache.h +22 -0
  8. data/ext/oj/cache8.c +10 -9
  9. data/ext/oj/circarray.c +8 -6
  10. data/ext/oj/circarray.h +2 -2
  11. data/ext/oj/code.c +19 -33
  12. data/ext/oj/code.h +2 -2
  13. data/ext/oj/compat.c +27 -77
  14. data/ext/oj/custom.c +86 -179
  15. data/ext/oj/debug.c +126 -0
  16. data/ext/oj/dump.c +256 -249
  17. data/ext/oj/dump.h +26 -12
  18. data/ext/oj/dump_compat.c +565 -642
  19. data/ext/oj/dump_leaf.c +17 -63
  20. data/ext/oj/dump_object.c +65 -187
  21. data/ext/oj/dump_strict.c +27 -51
  22. data/ext/oj/encoder.c +43 -0
  23. data/ext/oj/err.c +2 -13
  24. data/ext/oj/err.h +24 -8
  25. data/ext/oj/extconf.rb +21 -6
  26. data/ext/oj/fast.c +149 -149
  27. data/ext/oj/intern.c +313 -0
  28. data/ext/oj/intern.h +22 -0
  29. data/ext/oj/mem.c +318 -0
  30. data/ext/oj/mem.h +53 -0
  31. data/ext/oj/mimic_json.c +121 -106
  32. data/ext/oj/object.c +85 -162
  33. data/ext/oj/odd.c +89 -67
  34. data/ext/oj/odd.h +15 -15
  35. data/ext/oj/oj.c +542 -411
  36. data/ext/oj/oj.h +99 -73
  37. data/ext/oj/parse.c +175 -187
  38. data/ext/oj/parse.h +26 -24
  39. data/ext/oj/parser.c +1600 -0
  40. data/ext/oj/parser.h +101 -0
  41. data/ext/oj/rails.c +112 -159
  42. data/ext/oj/rails.h +1 -1
  43. data/ext/oj/reader.c +11 -14
  44. data/ext/oj/reader.h +4 -2
  45. data/ext/oj/resolve.c +5 -24
  46. data/ext/oj/rxclass.c +7 -6
  47. data/ext/oj/rxclass.h +1 -1
  48. data/ext/oj/saj.c +22 -33
  49. data/ext/oj/saj2.c +584 -0
  50. data/ext/oj/saj2.h +23 -0
  51. data/ext/oj/scp.c +5 -28
  52. data/ext/oj/sparse.c +28 -72
  53. data/ext/oj/stream_writer.c +50 -40
  54. data/ext/oj/strict.c +56 -61
  55. data/ext/oj/string_writer.c +72 -39
  56. data/ext/oj/trace.h +31 -4
  57. data/ext/oj/usual.c +1218 -0
  58. data/ext/oj/usual.h +69 -0
  59. data/ext/oj/util.h +1 -1
  60. data/ext/oj/val_stack.c +14 -3
  61. data/ext/oj/val_stack.h +8 -7
  62. data/ext/oj/validate.c +46 -0
  63. data/ext/oj/wab.c +63 -88
  64. data/lib/oj/active_support_helper.rb +1 -3
  65. data/lib/oj/bag.rb +7 -1
  66. data/lib/oj/easy_hash.rb +4 -5
  67. data/lib/oj/error.rb +1 -2
  68. data/lib/oj/json.rb +162 -150
  69. data/lib/oj/mimic.rb +9 -7
  70. data/lib/oj/saj.rb +20 -6
  71. data/lib/oj/schandler.rb +5 -4
  72. data/lib/oj/state.rb +12 -8
  73. data/lib/oj/version.rb +1 -2
  74. data/lib/oj.rb +2 -0
  75. data/pages/Compatibility.md +1 -1
  76. data/pages/InstallOptions.md +20 -0
  77. data/pages/JsonGem.md +15 -0
  78. data/pages/Modes.md +8 -3
  79. data/pages/Options.md +43 -5
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +14 -2
  82. data/test/_test_active.rb +8 -9
  83. data/test/_test_active_mimic.rb +7 -8
  84. data/test/_test_mimic_rails.rb +17 -20
  85. data/test/activerecord/result_test.rb +5 -6
  86. data/test/activesupport6/encoding_test.rb +63 -28
  87. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  88. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  89. data/test/{activesupport5 → activesupport7}/encoding_test.rb +86 -50
  90. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  91. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  92. data/test/files.rb +15 -15
  93. data/test/foo.rb +16 -45
  94. data/test/helper.rb +11 -8
  95. data/test/isolated/shared.rb +3 -2
  96. data/test/json_gem/json_addition_test.rb +2 -2
  97. data/test/json_gem/json_common_interface_test.rb +8 -6
  98. data/test/json_gem/json_encoding_test.rb +0 -0
  99. data/test/json_gem/json_ext_parser_test.rb +1 -0
  100. data/test/json_gem/json_fixtures_test.rb +3 -2
  101. data/test/json_gem/json_generator_test.rb +56 -38
  102. data/test/json_gem/json_generic_object_test.rb +11 -11
  103. data/test/json_gem/json_parser_test.rb +54 -47
  104. data/test/json_gem/json_string_matching_test.rb +9 -9
  105. data/test/json_gem/test_helper.rb +7 -3
  106. data/test/mem.rb +34 -0
  107. data/test/perf.rb +22 -27
  108. data/test/perf_compat.rb +31 -33
  109. data/test/perf_dump.rb +50 -0
  110. data/test/perf_fast.rb +80 -82
  111. data/test/perf_file.rb +27 -29
  112. data/test/perf_object.rb +65 -69
  113. data/test/perf_once.rb +59 -0
  114. data/test/perf_parser.rb +183 -0
  115. data/test/perf_saj.rb +46 -54
  116. data/test/perf_scp.rb +58 -69
  117. data/test/perf_simple.rb +41 -39
  118. data/test/perf_strict.rb +74 -82
  119. data/test/perf_wab.rb +67 -69
  120. data/test/prec.rb +5 -5
  121. data/test/sample/change.rb +0 -1
  122. data/test/sample/dir.rb +0 -1
  123. data/test/sample/doc.rb +0 -1
  124. data/test/sample/file.rb +0 -1
  125. data/test/sample/group.rb +0 -1
  126. data/test/sample/hasprops.rb +0 -1
  127. data/test/sample/layer.rb +0 -1
  128. data/test/sample/rect.rb +0 -1
  129. data/test/sample/shape.rb +0 -1
  130. data/test/sample/text.rb +0 -1
  131. data/test/sample.rb +16 -16
  132. data/test/sample_json.rb +8 -8
  133. data/test/test_compat.rb +95 -43
  134. data/test/test_custom.rb +73 -51
  135. data/test/test_debian.rb +7 -10
  136. data/test/test_fast.rb +135 -79
  137. data/test/test_file.rb +41 -30
  138. data/test/test_gc.rb +16 -5
  139. data/test/test_generate.rb +5 -5
  140. data/test/test_hash.rb +5 -5
  141. data/test/test_integer_range.rb +9 -9
  142. data/test/test_null.rb +20 -20
  143. data/test/test_object.rb +99 -96
  144. data/test/test_parser.rb +11 -0
  145. data/test/test_parser_debug.rb +27 -0
  146. data/test/test_parser_saj.rb +337 -0
  147. data/test/test_parser_usual.rb +251 -0
  148. data/test/test_rails.rb +2 -2
  149. data/test/test_saj.rb +10 -8
  150. data/test/test_scp.rb +37 -39
  151. data/test/test_strict.rb +40 -32
  152. data/test/test_various.rb +165 -84
  153. data/test/test_wab.rb +48 -44
  154. data/test/test_writer.rb +47 -47
  155. data/test/tests.rb +13 -5
  156. data/test/tests_mimic.rb +12 -3
  157. data/test/tests_mimic_addition.rb +12 -3
  158. metadata +74 -128
  159. data/ext/oj/hash.c +0 -131
  160. data/ext/oj/hash.h +0 -19
  161. data/ext/oj/hash_test.c +0 -491
  162. data/test/activesupport4/decoding_test.rb +0 -108
  163. data/test/activesupport4/encoding_test.rb +0 -531
  164. data/test/activesupport4/test_helper.rb +0 -41
  165. data/test/activesupport5/test_helper.rb +0 -72
  166. data/test/bar.rb +0 -35
  167. data/test/baz.rb +0 -16
  168. data/test/zoo.rb +0 -13
data/ext/oj/custom.c CHANGED
@@ -8,7 +8,8 @@
8
8
  #include "dump.h"
9
9
  #include "encode.h"
10
10
  #include "err.h"
11
- #include "hash.h"
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 = rb_string_value_ptr((VALUE *)&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 = rb_string_value_ptr((VALUE *)&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) {
@@ -123,7 +123,7 @@ static void date_dump(VALUE obj, int depth, Out out) {
123
123
  case RubyTime:
124
124
  case XmlTime:
125
125
  v = rb_funcall(obj, rb_intern("iso8601"), 0);
126
- oj_dump_cstr(rb_string_value_ptr((VALUE *)&v), (int)RSTRING_LEN(v), 0, 0, out);
126
+ oj_dump_cstr(RSTRING_PTR(v), (int)RSTRING_LEN(v), 0, 0, out);
127
127
  break;
128
128
  case UnixZTime:
129
129
  v = rb_funcall(obj, rb_intern("to_time"), 0);
@@ -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) {
@@ -282,7 +281,7 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
282
281
  Out out = (Out)ov;
283
282
  int depth = out->depth;
284
283
 
285
- if (oj_dump_ignore(out->opts, value)) {
284
+ if (dump_ignore(out->opts, value)) {
286
285
  return ST_CONTINUE;
287
286
  }
288
287
  if (out->omit_nil && Qnil == value) {
@@ -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,36 +380,31 @@ 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);
420
404
  if (Qundef == v || T_STRING != rb_type(v)) {
421
405
  rb_raise(rb_eEncodingError, "Invalid type for raw JSON.\n");
422
406
  } else {
423
- const char *s = rb_string_value_ptr((VALUE *)&v);
407
+ const char *s = RSTRING_PTR(v);
424
408
  int len = (int)RSTRING_LEN(v);
425
409
  const char *name = rb_id2name(*odd->attrs);
426
410
  size_t nlen = strlen(name);
@@ -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
- }
513
- s = rb_string_value_ptr((VALUE *)&rs);
489
+ TRACE(out->opts->trace, "to_json", obj, depth + 1, TraceRubyOut);
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(rb_string_value_ptr((VALUE *)&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
  }
@@ -577,7 +545,7 @@ static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
577
545
  size_t size;
578
546
  const char *attr;
579
547
 
580
- if (oj_dump_ignore(out->opts, value)) {
548
+ if (dump_ignore(out->opts, value)) {
581
549
  return ST_CONTINUE;
582
550
  }
583
551
  if (out->omit_nil && Qnil == value) {
@@ -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,25 +695,23 @@ 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 {
750
712
  fill_indent(out, d2);
751
713
  }
752
- oj_dump_custom_val(rb_ary_entry(a, i), d2, out, true);
714
+ oj_dump_custom_val(RARRAY_AREF(a, i), d2, out, true);
753
715
  if (i < cnt) {
754
716
  *out->cur++ = ',';
755
717
  }
@@ -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
  }
@@ -833,9 +792,9 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
833
792
  v = rb_struct_aref(obj, INT2FIX(i));
834
793
  #endif
835
794
  if (ma != Qnil) {
836
- volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i));
795
+ volatile VALUE s = rb_sym2str(RARRAY_AREF(ma, i));
837
796
 
838
- name = rb_string_value_ptr((VALUE *)&s);
797
+ name = RSTRING_PTR(s);
839
798
  len = (int)RSTRING_LEN(s);
840
799
  } else {
841
800
  len = snprintf(num_id, sizeof(num_id), "%d", i);
@@ -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,27 +878,22 @@ 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;
942
- int klen = kval->klen;
943
- Val parent = stack_peek(&pi->stack);
944
- volatile VALUE rkey = kval->key_val;
892
+ const char *key = kval->key;
893
+ int klen = kval->klen;
894
+ Val parent = stack_peek(&pi->stack);
945
895
 
946
- if (Qundef == rkey && Yes == pi->options.create_ok && NULL != pi->options.create_id &&
896
+ if (Qundef == kval->key_val && Yes == pi->options.create_ok && NULL != pi->options.create_id &&
947
897
  *pi->options.create_id == *key && (int)pi->options.create_id_len == klen &&
948
898
  0 == strncmp(pi->options.create_id, key, klen)) {
949
899
  parent->clas = oj_name2class(pi, str, len, false, rb_eArgError);
@@ -955,16 +905,9 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
955
905
  }
956
906
  }
957
907
  } else {
958
- volatile VALUE rstr = rb_str_new(str, len);
959
-
960
- if (Qundef == rkey) {
961
- rkey = rb_str_new(key, klen);
962
- rstr = oj_encode(rstr);
963
- rkey = oj_encode(rkey);
964
- if (Yes == pi->options.sym_key) {
965
- rkey = rb_str_intern(rkey);
966
- }
967
- }
908
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
909
+ volatile VALUE rkey = oj_calc_hash_key(pi, kval);
910
+
968
911
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
969
912
  VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
970
913
 
@@ -986,9 +929,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
986
929
  break;
987
930
  default: break;
988
931
  }
989
- if (Yes == pi->options.trace) {
990
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
991
- }
932
+ TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rstr);
992
933
  }
993
934
  }
994
935
 
@@ -1005,22 +946,7 @@ static void end_hash(struct _parseInfo *pi) {
1005
946
  }
1006
947
  parent->clas = Qundef;
1007
948
  }
1008
- if (Yes == pi->options.trace) {
1009
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
1010
- }
1011
- }
1012
-
1013
- static VALUE calc_hash_key(ParseInfo pi, Val parent) {
1014
- volatile VALUE rkey = parent->key_val;
1015
-
1016
- if (Qundef == rkey) {
1017
- rkey = rb_str_new(parent->key, parent->klen);
1018
- }
1019
- rkey = oj_encode(rkey);
1020
- if (Yes == pi->options.sym_key) {
1021
- rkey = rb_str_intern(rkey);
1022
- }
1023
- return rkey;
949
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
1024
950
  }
1025
951
 
1026
952
  static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
@@ -1043,38 +969,26 @@ static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
1043
969
  }
1044
970
  if (86400 == ni->exp) { // UTC time
1045
971
  parent->val = rb_time_nano_new(ni->i, (long)nsec);
1046
- // Since the ruby C routines alway create local time, the
972
+ // Since the ruby C routines always create local time, the
1047
973
  // offset and then a conversion to UTC keeps makes the time
1048
974
  // match the expected value.
1049
975
  parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
1050
976
  } else if (ni->has_exp) {
1051
- int64_t t = (int64_t)(ni->i + ni->exp);
1052
- struct _timeInfo ti;
1053
- VALUE args[8];
1054
-
1055
- sec_as_time(t, &ti);
1056
-
1057
- args[0] = LONG2NUM(ti.year);
1058
- args[1] = LONG2NUM(ti.mon);
1059
- args[2] = LONG2NUM(ti.day);
1060
- args[3] = LONG2NUM(ti.hour);
1061
- args[4] = LONG2NUM(ti.min);
1062
- args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
1063
- args[6] = LONG2NUM(ni->exp);
1064
- parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
977
+ struct timespec ts;
978
+ ts.tv_sec = ni->i;
979
+ ts.tv_nsec = nsec;
980
+ parent->val = rb_time_timespec_new(&ts, (int)ni->exp);
1065
981
  } else {
1066
982
  parent->val = rb_time_nano_new(ni->i, (long)nsec);
1067
983
  }
1068
984
  rval = parent->val;
1069
985
  } else {
1070
- rb_hash_aset(parent->val, calc_hash_key(pi, kval), rval);
986
+ rb_hash_aset(parent->val, oj_calc_hash_key(pi, kval), rval);
1071
987
  }
1072
988
  break;
1073
989
  default: break;
1074
990
  }
1075
- if (Yes == pi->options.trace) {
1076
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
1077
- }
991
+ TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rval);
1078
992
  }
1079
993
 
1080
994
  static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
@@ -1082,12 +996,10 @@ static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
1082
996
 
1083
997
  switch (rb_type(parent->val)) {
1084
998
  case T_OBJECT: oj_set_obj_ivar(parent, kval, value); break;
1085
- case T_HASH: rb_hash_aset(parent->val, calc_hash_key(pi, kval), value); break;
999
+ case T_HASH: rb_hash_aset(parent->val, oj_calc_hash_key(pi, kval), value); break;
1086
1000
  default: break;
1087
1001
  }
1088
- if (Yes == pi->options.trace) {
1089
- oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
1090
- }
1002
+ TRACE_PARSE_CALL(pi->options.trace, "set_value", pi, value);
1091
1003
  }
1092
1004
 
1093
1005
  static void array_append_num(ParseInfo pi, NumInfo ni) {
@@ -1095,15 +1007,12 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
1095
1007
  volatile VALUE rval = oj_num_as_value(ni);
1096
1008
 
1097
1009
  rb_ary_push(parent->val, rval);
1098
- if (Yes == pi->options.trace) {
1099
- oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
1100
- }
1010
+ TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, rval);
1101
1011
  }
1102
1012
 
1103
1013
  static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
1104
- volatile VALUE rstr = rb_str_new(str, len);
1014
+ volatile VALUE rstr = rb_utf8_str_new(str, len);
1105
1015
 
1106
- rstr = oj_encode(rstr);
1107
1016
  if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
1108
1017
  VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
1109
1018
 
@@ -1113,9 +1022,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
1113
1022
  }
1114
1023
  }
1115
1024
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
1116
- if (Yes == pi->options.trace) {
1117
- oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
1118
- }
1025
+ TRACE_PARSE_CALL(pi->options.trace, "append_string", pi, rstr);
1119
1026
  }
1120
1027
 
1121
1028
  void oj_set_custom_callbacks(ParseInfo pi) {