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.
- data/CHANGELOG.rdoc +10 -0
- data/README.rdoc +25 -23
- data/Rakefile +11 -1
- data/VERSION.yml +2 -2
- data/benchmark/encode.rb +1 -1
- data/benchmark/encode_json_and_marshal.rb +1 -1
- data/benchmark/encode_json_and_yaml.rb +1 -1
- data/benchmark/parse.rb +1 -1
- data/benchmark/parse_json_and_marshal.rb +1 -1
- data/benchmark/parse_json_and_yaml.rb +1 -1
- data/benchmark/subjects/unicode.json +1 -3315
- data/ext/api/yajl_common.h +85 -0
- data/ext/api/yajl_gen.h +123 -0
- data/ext/api/yajl_parse.h +179 -0
- data/ext/extconf.rb +2 -8
- data/ext/yajl.c +128 -260
- data/ext/yajl_alloc.c +65 -0
- data/ext/yajl_alloc.h +50 -0
- data/ext/yajl_buf.c +119 -0
- data/ext/yajl_buf.h +73 -0
- data/ext/yajl_bytestack.h +85 -0
- data/ext/yajl_encode.c +179 -0
- data/ext/yajl_encode.h +44 -0
- data/ext/yajl_ext.c +283 -0
- data/ext/{yajl.h → yajl_ext.h} +2 -2
- data/ext/yajl_gen.c +295 -0
- data/ext/yajl_lex.c +737 -0
- data/ext/yajl_lex.h +133 -0
- data/ext/yajl_parser.c +445 -0
- data/ext/yajl_parser.h +79 -0
- data/lib/yajl/bzip2.rb +1 -1
- data/lib/yajl/deflate.rb +1 -1
- data/lib/yajl/gzip.rb +1 -1
- data/lib/yajl/http_stream.rb +1 -1
- data/lib/yajl.rb +1 -1
- data/spec/encoding/encoding_spec.rb +23 -0
- data/spec/http/{http.bzip2.dump → fixtures/http.bzip2.dump} +0 -0
- data/spec/http/{http.deflate.dump → fixtures/http.deflate.dump} +0 -0
- data/spec/http/{http.gzip.dump → fixtures/http.gzip.dump} +0 -0
- data/spec/http/{http.raw.dump → fixtures/http.raw.dump} +0 -0
- data/spec/http/http_spec.rb +98 -0
- data/spec/{active_support_spec.rb → parsing/active_support_spec.rb} +1 -1
- data/spec/{fixtures → parsing/fixtures}/fail.15.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail.16.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail.17.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail.26.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail11.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail12.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail13.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail14.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail19.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail20.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail21.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail22.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail23.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail24.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail25.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail27.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail28.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail3.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail4.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail5.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail6.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/fail9.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.array.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.codepoints_from_unicode_org.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.contacts.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.db100.xml.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.db1000.xml.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.dc_simple_with_comments.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.deep_arrays.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.difficult_json_c_test_case.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.difficult_json_c_test_case_with_comments.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.doubles.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.empty_array.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.empty_string.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.escaped_bulgarian.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.escaped_foobar.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.item.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.json-org-sample1.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.json-org-sample2.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.json-org-sample3.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.json-org-sample4-nows.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.json-org-sample4.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.json-org-sample5.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.map-spain.xml.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.ns-invoice100.xml.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.ns-soap.xml.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.numbers-fp-4k.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.numbers-fp-64k.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.numbers-int-4k.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.numbers-int-64k.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.twitter-search.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.twitter-search2.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.unicode.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass.yelp.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass1.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass2.json +0 -0
- data/spec/{fixtures → parsing/fixtures}/pass3.json +0 -0
- data/spec/{fixtures_spec.rb → parsing/fixtures_spec.rb} +1 -1
- data/spec/{one_off_spec.rb → parsing/one_off_spec.rb} +1 -1
- data/yajl-ruby.gemspec +91 -72
- metadata +91 -71
- 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
|
+
}
|
data/ext/{yajl.h → yajl_ext.h}
RENAMED