json 1.2.4 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of json might be problematic. Click here for more details.
- data/README +9 -11
- data/Rakefile +27 -26
- data/VERSION +1 -1
- data/benchmarks/generator2_benchmark.rb +222 -0
- data/benchmarks/generator_benchmark.rb +63 -4
- data/benchmarks/ohai.json +1216 -0
- data/benchmarks/ohai.ruby +1 -0
- data/benchmarks/parser2_benchmark.rb +251 -0
- data/benchmarks/parser_benchmark.rb +52 -4
- data/ext/json/ext/extconf_generator.rb +16 -0
- data/ext/json/ext/extconf_parser.rb +15 -0
- data/ext/json/ext/generator.c +1334 -0
- data/ext/json/ext/generator.h +170 -0
- data/ext/json/ext/{parser/parser.c → parser.c} +223 -182
- data/ext/json/ext/parser.h +71 -0
- data/ext/json/ext/{parser/parser.rl → parser.rl} +149 -108
- data/lib/json/common.rb +53 -36
- data/lib/json/pure/generator.rb +85 -81
- data/lib/json/version.rb +1 -1
- data/tests/test_json_encoding.rb +4 -3
- data/tests/test_json_generate.rb +7 -7
- data/tests/test_json_unicode.rb +20 -6
- metadata +17 -15
- data/ext/json/ext/generator/extconf.rb +0 -11
- data/ext/json/ext/generator/generator.c +0 -953
- data/ext/json/ext/generator/unicode.c +0 -180
- data/ext/json/ext/generator/unicode.h +0 -53
- data/ext/json/ext/parser/extconf.rb +0 -11
- data/ext/json/ext/parser/unicode.c +0 -154
- data/ext/json/ext/parser/unicode.h +0 -58
@@ -0,0 +1,71 @@
|
|
1
|
+
#ifndef _PARSER_H_
|
2
|
+
#define _PARSER_H_
|
3
|
+
|
4
|
+
#include "ruby.h"
|
5
|
+
|
6
|
+
#if HAVE_RE_H
|
7
|
+
#include "re.h"
|
8
|
+
#endif
|
9
|
+
|
10
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
11
|
+
#include "ruby/encoding.h"
|
12
|
+
#define FORCE_UTF8(obj) rb_enc_associate((obj), rb_utf8_encoding())
|
13
|
+
#else
|
14
|
+
#define FORCE_UTF8(obj)
|
15
|
+
#endif
|
16
|
+
|
17
|
+
#define option_given_p(opts, key) RTEST(rb_funcall(opts, i_key_p, 1, key))
|
18
|
+
|
19
|
+
/* unicode */
|
20
|
+
|
21
|
+
typedef unsigned long UTF32; /* at least 32 bits */
|
22
|
+
typedef unsigned short UTF16; /* at least 16 bits */
|
23
|
+
typedef unsigned char UTF8; /* typically 8 bits */
|
24
|
+
|
25
|
+
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
|
26
|
+
#define UNI_SUR_HIGH_START (UTF32)0xD800
|
27
|
+
#define UNI_SUR_HIGH_END (UTF32)0xDBFF
|
28
|
+
#define UNI_SUR_LOW_START (UTF32)0xDC00
|
29
|
+
#define UNI_SUR_LOW_END (UTF32)0xDFFF
|
30
|
+
|
31
|
+
typedef struct JSON_ParserStruct {
|
32
|
+
VALUE Vsource;
|
33
|
+
char *source;
|
34
|
+
long len;
|
35
|
+
char *memo;
|
36
|
+
VALUE create_id;
|
37
|
+
int max_nesting;
|
38
|
+
int current_nesting;
|
39
|
+
int allow_nan;
|
40
|
+
int parsing_name;
|
41
|
+
int symbolize_names;
|
42
|
+
VALUE object_class;
|
43
|
+
VALUE array_class;
|
44
|
+
} JSON_Parser;
|
45
|
+
|
46
|
+
#define GET_PARSER \
|
47
|
+
JSON_Parser *json; \
|
48
|
+
Data_Get_Struct(self, JSON_Parser, json)
|
49
|
+
|
50
|
+
#define MinusInfinity "-Infinity"
|
51
|
+
#define EVIL 0x666
|
52
|
+
|
53
|
+
static UTF32 unescape_unicode(const unsigned char *p);
|
54
|
+
static int convert_UTF32_to_UTF8(char *buf, UTF32 ch);
|
55
|
+
static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
56
|
+
static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
57
|
+
static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
58
|
+
static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
59
|
+
static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
60
|
+
static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd);
|
61
|
+
static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
62
|
+
static VALUE convert_encoding(VALUE source);
|
63
|
+
static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self);
|
64
|
+
static VALUE cParser_parse(VALUE self);
|
65
|
+
static JSON_Parser *JSON_allocate();
|
66
|
+
static void JSON_mark(JSON_Parser *json);
|
67
|
+
static void JSON_free(JSON_Parser *json);
|
68
|
+
static VALUE cJSON_parser_s_allocate(VALUE klass);
|
69
|
+
static VALUE cParser_source(VALUE self);
|
70
|
+
|
71
|
+
#endif
|
@@ -1,21 +1,74 @@
|
|
1
|
-
#include "
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
#include "parser.h"
|
2
|
+
|
3
|
+
/* unicode */
|
4
|
+
|
5
|
+
static const char digit_values[256] = {
|
6
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
7
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
8
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
|
9
|
+
-1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1,
|
10
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
11
|
+
10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
12
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
13
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
14
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
15
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
16
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
17
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
18
|
+
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
19
|
+
-1, -1, -1, -1, -1, -1, -1
|
20
|
+
};
|
21
|
+
|
22
|
+
static UTF32 unescape_unicode(const unsigned char *p)
|
23
|
+
{
|
24
|
+
char b;
|
25
|
+
UTF32 result = 0;
|
26
|
+
b = digit_values[p[0]];
|
27
|
+
if (b < 0) return UNI_REPLACEMENT_CHAR;
|
28
|
+
result = (result << 4) | b;
|
29
|
+
b = digit_values[p[1]];
|
30
|
+
result = (result << 4) | b;
|
31
|
+
if (b < 0) return UNI_REPLACEMENT_CHAR;
|
32
|
+
b = digit_values[p[2]];
|
33
|
+
result = (result << 4) | b;
|
34
|
+
if (b < 0) return UNI_REPLACEMENT_CHAR;
|
35
|
+
b = digit_values[p[3]];
|
36
|
+
result = (result << 4) | b;
|
37
|
+
if (b < 0) return UNI_REPLACEMENT_CHAR;
|
38
|
+
return result;
|
39
|
+
}
|
8
40
|
|
9
|
-
|
41
|
+
static int convert_UTF32_to_UTF8(char *buf, UTF32 ch)
|
42
|
+
{
|
43
|
+
int len = 1;
|
44
|
+
if (ch <= 0x7F) {
|
45
|
+
buf[0] = (char) ch;
|
46
|
+
} else if (ch <= 0x07FF) {
|
47
|
+
buf[0] = (char) ((ch >> 6) | 0xC0);
|
48
|
+
buf[1] = (char) ((ch & 0x3F) | 0x80);
|
49
|
+
len++;
|
50
|
+
} else if (ch <= 0xFFFF) {
|
51
|
+
buf[0] = (char) ((ch >> 12) | 0xE0);
|
52
|
+
buf[1] = (char) (((ch >> 6) & 0x3F) | 0x80);
|
53
|
+
buf[2] = (char) ((ch & 0x3F) | 0x80);
|
54
|
+
len += 2;
|
55
|
+
} else if (ch <= 0x1fffff) {
|
56
|
+
buf[0] =(char) ((ch >> 18) | 0xF0);
|
57
|
+
buf[1] =(char) (((ch >> 12) & 0x3F) | 0x80);
|
58
|
+
buf[2] =(char) (((ch >> 6) & 0x3F) | 0x80);
|
59
|
+
buf[3] =(char) ((ch & 0x3F) | 0x80);
|
60
|
+
len += 3;
|
61
|
+
} else {
|
62
|
+
buf[0] = '?';
|
63
|
+
}
|
64
|
+
return len;
|
65
|
+
}
|
10
66
|
|
11
67
|
#ifdef HAVE_RUBY_ENCODING_H
|
12
|
-
|
13
|
-
|
14
|
-
static VALUE mEncoding_ASCII_8BIT, mEncoding_UTF_8, mEncoding_UTF_16BE,
|
15
|
-
mEncoding_UTF_16LE, mEncoding_UTF_32BE, mEncoding_UTF_32LE;
|
68
|
+
static VALUE CEncoding_ASCII_8BIT, CEncoding_UTF_8, CEncoding_UTF_16BE,
|
69
|
+
CEncoding_UTF_16LE, CEncoding_UTF_32BE, CEncoding_UTF_32LE;
|
16
70
|
static ID i_encoding, i_encode, i_encode_bang, i_force_encoding;
|
17
71
|
#else
|
18
|
-
#define FORCE_UTF8(obj)
|
19
72
|
static ID i_iconv;
|
20
73
|
#endif
|
21
74
|
|
@@ -26,34 +79,6 @@ static ID i_json_creatable_p, i_json_create, i_create_id, i_create_additions,
|
|
26
79
|
i_chr, i_max_nesting, i_allow_nan, i_symbolize_names, i_object_class,
|
27
80
|
i_array_class, i_key_p, i_deep_const_get;
|
28
81
|
|
29
|
-
#define MinusInfinity "-Infinity"
|
30
|
-
|
31
|
-
typedef struct JSON_ParserStruct {
|
32
|
-
VALUE Vsource;
|
33
|
-
char *source;
|
34
|
-
long len;
|
35
|
-
char *memo;
|
36
|
-
VALUE create_id;
|
37
|
-
int max_nesting;
|
38
|
-
int current_nesting;
|
39
|
-
int allow_nan;
|
40
|
-
int parsing_name;
|
41
|
-
int symbolize_names;
|
42
|
-
VALUE object_class;
|
43
|
-
VALUE array_class;
|
44
|
-
} JSON_Parser;
|
45
|
-
|
46
|
-
static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
47
|
-
static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
48
|
-
static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
49
|
-
static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
50
|
-
static char *JSON_parse_integer(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
51
|
-
static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *result);
|
52
|
-
|
53
|
-
#define GET_STRUCT \
|
54
|
-
JSON_Parser *json; \
|
55
|
-
Data_Get_Struct(self, JSON_Parser, json);
|
56
|
-
|
57
82
|
%%{
|
58
83
|
machine JSON_common;
|
59
84
|
|
@@ -348,62 +373,77 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
348
373
|
return p + 1;
|
349
374
|
} else {
|
350
375
|
rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p);
|
376
|
+
return NULL;
|
351
377
|
}
|
352
378
|
}
|
353
379
|
|
354
|
-
static VALUE json_string_unescape(char *
|
380
|
+
static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)
|
355
381
|
{
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
382
|
+
char *p = string, *pe = string, *unescape;
|
383
|
+
int unescape_len;
|
384
|
+
|
385
|
+
while (pe < stringEnd) {
|
386
|
+
if (*pe == '\\') {
|
387
|
+
unescape = (char *) "?";
|
388
|
+
unescape_len = 1;
|
389
|
+
if (pe > p) rb_str_buf_cat(result, p, pe - p);
|
390
|
+
switch (*++pe) {
|
391
|
+
case 'n':
|
392
|
+
unescape = (char *) "\n";
|
393
|
+
break;
|
394
|
+
case 'r':
|
395
|
+
unescape = (char *) "\r";
|
396
|
+
break;
|
397
|
+
case 't':
|
398
|
+
unescape = (char *) "\t";
|
399
|
+
break;
|
363
400
|
case '"':
|
401
|
+
unescape = (char *) "\"";
|
402
|
+
break;
|
364
403
|
case '\\':
|
365
|
-
|
366
|
-
p++;
|
404
|
+
unescape = (char *) "\\";
|
367
405
|
break;
|
368
406
|
case 'b':
|
369
|
-
|
370
|
-
p++;
|
407
|
+
unescape = (char *) "\b";
|
371
408
|
break;
|
372
409
|
case 'f':
|
373
|
-
|
374
|
-
p++;
|
375
|
-
break;
|
376
|
-
case 'n':
|
377
|
-
rb_str_buf_cat2(result, "\n");
|
378
|
-
p++;
|
379
|
-
break;
|
380
|
-
case 'r':
|
381
|
-
rb_str_buf_cat2(result, "\r");
|
382
|
-
p++;
|
383
|
-
break;
|
384
|
-
case 't':
|
385
|
-
rb_str_buf_cat2(result, "\t");
|
386
|
-
p++;
|
410
|
+
unescape = (char *) "\f";
|
387
411
|
break;
|
388
412
|
case 'u':
|
389
|
-
if (
|
413
|
+
if (pe > stringEnd - 4) {
|
390
414
|
return Qnil;
|
391
415
|
} else {
|
392
|
-
|
416
|
+
char buf[4];
|
417
|
+
UTF32 ch = unescape_unicode((unsigned char *) ++pe);
|
418
|
+
pe += 3;
|
419
|
+
if (UNI_SUR_HIGH_START == (ch & 0xFC00)) {
|
420
|
+
pe++;
|
421
|
+
if (pe > stringEnd - 6) return Qnil;
|
422
|
+
if (pe[0] == '\\' && pe[1] == 'u') {
|
423
|
+
UTF32 sur = unescape_unicode((unsigned char *) pe + 2);
|
424
|
+
ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
|
425
|
+
| (sur & 0x3FF));
|
426
|
+
pe += 5;
|
427
|
+
} else {
|
428
|
+
unescape = (char *) "?";
|
429
|
+
break;
|
430
|
+
}
|
431
|
+
}
|
432
|
+
unescape_len = convert_UTF32_to_UTF8(buf, ch);
|
433
|
+
unescape = buf;
|
393
434
|
}
|
394
435
|
break;
|
395
436
|
default:
|
396
|
-
|
397
|
-
|
398
|
-
break;
|
437
|
+
p = pe;
|
438
|
+
continue;
|
399
439
|
}
|
440
|
+
rb_str_buf_cat(result, unescape, unescape_len);
|
441
|
+
p = ++pe;
|
400
442
|
} else {
|
401
|
-
|
402
|
-
while (*q != '\\' && q < pe) q++;
|
403
|
-
rb_str_buf_cat(result, p, q - p);
|
404
|
-
p = q;
|
443
|
+
pe++;
|
405
444
|
}
|
406
445
|
}
|
446
|
+
rb_str_buf_cat(result, p, pe - p);
|
407
447
|
return result;
|
408
448
|
}
|
409
449
|
|
@@ -414,15 +454,15 @@ static VALUE json_string_unescape(char *p, char *pe)
|
|
414
454
|
write data;
|
415
455
|
|
416
456
|
action parse_string {
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
457
|
+
*result = json_string_unescape(*result, json->memo + 1, p);
|
458
|
+
if (NIL_P(*result)) {
|
459
|
+
fhold;
|
460
|
+
fbreak;
|
461
|
+
} else {
|
462
|
+
FORCE_UTF8(*result);
|
463
|
+
fexec p + 1;
|
464
|
+
}
|
465
|
+
}
|
426
466
|
|
427
467
|
action exit { fhold; fbreak; }
|
428
468
|
|
@@ -433,7 +473,7 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
|
|
433
473
|
{
|
434
474
|
int cs = EVIL;
|
435
475
|
|
436
|
-
*result =
|
476
|
+
*result = rb_str_buf_new(0);
|
437
477
|
%% write init;
|
438
478
|
json->memo = p;
|
439
479
|
%% write exec;
|
@@ -488,7 +528,7 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
|
|
488
528
|
*
|
489
529
|
*/
|
490
530
|
|
491
|
-
|
531
|
+
static VALUE convert_encoding(VALUE source)
|
492
532
|
{
|
493
533
|
char *ptr = RSTRING_PTR(source);
|
494
534
|
long len = RSTRING_LEN(source);
|
@@ -498,28 +538,28 @@ inline static VALUE convert_encoding(VALUE source)
|
|
498
538
|
#ifdef HAVE_RUBY_ENCODING_H
|
499
539
|
{
|
500
540
|
VALUE encoding = rb_funcall(source, i_encoding, 0);
|
501
|
-
if (encoding ==
|
541
|
+
if (encoding == CEncoding_ASCII_8BIT) {
|
502
542
|
if (len >= 4 && ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 0) {
|
503
543
|
source = rb_str_dup(source);
|
504
|
-
rb_funcall(source, i_force_encoding, 1,
|
505
|
-
source = rb_funcall(source, i_encode_bang, 1,
|
544
|
+
rb_funcall(source, i_force_encoding, 1, CEncoding_UTF_32BE);
|
545
|
+
source = rb_funcall(source, i_encode_bang, 1, CEncoding_UTF_8);
|
506
546
|
} else if (len >= 4 && ptr[0] == 0 && ptr[2] == 0) {
|
507
547
|
source = rb_str_dup(source);
|
508
|
-
rb_funcall(source, i_force_encoding, 1,
|
509
|
-
source = rb_funcall(source, i_encode_bang, 1,
|
548
|
+
rb_funcall(source, i_force_encoding, 1, CEncoding_UTF_16BE);
|
549
|
+
source = rb_funcall(source, i_encode_bang, 1, CEncoding_UTF_8);
|
510
550
|
} else if (len >= 4 && ptr[1] == 0 && ptr[2] == 0 && ptr[3] == 0) {
|
511
551
|
source = rb_str_dup(source);
|
512
|
-
rb_funcall(source, i_force_encoding, 1,
|
513
|
-
source = rb_funcall(source, i_encode_bang, 1,
|
552
|
+
rb_funcall(source, i_force_encoding, 1, CEncoding_UTF_32LE);
|
553
|
+
source = rb_funcall(source, i_encode_bang, 1, CEncoding_UTF_8);
|
514
554
|
} else if (len >= 4 && ptr[1] == 0 && ptr[3] == 0) {
|
515
555
|
source = rb_str_dup(source);
|
516
|
-
rb_funcall(source, i_force_encoding, 1,
|
517
|
-
source = rb_funcall(source, i_encode_bang, 1,
|
556
|
+
rb_funcall(source, i_force_encoding, 1, CEncoding_UTF_16LE);
|
557
|
+
source = rb_funcall(source, i_encode_bang, 1, CEncoding_UTF_8);
|
518
558
|
} else {
|
519
|
-
|
559
|
+
FORCE_UTF8(source);
|
520
560
|
}
|
521
561
|
} else {
|
522
|
-
source = rb_funcall(source, i_encode, 1,
|
562
|
+
source = rb_funcall(source, i_encode, 1, CEncoding_UTF_8);
|
523
563
|
}
|
524
564
|
}
|
525
565
|
#else
|
@@ -567,7 +607,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
|
|
567
607
|
char *ptr;
|
568
608
|
long len;
|
569
609
|
VALUE source, opts;
|
570
|
-
|
610
|
+
GET_PARSER;
|
571
611
|
rb_scan_args(argc, argv, "11", &source, &opts);
|
572
612
|
source = convert_encoding(StringValue(source));
|
573
613
|
ptr = RSTRING_PTR(source);
|
@@ -652,7 +692,7 @@ static VALUE cParser_parse(VALUE self)
|
|
652
692
|
char *p, *pe;
|
653
693
|
int cs = EVIL;
|
654
694
|
VALUE result = Qnil;
|
655
|
-
|
695
|
+
GET_PARSER;
|
656
696
|
|
657
697
|
%% write init;
|
658
698
|
p = json->source;
|
@@ -663,10 +703,11 @@ static VALUE cParser_parse(VALUE self)
|
|
663
703
|
return result;
|
664
704
|
} else {
|
665
705
|
rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p);
|
706
|
+
return Qnil;
|
666
707
|
}
|
667
708
|
}
|
668
709
|
|
669
|
-
|
710
|
+
static JSON_Parser *JSON_allocate()
|
670
711
|
{
|
671
712
|
JSON_Parser *json = ALLOC(JSON_Parser);
|
672
713
|
MEMZERO(json, JSON_Parser, 1);
|
@@ -700,7 +741,7 @@ static VALUE cJSON_parser_s_allocate(VALUE klass)
|
|
700
741
|
*/
|
701
742
|
static VALUE cParser_source(VALUE self)
|
702
743
|
{
|
703
|
-
|
744
|
+
GET_PARSER;
|
704
745
|
return rb_str_dup(json->Vsource);
|
705
746
|
}
|
706
747
|
|
@@ -734,12 +775,12 @@ void Init_parser()
|
|
734
775
|
i_key_p = rb_intern("key?");
|
735
776
|
i_deep_const_get = rb_intern("deep_const_get");
|
736
777
|
#ifdef HAVE_RUBY_ENCODING_H
|
737
|
-
|
738
|
-
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
778
|
+
CEncoding_UTF_8 = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-8"));
|
779
|
+
CEncoding_UTF_16BE = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-16be"));
|
780
|
+
CEncoding_UTF_16LE = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-16le"));
|
781
|
+
CEncoding_UTF_32BE = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-32be"));
|
782
|
+
CEncoding_UTF_32LE = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-32le"));
|
783
|
+
CEncoding_ASCII_8BIT = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("ascii-8bit"));
|
743
784
|
i_encoding = rb_intern("encoding");
|
744
785
|
i_encode = rb_intern("encode");
|
745
786
|
i_encode_bang = rb_intern("encode!");
|
data/lib/json/common.rb
CHANGED
@@ -63,6 +63,20 @@ module JSON
|
|
63
63
|
end
|
64
64
|
self.state = generator::State
|
65
65
|
const_set :State, self.state
|
66
|
+
const_set :SAFE_STATE_PROTOTYPE, State.new.freeze
|
67
|
+
const_set :FAST_STATE_PROTOTYPE, State.new(
|
68
|
+
:indent => '',
|
69
|
+
:space => '',
|
70
|
+
:object_nl => "",
|
71
|
+
:array_nl => "",
|
72
|
+
:max_nesting => false
|
73
|
+
).freeze
|
74
|
+
const_set :PRETTY_STATE_PROTOTYPE, State.new(
|
75
|
+
:indent => ' ',
|
76
|
+
:space => ' ',
|
77
|
+
:object_nl => "\n",
|
78
|
+
:array_nl => "\n"
|
79
|
+
).freeze
|
66
80
|
end
|
67
81
|
|
68
82
|
# Returns the JSON generator modul, that is used by JSON. This might be
|
@@ -95,15 +109,15 @@ module JSON
|
|
95
109
|
# deep.
|
96
110
|
class NestingError < ParserError; end
|
97
111
|
|
112
|
+
# :stopdoc:
|
113
|
+
class CircularDatastructure < NestingError; end
|
114
|
+
# :startdoc:
|
115
|
+
|
98
116
|
# This exception is raised, if a generator or unparser error occurs.
|
99
117
|
class GeneratorError < JSONError; end
|
100
118
|
# For backwards compatibility
|
101
119
|
UnparserError = GeneratorError
|
102
120
|
|
103
|
-
# If a circular data structure is encountered while unparsing
|
104
|
-
# this exception is raised.
|
105
|
-
class CircularDatastructure < GeneratorError; end
|
106
|
-
|
107
121
|
# This exception is raised, if the required unicode support is missing on the
|
108
122
|
# system. Usually this means, that the iconv library is not installed.
|
109
123
|
class MissingUnicodeSupport < JSONError; end
|
@@ -129,7 +143,7 @@ module JSON
|
|
129
143
|
# * *object_class*: Defaults to Hash
|
130
144
|
# * *array_class*: Defaults to Array
|
131
145
|
def parse(source, opts = {})
|
132
|
-
|
146
|
+
Parser.new(source, opts).parse
|
133
147
|
end
|
134
148
|
|
135
149
|
# Parse the JSON document _source_ into a Ruby data structure and return it.
|
@@ -149,10 +163,10 @@ module JSON
|
|
149
163
|
# defaults to true.
|
150
164
|
def parse!(source, opts = {})
|
151
165
|
opts = {
|
152
|
-
:max_nesting
|
153
|
-
:allow_nan
|
166
|
+
:max_nesting => false,
|
167
|
+
:allow_nan => true
|
154
168
|
}.update(opts)
|
155
|
-
|
169
|
+
Parser.new(source, opts).parse
|
156
170
|
end
|
157
171
|
|
158
172
|
# Generate a JSON document from the Ruby data structure _obj_ and return
|
@@ -171,8 +185,6 @@ module JSON
|
|
171
185
|
# * *space_before*: a string that is put before a : pair delimiter (default: ''),
|
172
186
|
# * *object_nl*: a string that is put at the end of a JSON object (default: ''),
|
173
187
|
# * *array_nl*: a string that is put at the end of a JSON array (default: ''),
|
174
|
-
# * *check_circular*: true if checking for circular data structures
|
175
|
-
# should be done (the default), false otherwise.
|
176
188
|
# * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
177
189
|
# generated, otherwise an exception is thrown, if these values are
|
178
190
|
# encountered. This options defaults to false.
|
@@ -183,17 +195,21 @@ module JSON
|
|
183
195
|
# See also the fast_generate for the fastest creation method with the least
|
184
196
|
# amount of sanity checks, and the pretty_generate method for some
|
185
197
|
# defaults for a pretty output.
|
186
|
-
def generate(obj,
|
187
|
-
if
|
188
|
-
|
198
|
+
def generate(obj, opts = nil)
|
199
|
+
if opts
|
200
|
+
if opts.respond_to? :to_hash
|
201
|
+
opts = opts.to_hash
|
202
|
+
elsif opts.respond_to? :to_h
|
203
|
+
opts = opts.to_h
|
204
|
+
else
|
205
|
+
raise TypeError, "can't convert #{opts.class} into Hash"
|
206
|
+
end
|
207
|
+
state = SAFE_STATE_PROTOTYPE.dup
|
208
|
+
state = state.configure(opts)
|
189
209
|
else
|
190
|
-
state =
|
191
|
-
end
|
192
|
-
result = obj.to_json(state)
|
193
|
-
if result !~ /\A\s*(?:\[.*\]|\{.*\})\s*\Z/m
|
194
|
-
raise GeneratorError, "only generation of JSON objects or arrays allowed"
|
210
|
+
state = SAFE_STATE_PROTOTYPE
|
195
211
|
end
|
196
|
-
|
212
|
+
state.generate(obj)
|
197
213
|
end
|
198
214
|
|
199
215
|
# :stopdoc:
|
@@ -208,12 +224,21 @@ module JSON
|
|
208
224
|
#
|
209
225
|
# *WARNING*: Be careful not to pass any Ruby data structures with circles as
|
210
226
|
# _obj_ argument, because this will cause JSON to go into an infinite loop.
|
211
|
-
def fast_generate(obj)
|
212
|
-
|
213
|
-
|
214
|
-
|
227
|
+
def fast_generate(obj, opts = nil)
|
228
|
+
if opts
|
229
|
+
if opts.respond_to? :to_hash
|
230
|
+
opts = opts.to_hash
|
231
|
+
elsif opts.respond_to? :to_h
|
232
|
+
opts = opts.to_h
|
233
|
+
else
|
234
|
+
raise TypeError, "can't convert #{opts.class} into Hash"
|
235
|
+
end
|
236
|
+
state = FAST_STATE_PROTOTYPE.dup
|
237
|
+
state.configure(opts)
|
238
|
+
else
|
239
|
+
state = FAST_STATE_PROTOTYPE
|
215
240
|
end
|
216
|
-
|
241
|
+
state.generate(obj)
|
217
242
|
end
|
218
243
|
|
219
244
|
# :stopdoc:
|
@@ -229,13 +254,6 @@ module JSON
|
|
229
254
|
# The _opts_ argument can be used to configure the generator, see the
|
230
255
|
# generate method for a more detailed explanation.
|
231
256
|
def pretty_generate(obj, opts = nil)
|
232
|
-
state = JSON.state.new(
|
233
|
-
:indent => ' ',
|
234
|
-
:space => ' ',
|
235
|
-
:object_nl => "\n",
|
236
|
-
:array_nl => "\n",
|
237
|
-
:check_circular => true
|
238
|
-
)
|
239
257
|
if opts
|
240
258
|
if opts.respond_to? :to_hash
|
241
259
|
opts = opts.to_hash
|
@@ -244,13 +262,12 @@ module JSON
|
|
244
262
|
else
|
245
263
|
raise TypeError, "can't convert #{opts.class} into Hash"
|
246
264
|
end
|
265
|
+
state = PRETTY_STATE_PROTOTYPE.dup
|
247
266
|
state.configure(opts)
|
267
|
+
else
|
268
|
+
state = PRETTY_STATE_PROTOTYPE
|
248
269
|
end
|
249
|
-
|
250
|
-
if result !~ /\A\s*(?:\[.*\]|\{.*\})\s*\Z/m
|
251
|
-
raise GeneratorError, "only generation of JSON objects or arrays allowed"
|
252
|
-
end
|
253
|
-
result
|
270
|
+
state.generate(obj)
|
254
271
|
end
|
255
272
|
|
256
273
|
# :stopdoc:
|