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/parse.h ADDED
@@ -0,0 +1,92 @@
1
+ /* parse.h
2
+ * Copyright (c) 2011, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #ifndef __OJ_PARSE_H__
7
+ #define __OJ_PARSE_H__
8
+
9
+ #include <stdarg.h>
10
+ #include <stdio.h>
11
+ #include <string.h>
12
+
13
+ #include "ruby.h"
14
+ #include "oj.h"
15
+ #include "val_stack.h"
16
+ #include "circarray.h"
17
+ #include "reader.h"
18
+ #include "rxclass.h"
19
+
20
+ struct _RxClass;
21
+
22
+ typedef struct _NumInfo {
23
+ int64_t i;
24
+ int64_t num;
25
+ int64_t div;
26
+ int64_t di;
27
+ const char *str;
28
+ size_t len;
29
+ long exp;
30
+ int big;
31
+ int infinity;
32
+ int nan;
33
+ int neg;
34
+ int hasExp;
35
+ int no_big;
36
+ } *NumInfo;
37
+
38
+ typedef struct _ParseInfo {
39
+ // used for the string parser
40
+ const char *json;
41
+ const char *cur;
42
+ const char *end;
43
+ // used for the stream parser
44
+ struct _Reader rd;
45
+
46
+ struct _Err err;
47
+ struct _Options options;
48
+ VALUE handler;
49
+ struct _ValStack stack;
50
+ CircArray circ_array;
51
+ struct _RxClass str_rx;
52
+ int expect_value;
53
+ int max_depth; // just for the json gem
54
+ VALUE proc;
55
+ VALUE (*start_hash)(struct _ParseInfo *pi);
56
+ void (*end_hash)(struct _ParseInfo *pi);
57
+ VALUE (*hash_key)(struct _ParseInfo *pi, const char *key, size_t klen);
58
+ void (*hash_set_cstr)(struct _ParseInfo *pi, Val kval, const char *str, size_t len, const char *orig);
59
+ void (*hash_set_num)(struct _ParseInfo *pi, Val kval, NumInfo ni);
60
+ void (*hash_set_value)(struct _ParseInfo *pi, Val kval, VALUE value);
61
+
62
+ VALUE (*start_array)(struct _ParseInfo *pi);
63
+ void (*end_array)(struct _ParseInfo *pi);
64
+ void (*array_append_cstr)(struct _ParseInfo *pi, const char *str, size_t len, const char *orig);
65
+ void (*array_append_num)(struct _ParseInfo *pi, NumInfo ni);
66
+ void (*array_append_value)(struct _ParseInfo *pi, VALUE value);
67
+
68
+ void (*add_cstr)(struct _ParseInfo *pi, const char *str, size_t len, const char *orig);
69
+ void (*add_num)(struct _ParseInfo *pi, NumInfo ni);
70
+ void (*add_value)(struct _ParseInfo *pi, VALUE val);
71
+ VALUE err_class;
72
+ bool has_callbacks;
73
+ } *ParseInfo;
74
+
75
+ extern void oj_parse2(ParseInfo pi);
76
+ extern void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char* file, int line, const char *format, ...);
77
+ extern VALUE oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk);
78
+ extern VALUE oj_num_as_value(NumInfo ni);
79
+
80
+ extern void oj_set_strict_callbacks(ParseInfo pi);
81
+ extern void oj_set_object_callbacks(ParseInfo pi);
82
+ extern void oj_set_compat_callbacks(ParseInfo pi);
83
+
84
+ extern void oj_sparse2(ParseInfo pi);
85
+ extern VALUE oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd);
86
+
87
+ static inline void
88
+ parse_info_init(ParseInfo pi) {
89
+ memset(pi, 0, sizeof(struct _ParseInfo));
90
+ }
91
+
92
+ #endif /* __OJ_PARSE_H__ */
data/ext/oj/reader.c ADDED
@@ -0,0 +1,223 @@
1
+ /* reader.c
2
+ * Copyright (c) 2011, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #include <stdlib.h>
7
+ #include <errno.h>
8
+ #include <stdio.h>
9
+ #include <strings.h>
10
+ #include <sys/types.h>
11
+ #if NEEDS_UIO
12
+ #include <sys/uio.h>
13
+ #endif
14
+ #include <unistd.h>
15
+ #include <time.h>
16
+
17
+ #include "ruby.h"
18
+ #include "oj.h"
19
+ #include "reader.h"
20
+
21
+ #define BUF_PAD 4
22
+
23
+ static VALUE rescue_cb(VALUE rdr, VALUE err);
24
+ static VALUE io_cb(VALUE rdr);
25
+ static VALUE partial_io_cb(VALUE rdr);
26
+ static int read_from_io(Reader reader);
27
+ static int read_from_fd(Reader reader);
28
+ static int read_from_io_partial(Reader reader);
29
+ //static int read_from_str(Reader reader);
30
+
31
+ void
32
+ oj_reader_init(Reader reader, VALUE io, int fd) {
33
+ VALUE io_class = rb_obj_class(io);
34
+ VALUE stat;
35
+ VALUE ftype;
36
+
37
+ reader->head = reader->base;
38
+ *((char*)reader->head) = '\0';
39
+ reader->end = reader->head + sizeof(reader->base) - BUF_PAD;
40
+ reader->tail = reader->head;
41
+ reader->read_end = reader->head;
42
+ reader->pro = 0;
43
+ reader->str = 0;
44
+ reader->pos = 0;
45
+ reader->line = 1;
46
+ reader->col = 0;
47
+ reader->free_head = 0;
48
+
49
+ if (0 != fd) {
50
+ reader->read_func = read_from_fd;
51
+ reader->fd = fd;
52
+ } else if (rb_cString == io_class) {
53
+ reader->read_func = 0;
54
+ reader->in_str = StringValuePtr(io);
55
+ reader->head = (char*)reader->in_str;
56
+ reader->tail = reader->head;
57
+ reader->read_end = reader->head + RSTRING_LEN(io);
58
+ } else if (oj_stringio_class == io_class) {
59
+ VALUE s = rb_funcall2(io, oj_string_id, 0, 0);
60
+
61
+ reader->read_func = 0;
62
+ reader->in_str = StringValuePtr(s);
63
+ reader->head = (char*)reader->in_str;
64
+ reader->tail = reader->head;
65
+ reader->read_end = reader->head + RSTRING_LEN(s);
66
+ } else if (rb_cFile == io_class &&
67
+ Qnil != (stat = rb_funcall(io, oj_stat_id, 0)) &&
68
+ Qnil != (ftype = rb_funcall(stat, oj_ftype_id, 0)) &&
69
+ 0 == strcmp("file", StringValuePtr(ftype)) &&
70
+ 0 == FIX2INT(rb_funcall(io, oj_pos_id, 0))) {
71
+ reader->read_func = read_from_fd;
72
+ reader->fd = FIX2INT(rb_funcall(io, oj_fileno_id, 0));
73
+ } else if (rb_respond_to(io, oj_readpartial_id)) {
74
+ reader->read_func = read_from_io_partial;
75
+ reader->io = io;
76
+ } else if (rb_respond_to(io, oj_read_id)) {
77
+ reader->read_func = read_from_io;
78
+ reader->io = io;
79
+ } else {
80
+ rb_raise(rb_eArgError, "parser io argument must be a String or respond to readpartial() or read().\n");
81
+ }
82
+ }
83
+
84
+ int
85
+ oj_reader_read(Reader reader) {
86
+ int err;
87
+ size_t shift = 0;
88
+
89
+ if (0 == reader->read_func) {
90
+ return -1;
91
+ }
92
+ // if there is not much room to read into, shift or realloc a larger buffer.
93
+ if (reader->head < reader->tail && 4096 > reader->end - reader->tail) {
94
+ if (0 == reader->pro) {
95
+ shift = reader->tail - reader->head;
96
+ } else {
97
+ shift = reader->pro - reader->head - 1; // leave one character so we can backup one
98
+ }
99
+ if (0 >= shift) { /* no space left so allocate more */
100
+ const char *old = reader->head;
101
+ size_t size = reader->end - reader->head + BUF_PAD;
102
+
103
+ if (reader->head == reader->base) {
104
+ reader->head = ALLOC_N(char, size * 2);
105
+ memcpy((char*)reader->head, old, size);
106
+ } else {
107
+ REALLOC_N(reader->head, char, size * 2);
108
+ }
109
+ reader->free_head = 1;
110
+ reader->end = reader->head + size * 2 - BUF_PAD;
111
+ reader->tail = reader->head + (reader->tail - old);
112
+ reader->read_end = reader->head + (reader->read_end - old);
113
+ if (0 != reader->pro) {
114
+ reader->pro = reader->head + (reader->pro - old);
115
+ }
116
+ if (0 != reader->str) {
117
+ reader->str = reader->head + (reader->str - old);
118
+ }
119
+ } else {
120
+ memmove((char*)reader->head, reader->head + shift, reader->read_end - (reader->head + shift));
121
+ reader->tail -= shift;
122
+ reader->read_end -= shift;
123
+ if (0 != reader->pro) {
124
+ reader->pro -= shift;
125
+ }
126
+ if (0 != reader->str) {
127
+ reader->str -= shift;
128
+ }
129
+ }
130
+ }
131
+ err = reader->read_func(reader);
132
+ *(char*)reader->read_end = '\0';
133
+
134
+ return err;
135
+ }
136
+
137
+ static VALUE
138
+ rescue_cb(VALUE rbuf, VALUE err) {
139
+ VALUE clas = rb_obj_class(err);
140
+
141
+ if (rb_eTypeError != clas && rb_eEOFError != clas) {
142
+ Reader reader = (Reader)rbuf;
143
+
144
+ rb_raise(clas, "at line %d, column %d\n", reader->line, reader->col);
145
+ }
146
+ return Qfalse;
147
+ }
148
+
149
+ static VALUE
150
+ partial_io_cb(VALUE rbuf) {
151
+ Reader reader = (Reader)rbuf;
152
+ VALUE args[1];
153
+ VALUE rstr;
154
+ char *str;
155
+ size_t cnt;
156
+
157
+ args[0] = ULONG2NUM(reader->end - reader->tail);
158
+ rstr = rb_funcall2(reader->io, oj_readpartial_id, 1, args);
159
+ if (Qnil == rstr) {
160
+ return Qfalse;
161
+ }
162
+ str = StringValuePtr(rstr);
163
+ cnt = RSTRING_LEN(rstr);
164
+ //printf("*** partial read %lu bytes, str: '%s'\n", cnt, str);
165
+ strcpy(reader->tail, str);
166
+ reader->read_end = reader->tail + cnt;
167
+
168
+ return Qtrue;
169
+ }
170
+
171
+ static VALUE
172
+ io_cb(VALUE rbuf) {
173
+ Reader reader = (Reader)rbuf;
174
+ VALUE args[1];
175
+ VALUE rstr;
176
+ char *str;
177
+ size_t cnt;
178
+
179
+ args[0] = ULONG2NUM(reader->end - reader->tail);
180
+ rstr = rb_funcall2(reader->io, oj_read_id, 1, args);
181
+ if (Qnil == rstr) {
182
+ return Qfalse;
183
+ }
184
+ str = StringValuePtr(rstr);
185
+ cnt = RSTRING_LEN(rstr);
186
+ //printf("*** read %lu bytes, str: '%s'\n", cnt, str);
187
+ strcpy(reader->tail, str);
188
+ reader->read_end = reader->tail + cnt;
189
+
190
+ return Qtrue;
191
+ }
192
+
193
+ static int
194
+ read_from_io_partial(Reader reader) {
195
+ return (Qfalse == rb_rescue(partial_io_cb, (VALUE)reader, rescue_cb, (VALUE)reader));
196
+ }
197
+
198
+ static int
199
+ read_from_io(Reader reader) {
200
+ return (Qfalse == rb_rescue(io_cb, (VALUE)reader, rescue_cb, (VALUE)reader));
201
+ }
202
+
203
+ static int
204
+ read_from_fd(Reader reader) {
205
+ ssize_t cnt;
206
+ size_t max = reader->end - reader->tail;
207
+
208
+ cnt = read(reader->fd, reader->tail, max);
209
+ if (cnt <= 0) {
210
+ return -1;
211
+ } else if (0 != cnt) {
212
+ reader->read_end = reader->tail + cnt;
213
+ }
214
+ return 0;
215
+ }
216
+
217
+ // This is only called when the end of the string is reached so just return -1.
218
+ /*
219
+ static int
220
+ read_from_str(Reader reader) {
221
+ return -1;
222
+ }
223
+ */
data/ext/oj/reader.h ADDED
@@ -0,0 +1,151 @@
1
+ /* reader.h
2
+ * Copyright (c) 2011, Peter Ohler
3
+ * All rights reserved.
4
+ */
5
+
6
+ #ifndef __OJ_READER_H__
7
+ #define __OJ_READER_H__
8
+
9
+ typedef struct _Reader {
10
+ char base[0x00001000];
11
+ char *head;
12
+ char *end;
13
+ char *tail;
14
+ char *read_end; /* one past last character read */
15
+ char *pro; /* protection start, buffer can not slide past this point */
16
+ char *str; /* start of current string being read */
17
+ long pos;
18
+ int line;
19
+ int col;
20
+ int free_head;
21
+ int (*read_func)(struct _Reader *reader);
22
+ union {
23
+ int fd;
24
+ VALUE io;
25
+ const char *in_str;
26
+ };
27
+ } *Reader;
28
+
29
+ extern void oj_reader_init(Reader reader, VALUE io, int fd);
30
+ extern int oj_reader_read(Reader reader);
31
+
32
+ static inline char
33
+ reader_get(Reader reader) {
34
+ //printf("*** drive get from '%s' from start: %ld buf: %p from read_end: %ld\n", reader->tail, reader->tail - reader->head, reader->head, reader->read_end - reader->tail);
35
+ if (reader->read_end <= reader->tail) {
36
+ if (0 != oj_reader_read(reader)) {
37
+ return '\0';
38
+ }
39
+ }
40
+ if ('\n' == *reader->tail) {
41
+ reader->line++;
42
+ reader->col = 0;
43
+ }
44
+ reader->col++;
45
+ reader->pos++;
46
+
47
+ return *reader->tail++;
48
+ }
49
+
50
+ static inline void
51
+ reader_backup(Reader reader) {
52
+ reader->tail--;
53
+ reader->col--;
54
+ reader->pos--;
55
+ if (0 >= reader->col) {
56
+ reader->line--;
57
+ // allow col to be negative since we never backup twice in a row
58
+ }
59
+ }
60
+
61
+ static inline void
62
+ reader_protect(Reader reader) {
63
+ reader->pro = reader->tail;
64
+ reader->str = reader->tail; // can't have str before pro
65
+ }
66
+
67
+ static inline void
68
+ reader_release(Reader reader) {
69
+ reader->pro = 0;
70
+ }
71
+
72
+ /* Starts by reading a character so it is safe to use with an empty or
73
+ * compacted buffer.
74
+ */
75
+ static inline char
76
+ reader_next_non_white(Reader reader) {
77
+ char c;
78
+
79
+ while ('\0' != (c = reader_get(reader))) {
80
+ switch(c) {
81
+ case ' ':
82
+ case '\t':
83
+ case '\f':
84
+ case '\n':
85
+ case '\r':
86
+ break;
87
+ default:
88
+ return c;
89
+ }
90
+ }
91
+ return '\0';
92
+ }
93
+
94
+ /* Starts by reading a character so it is safe to use with an empty or
95
+ * compacted buffer.
96
+ */
97
+ static inline char
98
+ reader_next_white(Reader reader) {
99
+ char c;
100
+
101
+ while ('\0' != (c = reader_get(reader))) {
102
+ switch(c) {
103
+ case ' ':
104
+ case '\t':
105
+ case '\f':
106
+ case '\n':
107
+ case '\r':
108
+ case '\0':
109
+ return c;
110
+ default:
111
+ break;
112
+ }
113
+ }
114
+ return '\0';
115
+ }
116
+
117
+ static inline int
118
+ reader_expect(Reader reader, const char *s) {
119
+ for (; '\0' != *s; s++) {
120
+ if (reader_get(reader) != *s) {
121
+ return -1;
122
+ }
123
+ }
124
+ return 0;
125
+ }
126
+
127
+ static inline void
128
+ reader_cleanup(Reader reader) {
129
+ if (reader->free_head && 0 != reader->head) {
130
+ xfree((char*)reader->head);
131
+ reader->head = 0;
132
+ reader->free_head = 0;
133
+ }
134
+ }
135
+
136
+ static inline int
137
+ is_white(char c) {
138
+ switch(c) {
139
+ case ' ':
140
+ case '\t':
141
+ case '\f':
142
+ case '\n':
143
+ case '\r':
144
+ return 1;
145
+ default:
146
+ break;
147
+ }
148
+ return 0;
149
+ }
150
+
151
+ #endif /* __OJ_READER_H__ */
data/ext/oj/resolve.c ADDED
@@ -0,0 +1,127 @@
1
+ /* resolve.c
2
+ * Copyright (c) 2012, Peter Ohler
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
+ */
30
+
31
+ #include <stdlib.h>
32
+ #include <stdio.h>
33
+ #include <string.h>
34
+ #if USE_PTHREAD_MUTEX
35
+ #include <pthread.h>
36
+ #endif
37
+
38
+ #include "oj.h"
39
+ #include "err.h"
40
+ #include "parse.h"
41
+ #include "hash.h"
42
+
43
+ inline static VALUE
44
+ resolve_classname(VALUE mod, const char *classname, int auto_define) {
45
+ VALUE clas;
46
+ ID ci = rb_intern(classname);
47
+
48
+ if (rb_const_defined_at(mod, ci)) {
49
+ clas = rb_const_get_at(mod, ci);
50
+ } else if (auto_define) {
51
+ clas = rb_define_class_under(mod, classname, oj_bag_class);
52
+ } else {
53
+ clas = Qundef;
54
+ }
55
+ return clas;
56
+ }
57
+
58
+ static VALUE
59
+ resolve_classpath(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
60
+ char class_name[1024];
61
+ VALUE clas;
62
+ char *end = class_name + sizeof(class_name) - 1;
63
+ char *s;
64
+ const char *n = name;
65
+
66
+ clas = rb_cObject;
67
+ for (s = class_name; 0 < len; n++, len--) {
68
+ if (':' == *n) {
69
+ *s = '\0';
70
+ n++;
71
+ len--;
72
+ if (':' != *n) {
73
+ return Qundef;
74
+ }
75
+ if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
76
+ return Qundef;
77
+ }
78
+ s = class_name;
79
+ } else if (end <= s) {
80
+ return Qundef;
81
+ } else {
82
+ *s++ = *n;
83
+ }
84
+ }
85
+ *s = '\0';
86
+ if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
87
+ oj_set_error_at(pi, error_class, __FILE__, __LINE__, "class %s is not defined", name);
88
+ if (Qnil != error_class) {
89
+ pi->err_class = error_class;
90
+ }
91
+ }
92
+ return clas;
93
+ }
94
+
95
+ VALUE
96
+ oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class) {
97
+ VALUE clas;
98
+ VALUE *slot;
99
+
100
+ if (No == pi->options.class_cache) {
101
+ return resolve_classpath(pi, name, len, auto_define, error_class);
102
+ }
103
+ #if USE_PTHREAD_MUTEX
104
+ pthread_mutex_lock(&oj_cache_mutex);
105
+ #elif USE_RB_MUTEX
106
+ rb_mutex_lock(oj_cache_mutex);
107
+ #endif
108
+ if (Qnil == (clas = oj_class_hash_get(name, len, &slot))) {
109
+ if (Qundef != (clas = resolve_classpath(pi, name, len, auto_define, error_class))) {
110
+ *slot = clas;
111
+ }
112
+ }
113
+ #if USE_PTHREAD_MUTEX
114
+ pthread_mutex_unlock(&oj_cache_mutex);
115
+ #elif USE_RB_MUTEX
116
+ rb_mutex_unlock(oj_cache_mutex);
117
+ #endif
118
+ return clas;
119
+ }
120
+
121
+ VALUE
122
+ oj_name2struct(ParseInfo pi, VALUE nameVal, VALUE error_class) {
123
+ size_t len = RSTRING_LEN(nameVal);
124
+ const char *str = StringValuePtr(nameVal);
125
+
126
+ return resolve_classpath(pi, str, len, 0, error_class);
127
+ }
@@ -1,4 +1,4 @@
1
- /* cache.h
1
+ /* resolve.h
2
2
  * Copyright (c) 2011, Peter Ohler
3
3
  * All rights reserved.
4
4
  *
@@ -28,19 +28,12 @@
28
28
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
29
  */
30
30
 
31
- #ifndef __OJ_CACHE_H__
32
- #define __OJ_CACHE_H__
33
-
34
- #define RSTRING_NOT_MODIFIED
31
+ #ifndef __OJ_RESOLVE_H__
32
+ #define __OJ_RESOLVE_H__
35
33
 
36
34
  #include "ruby.h"
37
35
 
38
- typedef struct _Cache *Cache;
39
-
40
- extern void oj_cache_new(Cache *cache);
41
-
42
- extern VALUE oj_cache_get(Cache cache, const char *key, VALUE **slot);
43
-
44
- extern void oj_cache_print(Cache cache);
36
+ extern VALUE oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE error_class);
37
+ extern VALUE oj_name2struct(ParseInfo pi, VALUE nameVal, VALUE error_class);
45
38
 
46
- #endif /* __OJ_CACHE_H__ */
39
+ #endif /* __OJ_RESOLVE_H__ */