yajl-ruby 1.3.1 → 1.4.2
Sign up to get free protection for your applications and to get access to all the features.
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
|