oj 3.7.4 → 3.13.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1352 -0
  3. data/README.md +29 -8
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +53 -72
  6. data/ext/oj/cache.c +326 -0
  7. data/ext/oj/cache.h +21 -0
  8. data/ext/oj/cache8.c +61 -64
  9. data/ext/oj/cache8.h +12 -39
  10. data/ext/oj/circarray.c +37 -43
  11. data/ext/oj/circarray.h +16 -17
  12. data/ext/oj/code.c +165 -179
  13. data/ext/oj/code.h +27 -29
  14. data/ext/oj/compat.c +174 -194
  15. data/ext/oj/custom.c +809 -866
  16. data/ext/oj/debug.c +132 -0
  17. data/ext/oj/dump.c +848 -863
  18. data/ext/oj/dump.h +81 -67
  19. data/ext/oj/dump_compat.c +85 -123
  20. data/ext/oj/dump_leaf.c +100 -188
  21. data/ext/oj/dump_object.c +527 -656
  22. data/ext/oj/dump_strict.c +315 -338
  23. data/ext/oj/encode.h +7 -34
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +40 -29
  26. data/ext/oj/err.h +48 -48
  27. data/ext/oj/extconf.rb +17 -4
  28. data/ext/oj/fast.c +1070 -1087
  29. data/ext/oj/intern.c +301 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +469 -436
  32. data/ext/oj/object.c +525 -593
  33. data/ext/oj/odd.c +154 -138
  34. data/ext/oj/odd.h +37 -38
  35. data/ext/oj/oj.c +1325 -986
  36. data/ext/oj/oj.h +333 -316
  37. data/ext/oj/parse.c +1002 -846
  38. data/ext/oj/parse.h +92 -87
  39. data/ext/oj/parser.c +1557 -0
  40. data/ext/oj/parser.h +91 -0
  41. data/ext/oj/rails.c +888 -878
  42. data/ext/oj/rails.h +11 -14
  43. data/ext/oj/reader.c +141 -147
  44. data/ext/oj/reader.h +73 -89
  45. data/ext/oj/resolve.c +41 -62
  46. data/ext/oj/resolve.h +7 -9
  47. data/ext/oj/rxclass.c +71 -75
  48. data/ext/oj/rxclass.h +18 -19
  49. data/ext/oj/saj.c +443 -486
  50. data/ext/oj/saj2.c +602 -0
  51. data/ext/oj/scp.c +88 -113
  52. data/ext/oj/sparse.c +787 -709
  53. data/ext/oj/stream_writer.c +133 -159
  54. data/ext/oj/strict.c +127 -118
  55. data/ext/oj/string_writer.c +230 -249
  56. data/ext/oj/trace.c +34 -41
  57. data/ext/oj/trace.h +19 -19
  58. data/ext/oj/usual.c +1254 -0
  59. data/ext/oj/util.c +136 -0
  60. data/ext/oj/util.h +20 -0
  61. data/ext/oj/val_stack.c +59 -67
  62. data/ext/oj/val_stack.h +91 -129
  63. data/ext/oj/validate.c +46 -0
  64. data/ext/oj/wab.c +342 -353
  65. data/lib/oj/bag.rb +1 -0
  66. data/lib/oj/easy_hash.rb +5 -4
  67. data/lib/oj/error.rb +1 -1
  68. data/lib/oj/json.rb +1 -1
  69. data/lib/oj/mimic.rb +48 -14
  70. data/lib/oj/saj.rb +20 -6
  71. data/lib/oj/state.rb +8 -7
  72. data/lib/oj/version.rb +2 -2
  73. data/lib/oj.rb +0 -8
  74. data/pages/Compatibility.md +1 -1
  75. data/pages/JsonGem.md +15 -0
  76. data/pages/Modes.md +53 -46
  77. data/pages/Options.md +72 -11
  78. data/pages/Parser.md +309 -0
  79. data/pages/Rails.md +73 -22
  80. data/pages/Security.md +1 -1
  81. data/test/activerecord/result_test.rb +7 -2
  82. data/test/activesupport5/abstract_unit.rb +45 -0
  83. data/test/activesupport5/decoding_test.rb +68 -60
  84. data/test/activesupport5/encoding_test.rb +111 -96
  85. data/test/activesupport5/encoding_test_cases.rb +33 -25
  86. data/test/activesupport5/test_helper.rb +43 -21
  87. data/test/activesupport5/time_zone_test_helpers.rb +18 -3
  88. data/test/activesupport6/abstract_unit.rb +44 -0
  89. data/test/activesupport6/decoding_test.rb +133 -0
  90. data/test/activesupport6/encoding_test.rb +507 -0
  91. data/test/activesupport6/encoding_test_cases.rb +98 -0
  92. data/test/activesupport6/test_common.rb +17 -0
  93. data/test/activesupport6/test_helper.rb +163 -0
  94. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  95. data/test/activesupport7/abstract_unit.rb +49 -0
  96. data/test/activesupport7/decoding_test.rb +125 -0
  97. data/test/activesupport7/encoding_test.rb +486 -0
  98. data/test/activesupport7/encoding_test_cases.rb +104 -0
  99. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  100. data/test/bar.rb +6 -12
  101. data/test/baz.rb +16 -0
  102. data/test/bug.rb +16 -0
  103. data/test/foo.rb +69 -75
  104. data/test/helper.rb +16 -0
  105. data/test/json_gem/json_common_interface_test.rb +8 -3
  106. data/test/json_gem/json_generator_test.rb +18 -4
  107. data/test/json_gem/json_parser_test.rb +9 -0
  108. data/test/json_gem/test_helper.rb +12 -0
  109. data/test/mem.rb +33 -0
  110. data/test/perf.rb +1 -1
  111. data/test/perf_dump.rb +50 -0
  112. data/test/perf_once.rb +58 -0
  113. data/test/perf_parser.rb +189 -0
  114. data/test/perf_scp.rb +11 -10
  115. data/test/perf_strict.rb +17 -23
  116. data/test/prec.rb +23 -0
  117. data/test/sample_json.rb +1 -1
  118. data/test/test_compat.rb +46 -10
  119. data/test/test_custom.rb +147 -8
  120. data/test/test_fast.rb +62 -2
  121. data/test/test_file.rb +25 -2
  122. data/test/test_gc.rb +13 -0
  123. data/test/test_generate.rb +21 -0
  124. data/test/test_hash.rb +11 -1
  125. data/test/test_integer_range.rb +7 -2
  126. data/test/test_object.rb +85 -9
  127. data/test/test_parser.rb +27 -0
  128. data/test/test_parser_saj.rb +335 -0
  129. data/test/test_parser_usual.rb +217 -0
  130. data/test/test_rails.rb +35 -0
  131. data/test/test_saj.rb +1 -1
  132. data/test/test_scp.rb +5 -5
  133. data/test/test_strict.rb +26 -1
  134. data/test/test_various.rb +87 -65
  135. data/test/test_wab.rb +2 -0
  136. data/test/test_writer.rb +19 -2
  137. data/test/tests.rb +1 -1
  138. data/test/zoo.rb +13 -0
  139. metadata +60 -110
  140. data/ext/oj/hash.c +0 -163
  141. data/ext/oj/hash.h +0 -46
  142. data/ext/oj/hash_test.c +0 -512
