brianmario-yajl-ruby 0.4.6 → 0.4.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. data/CHANGELOG.rdoc +10 -0
  2. data/README.rdoc +25 -23
  3. data/Rakefile +11 -1
  4. data/VERSION.yml +2 -2
  5. data/benchmark/encode.rb +1 -1
  6. data/benchmark/encode_json_and_marshal.rb +1 -1
  7. data/benchmark/encode_json_and_yaml.rb +1 -1
  8. data/benchmark/parse.rb +1 -1
  9. data/benchmark/parse_json_and_marshal.rb +1 -1
  10. data/benchmark/parse_json_and_yaml.rb +1 -1
  11. data/benchmark/subjects/unicode.json +1 -3315
  12. data/ext/api/yajl_common.h +85 -0
  13. data/ext/api/yajl_gen.h +123 -0
  14. data/ext/api/yajl_parse.h +179 -0
  15. data/ext/extconf.rb +2 -8
  16. data/ext/yajl.c +128 -260
  17. data/ext/yajl_alloc.c +65 -0
  18. data/ext/yajl_alloc.h +50 -0
  19. data/ext/yajl_buf.c +119 -0
  20. data/ext/yajl_buf.h +73 -0
  21. data/ext/yajl_bytestack.h +85 -0
  22. data/ext/yajl_encode.c +179 -0
  23. data/ext/yajl_encode.h +44 -0
  24. data/ext/yajl_ext.c +283 -0
  25. data/ext/{yajl.h → yajl_ext.h} +2 -2
  26. data/ext/yajl_gen.c +295 -0
  27. data/ext/yajl_lex.c +737 -0
  28. data/ext/yajl_lex.h +133 -0
  29. data/ext/yajl_parser.c +445 -0
  30. data/ext/yajl_parser.h +79 -0
  31. data/lib/yajl/bzip2.rb +1 -1
  32. data/lib/yajl/deflate.rb +1 -1
  33. data/lib/yajl/gzip.rb +1 -1
  34. data/lib/yajl/http_stream.rb +1 -1
  35. data/lib/yajl.rb +1 -1
  36. data/spec/encoding/encoding_spec.rb +23 -0
  37. data/spec/http/{http.bzip2.dump → fixtures/http.bzip2.dump} +0 -0
  38. data/spec/http/{http.deflate.dump → fixtures/http.deflate.dump} +0 -0
  39. data/spec/http/{http.gzip.dump → fixtures/http.gzip.dump} +0 -0
  40. data/spec/http/{http.raw.dump → fixtures/http.raw.dump} +0 -0
  41. data/spec/http/http_spec.rb +98 -0
  42. data/spec/{active_support_spec.rb → parsing/active_support_spec.rb} +1 -1
  43. data/spec/{fixtures → parsing/fixtures}/fail.15.json +0 -0
  44. data/spec/{fixtures → parsing/fixtures}/fail.16.json +0 -0
  45. data/spec/{fixtures → parsing/fixtures}/fail.17.json +0 -0
  46. data/spec/{fixtures → parsing/fixtures}/fail.26.json +0 -0
  47. data/spec/{fixtures → parsing/fixtures}/fail11.json +0 -0
  48. data/spec/{fixtures → parsing/fixtures}/fail12.json +0 -0
  49. data/spec/{fixtures → parsing/fixtures}/fail13.json +0 -0
  50. data/spec/{fixtures → parsing/fixtures}/fail14.json +0 -0
  51. data/spec/{fixtures → parsing/fixtures}/fail19.json +0 -0
  52. data/spec/{fixtures → parsing/fixtures}/fail20.json +0 -0
  53. data/spec/{fixtures → parsing/fixtures}/fail21.json +0 -0
  54. data/spec/{fixtures → parsing/fixtures}/fail22.json +0 -0
  55. data/spec/{fixtures → parsing/fixtures}/fail23.json +0 -0
  56. data/spec/{fixtures → parsing/fixtures}/fail24.json +0 -0
  57. data/spec/{fixtures → parsing/fixtures}/fail25.json +0 -0
  58. data/spec/{fixtures → parsing/fixtures}/fail27.json +0 -0
  59. data/spec/{fixtures → parsing/fixtures}/fail28.json +0 -0
  60. data/spec/{fixtures → parsing/fixtures}/fail3.json +0 -0
  61. data/spec/{fixtures → parsing/fixtures}/fail4.json +0 -0
  62. data/spec/{fixtures → parsing/fixtures}/fail5.json +0 -0
  63. data/spec/{fixtures → parsing/fixtures}/fail6.json +0 -0
  64. data/spec/{fixtures → parsing/fixtures}/fail9.json +0 -0
  65. data/spec/{fixtures → parsing/fixtures}/pass.array.json +0 -0
  66. data/spec/{fixtures → parsing/fixtures}/pass.codepoints_from_unicode_org.json +0 -0
  67. data/spec/{fixtures → parsing/fixtures}/pass.contacts.json +0 -0
  68. data/spec/{fixtures → parsing/fixtures}/pass.db100.xml.json +0 -0
  69. data/spec/{fixtures → parsing/fixtures}/pass.db1000.xml.json +0 -0
  70. data/spec/{fixtures → parsing/fixtures}/pass.dc_simple_with_comments.json +0 -0
  71. data/spec/{fixtures → parsing/fixtures}/pass.deep_arrays.json +0 -0
  72. data/spec/{fixtures → parsing/fixtures}/pass.difficult_json_c_test_case.json +0 -0
  73. data/spec/{fixtures → parsing/fixtures}/pass.difficult_json_c_test_case_with_comments.json +0 -0
  74. data/spec/{fixtures → parsing/fixtures}/pass.doubles.json +0 -0
  75. data/spec/{fixtures → parsing/fixtures}/pass.empty_array.json +0 -0
  76. data/spec/{fixtures → parsing/fixtures}/pass.empty_string.json +0 -0
  77. data/spec/{fixtures → parsing/fixtures}/pass.escaped_bulgarian.json +0 -0
  78. data/spec/{fixtures → parsing/fixtures}/pass.escaped_foobar.json +0 -0
  79. data/spec/{fixtures → parsing/fixtures}/pass.item.json +0 -0
  80. data/spec/{fixtures → parsing/fixtures}/pass.json-org-sample1.json +0 -0
  81. data/spec/{fixtures → parsing/fixtures}/pass.json-org-sample2.json +0 -0
  82. data/spec/{fixtures → parsing/fixtures}/pass.json-org-sample3.json +0 -0
  83. data/spec/{fixtures → parsing/fixtures}/pass.json-org-sample4-nows.json +0 -0
  84. data/spec/{fixtures → parsing/fixtures}/pass.json-org-sample4.json +0 -0
  85. data/spec/{fixtures → parsing/fixtures}/pass.json-org-sample5.json +0 -0
  86. data/spec/{fixtures → parsing/fixtures}/pass.map-spain.xml.json +0 -0
  87. data/spec/{fixtures → parsing/fixtures}/pass.ns-invoice100.xml.json +0 -0
  88. data/spec/{fixtures → parsing/fixtures}/pass.ns-soap.xml.json +0 -0
  89. data/spec/{fixtures → parsing/fixtures}/pass.numbers-fp-4k.json +0 -0
  90. data/spec/{fixtures → parsing/fixtures}/pass.numbers-fp-64k.json +0 -0
  91. data/spec/{fixtures → parsing/fixtures}/pass.numbers-int-4k.json +0 -0
  92. data/spec/{fixtures → parsing/fixtures}/pass.numbers-int-64k.json +0 -0
  93. data/spec/{fixtures → parsing/fixtures}/pass.twitter-search.json +0 -0
  94. data/spec/{fixtures → parsing/fixtures}/pass.twitter-search2.json +0 -0
  95. data/spec/{fixtures → parsing/fixtures}/pass.unicode.json +0 -0
  96. data/spec/{fixtures → parsing/fixtures}/pass.yelp.json +0 -0
  97. data/spec/{fixtures → parsing/fixtures}/pass1.json +0 -0
  98. data/spec/{fixtures → parsing/fixtures}/pass2.json +0 -0
  99. data/spec/{fixtures → parsing/fixtures}/pass3.json +0 -0
  100. data/spec/{fixtures_spec.rb → parsing/fixtures_spec.rb} +1 -1
  101. data/spec/{one_off_spec.rb → parsing/one_off_spec.rb} +1 -1
  102. data/yajl-ruby.gemspec +91 -72
  103. metadata +91 -71
  104. data/benchmark/subjects/yelp.json +0 -1
