oj 3.9.1 → 3.16.11

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 (171) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1452 -0
  3. data/README.md +21 -6
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +50 -68
  6. data/ext/oj/cache.c +329 -0
  7. data/ext/oj/cache.h +22 -0
  8. data/ext/oj/cache8.c +60 -62
  9. data/ext/oj/cache8.h +9 -36
  10. data/ext/oj/circarray.c +38 -42
  11. data/ext/oj/circarray.h +12 -13
  12. data/ext/oj/code.c +158 -179
  13. data/ext/oj/code.h +20 -22
  14. data/ext/oj/compat.c +145 -205
  15. data/ext/oj/custom.c +740 -880
  16. data/ext/oj/debug.c +126 -0
  17. data/ext/oj/dump.c +1145 -844
  18. data/ext/oj/dump.h +71 -57
  19. data/ext/oj/dump_compat.c +575 -655
  20. data/ext/oj/dump_leaf.c +96 -186
  21. data/ext/oj/dump_object.c +533 -660
  22. data/ext/oj/dump_strict.c +306 -340
  23. data/ext/oj/encode.h +4 -33
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +28 -28
  26. data/ext/oj/err.h +39 -42
  27. data/ext/oj/extconf.rb +28 -7
  28. data/ext/oj/fast.c +1052 -1113
  29. data/ext/oj/intern.c +313 -0
  30. data/ext/oj/intern.h +22 -0
  31. data/ext/oj/mem.c +318 -0
  32. data/ext/oj/mem.h +53 -0
  33. data/ext/oj/mimic_json.c +471 -430
  34. data/ext/oj/object.c +532 -580
  35. data/ext/oj/odd.c +156 -142
  36. data/ext/oj/odd.h +25 -26
  37. data/ext/oj/oj.c +1346 -961
  38. data/ext/oj/oj.h +307 -290
  39. data/ext/oj/parse.c +954 -858
  40. data/ext/oj/parse.h +74 -72
  41. data/ext/oj/parser.c +1600 -0
  42. data/ext/oj/parser.h +103 -0
  43. data/ext/oj/rails.c +819 -836
  44. data/ext/oj/rails.h +8 -11
  45. data/ext/oj/reader.c +136 -147
  46. data/ext/oj/reader.h +69 -83
  47. data/ext/oj/resolve.c +41 -63
  48. data/ext/oj/resolve.h +4 -6
  49. data/ext/oj/rxclass.c +69 -72
  50. data/ext/oj/rxclass.h +12 -13
  51. data/ext/oj/saj.c +440 -485
  52. data/ext/oj/saj2.c +584 -0
  53. data/ext/oj/saj2.h +23 -0
  54. data/ext/oj/scp.c +79 -118
  55. data/ext/oj/simd.h +10 -0
  56. data/ext/oj/sparse.c +739 -709
  57. data/ext/oj/stream_writer.c +141 -175
  58. data/ext/oj/strict.c +103 -128
  59. data/ext/oj/string_writer.c +244 -261
  60. data/ext/oj/trace.c +34 -41
  61. data/ext/oj/trace.h +42 -15
  62. data/ext/oj/usual.c +1218 -0
  63. data/ext/oj/usual.h +69 -0
  64. data/ext/oj/util.c +107 -107
  65. data/ext/oj/util.h +4 -3
  66. data/ext/oj/val_stack.c +61 -78
  67. data/ext/oj/val_stack.h +80 -114
  68. data/ext/oj/validate.c +46 -0
  69. data/ext/oj/wab.c +316 -361
  70. data/lib/oj/active_support_helper.rb +1 -3
  71. data/lib/oj/bag.rb +8 -1
  72. data/lib/oj/easy_hash.rb +9 -9
  73. data/lib/oj/error.rb +1 -2
  74. data/lib/oj/json.rb +162 -150
  75. data/lib/oj/mimic.rb +54 -20
  76. data/lib/oj/saj.rb +20 -6
  77. data/lib/oj/schandler.rb +5 -4
  78. data/lib/oj/state.rb +12 -8
  79. data/lib/oj/version.rb +1 -2
  80. data/lib/oj.rb +2 -8
  81. data/pages/Compatibility.md +1 -1
  82. data/pages/Encoding.md +1 -1
  83. data/pages/InstallOptions.md +20 -0
  84. data/pages/JsonGem.md +15 -0
  85. data/pages/Modes.md +9 -3
  86. data/pages/Options.md +62 -12
  87. data/pages/Parser.md +309 -0
  88. data/pages/Rails.md +73 -22
  89. metadata +68 -192
  90. data/ext/oj/hash.c +0 -163
  91. data/ext/oj/hash.h +0 -46
  92. data/ext/oj/hash_test.c +0 -512
  93. data/test/_test_active.rb +0 -76
  94. data/test/_test_active_mimic.rb +0 -96
  95. data/test/_test_mimic_rails.rb +0 -126
  96. data/test/activerecord/result_test.rb +0 -27
  97. data/test/activesupport4/decoding_test.rb +0 -108
  98. data/test/activesupport4/encoding_test.rb +0 -531
  99. data/test/activesupport4/test_helper.rb +0 -41
  100. data/test/activesupport5/decoding_test.rb +0 -125
  101. data/test/activesupport5/encoding_test.rb +0 -485
  102. data/test/activesupport5/encoding_test_cases.rb +0 -90
  103. data/test/activesupport5/test_helper.rb +0 -50
  104. data/test/activesupport5/time_zone_test_helpers.rb +0 -24
  105. data/test/bar.rb +0 -25
  106. data/test/files.rb +0 -29
  107. data/test/foo.rb +0 -21
  108. data/test/helper.rb +0 -26
  109. data/test/isolated/shared.rb +0 -308
  110. data/test/isolated/test_mimic_after.rb +0 -13
  111. data/test/isolated/test_mimic_alone.rb +0 -12
  112. data/test/isolated/test_mimic_as_json.rb +0 -45
  113. data/test/isolated/test_mimic_before.rb +0 -13
  114. data/test/isolated/test_mimic_define.rb +0 -28
  115. data/test/isolated/test_mimic_rails_after.rb +0 -22
  116. data/test/isolated/test_mimic_rails_before.rb +0 -21
  117. data/test/isolated/test_mimic_redefine.rb +0 -15
  118. data/test/json_gem/json_addition_test.rb +0 -216
  119. data/test/json_gem/json_common_interface_test.rb +0 -148
  120. data/test/json_gem/json_encoding_test.rb +0 -107
  121. data/test/json_gem/json_ext_parser_test.rb +0 -20
  122. data/test/json_gem/json_fixtures_test.rb +0 -35
  123. data/test/json_gem/json_generator_test.rb +0 -383
  124. data/test/json_gem/json_generic_object_test.rb +0 -90
  125. data/test/json_gem/json_parser_test.rb +0 -470
  126. data/test/json_gem/json_string_matching_test.rb +0 -42
  127. data/test/json_gem/test_helper.rb +0 -18
  128. data/test/perf.rb +0 -107
  129. data/test/perf_compat.rb +0 -130
  130. data/test/perf_fast.rb +0 -164
  131. data/test/perf_file.rb +0 -64
  132. data/test/perf_object.rb +0 -138
  133. data/test/perf_saj.rb +0 -109
  134. data/test/perf_scp.rb +0 -151
  135. data/test/perf_simple.rb +0 -287
  136. data/test/perf_strict.rb +0 -145
  137. data/test/perf_wab.rb +0 -131
  138. data/test/sample/change.rb +0 -14
  139. data/test/sample/dir.rb +0 -19
  140. data/test/sample/doc.rb +0 -36
  141. data/test/sample/file.rb +0 -48
  142. data/test/sample/group.rb +0 -16
  143. data/test/sample/hasprops.rb +0 -16
  144. data/test/sample/layer.rb +0 -12
  145. data/test/sample/line.rb +0 -20
  146. data/test/sample/oval.rb +0 -10
  147. data/test/sample/rect.rb +0 -10
  148. data/test/sample/shape.rb +0 -35
  149. data/test/sample/text.rb +0 -20
  150. data/test/sample.rb +0 -54
  151. data/test/sample_json.rb +0 -37
  152. data/test/test_compat.rb +0 -509
  153. data/test/test_custom.rb +0 -503
  154. data/test/test_debian.rb +0 -53
  155. data/test/test_fast.rb +0 -470
  156. data/test/test_file.rb +0 -239
  157. data/test/test_gc.rb +0 -49
  158. data/test/test_hash.rb +0 -29
  159. data/test/test_integer_range.rb +0 -73
  160. data/test/test_null.rb +0 -376
  161. data/test/test_object.rb +0 -1018
  162. data/test/test_saj.rb +0 -186
  163. data/test/test_scp.rb +0 -433
  164. data/test/test_strict.rb +0 -410
  165. data/test/test_various.rb +0 -741
  166. data/test/test_wab.rb +0 -307
  167. data/test/test_writer.rb +0 -380
  168. data/test/tests.rb +0 -24
  169. data/test/tests_mimic.rb +0 -14
  170. data/test/tests_mimic_addition.rb +0 -7
  171. data/test/zoo.rb +0 -13
data/ext/oj/rails.c CHANGED
@@ -1,159 +1,154 @@
1
- /* rails.c
2
- * Copyright (c) 2017, Peter Ohler
3
- * All rights reserved.
4
- */
1
+ // Copyright (c) 2017 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
5
3
 
6
4
  #include "rails.h"
7
- #include "encode.h"
5
+
8
6
  #include "code.h"
9
7
  #include "encode.h"
8
+ #include "mem.h"
10
9
  #include "trace.h"
11
10
  #include "util.h"
12
11
 
13
- #define OJ_INFINITY (1.0/0.0)
12
+ #define OJ_INFINITY (1.0 / 0.0)
14
13
 
15
14
  // TBD keep static array of strings and functions to help with rails optimization
16
15
  typedef struct _encoder {
17
- struct _rOptTable ropts;
18
- struct _options opts;
19
- VALUE arg;
16
+ struct _rOptTable ropts;
17
+ struct _options opts;
18
+ VALUE arg;
20
19
  } *Encoder;
21
20
 
22
- bool oj_rails_hash_opt = false;
23
- bool oj_rails_array_opt = false;
24
- bool oj_rails_float_opt = false;
21
+ bool oj_rails_hash_opt = false;
22
+ bool oj_rails_array_opt = false;
23
+ bool oj_rails_float_opt = false;
25
24
 
26
- extern void oj_mimic_json_methods(VALUE json);
25
+ extern void oj_mimic_json_methods(VALUE json);
27
26
 
28
- static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok);
27
+ static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok);
29
28
 
30
- extern VALUE Oj;
29
+ extern VALUE Oj;
31
30
 
32
- static struct _rOptTable ropts = { 0, 0, NULL };
31
+ static struct _rOptTable ropts = {0, 0, NULL};
33
32
 
34
- static VALUE encoder_class = Qnil;
35
- static bool escape_html = true;
36
- static bool xml_time = true;
33
+ static VALUE encoder_class = Qnil;
34
+ static bool escape_html = true;
35
+ static bool xml_time = true;
37
36
 
38
- static ROpt create_opt(ROptTable rot, VALUE clas);
37
+ static ROpt create_opt(ROptTable rot, VALUE clas);
39
38
 