data/ext/oj/saj.c CHANGED
@@ -1,48 +1,46 @@
1
- /* saj.c
2
- * Copyright (c) 2012, Peter Ohler
3
- * All rights reserved.
4
- */
1
+ // Copyright (c) 2012 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
  #if !IS_WINDOWS
7
- #include <sys/resource.h> /* for getrlimit() on linux */
5
+ #include <sys/resource.h> /* for getrlimit() on linux */
8
6
  #endif
9
- #include <stdlib.h>
7
+ #include <math.h>
10
8
  #include <stdio.h>
9
+ #include <stdlib.h>
11
10
  #include <string.h>
12
- #include <math.h>
13
11
  #include <sys/types.h>
14
12
  #include <unistd.h>
15
13
 
16
14
  // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
17
- #define OJ_INFINITY (1.0/0.0)
15
+ #define OJ_INFINITY (1.0 / 0.0)
18
16
 
19
- #include "oj.h"
20
17
  #include "encode.h"
18
+ #include "oj.h"
21
19
 
22
- typedef struct _ParseInfo {
23
- char *str; /* buffer being read from */
24
- char *s; /* current position in buffer */
25
- void *stack_min;
26
- VALUE handler;
27
- int has_hash_start;
28
- int has_hash_end;
29
- int has_array_start;
30
- int has_array_end;
31
- int has_add_value;
32
- int has_error;
33
- } *ParseInfo;
34
-
35
- static void read_next(ParseInfo pi, const char *key);
36
- static void read_hash(ParseInfo pi, const char *key);
37
- static void read_array(ParseInfo pi, const char *key);
38
- static void read_str(ParseInfo pi, const char *key);
39
- static void read_num(ParseInfo pi, const char *key);
40
- static void read_true(ParseInfo pi, const char *key);
41
- static void read_false(ParseInfo pi, const char *key);
42
- static void read_nil(ParseInfo pi, const char *key);
43
- static void next_non_white(ParseInfo pi);
44
- static char* read_quoted_value(ParseInfo pi);
45
- static void skip_comment(ParseInfo pi);
20
+ typedef struct _parseInfo {
21
+ char *str; /* buffer being read from */
22
+ char *s; /* current position in buffer */
23
+ void *stack_min;
24
+ VALUE handler;
25
+ int has_hash_start;
26
+ int has_hash_end;
27
+ int has_array_start;
28
+ int has_array_end;
29
+ int has_add_value;
30
+ int has_error;
31
+ } * ParseInfo;
32
+
33
+ static void read_next(ParseInfo pi, const char *key);
34
+ static void read_hash(ParseInfo pi, const char *key);
35
+ static void read_array(ParseInfo pi, const char *key);
36
+ static void read_str(ParseInfo pi, const char *key);
37
+ static void read_num(ParseInfo pi, const char *key);
38
+ static void read_true(ParseInfo pi, const char *key);
39
+ static void read_false(ParseInfo pi, const char *key);
40
+ static void read_nil(ParseInfo pi, const char *key);
41
+ static void next_non_white(ParseInfo pi);
42
+ static char *read_quoted_value(ParseInfo pi);
43
+ static void skip_comment(ParseInfo pi);
46
44
 
47
45
  /* This JSON parser is a single pass, destructive, callback parser. It is a
48
46
  * single pass parse since it only make one pass over the characters in the
@@ -57,126 +55,108 @@ static void skip_comment(ParseInfo pi);
57
55
  * all cases to parse the string.
58
56
  */
59
57
 