data/ext/yajl_buf.h ADDED
@@ -0,0 +1,73 @@
1
+ /*
2
+ * Copyright 2007-2009, Lloyd Hilaiel.
3
+ *
4
+ * Redistribution and use in source and binary forms, with or without
5
+ * modification, are permitted provided that the following conditions are
6
+ * met:
7
+ *
8
+ * 1. Redistributions of source code must retain the above copyright
9
+ * notice, this list of conditions and the following disclaimer.
10
+ *
11
+ * 2. Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in
13
+ * the documentation and/or other materials provided with the
14
+ * distribution.
15
+ *
16
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
17
+ * contributors may be used to endorse or promote products derived
18
+ * from this software without specific prior written permission.
19
+ *
20
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
24
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ * POSSIBILITY OF SUCH DAMAGE.
31
+ */
32
+
33
+ #ifndef __YAJL_BUF_H__
34
+ #define __YAJL_BUF_H__
35
+
36
+ #include "api/yajl_common.h"
37
+ #include "yajl_alloc.h"
38
+
39
+ /*
40
+ * Implementation/performance notes. If this were moved to a header
41
+ * only implementation using #define's where possible we might be
42
+ * able to sqeeze a little performance out of the guy by killing function
43
+ * call overhead. YMMV.
44
+ */
45
+
46
+ /**
47
+ * yajl_buf is a buffer with exponential growth. the buffer ensures that
48
+ * you are always null padded.
49
+ */
50
+ typedef struct yajl_buf_t * yajl_buf;
51
+
52
+ /* allocate a new buffer */
53
+ yajl_buf yajl_buf_alloc(yajl_alloc_funcs * alloc);
54
+
55
+ /* free the buffer */
56
+ void yajl_buf_free(yajl_buf buf);
57
+
58
+ /* append a number of bytes to the buffer */
59
+ void yajl_buf_append(yajl_buf buf, const void * data, unsigned int len);
60
+
61
+ /* empty the buffer */
62
+ void yajl_buf_clear(yajl_buf buf);
63
+
64
+ /* get a pointer to the beginning of the buffer */
65
+ const unsigned char * yajl_buf_data(yajl_buf buf);
66
+
67
+ /* get the length of the buffer */
68
+ unsigned int yajl_buf_len(yajl_buf buf);
69
+
70
+ /* truncate the buffer */
71
+ void yajl_buf_truncate(yajl_buf buf, unsigned int len);
72
+
73
+ #endif
@@ -0,0 +1,85 @@
1
+ /*
2
+ * Copyright 2009, Lloyd Hilaiel.
3
+ *
4
+ * Redistribution and use in source and binary forms, with or without
5
+ * modification, are permitted provided that the following conditions are
6
+ * met:
7
+ *
8
+ * 1. Redistributions of source code must retain the above copyright
9
+ * notice, this list of conditions and the following disclaimer.
10
+ *
11
+ * 2. Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in
13
+ * the documentation and/or other materials provided with the
14
+ * distribution.
15
+ *
16
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
17
+ * contributors may be used to endorse or promote products derived
18
+ * from this software without specific prior written permission.
19
+ *
20
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
24
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ * POSSIBILITY OF SUCH DAMAGE.
31
+ */
32
+
33
+ /*
34
+ * A header only implementation of a simple stack of bytes, used in YAJL
35
+ * to maintain parse state.
36
+ */
37
+
38
+ #ifndef __YAJL_BYTESTACK_H__
39
+ #define __YAJL_BYTESTACK_H__
40
+
41
+ #include "api/yajl_common.h"
42
+
43
+ #define YAJL_BS_INC 128
44
+
45
+ typedef struct yajl_bytestack_t
46
+ {
47
+ unsigned char * stack;
48
+ unsigned int size;
49
+ unsigned int used;
50
+ yajl_alloc_funcs * yaf;
51
+ } yajl_bytestack;
52
+
53
+ /* initialize a bytestack */
54
+ #define yajl_bs_init(obs, _yaf) { \
55
+ (obs).stack = NULL; \
56
+ (obs).size = 0; \
57
+ (obs).used = 0; \
58
+ (obs).yaf = (_yaf); \
59
+ } \
60
+
61
+
62
+ /* initialize a bytestack */
63
+ #define yajl_bs_free(obs) \
64
+ if ((obs).stack) (obs).yaf->free((obs).yaf->ctx, (obs).stack);
65
+
66
+ #define yajl_bs_current(obs) \
67
+ (assert((obs).used > 0), (obs).stack[(obs).used - 1])
68
+
69
+ #define yajl_bs_push(obs, byte) { \
70
+ if (((obs).size - (obs).used) == 0) { \
71
+ (obs).size += YAJL_BS_INC; \
72
+ (obs).stack = (obs).yaf->realloc((obs).yaf->ctx,\
73
+ (void *) (obs).stack, (obs).size);\
74
+ } \
75
+ (obs).stack[((obs).used)++] = (byte); \
76
+ }
77
+
78
+ /* removes the top item of the stack, returns nothing */
79
+ #define yajl_bs_pop(obs) { ((obs).used)--; }
80
+
81
+ #define yajl_bs_set(obs, byte) \
82
+ (obs).stack[((obs).used) - 1] = (byte);
83
+
84
+
85
+ #endif
data/ext/yajl_encode.c ADDED
@@ -0,0 +1,179 @@
1
+ /*
2
+ * Copyright 2007-2009, Lloyd Hilaiel.
3
+ *
4
+ * Redistribution and use in source and binary forms, with or without
5
+ * modification, are permitted provided that the following conditions are
6
+ * met:
7
+ *
8
+ * 1. Redistributions of source code must retain the above copyright
9
+ * notice, this list of conditions and the following disclaimer.
10
+ *
11
+ * 2. Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in
13
+ * the documentation and/or other materials provided with the
14
+ * distribution.
15
+ *
16
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
17
+ * contributors may be used to endorse or promote products derived
18
+ * from this software without specific prior written permission.
19
+ *
20
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
24
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ * POSSIBILITY OF SUCH DAMAGE.
31
+ */
32
+
33
+ #include "yajl_encode.h"
34
+
35
+ #include <assert.h>
36
+ #include <stdlib.h>
37
+ #include <string.h>
38
+ #include <stdio.h>
39
+
40
+ static void CharToHex(unsigned char c, char * hexBuf)
41
+ {
42
+ const char * hexchar = "0123456789ABCDEF";
43
+ hexBuf[0] = hexchar[c >> 4];
44
+ hexBuf[1] = hexchar[c & 0x0F];
45
+ }
46
+
47
+ void
48
+ yajl_string_encode(yajl_buf buf, const unsigned char * str,
49
+ unsigned int len)
50
+ {
51
+ unsigned int beg = 0;
52
+ unsigned int end = 0;
53
+ char hexBuf[7];
54
+ hexBuf[0] = '\\'; hexBuf[1] = 'u'; hexBuf[2] = '0'; hexBuf[3] = '0';
55
+ hexBuf[6] = 0;
56
+
57
+ while (end < len) {
58
+ const char * escaped = NULL;
59
+ switch (str[end]) {
60
+ case '\r': escaped = "\\r"; break;
61
+ case '\n': escaped = "\\n"; break;
62
+ case '\\': escaped = "\\\\"; break;
63
+ /* case '/': escaped = "\\/"; break; */
64
+ case '"': escaped = "\\\""; break;
65
+ case '\f': escaped = "\\f"; break;
66
+ case '\b': escaped = "\\b"; break;
67
+ case '\t': escaped = "\\t"; break;
68
+ default:
69
+ if ((unsigned char) str[end] < 32) {
70
+ CharToHex(str[end], hexBuf + 4);
71
+ escaped = hexBuf;
72
+ }
73
+ break;
74
+ }
75
+ if (escaped != NULL) {
76
+ yajl_buf_append(buf, str + beg, end - beg);
77
+ yajl_buf_append(buf, escaped, strlen(escaped));
78
+ beg = ++end;
79
+ } else {
80
+ ++end;
81
+ }
82
+ }
83
+ yajl_buf_append(buf, str + beg, end - beg);
84
+ }
85
+
86
+ static void hexToDigit(unsigned int * val, const unsigned char * hex)
87
+ {
88
+ unsigned int i;
89
+ for (i=0;i<4;i++) {
90
+ unsigned char c = hex[i];
91
+ if (c >= 'A') c = (c & ~0x20) - 7;
92
+ c -= '0';
93
+ assert(!(c & 0xF0));
94
+ *val = (*val << 4) | c;
95
+ }
96
+ }
97
+
98
+ static void Utf32toUtf8(unsigned int codepoint, char * utf8Buf)
99
+ {
100
+ if (codepoint < 0x80) {
101
+ utf8Buf[0] = (char) codepoint;
102
+ utf8Buf[1] = 0;
103
+ } else if (codepoint < 0x0800) {
104
+ utf8Buf[0] = (char) ((codepoint >> 6) | 0xC0);
105
+ utf8Buf[1] = (char) ((codepoint & 0x3F) | 0x80);
106
+ utf8Buf[2] = 0;
107
+ } else if (codepoint < 0x10000) {
108
+ utf8Buf[0] = (char) ((codepoint >> 12) | 0xE0);
109
+ utf8Buf[1] = (char) (((codepoint >> 6) & 0x3F) | 0x80);
110
+ utf8Buf[2] = (char) ((codepoint & 0x3F) | 0x80);
111
+ utf8Buf[3] = 0;
112
+ } else if (codepoint < 0x200000) {
113
+ utf8Buf[0] =(char)((codepoint >> 18) | 0xF0);
114
+ utf8Buf[1] =(char)(((codepoint >> 12) & 0x3F) | 0x80);
115
+ utf8Buf[2] =(char)(((codepoint >> 6) & 0x3F) | 0x80);
116
+ utf8Buf[3] =(char)((codepoint & 0x3F) | 0x80);
117
+ utf8Buf[4] = 0;
118
+ } else {
119
+ utf8Buf[0] = '?';
120
+ utf8Buf[1] = 0;
121
+ }
122
+ }
123
+
124
+ void yajl_string_decode(yajl_buf buf, const unsigned char * str,
125
+ unsigned int len)
126
+ {
127
+ unsigned int beg = 0;
128
+ unsigned int end = 0;
129
+
130
+ while (end < len) {
131
+ if (str[end] == '\\') {
132
+ char utf8Buf[5];
133
+ const char * unescaped = "?";
134
+ yajl_buf_append(buf, str + beg, end - beg);
135
+ switch (str[++end]) {
136
+ case 'r': unescaped = "\r"; break;
137
+ case 'n': unescaped = "\n"; break;
138
+ case '\\': unescaped = "\\"; break;
139
+ case '/': unescaped = "/"; break;
140
+ case '"': unescaped = "\""; break;
141
+ case 'f': unescaped = "\f"; break;
142
+ case 'b': unescaped = "\b"; break;
143
+ case 't': unescaped = "\t"; break;
144
+ case 'u': {
145
+ unsigned int codepoint = 0;
146
+ hexToDigit(&codepoint, str + ++end);
147
+ end+=3;
148
+ /* check if this is a surrogate */
149
+ if ((codepoint & 0xFC00) == 0xD800) {
150
+ end++;
151
+ if (str[end] == '\\' && str[end + 1] == 'u') {
152
+ unsigned int surrogate = 0;
153
+ hexToDigit(&surrogate, str + end + 2);
154
+ codepoint =
155
+ (((codepoint & 0x3F) << 10) |
156
+ ((((codepoint >> 6) & 0xF) + 1) << 16) |
157
+ (surrogate & 0x3FF));
158
+ end += 5;
159
+ } else {
160
+ unescaped = "?";
161
+ break;
162
+ }
163
+ }
164
+
165
+ Utf32toUtf8(codepoint, utf8Buf);
166
+ unescaped = utf8Buf;
167
+ break;
168
+ }
169
+ default:
170
+ assert("this should never happen" == NULL);
171
+ }
172
+ yajl_buf_append(buf, unescaped, strlen(unescaped));
173
+ beg = ++end;
174
+ } else {
175
+ end++;
176
+ }
177
+ }
178
+ yajl_buf_append(buf, str + beg, end - beg);
179
+ }
data/ext/yajl_encode.h ADDED
@@ -0,0 +1,44 @@
1
+ /*
2
+ * Copyright 2007-2009, Lloyd Hilaiel.
3
+ *
4
+ * Redistribution and use in source and binary forms, with or without
5
+ * modification, are permitted provided that the following conditions are
6
+ * met:
7
+ *
8
+ * 1. Redistributions of source code must retain the above copyright
9
+ * notice, this list of conditions and the following disclaimer.
10
+ *
11
+ * 2. Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in
13
+ * the documentation and/or other materials provided with the
14
+ * distribution.
15
+ *
16
+ * 3. Neither the name of Lloyd Hilaiel nor the names of its
17
+ * contributors may be used to endorse or promote products derived
18
+ * from this software without specific prior written permission.
19
+ *
20
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
24
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30
+ * POSSIBILITY OF SUCH DAMAGE.
31
+ */
32
+
33
+ #ifndef __YAJL_ENCODE_H__
34
+ #define __YAJL_ENCODE_H__
35
+
36
+ #include "yajl_buf.h"
37
+
38
+ void yajl_string_encode(yajl_buf buf, const unsigned char * str,
39
+ unsigned int length);
40
+
41
+ void yajl_string_decode(yajl_buf buf, const unsigned char * str,
42
+ unsigned int length);
43
+
44
+ #endif
data/ext/yajl_ext.c ADDED
@@ -0,0 +1,283 @@
1
+ #include "yajl_ext.h"
2
+
3
+ void check_and_fire_callback(void * ctx) {
4
+ yajl_status stat;
5
+
6
+ if (RARRAY_LEN((VALUE)ctx) == 1 && parse_complete_callback != Qnil) {
7
+ // parse any remaining buffered data
8
+ stat = yajl_parse_complete(chunkedParser);
9
+
10
+ rb_funcall(parse_complete_callback, intern_call, 1, rb_ary_pop((VALUE)ctx));
11
+ }
12
+ }
13
+
14
+ void set_static_value(void * ctx, VALUE val) {
15
+ VALUE len = RARRAY_LEN((VALUE)ctx);
16
+
17
+ if (len > 0) {
18
+ VALUE lastEntry = rb_ary_entry((VALUE)ctx, len-1);
19
+ VALUE hash;
20
+ switch (TYPE(lastEntry)) {
21
+ case T_ARRAY:
22
+ rb_ary_push(lastEntry, val);
23
+ if (TYPE(val) == T_HASH || TYPE(val) == T_ARRAY) {
24
+ rb_ary_push((VALUE)ctx, val);
25
+ }
26
+ break;
27
+ case T_HASH:
28
+ rb_hash_aset(lastEntry, val, Qnil);
29
+ rb_ary_push((VALUE)ctx, val);
30
+ break;
31
+ case T_STRING:
32
+ hash = rb_ary_entry((VALUE)ctx, len-2);
33
+ if (TYPE(hash) == T_HASH) {
34
+ rb_hash_aset(hash, lastEntry, val);
35
+ rb_ary_pop((VALUE)ctx);
36
+ if (TYPE(val) == T_HASH || TYPE(val) == T_ARRAY) {
37
+ rb_ary_push((VALUE)ctx, val);
38
+ }
39
+ }
40
+ break;
41
+ }
42
+ } else {
43
+ rb_ary_push((VALUE)ctx, val);
44
+ }
45
+ }
46
+
47
+ void encode_part(yajl_gen hand, VALUE obj, VALUE io) {
48
+ VALUE str, outBuff, otherObj;
49
+ int objLen;
50
+ int idx = 0;
51
+ const unsigned char * buffer;
52
+ unsigned int len;
53
+ yajl_gen_get_buf(hand, &buffer, &len);
54
+ outBuff = rb_str_new((const char *)buffer, len);
55
+ rb_io_write(io, outBuff);
56
+ yajl_gen_clear(hand);
57
+
58
+ switch (TYPE(obj)) {
59
+ case T_HASH:
60
+ yajl_gen_map_open(hand);
61
+
62
+ // TODO: itterate through keys in the hash
63
+ VALUE keys = rb_funcall(obj, intern_keys, 0);
64
+ VALUE entry;
65
+ for(idx=0; idx<RARRAY_LEN(keys); idx++) {
66
+ entry = rb_ary_entry(keys, idx);
67
+ // the key
68
+ encode_part(hand, entry, io);
69
+ // the value
70
+ encode_part(hand, rb_hash_aref(obj, entry), io);
71
+ }
72
+
73
+ yajl_gen_map_close(hand);
74
+ break;
75
+ case T_ARRAY:
76
+ yajl_gen_array_open(hand);
77
+ for(idx=0; idx<RARRAY_LEN(obj); idx++) {
78
+ otherObj = rb_ary_entry(obj, idx);
79
+ encode_part(hand, otherObj, io);
80
+ }
81
+ yajl_gen_array_close(hand);
82
+ break;
83
+ case T_NIL:
84
+ yajl_gen_null(hand);
85
+ break;
86
+ case T_TRUE:
87
+ yajl_gen_bool(hand, 1);
88
+ break;
89
+ case T_FALSE:
90
+ yajl_gen_bool(hand, 0);
91
+ break;
92
+ case T_FIXNUM:
93
+ case T_FLOAT:
94
+ case T_BIGNUM:
95
+ str = rb_funcall(obj, intern_to_s, 0);
96
+ objLen = RSTRING_LEN(str);
97
+ yajl_gen_number(hand, RSTRING_PTR(str), (unsigned int)objLen);
98
+ break;
99
+ default:
100
+ str = rb_funcall(obj, intern_to_s, 0);
101
+ objLen = RSTRING_LEN(str);
102
+ yajl_gen_string(hand, (const unsigned char *)RSTRING_PTR(str), (unsigned int)objLen);
103
+ break;
104
+ }
105
+ }
106
+
107
+ static int found_null(void * ctx) {
108
+ set_static_value(ctx, Qnil);
109
+ check_and_fire_callback(ctx);
110
+ return 1;
111
+ }
112
+
113
+ static int found_boolean(void * ctx, int boolean) {
114
+ set_static_value(ctx, boolean ? Qtrue : Qfalse);
115
+ check_and_fire_callback(ctx);
116
+ return 1;
117
+ }
118
+
119
+ static int found_number(void * ctx, const char * numberVal, unsigned int numberLen) {
120
+ VALUE subString = rb_str_new(numberVal, numberLen);
121
+ if (strstr(RSTRING_PTR(subString), ".") != NULL || strstr(RSTRING_PTR(subString), "e") != NULL || strstr(RSTRING_PTR(subString), "E") != NULL) {
122
+ set_static_value(ctx, rb_Float(subString));
123
+ } else {
124
+ set_static_value(ctx, rb_Integer(subString));
125
+ }
126
+ check_and_fire_callback(ctx);
127
+ return 1;
128
+ }
129
+
130
+ static int found_string(void * ctx, const unsigned char * stringVal, unsigned int stringLen) {
131
+ set_static_value(ctx, rb_str_new((const char *)stringVal, stringLen));
132
+ check_and_fire_callback(ctx);
133
+ return 1;
134
+ }
135
+
136
+ static int found_hash_key(void * ctx, const unsigned char * stringVal, unsigned int stringLen) {
137
+ set_static_value(ctx, rb_str_new((const char *)stringVal, stringLen));
138
+ return 1;
139
+ }
140
+
141
+ static int found_start_hash(void * ctx) {
142
+ set_static_value(ctx, rb_hash_new());
143
+ return 1;
144
+ }
145
+
146
+ static int found_end_hash(void * ctx) {
147
+ if (RARRAY_LEN((VALUE)ctx) > 1) {
148
+ rb_ary_pop((VALUE)ctx);
149
+ }
150
+ check_and_fire_callback(ctx);
151
+ return 1;
152
+ }
153
+
154
+ static int found_start_array(void * ctx) {
155
+ set_static_value(ctx, rb_ary_new());
156
+ return 1;
157
+ }
158
+
159
+ static int found_end_array(void * ctx) {
160
+ if (RARRAY_LEN((VALUE)ctx) > 1) {
161
+ rb_ary_pop((VALUE)ctx);
162
+ }
163
+ check_and_fire_callback(ctx);
164
+ return 1;
165
+ }
166
+
167
+ static VALUE t_setParseComplete(VALUE self, VALUE callback) {
168
+ parse_complete_callback = callback;
169
+ return Qnil;
170
+ }
171
+
172
+ static VALUE t_parseSome(VALUE self, VALUE string) {
173
+ yajl_status stat;
174
+
175
+ if (string == Qnil) {
176
+ rb_raise(cParseError, "%s", "Can't parse a nil string.");
177
+ return Qnil;
178
+ }
179
+
180
+ if (parse_complete_callback != Qnil) {
181
+ if (context == Qnil) {
182
+ context = rb_ary_new();
183
+ }
184
+ if (chunkedParser == NULL) {
185
+ // allocate our parser
186
+ chunkedParser = yajl_alloc(&callbacks, &cfg, NULL, (void *)context);
187
+ }
188
+
189
+ stat = yajl_parse(chunkedParser, (const unsigned char *)RSTRING_PTR(string), RSTRING_LEN(string));
190
+ if (stat != yajl_status_ok && stat != yajl_status_insufficient_data) {
191
+ unsigned char * str = yajl_get_error(chunkedParser, 1, (const unsigned char *)RSTRING_PTR(string), RSTRING_LEN(string));
192
+ rb_raise(cParseError, "%s", (const char *) str);
193
+ yajl_free_error(chunkedParser, str);
194
+ }
195
+ } else {
196
+ rb_raise(cParseError, "%s", "The on_parse_complete callback isn't setup, parsing useless.");
197
+ }
198
+
199
+ if (RARRAY_LEN(context) == 0) {
200
+ yajl_free(chunkedParser);
201
+ }
202
+
203
+ return Qnil;
204
+ }
205
+
206
+ static VALUE t_parse(VALUE self, VALUE io) {
207
+ yajl_status stat;
208
+ context = rb_ary_new();
209
+
210
+ // allocate our parser
211
+ streamParser = yajl_alloc(&callbacks, &cfg, NULL, (void *)context);
212
+
213
+ VALUE parsed = rb_str_new2("");
214
+ VALUE rbufsize = INT2FIX(readBufferSize);
215
+
216
+ // now parse from the IO
217
+ while (rb_funcall(io, intern_eof, 0) != Qtrue) {
218
+ rb_funcall(io, intern_io_read, 2, rbufsize, parsed);
219
+
220
+ stat = yajl_parse(streamParser, (const unsigned char *)RSTRING_PTR(parsed), RSTRING_LEN(parsed));
221
+
222
+ if (stat != yajl_status_ok && stat != yajl_status_insufficient_data) {
223
+ unsigned char * str = yajl_get_error(streamParser, 1, (const unsigned char *)RSTRING_PTR(parsed), RSTRING_LEN(parsed));
224
+ rb_raise(cParseError, "%s", (const char *) str);
225
+ yajl_free_error(streamParser, str);
226
+ break;
227
+ }
228
+ }
229
+
230
+ // parse any remaining buffered data
231
+ stat = yajl_parse_complete(streamParser);
232
+ yajl_free(streamParser);
233
+
234
+ if (parse_complete_callback != Qnil) {
235
+ check_and_fire_callback((void *)context);
236
+ return Qnil;
237
+ }
238
+
239
+ return rb_ary_pop(context);
240
+ }
241
+
242
+ static VALUE t_encode(VALUE self, VALUE obj, VALUE io) {
243
+ yajl_gen_config conf = {0, " "};
244
+ yajl_gen hand;
245
+ const unsigned char * buffer;
246
+ unsigned int len;
247
+ VALUE outBuff;
248
+
249
+ hand = yajl_gen_alloc(&conf, NULL);
250
+ encode_part(hand, obj, io);
251
+
252
+ // just make sure we output the remaining buffer
253
+ yajl_gen_get_buf(hand, &buffer, &len);
254
+ outBuff = rb_str_new((const char *)buffer, len);
255
+ rb_io_write(io, outBuff);
256
+
257
+ yajl_gen_clear(hand);
258
+ yajl_gen_free(hand);
259
+ return Qnil;
260
+ }
261
+
262
+ void Init_yajl_ext() {
263
+ mYajl = rb_define_module("Yajl");
264
+
265
+ mStream = rb_define_module_under(mYajl, "Stream");
266
+ rb_define_module_function(mStream, "parse", t_parse, 1);
267
+ rb_define_module_function(mStream, "encode", t_encode, 2);
268
+
269
+ mChunked = rb_define_module_under(mYajl, "Chunked");
270
+ rb_define_module_function(mChunked, "parse_some", t_parseSome, 1);
271
+ rb_define_module_function(mChunked, "<<", t_parseSome, 1);
272
+ rb_define_module_function(mChunked, "on_parse_complete=", t_setParseComplete, 1);
273
+
274
+ VALUE rb_cStandardError = rb_const_get(rb_cObject, rb_intern("StandardError"));
275
+ cParseError = rb_define_class_under(mYajl, "ParseError", rb_cStandardError);
276
+
277
+ intern_io_read = rb_intern("read");
278
+ intern_eof = rb_intern("eof?");
279
+ intern_respond_to = rb_intern("respond_to?");
280
+ intern_call = rb_intern("call");
281
+ intern_keys = rb_intern("keys");
282
+ intern_to_s = rb_intern("to_s");
283
+ }
@@ -1,5 +1,5 @@
1
- #include <yajl/yajl_parse.h>
2
- #include <yajl/yajl_gen.h>
1
+ #include "api/yajl_parse.h"
2
+ #include "api/yajl_gen.h"
3
3
  #include <ruby.h>
4
4
 
5
5
  #define READ_BUFSIZE 4096