40
- ROpt
41
- oj_rails_get_opt(ROptTable rot, VALUE clas) {
39
+ ROpt oj_rails_get_opt(ROptTable rot, VALUE clas) {
42
40
  if (NULL == rot) {
43
- rot = &ropts;
41
+ rot = &ropts;
44
42
  }
45
43
  if (0 < rot->len) {
46
- int lo = 0;
47
- int hi = rot->len - 1;
48
- int mid;
49
- VALUE v;
50
-
51
- if (clas < rot->table->clas || rot->table[hi].clas < clas) {
52
- return NULL;
53
- }
54
- if (rot->table[lo].clas == clas) {
55
- return rot->table;
56
- }
57
- if (rot->table[hi].clas == clas) {
58
- return &rot->table[hi];
59
- }
60
- while (2 <= hi - lo) {
61
- mid = (hi + lo) / 2;
62
- v = rot->table[mid].clas;
63
- if (v == clas) {
64
- return &rot->table[mid];
65
- }
66
- if (v < clas) {
67
- lo = mid;
68
- } else {
69
- hi = mid;
70
- }
71
- }
44
+ int lo = 0;
45
+ int hi = rot->len - 1;
46
+ int mid;
47
+ VALUE v;
48
+
49
+ if (clas < rot->table->clas || rot->table[hi].clas < clas) {
50
+ return NULL;
51
+ }
52
+ if (rot->table[lo].clas == clas) {
53
+ return rot->table;
54
+ }
55
+ if (rot->table[hi].clas == clas) {
56
+ return &rot->table[hi];
57
+ }
58
+ while (2 <= hi - lo) {
59
+ mid = (hi + lo) / 2;
60
+ v = rot->table[mid].clas;
61
+ if (v == clas) {
62
+ return &rot->table[mid];
63
+ }
64
+ if (v < clas) {
65
+ lo = mid;
66
+ } else {
67
+ hi = mid;
68
+ }
69
+ }
72
70
  }
73
71
  return NULL;
74
72
  }
75
73
 
76
- static ROptTable
77
- copy_opts(ROptTable src, ROptTable dest) {
78
- dest->len = src->len;
74
+ static ROptTable copy_opts(ROptTable src, ROptTable dest) {
75
+ dest->len = src->len;
79
76
  dest->alen = src->alen;
80
77
  if (NULL == src->table) {
81
- dest->table = NULL;
78
+ dest->table = NULL;
82
79
  } else {
83
- dest->table = ALLOC_N(struct _rOpt, dest->alen);
84
- memcpy(dest->table, src->table, sizeof(struct _rOpt) * dest->alen);
80
+ dest->table = OJ_R_ALLOC_N(struct _rOpt, dest->alen);
81
+ memcpy(dest->table, src->table, sizeof(struct _rOpt) * dest->alen);
85
82
  }
86
83
  return NULL;
87
84
  }
88
85
 
89
- static int
90
- dump_attr_cb(ID key, VALUE value, Out out) {
91
- int depth = out->depth;
92
- size_t size = depth * out->indent + 1;
93
- const char *attr = rb_id2name(key);
86
+ static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
87
+ Out out = (Out)ov;
88
+ int depth = out->depth;
89
+ size_t size = depth * out->indent + 1;
90
+ const char *attr = rb_id2name(key);
94
91
 
95
92
  // Some exceptions such as NoMethodError have an invisible attribute where
96
93
  // the key name is NULL. Not an empty string but NULL.
97
94
  if (NULL == attr) {
98
- attr = "";
95
+ attr = "";
99
96
  }
100
97
  if (0 == strcmp("bt", attr) || 0 == strcmp("mesg", attr)) {
101
- return ST_CONTINUE;
98
+ return ST_CONTINUE;
102
99
  }
103
100
  assure_size(out, size);
104
101
  fill_indent(out, depth);
105
102
  if ('@' == *attr) {
106
- attr++;
107
- oj_dump_cstr(attr, strlen(attr), 0, 0, out);
103
+ attr++;
104
+ oj_dump_cstr(attr, strlen(attr), 0, 0, out);
108
105
  } else {
109
- char buf[32];
106
+ char buf[32];
110
107
 
111
- *buf = '~';
112
- strncpy(buf + 1, attr, sizeof(buf) - 2);
113
- buf[sizeof(buf) - 1] = '\0';
114
- oj_dump_cstr(buf, strlen(buf), 0, 0, out);
108
+ *buf = '~';
109
+ strncpy(buf + 1, attr, sizeof(buf) - 2);
110
+ buf[sizeof(buf) - 1] = '\0';
111
+ oj_dump_cstr(buf, strlen(buf), 0, 0, out);
115
112
  }
116
113
  *out->cur++ = ':';
117
114
  dump_rails_val(value, depth, out, true);
118
- out->depth = depth;
115
+ out->depth = depth;
119
116
  *out->cur++ = ',';
120
117
 
121
118
  return ST_CONTINUE;
122
119
  }
123
120
 
124
- static void
125
- dump_obj_attrs(VALUE obj, int depth, Out out, bool as_ok) {
121
+ static void dump_obj_attrs(VALUE obj, int depth, Out out, bool as_ok) {
126
122
  assure_size(out, 2);
127
123
  *out->cur++ = '{';
128
- out->depth = depth + 1;
124
+ out->depth = depth + 1;
129
125
  rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
130
126
  if (',' == *(out->cur - 1)) {
131
- out->cur--; // backup to overwrite last comma
127
+ out->cur--; // backup to overwrite last comma
132
128
  }
133
129
  out->depth = depth;
134
130
  fill_indent(out, depth);
135
131
  *out->cur++ = '}';
136
- *out->cur = '\0';
132
+ *out->cur = '\0';
137
133
  }
138
134
 
139
- static void
140
- dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
141
- int d3 = depth + 2;
142
- size_t size = d3 * out->indent + 2;
143
- size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
144
- volatile VALUE ma;
145
- volatile VALUE v;
146
- int cnt;
147
- int i;
148
- int len;
149
- const char *name;
135
+ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
136
+ int d3 = depth + 2;
137
+ size_t size = d3 * out->indent + 2;
138
+ size_t sep_len = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
139
+ volatile VALUE ma;
140
+ volatile VALUE v;
141
+ int cnt;
142
+ int i;
143
+ size_t len;
144
+ const char *name;
150
145
 
151
146
  #ifdef RSTRUCT_LEN
152
147
  #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
153
148
  cnt = (int)NUM2LONG(RSTRUCT_LEN(obj));
154
- #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
149
+ #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
155
150
  cnt = (int)RSTRUCT_LEN(obj);
156
- #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
151
+ #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
157
152
  #else
158
153
  // This is a bit risky as a struct in C ruby is not the same as a Struct
159
154
  // class in interpreted Ruby so length() may not be defined.
@@ -163,89 +158,85 @@ dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
163
158
  assure_size(out, 2);
164
159
  *out->cur++ = '{';
165
160
  for (i = 0; i < cnt; i++) {
166
- volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i));
167
-
168
- name = rb_string_value_ptr((VALUE*)&s);
169
- len = (int)RSTRING_LEN(s);
170
- assure_size(out, size + sep_len + 6);
171
- if (0 < i) {
172
- *out->cur++ = ',';
173
- }
174
- fill_indent(out, d3);
175
- *out->cur++ = '"';
176
- memcpy(out->cur, name, len);
177
- out->cur += len;
178
- *out->cur++ = '"';
179
- if (0 < out->opts->dump_opts.before_size) {
180
- strcpy(out->cur, out->opts->dump_opts.before_sep);
181
- out->cur += out->opts->dump_opts.before_size;
182
- }
183
- *out->cur++ = ':';
184
- if (0 < out->opts->dump_opts.after_size) {
185
- strcpy(out->cur, out->opts->dump_opts.after_sep);
186
- out->cur += out->opts->dump_opts.after_size;
187
- }
161
+ volatile VALUE s = rb_sym2str(RARRAY_AREF(ma, i));
162
+
163
+ name = RSTRING_PTR(s);
164
+ len = RSTRING_LEN(s);
165
+ assure_size(out, size + sep_len + 6);
166
+ if (0 < i) {
167
+ *out->cur++ = ',';
168
+ }
169
+ fill_indent(out, d3);
170
+ *out->cur++ = '"';
171
+ APPEND_CHARS(out->cur, name, len);
172
+ *out->cur++ = '"';
173
+ if (0 < out->opts->dump_opts.before_size) {
174
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
175
+ }
176
+ *out->cur++ = ':';
177
+ if (0 < out->opts->dump_opts.after_size) {
178
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
179
+ }
188
180
  #ifdef RSTRUCT_LEN
189
- v = RSTRUCT_GET(obj, i);
181
+ v = RSTRUCT_GET(obj, i);
190
182
  #else
191
- v = rb_struct_aref(obj, INT2FIX(i));
183
+ v = rb_struct_aref(obj, INT2FIX(i));
192
184
  #endif
193
- dump_rails_val(v, d3, out, true);
185
+ dump_rails_val(v, d3, out, true);
194
186
  }
195
187
  fill_indent(out, depth);
196
188
  *out->cur++ = '}';
197
- *out->cur = '\0';
189
+ *out->cur = '\0';
198
190
  }
199
191
 
200
- static ID to_a_id = 0;
192
+ static ID to_a_id = 0;
201
193
 
202
- static void
203
- dump_enumerable(VALUE obj, int depth, Out out, bool as_ok) {
194
+ static void dump_enumerable(VALUE obj, int depth, Out out, bool as_ok) {
204
195
  if (0 == to_a_id) {
205
- to_a_id = rb_intern("to_a");
196
+ to_a_id = rb_intern("to_a");
206
197
  }
207
198
  dump_rails_val(rb_funcall(obj, to_a_id, 0), depth, out, false);
208
199
  }
209
200
 
210
- static void
211
- dump_bigdecimal(VALUE obj, int depth, Out out, bool as_ok) {
212
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
213
- const char *str = rb_string_value_ptr((VALUE*)&rstr);
201
+ static void dump_bigdecimal(VALUE obj, int depth, Out out, bool as_ok) {
202
+ volatile VALUE rstr = oj_safe_string_convert(obj);
203
+ const char *str = RSTRING_PTR(rstr);
214
204
 
215
205
  if ('I' == *str || 'N' == *str || ('-' == *str && 'I' == str[1])) {
216
- oj_dump_nil(Qnil, depth, out, false);
206
+ oj_dump_nil(Qnil, depth, out, false);
207
+ } else if (out->opts->int_range_max != 0 || out->opts->int_range_min != 0) {
208
+ oj_dump_cstr(str, RSTRING_LEN(rstr), 0, 0, out);
217
209
  } else if (Yes == out->opts->bigdec_as_num) {
218
- oj_dump_raw(str, (int)RSTRING_LEN(rstr), out);
210
+ oj_dump_raw(str, RSTRING_LEN(rstr), out);
219
211
  } else {
220
- oj_dump_cstr(str, (int)RSTRING_LEN(rstr), 0, 0, out);
212
+ oj_dump_cstr(str, RSTRING_LEN(rstr), 0, 0, out);
221
213
  }
222
214
  }
223
215
 
224
- static void
225
- dump_sec_nano(VALUE obj, int64_t sec, long nsec, Out out) {
226
- char buf[64];
227
- struct _timeInfo ti;
228
- long one = 1000000000;
229
- long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
230
- int tzhour, tzmin;
231
- char tzsign = '+';
232
- int len;
216
+ static void dump_sec_nano(VALUE obj, int64_t sec, long nsec, Out out) {
217
+ char buf[64];
218
+ struct _timeInfo ti;
219
+ long one = 1000000000;
220
+ long tzsecs = NUM2LONG(rb_funcall2(obj, oj_utc_offset_id, 0, 0));
221
+ int tzhour, tzmin;
222
+ char tzsign = '+';
223
+ int len;
233
224
 
234
225
  if (out->end - out->cur <= 36) {
235
- assure_size(out, 36);
226
+ assure_size(out, 36);
236
227
  }
237
228
  if (9 > out->opts->sec_prec) {
238
- int i;
239
-
240
- // Rails does not round when reducing precision but instead floors,
241
- for (i = 9 - out->opts->sec_prec; 0 < i; i--) {
242
- nsec = nsec / 10;
243
- one /= 10;
244
- }
245
- if (one <= nsec) {
246
- nsec -= one;
247
- sec++;
248
- }
229
+ int i;
230
+
231
+ // Rails does not round when reducing precision but instead floors,
232
+ for (i = 9 - out->opts->sec_prec; 0 < i; i--) {
233
+ nsec = nsec / 10;
234
+ one /= 10;
235
+ }
236
+ if (one <= nsec) {
237
+ nsec -= one;
238
+ sec++;
239
+ }
249
240
  }
250
241
  // 2012-01-05T23:58:07.123456000+09:00 or 2012/01/05 23:58:07 +0900
251
242
  sec += tzsecs;
@@ -253,509 +244,506 @@ dump_sec_nano(VALUE obj, int64_t sec, long nsec, Out out) {
253
244
  if (0 > tzsecs) {
254
245
  tzsign = '-';
255
246
  tzhour = (int)(tzsecs / -3600);
256
- tzmin = (int)(tzsecs / -60) - (tzhour * 60);
247
+ tzmin = (int)(tzsecs / -60) - (tzhour * 60);
257
248
  } else {
258
249
  tzhour = (int)(tzsecs / 3600);
259
- tzmin = (int)(tzsecs / 60) - (tzhour * 60);
250
+ tzmin = (int)(tzsecs / 60) - (tzhour * 60);
260
251
  }
261
252
  if (!xml_time) {
262
- len = sprintf(buf, "%04d/%02d/%02d %02d:%02d:%02d %c%02d%02d", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, tzsign, tzhour, tzmin);
253
+ len = sprintf(buf,
254
+ "%04d/%02d/%02d %02d:%02d:%02d %c%02d%02d",
255
+ ti.year,
256
+ ti.mon,
257
+ ti.day,
258
+ ti.hour,
259
+ ti.min,
260
+ ti.sec,
261
+ tzsign,
262
+ tzhour,
263
+ tzmin);
263
264
  } else if (0 == out->opts->sec_prec) {
264
- if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
265
- len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec);
266
- } else {
267
- len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, tzsign, tzhour, tzmin);
268
- }
265
+ if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
266
+ len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec);
267
+ } else {
268
+ len = sprintf(buf,
269
+ "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
270
+ ti.year,
271
+ ti.mon,
272
+ ti.day,
273
+ ti.hour,
274
+ ti.min,
275
+ ti.sec,
276
+ tzsign,
277
+ tzhour,
278
+ tzmin);
279
+ }
269
280
  } else if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
