oj 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +17 -23
  3. data/README.md +74 -425
  4. data/ext/oj/buf.h +103 -0
  5. data/ext/oj/cache8.c +4 -0
  6. data/ext/oj/circarray.c +68 -0
  7. data/ext/oj/circarray.h +23 -0
  8. data/ext/oj/code.c +227 -0
  9. data/ext/oj/code.h +40 -0
  10. data/ext/oj/compat.c +243 -0
  11. data/ext/oj/custom.c +1097 -0
  12. data/ext/oj/dump.c +766 -1534
  13. data/ext/oj/dump.h +92 -0
  14. data/ext/oj/dump_compat.c +937 -0
  15. data/ext/oj/dump_leaf.c +254 -0
  16. data/ext/oj/dump_object.c +810 -0
  17. data/ext/oj/dump_rails.c +329 -0
  18. data/ext/oj/dump_strict.c +416 -0
  19. data/ext/oj/encode.h +51 -0
  20. data/ext/oj/err.c +57 -0
  21. data/ext/oj/err.h +70 -0
  22. data/ext/oj/extconf.rb +17 -7
  23. data/ext/oj/fast.c +213 -180
  24. data/ext/oj/hash.c +163 -0
  25. data/ext/oj/hash.h +46 -0
  26. data/ext/oj/hash_test.c +512 -0
  27. data/ext/oj/mimic_json.c +817 -0
  28. data/ext/oj/mimic_rails.c +806 -0
  29. data/ext/oj/mimic_rails.h +17 -0
  30. data/ext/oj/object.c +752 -0
  31. data/ext/oj/odd.c +230 -0
  32. data/ext/oj/odd.h +44 -0
  33. data/ext/oj/oj.c +1288 -929
  34. data/ext/oj/oj.h +240 -69
  35. data/ext/oj/parse.c +1014 -0
  36. data/ext/oj/parse.h +92 -0
  37. data/ext/oj/reader.c +223 -0
  38. data/ext/oj/reader.h +151 -0
  39. data/ext/oj/resolve.c +127 -0
  40. data/ext/oj/{cache.h → resolve.h} +6 -13
  41. data/ext/oj/rxclass.c +133 -0
  42. data/ext/oj/rxclass.h +27 -0
  43. data/ext/oj/saj.c +77 -175
  44. data/ext/oj/scp.c +224 -0
  45. data/ext/oj/sparse.c +911 -0
  46. data/ext/oj/stream_writer.c +301 -0
  47. data/ext/oj/strict.c +162 -0
  48. data/ext/oj/string_writer.c +480 -0
  49. data/ext/oj/val_stack.c +98 -0
  50. data/ext/oj/val_stack.h +188 -0
  51. data/lib/oj/active_support_helper.rb +41 -0
  52. data/lib/oj/bag.rb +6 -10
  53. data/lib/oj/easy_hash.rb +52 -0
  54. data/lib/oj/json.rb +172 -0
  55. data/lib/oj/mimic.rb +260 -5
  56. data/lib/oj/saj.rb +13 -10
  57. data/lib/oj/schandler.rb +142 -0
  58. data/lib/oj/state.rb +131 -0
  59. data/lib/oj/version.rb +1 -1
  60. data/lib/oj.rb +11 -23
  61. data/pages/Advanced.md +22 -0
  62. data/pages/Compatibility.md +25 -0
  63. data/pages/Custom.md +23 -0
  64. data/pages/Encoding.md +65 -0
  65. data/pages/JsonGem.md +79 -0
  66. data/pages/Modes.md +140 -0
  67. data/pages/Options.md +250 -0
  68. data/pages/Rails.md +60 -0
  69. data/pages/Security.md +20 -0
  70. data/test/_test_active.rb +76 -0
  71. data/test/_test_active_mimic.rb +96 -0
  72. data/test/_test_mimic_rails.rb +126 -0
  73. data/test/activesupport4/decoding_test.rb +105 -0
  74. data/test/activesupport4/encoding_test.rb +531 -0
  75. data/test/activesupport4/test_helper.rb +41 -0
  76. data/test/activesupport5/decoding_test.rb +125 -0
  77. data/test/activesupport5/encoding_test.rb +483 -0
  78. data/test/activesupport5/encoding_test_cases.rb +90 -0
  79. data/test/activesupport5/test_helper.rb +50 -0
  80. data/test/activesupport5/time_zone_test_helpers.rb +24 -0
  81. data/test/helper.rb +27 -0
  82. data/test/isolated/shared.rb +310 -0
  83. data/test/isolated/test_mimic_after.rb +13 -0
  84. data/test/isolated/test_mimic_alone.rb +12 -0
  85. data/test/isolated/test_mimic_as_json.rb +45 -0
  86. data/test/isolated/test_mimic_before.rb +13 -0
  87. data/test/isolated/test_mimic_define.rb +28 -0
  88. data/test/isolated/test_mimic_rails_after.rb +22 -0
  89. data/test/isolated/test_mimic_rails_before.rb +21 -0
  90. data/test/isolated/test_mimic_redefine.rb +15 -0
  91. data/test/json_gem/json_addition_test.rb +216 -0
  92. data/test/json_gem/json_common_interface_test.rb +143 -0
  93. data/test/json_gem/json_encoding_test.rb +109 -0
  94. data/test/json_gem/json_ext_parser_test.rb +20 -0
  95. data/test/json_gem/json_fixtures_test.rb +35 -0
  96. data/test/json_gem/json_generator_test.rb +383 -0
  97. data/test/json_gem/json_generic_object_test.rb +90 -0
  98. data/test/json_gem/json_parser_test.rb +470 -0
  99. data/test/json_gem/json_string_matching_test.rb +42 -0
  100. data/test/json_gem/test_helper.rb +18 -0
  101. data/test/perf_compat.rb +130 -0
  102. data/test/perf_fast.rb +9 -9
  103. data/test/perf_file.rb +64 -0
  104. data/test/{perf_obj.rb → perf_object.rb} +24 -10
  105. data/test/perf_scp.rb +151 -0
  106. data/test/perf_strict.rb +32 -113
  107. data/test/sample.rb +2 -3
  108. data/test/test_compat.rb +474 -0
  109. data/test/test_custom.rb +355 -0
  110. data/test/test_debian.rb +53 -0
  111. data/test/test_fast.rb +66 -16
  112. data/test/test_file.rb +237 -0
  113. data/test/test_gc.rb +49 -0
  114. data/test/test_hash.rb +29 -0
  115. data/test/test_null.rb +376 -0
  116. data/test/test_object.rb +1010 -0
  117. data/test/test_saj.rb +16 -16
  118. data/test/test_scp.rb +417 -0
  119. data/test/test_strict.rb +410 -0
  120. data/test/test_various.rb +815 -0
  121. data/test/test_writer.rb +308 -0
  122. data/test/tests.rb +9 -902
  123. data/test/tests_mimic.rb +14 -0
  124. data/test/tests_mimic_addition.rb +7 -0
  125. metadata +253 -38
  126. data/ext/oj/cache.c +0 -148
  127. data/ext/oj/foo.rb +0 -6
  128. data/ext/oj/load.c +0 -1049
  129. data/test/a.rb +0 -38
  130. data/test/perf1.rb +0 -64
  131. data/test/perf2.rb +0 -76
  132. data/test/perf_obj_old.rb +0 -213
  133. data/test/test_mimic.rb +0 -208
