oj 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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