270
- char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ";
271
-
272
- len = 30;
273
- if (9 > out->opts->sec_prec) {
274
- format[32] = '0' + out->opts->sec_prec;
275
- len -= 9 - out->opts->sec_prec;
276
- }
277
- len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, nsec);
281
+ char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ldZ";
282
+
283
+ len = 30;
284
+ if (9 > out->opts->sec_prec) {
285
+ format[32] = '0' + out->opts->sec_prec;
286
+ len -= 9 - out->opts->sec_prec;
287
+ }
288
+ len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, nsec);
278
289
  } else {
279
- char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d";
290
+ char format[64] = "%04d-%02d-%02dT%02d:%02d:%02d.%09ld%c%02d:%02d";
280
291
 
281
- len = 35;
282
- if (9 > out->opts->sec_prec) {
283
- format[32] = '0' + out->opts->sec_prec;
284
- len -= 9 - out->opts->sec_prec;
285
- }
286
- len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, nsec, tzsign, tzhour, tzmin);
292
+ len = 35;
293
+ if (9 > out->opts->sec_prec) {
294
+ format[32] = '0' + out->opts->sec_prec;
295
+ len -= 9 - out->opts->sec_prec;
296
+ }
297
+ len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, nsec, tzsign, tzhour, tzmin);
287
298
  }
288
299
  oj_dump_cstr(buf, len, 0, 0, out);
289
300
  }
290
301
 