data/ext/oj/rxclass.c ADDED
@@ -0,0 +1,133 @@
1
+ /* rxclass.c
2
+ * Copyright (c) 2017, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #include <sys/types.h>
7
+ #include <stdlib.h>
8
+ #include <errno.h>
9
+ #include <regex.h>
10
+ #include <string.h>
11
+ #include <stdio.h>
12
+
13
+ #include "rxclass.h"
14
+
15
+ typedef struct _RxC {
16
+ struct _RxC *next;
17
+ VALUE rrx;
18
+ regex_t rx;
19
+ VALUE clas;
20
+ char src[256];
21
+ } *RxC;
22
+
23
+ void
24
+ oj_rxclass_init(RxClass rc) {
25
+ *rc->err = '\0';
26
+ rc->head = NULL;
27
+ rc->tail = NULL;
28
+ }
29
+
30
+ void
31
+ oj_rxclass_cleanup(RxClass rc) {
32
+ RxC rxc;
33
+
34
+ while (NULL != (rxc = rc->head)) {
35
+ rc->head = rc->head->next;
36
+ if (Qnil == rxc->rrx) {
37
+ regfree(&rxc->rx);
38
+ }
39
+ xfree(rxc);
40
+ }
41
+ }
42
+
43
+ void
44
+ oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas) {
45
+ RxC rxc = ALLOC_N(struct _RxC, 1);
46
+
47
+ memset(rxc, 0, sizeof(struct _RxC));
48
+ rxc->rrx = rx;
49
+ rxc->clas = clas;
50
+ if (NULL == rc->tail) {
51
+ rc->head = rxc;
52
+ } else {
53
+ rc->tail->next = rxc;
54
+ }
55
+ rc->tail = rxc;
56
+ }
57
+
58
+ // Attempt to compile the expression. If it fails populate the error code..
59
+ int
60
+ oj_rxclass_append(RxClass rc, const char *expr, VALUE clas) {
61
+ // Use mallow and not ALLOC_N to avoid pulliing ruby.h which conflicts
62
+ // with regex_t.
63
+ RxC rxc;
64
+ int err;
65
+ int flags = 0;
66
+
67
+ if (sizeof(rxc->src) <= strlen(expr)) {
68
+ snprintf(rc->err, sizeof(rc->err), "expressions must be less than %lu chracter", sizeof(rxc->src));
69
+ return EINVAL;
70
+ }
71
+ rxc = ALLOC_N(struct _RxC, 1);
72
+ rxc->next = 0;
73
+ rxc->rrx = Qnil;
74
+ rxc->clas = clas;
75
+ if (0 != (err = regcomp(&rxc->rx, expr, flags))) {
76
+ regerror(err, &rxc->rx, rc->err, sizeof(rc->err));
77
+ free(rxc);
78
+ return err;
79
+ }
80
+ if (NULL == rc->tail) {
81
+ rc->head = rxc;
82
+ } else {
83
+ rc->tail->next = rxc;
84
+ }
85
+ rc->tail = rxc;
86
+
87
+ return 0;
88
+ }
89
+
90
+ VALUE
91
+ oj_rxclass_match(RxClass rc, const char *str, int len) {
92
+ RxC rxc;
93
+ char buf[4096];
94
+
95
+ for (rxc = rc->head; NULL != rxc; rxc = rxc->next) {
96
+ if (Qnil != rxc->rrx) {
97
+ // Must use a valiabel for this to work.
98
+ volatile VALUE rstr = rb_str_new(str, len);
99
+
100
+ //if (Qtrue == rb_funcall(rxc->rrx, rb_intern("match?"), 1, rstr)) {
101
+ if (Qnil != rb_funcall(rxc->rrx, rb_intern("match"), 1, rstr)) {
102
+ return rxc->clas;
103
+ }
104
+ } else if (len < (int)sizeof(buf)) {
105
+ // string is not \0 terminated so copy and atempt a match
106
+ memcpy(buf, str, len);
107
+ buf[len] = '\0';
108
+ if (0 == regexec(&rxc->rx, buf, 0, NULL, 0)) { // match
109
+ return rxc->clas;
110
+ }
111
+ } else {
112
+ // TBD allocate a larger buffer and attempt
113
+ }
114
+ }
115
+ return Qnil;
116
+ }
117
+
118
+ void
119
+ oj_rxclass_copy(RxClass src, RxClass dest) {
120
+ dest->head = NULL;
121
+ dest->tail = NULL;
122
+ if (NULL != src->head) {
123
+ RxC rxc;
124
+
125
+ for (rxc = src->head; NULL != rxc; rxc = rxc->next) {
126
+ if (Qnil != rxc->rrx) {
127
+ oj_rxclass_rappend(dest, rxc->rrx, rxc->clas);
128
+ } else {
129
+ oj_rxclass_append(dest, rxc->src, rxc->clas);
130
+ }
131
+ }
132
+ }
133
+ }
data/ext/oj/rxclass.h ADDED
@@ -0,0 +1,27 @@
1
+ /* rxclass.h
2
+ * Copyright (c) 2017, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #ifndef __OJ_RXCLASS_H__
7
+ #define __OJ_RXCLASS_H__
8
+
9
+ #include <stdbool.h>
10
+ #include "ruby.h"
11
+
12
+ struct _RxC;
13
+
14
+ typedef struct _RxClass {
15
+ struct _RxC *head;
16
+ struct _RxC *tail;
17
+ char err[128];
18
+ } *RxClass;
19
+
20
+ extern void oj_rxclass_init(RxClass rc);
21
+ extern void oj_rxclass_cleanup(RxClass rc);
22
+ extern int oj_rxclass_append(RxClass rc, const char *expr, VALUE clas);
23
+ extern VALUE oj_rxclass_match(RxClass rc, const char *str, int len);
24
+ extern void oj_rxclass_copy(RxClass src, RxClass dest);
25
+ extern void oj_rxclass_rappend(RxClass rc, VALUE rx, VALUE clas);
26
+
27
+ #endif /* __OJ_RXCLASS_H__ */
data/ext/oj/saj.c CHANGED
@@ -1,31 +1,6 @@
1
1
  /* saj.c
2
2
  * Copyright (c) 2012, Peter Ohler
3
3
  * All rights reserved.
4
- *
5
- * Redistribution and use in source and binary forms, with or without
6
- * modification, are permitted provided that the following conditions are met:
7
- *
8
- * - Redistributions of source code must retain the above copyright notice, this
9
- * list of conditions and the following disclaimer.
10
- *
11
- * - Redistributions in binary form must reproduce the above copyright notice,
12
- * this list of conditions and the following disclaimer in the documentation
13
- * and/or other materials provided with the distribution.
14
- *
15
- * - Neither the name of Peter Ohler nor the names of its contributors may be
16
- * used to endorse or promote products derived from this software without
17
- * specific prior written permission.
18
- *
19
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
4
  */
