yajl-ruby 1.3.1 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of yajl-ruby might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/.github/workflows/ci.yml +26 -0
- data/README.md +1 -1
- data/ext/yajl/api/yajl_common.h +6 -0
- data/ext/yajl/api/yajl_gen.h +7 -2
- data/ext/yajl/api/yajl_parse.h +3 -1
- data/ext/yajl/extconf.rb +6 -1
- data/ext/yajl/yajl.c +17 -1
- data/ext/yajl/yajl_buf.c +83 -2
- data/ext/yajl/yajl_buf.h +9 -0
- data/ext/yajl/yajl_bytestack.h +28 -11
- data/ext/yajl/yajl_encode.c +39 -3
- data/ext/yajl/yajl_ext.c +512 -31
- data/ext/yajl/yajl_ext.h +2 -2
- data/ext/yajl/yajl_gen.c +35 -1
- data/ext/yajl/yajl_lex.c +20 -10
- data/ext/yajl/yajl_lex.h +18 -16
- data/ext/yajl/yajl_parser.c +16 -2
- data/lib/yajl/version.rb +1 -1
- data/lib/yajl.rb +7 -0
- data/spec/encoding/encoding_spec.rb +26 -0
- data/spec/projection/project_file.rb +41 -0
- data/spec/projection/projection.rb +498 -0
- data/yajl-ruby.gemspec +5 -5
- metadata +37 -20
- data/.travis.yml +0 -9
data/ext/yajl/yajl_ext.h
CHANGED
@@ -53,10 +53,10 @@ static rb_encoding *utf8Encoding;
|
|
53
53
|
#define RARRAY_LEN(s) (RARRAY(s)->len)
|
54
54
|
#endif
|
55
55
|
|
56
|
-
static VALUE cParseError, cEncodeError, mYajl, cParser, cEncoder;
|
56
|
+
static VALUE cStandardError, cParseError, cEncodeError, mYajl, cParser, cProjector, cEncoder;
|
57
57
|
static ID intern_io_read, intern_call, intern_keys, intern_to_s,
|
58
58
|
intern_to_json, intern_has_key, intern_to_sym, intern_as_json;
|
59
|
-
static ID sym_allow_comments, sym_check_utf8, sym_pretty, sym_indent, sym_terminator, sym_symbolize_keys, sym_symbolize_names, sym_html_safe;
|
59
|
+
static ID sym_allow_comments, sym_check_utf8, sym_pretty, sym_indent, sym_terminator, sym_symbolize_keys, sym_symbolize_names, sym_html_safe, sym_entities;
|
60
60
|
|
61
61
|
#define GetParser(obj, sval) Data_Get_Struct(obj, yajl_parser_wrapper, sval);
|
62
62
|
#define GetEncoder(obj, sval) Data_Get_Struct(obj, yajl_encoder_wrapper, sval);
|
data/ext/yajl/yajl_gen.c
CHANGED
@@ -178,7 +178,7 @@ yajl_gen_free(yajl_gen g)
|
|
178
178
|
if (++(g->depth) >= YAJL_MAX_DEPTH) return yajl_max_depth_exceeded;
|
179
179
|
|
180
180
|
#define DECREMENT_DEPTH \
|
181
|
-
if (--(g->depth) >= YAJL_MAX_DEPTH) return
|
181
|
+
if (--(g->depth) >= YAJL_MAX_DEPTH) return yajl_depth_underflow;
|
182
182
|
|
183
183
|
#define APPENDED_ATOM \
|
184
184
|
switch (g->state[g->depth]) { \
|
@@ -230,6 +230,36 @@ yajl_gen_double(yajl_gen g, double number)
|
|
230
230
|
return yajl_gen_status_ok;
|
231
231
|
}
|
232
232
|
|
233
|
+
yajl_gen_status
|
234
|
+
yajl_gen_long(yajl_gen g, long val)
|
235
|
+
{
|
236
|
+
char buf[32], *b = buf + sizeof buf;
|
237
|
+
unsigned int len = 0;
|
238
|
+
unsigned long uval;
|
239
|
+
|
240
|
+
ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
|
241
|
+
|
242
|
+
if (val < 0) {
|
243
|
+
g->print(g->ctx, "-", 1);
|
244
|
+
// Avoid overflow. This shouldn't happen because FIXNUMs are 1 bit less
|
245
|
+
// than LONGs, but good to be safe.
|
246
|
+
uval = 1 + (unsigned long)(-(val + 1));
|
247
|
+
} else {
|
248
|
+
uval = val;
|
249
|
+
}
|
250
|
+
|
251
|
+
do {
|
252
|
+
*--b = "0123456789"[uval % 10];
|
253
|
+
uval /= 10;
|
254
|
+
len++;
|
255
|
+
} while(uval);
|
256
|
+
g->print(g->ctx, b, len);
|
257
|
+
|
258
|
+
APPENDED_ATOM;
|
259
|
+
FINAL_NEWLINE;
|
260
|
+
return yajl_gen_status_ok;
|
261
|
+
}
|
262
|
+
|
233
263
|
yajl_gen_status
|
234
264
|
yajl_gen_number(yajl_gen g, const char * s, unsigned int l)
|
235
265
|
{
|
@@ -332,6 +362,10 @@ yajl_gen_get_buf(yajl_gen g, const unsigned char ** buf,
|
|
332
362
|
unsigned int * len)
|
333
363
|
{
|
334
364
|
if (g->print != (yajl_print_t)&yajl_buf_append) return yajl_gen_no_buf;
|
365
|
+
yajl_buf_state buf_err = yajl_buf_err((yajl_buf)g->ctx);
|
366
|
+
if (buf_err) {
|
367
|
+
return yajl_gen_alloc_error;
|
368
|
+
}
|
335
369
|
*buf = yajl_buf_data((yajl_buf)g->ctx);
|
336
370
|
*len = yajl_buf_len((yajl_buf)g->ctx);
|
337
371
|
return yajl_gen_status_ok;
|
data/ext/yajl/yajl_lex.c
CHANGED
@@ -38,29 +38,26 @@
|
|
38
38
|
#include <assert.h>
|
39
39
|
#include <string.h>
|
40
40
|
|
41
|
-
|
42
|
-
static const char *
|
43
|
-
tokToStr(yajl_tok tok)
|
44
|
-
{
|
41
|
+
const char *yajl_tok_name(yajl_tok tok) {
|
45
42
|
switch (tok) {
|
46
43
|
case yajl_tok_bool: return "bool";
|
47
44
|
case yajl_tok_colon: return "colon";
|
48
45
|
case yajl_tok_comma: return "comma";
|
46
|
+
case yajl_tok_comment: return "comment";
|
49
47
|
case yajl_tok_eof: return "eof";
|
50
48
|
case yajl_tok_error: return "error";
|
51
|
-
case yajl_tok_left_brace: return "
|
52
|
-
case yajl_tok_left_bracket: return "
|
49
|
+
case yajl_tok_left_brace: return "open_array";
|
50
|
+
case yajl_tok_left_bracket: return "open_object";
|
53
51
|
case yajl_tok_null: return "null";
|
54
52
|
case yajl_tok_integer: return "integer";
|
55
53
|
case yajl_tok_double: return "double";
|
56
|
-
case yajl_tok_right_brace: return "
|
57
|
-
case yajl_tok_right_bracket: return "
|
54
|
+
case yajl_tok_right_brace: return "close_array";
|
55
|
+
case yajl_tok_right_bracket: return "close_object";
|
58
56
|
case yajl_tok_string: return "string";
|
59
57
|
case yajl_tok_string_with_escapes: return "string_with_escapes";
|
60
58
|
}
|
61
59
|
return "unknown";
|
62
60
|
}
|
63
|
-
#endif
|
64
61
|
|
65
62
|
/* Impact of the stream parsing feature on the lexer:
|
66
63
|
*
|
@@ -121,6 +118,8 @@ yajl_lex_alloc(yajl_alloc_funcs * alloc,
|
|
121
118
|
unsigned int allowComments, unsigned int validateUTF8)
|
122
119
|
{
|
123
120
|
yajl_lexer lxr = (yajl_lexer) YA_MALLOC(alloc, sizeof(struct yajl_lexer_t));
|
121
|
+
if (!lxr)
|
122
|
+
return NULL;
|
124
123
|
memset((void *) lxr, 0, sizeof(struct yajl_lexer_t));
|
125
124
|
lxr->buf = yajl_buf_alloc(alloc);
|
126
125
|
lxr->allowComments = allowComments;
|
@@ -636,7 +635,12 @@ yajl_lex_lex(yajl_lexer lexer, const unsigned char * jsonText,
|
|
636
635
|
lexer->bufInUse = 1;
|
637
636
|
yajl_buf_append(lexer->buf, jsonText + startOffset, *offset - startOffset);
|
638
637
|
lexer->bufOff = 0;
|
639
|
-
|
638
|
+
|
639
|
+
if (yajl_buf_err(lexer->buf)) {
|
640
|
+
lexer->error = yajl_lex_alloc_failed;
|
641
|
+
return yajl_tok_error;
|
642
|
+
}
|
643
|
+
|
640
644
|
if (tok != yajl_tok_eof) {
|
641
645
|
*outBuf = yajl_buf_data(lexer->buf);
|
642
646
|
*outLen = yajl_buf_len(lexer->buf);
|
@@ -703,6 +707,8 @@ yajl_lex_error_to_string(yajl_lex_error error)
|
|
703
707
|
case yajl_lex_unallowed_comment:
|
704
708
|
return "probable comment found in input text, comments are "
|
705
709
|
"not enabled.";
|
710
|
+
case yajl_lex_alloc_failed:
|
711
|
+
return "allocation failed";
|
706
712
|
}
|
707
713
|
return "unknown error code";
|
708
714
|
}
|
@@ -740,6 +746,10 @@ yajl_tok yajl_lex_peek(yajl_lexer lexer, const unsigned char * jsonText,
|
|
740
746
|
tok = yajl_lex_lex(lexer, jsonText, jsonTextLen, &offset,
|
741
747
|
&outBuf, &outLen);
|
742
748
|
|
749
|
+
if (tok == yajl_tok_eof) {
|
750
|
+
return tok;
|
751
|
+
}
|
752
|
+
|
743
753
|
lexer->bufOff = bufOff;
|
744
754
|
lexer->bufInUse = bufInUse;
|
745
755
|
yajl_buf_truncate(lexer->buf, bufLen);
|
data/ext/yajl/yajl_lex.h
CHANGED
@@ -36,33 +36,34 @@
|
|
36
36
|
#include "api/yajl_common.h"
|
37
37
|
|
38
38
|
typedef enum {
|
39
|
-
yajl_tok_bool,
|
40
|
-
yajl_tok_colon,
|
41
|
-
yajl_tok_comma,
|
42
|
-
yajl_tok_eof,
|
43
|
-
yajl_tok_error,
|
44
|
-
yajl_tok_left_brace,
|
45
|
-
yajl_tok_left_bracket,
|
46
|
-
yajl_tok_null,
|
47
|
-
yajl_tok_right_brace,
|
48
|
-
yajl_tok_right_bracket,
|
39
|
+
yajl_tok_bool, // 0
|
40
|
+
yajl_tok_colon, // 1
|
41
|
+
yajl_tok_comma, // 2
|
42
|
+
yajl_tok_eof, // 3
|
43
|
+
yajl_tok_error, // 4
|
44
|
+
yajl_tok_left_brace, // 5
|
45
|
+
yajl_tok_left_bracket, // 6
|
46
|
+
yajl_tok_null, // 7
|
47
|
+
yajl_tok_right_brace, // 8
|
48
|
+
yajl_tok_right_bracket, // 9
|
49
49
|
|
50
50
|
/* we differentiate between integers and doubles to allow the
|
51
51
|
* parser to interpret the number without re-scanning */
|
52
|
-
yajl_tok_integer,
|
53
|
-
yajl_tok_double,
|
52
|
+
yajl_tok_integer, // 10
|
53
|
+
yajl_tok_double, // 11
|
54
54
|
|
55
55
|
/* we differentiate between strings which require further processing,
|
56
56
|
* and strings that do not */
|
57
|
-
yajl_tok_string,
|
58
|
-
yajl_tok_string_with_escapes,
|
57
|
+
yajl_tok_string, // 12
|
58
|
+
yajl_tok_string_with_escapes, // 13
|
59
59
|
|
60
60
|
/* comment tokens are not currently returned to the parser, ever */
|
61
|
-
yajl_tok_comment
|
61
|
+
yajl_tok_comment // 14
|
62
62
|
} yajl_tok;
|
63
63
|
|
64
64
|
typedef struct yajl_lexer_t * yajl_lexer;
|
65
65
|
|
66
|
+
const char *yajl_tok_name(yajl_tok tok);
|
66
67
|
|
67
68
|
YAJL_API
|
68
69
|
yajl_lexer yajl_lex_alloc(yajl_alloc_funcs * alloc,
|
@@ -119,7 +120,8 @@ typedef enum {
|
|
119
120
|
yajl_lex_missing_integer_after_decimal,
|
120
121
|
yajl_lex_missing_integer_after_exponent,
|
121
122
|
yajl_lex_missing_integer_after_minus,
|
122
|
-
yajl_lex_unallowed_comment
|
123
|
+
yajl_lex_unallowed_comment,
|
124
|
+
yajl_lex_alloc_failed
|
123
125
|
} yajl_lex_error;
|
124
126
|
|
125
127
|
YAJL_API
|
data/ext/yajl/yajl_parser.c
CHANGED
@@ -134,6 +134,14 @@ yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText,
|
|
134
134
|
return yajl_status_client_canceled; \
|
135
135
|
}
|
136
136
|
|
137
|
+
/* check for buffer error */
|
138
|
+
#define _BUF_CHK(x) \
|
139
|
+
if (yajl_buf_err(x)) { \
|
140
|
+
yajl_bs_set(hand->stateStack, yajl_state_parse_error); \
|
141
|
+
hand->parseError = \
|
142
|
+
"allocation failed"; \
|
143
|
+
return yajl_status_alloc_failed; \
|
144
|
+
}
|
137
145
|
|
138
146
|
yajl_status
|
139
147
|
yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
|
@@ -161,7 +169,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
|
|
161
169
|
/* for arrays and maps, we advance the state for this
|
162
170
|
* depth, then push the state of the next depth.
|
163
171
|
* If an error occurs during the parsing of the nesting
|
164
|
-
*
|
172
|
+
* entity, the state at this level will not matter.
|
165
173
|
* a state that needs pushing will be anything other
|
166
174
|
* than state_start */
|
167
175
|
yajl_state stateToPush = yajl_state_start;
|
@@ -185,6 +193,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
|
|
185
193
|
if (hand->callbacks && hand->callbacks->yajl_string) {
|
186
194
|
yajl_buf_clear(hand->decodeBuf);
|
187
195
|
yajl_string_decode(hand->decodeBuf, buf, bufLen);
|
196
|
+
_BUF_CHK(hand->decodeBuf);
|
188
197
|
_CC_CHK(hand->callbacks->yajl_string(
|
189
198
|
hand->ctx, yajl_buf_data(hand->decodeBuf),
|
190
199
|
yajl_buf_len(hand->decodeBuf)));
|
@@ -234,6 +243,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
|
|
234
243
|
long int i = 0;
|
235
244
|
yajl_buf_clear(hand->decodeBuf);
|
236
245
|
yajl_buf_append(hand->decodeBuf, buf, bufLen);
|
246
|
+
_BUF_CHK(hand->decodeBuf);
|
237
247
|
buf = yajl_buf_data(hand->decodeBuf);
|
238
248
|
i = strtol((const char *) buf, NULL, 10);
|
239
249
|
if ((i == LONG_MIN || i == LONG_MAX) &&
|
@@ -261,6 +271,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
|
|
261
271
|
double d = 0.0;
|
262
272
|
yajl_buf_clear(hand->decodeBuf);
|
263
273
|
yajl_buf_append(hand->decodeBuf, buf, bufLen);
|
274
|
+
_BUF_CHK(hand->decodeBuf);
|
264
275
|
buf = yajl_buf_data(hand->decodeBuf);
|
265
276
|
d = strtod((char *) buf, NULL);
|
266
277
|
if ((d == HUGE_VAL || d == -HUGE_VAL) &&
|
@@ -320,7 +331,9 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
|
|
320
331
|
}
|
321
332
|
}
|
322
333
|
if (stateToPush != yajl_state_start) {
|
323
|
-
yajl_bs_push(hand->stateStack, stateToPush)
|
334
|
+
if (yajl_bs_push(hand->stateStack, stateToPush)) {
|
335
|
+
return yajl_status_alloc_failed;
|
336
|
+
}
|
324
337
|
}
|
325
338
|
|
326
339
|
goto around_again;
|
@@ -342,6 +355,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText,
|
|
342
355
|
if (hand->callbacks && hand->callbacks->yajl_map_key) {
|
343
356
|
yajl_buf_clear(hand->decodeBuf);
|
344
357
|
yajl_string_decode(hand->decodeBuf, buf, bufLen);
|
358
|
+
_BUF_CHK(hand->decodeBuf);
|
345
359
|
buf = yajl_buf_data(hand->decodeBuf);
|
346
360
|
bufLen = yajl_buf_len(hand->decodeBuf);
|
347
361
|
}
|
data/lib/yajl/version.rb
CHANGED
data/lib/yajl.rb
CHANGED
@@ -23,6 +23,13 @@ module Yajl
|
|
23
23
|
Encoder.encode(obj, args, &block)
|
24
24
|
end
|
25
25
|
|
26
|
+
class Projector
|
27
|
+
def initialize(stream, read_bufsize=4096)
|
28
|
+
@stream = stream
|
29
|
+
@buffer_size = read_bufsize
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
26
33
|
class Parser
|
27
34
|
# A helper method for parse-and-forget use-cases
|
28
35
|
#
|
@@ -230,6 +230,16 @@ describe "Yajl JSON encoder" do
|
|
230
230
|
expect(s.read).to eql("{\"foo\":\"bar\"}")
|
231
231
|
end
|
232
232
|
|
233
|
+
it "should encode all integers correctly" do
|
234
|
+
0.upto(129).each do |b|
|
235
|
+
b = 1 << b
|
236
|
+
[b, b-1, b-2, b+1, b+2].each do |i|
|
237
|
+
expect(Yajl::Encoder.encode(i)).to eq(i.to_s)
|
238
|
+
expect(Yajl::Encoder.encode(-i)).to eq((-i).to_s)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
233
243
|
it "should not encode NaN" do
|
234
244
|
expect {
|
235
245
|
Yajl::Encoder.encode(0.0/0.0)
|
@@ -275,11 +285,27 @@ describe "Yajl JSON encoder" do
|
|
275
285
|
expect(safe_encoder.encode("</script>")).to eql("\"<\\/script>\"")
|
276
286
|
end
|
277
287
|
|
288
|
+
it "should not encode characters with entities by default" do
|
289
|
+
expect(Yajl.dump("\u2028\u2029><&")).to eql("\"\u2028\u2029><&\"")
|
290
|
+
end
|
291
|
+
|
292
|
+
it "should encode characters with entities when enabled" do
|
293
|
+
expect(Yajl.dump("\u2028\u2029><&", entities: true)).to eql("\"\\u2028\\u2029\\u003E\\u003C\\u0026\"")
|
294
|
+
end
|
295
|
+
|
278
296
|
it "should default to *not* escaping / characters" do
|
279
297
|
unsafe_encoder = Yajl::Encoder.new
|
280
298
|
expect(unsafe_encoder.encode("</script>")).not_to eql("\"<\\/script>\"")
|
281
299
|
end
|
282
300
|
|
301
|
+
it "should encode slashes when enabled" do
|
302
|
+
unsafe_encoder = Yajl::Encoder.new(:entities => false)
|
303
|
+
safe_encoder = Yajl::Encoder.new(:entities => true)
|
304
|
+
|
305
|
+
expect(unsafe_encoder.encode("</script>")).not_to eql("\"<\\/script>\"")
|
306
|
+
expect(safe_encoder.encode("</script>")).to eql("\"\\u003C\\/script\\u003E\"")
|
307
|
+
end
|
308
|
+
|
283
309
|
it "return value of #to_json must be a string" do
|
284
310
|
expect {
|
285
311
|
Yajl::Encoder.encode(TheMindKiller.new)
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
|
2
|
+
|
3
|
+
require 'benchmark'
|
4
|
+
require 'benchmark/memory'
|
5
|
+
|
6
|
+
describe "file projection" do
|
7
|
+
it "projects file streams" do
|
8
|
+
schema = {
|
9
|
+
"forced" => nil,
|
10
|
+
"created" => nil,
|
11
|
+
"pusher" => {
|
12
|
+
"name" => nil,
|
13
|
+
},
|
14
|
+
"repository" => {
|
15
|
+
"name" => nil,
|
16
|
+
"full_name" => nil,
|
17
|
+
},
|
18
|
+
"ref" => nil,
|
19
|
+
"compare" => nil,
|
20
|
+
"commits" => {
|
21
|
+
"distinct" => nil,
|
22
|
+
"message" => nil,
|
23
|
+
"url" => nil,
|
24
|
+
"id" => nil,
|
25
|
+
"author" => {
|
26
|
+
"username" => nil,
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
file_path = ENV['JSON_FILE']
|
32
|
+
if file_path.nil? || file_path.empty?
|
33
|
+
return
|
34
|
+
end
|
35
|
+
|
36
|
+
Benchmark.memory { |x|
|
37
|
+
x.report("project (yajl)") { Yajl::Projector.new(File.open(file_path, 'r')).project(schema) }
|
38
|
+
x.compare!
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|