291
- static void
292
- dump_time(VALUE obj, int depth, Out out, bool as_ok) {
293
- long long sec;
294
- long long nsec;
302
+ static void dump_time(VALUE obj, int depth, Out out, bool as_ok) {
303
+ long long sec;
304
+ long long nsec;
295
305
 
296
- #ifdef HAVE_RB_TIME_TIMESPEC
297
306
  if (16 <= sizeof(struct timespec)) {
298
- struct timespec ts = rb_time_timespec(obj);
307
+ struct timespec ts = rb_time_timespec(obj);
299
308
 
300
- sec = (long long)ts.tv_sec;
301
- nsec = ts.tv_nsec;
309
+ sec = (long long)ts.tv_sec;
310
+ nsec = ts.tv_nsec;
302
311
  } else {
303
- sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
304
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
312
+ sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
313
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
305
314
  }
306
- #else
307
- sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
308
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
309
- #endif
310
315
  dump_sec_nano(obj, sec, nsec, out);
311
316
  }
312
317
 
313
- static void
314
- dump_timewithzone(VALUE obj, int depth, Out out, bool as_ok) {
315
- int64_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
316
- long long nsec = 0;
318
+ static void dump_timewithzone(VALUE obj, int depth, Out out, bool as_ok) {
319
+ int64_t sec = NUM2LONG(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
320
+ long long nsec = 0;
317
321
 
318
322
  if (rb_respond_to(obj, oj_tv_nsec_id)) {
319
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
323
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
320
324
  } else if (rb_respond_to(obj, oj_tv_usec_id)) {
321
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
325
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
322
326
  }
323
327
  dump_sec_nano(obj, sec, nsec, out);
324
328
  }
325
329
 
326
- static void
327
- dump_to_s(VALUE obj, int depth, Out out, bool as_ok) {
328
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
330
+ static void dump_to_s(VALUE obj, int depth, Out out, bool as_ok) {
331
+ volatile VALUE rstr = oj_safe_string_convert(obj);
329
332
 
330
- oj_dump_cstr(rb_string_value_ptr((VALUE*)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
333
+ oj_dump_cstr(RSTRING_PTR(rstr), RSTRING_LEN(rstr), 0, 0, out);
331
334
  }
332
335
 
333
- static ID parameters_id = 0;
336
+ static ID parameters_id = 0;
334
337
 
335
338
  typedef struct _strLen {
336
- const char *str;
337
- int len;
339
+ const char *str;
340
+ size_t len;
338
341
  } *StrLen;
339
342
 
340
- static void
341
- dump_actioncontroller_parameters(VALUE obj, int depth, Out out, bool as_ok) {
343
+ static void dump_actioncontroller_parameters(VALUE obj, int depth, Out out, bool as_ok) {
342
344
  if (0 == parameters_id) {
343
- parameters_id = rb_intern("@parameters");
345
+ parameters_id = rb_intern("@parameters");
344
346
  }
345
347
  out->argc = 0;
346
348
  dump_rails_val(rb_ivar_get(obj, parameters_id), depth, out, true);
347
349
  }
348
350
 
349
- static StrLen
350
- columns_array(VALUE rcols, int *ccnt) {
351
- volatile VALUE v;
352
- StrLen cp;
353
- StrLen cols;
354
- int i;
355
- int cnt = (int)RARRAY_LEN(rcols);
351
+ static StrLen columns_array(VALUE rcols, int *ccnt) {
352
+ volatile VALUE v;
353
+ StrLen cp;
354
+ StrLen cols;
355
+ size_t i;
356
+ size_t cnt = RARRAY_LEN(rcols);
356
357
 
357
- *ccnt = cnt;
358
- cols = ALLOC_N(struct _strLen, cnt);
358
+ *ccnt = (int)cnt;
359
+ cols = OJ_R_ALLOC_N(struct _strLen, cnt);
359
360
  for (i = 0, cp = cols; i < cnt; i++, cp++) {
360
- v = rb_ary_entry(rcols, i);
361
- if (T_STRING != rb_type(v)) {
362
- v = rb_funcall(v, oj_to_s_id, 0);
363
- }
364
- cp->str = StringValuePtr(v);
365
- cp->len = (int)RSTRING_LEN(v);
361
+ v = RARRAY_AREF(rcols, i);
362
+ if (T_STRING != rb_type(v)) {
363
+ v = oj_safe_string_convert(v);
364
+ }
365
+ cp->str = StringValuePtr(v);
366
+ cp->len = RSTRING_LEN(v);
366
367
  }
367
368
  return cols;
368
369
  }
369
370
 
370
- static void
371
- dump_row(VALUE row, StrLen cols, int ccnt, int depth, Out out) {
372
- size_t size;
373
- int d2 = depth + 1;
374
- int i;
371
+ static void dump_row(VALUE row, StrLen cols, int ccnt, int depth, Out out) {
372
+ size_t size;
373
+ int d2 = depth + 1;
374
+ int i;
375
375
 
376
376
  assure_size(out, 2);
377
377
  *out->cur++ = '{';
378
- size = depth * out->indent + 3;
378
+ size = depth * out->indent + 3;
379
379
  for (i = 0; i < ccnt; i++, cols++) {
380
- assure_size(out, size);
381
- if (out->opts->dump_opts.use) {
382
- if (0 < out->opts->dump_opts.array_size) {
383
- strcpy(out->cur, out->opts->dump_opts.array_nl);
384
- out->cur += out->opts->dump_opts.array_size;
385
- }
386
- if (0 < out->opts->dump_opts.indent_size) {
387
- int i;
388
- for (i = d2; 0 < i; i--) {
389
- strcpy(out->cur, out->opts->dump_opts.indent_str);
390
- out->cur += out->opts->dump_opts.indent_size;
391
- }
392
- }
393
- } else {
394
- fill_indent(out, d2);
395
- }
396
- oj_dump_cstr(cols->str, cols->len, 0, 0, out);
397
- *out->cur++ = ':';
398
- dump_rails_val(rb_ary_entry(row, i), depth, out, true);
399
- if (i < ccnt - 1) {
400
- *out->cur++ = ',';
401
- }
380
+ assure_size(out, size);
381
+ if (out->opts->dump_opts.use) {
382
+ if (0 < out->opts->dump_opts.array_size) {
383
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
384
+ }
385
+ if (0 < out->opts->dump_opts.indent_size) {
386
+ int i;
387
+ for (i = d2; 0 < i; i--) {
388
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
389
+ }
390
+ }
391
+ } else {
392
+ fill_indent(out, d2);
393
+ }
394
+ oj_dump_cstr(cols->str, cols->len, 0, 0, out);
395
+ *out->cur++ = ':';
396
+ dump_rails_val(RARRAY_AREF(row, i), depth, out, true);
397
+ if (i < ccnt - 1) {
398
+ *out->cur++ = ',';
399
+ }
402
400
  }
403
401
  size = depth * out->indent + 1;
404
402
  assure_size(out, size);
405
403
  if (out->opts->dump_opts.use) {
406
- if (0 < out->opts->dump_opts.array_size) {
407
- strcpy(out->cur, out->opts->dump_opts.array_nl);
408
- out->cur += out->opts->dump_opts.array_size;
409
- }
410
- if (0 < out->opts->dump_opts.indent_size) {
411
- int i;
412
-
413
- for (i = depth; 0 < i; i--) {
414
- strcpy(out->cur, out->opts->dump_opts.indent_str);
415
- out->cur += out->opts->dump_opts.indent_size;
416
- }
417
- }
404
+ if (0 < out->opts->dump_opts.array_size) {
405
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
406
+ }
407
+ if (0 < out->opts->dump_opts.indent_size) {
408
+ int i;
409
+
410
+ for (i = depth; 0 < i; i--) {
411
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
412
+ }
413
+ }
418
414
  } else {
419
- fill_indent(out, depth);
415
+ fill_indent(out, depth);
420
416
  }
421
417
  *out->cur++ = '}';
422
418
  }
423
419
 
424
- static ID rows_id = 0;
425
- static ID columns_id = 0;
420
+ static ID rows_id = 0;
421
+ static ID columns_id = 0;
426
422
 
427
- static void
428
- dump_activerecord_result(VALUE obj, int depth, Out out, bool as_ok) {
429
- volatile VALUE rows;
430
- StrLen cols;
431
- int ccnt = 0;
432
- int i, rcnt;
433
- size_t size;
434
- int d2 = depth + 1;
423
+ static void dump_activerecord_result(VALUE obj, int depth, Out out, bool as_ok) {
424
+ volatile VALUE rows;
425
+ StrLen cols;
426
+ int ccnt = 0;
427
+ size_t i;
428
+ size_t rcnt;
429
+ size_t size;
430
+ int d2 = depth + 1;
435
431
 
436
432
  if (0 == rows_id) {
437
- rows_id = rb_intern("@rows");
438
- columns_id = rb_intern("@columns");
433
+ rows_id = rb_intern("@rows");
434
+ columns_id = rb_intern("@columns");
439
435
  }
440
436
  out->argc = 0;
441
- cols = columns_array(rb_ivar_get(obj, columns_id), &ccnt);
442
- rows = rb_ivar_get(obj, rows_id);
443
- rcnt = (int)RARRAY_LEN(rows);
437
+ cols = columns_array(rb_ivar_get(obj, columns_id), &ccnt);
438
+ rows = rb_ivar_get(obj, rows_id);
439
+ rcnt = RARRAY_LEN(rows);
444
440
  assure_size(out, 2);
445
441
  *out->cur++ = '[';
446
442
  if (out->opts->dump_opts.use) {
447
- size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
443
+ size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
448
444
  } else {
449
- size = d2 * out->indent + 2;
445
+ size = d2 * out->indent + 2;
450
446
  }
451
447
  assure_size(out, 2);
452
448
  for (i = 0; i < rcnt; i++) {
453
- assure_size(out, size);
454
- if (out->opts->dump_opts.use) {
455
- if (0 < out->opts->dump_opts.array_size) {
456
- strcpy(out->cur, out->opts->dump_opts.array_nl);
457
- out->cur += out->opts->dump_opts.array_size;
458
- }
459
- if (0 < out->opts->dump_opts.indent_size) {
460
- int i;
461
- for (i = d2; 0 < i; i--) {
462
- strcpy(out->cur, out->opts->dump_opts.indent_str);
463
- out->cur += out->opts->dump_opts.indent_size;
464
- }
465
- }
466
- } else {
467
- fill_indent(out, d2);
468
- }
469
- dump_row(rb_ary_entry(rows, i), cols, ccnt, d2, out);
470
- if (i < rcnt - 1) {
471
- *out->cur++ = ',';
472
- }
473
- }
474
- xfree(cols);
449
+ assure_size(out, size);
450
+ if (out->opts->dump_opts.use) {
451
+ if (0 < out->opts->dump_opts.array_size) {
452
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
453
+ }
454
+ if (0 < out->opts->dump_opts.indent_size) {
455
+ int i;
456
+ for (i = d2; 0 < i; i--) {
457
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
458
+ }
459
+ }
460
+ } else {
461
+ fill_indent(out, d2);
462
+ }
463
+ dump_row(RARRAY_AREF(rows, i), cols, ccnt, d2, out);
464
+ if (i < rcnt - 1) {
465
+ *out->cur++ = ',';
466
+ }
467
+ }
468
+ OJ_R_FREE(cols);
475
469
  size = depth * out->indent + 1;
476
470
  assure_size(out, size);
477
471
  if (out->opts->dump_opts.use) {
478
- if (0 < out->opts->dump_opts.array_size) {
479
- strcpy(out->cur, out->opts->dump_opts.array_nl);
480
- out->cur += out->opts->dump_opts.array_size;
481
- }
482
- if (0 < out->opts->dump_opts.indent_size) {
483
- int i;
484
-
485
- for (i = depth; 0 < i; i--) {
486
- strcpy(out->cur, out->opts->dump_opts.indent_str);
487
- out->cur += out->opts->dump_opts.indent_size;
488
- }
489
- }
472
+ if (0 < out->opts->dump_opts.array_size) {
473
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
474
+ }
475
+ if (0 < out->opts->dump_opts.indent_size) {
476
+ int i;
477
+
478
+ for (i = depth; 0 < i; i--) {
479
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
480
+ }
481
+ }
490
482
  } else {
491
- fill_indent(out, depth);
483
+ fill_indent(out, depth);
492
484
  }
493
485
  *out->cur++ = ']';
494
486
  }
495
487
 
496
488
  typedef struct _namedFunc {
497
- const char *name;
498
- DumpFunc func;
489
+ const char *name;
490
+ DumpFunc func;
499
491
  } *NamedFunc;
500
492
 
501
- static void
502
- dump_as_string(VALUE obj, int depth, Out out, bool as_ok) {
493
+ static void dump_as_string(VALUE obj, int depth, Out out, bool as_ok) {
503
494
  if (oj_code_dump(oj_compat_codes, obj, depth, out)) {
504
- out->argc = 0;
505
- return;
495
+ out->argc = 0;
496
+ return;
506
497
  }
507
498
  oj_dump_obj_to_s(obj, out);
508
499
  }
509
500
 
510
- static void
511
- dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
512
- volatile VALUE ja;
501
+ static void dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
502
+ volatile VALUE ja;
513
503
 
514
- if (Yes == out->opts->trace) {
515
- oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
516
- }
504
+ TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyIn);
517
505
  // Some classes elect to not take an options argument so check the arity
518
506
  // of as_json.
519
507
  if (0 == rb_obj_method_arity(obj, oj_as_json_id)) {
520
- ja = rb_funcall(obj, oj_as_json_id, 0);
508
+ ja = rb_funcall(obj, oj_as_json_id, 0);
521
509
  } else {
522
- ja = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
523
- }
524
- if (Yes == out->opts->trace) {
525
- oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
510
+ ja = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
526
511
  }
512
+ TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyOut);
527
513
 
528
514
  out->argc = 0;
529
515
  if (ja == obj || !as_ok) {
530
- // Once as_json is called it should never be called again on the same
531
- // object with as_ok.
532
- dump_rails_val(ja, depth, out, false);
516
+ // Once as_json is called it should never be called again on the same
517
+ // object with as_ok.
518
+ dump_rails_val(ja, depth, out, false);
533
519
  } else {
534
- int type = rb_type(ja);
520
+ int type = rb_type(ja);
535
521
 
536
- if (T_HASH == type || T_ARRAY == type) {
537
- dump_rails_val(ja, depth, out, true);
538
- } else {
539
- dump_rails_val(ja, depth, out, true);
540
- }
522
+ if (T_HASH == type || T_ARRAY == type) {
523
+ dump_rails_val(ja, depth, out, true);
524
+ } else {
525
+ dump_rails_val(ja, depth, out, true);
526
+ }
541
527
  }
542
528
  }
543
529
 
544
- static void
545
- dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
530
+ static void dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
546
531
  if (as_ok && rb_respond_to(obj, oj_as_json_id)) {
547
- dump_as_json(obj, depth, out, false);
548
- return;
532
+ dump_as_json(obj, depth, out, false);
533
+ return;
549
534
  }
550
535
  dump_as_string(obj, depth, out, as_ok);
551
536
  }
552
537
 
553
- static struct _namedFunc dump_map[] = {
554
- { "ActionController::Parameters", dump_actioncontroller_parameters },
555
- { "ActiveRecord::Result", dump_activerecord_result },
556
- { "ActiveSupport::TimeWithZone", dump_timewithzone },
557
- { "BigDecimal", dump_bigdecimal },
558
- { "Range", dump_to_s },
559
- { "Regexp", dump_regexp },
538
+ static struct _namedFunc dump_map[] = {
539
+ {"ActionController::Parameters", dump_actioncontroller_parameters},
540
+ {"ActiveRecord::Result", dump_activerecord_result},
541
+ {"ActiveSupport::TimeWithZone", dump_timewithzone},
542
+ {"BigDecimal", dump_bigdecimal},
543
+ {"Range", dump_to_s},
544
+ {"Regexp", dump_regexp},
560
545
  //{ "Regexp", dump_to_s },
561
- { "Time", dump_time },
562
- { NULL, NULL },
546
+ {"Time", dump_time},
547
+ {NULL, NULL},
563
548
  };
564
549
 
565
- static VALUE activerecord_base = Qundef;
566
- static ID attributes_id = 0;
550
+ static VALUE activerecord_base = Qundef;
551
+ static ID attributes_id = 0;
567
552
 
568
- static void
569
- dump_activerecord(VALUE obj, int depth, Out out, bool as_ok) {
553
+ static void dump_activerecord(VALUE obj, int depth, Out out, bool as_ok) {
570
554
  if (0 == attributes_id) {
571
- attributes_id = rb_intern("@attributes");
555
+ attributes_id = rb_intern("@attributes");
572
556
  }
573
557
  out->argc = 0;
574
558
  dump_rails_val(rb_ivar_get(obj, attributes_id), depth, out, true);
575
559
  }
576
560
 
577
- static ROpt
578
- create_opt(ROptTable rot, VALUE clas) {
579
- ROpt ro;
580
- NamedFunc nf;
581
- const char *classname = rb_class2name(clas);
582
- int olen = rot->len;
561
+ static ROpt create_opt(ROptTable rot, VALUE clas) {
562
+ ROpt ro;
563
+ NamedFunc nf;
564
+ const char *classname = rb_class2name(clas);
565
+ int olen = rot->len;
583
566
 
584
567
  rot->len++;
585
568
  if (NULL == rot->table) {
586
- rot->alen = 256;
587
- rot->table = ALLOC_N(struct _rOpt, rot->alen);
588
- memset(rot->table, 0, sizeof(struct _rOpt) * rot->alen);
569
+ rot->alen = 256;
570
+ rot->table = OJ_R_ALLOC_N(struct _rOpt, rot->alen);
571
+ memset(rot->table, 0, sizeof(struct _rOpt) * rot->alen);
589
572
  } else if (rot->alen <= rot->len) {
590
- rot->alen *= 2;
591
- REALLOC_N(rot->table, struct _rOpt, rot->alen);
592
- memset(rot->table + olen, 0, sizeof(struct _rOpt) * olen);
573
+ rot->alen *= 2;
574
+ OJ_R_REALLOC_N(rot->table, struct _rOpt, rot->alen);
575
+ memset(rot->table + olen, 0, sizeof(struct _rOpt) * olen);
593
576
  }
594
577
  if (0 == olen) {
595
- ro = rot->table;
578
+ ro = rot->table;
596
579
  } else if (rot->table[olen - 1].clas < clas) {
597
- ro = &rot->table[olen];
580
+ ro = &rot->table[olen];
598
581
  } else {
599
- int i;
582
+ int i;
600
583
 
601
- for (i = 0, ro = rot->table; i < olen; i++, ro++) {
602
- if (clas < ro->clas) {
603
- memmove(ro + 1, ro, sizeof(struct _rOpt) * (olen - i));
604
- break;
605
- }
606
- }
584
+ for (i = 0, ro = rot->table; i < olen; i++, ro++) {
585
+ if (clas < ro->clas) {
586
+ memmove(ro + 1, ro, sizeof(struct _rOpt) * (olen - i));
587
+ break;
588
+ }
589
+ }
607
590
  }
608
591
  ro->clas = clas;
609
- ro->on = true;
592
+ ro->on = true;
610
593
  ro->dump = dump_obj_attrs;
611
594
  for (nf = dump_map; NULL != nf->name; nf++) {
612
- if (0 == strcmp(nf->name, classname)) {
613
- ro->dump = nf->func;
614
- break;
615
- }
595
+ if (0 == strcmp(nf->name, classname)) {
596
+ ro->dump = nf->func;
597
+ break;
598
+ }
616
599
  }
617
600
  if (ro->dump == dump_obj_attrs) {
618
- if (Qundef == activerecord_base) {
619
- // If not defined let an exception be raised.
620
- VALUE ar = rb_const_get_at(rb_cObject, rb_intern("ActiveRecord"));
621
-
622
- if (Qundef != ar) {
623
- activerecord_base = rb_const_get_at(ar, rb_intern("Base"));
624
- }
625
- }
626
- if (Qundef != activerecord_base && Qtrue == rb_class_inherited_p(clas, activerecord_base)) {
627
- ro->dump = dump_activerecord;
628
- } else if (Qtrue == rb_class_inherited_p(clas, rb_cStruct)) { // check before enumerable
629
- ro->dump = dump_struct;
630
- } else if (Qtrue == rb_class_inherited_p(clas, rb_mEnumerable)) {
631
- ro->dump = dump_enumerable;
632
- } else if (Qtrue == rb_class_inherited_p(clas, rb_eException)) {
633
- ro->dump = dump_to_s;
634
- }
601
+ if (Qundef == activerecord_base) {
602
+ // If not defined let an exception be raised.
603
+ VALUE ar = rb_const_get_at(rb_cObject, rb_intern("ActiveRecord"));
604
+
605
+ if (Qundef != ar) {
606
+ activerecord_base = rb_const_get_at(ar, rb_intern("Base"));
607
+ }
608
+ }
609
+ if (Qundef != activerecord_base && Qtrue == rb_class_inherited_p(clas, activerecord_base)) {
610
+ ro->dump = dump_activerecord;
611
+ } else if (Qtrue == rb_class_inherited_p(clas, rb_cStruct)) { // check before enumerable
612
+ ro->dump = dump_struct;
613
+ } else if (Qtrue == rb_class_inherited_p(clas, rb_mEnumerable)) {
614
+ ro->dump = dump_enumerable;
615
+ } else if (Qtrue == rb_class_inherited_p(clas, rb_eException)) {
616
+ ro->dump = dump_to_s;
617
+ }
635
618
  }
636
619
  return ro;
637
620
  }
638
621
 
639
- static void
640
- encoder_free(void *ptr) {
622
+ static void encoder_free(void *ptr) {
641
623
  if (NULL != ptr) {
642
- Encoder e = (Encoder)ptr;
624
+ Encoder e = (Encoder)ptr;
643
625
 
644
- if (NULL != e->ropts.table) {
645
- xfree(e->ropts.table);
646
- }
647
- xfree(ptr);
626
+ if (NULL != e->ropts.table) {
627
+ OJ_R_FREE(e->ropts.table);
628
+ }
629
+ OJ_R_FREE(ptr);
648
630
  }
649
631
  }
650
632
 
651
- static void
652
- encoder_mark(void *ptr) {
633
+ static void encoder_mark(void *ptr) {
653
634
  if (NULL != ptr) {
654
- Encoder e = (Encoder)ptr;
635
+ Encoder e = (Encoder)ptr;
655
636
 
656
- if (Qnil != e->arg) {
657
- rb_gc_mark(e->arg);
658
- }
637
+ if (Qnil != e->arg) {
638
+ rb_gc_mark(e->arg);
639
+ }
659
640
  }
660
641
  }
661
642
 
643
+ static const rb_data_type_t oj_encoder_type = {
644
+ "Oj/encoder",
645
+ {
646
+ encoder_mark,
647
+ encoder_free,
648
+ NULL,
649
+ },
650
+ 0,
651
+ 0,
652
+ };
653
+
662
654
  /* Document-method: new
663
655
  * call-seq: new(options=nil)
664
656
  *
665
657
  * Creates a new Encoder.
666
658
  * - *options* [_Hash_] formatting options
667
659
  */
668
- static VALUE
669
- encoder_new(int argc, VALUE *argv, VALUE self) {
670
- Encoder e = ALLOC(struct _encoder);
660
+ static VALUE encoder_new(int argc, VALUE *argv, VALUE self) {
661
+ Encoder e = OJ_R_ALLOC(struct _encoder);
671
662
 
672
663
  e->opts = oj_default_options;
673
- e->arg = Qnil;
664
+ e->arg = Qnil;
674
665
  copy_opts(&ropts, &e->ropts);
675
666
 
676
667
  if (1 <= argc && Qnil != *argv) {
677
- oj_parse_options(*argv, &e->opts);
678
- e->arg = *argv;
668
+ oj_parse_options(*argv, &e->opts);
669
+ e->arg = *argv;
679
670
  }
680
- return Data_Wrap_Struct(encoder_class, encoder_mark, encoder_free, e);
671
+ return TypedData_Wrap_Struct(encoder_class, &oj_encoder_type, e);
681
672
  }
682
673
 
683
- static VALUE
684
- resolve_classpath(const char *name) {
685
- char class_name[1024];
686
- VALUE clas;
687
- char *end = class_name + sizeof(class_name) - 1;
688
- char *s;
689
- const char *n = name;
690
- ID cid;
674
+ static VALUE resolve_classpath(const char *name) {
675
+ char class_name[1024];
676
+ VALUE clas;
677
+ char *end = class_name + sizeof(class_name) - 1;
678
+ char *s;
679
+ const char *n = name;
680
+ ID cid;
691
681
 
692
682
  clas = rb_cObject;
693
683
  for (s = class_name; '\0' != *n; n++) {
694
- if (':' == *n) {
695
- *s = '\0';
696
- n++;
697
- if (':' != *n) {
698
- return Qnil;
699
- }
700
- cid = rb_intern(class_name);
701
- if (!rb_const_defined_at(clas, cid)) {
702
- return Qnil;
703
- }
704
- clas = rb_const_get_at(clas, cid);
705
- s = class_name;
706
- } else if (end <= s) {
707
- return Qnil;
708
- } else {
709
- *s++ = *n;
710
- }
711
- }
712
- *s = '\0';
684
+ if (':' == *n) {
685
+ *s = '\0';
686
+ n++;
687
+ if (':' != *n) {
688
+ return Qnil;
689
+ }
690
+ cid = rb_intern(class_name);
691
+ if (!rb_const_defined_at(clas, cid)) {
692
+ return Qnil;
693
+ }
694
+ clas = rb_const_get_at(clas, cid);
695
+ s = class_name;
696
+ } else if (end <= s) {
697
+ return Qnil;
698
+ } else {
699
+ *s++ = *n;
700
+ }
701
+ }
702
+ *s = '\0';
713
703
  cid = rb_intern(class_name);
714
704
  if (!rb_const_defined_at(clas, cid)) {
715
- return Qnil;
705
+ return Qnil;
716
706
  }
717
707
  clas = rb_const_get_at(clas, cid);
718
708
 
719
709
  return clas;
720
710
  }
721
711
 
722
- static void
723
- optimize(int argc, VALUE *argv, ROptTable rot, bool on) {
724
- ROpt ro;
712
+ static void optimize(int argc, VALUE *argv, ROptTable rot, bool on) {
713
+ ROpt ro;
725
714
 
726
715
  if (0 == argc) {
727
- int i;
728
- NamedFunc nf;
729
- VALUE clas;
730
-
731
- oj_rails_hash_opt = on;
732
- oj_rails_array_opt = on;
733
- oj_rails_float_opt = on;
734
-
735
- for (nf = dump_map; NULL != nf->name; nf++) {
736
- if (Qnil != (clas = resolve_classpath(nf->name))) {
737
- if (NULL == oj_rails_get_opt(rot, clas)) {
738
- create_opt(rot, clas);
739
- }
740
- }
741
- }
742
- for (i = 0; i < rot->len; i++) {
743
- rot->table[i].on = on;
744
- }
716
+ int i;
717
+ NamedFunc nf;
718
+ VALUE clas;
719
+
720
+ oj_rails_hash_opt = on;
721
+ oj_rails_array_opt = on;
722
+ oj_rails_float_opt = on;
723
+
724
+ for (nf = dump_map; NULL != nf->name; nf++) {
725
+ if (Qnil != (clas = resolve_classpath(nf->name))) {
726
+ if (NULL == oj_rails_get_opt(rot, clas)) {
727
+ create_opt(rot, clas);
728
+ }
729
+ }
730
+ }
731
+ for (i = 0; i < rot->len; i++) {
732
+ rot->table[i].on = on;
733
+ }
745
734
  }
746
735
  for (; 0 < argc; argc--, argv++) {
747
- if (rb_cHash == *argv) {
748
- oj_rails_hash_opt = on;
749
- } else if (rb_cArray == *argv) {
750
- oj_rails_array_opt = on;
751
- } else if (rb_cFloat == *argv) {
752
- oj_rails_float_opt = on;
753
- } else if (oj_string_writer_class == *argv) {
754
- string_writer_optimized = on;
755
- } else if (NULL != (ro = oj_rails_get_opt(rot, *argv)) ||
756
- NULL != (ro = create_opt(rot, *argv))) {
757
- ro->on = on;
758
- }
736
+ if (rb_cHash == *argv) {
737
+ oj_rails_hash_opt = on;
738
+ } else if (rb_cArray == *argv) {
739
+ oj_rails_array_opt = on;
740
+ } else if (rb_cFloat == *argv) {
741
+ oj_rails_float_opt = on;
742
+ } else if (oj_string_writer_class == *argv) {
743
+ string_writer_optimized = on;
744
+ } else if (NULL != (ro = oj_rails_get_opt(rot, *argv)) || NULL != (ro = create_opt(rot, *argv))) {
745
+ ro->on = on;
746
+ }
759
747
  }
760
748
  }
761
749
 
@@ -771,9 +759,9 @@ optimize(int argc, VALUE *argv, ROptTable rot, bool on) {
771
759
  *
772
760
  * - *classes* [_Class_] a list of classes to optimize
773
761
  */
774
- static VALUE
775
- encoder_optimize(int argc, VALUE *argv, VALUE self) {
776
- Encoder e = (Encoder)DATA_PTR(self);
762
+ static VALUE encoder_optimize(int argc, VALUE *argv, VALUE self) {
763
+ Encoder e;
764
+ TypedData_Get_Struct(self, struct _encoder, &oj_encoder_type, e);
777
765
 
778
766
  optimize(argc, argv, &e->ropts, true);
779
767
 
@@ -792,8 +780,7 @@ encoder_optimize(int argc, VALUE *argv, VALUE self) {
792
780
  *
793
781
  * - *classes* [_Class_] a list of classes to optimize
794
782
  */
795
- static VALUE
796
- rails_optimize(int argc, VALUE *argv, VALUE self) {
783
+ static VALUE rails_optimize(int argc, VALUE *argv, VALUE self) {
797
784
  optimize(argc, argv, &ropts, true);
798
785
  string_writer_optimized = true;
799
786
 
@@ -808,15 +795,16 @@ rails_optimize(int argc, VALUE *argv, VALUE self) {
808
795
  */
809
796
  VALUE
810
797
  rails_mimic_json(VALUE self) {
811
- VALUE json;
798
+ VALUE json;
812
799
 
813
800
  if (rb_const_defined_at(rb_cObject, rb_intern("JSON"))) {
814
- json = rb_const_get_at(rb_cObject, rb_intern("JSON"));
801
+ json = rb_const_get_at(rb_cObject, rb_intern("JSON"));
815
802
  } else {
816
- json = rb_define_module("JSON");
803
+ json = rb_define_module("JSON");
817
804
  }
818
805
  oj_mimic_json_methods(json);
819
- //oj_default_options.mode = RailsMode;
806
+ // Setting the default mode breaks the prmoise in the docs not to.
807
+ // oj_default_options.mode = RailsMode;
820
808
 
821
809
  return Qnil;
822
810
  }
@@ -828,9 +816,9 @@ rails_mimic_json(VALUE self) {
828
816
  *
829
817
  * - *classes* [_Class_] a list of classes to deoptimize
830
818
  */
831
- static VALUE
832
- encoder_deoptimize(int argc, VALUE *argv, VALUE self) {
833
- Encoder e = (Encoder)DATA_PTR(self);
819
+ static VALUE encoder_deoptimize(int argc, VALUE *argv, VALUE self) {
820
+ Encoder e;
821
+ TypedData_Get_Struct(self, struct _encoder, &oj_encoder_type, e);
834
822
 
835
823
  optimize(argc, argv, &e->ropts, false);
836
824
 
@@ -844,8 +832,7 @@ encoder_deoptimize(int argc, VALUE *argv, VALUE self) {
844
832
  *
845
833
  * - *classes* [_Class_] a list of classes to deoptimize
846
834
  */
847
- static VALUE
848
- rails_deoptimize(int argc, VALUE *argv, VALUE self) {
835
+ static VALUE rails_deoptimize(int argc, VALUE *argv, VALUE self) {
849
836
  optimize(argc, argv, &ropts, false);
850
837
  string_writer_optimized = false;
851
838
 
@@ -859,13 +846,15 @@ rails_deoptimize(int argc, VALUE *argv, VALUE self) {
859
846
  *
860
847
  * @return true if the class is being optimized for rails and false otherwise
861
848
  */
862
- static VALUE
863
- encoder_optimized(VALUE self, VALUE clas) {
864
- Encoder e = (Encoder)DATA_PTR(self);
865
- ROpt ro = oj_rails_get_opt(&e->ropts, clas);
849
+ static VALUE encoder_optimized(VALUE self, VALUE clas) {
850
+ Encoder e;
851
+ ROpt ro;
852
+
853
+ TypedData_Get_Struct(self, struct _encoder, &oj_encoder_type, e);
854
+ ro = oj_rails_get_opt(&e->ropts, clas);
866
855
 
867
856
  if (NULL == ro) {
868
- return Qfalse;
857
+ return Qfalse;
869
858
  }
870
859
  return (ro->on) ? Qtrue : Qfalse;
871
860
  }
@@ -875,95 +864,86 @@ encoder_optimized(VALUE self, VALUE clas) {
875
864
  *
876
865
  * Returns true if the specified Class is being optimized.
877
866
  */
878
- static VALUE
879
- rails_optimized(VALUE self, VALUE clas) {
880
- ROpt ro = oj_rails_get_opt(&ropts, clas);
867
+ static VALUE rails_optimized(VALUE self, VALUE clas) {
868
+ ROpt ro = oj_rails_get_opt(&ropts, clas);
881
869
 
882
870
  if (NULL == ro) {
883
- return Qfalse;
871
+ return Qfalse;
884
872
  }
885
873
  return (ro->on) ? Qtrue : Qfalse;
886
874
  }
887
875
 
888
876
  typedef struct _oo {
889
- Out out;
890
- VALUE obj;
877
+ Out out;
878
+ VALUE obj;
891
879
  } *OO;
892
880
 
893
- static VALUE
894
- protect_dump(VALUE ov) {
895
- OO oo = (OO)ov;
881
+ static VALUE protect_dump(VALUE ov) {
882
+ OO oo = (OO)ov;
896
883
 
897
884
  dump_rails_val(oo->obj, 0, oo->out, true);
898
885
 
899
886
  return Qnil;
900
887
  }
901
888
 
902
- static VALUE
903
- encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *argv) {
904
- char buf[4096];
905
- struct _out out;
906
- struct _options copts = *opts;
907
- volatile VALUE rstr = Qnil;
908
- struct _oo oo;
909
- int line = 0;
910
-
911
- oo.out = &out;
912
- oo.obj = obj;
889
+ static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *argv) {
890
+ struct _out out;
891
+ struct _options copts = *opts;
892
+ volatile VALUE rstr = Qnil;
893
+ struct _oo oo;
894
+ int line = 0;
895
+
896
+ oo.out = &out;
897
+ oo.obj = obj;
913
898
  copts.str_rx.head = NULL;
914
899
  copts.str_rx.tail = NULL;
915
- copts.mode = RailsMode;
900
+ copts.mode = RailsMode;
916
901
  if (escape_html) {
917
- copts.escape_mode = RailsXEsc;
902
+ copts.escape_mode = RailsXEsc;
918
903
  } else {
919
- copts.escape_mode = RailsEsc;
904
+ copts.escape_mode = RailsEsc;
920
905
  }
921
- out.buf = buf;
922
- out.end = buf + sizeof(buf) - 10;
923
- out.allocated = false;
906
+
907
+ oj_out_init(&out);
908
+
924
909
  out.omit_nil = copts.dump_opts.omit_nil;
925
- out.caller = 0;
926
- out.cur = out.buf;
910
+ out.cur = out.buf;
927
911
  out.circ_cnt = 0;
928
- out.opts = &copts;
912
+ out.opts = &copts;
929
913
  out.hash_cnt = 0;
930
- out.indent = copts.indent;
931
- out.argc = argc;
932
- out.argv = argv;
933
- out.ropts = ropts;
914
+ out.indent = copts.indent;
915
+ out.argc = argc;
916
+ out.argv = argv;
917
+ out.ropts = ropts;
934
918
  if (Yes == copts.circular) {
935
- oj_cache8_new(&out.circ_cache);
919
+ oj_cache8_new(&out.circ_cache);
936
920
  }
937
- //dump_rails_val(*argv, 0, &out, true);
921
+ // dump_rails_val(*argv, 0, &out, true);
938
922
  rb_protect(protect_dump, (VALUE)&oo, &line);
939
923
 
940
924
  if (0 == line) {
941
- if (0 < out.indent) {
942
- switch (*(out.cur - 1)) {
943
- case ']':
944
- case '}':
945
- assure_size(&out, 2);
946
- *out.cur++ = '\n';
947
- default:
948
- break;
949
- }
950
- }
951
- *out.cur = '\0';
952
-
953
- if (0 == out.buf) {
954
- rb_raise(rb_eNoMemError, "Not enough memory.");
955
- }
956
- rstr = rb_str_new2(out.buf);
957
- rstr = oj_encode(rstr);
925
+ if (0 < out.indent) {
926
+ switch (*(out.cur - 1)) {
927
+ case ']':
928
+ case '}': assure_size(&out, 2); *out.cur++ = '\n';
929
+ default: break;
930
+ }
931
+ }
932
+ *out.cur = '\0';
933
+
934
+ if (0 == out.buf) {
935
+ rb_raise(rb_eNoMemError, "Not enough memory.");
936
+ }
937
+ rstr = rb_utf8_str_new_cstr(out.buf);
958
938
  }
959
939
  if (Yes == copts.circular) {
960
- oj_cache8_delete(out.circ_cache);
961
- }
962
- if (out.allocated) {
963
- xfree(out.buf);
940
+ oj_cache8_delete(out.circ_cache);
964
941
  }
942
+
943
+ oj_out_free(&out);
944
+
965
945
  if (0 != line) {
966
- rb_jump_tag(line);
946
+ rb_jump_tag(line);
967
947
  }
968
948
  return rstr;
969
949
  }
@@ -975,14 +955,14 @@ encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *argv) {
975
955
  *
976
956
  * Returns encoded object as a JSON string.
977
957
  */
978
- static VALUE
979
- encoder_encode(VALUE self, VALUE obj) {
980
- Encoder e = (Encoder)DATA_PTR(self);
958
+ static VALUE encoder_encode(VALUE self, VALUE obj) {
959
+ Encoder e;
960
+ TypedData_Get_Struct(self, struct _encoder, &oj_encoder_type, e);
981
961
 
982
962
  if (Qnil != e->arg) {
983
- VALUE argv[1] = { e->arg };
963
+ VALUE argv[1] = {e->arg};
984
964
 
985
- return encode(obj, &e->ropts, &e->opts, 1, argv);
965
+ return encode(obj, &e->ropts, &e->opts, 1, argv);
986
966
  }
987
967
  return encode(obj, &e->ropts, &e->opts, 0, NULL);
988
968
  }
@@ -997,25 +977,24 @@ encoder_encode(VALUE self, VALUE obj) {
997
977
  *
998
978
  * Returns [_String_]
999
979
  */
1000
- static VALUE
1001
- rails_encode(int argc, VALUE *argv, VALUE self) {
980
+ static VALUE rails_encode(int argc, VALUE *argv, VALUE self) {
1002
981
  if (1 > argc) {
1003
- rb_raise(rb_eArgError, "wrong number of arguments (0 for 1).");
982
+ rb_raise(rb_eArgError, "wrong number of arguments (0 for 1).");
1004
983
  }
1005
984
  if (1 == argc) {
1006
- return encode(*argv, NULL, &oj_default_options, 0, NULL);
985
+ return encode(*argv, NULL, &oj_default_options, 0, NULL);
1007
986
  } else {
1008
- return encode(*argv, NULL, &oj_default_options, argc - 1, argv + 1);
987
+ return encode(*argv, NULL, &oj_default_options, argc - 1, argv + 1);
1009
988
  }
1010
989
  }
1011
990
 
1012
- static VALUE
1013
- rails_use_standard_json_time_format(VALUE self, VALUE state) {
991
+ static VALUE rails_use_standard_json_time_format(VALUE self, VALUE state) {
1014
992
  if (Qtrue == state || Qfalse == state) {
993
+ // no change needed
1015
994
  } else if (Qnil == state) {
1016
- state = Qfalse;
995
+ state = Qfalse;
1017
996
  } else {
1018
- state = Qtrue;
997
+ state = Qtrue;
1019
998
  }
1020
999
  rb_iv_set(self, "@use_standard_json_time_format", state);
1021
1000
  xml_time = Qtrue == state;
@@ -1023,18 +1002,25 @@ rails_use_standard_json_time_format(VALUE self, VALUE state) {
1023
1002
  return state;
1024
1003
  }
1025
1004
 
1026
- static VALUE
1027
- rails_escape_html_entities_in_json(VALUE self, VALUE state) {
1005
+ static VALUE rails_use_standard_json_time_format_get(VALUE self) {
1006
+ return xml_time ? Qtrue : Qfalse;
1007
+ }
1008
+
1009
+ static VALUE rails_escape_html_entities_in_json(VALUE self, VALUE state) {
1028
1010
  rb_iv_set(self, "@escape_html_entities_in_json", state);
1029
1011
  escape_html = Qtrue == state;
1030
1012
 
1031
1013
  return state;
1032
1014
  }
1033
1015
 
1034
- static VALUE
1035
- rails_time_precision(VALUE self, VALUE prec) {
1016
+ static VALUE rails_escape_html_entities_in_json_get(VALUE self) {
1017
+ return escape_html ? Qtrue : Qfalse;
1018
+ }
1019
+
1020
+ static VALUE rails_time_precision(VALUE self, VALUE prec) {
1036
1021
  rb_iv_set(self, "@time_precision", prec);
1037
- oj_default_options.sec_prec = NUM2INT(prec);
1022
+ oj_default_options.sec_prec = NUM2INT(prec);
1023
+ oj_default_options.sec_prec_set = true;
1038
1024
 
1039
1025
  return prec;
1040
1026
  }
@@ -1046,22 +1032,26 @@ rails_time_precision(VALUE self, VALUE prec) {
1046
1032
  * formatting globals used by ActiveSupport to allow the use of those globals
1047
1033
  * in the Oj::Rails optimizations.
1048
1034
  */
1049
- static VALUE
1050
- rails_set_encoder(VALUE self) {
1051
- VALUE active;
1052
- VALUE json;
1053
- VALUE encoding;
1054
- VALUE pv;
1055
- VALUE verbose;
1056
-
1035
+ static VALUE rails_set_encoder(VALUE self) {
1036
+ VALUE active;
1037
+ VALUE json;
1038
+ VALUE encoding;
1039
+ VALUE pv;
1040
+ VALUE verbose;
1041
+ VALUE enc = resolve_classpath("ActiveSupport::JSON::Encoding");
1042
+
1043
+ if (Qnil != enc) {
1044
+ escape_html = Qtrue == rb_iv_get(self, "@escape_html_entities_in_json");
1045
+ xml_time = Qtrue == rb_iv_get(enc, "@use_standard_json_time_format");
1046
+ }
1057
1047
  if (rb_const_defined_at(rb_cObject, rb_intern("ActiveSupport"))) {
1058
- active = rb_const_get_at(rb_cObject, rb_intern("ActiveSupport"));
1048
+ active = rb_const_get_at(rb_cObject, rb_intern("ActiveSupport"));
1059
1049
  } else {
1060
- rb_raise(rb_eStandardError, "ActiveSupport not loaded.");
1050
+ rb_raise(rb_eStandardError, "ActiveSupport not loaded.");
1061
1051
  }
1062
1052
  rb_funcall(active, rb_intern("json_encoder="), 1, encoder_class);
1063
1053
 
1064
- json = rb_const_get_at(active, rb_intern("JSON"));
1054
+ json = rb_const_get_at(active, rb_intern("JSON"));
1065
1055
  encoding = rb_const_get_at(json, rb_intern("Encoding"));
1066
1056
 
1067
1057
  // rb_undef_method doesn't work for modules or maybe sometimes
@@ -1070,14 +1060,19 @@ rails_set_encoder(VALUE self) {
1070
1060
  rb_gv_set("$VERBOSE", Qfalse);
1071
1061
  rb_undef_method(encoding, "use_standard_json_time_format=");
1072
1062
  rb_define_module_function(encoding, "use_standard_json_time_format=", rails_use_standard_json_time_format, 1);
1063
+ rb_undef_method(encoding, "use_standard_json_time_format");
1064
+ rb_define_module_function(encoding, "use_standard_json_time_format", rails_use_standard_json_time_format_get, 0);
1073
1065
 
1074
- pv = rb_iv_get(encoding, "@escape_html_entities_in_json");
1066
+ pv = rb_iv_get(encoding, "@escape_html_entities_in_json");
1075
1067
  escape_html = Qtrue == pv;
1076
1068
  rb_undef_method(encoding, "escape_html_entities_in_json=");
1077
1069
  rb_define_module_function(encoding, "escape_html_entities_in_json=", rails_escape_html_entities_in_json, 1);
1070
+ rb_undef_method(encoding, "escape_html_entities_in_json");
1071
+ rb_define_module_function(encoding, "escape_html_entities_in_json", rails_escape_html_entities_in_json_get, 0);
1078
1072
 
1079
- pv = rb_iv_get(encoding, "@time_precision");
1080
- oj_default_options.sec_prec = NUM2INT(pv);
1073
+ pv = rb_iv_get(encoding, "@time_precision");
1074
+ oj_default_options.sec_prec = NUM2INT(pv);
1075
+ oj_default_options.sec_prec_set = true;
1081
1076
  rb_undef_method(encoding, "time_precision=");
1082
1077
  rb_define_module_function(encoding, "time_precision=", rails_time_precision, 1);
1083
1078
  rb_gv_set("$VERBOSE", verbose);
@@ -1091,26 +1086,27 @@ rails_set_encoder(VALUE self) {
1091
1086
  * Sets the JSON.parse function to be the Oj::parse function which is json gem
1092
1087
  * compatible.
1093
1088
  */
1094
- static VALUE
1095
- rails_set_decoder(VALUE self) {
1096
- VALUE json;
1097
- VALUE json_error;
1098
- VALUE verbose;
1089
+ static VALUE rails_set_decoder(VALUE self) {
1090
+ VALUE json;
1091
+ VALUE json_error;
1092
+ VALUE verbose;
1099
1093
 
1100
1094
  if (rb_const_defined_at(rb_cObject, rb_intern("JSON"))) {
1101
- json = rb_const_get_at(rb_cObject, rb_intern("JSON"));
1095
+ json = rb_const_get_at(rb_cObject, rb_intern("JSON"));
1102
1096
  } else {
1103
- json = rb_define_module("JSON");
1097
+ json = rb_define_module("JSON");
1104
1098
  }
1105
1099
  if (rb_const_defined_at(json, rb_intern("JSONError"))) {
1106
1100
  json_error = rb_const_get(json, rb_intern("JSONError"));
1107
1101
  } else {
1108
1102
  json_error = rb_define_class_under(json, "JSONError", rb_eStandardError);
1109
1103
  }
1104
+
1105
+ rb_global_variable(&oj_json_parser_error_class);
1110
1106
  if (rb_const_defined_at(json, rb_intern("ParserError"))) {
1111
1107
  oj_json_parser_error_class = rb_const_get(json, rb_intern("ParserError"));
1112
1108
  } else {
1113
- oj_json_parser_error_class = rb_define_class_under(json, "ParserError", json_error);
1109
+ oj_json_parser_error_class = rb_define_class_under(json, "ParserError", json_error);
1114
1110
  }
1115
1111
  // rb_undef_method doesn't work for modules or maybe sometimes
1116
1112
  // doesn't. Anyway setting verbose should hide the warning.
@@ -1146,13 +1142,15 @@ oj_optimize_rails(VALUE self) {
1146
1142
  *
1147
1143
  * The Oj ActiveSupport compliant encoder.
1148
1144
  */
1149
- void
1150
- oj_mimic_rails_init() {
1151
- VALUE rails = rb_define_module_under(Oj, "Rails");
1145
+ void oj_mimic_rails_init(void) {
1146
+ VALUE rails = rb_define_module_under(Oj, "Rails");
1152
1147
 
1153
1148
  rb_define_module_function(rails, "encode", rails_encode, -1);
1154
1149
 
1155
1150
  encoder_class = rb_define_class_under(rails, "Encoder", rb_cObject);
1151
+ rb_gc_register_address(&encoder_class);
1152
+ rb_undef_alloc_func(encoder_class);
1153
+
1156
1154
  rb_define_module_function(encoder_class, "new", encoder_new, -1);
1157
1155
  rb_define_module_function(rails, "optimize", rails_optimize, -1);
1158
1156
  rb_define_module_function(rails, "deoptimize", rails_deoptimize, -1);
@@ -1168,328 +1166,313 @@ oj_mimic_rails_init() {
1168
1166
  rb_define_method(encoder_class, "optimized?", encoder_optimized, 1);
1169
1167
  }
1170
1168
 
1171
- static void
1172
- dump_to_hash(VALUE obj, int depth, Out out) {
1169
+ static void dump_to_hash(VALUE obj, int depth, Out out) {
1173
1170
  dump_rails_val(rb_funcall(obj, oj_to_hash_id, 0), depth, out, true);
1174
1171
  }
1175
1172
 
1176
- static void
1177
- dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1178
- char buf[64];
1179
- char *b;
1180
- double d = rb_num2dbl(obj);
1181
- int cnt = 0;
1173
+ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1174
+ char buf[64];
1175
+ char *b;
1176
+ double d = rb_num2dbl(obj);
1177
+ size_t cnt = 0;
1182
1178
 
1183
1179
  if (0.0 == d) {
1184
- b = buf;
1185
- *b++ = '0';
1186
- *b++ = '.';
1187
- *b++ = '0';
1188
- *b++ = '\0';
1189
- cnt = 3;
1180
+ b = buf;
1181
+ *b++ = '0';
1182
+ *b++ = '.';
1183
+ *b++ = '0';
1184
+ *b++ = '\0';
1185
+ cnt = 3;
1190
1186
  } else {
1191
- if (isnan(d) || OJ_INFINITY == d || -OJ_INFINITY == d) {
1192
- strcpy(buf, "null");
1193
- cnt = 4;
1194
- } else if (d == (double)(long long int)d) {
1195
- cnt = snprintf(buf, sizeof(buf), "%.1f", d);
1196
- } else if (oj_rails_float_opt) {
1197
- cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, "%0.16g");
1198
- } else {
1199
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
1200
-
1201
- strcpy(buf, rb_string_value_ptr((VALUE*)&rstr));
1202
- cnt = (int)RSTRING_LEN(rstr);
1203
- }
1187
+ if (isnan(d) || OJ_INFINITY == d || -OJ_INFINITY == d) {
1188
+ strcpy(buf, "null");
1189
+ cnt = 4;
1190
+ } else if (d == (double)(long long int)d) {
1191
+ cnt = snprintf(buf, sizeof(buf), "%.1f", d);
1192
+ } else if (oj_rails_float_opt) {
1193
+ cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, "%0.16g");
1194
+ } else {
1195
+ volatile VALUE rstr = oj_safe_string_convert(obj);
1196
+
1197
+ strcpy(buf, RSTRING_PTR(rstr));
1198
+ cnt = RSTRING_LEN(rstr);
1199
+ }
1204
1200
  }
1205
1201
  assure_size(out, cnt);
1206
1202
  for (b = buf; '\0' != *b; b++) {
1207
- *out->cur++ = *b;
1203
+ *out->cur++ = *b;
1208
1204
  }
1209
1205
  *out->cur = '\0';
1210
1206
  }
1211
1207
 
1212
- static void
1213
- dump_array(VALUE a, int depth, Out out, bool as_ok) {
1214
- size_t size;
1215
- int i, cnt;
1216
- int d2 = depth + 1;
1208
+ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
1209
+ size_t size;
1210
+ size_t i;
1211
+ size_t cnt;
1212
+ int d2 = depth + 1;
1217
1213
 
1218
1214
  if (Yes == out->opts->circular) {
1219
- if (0 > oj_check_circular(a, out)) {
1220
- oj_dump_nil(Qnil, 0, out, false);
1221
- return;
1222
- }
1215
+ if (0 > oj_check_circular(a, out)) {
1216
+ oj_dump_nil(Qnil, 0, out, false);
1217
+ return;
1218
+ }
1223
1219
  }
1224
- //if (!oj_rails_array_opt && as_ok && 0 < out->argc && rb_respond_to(a, oj_as_json_id)) {
1220
+ // if (!oj_rails_array_opt && as_ok && 0 < out->argc && rb_respond_to(a, oj_as_json_id)) {
1225
1221
  if (as_ok && 0 < out->argc && rb_respond_to(a, oj_as_json_id)) {
1226
- dump_as_json(a, depth, out, false);
1227
- return;
1222
+ dump_as_json(a, depth, out, false);
1223
+ return;
1228
1224
  }
1229
- cnt = (int)RARRAY_LEN(a);
1225
+ cnt = RARRAY_LEN(a);
1230
1226
  *out->cur++ = '[';
1231
- size = 2;
1227
+ size = 2;
1232
1228
  assure_size(out, size);
1233
1229
  if (0 == cnt) {
1234
- *out->cur++ = ']';
1230
+ *out->cur++ = ']';
1235
1231
  } else {
1236
- if (out->opts->dump_opts.use) {
1237
- size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
1238
- } else {
1239
- size = d2 * out->indent + 2;
1240
- }
1241
- cnt--;
1242
- for (i = 0; i <= cnt; i++) {
1243
- assure_size(out, size);
1244
- if (out->opts->dump_opts.use) {
1245
- if (0 < out->opts->dump_opts.array_size) {
1246
- strcpy(out->cur, out->opts->dump_opts.array_nl);
1247
- out->cur += out->opts->dump_opts.array_size;
1248
- }
1249
- if (0 < out->opts->dump_opts.indent_size) {
1250
- int i;
1251
- for (i = d2; 0 < i; i--) {
1252
- strcpy(out->cur, out->opts->dump_opts.indent_str);
1253
- out->cur += out->opts->dump_opts.indent_size;
1254
- }
1255
- }
1256
- } else {
1257
- fill_indent(out, d2);
1258
- }
1259
- dump_rails_val(rb_ary_entry(a, i), d2, out, true);
1260
- if (i < cnt) {
1261
- *out->cur++ = ',';
1262
- }
1263
- }
1264
- size = depth * out->indent + 1;
1265
- assure_size(out, size);
1266
- if (out->opts->dump_opts.use) {
1267
- if (0 < out->opts->dump_opts.array_size) {
1268
- strcpy(out->cur, out->opts->dump_opts.array_nl);
1269
- out->cur += out->opts->dump_opts.array_size;
1270
- }
1271
- if (0 < out->opts->dump_opts.indent_size) {
1272
- int i;
1273
-
1274
- for (i = depth; 0 < i; i--) {
1275
- strcpy(out->cur, out->opts->dump_opts.indent_str);
1276
- out->cur += out->opts->dump_opts.indent_size;
1277
- }
1278
- }
1279
- } else {
1280
- fill_indent(out, depth);
1281
- }
1282
- *out->cur++ = ']';
1232
+ if (out->opts->dump_opts.use) {
1233
+ size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
1234
+ } else {
1235
+ size = d2 * out->indent + 2;
1236
+ }
1237
+ assure_size(out, size * cnt);
1238
+ cnt--;
1239
+ for (i = 0; i <= cnt; i++) {
1240
+ if (out->opts->dump_opts.use) {
1241
+ if (0 < out->opts->dump_opts.array_size) {
1242
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
1243
+ }
1244
+ if (0 < out->opts->dump_opts.indent_size) {
1245
+ int i;
1246
+ for (i = d2; 0 < i; i--) {
1247
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1248
+ }
1249
+ }
1250
+ } else {
1251
+ fill_indent(out, d2);
1252
+ }
1253
+ dump_rails_val(RARRAY_AREF(a, i), d2, out, true);
1254
+ if (i < cnt) {
1255
+ *out->cur++ = ',';
1256
+ }
1257
+ }
1258
+ size = depth * out->indent + 1;
1259
+ assure_size(out, size);
1260
+ if (out->opts->dump_opts.use) {
1261
+ if (0 < out->opts->dump_opts.array_size) {
1262
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
1263
+ }
1264
+ if (0 < out->opts->dump_opts.indent_size) {
1265
+ int i;
1266
+
1267
+ for (i = depth; 0 < i; i--) {
1268
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1269
+ }
1270
+ }
1271
+ } else {
1272
+ fill_indent(out, depth);
1273
+ }
1274
+ *out->cur++ = ']';
1283
1275
  }
1284
1276
  *out->cur = '\0';
1285
1277
  }
1286
1278
 
1287
- static int
1288
- hash_cb(VALUE key, VALUE value, Out out) {
1289
- int depth = out->depth;
1290
- long size;
1291
- int rtype = rb_type(key);
1279
+ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
1280
+ Out out = (Out)ov;
1281
+ int depth = out->depth;
1282
+ long size;
1283
+ int rtype = rb_type(key);
1292
1284
 
1293
1285
  if (out->omit_nil && Qnil == value) {
1294
- return ST_CONTINUE;
1286
+ return ST_CONTINUE;
1295
1287
  }
1296
1288
  if (rtype != T_STRING && rtype != T_SYMBOL) {
1297
- key = rb_funcall(key, oj_to_s_id, 0);
1298
- rtype = rb_type(key);
1289
+ key = oj_safe_string_convert(key);
1290
+ rtype = rb_type(key);
1299
1291
  }
1300
1292
  if (!out->opts->dump_opts.use) {
1301
- size = depth * out->indent + 1;
1302
- assure_size(out, size);
1303
- fill_indent(out, depth);
1304
- if (rtype == T_STRING) {
1305
- oj_dump_str(key, 0, out, false);
1306
- } else {
1307
- oj_dump_sym(key, 0, out, false);
1308
- }
1309
- *out->cur++ = ':';
1293
+ size = depth * out->indent + 1;
1294
+ assure_size(out, size);
1295
+ fill_indent(out, depth);
1296
+ if (rtype == T_STRING) {
1297
+ oj_dump_str(key, 0, out, false);
1298
+ } else {
1299
+ oj_dump_sym(key, 0, out, false);
1300
+ }
1301
+ *out->cur++ = ':';
1310
1302
  } else {
1311
- size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
1312
- assure_size(out, size);
1313
- if (0 < out->opts->dump_opts.hash_size) {
1314
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
1315
- out->cur += out->opts->dump_opts.hash_size;
1316
- }
1317
- if (0 < out->opts->dump_opts.indent_size) {
1318
- int i;
1319
- for (i = depth; 0 < i; i--) {
1320
- strcpy(out->cur, out->opts->dump_opts.indent_str);
1321
- out->cur += out->opts->dump_opts.indent_size;
1322
- }
1323
- }
1324
- if (rtype == T_STRING) {
1325
- oj_dump_str(key, 0, out, false);
1326
- } else {
1327
- oj_dump_sym(key, 0, out, false);
1328
- }
1329
- size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
1330
- assure_size(out, size);
1331
- if (0 < out->opts->dump_opts.before_size) {
1332
- strcpy(out->cur, out->opts->dump_opts.before_sep);
1333
- out->cur += out->opts->dump_opts.before_size;
1334
- }
1335
- *out->cur++ = ':';
1336
- if (0 < out->opts->dump_opts.after_size) {
1337
- strcpy(out->cur, out->opts->dump_opts.after_sep);
1338
- out->cur += out->opts->dump_opts.after_size;
1339
- }
1303
+ size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
1304
+ assure_size(out, size);
1305
+ if (0 < out->opts->dump_opts.hash_size) {
1306
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
1307
+ }
1308
+ if (0 < out->opts->dump_opts.indent_size) {
1309
+ int i;
1310
+ for (i = depth; 0 < i; i--) {
1311
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1312
+ }
1313
+ }
1314
+ if (rtype == T_STRING) {
1315
+ oj_dump_str(key, 0, out, false);
1316
+ } else {
1317
+ oj_dump_sym(key, 0, out, false);
1318
+ }
1319
+ size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
1320
+ assure_size(out, size);
1321
+ if (0 < out->opts->dump_opts.before_size) {
1322
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
1323
+ }
1324
+ *out->cur++ = ':';
1325
+ if (0 < out->opts->dump_opts.after_size) {
1326
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
1327
+ }
1340
1328
  }
1341
1329
  dump_rails_val(value, depth, out, true);
1342
- out->depth = depth;
1330
+ out->depth = depth;
1343
1331
  *out->cur++ = ',';
1344
1332
 
1345
1333
  return ST_CONTINUE;
1346
1334
  }
1347
1335
 
1348
- static void
1349
- dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
1350
- int cnt;
1351
- size_t size;
1336
+ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
1337
+ int cnt;
1338
+ size_t size;
1352
1339
 
1353
1340
  if (Yes == out->opts->circular) {
1354
- if (0 > oj_check_circular(obj, out)) {
1355
- oj_dump_nil(Qnil, 0, out, false);
1356
- return;
1357
- }
1341
+ if (0 > oj_check_circular(obj, out)) {
1342
+ oj_dump_nil(Qnil, 0, out, false);
1343
+ return;
1344
+ }
1358
1345
  }
1359
1346
  if ((!oj_rails_hash_opt || 0 < out->argc) && as_ok && rb_respond_to(obj, oj_as_json_id)) {
1360
- dump_as_json(obj, depth, out, false);
1361
- return;
1347
+ dump_as_json(obj, depth, out, false);
1348
+ return;
1362
1349
  }
1363
- cnt = (int)RHASH_SIZE(obj);
1350
+ cnt = (int)RHASH_SIZE(obj);
1364
1351
  size = depth * out->indent + 2;
1365
1352
  assure_size(out, 2);
1366
1353
  *out->cur++ = '{';
1367
1354
  if (0 == cnt) {
1368
- *out->cur++ = '}';
1355
+ *out->cur++ = '}';
1369
1356
  } else {
1370
- out->depth = depth + 1;
1371
- rb_hash_foreach(obj, hash_cb, (VALUE)out);
1372
- if (',' == *(out->cur - 1)) {
1373
- out->cur--; // backup to overwrite last comma
1374
- }
1375
- if (!out->opts->dump_opts.use) {
1376
- assure_size(out, size);
1377
- fill_indent(out, depth);
1378
- } else {
1379
- size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
1380
- assure_size(out, size);
1381
- if (0 < out->opts->dump_opts.hash_size) {
1382
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
1383
- out->cur += out->opts->dump_opts.hash_size;
1384
- }
1385
- if (0 < out->opts->dump_opts.indent_size) {
1386
- int i;
1387
-
1388
- for (i = depth; 0 < i; i--) {
1389
- strcpy(out->cur, out->opts->dump_opts.indent_str);
1390
- out->cur += out->opts->dump_opts.indent_size;
1391
- }
1392
- }
1393
- }
1394
- *out->cur++ = '}';
1357
+ out->depth = depth + 1;
1358
+ rb_hash_foreach(obj, hash_cb, (VALUE)out);
1359
+ if (',' == *(out->cur - 1)) {
1360
+ out->cur--; // backup to overwrite last comma
1361
+ }
1362
+ if (!out->opts->dump_opts.use) {
1363
+ assure_size(out, size);
1364
+ fill_indent(out, depth);
1365
+ } else {
1366
+ size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
1367
+ assure_size(out, size);
1368
+ if (0 < out->opts->dump_opts.hash_size) {
1369
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
1370
+ }
1371
+ if (0 < out->opts->dump_opts.indent_size) {
1372
+ int i;
1373
+
1374
+ for (i = depth; 0 < i; i--) {
1375
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1376
+ }
1377
+ }
1378
+ }
1379
+ *out->cur++ = '}';
1395
1380
  }
1396
1381
  *out->cur = '\0';
1397
1382
  }
1398
1383
 
1399
- static void
1400
- dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
1384
+ static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
1385
+ VALUE clas;
1386
+
1401
1387
  if (oj_code_dump(oj_compat_codes, obj, depth, out)) {
1402
- out->argc = 0;
1403
- return;
1388
+ out->argc = 0;
1389
+ return;
1404
1390
  }
1391
+ clas = rb_obj_class(obj);
1405
1392
  if (as_ok) {
1406
- ROpt ro;
1407
-
1408
- if (NULL != (ro = oj_rails_get_opt(out->ropts, rb_obj_class(obj))) && ro->on) {
1409
- ro->dump(obj, depth, out, as_ok);
1410
- } else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
1411
- oj_dump_raw_json(obj, depth, out);
1412
- } else if (rb_respond_to(obj, oj_as_json_id)) {
1413
- dump_as_json(obj, depth, out, true);
1414
- } else if (rb_respond_to(obj, oj_to_hash_id)) {
1415
- dump_to_hash(obj, depth, out);
1416
- } else {
1417
- oj_dump_obj_to_s(obj, out);
1418
- }
1393
+ ROpt ro;
1394
+
1395
+ if (NULL != (ro = oj_rails_get_opt(out->ropts, clas)) && ro->on) {
1396
+ ro->dump(obj, depth, out, as_ok);
1397
+ } else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
1398
+ oj_dump_raw_json(obj, depth, out);
1399
+ } else if (rb_respond_to(obj, oj_as_json_id)) {
1400
+ dump_as_json(obj, depth, out, true);
1401
+ } else if (rb_respond_to(obj, oj_to_hash_id)) {
1402
+ dump_to_hash(obj, depth, out);
1403
+ } else if (oj_bigdecimal_class == clas) {
1404
+ dump_bigdecimal(obj, depth, out, false);
1405
+ } else {
1406
+ oj_dump_obj_to_s(obj, out);
1407
+ }
1419
1408
  } else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
1420
- oj_dump_raw_json(obj, depth, out);
1409
+ oj_dump_raw_json(obj, depth, out);
1421
1410
  } else if (rb_respond_to(obj, oj_to_hash_id)) {
1422
- // Always attempt to_hash.
1423
- dump_to_hash(obj, depth, out);
1411
+ // Always attempt to_hash.
1412
+ dump_to_hash(obj, depth, out);
1413
+ } else if (oj_bigdecimal_class == clas) {
1414
+ dump_bigdecimal(obj, depth, out, false);
1424
1415
  } else {
1425
- oj_dump_obj_to_s(obj, out);
1416
+ oj_dump_obj_to_s(obj, out);
1426
1417
  }
1427
1418
  }
1428
1419
 
1429
- static DumpFunc rails_funcs[] = {
1430
- NULL, // RUBY_T_NONE = 0x00,
1431
- dump_obj, // RUBY_T_OBJECT = 0x01,
1432
- oj_dump_class, // RUBY_T_CLASS = 0x02,
1433
- oj_dump_class, // RUBY_T_MODULE = 0x03,
1434
- dump_float, // RUBY_T_FLOAT = 0x04,
1435
- oj_dump_str, // RUBY_T_STRING = 0x05,
1436
- dump_regexp, // RUBY_T_REGEXP = 0x06,
1437
- //dump_as_string, // RUBY_T_REGEXP = 0x06,
1438
- dump_array, // RUBY_T_ARRAY = 0x07,
1439
- dump_hash, // RUBY_T_HASH = 0x08,
1440
- dump_obj, // RUBY_T_STRUCT = 0x09,
1441
- oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
1442
- NULL, // RUBY_T_FILE = 0x0b,
1443
- dump_obj, // RUBY_T_DATA = 0x0c,
1444
- NULL, // RUBY_T_MATCH = 0x0d,
1420
+ static DumpFunc rails_funcs[] = {
1421
+ NULL, // RUBY_T_NONE = 0x00,
1422
+ dump_obj, // RUBY_T_OBJECT = 0x01,
1423
+ oj_dump_class, // RUBY_T_CLASS = 0x02,
1424
+ oj_dump_class, // RUBY_T_MODULE = 0x03,
1425
+ dump_float, // RUBY_T_FLOAT = 0x04,
1426
+ oj_dump_str, // RUBY_T_STRING = 0x05,
1427
+ dump_regexp, // RUBY_T_REGEXP = 0x06,
1428
+ // dump_as_string, // RUBY_T_REGEXP = 0x06,
1429
+ dump_array, // RUBY_T_ARRAY = 0x07,
1430
+ dump_hash, // RUBY_T_HASH = 0x08,
1431
+ dump_obj, // RUBY_T_STRUCT = 0x09,
1432
+ oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
1433
+ dump_as_string, // RUBY_T_FILE = 0x0b,
1434
+ dump_obj, // RUBY_T_DATA = 0x0c,
1435
+ NULL, // RUBY_T_MATCH = 0x0d,
1445
1436
  // Rails raises a stack error on Complex and Rational. It also corrupts
1446
1437
  // something which causes a segfault on the next call. Oj will not mimic
1447
1438
  // that behavior.
1448
- dump_as_string, // RUBY_T_COMPLEX = 0x0e,
1449
- dump_as_string, // RUBY_T_RATIONAL = 0x0f,
1450
- NULL, // 0x10
1451
- oj_dump_nil, // RUBY_T_NIL = 0x11,
1452
- oj_dump_true, // RUBY_T_TRUE = 0x12,
1453
- oj_dump_false, // RUBY_T_FALSE = 0x13,
1454
- oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
1455
- oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
1439
+ dump_as_string, // RUBY_T_COMPLEX = 0x0e,
1440
+ dump_as_string, // RUBY_T_RATIONAL = 0x0f,
1441
+ NULL, // 0x10
1442
+ oj_dump_nil, // RUBY_T_NIL = 0x11,
1443
+ oj_dump_true, // RUBY_T_TRUE = 0x12,
1444
+ oj_dump_false, // RUBY_T_FALSE = 0x13,
1445
+ oj_dump_sym, // RUBY_T_SYMBOL = 0x14,
1446
+ oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
1456
1447
  };
1457
1448
 
1458
- static void
1459
- dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
1460
- int type = rb_type(obj);
1449
+ static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
1450
+ int type = rb_type(obj);
1461
1451
 
1462
- if (Yes == out->opts->trace) {
1463
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
1464
- }
1452
+ TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
1465
1453
  if (MAX_DEPTH < depth) {
1466
- rb_raise(rb_eNoMemError, "Too deeply nested.\n");
1454
+ rb_raise(rb_eNoMemError, "Too deeply nested.\n");
1467
1455
  }
1468
1456
  if (0 < type && type <= RUBY_T_FIXNUM) {
1469
- DumpFunc f = rails_funcs[type];
1457
+ DumpFunc f = rails_funcs[type];
1470
1458
 
1471
- if (NULL != f) {
1472
- f(obj, depth, out, as_ok);
1473
- if (Yes == out->opts->trace) {
1474
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
1475
- }
1476
- return;
1477
- }
1459
+ if (NULL != f) {
1460
+ f(obj, depth, out, as_ok);
1461
+ TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
1462
+ return;
1463
+ }
1478
1464
  }
1479
1465
  oj_dump_nil(Qnil, depth, out, false);
1480
- if (Yes == out->opts->trace) {
1481
- oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
1482
- }
1466
+ TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
1483
1467
  }
1484
1468
 
1485
- void
1486
- oj_dump_rails_val(VALUE obj, int depth, Out out) {
1469
+ void oj_dump_rails_val(VALUE obj, int depth, Out out) {
1487
1470
  out->opts->str_rx.head = NULL;
1488
1471
  out->opts->str_rx.tail = NULL;
1489
1472
  if (escape_html) {
1490
- out->opts->escape_mode = RailsXEsc;
1473
+ out->opts->escape_mode = RailsXEsc;
1491
1474
  } else {
1492
- out->opts->escape_mode = RailsEsc;
1475
+ out->opts->escape_mode = RailsEsc;
1493
1476
  }
1494
1477
  dump_rails_val(obj, depth, out, true);
1495
1478
  }