30
5
 
31
6
  #if !IS_WINDOWS
@@ -35,19 +10,14 @@
35
10
  #include <stdio.h>
36
11
  #include <string.h>
37
12
  #include <math.h>
13
+ #include <sys/types.h>
14
+ #include <unistd.h>
38
15
 
39
- /* Workaround: */
40
- #ifndef INFINITY
41
- #define INFINITY (1.0/0.0)
42
- #endif
16
+ // Workaround in case INFINITY is not defined in math.h or if the OS is CentOS
17
+ #define OJ_INFINITY (1.0/0.0)
43
18
 
44
19
  #include "oj.h"
45
-
46
- typedef struct _CX {
47
- VALUE *cur;
48
- VALUE *end;
49
- VALUE stack[1024];
50
- } *CX;
20
+ #include "encode.h"
51
21
 
52
22
  typedef struct _ParseInfo {
53
23
  char *str; /* buffer being read from */
@@ -74,9 +44,9 @@ static void next_non_white(ParseInfo pi);
74
44
  static char* read_quoted_value(ParseInfo pi);
75
45
  static void skip_comment(ParseInfo pi);
76
46
 
77
- /* This XML parser is a single pass, destructive, callback parser. It is a
47
+ /* This JSON parser is a single pass, destructive, callback parser. It is a
78
48
  * single pass parse since it only make one pass over the characters in the
79
- * XML document string. It is destructive because it re-uses the content of
49
+ * JSON document string. It is destructive because it re-uses the content of
80
50
  * the string for values in the callback and places \0 characters at various
81
51
  * places to mark the end of tokens and strings. It is a callback parser like
82
52
  * a SAX parser because it uses callback when document elements are
@@ -125,49 +95,28 @@ next_non_white(ParseInfo pi) {
125
95
  }
126
96
  }
127
97
 
128
- inline static void
129
- next_white(ParseInfo pi) {
130
- for (; 1; pi->s++) {
131
- switch(*pi->s) {
132
- case ' ':
133
- case '\t':
134
- case '\f':
135
- case '\n':
136
- case '\r':
137
- case '\0':
138
- return;
139
- default:
140
- break;
141
- }
142
- }
143
- }
144
-
145
98
  inline static void
146
99
  call_add_value(VALUE handler, VALUE value, const char *key) {
147
- VALUE k;
100
+ volatile VALUE k;
148
101
 
149
102
  if (0 == key) {
150
103
  k = Qnil;
151
104
  } else {
152
105
  k = rb_str_new2(key);
153
- #if HAS_ENCODING_SUPPORT
154
- rb_enc_associate(k, oj_utf8_encoding);
155
- #endif
106
+ k = oj_encode(k);
156
107
  }
157
108
  rb_funcall(handler, oj_add_value_id, 2, value, k);
158
109
  }
159
110
 
160
111
  inline static void
161
112
  call_no_value(VALUE handler, ID method, const char *key) {
162
- VALUE k;
113
+ volatile VALUE k;
163
114
 
164
115
  if (0 == key) {
165
116
  k = Qnil;
166
117
  } else {
167
118
  k = rb_str_new2(key);
168
- #if HAS_ENCODING_SUPPORT
169
- rb_enc_associate(k, oj_utf8_encoding);
170
- #endif
119
+ k = oj_encode(k);
171
120
  }
172
121
  rb_funcall(handler, method, 1, k);
173
122
  }
@@ -344,9 +293,7 @@ read_str(ParseInfo pi, const char *key) {
344
293
  if (pi->has_add_value) {
345
294
  VALUE s = rb_str_new2(text);
346
295
 
347
- #if HAS_ENCODING_SUPPORT
348
- rb_enc_associate(s, oj_utf8_encoding);
349
- #endif
296
+ s = oj_encode(s);
350
297
  call_add_value(pi->handler, s, key);
351
298
  }
352
299
  }
@@ -384,11 +331,11 @@ read_num(ParseInfo pi, const char *key) {
384
331
  pi->s += 8;
385
332
  if (neg) {
386
333
  if (pi->has_add_value) {
387
- call_add_value(pi->handler, rb_float_new(-INFINITY), key);
334
+ call_add_value(pi->handler, rb_float_new(-OJ_INFINITY), key);
388
335
  }
389
336
  } else {
390
337
  if (pi->has_add_value) {
391
- call_add_value(pi->handler, rb_float_new(INFINITY), key);
338
+ call_add_value(pi->handler, rb_float_new(OJ_INFINITY), key);
392
339
  }
393
340
  }
394
341
  return;
@@ -655,25 +602,9 @@ read_quoted_value(ParseInfo pi) {
655
602
  return value;
656
603
  }
657
604
 
658
- inline static int
659
- respond_to(VALUE obj, ID method) {
660
- #ifdef JRUBY_RUBY
661
- /* There is a bug in JRuby where rb_respond_to() returns true (1) even if
662
- * a method is private. */
663
- {
664
- VALUE args[1];
665
-
666
- *args = ID2SYM(method);
667
- return (Qtrue == rb_funcall2(obj, rb_intern("respond_to?"), 1, args));
668
- }
669
- #else
670
- return rb_respond_to(obj, method);
671
- #endif
672
- }
673
-
674
- void
675
- oj_saj_parse(VALUE handler, char *json) {
676
- VALUE obj = Qnil;
605
+ static void
606
+ saj_parse(VALUE handler, char *json) {
607
+ volatile VALUE obj = Qnil;
677
608
  struct _ParseInfo pi;
678
609
 
679
610
  if (0 == json) {
@@ -703,12 +634,12 @@ oj_saj_parse(VALUE handler, char *json) {
703
634
  }
704
635
  #endif
705
636
  pi.handler = handler;
706
- pi.has_hash_start = respond_to(handler, oj_hash_start_id);
707
- pi.has_hash_end = respond_to(handler, oj_hash_end_id);
708
- pi.has_array_start = respond_to(handler, oj_array_start_id);
709
- pi.has_array_end = respond_to(handler, oj_array_end_id);
710
- pi.has_add_value = respond_to(handler, oj_add_value_id);
711
- pi.has_error = respond_to(handler, oj_error_id);
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);
639
+ 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);
712
643
  read_next(&pi, 0);
713
644
  next_non_white(&pi);
714
645
  if ('\0' != *pi.s) {
@@ -720,93 +651,64 @@ oj_saj_parse(VALUE handler, char *json) {
720
651
  }
721
652
  }
722
653
 
723
-
724
- #if 0
725
- static void
726
- cx_add(CX cx, VALUE obj, const char *key) {
727
- if (0 == cx->cur) {
728
- cx->cur = cx->stack;
729
- *cx->cur = obj;
654
+ /* call-seq: saj_parse(handler, io)
655
+ *
656
+ * Parses an IO stream or file containing an JSON document. Raises an exception
657
+ * if the JSON is malformed.
658
+ * @param [Oj::Saj] handler Saj (responds to Oj::Saj methods) like handler
659
+ * @param [IO|String] io IO Object to read from
660
+ * @deprecated The sc_parse() method along with the ScHandler is the preferred
661
+ * callback parser. It is slightly faster and handles streams while the
662
+ * saj_parse() methos requires a complete read before parsing.
663
+ * @see sc_parse
664
+ */
665
+ VALUE
666
+ oj_saj_parse(int argc, VALUE *argv, VALUE self) {
667
+ char *json = 0;
668
+ size_t len = 0;
669
+ VALUE input = argv[1];
670
+
671
+ if (argc < 2) {
672
+ rb_raise(rb_eArgError, "Wrong number of arguments to saj_parse.\n");
673
+ }
674
+ 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));
730
679
  } else {
731
- if (0 != key) {
732
- VALUE ks = rb_str_new2(key);
733
- #if HAS_ENCODING_SUPPORT
734
- rb_enc_associate(ks, oj_utf8_encoding);
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));
688
+ #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';
735
700
  #endif
736
- rb_hash_aset(*cx->cur, ks, obj);
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));
737
706
  } else {
738
- rb_ary_push(*cx->cur, obj);
707
+ rb_raise(rb_eArgError, "saj_parse() expected a String or IO Object.");
739
708
  }
