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/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__ */