oj 0.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of oj might be problematic. Click here for more details.

data/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ Copyright (c) 2011, Peter Ohler
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ - Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ - Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ - Neither the name of Peter Ohler nor the names of its contributors may be
15
+ used to endorse or promote products derived from this software without
16
+ specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,58 @@
1
+ # Oj gem
2
+ A fast JSON parser and Object marshaller as a Ruby gem.
3
+
4
+ ## <a name="installation">Installation</a>
5
+ gem install oj
6
+
7
+ ## <a name="source">Source</a>
8
+
9
+ *GitHub* *repo*: https://github.com/ohler55/oj
10
+
11
+ *RubyGems* *repo*: https://rubygems.org/gems/oj
12
+
13
+ ## <a name="build_status">Build Status</a>
14
+
15
+ [![Build Status](http://travis-ci.org/ohler55/oj.png)](http://travis-ci.org/ohler55/oj)
16
+
17
+ ## <a name="links">Links of Interest</a>
18
+
19
+ ## <a name="release">Release Notes</a>
20
+
21
+ ### Release 0.5
22
+
23
+ This is the first release sith a version of 0.5 indicating it is only half
24
+ done. Basic load() and dump() is supported for Hash, Array, NilClass,
25
+ TrueClass, FalseClass, Fixnum, Float, Symbol, and String Objects.
26
+
27
+ ## <a name="description">Description</a>
28
+
29
+ Optimized JSON (Oj), as the name implies was written to provide speed
30
+ optimized JSON handling. It was designed as a faster alternative to Yajl and
31
+ other the common Ruby JSON parsers. So far is has achieved that at about 2
32
+ time faster than Yajl for parsing and 3 or more times faster writing JSON.
33
+
34
+ Coming soon: As an Object marshaller with support for circular references.
35
+
36
+ Coming soon: A SAX like JSON stream parser.
37
+
38
+ Oj is compatible with Ruby 1.8.7, 1.9.2, 1.9.3, JRuby, and RBX.
39
+
40
+ ### Simple JSON Writing and Parsing:
41
+
42
+ require 'oj'
43
+
44
+ h = { 'one' => 1, 'array' => [ true, false ] }
45
+ json = Oj.dump(h)
46
+
47
+ # json =
48
+ # {
49
+ # "one":1,
50
+ # "array":[
51
+ # true,
52
+ # false
53
+ # ]
54
+ # }
55
+
56
+ h2 = Oj.parse(json)
57
+ puts "Same? #{h == h2}"
58
+ # true
@@ -0,0 +1,484 @@
1
+ /* dump.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 <errno.h>
33
+ #include <time.h>
34
+ #include <stdio.h>
35
+ #include <string.h>
36
+
37
+ #include "ruby.h"
38
+ #include "oj.h"
39
+
40
+ typedef unsigned long ulong;
41
+
42
+ typedef struct _Str {
43
+ const char *str;
44
+ size_t len;
45
+ } *Str;
46
+
47
+ typedef struct _Element {
48
+ struct _Str clas;
49
+ struct _Str attr;
50
+ unsigned long id;
51
+ int indent; // < 0 indicates no \n
52
+ int closed;
53
+ char type;
54
+ } *Element;
55
+
56
+ typedef struct _Out {
57
+ void (*w_start)(struct _Out *out, Element e);
58
+ void (*w_end)(struct _Out *out, Element e);
59
+ void (*w_time)(struct _Out *out, VALUE obj);
60
+ char *buf;
61
+ char *end;
62
+ char *cur;
63
+ // Cache8 circ_cache;
64
+ // unsigned long circ_cnt;
65
+ int indent;
66
+ int depth; // used by dumpHash
67
+ Options opts;
68
+ VALUE obj;
69
+ } *Out;
70
+
71
+ static void dump_obj_to_json(VALUE obj, Options copts, Out out);
72
+ static void dump_val(VALUE obj, int depth, Out out);
73
+ static void dump_nil(Out out);
74
+ static void dump_true(Out out);
75
+ static void dump_false(Out out);
76
+ static void dump_fixnum(VALUE obj, Out out);
77
+ static void dump_float(VALUE obj, Out out);
78
+ static void dump_cstr(const char *str, int cnt, Out out);
79
+ static void dump_hex(u_char c, Out out);
80
+ static void dump_str(VALUE obj, Out out);
81
+ static void dump_sym(VALUE obj, Out out);
82
+ static void dump_array(VALUE obj, int depth, Out out);
83
+ static void dump_hash(VALUE obj, int depth, Out out);
84
+
85
+ static void grow(Out out, size_t len);
86
+ static int is_json_friendly(const u_char *str, int len);
87
+ static int json_friendly_size(const u_char *str, int len);
88
+
89
+
90
+ static char json_friendly_chars[256] = "\
91
+ uuuuuuuuxxxuxxuuuuuuuuuuuuuuuuuu\
92
+ ooxooooooooooooxoooooooooooooooo\
93
+ ooooooooooooooooooooooooooooxooo\
94
+ ooooooooooooooooooooooooooooooou\
95
+ uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu\
96
+ uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu\
97
+ uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu\
98
+ uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu";
99
+
100
+ inline static int
101
+ is_json_friendly(const u_char *str, int len) {
102
+ for (; 0 < len; str++, len--) {
103
+ if ('o' != json_friendly_chars[*str]) {
104
+ return 0;
105
+ }
106
+ }
107
+ return 1;
108
+ }
109
+
110
+ inline static int
111
+ json_friendly_size(const u_char *str, int len) {
112
+ int cnt = 0;
113
+
114
+ for (; 0 < len; str++, len--) {
115
+ switch (json_friendly_chars[*str]) {
116
+ case 'o': cnt++; break;
117
+ case 'x': cnt += 2; break;
118
+ case 'u': cnt += 6; break;
119
+ default: break;
120
+ }
121
+ }
122
+ return cnt;
123
+ }
124
+
125
+ inline static void
126
+ fill_indent(Out out, int cnt) {
127
+ cnt *= out->indent;
128
+ if (0 <= cnt) {
129
+ *out->cur++ = '\n';
130
+ for (; 0 < cnt; cnt--) {
131
+ *out->cur++ = ' ';
132
+ }
133
+ }
134
+ }
135
+
136
+ static void
137
+ grow(Out out, size_t len) {
138
+ size_t size = out->end - out->buf;
139
+ long pos = out->cur - out->buf;
140
+ char *buf;
141
+
142
+ size *= 2;
143
+ if (size <= len * 2 + pos) {
144
+ size += len;
145
+ }
146
+ if (0 == (buf = (char*)realloc(out->buf, size + 10))) { // 1 extra for terminator character plus extra (paranoid)
147
+ rb_raise(rb_eNoMemError, "Failed to create string. [%d:%s]\n", ENOSPC, strerror(ENOSPC));
148
+ }
149
+ out->buf = buf;
150
+ out->end = buf + size;
151
+ out->cur = out->buf + pos;
152
+ }
153
+
154
+ inline static void
155
+ dump_hex(u_char c, Out out) {
156
+ u_char d = c & 0xF0;
157
+
158
+ if (9 < d) {
159
+ *out->cur++ = (d - 10) + 'a';
160
+ } else {
161
+ *out->cur++ = d + '0';
162
+ }
163
+ d = c & 0x0F;
164
+ if (9 < d) {
165
+ *out->cur++ = (d - 10) + 'a';
166
+ } else {
167
+ *out->cur++ = d + '0';
168
+ }
169
+ }
170
+
171
+ static void
172
+ dump_nil(Out out) {
173
+ size_t size = 4;
174
+
175
+ if (out->end - out->cur <= (long)size) {
176
+ grow(out, size);
177
+ }
178
+ *out->cur++ = 'n';
179
+ *out->cur++ = 'u';
180
+ *out->cur++ = 'l';
181
+ *out->cur++ = 'l';
182
+ *out->cur = '\0';
183
+ }
184
+
185
+ static void
186
+ dump_true(Out out) {
187
+ size_t size = 4;
188
+
189
+ if (out->end - out->cur <= (long)size) {
190
+ grow(out, size);
191
+ }
192
+ *out->cur++ = 't';
193
+ *out->cur++ = 'r';
194
+ *out->cur++ = 'u';
195
+ *out->cur++ = 'e';
196
+ *out->cur = '\0';
197
+ }
198
+
199
+ static void
200
+ dump_false(Out out) {
201
+ size_t size = 5;
202
+
203
+ if (out->end - out->cur <= (long)size) {
204
+ grow(out, size);
205
+ }
206
+ *out->cur++ = 'f';
207
+ *out->cur++ = 'a';
208
+ *out->cur++ = 'l';
209
+ *out->cur++ = 's';
210
+ *out->cur++ = 'e';
211
+ *out->cur = '\0';
212
+ }
213
+
214
+ static void
215
+ dump_fixnum(VALUE obj, Out out) {
216
+ char buf[32];
217
+ char *b = buf + sizeof(buf) - 1;
218
+ long num = NUM2LONG(obj);
219
+ int neg = 0;
220
+
221
+ if (0 > num) {
222
+ neg = 1;
223
+ num = -num;
224
+ }
225
+ *b-- = '\0';
226
+ if (0 < num) {
227
+ for (; 0 < num; num /= 10, b--) {
228
+ *b = (num % 10) + '0';
229
+ }
230
+ if (neg) {
231
+ *b = '-';
232
+ } else {
233
+ b++;
234
+ }
235
+ } else {
236
+ *b = '0';
237
+ }
238
+ if (out->end - out->cur <= (long)(sizeof(buf) - (b - buf))) {
239
+ grow(out, sizeof(buf) - (b - buf));
240
+ }
241
+ for (; '\0' != *b; b++) {
242
+ *out->cur++ = *b;
243
+ }
244
+ *out->cur = '\0';
245
+ }
246
+
247
+ static void
248
+ dump_float(VALUE obj, Out out) {
249
+ char buf[64];
250
+ char *b;
251
+ int cnt = sprintf(buf, "%0.16g", RFLOAT_VALUE(obj)); // used sprintf due to bug in snprintf
252
+
253
+ if (out->end - out->cur <= (long)cnt) {
254
+ grow(out, cnt);
255
+ }
256
+ for (b = buf; '\0' != *b; b++) {
257
+ *out->cur++ = *b;
258
+ }
259
+ *out->cur = '\0';
260
+ }
261
+
262
+ static void
263
+ dump_cstr(const char *str, int cnt, Out out) {
264
+ int size = json_friendly_size((u_char*)str, cnt);
265
+
266
+ if (cnt == size) {
267
+ cnt += 2;
268
+ if (out->end - out->cur <= (long)cnt) {
269
+ grow(out, cnt);
270
+ }
271
+ *out->cur++ = '"';
272
+ for (; '\0' != *str; str++) {
273
+ *out->cur++ = *str;
274
+ }
275
+ *out->cur++ = '"';
276
+ } else {
277
+ size += 2;
278
+ if (out->end - out->cur <= (long)size) {
279
+ grow(out, size);
280
+ }
281
+ *out->cur++ = '"';
282
+ for (; 0 < cnt; cnt--, str++) {
283
+ switch (json_friendly_chars[(u_char)*str]) {
284
+ case 'o':
285
+ *out->cur++ = *str;
286
+ break;
287
+ case 'x':
288
+ *out->cur++ = '\\';
289
+ switch (*str) {
290
+ case '\b': *out->cur++ = 'b'; break;
291
+ case '\t': *out->cur++ = 't'; break;
292
+ case '\n': *out->cur++ = 'n'; break;
293
+ case '\f': *out->cur++ = 'f'; break;
294
+ case '\r': *out->cur++ = 'r'; break;
295
+ default: *out->cur++ = *str; break;
296
+ }
297
+ break;
298
+ case 'u':
299
+ *out->cur++ = '\\';
300
+ *out->cur++ = 'u';
301
+ if ((u_char)*str <= 0x7F) {
302
+ *out->cur++ = '0';
303
+ *out->cur++ = '0';
304
+ dump_hex((u_char)*str, out);
305
+ } else { // continuation?
306
+ // TBD lead with \u00 . grab next char?
307
+ *out->cur++ = '0';
308
+ *out->cur++ = '0';
309
+ dump_hex((u_char)*str, out);
310
+ }
311
+ break;
312
+ default:
313
+ break; // ignore, should never happen if the table is correct
314
+ }
315
+ }
316
+ *out->cur++ = '"';
317
+ }
318
+ *out->cur = '\0';
319
+ }
320
+
321
+ static void
322
+ dump_str(VALUE obj, Out out) {
323
+ dump_cstr(StringValuePtr(obj), (int)RSTRING_LEN(obj), out);
324
+ }
325
+
326
+ static void
327
+ dump_sym(VALUE obj, Out out) {
328
+ const char *sym = rb_id2name(SYM2ID(obj));
329
+
330
+ dump_cstr(sym, (int)strlen(sym), out);
331
+ }
332
+
333
+ static void
334
+ dump_array(VALUE a, int depth, Out out) {
335
+ VALUE *np = RARRAY_PTR(a);
336
+ size_t size = 2;
337
+ int cnt = (int)RARRAY_LEN(a);
338
+ int d2 = depth + 1;
339
+
340
+ if (out->end - out->cur <= (long)size) {
341
+ grow(out, size);
342
+ }
343
+ *out->cur++ = '[';
344
+ if (0 == cnt) {
345
+ *out->cur++ = ']';
346
+ } else {
347
+ size = d2 * out->indent + 2;
348
+ for (; 0 < cnt; cnt--, np++) {
349
+ if (out->end - out->cur <= (long)size) {
350
+ grow(out, size);
351
+ }
352
+ fill_indent(out, d2);
353
+ dump_val(*np, d2, out);
354
+ if (1 < cnt) {
355
+ // TBD check size?
356
+ *out->cur++ = ',';
357
+ }
358
+ }
359
+ size = depth * out->indent + 1;
360
+ if (out->end - out->cur <= (long)size) {
361
+ grow(out, size);
362
+ }
363
+ fill_indent(out, depth);
364
+ *out->cur++ = ']';
365
+ }
366
+ *out->cur = '\0';
367
+ }
368
+
369
+ static int
370
+ hash_cb(VALUE key, VALUE value, Out out) {
371
+ int depth = out->depth;
372
+ size_t size = depth * out->indent + 1;
373
+
374
+ if (out->end - out->cur <= (long)size) {
375
+ grow(out, size);
376
+ }
377
+ fill_indent(out, depth);
378
+ dump_str(key, out);
379
+ *out->cur++ = ':';
380
+ dump_val(value, depth, out);
381
+ out->depth = depth;
382
+ *out->cur++ = ',';
383
+
384
+ return ST_CONTINUE;
385
+ }
386
+
387
+ static void
388
+ dump_hash(VALUE obj, int depth, Out out) {
389
+ int cnt = (int)RHASH_SIZE(obj);
390
+
391
+ *out->cur++ = '{';
392
+ if (0 == cnt) {
393
+ *out->cur++ = '}';
394
+ } else {
395
+ size_t size = depth * out->indent + 2;
396
+
397
+ out->depth = depth + 1;
398
+ rb_hash_foreach(obj, hash_cb, (VALUE)out);
399
+ out->cur--; // backup to overwrite last comma
400
+ if (out->end - out->cur <= (long)size) {
401
+ grow(out, size);
402
+ }
403
+ fill_indent(out, depth);
404
+ *out->cur++ = '}';
405
+ }
406
+ *out->cur = '\0';
407
+ }
408
+
409
+ static void
410
+ dump_val(VALUE obj, int depth, Out out) {
411
+ switch (rb_type(obj)) {
412
+ case T_NIL: dump_nil(out); break;
413
+ case T_TRUE: dump_true(out); break;
414
+ case T_FALSE: dump_false(out); break;
415
+ case T_FIXNUM: dump_fixnum(obj, out); break;
416
+ case T_FLOAT: dump_float(obj, out); break;
417
+ case T_BIGNUM: break; // TBD
418
+ case T_STRING: dump_str(obj, out); break;
419
+ case T_SYMBOL: dump_sym(obj, out); break;
420
+ case T_ARRAY: dump_array(obj, depth, out); break;
421
+ case T_HASH: dump_hash(obj, depth, out); break;
422
+ case T_OBJECT:
423
+ case T_REGEXP:
424
+ case T_CLASS:
425
+ case T_DATA: // for Time
426
+ // TBD
427
+ rb_raise(rb_eNotImpError, "Failed to dump '%s' Object (%02x)\n",
428
+ rb_class2name(rb_obj_class(obj)), rb_type(obj));
429
+ break;
430
+ default:
431
+ rb_raise(rb_eNotImpError, "Failed to dump '%s' Object (%02x)\n",
432
+ rb_class2name(rb_obj_class(obj)), rb_type(obj));
433
+ break;
434
+ }
435
+ }
436
+
437
+ static void
438
+ dump_obj_to_json(VALUE obj, Options copts, Out out) {
439
+ out->buf = (char*)malloc(65336);
440
+ out->end = out->buf + 65325; // 1 less than end plus extra for possible errors
441
+ out->cur = out->buf;
442
+ // out->circ_cache = 0;
443
+ // out->circ_cnt = 0;
444
+ out->opts = copts;
445
+ out->obj = obj;
446
+ /* if (Yes == copts->circular) {
447
+ ox_cache8_new(&out->circ_cache);
448
+ }*/
449
+ out->indent = copts->indent;
450
+ out->indent = 2; // TBD
451
+ dump_val(obj, 0, out);
452
+
453
+ /* if (Yes == copts->circular) {
454
+ ox_cache8_delete(out->circ_cache);
455
+ }*/
456
+ }
457
+
458
+ char*
459
+ write_obj_to_str(VALUE obj, Options copts) {
460
+ struct _Out out;
461
+
462
+ dump_obj_to_json(obj, copts, &out);
463
+
464
+ return out.buf;
465
+ }
466
+
467
+ void
468
+ write_obj_to_file(VALUE obj, const char *path, Options copts) {
469
+ struct _Out out;
470
+ size_t size;
471
+ FILE *f;
472
+
473
+ dump_obj_to_json(obj, copts, &out);
474
+ size = out.cur - out.buf;
475
+ if (0 == (f = fopen(path, "w"))) {
476
+ rb_raise(rb_eIOError, "%s\n", strerror(errno));
477
+ }
478
+ if (size != fwrite(out.buf, 1, size, f)) {
479
+ int err = ferror(f);
480
+ rb_raise(rb_eIOError, "Write failed. [%d:%s]\n", err, strerror(err));
481
+ }
482
+ free(out.buf);
483
+ fclose(f);
484
+ }
@@ -0,0 +1,7 @@
1
+ require 'mkmf'
2
+
3
+ $CPPFLAGS += ' -Wall'
4
+ #puts "*** $CPPFLAGS: #{$CPPFLAGS}"
5
+ extension_name = 'oj'
6
+ dir_config(extension_name)
7
+ create_makefile(extension_name)
@@ -0,0 +1,426 @@
1
+ /* load.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
+ #include <math.h>
35
+
36
+ #include "ruby.h"
37
+ #include "oj.h"
38
+
39
+ typedef struct _ParseInfo {
40
+ char *str; /* buffer being read from */
41
+ char *s; /* current position in buffer */
42
+ #ifdef HAVE_RUBY_ENCODING_H
43
+ rb_encoding *encoding;
44
+ #else
45
+ void *encoding;
46
+ #endif
47
+ int trace;
48
+ } *ParseInfo;
49
+
50
+ static VALUE read_next(ParseInfo pi);
51
+ static VALUE read_obj(ParseInfo pi);
52
+ static VALUE read_array(ParseInfo pi);
53
+ static VALUE read_str(ParseInfo pi);
54
+ static VALUE read_num(ParseInfo pi);
55
+ static VALUE read_true(ParseInfo pi);
56
+ static VALUE read_false(ParseInfo pi);
57
+ static VALUE read_nil(ParseInfo pi);
58
+ static void next_non_white(ParseInfo pi);
59
+ static char* read_quoted_value(ParseInfo pi);
60
+
61
+
62
+ /* This XML parser is a single pass, destructive, callback parser. It is a
63
+ * single pass parse since it only make one pass over the characters in the
64
+ * XML document string. It is destructive because it re-uses the content of
65
+ * the string for values in the callback and places \0 characters at various
66
+ * places to mark the end of tokens and strings. It is a callback parser like
67
+ * a SAX parser because it uses callback when document elements are
68
+ * encountered.
69
+ *
70
+ * Parsing is very tolerant. Lack of headers and even mispelled element
71
+ * endings are passed over without raising an error. A best attempt is made in
72
+ * all cases to parse the string.
73
+ */
74
+
75
+ inline static void
76
+ next_non_white(ParseInfo pi) {
77
+ for (; 1; pi->s++) {
78
+ switch(*pi->s) {
79
+ case ' ':
80
+ case '\t':
81
+ case '\f':
82
+ case '\n':
83
+ case '\r':
84
+ break;
85
+ default:
86
+ return;
87
+ }
88
+ }
89
+ }
90
+
91
+ inline static void
92
+ next_white(ParseInfo pi) {
93
+ for (; 1; pi->s++) {
94
+ switch(*pi->s) {
95
+ case ' ':
96
+ case '\t':
97
+ case '\f':
98
+ case '\n':
99
+ case '\r':
100
+ case '\0':
101
+ return;
102
+ default:
103
+ break;
104
+ }
105
+ }
106
+ }
107
+
108
+ VALUE
109
+ parse(char *json, int trace) {
110
+ VALUE obj;
111
+ struct _ParseInfo pi;
112
+
113
+ if (0 == json) {
114
+ raise_error("Invalid arg, xml string can not be null", json, 0);
115
+ }
116
+ if (trace) {
117
+ printf("Parsing JSON:\n%s\n", json);
118
+ }
119
+ /* initialize parse info */
120
+ pi.str = json;
121
+ pi.s = json;
122
+ pi.encoding = 0;
123
+ pi.trace = trace;
124
+ if (Qundef == (obj = read_next(&pi))) {
125
+ raise_error("no object read", pi.str, pi.s);
126
+ }
127
+ next_non_white(&pi); // skip white space
128
+ if ('\0' != *pi.s) {
129
+ raise_error("invalid format, extra characters", pi.str, pi.s);
130
+ }
131
+ return obj;
132
+ }
133
+
134
+ static VALUE
135
+ read_next(ParseInfo pi) {
136
+ VALUE obj;
137
+
138
+ next_non_white(pi); // skip white space
139
+ switch (*pi->s) {
140
+ case '{':
141
+ obj = read_obj(pi);
142
+ break;
143
+ case '[':
144
+ obj = read_array(pi);
145
+ break;
146
+ case '"':
147
+ obj = read_str(pi);
148
+ break;
149
+ case '+':
150
+ case '-':
151
+ case '0':
152
+ case '1':
153
+ case '2':
154
+ case '3':
155
+ case '4':
156
+ case '5':
157
+ case '6':
158
+ case '7':
159
+ case '8':
160
+ case '9':
161
+ obj = read_num(pi);
162
+ break;
163
+ case 't':
164
+ obj = read_true(pi);
165
+ break;
166
+ case 'f':
167
+ obj = read_false(pi);
168
+ break;
169
+ case 'n':
170
+ obj = read_nil(pi);
171
+ break;
172
+ case '\0':
173
+ obj = Qundef;
174
+ break;
175
+ default:
176
+ obj = Qundef;
177
+ break;
178
+ }
179
+ return obj;
180
+ }
181
+
182
+ static VALUE
183
+ read_obj(ParseInfo pi) {
184
+ VALUE obj = Qundef;
185
+ VALUE key = Qundef;
186
+ VALUE val = Qundef;
187
+
188
+ pi->s++;
189
+ while (1) {
190
+ next_non_white(pi);
191
+ if ('"' != *pi->s || Qundef == (key = read_str(pi))) {
192
+ raise_error("unexpected character", pi->str, pi->s);
193
+ }
194
+ next_non_white(pi);
195
+ if (':' == *pi->s) {
196
+ pi->s++;
197
+ } else {
198
+ raise_error("invalid format, expected :", pi->str, pi->s);
199
+ }
200
+ if (Qundef == (val = read_next(pi))) {
201
+ raise_error("unexpected character", pi->str, pi->s);
202
+ }
203
+ if (Qundef == obj) {
204
+ obj = rb_hash_new();
205
+ }
206
+ rb_hash_aset(obj, key, val);
207
+ next_non_white(pi);
208
+ if ('}' == *pi->s) {
209
+ pi->s++;
210
+ break;
211
+ } else if (',' == *pi->s) {
212
+ pi->s++;
213
+ } else {
214
+ raise_error("invalid format, expected , or } while in an object", pi->str, pi->s);
215
+ }
216
+ }
217
+ return obj;
218
+ }
219
+
220
+ static VALUE
221
+ read_array(ParseInfo pi) {
222
+ VALUE a = rb_ary_new();
223
+ VALUE e;
224
+
225
+ pi->s++;
226
+ while (1) {
227
+ if (Qundef == (e = read_next(pi))) {
228
+ raise_error("unexpected character", pi->str, pi->s);
229
+ }
230
+ rb_ary_push(a, e);
231
+ next_non_white(pi); // skip white space
232
+ if (',' == *pi->s) {
233
+ pi->s++;
234
+ } else if (']' == *pi->s) {
235
+ pi->s++;
236
+ break;
237
+ } else {
238
+ raise_error("invalid format, expected , or ] while in an array", pi->str, pi->s);
239
+ }
240
+ }
241
+ return a;
242
+ }
243
+
244
+ static VALUE
245
+ read_str(ParseInfo pi) {
246
+ char *text = read_quoted_value(pi);
247
+ VALUE s = rb_str_new2(text);
248
+
249
+ #ifdef HAVE_RUBY_ENCODING_H
250
+ if (0 != pi->encoding) {
251
+ rb_enc_associate(s, pi->encoding);
252
+ }
253
+ #endif
254
+ return s;
255
+ }
256
+
257
+ static VALUE
258
+ read_num(ParseInfo pi) {
259
+ int64_t n = 0;
260
+ long a = 0;
261
+ long div = 1;
262
+ long e = 0;
263
+ int neg = 0;
264
+ int eneg = 0;
265
+
266
+ if ('-' == *pi->s) {
267
+ pi->s++;
268
+ neg = 1;
269
+ } else if ('+' == *pi->s) {
270
+ pi->s++;
271
+ }
272
+ for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
273
+ n = n * 10 + (*pi->s - '0');
274
+ }
275
+ if ('.' == *pi->s) {
276
+ pi->s++;
277
+ for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
278
+ a = a * 10 + (*pi->s - '0');
279
+ div *= 10;
280
+ }
281
+ }
282
+ if ('e' == *pi->s || 'E' == *pi->s) {
283
+ pi->s++;
284
+ if ('-' == *pi->s) {
285
+ pi->s++;
286
+ eneg = 1;
287
+ } else if ('+' == *pi->s) {
288
+ pi->s++;
289
+ }
290
+ for (; '0' <= *pi->s && *pi->s <= '9'; pi->s++) {
291
+ e = e * 10 + (*pi->s - '0');
292
+ }
293
+ }
294
+ if (neg) {
295
+ n = -n;
296
+ }
297
+ if (0 == e && 0 == a && 1 == div) {
298
+ return LONG2NUM(n);
299
+ } else {
300
+ double d = (double)n + (double)a / (double)div;
301
+
302
+ if (0 != e) {
303
+ if (eneg) {
304
+ e = -e;
305
+ }
306
+ d *= pow(10.0, e);
307
+ }
308
+ return DBL2NUM(d);
309
+ }
310
+ }
311
+
312
+ static VALUE
313
+ read_true(ParseInfo pi) {
314
+ pi->s++;
315
+ if ('r' != *pi->s || 'u' != *(pi->s + 1) || 'e' != *(pi->s + 2)) {
316
+ raise_error("invalid format, expected 'true'", pi->str, pi->s);
317
+ }
318
+ pi->s += 3;
319
+
320
+ return Qtrue;
321
+ }
322
+
323
+ static VALUE
324
+ read_false(ParseInfo pi) {
325
+ pi->s++;
326
+ if ('a' != *pi->s || 'l' != *(pi->s + 1) || 's' != *(pi->s + 2) || 'e' != *(pi->s + 3)) {
327
+ raise_error("invalid format, expected 'false'", pi->str, pi->s);
328
+ }
329
+ pi->s += 4;
330
+
331
+ return Qfalse;
332
+ }
333
+
334
+ static VALUE
335
+ read_nil(ParseInfo pi) {
336
+ pi->s++;
337
+ if ('u' != *pi->s || 'l' != *(pi->s + 1) || 'l' != *(pi->s + 2)) {
338
+ raise_error("invalid format, expected 'nil'", pi->str, pi->s);
339
+ }
340
+ pi->s += 3;
341
+
342
+ return Qnil;
343
+ }
344
+
345
+ static char
346
+ read_hex(ParseInfo pi, char *h) {
347
+ uint8_t b = 0;
348
+
349
+ if ('0' <= *h && *h <= '9') {
350
+ b = *h - '0';
351
+ } else if ('A' <= *h && *h <= 'F') {
352
+ b = *h - 'A' + 10;
353
+ } else if ('a' <= *h && *h <= 'f') {
354
+ b = *h - 'a' + 10;
355
+ } else {
356
+ pi->s = h;
357
+ raise_error("invalid hex character", pi->str, pi->s);
358
+ }
359
+ h++;
360
+ b = b << 4;
361
+ if ('0' <= *h && *h <= '9') {
362
+ b += *h - '0';
363
+ } else if ('A' <= *h && *h <= 'F') {
364
+ b += *h - 'A' + 10;
365
+ } else if ('a' <= *h && *h <= 'f') {
366
+ b += *h - 'a' + 10;
367
+ } else {
368
+ pi->s = h;
369
+ raise_error("invalid hex character", pi->str, pi->s);
370
+ }
371
+ return (char)b;
372
+ }
373
+
374
+ /* Assume the value starts immediately and goes until the quote character is
375
+ * reached again. Do not read the character after the terminating quote.
376
+ */
377
+ static char*
378
+ read_quoted_value(ParseInfo pi) {
379
+ char *value = 0;
380
+ char *h = pi->s; // head
381
+ char *t = h; // tail
382
+
383
+ h++; // skip quote character
384
+ t++;
385
+ value = h;
386
+ // TBD can whole string be read in and then eval-ed by ruby of there is a special character
387
+ for (; '"' != *h; h++, t++) {
388
+ if ('\0' == *h) {
389
+ pi->s = h;
390
+ raise_error("quoted string not terminated", pi->str, pi->s);
391
+ } else if ('\\' == *h) {
392
+ h++;
393
+ switch (*h) {
394
+ case 'n': *t = '\n'; break;
395
+ case 'r': *t = '\r'; break;
396
+ case 't': *t = '\t'; break;
397
+ case 'f': *t = '\f'; break;
398
+ case 'b': *t = '\b'; break;
399
+ case '"': *t = '"'; break;
400
+ case '/': *t = '/'; break;
401
+ case '\\': *t = '\\'; break;
402
+ case 'u':
403
+ // TBD if first character is 00 then skip it
404
+ h++;
405
+ *t = read_hex(pi, h);
406
+ h += 2;
407
+ if ('\0' != *t) {
408
+ t++;
409
+ }
410
+ *t = read_hex(pi, h);
411
+ h++;
412
+ break;
413
+ default:
414
+ pi->s = h;
415
+ raise_error("invalid escaped character", pi->str, pi->s);
416
+ break;
417
+ }
418
+ } else if (t != h) {
419
+ *t = *h;
420
+ }
421
+ }
422
+ *t = '\0'; // terminate value
423
+ pi->s = h + 1;
424
+
425
+ return value;
426
+ }
@@ -0,0 +1,157 @@
1
+ /* oj.c
2
+ * Copyright (c) 2011, 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 <errno.h>
33
+ #include <stdio.h>
34
+ #include <string.h>
35
+
36
+ #include "ruby.h"
37
+ #include "oj.h"
38
+
39
+ struct _Options default_options = {
40
+ { '\0' }, // encoding
41
+ 2, // indent
42
+ 0, // trace
43
+ No, // circular
44
+ NoMode, // mode
45
+ // StrictEffort, // effort
46
+ };
47
+
48
+ void Init_oj();
49
+
50
+ VALUE Oj = Qnil;
51
+
52
+ static VALUE
53
+ load(char *json, int argc, VALUE *argv, VALUE self) {
54
+ VALUE obj;
55
+
56
+ // TBD other options like obj mode
57
+ obj = parse(json, 0);
58
+ free(json);
59
+
60
+ return obj;
61
+ }
62
+
63
+ /* call-seq: load(xml, options) => Hash, Array, String, Fixnum, Float, true, false, or nil
64
+ *
65
+ * Parses a JSON document String into a Hash, Array, String, Fixnum, Float,
66
+ * true, false, or nil Raises an exception if the JSON is * malformed or the
67
+ * classes specified are not valid.
68
+ * @param [String] json JSON String
69
+ * @param [Hash] options load options
70
+ */
71
+ static VALUE
72
+ load_str(int argc, VALUE *argv, VALUE self) {
73
+ char *json;
74
+
75
+ Check_Type(*argv, T_STRING);
76
+ // the xml string gets modified so make a copy of it
77
+ json = strdup(StringValuePtr(*argv));
78
+
79
+ return load(json, argc - 1, argv + 1, self);
80
+ }
81
+
82
+ static VALUE
83
+ load_file(int argc, VALUE *argv, VALUE self) {
84
+ char *path;
85
+ char *json;
86
+ FILE *f;
87
+ unsigned long len;
88
+
89
+ Check_Type(*argv, T_STRING);
90
+ path = StringValuePtr(*argv);
91
+ if (0 == (f = fopen(path, "r"))) {
92
+ rb_raise(rb_eIOError, "%s\n", strerror(errno));
93
+ }
94
+ fseek(f, 0, SEEK_END);
95
+ len = ftell(f);
96
+ if (0 == (json = malloc(len + 1))) {
97
+ fclose(f);
98
+ rb_raise(rb_eNoMemError, "Could not allocate memory for %ld byte file.\n", len);
99
+ }
100
+ fseek(f, 0, SEEK_SET);
101
+ if (len != fread(json, 1, len, f)) {
102
+ fclose(f);
103
+ rb_raise(rb_eLoadError, "Failed to read %ld bytes from %s.\n", len, path);
104
+ }
105
+ fclose(f);
106
+ json[len] = '\0';
107
+
108
+ return load(json, argc - 1, argv + 1, self);
109
+ }
110
+
111
+ static VALUE
112
+ dump(int argc, VALUE *argv, VALUE self) {
113
+ char *json;
114
+ struct _Options copts = default_options;
115
+ VALUE rstr;
116
+
117
+ if (2 == argc) {
118
+ //parse_dump_options(argv[1], &copts);
119
+ }
120
+ if (0 == (json = write_obj_to_str(*argv, &copts))) {
121
+ rb_raise(rb_eNoMemError, "Not enough memory.\n");
122
+ }
123
+ rstr = rb_str_new2(json);
124
+ #ifdef ENCODING_INLINE_MAX
125
+ if ('\0' != *copts.encoding) {
126
+ rb_enc_associate(rstr, rb_enc_find(copts.encoding));
127
+ }
128
+ #endif
129
+ free(json);
130
+
131
+ return rstr;
132
+ }
133
+
134
+ void Init_oj() {
135
+
136
+ Oj = rb_define_module("Oj");
137
+
138
+ rb_define_module_function(Oj, "load", load_str, -1);
139
+ rb_define_module_function(Oj, "load_file", load_file, -1);
140
+ rb_define_module_function(Oj, "dump", dump, -1);
141
+ }
142
+
143
+ void
144
+ _raise_error(const char *msg, const char *xml, const char *current, const char* file, int line) {
145
+ int xline = 1;
146
+ int col = 1;
147
+
148
+ for (; xml < current && '\n' != *current; current--) {
149
+ col++;
150
+ }
151
+ for (; xml < current; current--) {
152
+ if ('\n' == *current) {
153
+ xline++;
154
+ }
155
+ }
156
+ rb_raise(rb_eSyntaxError, "%s at line %d, column %d [%s:%d]\n", msg, xline, col, file, line);
157
+ }
@@ -0,0 +1,98 @@
1
+ /* oj.h
2
+ * Copyright (c) 2011, 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
+ #ifndef __OJ_H__
32
+ #define __OJ_H__
33
+
34
+ #if defined(__cplusplus)
35
+ extern "C" {
36
+ #if 0
37
+ } /* satisfy cc-mode */
38
+ #endif
39
+ #endif
40
+
41
+ #include "ruby.h"
42
+ #ifdef HAVE_RUBY_ENCODING_H
43
+ // HAVE_RUBY_ENCODING_H defined for Ruby 1.9
44
+ #include "ruby/encoding.h"
45
+ #endif
46
+
47
+ #ifdef JRUBY
48
+ #define NO_RSTRUCT 1
49
+ #endif
50
+
51
+ #if (defined RBX_Qnil && !defined RUBINIUS)
52
+ #define RUBINIUS
53
+ #endif
54
+
55
+ #ifdef RUBINIUS
56
+ #undef T_RATIONAL
57
+ #undef T_COMPLEX
58
+ #define NO_RSTRUCT 1
59
+ #endif
60
+
61
+ #define raise_error(msg, xml, current) _raise_error(msg, xml, current, __FILE__, __LINE__)
62
+
63
+ typedef enum {
64
+ Yes = 'y',
65
+ No = 'n',
66
+ NotSet = 0
67
+ } YesNo;
68
+
69
+ typedef enum {
70
+ ObjMode = 'o',
71
+ GenMode = 'g',
72
+ NoMode = 0
73
+ } LoadMode;
74
+
75
+ typedef struct _Options {
76
+ char encoding[64]; // encoding, stored in the option to avoid GC invalidation in default values
77
+ int indent; // indention for dump, default 2
78
+ int trace; // trace level
79
+ char circular; // YesNo
80
+ char mode; // LoadMode
81
+ char effort; // Effort
82
+ } *Options;
83
+
84
+ extern VALUE parse(char *json, int trace);
85
+ extern char* write_obj_to_str(VALUE obj, Options copts);
86
+
87
+ extern void _raise_error(const char *msg, const char *xml, const char *current, const char* file, int line);
88
+
89
+
90
+ extern VALUE Oj;
91
+
92
+ #if defined(__cplusplus)
93
+ #if 0
94
+ { /* satisfy cc-mode */
95
+ #endif
96
+ } /* extern "C" { */
97
+ #endif
98
+ #endif /* __OJ_H__ */
@@ -0,0 +1,36 @@
1
+ # Copyright (c) 2011, Peter Ohler<br>
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # - Redistributions of source code must retain the above copyright notice, this
8
+ # list of conditions and the following disclaimer.
9
+ #
10
+ # - Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ #
14
+ # - Neither the name of Peter Ohler nor the names of its contributors may be
15
+ # used to endorse or promote products derived from this software without
16
+ # specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ module Oj
30
+ private
31
+ @@keep = []
32
+ end
33
+
34
+ #require 'ox/version'
35
+
36
+ require 'oj/oj' # C extension
@@ -0,0 +1,5 @@
1
+
2
+ module Oj
3
+ # Current version of the module.
4
+ VERSION = '0.5'
5
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: oj
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.5'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Peter Ohler
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-19 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: ! "A fast JSON parser and object serializer that uses only standard C
15
+ lib.\n \nOptimized JSON (Oj), as the name implies was written to provide
16
+ speed optimized\nJSON handling. It was designed to be an alternative to Yajl and
17
+ other Ruby\nJSON parsers and as an alternative to Marshal for Object serialization. "
18
+ email: peter@ohler.com
19
+ executables: []
20
+ extensions:
21
+ - ext/oj/extconf.rb
22
+ extra_rdoc_files:
23
+ - README.md
24
+ files:
25
+ - lib/oj/version.rb
26
+ - lib/oj.rb
27
+ - ext/oj/extconf.rb
28
+ - ext/oj/oj.h
29
+ - ext/oj/dump.c
30
+ - ext/oj/load.c
31
+ - ext/oj/oj.c
32
+ - LICENSE
33
+ - README.md
34
+ homepage: https://github.com/ohler55/oj
35
+ licenses: []
36
+ post_install_message:
37
+ rdoc_options:
38
+ - --main
39
+ - README.md
40
+ require_paths:
41
+ - lib
42
+ - ext
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ requirements: []
56
+ rubyforge_project: oj
57
+ rubygems_version: 1.8.15
58
+ signing_key:
59
+ specification_version: 3
60
+ summary: A fast JSON parser and serializer.
61
+ test_files: []