740
709
  }
741
- }
710
+ saj_parse(*argv, json);
711
+ xfree(json);
742
712
 
743
- static void
744
- cx_push(CX cx, VALUE obj, const char *key) {
745
- if (0 == cx->cur) {
746
- cx->cur = cx->stack;
747
- } else {
748
- if (cx->end <= cx->cur) {
749
- rb_raise(oj_parse_error_class, "too deeply nested");
750
- }
751
- cx_add(cx, obj, key);
752
- cx->cur++;
753
- }
754
- *cx->cur = obj;
755
- }
756
-
757
- static void
758
- hash_start(void *context, const char *key) {
759
- cx_push((CX)context, rb_hash_new(), key);
760
- }
761
-
762
- static void
763
- col_end(void *context, const char *key) {
764
- ((CX)context)->cur--;
765
- }
766
-
767
- static void
768
- array_start(void *context, const char *key) {
769
- cx_push((CX)context, rb_ary_new(), key);
770
- }
771
-
772
- static void
773
- add_str(void *context, const char *str, const char *key) {
774
- VALUE s;
775
-
776
- s = rb_str_new2(str);
777
- #if HAS_ENCODING_SUPPORT
778
- rb_enc_associate(s, oj_utf8_encoding);
779
- #endif
780
- cx_add((CX)context, s, key);
781
- }
782
-
783
- static void
784
- add_big(void *context, const char *str, const char *key) {
785
- cx_add((CX)context, rb_funcall(oj_bigdecimal_class, oj_new_id, 1, rb_str_new2(str)), key);
786
- }
787
-
788
- static void
789
- add_float(void *context, double num, const char *key) {
790
- cx_add((CX)context, rb_float_new(num), key);
791
- }
792
-
793
- static void
794
- add_fixnum(void *context, int64_t num, const char *key) {
795
- cx_add((CX)context, LONG2NUM(num), key);
796
- }
797
-
798
- static void
799
- add_true(void *context, const char *key) {
800
- cx_add((CX)context, Qtrue, key);
801
- }
802
-
803
- static void
804
- add_false(void *context, const char *key) {
805
- cx_add((CX)context, Qfalse, key);
713
+ return Qnil;
806
714
  }
807
-
808
- static void
809
- add_nil(void *context, const char *key) {
810
- cx_add((CX)context, Qnil, key);
811
- }
812
- #endif