60
- inline static void
61
- call_error(const char *msg, ParseInfo pi, const char* file, int line) {
62
- char buf[128];
63
- const char *s = pi->s;
64
- int jline = 1;
65
- int col = 1;
58
+ inline static void call_error(const char *msg, ParseInfo pi, const char *file, int line) {
59
+ char buf[128];
60
+ const char *s = pi->s;
61
+ int jline = 1;
62
+ int col = 1;
66
63
 
67
64
  for (; pi->str < s && '\n' != *s; s--) {
68
- col++;
65
+ col++;
69
66
  }
70
67
  for (; pi->str < s; s--) {
71
- if ('\n' == *s) {
72
- jline++;
73
- }
68
+ if ('\n' == *s) {
69
+ jline++;
70
+ }
74
71
  }
75
72
  sprintf(buf, "%s at line %d, column %d [%s:%d]", msg, jline, col, file, line);
76
73
  rb_funcall(pi->handler, oj_error_id, 3, rb_str_new2(buf), LONG2NUM(jline), LONG2NUM(col));
77
74
  }
78
75
 
79
- inline static void
80
- next_non_white(ParseInfo pi) {
76
+ inline static void next_non_white(ParseInfo pi) {
81
77
  for (; 1; pi->s++) {
82
- switch(*pi->s) {
83
- case ' ':
84
- case '\t':
85
- case '\f':
86
- case '\n':
87
- case '\r':
88
- break;
89
- case '/':
90
- skip_comment(pi);
91
- break;
92
- default:
93
- return;
94
- }
78
+ switch (*pi->s) {
79
+ case ' ':
80
+ case '\t':
81
+ case '\f':
82
+ case '\n':
83
+ case '\r': break;
84
+ case '/': skip_comment(pi); break;
85
+ default: return;
86
+ }
95
87
  }
96
88
  }
97
89
 
98
- inline static void
99
- call_add_value(VALUE handler, VALUE value, const char *key) {
100
- volatile VALUE k;
90
+ inline static void call_add_value(VALUE handler, VALUE value, const char *key) {
91
+ volatile VALUE k;
101
92
 
102
93
  if (0 == key) {
103
- k = Qnil;
94
+ k = Qnil;
104
95
  } else {
105
- k = rb_str_new2(key);
106
- k = oj_encode(k);
96
+ k = rb_str_new2(key);
97
+ k = oj_encode(k);
107
98
  }
108
99
  rb_funcall(handler, oj_add_value_id, 2, value, k);
109
100
  }
110
101
 
111
- inline static void
112
- call_no_value(VALUE handler, ID method, const char *key) {
113
- volatile VALUE k;
102
+ inline static void call_no_value(VALUE handler, ID method, const char *key) {
103
+ volatile VALUE k;
114
104
 
115
105
  if (0 == key) {
116
- k = Qnil;
106
+ k = Qnil;
117
107
  } else {
118
- k = rb_str_new2(key);
119
- k = oj_encode(k);
108
+ k = rb_str_new2(key);
109
+ k = oj_encode(k);
120
110
  }
121
111
  rb_funcall(handler, method, 1, k);
122
112
  }
123
113
 
124
- static void
125
- skip_comment(ParseInfo pi) {
114
+ static void skip_comment(ParseInfo pi) {
126
115
  pi->s++; /* skip first / */
127
116
  if ('*' == *pi->s) {
128
- pi->s++;
129
- for (; '\0' != *pi->s; pi->s++) {
130
- if ('*' == *pi->s && '/' == *(pi->s + 1)) {
131
- pi->s++;
132
- return;
133
- } else if ('\0' == *pi->s) {
134
- if (pi->has_error) {
135
- call_error("comment not terminated", pi, __FILE__, __LINE__);
136
- } else {
137
- raise_error("comment not terminated", pi->str, pi->s);
138
- }
139
- }
140
- }
117
+ pi->s++;
118
+ for (; '\0' != *pi->s; pi->s++) {
119
+ if ('*' == *pi->s && '/' == *(pi->s + 1)) {
120
+ pi->s++;
121
+ return;
122
+ } else if ('\0' == *pi->s) {
123
+ if (pi->has_error) {
124
+ call_error("comment not terminated", pi, __FILE__, __LINE__);
125
+ } else {
126
+ raise_error("comment not terminated", pi->str, pi->s);
127
+ }
128
+ }
129
+ }
141
130
  } else if ('/' == *pi->s) {
142
- for (; 1; pi->s++) {
143
- switch (*pi->s) {
144
- case '\n':
145
- case '\r':
146
- case '\f':
147
- case '\0':
148
- return;
149
- default:
150
- break;
151
- }
152
- }
131
+ for (; 1; pi->s++) {
132
+ switch (*pi->s) {
133
+ case '\n':
134
+ case '\r':
135
+ case '\f':
136
+ case '\0': return;
137
+ default: break;
138
+ }
139
+ }
153
140
  } else {
154
- if (pi->has_error) {
155
- call_error("invalid comment", pi, __FILE__, __LINE__);
156
- } else {
157
- raise_error("invalid comment", pi->str, pi->s);
158
- }
141
+ if (pi->has_error) {
142
+ call_error("invalid comment", pi, __FILE__, __LINE__);
143
+ } else {
144
+ raise_error("invalid comment", pi->str, pi->s);
145
+ }
159
146
  }
160
147
  }
161
148
 
162
- static void
163
- read_next(ParseInfo pi, const char *key) {
164
- VALUE obj;
149
+ static void read_next(ParseInfo pi, const char *key) {
150
+ VALUE obj;
165
151
 
166
- if ((void*)&obj < pi->stack_min) {
167
- rb_raise(rb_eSysStackError, "JSON is too deeply nested");
152
+ if ((void *)&obj < pi->stack_min) {
153
+ rb_raise(rb_eSysStackError, "JSON is too deeply nested");
168
154
  }
169
- next_non_white(pi); /* skip white space */
155
+ next_non_white(pi); /* skip white space */
170
156
  switch (*pi->s) {
171
- case '{':
172
- read_hash(pi, key);
173
- break;
174
- case '[':
175
- read_array(pi, key);
176
- break;
177
- case '"':
178
- read_str(pi, key);
179
- break;
157
+ case '{': read_hash(pi, key); break;
158
+ case '[': read_array(pi, key); break;
159
+ case '"': read_str(pi, key); break;
180
160
  case '+':
181
161
  case '-':
182
162
  case '0':
@@ -188,113 +168,98 @@ read_next(ParseInfo pi, const char *key) {
188
168
  case '6':
189
169
  case '7':
190
170
  case '8':
191
- case '9':
192
- read_num(pi, key);
193
- break;
194
- case 'I':
195
- read_num(pi, key);
196
- break;
197
- case 't':
198
- read_true(pi, key);
199
- break;
200
- case 'f':
201
- read_false(pi, key);
202
- break;
203
- case 'n':
204
- read_nil(pi, key);
205
- break;
206
- case '\0':
207
- return;
208
- default:
209
- return;
171
+ case '9': read_num(pi, key); break;
172
+ case 'I': read_num(pi, key); break;
173
+ case 't': read_true(pi, key); break;
174
+ case 'f': read_false(pi, key); break;
175
+ case 'n': read_nil(pi, key); break;
176
+ case '\0': return;
177
+ default: return;
210
178
  }
211
179
  }
212
180
 
213
- static void
214
- read_hash(ParseInfo pi, const char *key) {
215
- const char *ks;
216
-
181
+ static void read_hash(ParseInfo pi, const char *key) {
182
+ const char *ks;
183
+
217
184
  if (pi->has_hash_start) {
218
- call_no_value(pi->handler, oj_hash_start_id, key);
185
+ call_no_value(pi->handler, oj_hash_start_id, key);
219
186
  }
220
187
  pi->s++;
221
188
  next_non_white(pi);
222
189
  if ('}' == *pi->s) {
223
- pi->s++;
190
+ pi->s++;
224
191
  } else {
225
- while (1) {
226
- next_non_white(pi);
227
- ks = read_quoted_value(pi);
228
- next_non_white(pi);
229
- if (':' == *pi->s) {
230
- pi->s++;
231
- } else {
232
- if (pi->has_error) {
233
- call_error("invalid format, expected :", pi, __FILE__, __LINE__);
234
- }
235
- raise_error("invalid format, expected :", pi->str, pi->s);
236
- }
237
- read_next(pi, ks);
238
- next_non_white(pi);
239
- if ('}' == *pi->s) {
240
- pi->s++;
241
- break;
242
- } else if (',' == *pi->s) {
243
- pi->s++;
244
- } else {
245
- if (pi->has_error) {
246
- call_error("invalid format, expected , or } while in an object", pi, __FILE__, __LINE__);
247
- }
248
- raise_error("invalid format, expected , or } while in an object", pi->str, pi->s);
249
- }
250
- }
192
+ while (1) {
193
+ next_non_white(pi);
194
+ ks = read_quoted_value(pi);
195
+ next_non_white(pi);
196
+ if (':' == *pi->s) {
197
+ pi->s++;
198
+ } else {
199
+ if (pi->has_error) {
200
+ call_error("invalid format, expected :", pi, __FILE__, __LINE__);
201
+ }
202
+ raise_error("invalid format, expected :", pi->str, pi->s);
203
+ }
204
+ read_next(pi, ks);
205
+ next_non_white(pi);
206
+ if ('}' == *pi->s) {
207
+ pi->s++;
208
+ break;
209
+ } else if (',' == *pi->s) {
210
+ pi->s++;
211
+ } else {
212
+ if (pi->has_error) {
213
+ call_error("invalid format, expected , or } while in an object", pi, __FILE__, __LINE__);
214
+ }
215
+ raise_error("invalid format, expected , or } while in an object", pi->str, pi->s);
216
+ }
217
+ }
251
218
  }
252
219
  if (pi->has_hash_end) {
253
- call_no_value(pi->handler, oj_hash_end_id, key);
220
+ call_no_value(pi->handler, oj_hash_end_id, key);
254
221
  }
255
222
  }
256
223
 
257
- static void
258
- read_array(ParseInfo pi, const char *key) {
224
+ static void read_array(ParseInfo pi, const char *key) {
259
225
  if (pi->has_array_start) {
260
- call_no_value(pi->handler, oj_array_start_id, key);
226
+ call_no_value(pi->handler, oj_array_start_id, key);
261
227
  }
262
228
  pi->s++;
263
229
  next_non_white(pi);
264
230
  if (']' == *pi->s) {
265
- pi->s++;
231
+ pi->s++;
266
232
  } else {
267
- while (1) {
268
- read_next(pi, 0);
269
- next_non_white(pi);
270
- if (',' == *pi->s) {
271
- pi->s++;
272
- } else if (']' == *pi->s) {
273
- pi->s++;
274
- break;
275
- } else {
276
- if (pi->has_error) {
277
- call_error("invalid format, expected , or ] while in an array", pi, __FILE__, __LINE__);
278
- }
279
- raise_error("invalid format, expected , or ] while in an array", pi->str, pi->s);
280
- }
281
- }
233
+ while (1) {
234
+ read_next(pi, 0);
235
+ next_non_white(pi);
236
+ if (',' == *pi->s) {
237
+ pi->s++;
238
+ } else if (']' == *pi->s) {
239
+ pi->s++;
240
+ break;
241
+ } else {
242
+ if (pi->has_error) {
243
+ call_error("invalid format, expected , or ] while in an array", pi, __FILE__, __LINE__);
244
+ }
245
+ raise_error("invalid format, expected , or ] while in an array", pi->str, pi->s);
246
+ }
247
+ }
282
248
  }
283
249
  if (pi->has_array_end) {
284
- call_no_value(pi->handler, oj_array_end_id, key);
250
+ call_no_value(pi->handler, oj_array_end_id, key);
285
251
  }
286
252
  }
287
253
 
288
- static void
289
- read_str(ParseInfo pi, const char *key) {
290
- char *text;
254
+ static void read_str(ParseInfo pi, const char *key) {
255
+ char *text;
291
256
 
292
257
  text = read_quoted_value(pi);
293
258
  if (pi->has_add_value) {
294
- VALUE s = rb_str_new2(text);
259
+ VALUE s = rb_str_new2(text);
295
260
 
296
- s = oj_encode(s);
297
- call_add_value(pi->handler, s, key);
261
+ s = oj_encode(s);
262
+ call_add_value(pi->handler, s, key);
298
263
  }
299
264
  }
300
265
 
@@ -304,230 +269,224 @@ read_str(ParseInfo pi, const char *key) {
304
269
  #define NUM_MAX (FIXNUM_MAX >> 8)
305
270
  #endif
306
271
 
307
- static void
308
- read_num(ParseInfo pi, const char *key) {
309
- char *start = pi->s;
310
- int64_t n = 0;
311
- long a = 0;
312
- long div = 1;
313
- long e = 0;
314
- int neg = 0;
315
- int eneg = 0;
316
- int big = 0;
272
+ static void read_num(ParseInfo pi, const char *key) {
273
+ char *start = pi->s;
274
+ int64_t n = 0;
275
+ long a = 0;
276
+ long div = 1;
277
+ long e = 0;
278
+ int neg = 0;
279
+ int eneg = 0;
280
+ int big = 0;
317
281
 
318
282
  if ('-' == *pi->s) {
319
- pi->s++;
320
- neg = 1;
283
+ pi->s++;
284
+ neg = 1;
321
285
  } else if ('+' == *pi->s) {
322
- pi->s++;
286
+ pi->s++;
323
287
  }
324
288
  if ('I' == *pi->s) {
325
- if (0 != strncmp("Infinity", pi->s, 8)) {
326
- if (pi->has_error) {
327
- call_error("number or other value", pi, __FILE__, __LINE__);
328
- }
329
- raise_error("number or other value", pi->str, pi->s);
330
- }
331
- pi->s += 8;
332
- if (neg) {
333
- if (pi->has_add_value) {
334
- call_add_value(pi->handler, rb_float_new(-OJ_INFINITY), key);
335
- }
336
- } else {
337
- if (pi->has_add_value) {
338
- call_add_value(pi->handler, rb_float_new(OJ_INFINITY), key);
339
- }
340
- }
341
- return;
289
+ if (0 != strncmp("Infinity", pi->s, 8)) {
290
+ if (pi->has_error) {
291
+ call_error("number or other value", pi, __FILE__, __LINE__);
292
+ }
293
+ raise_error("number or other value", pi->str, pi->s);
294
+ }
295
+ pi->s += 8;
296
+ if (neg) {
297
+ if (pi->has_add_value) {
298
+ call_add_value(pi->handler, rb_float_new(-OJ_INFINITY), key);
299
+ }
300
+ } else {
301
+ if (pi->has_add_value) {
302
+ call_add_value(pi->handler, rb_float_new(OJ_INFINITY), key);
303
+ }
304
+ }
305
+ return;
342
306
  }
343
307
  for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
344
- if (big) {
345
- big++;
346
- } else {
347
- n = n * 10 + (*pi->s - '0');
348
- if (NUM_MAX <= n) {
349
- big = 1;
350
- }
351
- }
308
+ if (big) {
309
+ big++;
310
+ } else {
311
+ n = n * 10 + (*pi->s - '0');
312
+ if (NUM_MAX <= n) {
313
+ big = 1;
314
+ }
315
+ }
352
316
  }
353
317
  if ('.' == *pi->s) {
354
- pi->s++;
355
- for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
356
- a = a * 10 + (*pi->s - '0');
357
- div *= 10;
358
- if (NUM_MAX <= div) {
359
- big = 1;
360
- }
361
- }
318
+ pi->s++;
319
+ for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
320
+ a = a * 10 + (*pi->s - '0');
321
+ div *= 10;
322
+ if (NUM_MAX <= div) {
323
+ big = 1;
324
+ }
325
+ }
362
326
  }
363
327
  if ('e' == *pi->s || 'E' == *pi->s) {
364
- pi->s++;
365
- if ('-' == *pi->s) {
366
- pi->s++;
367
- eneg = 1;
368
- } else if ('+' == *pi->s) {
369
- pi->s++;
370
- }
371
- for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
372
- e = e * 10 + (*pi->s - '0');
373
- if (NUM_MAX <= e) {
374
- big = 1;
375
- }
376
- }
328
+ pi->s++;
329
+ if ('-' == *pi->s) {
330
+ pi->s++;
331
+ eneg = 1;
332
+ } else if ('+' == *pi->s) {
333
+ pi->s++;
334
+ }
335
+ for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
336
+ e = e * 10 + (*pi->s - '0');
337
+ if (NUM_MAX <= e) {
338
+ big = 1;
339
+ }
340
+ }
377
341
  }
378
342
  if (0 == e && 0 == a && 1 == div) {
379
- if (big) {
380
- char c = *pi->s;
381
-
382
- *pi->s = '\0';
383
- if (pi->has_add_value) {
384
- call_add_value(pi->handler, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(start)), key);
385
- }
386
- *pi->s = c;
387
- } else {
388
- if (neg) {
389
- n = -n;
390
- }
391
- if (pi->has_add_value) {
392
- call_add_value(pi->handler, LONG2NUM(n), key);
393
- }
394
- }
395
- return;
343
+ if (big) {
344
+ char c = *pi->s;
345
+
346
+ *pi->s = '\0';
347
+ if (pi->has_add_value) {
348
+ call_add_value(pi->handler, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(start)), key);
349
+ }
350
+ *pi->s = c;
351
+ } else {
352
+ if (neg) {
353
+ n = -n;
354
+ }
355
+ if (pi->has_add_value) {
356
+ call_add_value(pi->handler, LONG2NUM(n), key);
357
+ }
358
+ }
359
+ return;
396
360
  } else { /* decimal */
397
- if (big) {
398
- char c = *pi->s;
399
-
400
- *pi->s = '\0';
401
- if (pi->has_add_value) {
402
- call_add_value(pi->handler, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(start)), key);
403
- }
404
- *pi->s = c;
405
- } else {
406
- double d = (double)n + (double)a / (double)div;
407
-
408
- if (neg) {
409
- d = -d;
410
- }
411
- if (1 < big) {
412
- e += big - 1;
413
- }
414
- if (0 != e) {
415
- if (eneg) {
416
- e = -e;
417
- }
418
- d *= pow(10.0, e);
419
- }
420
- if (pi->has_add_value) {
421
- call_add_value(pi->handler, rb_float_new(d), key);
422
- }
423
- }
361
+ if (big) {
362
+ char c = *pi->s;
363
+
364
+ *pi->s = '\0';
365
+ if (pi->has_add_value) {
366
+ call_add_value(pi->handler, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(start)), key);
367
+ }
368
+ *pi->s = c;
369
+ } else {
370
+ double d = (double)n + (double)a / (double)div;
371
+
372
+ if (neg) {
373
+ d = -d;
374
+ }
375
+ if (1 < big) {
376
+ e += big - 1;
377
+ }
378
+ if (0 != e) {
379
+ if (eneg) {
380
+ e = -e;
381
+ }
382
+ d *= pow(10.0, e);
383
+ }
384
+ if (pi->has_add_value) {
385
+ call_add_value(pi->handler, rb_float_new(d), key);
386
+ }
387
+ }
424
388
  }
425
389
  }
426
390
 
427
- static void
428
- read_true(ParseInfo pi, const char *key) {
391
+ static void read_true(ParseInfo pi, const char *key) {
429
392
  pi->s++;
430
393
  if ('r' != *pi->s || 'u' != *(pi->s + 1) || 'e' != *(pi->s + 2)) {
431
- if (pi->has_error) {
432
- call_error("invalid format, expected 'true'", pi, __FILE__, __LINE__);
433
- }
434
- raise_error("invalid format, expected 'true'", pi->str, pi->s);
394
+ if (pi->has_error) {
395
+ call_error("invalid format, expected 'true'", pi, __FILE__, __LINE__);
396
+ }
397
+ raise_error("invalid format, expected 'true'", pi->str, pi->s);
435
398
  }
436
399
  pi->s += 3;
437
400
  if (pi->has_add_value) {
438
- call_add_value(pi->handler, Qtrue, key);
401
+ call_add_value(pi->handler, Qtrue, key);
439
402
  }
440
403
  }
441
404
 
442
- static void
443
- read_false(ParseInfo pi, const char *key) {
405
+ static void read_false(ParseInfo pi, const char *key) {
444
406
  pi->s++;
445
407
  if ('a' != *pi->s || 'l' != *(pi->s + 1) || 's' != *(pi->s + 2) || 'e' != *(pi->s + 3)) {
446
- if (pi->has_error) {
447
- call_error("invalid format, expected 'false'", pi, __FILE__, __LINE__);
448
- }
449
- raise_error("invalid format, expected 'false'", pi->str, pi->s);
408
+ if (pi->has_error) {
409
+ call_error("invalid format, expected 'false'", pi, __FILE__, __LINE__);
410
+ }
411
+ raise_error("invalid format, expected 'false'", pi->str, pi->s);
450
412
  }
451
413
  pi->s += 4;
452
414
  if (pi->has_add_value) {
453
- call_add_value(pi->handler, Qfalse, key);
415
+ call_add_value(pi->handler, Qfalse, key);
454
416
  }
455
417
  }
456
418
 
457
- static void
458
- read_nil(ParseInfo pi, const char *key) {
419
+ static void read_nil(ParseInfo pi, const char *key) {
459
420
  pi->s++;
460
421
  if ('u' != *pi->s || 'l' != *(pi->s + 1) || 'l' != *(pi->s + 2)) {
461
- if (pi->has_error) {
462
- call_error("invalid format, expected 'null'", pi, __FILE__, __LINE__);
463
- }
464
- raise_error("invalid format, expected 'null'", pi->str, pi->s);
422
+ if (pi->has_error) {
423
+ call_error("invalid format, expected 'null'", pi, __FILE__, __LINE__);
424
+ }
425
+ raise_error("invalid format, expected 'null'", pi->str, pi->s);
465
426
  }
466
427
  pi->s += 3;
467
428
  if (pi->has_add_value) {
468
- call_add_value(pi->handler, Qnil, key);
429
+ call_add_value(pi->handler, Qnil, key);
469
430
  }
470
431
  }
471
432
 
472
- static uint32_t
473
- read_hex(ParseInfo pi, char *h) {
474
- uint32_t b = 0;
475
- int i;
433
+ static uint32_t read_hex(ParseInfo pi, char *h) {
434
+ uint32_t b = 0;
435
+ int i;
476
436
 
477
437
  /* TBD this can be made faster with a table */
478
438
  for (i = 0; i < 4; i++, h++) {
479
- b = b << 4;
480
- if ('0' <= *h && *h <= '9') {
481
- b += *h - '0';
482
- } else if ('A' <= *h && *h <= 'F') {
483
- b += *h - 'A' + 10;
484
- } else if ('a' <= *h && *h <= 'f') {
485
- b += *h - 'a' + 10;
486
- } else {
487
- pi->s = h;
488
- if (pi->has_error) {
489
- call_error("invalid hex character", pi, __FILE__, __LINE__);
490
- }
491
- raise_error("invalid hex character", pi->str, pi->s);
492
- }
439
+ b = b << 4;
440
+ if ('0' <= *h && *h <= '9') {
441
+ b += *h - '0';
442
+ } else if ('A' <= *h && *h <= 'F') {
443
+ b += *h - 'A' + 10;
444
+ } else if ('a' <= *h && *h <= 'f') {
445
+ b += *h - 'a' + 10;
446
+ } else {
447
+ pi->s = h;
448
+ if (pi->has_error) {
449
+ call_error("invalid hex character", pi, __FILE__, __LINE__);
450
+ }
451
+ raise_error("invalid hex character", pi->str, pi->s);
452
+ }
493
453
  }
494
454
  return b;
495
455
  }
496
456
 
497
- static char*
498
- unicode_to_chars(ParseInfo pi, char *t, uint32_t code) {
457
+ static char *unicode_to_chars(ParseInfo pi, char *t, uint32_t code) {
499
458
  if (0x0000007F >= code) {
500
- *t = (char)code;
459
+ *t = (char)code;
501
460
  } else if (0x000007FF >= code) {
502
- *t++ = 0xC0 | (code >> 6);
503
- *t = 0x80 | (0x3F & code);
461
+ *t++ = 0xC0 | (code >> 6);
462
+ *t = 0x80 | (0x3F & code);
504
463
  } else if (0x0000FFFF >= code) {
505
- *t++ = 0xE0 | (code >> 12);
506
- *t++ = 0x80 | ((code >> 6) & 0x3F);
507
- *t = 0x80 | (0x3F & code);
464
+ *t++ = 0xE0 | (code >> 12);
465
+ *t++ = 0x80 | ((code >> 6) & 0x3F);
466
+ *t = 0x80 | (0x3F & code);
508
467
  } else if (0x001FFFFF >= code) {
509
- *t++ = 0xF0 | (code >> 18);
510
- *t++ = 0x80 | ((code >> 12) & 0x3F);
511
- *t++ = 0x80 | ((code >> 6) & 0x3F);
512
- *t = 0x80 | (0x3F & code);
468
+ *t++ = 0xF0 | (code >> 18);
469
+ *t++ = 0x80 | ((code >> 12) & 0x3F);
470
+ *t++ = 0x80 | ((code >> 6) & 0x3F);
471
+ *t = 0x80 | (0x3F & code);
513
472
  } else if (0x03FFFFFF >= code) {
514
- *t++ = 0xF8 | (code >> 24);
515
- *t++ = 0x80 | ((code >> 18) & 0x3F);
516
- *t++ = 0x80 | ((code >> 12) & 0x3F);
517
- *t++ = 0x80 | ((code >> 6) & 0x3F);
518
- *t = 0x80 | (0x3F & code);
473
+ *t++ = 0xF8 | (code >> 24);
474
+ *t++ = 0x80 | ((code >> 18) & 0x3F);
475
+ *t++ = 0x80 | ((code >> 12) & 0x3F);
476
+ *t++ = 0x80 | ((code >> 6) & 0x3F);
477
+ *t = 0x80 | (0x3F & code);
519
478
  } else if (0x7FFFFFFF >= code) {
520
- *t++ = 0xFC | (code >> 30);
521
- *t++ = 0x80 | ((code >> 24) & 0x3F);
522
- *t++ = 0x80 | ((code >> 18) & 0x3F);
523
- *t++ = 0x80 | ((code >> 12) & 0x3F);
524
- *t++ = 0x80 | ((code >> 6) & 0x3F);
525
- *t = 0x80 | (0x3F & code);
479
+ *t++ = 0xFC | (code >> 30);
480
+ *t++ = 0x80 | ((code >> 24) & 0x3F);
481
+ *t++ = 0x80 | ((code >> 18) & 0x3F);
482
+ *t++ = 0x80 | ((code >> 12) & 0x3F);
483
+ *t++ = 0x80 | ((code >> 6) & 0x3F);
484
+ *t = 0x80 | (0x3F & code);
526
485
  } else {
527
- if (pi->has_error) {
528
- call_error("invalid Unicode", pi, __FILE__, __LINE__);
529
- }
530
- raise_error("invalid Unicode", pi->str, pi->s);
486
+ if (pi->has_error) {
487
+ call_error("invalid Unicode", pi, __FILE__, __LINE__);
488
+ }
489
+ raise_error("invalid Unicode", pi->str, pi->s);
531
490
  }
532
491
  return t;
533
492
  }
@@ -535,119 +494,117 @@ unicode_to_chars(ParseInfo pi, char *t, uint32_t code) {
535
494
  /* Assume the value starts immediately and goes until the quote character is
536
495
  * reached again. Do not read the character after the terminating quote.
537
496
  */
538
- static char*
539
- read_quoted_value(ParseInfo pi) {
540
- char *value = 0;
541
- char *h = pi->s; /* head */
542
- char *t = h; /* tail */
543
- uint32_t code;
544
-
545
- h++; /* skip quote character */
497
+ static char *read_quoted_value(ParseInfo pi) {
498
+ char *value = 0;
499
+ char *h = pi->s; /* head */
500
+ char *t = h; /* tail */
501
+ uint32_t code;
502
+
503
+ h++; /* skip quote character */
546
504
  t++;
547
505
  value = h;
548
506
  for (; '"' != *h; h++, t++) {
549
- if ('\0' == *h) {
550
- pi->s = h;
551
- raise_error("quoted string not terminated", pi->str, pi->s);
552
- } else if ('\\' == *h) {
553
- h++;
554
- switch (*h) {
555
- case 'n': *t = '\n'; break;
556
- case 'r': *t = '\r'; break;
557
- case 't': *t = '\t'; break;
558
- case 'f': *t = '\f'; break;
559
- case 'b': *t = '\b'; break;
560
- case '"': *t = '"'; break;
561
- case '/': *t = '/'; break;
562
- case '\\': *t = '\\'; break;
563
- case 'u':
564
- h++;
565
- code = read_hex(pi, h);
566
- h += 3;
567
- if (0x0000D800 <= code && code <= 0x0000DFFF) {
568
- uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
569
- uint32_t c2;
570
-
571
- h++;
572
- if ('\\' != *h || 'u' != *(h + 1)) {
573
- pi->s = h;
574
- if (pi->has_error) {
575
- call_error("invalid escaped character", pi, __FILE__, __LINE__);
576
- }
577
- raise_error("invalid escaped character", pi->str, pi->s);
578
- }
579
- h += 2;
580
- c2 = read_hex(pi, h);
581
- h += 3;
582
- c2 = (c2 - 0x0000DC00) & 0x000003FF;
583
- code = ((c1 << 10) | c2) + 0x00010000;
584
- }
585
- t = unicode_to_chars(pi, t, code);
586
- break;
587
- default:
588
- pi->s = h;
589
- if (pi->has_error) {
590
- call_error("invalid escaped character", pi, __FILE__, __LINE__);
591
- }
592
- raise_error("invalid escaped character", pi->str, pi->s);
593
- break;
594
- }
595
- } else if (t != h) {
596
- *t = *h;
597
- }
598
- }
599
- *t = '\0'; /* terminate value */
507
+ if ('\0' == *h) {
508
+ pi->s = h;
509
+ raise_error("quoted string not terminated", pi->str, pi->s);
510
+ } else if ('\\' == *h) {
511
+ h++;
512
+ switch (*h) {
513
+ case 'n': *t = '\n'; break;
514
+ case 'r': *t = '\r'; break;
515
+ case 't': *t = '\t'; break;
516
+ case 'f': *t = '\f'; break;
517
+ case 'b': *t = '\b'; break;
518
+ case '"': *t = '"'; break;
519
+ case '/': *t = '/'; break;
520
+ case '\\': *t = '\\'; break;
521
+ case 'u':
522
+ h++;
523
+ code = read_hex(pi, h);
524
+ h += 3;
525
+ if (0x0000D800 <= code && code <= 0x0000DFFF) {
526
+ uint32_t c1 = (code - 0x0000D800) & 0x000003FF;
527
+ uint32_t c2;
528
+
529
+ h++;
530
+ if ('\\' != *h || 'u' != *(h + 1)) {
531
+ pi->s = h;
532
+ if (pi->has_error) {
533
+ call_error("invalid escaped character", pi, __FILE__, __LINE__);
534
+ }
535
+ raise_error("invalid escaped character", pi->str, pi->s);
536
+ }
537
+ h += 2;
538
+ c2 = read_hex(pi, h);
539
+ h += 3;
540
+ c2 = (c2 - 0x0000DC00) & 0x000003FF;
541
+ code = ((c1 << 10) | c2) + 0x00010000;
542
+ }
543
+ t = unicode_to_chars(pi, t, code);
544
+ break;
545
+ default:
546
+ pi->s = h;
547
+ if (pi->has_error) {
548
+ call_error("invalid escaped character", pi, __FILE__, __LINE__);
549
+ }
550
+ raise_error("invalid escaped character", pi->str, pi->s);
551
+ break;
552
+ }
553
+ } else if (t != h) {
554
+ *t = *h;
555
+ }
556
+ }
557
+ *t = '\0'; /* terminate value */
600
558
  pi->s = h + 1;
601
559
 
602
560
  return value;
603
561
  }
604
562
 
605
- static void
606
- saj_parse(VALUE handler, char *json) {
607
- volatile VALUE obj = Qnil;
608
- struct _ParseInfo pi;
563
+ static void saj_parse(VALUE handler, char *json) {
564
+ volatile VALUE obj = Qnil;
565
+ struct _parseInfo pi;
609
566
 
610
567
  if (0 == json) {
611
- if (pi.has_error) {
612
- call_error("Invalid arg, xml string can not be null", &pi, __FILE__, __LINE__);
613
- }
614
- raise_error("Invalid arg, xml string can not be null", json, 0);
568
+ if (pi.has_error) {
569
+ call_error("Invalid arg, xml string can not be null", &pi, __FILE__, __LINE__);
570
+ }
571
+ raise_error("Invalid arg, xml string can not be null", json, 0);
615
572
  }
616
573
  /* skip UTF-8 BOM if present */
617
574
  if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) {
618
- json += 3;
575
+ json += 3;
619
576
  }
620
577
  /* initialize parse info */
621
578
  pi.str = json;
622
- pi.s = json;
579
+ pi.s = json;
623
580
  #if IS_WINDOWS
624
- pi.stack_min = (void*)((char*)&obj - (512 * 1024)); /* assume a 1M stack and give half to ruby */
581
+ pi.stack_min = (void *)((char *)&obj - (512L * 1024L)); /* assume a 1M stack and give half to ruby */
625
582
  #else
626
583
  {
627
- struct rlimit lim;
584
+ struct rlimit lim;
628
585
 
629
- if (0 == getrlimit(RLIMIT_STACK, &lim)) {
630
- pi.stack_min = (void*)((char*)&obj - (lim.rlim_cur / 4 * 3)); /* let 3/4ths of the stack be used only */
631
- } else {
632
- pi.stack_min = 0; /* indicates not to check stack limit */
633
- }
586
+ if (0 == getrlimit(RLIMIT_STACK, &lim) && RLIM_INFINITY != lim.rlim_cur) {
587
+ pi.stack_min = (void *)((char *)&obj - (lim.rlim_cur / 4 * 3)); /* let 3/4ths of the stack be used only */
588
+ } else {
589
+ pi.stack_min = 0; /* indicates not to check stack limit */
590
+ }
634
591
  }
635
592
  #endif
636
- pi.handler = handler;
637
- pi.has_hash_start = rb_respond_to(handler, oj_hash_start_id);
638
- pi.has_hash_end = rb_respond_to(handler, oj_hash_end_id);
593
+ pi.handler = handler;
594
+ pi.has_hash_start = rb_respond_to(handler, oj_hash_start_id);
595
+ pi.has_hash_end = rb_respond_to(handler, oj_hash_end_id);
639
596
  pi.has_array_start = rb_respond_to(handler, oj_array_start_id);
640
- pi.has_array_end = rb_respond_to(handler, oj_array_end_id);
641
- pi.has_add_value = rb_respond_to(handler, oj_add_value_id);
642
- pi.has_error = rb_respond_to(handler, oj_error_id);
597
+ pi.has_array_end = rb_respond_to(handler, oj_array_end_id);
598
+ pi.has_add_value = rb_respond_to(handler, oj_add_value_id);
599
+ pi.has_error = rb_respond_to(handler, oj_error_id);
643
600
  read_next(&pi, 0);
644
601
  next_non_white(&pi);
645
602
  if ('\0' != *pi.s) {
646
- if (pi.has_error) {
647
- call_error("invalid format, extra characters", &pi, __FILE__, __LINE__);
648
- } else {
649
- raise_error("invalid format, extra characters", pi.str, pi.s);
650
- }
603
+ if (pi.has_error) {
604
+ call_error("invalid format, extra characters", &pi, __FILE__, __LINE__);
605
+ } else {
606
+ raise_error("invalid format, extra characters", pi.str, pi.s);
607
+ }
651
608
  }
652
609
  }
653
610
 
@@ -659,53 +616,53 @@ saj_parse(VALUE handler, char *json) {
659
616
  * @param [IO|String] io IO Object to read from
660
617
  * @deprecated The sc_parse() method along with the ScHandler is the preferred
661
618
  * callback parser. It is slightly faster and handles streams while the
662
- * saj_parse() methos requires a complete read before parsing.
619
+ * saj_parse() method requires a complete read before parsing.
663
620
  * @see sc_parse
664
621
  */
665
622
  VALUE
666
623
  oj_saj_parse(int argc, VALUE *argv, VALUE self) {
667
- char *json = 0;
668
- size_t len = 0;
669
- VALUE input = argv[1];
624
+ char *json = 0;
625
+ size_t len = 0;
626
+ VALUE input = argv[1];
670
627
 
671
628
  if (argc < 2) {
672
- rb_raise(rb_eArgError, "Wrong number of arguments to saj_parse.\n");
629
+ rb_raise(rb_eArgError, "Wrong number of arguments to saj_parse.\n");
673
630
  }
674
631
  if (rb_type(input) == T_STRING) {
675
- // the json string gets modified so make a copy of it
676
- len = RSTRING_LEN(input) + 1;
677
- json = ALLOC_N(char, len);
678
- strcpy(json, StringValuePtr(input));
632
+ // the json string gets modified so make a copy of it
633
+ len = RSTRING_LEN(input) + 1;
634
+ json = ALLOC_N(char, len);
635
+ strcpy(json, StringValuePtr(input));
679
636
  } else {
680
- VALUE clas = rb_obj_class(input);
681
- volatile VALUE s;
682
-
683
- if (oj_stringio_class == clas) {
684
- s = rb_funcall2(input, oj_string_id, 0, 0);
685
- len = RSTRING_LEN(s) + 1;
686
- json = ALLOC_N(char, len);
687
- strcpy(json, rb_string_value_cstr((VALUE*)&s));
637
+ VALUE clas = rb_obj_class(input);
638
+ volatile VALUE s;
639
+
640
+ if (oj_stringio_class == clas) {
641
+ s = rb_funcall2(input, oj_string_id, 0, 0);
642
+ len = RSTRING_LEN(s) + 1;
643
+ json = ALLOC_N(char, len);
644
+ strcpy(json, rb_string_value_cstr((VALUE *)&s));
688
645
  #if !IS_WINDOWS
689
- } else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) {
690
- int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0));
691
- ssize_t cnt;
692
-
693
- len = lseek(fd, 0, SEEK_END);
694
- lseek(fd, 0, SEEK_SET);
695
- json = ALLOC_N(char, len + 1);
696
- if (0 >= (cnt = read(fd, json, len)) || cnt != (ssize_t)len) {
697
- rb_raise(rb_eIOError, "failed to read from IO Object.");
698
- }
699
- json[len] = '\0';
646
+ } else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) {
647
+ int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0));
648
+ ssize_t cnt;
649
+
650
+ len = lseek(fd, 0, SEEK_END);
651
+ lseek(fd, 0, SEEK_SET);
652
+ json = ALLOC_N(char, len + 1);
653
+ if (0 >= (cnt = read(fd, json, len)) || cnt != (ssize_t)len) {
654
+ rb_raise(rb_eIOError, "failed to read from IO Object.");
655
+ }
656
+ json[len] = '\0';
700
657
  #endif
701
- } else if (rb_respond_to(input, oj_read_id)) {
702
- s = rb_funcall2(input, oj_read_id, 0, 0);
703
- len = RSTRING_LEN(s) + 1;
704
- json = ALLOC_N(char, len);
705
- strcpy(json, rb_string_value_cstr((VALUE*)&s));
706
- } else {
707
- rb_raise(rb_eArgError, "saj_parse() expected a String or IO Object.");
708
- }
658
+ } else if (rb_respond_to(input, oj_read_id)) {
659
+ s = rb_funcall2(input, oj_read_id, 0, 0);
660
+ len = RSTRING_LEN(s) + 1;
661
+ json = ALLOC_N(char, len);
662
+ strcpy(json, rb_string_value_cstr((VALUE *)&s));
663
+ } else {
664
+ rb_raise(rb_eArgError, "saj_parse() expected a String or IO Object.");
665
+ }
709
666
  }
710
667
  saj_parse(*argv, json);
711
668
  xfree(json);