json_pure 1.2.4 → 1.4.6
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.
- data/CHANGES +32 -0
- data/README +14 -18
- data/Rakefile +19 -14
- 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/generator/extconf.rb +14 -5
- data/ext/json/ext/generator/generator.c +880 -416
- data/ext/json/ext/generator/generator.h +197 -0
- data/ext/json/ext/parser/extconf.rb +8 -4
- data/ext/json/ext/parser/parser.c +225 -183
- data/ext/json/ext/parser/parser.h +71 -0
- data/ext/json/ext/parser/parser.rl +151 -109
- data/lib/json/common.rb +53 -42
- data/lib/json/pure/generator.rb +111 -120
- data/lib/json/pure/parser.rb +29 -27
- data/lib/json/version.rb +1 -1
- data/tests/test_json.rb +70 -3
- data/tests/test_json_addition.rb +6 -6
- data/tests/test_json_encoding.rb +4 -3
- data/tests/test_json_generate.rb +66 -7
- data/tests/test_json_unicode.rb +20 -6
- metadata +10 -8
- data/ext/json/ext/generator/unicode.c +0 -180
- data/ext/json/ext/generator/unicode.h +0 -53
- 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
|
|
|
@@ -100,8 +125,9 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
|
100
125
|
}
|
|
101
126
|
|
|
102
127
|
action parse_name {
|
|
128
|
+
char *np;
|
|
103
129
|
json->parsing_name = 1;
|
|
104
|
-
|
|
130
|
+
np = JSON_parse_string(json, fpc, pe, &last_name);
|
|
105
131
|
json->parsing_name = 0;
|
|
106
132
|
if (np == NULL) { fhold; fbreak; } else fexec np;
|
|
107
133
|
}
|
|
@@ -348,62 +374,77 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul
|
|
|
348
374
|
return p + 1;
|
|
349
375
|
} else {
|
|
350
376
|
rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p);
|
|
377
|
+
return NULL;
|
|
351
378
|
}
|
|
352
379
|
}
|
|
353
380
|
|
|
354
|
-
static VALUE json_string_unescape(char *
|
|
381
|
+
static VALUE json_string_unescape(VALUE result, char *string, char *stringEnd)
|
|
355
382
|
{
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
383
|
+
char *p = string, *pe = string, *unescape;
|
|
384
|
+
int unescape_len;
|
|
385
|
+
|
|
386
|
+
while (pe < stringEnd) {
|
|
387
|
+
if (*pe == '\\') {
|
|
388
|
+
unescape = (char *) "?";
|
|
389
|
+
unescape_len = 1;
|
|
390
|
+
if (pe > p) rb_str_buf_cat(result, p, pe - p);
|
|
391
|
+
switch (*++pe) {
|
|
392
|
+
case 'n':
|
|
393
|
+
unescape = (char *) "\n";
|
|
394
|
+
break;
|
|
395
|
+
case 'r':
|
|
396
|
+
unescape = (char *) "\r";
|
|
397
|
+
break;
|
|
398
|
+
case 't':
|
|
399
|
+
unescape = (char *) "\t";
|
|
400
|
+
break;
|
|
363
401
|
case '"':
|
|
402
|
+
unescape = (char *) "\"";
|
|
403
|
+
break;
|
|
364
404
|
case '\\':
|
|
365
|
-
|
|
366
|
-
p++;
|
|
405
|
+
unescape = (char *) "\\";
|
|
367
406
|
break;
|
|
368
407
|
case 'b':
|
|
369
|
-
|
|
370
|
-
p++;
|
|
408
|
+
unescape = (char *) "\b";
|
|
371
409
|
break;
|
|
372
410
|
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++;
|
|
411
|
+
unescape = (char *) "\f";
|
|
387
412
|
break;
|
|
388
413
|
case 'u':
|
|
389
|
-
if (
|
|
414
|
+
if (pe > stringEnd - 4) {
|
|
390
415
|
return Qnil;
|
|
391
416
|
} else {
|
|
392
|
-
|
|
417
|
+
char buf[4];
|
|
418
|
+
UTF32 ch = unescape_unicode((unsigned char *) ++pe);
|
|
419
|
+
pe += 3;
|
|
420
|
+
if (UNI_SUR_HIGH_START == (ch & 0xFC00)) {
|
|
421
|
+
pe++;
|
|
422
|
+
if (pe > stringEnd - 6) return Qnil;
|
|
423
|
+
if (pe[0] == '\\' && pe[1] == 'u') {
|
|
424
|
+
UTF32 sur = unescape_unicode((unsigned char *) pe + 2);
|
|
425
|
+
ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
|
|
426
|
+
| (sur & 0x3FF));
|
|
427
|
+
pe += 5;
|
|
428
|
+
} else {
|
|
429
|
+
unescape = (char *) "?";
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
unescape_len = convert_UTF32_to_UTF8(buf, ch);
|
|
434
|
+
unescape = buf;
|
|
393
435
|
}
|
|
394
436
|
break;
|
|
395
437
|
default:
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
break;
|
|
438
|
+
p = pe;
|
|
439
|
+
continue;
|
|
399
440
|
}
|
|
441
|
+
rb_str_buf_cat(result, unescape, unescape_len);
|
|
442
|
+
p = ++pe;
|
|
400
443
|
} else {
|
|
401
|
-
|
|
402
|
-
while (*q != '\\' && q < pe) q++;
|
|
403
|
-
rb_str_buf_cat(result, p, q - p);
|
|
404
|
-
p = q;
|
|
444
|
+
pe++;
|
|
405
445
|
}
|
|
406
446
|
}
|
|
447
|
+
rb_str_buf_cat(result, p, pe - p);
|
|
407
448
|
return result;
|
|
408
449
|
}
|
|
409
450
|
|
|
@@ -414,15 +455,15 @@ static VALUE json_string_unescape(char *p, char *pe)
|
|
|
414
455
|
write data;
|
|
415
456
|
|
|
416
457
|
action parse_string {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
458
|
+
*result = json_string_unescape(*result, json->memo + 1, p);
|
|
459
|
+
if (NIL_P(*result)) {
|
|
460
|
+
fhold;
|
|
461
|
+
fbreak;
|
|
462
|
+
} else {
|
|
463
|
+
FORCE_UTF8(*result);
|
|
464
|
+
fexec p + 1;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
426
467
|
|
|
427
468
|
action exit { fhold; fbreak; }
|
|
428
469
|
|
|
@@ -433,7 +474,7 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
|
|
|
433
474
|
{
|
|
434
475
|
int cs = EVIL;
|
|
435
476
|
|
|
436
|
-
*result =
|
|
477
|
+
*result = rb_str_buf_new(0);
|
|
437
478
|
%% write init;
|
|
438
479
|
json->memo = p;
|
|
439
480
|
%% write exec;
|
|
@@ -488,7 +529,7 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
|
|
|
488
529
|
*
|
|
489
530
|
*/
|
|
490
531
|
|
|
491
|
-
|
|
532
|
+
static VALUE convert_encoding(VALUE source)
|
|
492
533
|
{
|
|
493
534
|
char *ptr = RSTRING_PTR(source);
|
|
494
535
|
long len = RSTRING_LEN(source);
|
|
@@ -498,28 +539,28 @@ inline static VALUE convert_encoding(VALUE source)
|
|
|
498
539
|
#ifdef HAVE_RUBY_ENCODING_H
|
|
499
540
|
{
|
|
500
541
|
VALUE encoding = rb_funcall(source, i_encoding, 0);
|
|
501
|
-
if (encoding ==
|
|
542
|
+
if (encoding == CEncoding_ASCII_8BIT) {
|
|
502
543
|
if (len >= 4 && ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 0) {
|
|
503
544
|
source = rb_str_dup(source);
|
|
504
|
-
rb_funcall(source, i_force_encoding, 1,
|
|
505
|
-
source = rb_funcall(source, i_encode_bang, 1,
|
|
545
|
+
rb_funcall(source, i_force_encoding, 1, CEncoding_UTF_32BE);
|
|
546
|
+
source = rb_funcall(source, i_encode_bang, 1, CEncoding_UTF_8);
|
|
506
547
|
} else if (len >= 4 && ptr[0] == 0 && ptr[2] == 0) {
|
|
507
548
|
source = rb_str_dup(source);
|
|
508
|
-
rb_funcall(source, i_force_encoding, 1,
|
|
509
|
-
source = rb_funcall(source, i_encode_bang, 1,
|
|
549
|
+
rb_funcall(source, i_force_encoding, 1, CEncoding_UTF_16BE);
|
|
550
|
+
source = rb_funcall(source, i_encode_bang, 1, CEncoding_UTF_8);
|
|
510
551
|
} else if (len >= 4 && ptr[1] == 0 && ptr[2] == 0 && ptr[3] == 0) {
|
|
511
552
|
source = rb_str_dup(source);
|
|
512
|
-
rb_funcall(source, i_force_encoding, 1,
|
|
513
|
-
source = rb_funcall(source, i_encode_bang, 1,
|
|
553
|
+
rb_funcall(source, i_force_encoding, 1, CEncoding_UTF_32LE);
|
|
554
|
+
source = rb_funcall(source, i_encode_bang, 1, CEncoding_UTF_8);
|
|
514
555
|
} else if (len >= 4 && ptr[1] == 0 && ptr[3] == 0) {
|
|
515
556
|
source = rb_str_dup(source);
|
|
516
|
-
rb_funcall(source, i_force_encoding, 1,
|
|
517
|
-
source = rb_funcall(source, i_encode_bang, 1,
|
|
557
|
+
rb_funcall(source, i_force_encoding, 1, CEncoding_UTF_16LE);
|
|
558
|
+
source = rb_funcall(source, i_encode_bang, 1, CEncoding_UTF_8);
|
|
518
559
|
} else {
|
|
519
|
-
|
|
560
|
+
FORCE_UTF8(source);
|
|
520
561
|
}
|
|
521
562
|
} else {
|
|
522
|
-
source = rb_funcall(source, i_encode, 1,
|
|
563
|
+
source = rb_funcall(source, i_encode, 1, CEncoding_UTF_8);
|
|
523
564
|
}
|
|
524
565
|
}
|
|
525
566
|
#else
|
|
@@ -567,7 +608,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
|
|
|
567
608
|
char *ptr;
|
|
568
609
|
long len;
|
|
569
610
|
VALUE source, opts;
|
|
570
|
-
|
|
611
|
+
GET_PARSER;
|
|
571
612
|
rb_scan_args(argc, argv, "11", &source, &opts);
|
|
572
613
|
source = convert_encoding(StringValue(source));
|
|
573
614
|
ptr = RSTRING_PTR(source);
|
|
@@ -652,7 +693,7 @@ static VALUE cParser_parse(VALUE self)
|
|
|
652
693
|
char *p, *pe;
|
|
653
694
|
int cs = EVIL;
|
|
654
695
|
VALUE result = Qnil;
|
|
655
|
-
|
|
696
|
+
GET_PARSER;
|
|
656
697
|
|
|
657
698
|
%% write init;
|
|
658
699
|
p = json->source;
|
|
@@ -663,10 +704,11 @@ static VALUE cParser_parse(VALUE self)
|
|
|
663
704
|
return result;
|
|
664
705
|
} else {
|
|
665
706
|
rb_raise(eParserError, "%u: unexpected token at '%s'", __LINE__, p);
|
|
707
|
+
return Qnil;
|
|
666
708
|
}
|
|
667
709
|
}
|
|
668
710
|
|
|
669
|
-
|
|
711
|
+
static JSON_Parser *JSON_allocate()
|
|
670
712
|
{
|
|
671
713
|
JSON_Parser *json = ALLOC(JSON_Parser);
|
|
672
714
|
MEMZERO(json, JSON_Parser, 1);
|
|
@@ -700,7 +742,7 @@ static VALUE cJSON_parser_s_allocate(VALUE klass)
|
|
|
700
742
|
*/
|
|
701
743
|
static VALUE cParser_source(VALUE self)
|
|
702
744
|
{
|
|
703
|
-
|
|
745
|
+
GET_PARSER;
|
|
704
746
|
return rb_str_dup(json->Vsource);
|
|
705
747
|
}
|
|
706
748
|
|
|
@@ -734,12 +776,12 @@ void Init_parser()
|
|
|
734
776
|
i_key_p = rb_intern("key?");
|
|
735
777
|
i_deep_const_get = rb_intern("deep_const_get");
|
|
736
778
|
#ifdef HAVE_RUBY_ENCODING_H
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
779
|
+
CEncoding_UTF_8 = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-8"));
|
|
780
|
+
CEncoding_UTF_16BE = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-16be"));
|
|
781
|
+
CEncoding_UTF_16LE = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-16le"));
|
|
782
|
+
CEncoding_UTF_32BE = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-32be"));
|
|
783
|
+
CEncoding_UTF_32LE = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("utf-32le"));
|
|
784
|
+
CEncoding_ASCII_8BIT = rb_funcall(rb_path2class("Encoding"), rb_intern("find"), 1, rb_str_new2("ascii-8bit"));
|
|
743
785
|
i_encoding = rb_intern("encoding");
|
|
744
786
|
i_encode = rb_intern("encode");
|
|
745
787
|
i_encode_bang = rb_intern("encode!");
|
data/lib/json/common.rb
CHANGED
|
@@ -11,9 +11,9 @@ module JSON
|
|
|
11
11
|
# generate and parse for their documentation.
|
|
12
12
|
def [](object, opts = {})
|
|
13
13
|
if object.respond_to? :to_str
|
|
14
|
-
JSON.parse(object.to_str, opts
|
|
14
|
+
JSON.parse(object.to_str, opts)
|
|
15
15
|
else
|
|
16
|
-
JSON.generate(object, opts
|
|
16
|
+
JSON.generate(object, opts)
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
|
@@ -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
|
|
67
|
+
const_set :FAST_STATE_PROTOTYPE, State.new(
|
|
68
|
+
:indent => '',
|
|
69
|
+
:space => '',
|
|
70
|
+
:object_nl => "",
|
|
71
|
+
:array_nl => "",
|
|
72
|
+
:max_nesting => false
|
|
73
|
+
)
|
|
74
|
+
const_set :PRETTY_STATE_PROTOTYPE, State.new(
|
|
75
|
+
:indent => ' ',
|
|
76
|
+
:space => ' ',
|
|
77
|
+
:object_nl => "\n",
|
|
78
|
+
:array_nl => "\n"
|
|
79
|
+
)
|
|
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,19 @@ 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
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
198
|
+
def generate(obj, opts = nil)
|
|
199
|
+
state = SAFE_STATE_PROTOTYPE.dup
|
|
200
|
+
if opts
|
|
201
|
+
if opts.respond_to? :to_hash
|
|
202
|
+
opts = opts.to_hash
|
|
203
|
+
elsif opts.respond_to? :to_h
|
|
204
|
+
opts = opts.to_h
|
|
205
|
+
else
|
|
206
|
+
raise TypeError, "can't convert #{opts.class} into Hash"
|
|
207
|
+
end
|
|
208
|
+
state = state.configure(opts)
|
|
195
209
|
end
|
|
196
|
-
|
|
210
|
+
state.generate(obj)
|
|
197
211
|
end
|
|
198
212
|
|
|
199
213
|
# :stopdoc:
|
|
@@ -208,12 +222,19 @@ module JSON
|
|
|
208
222
|
#
|
|
209
223
|
# *WARNING*: Be careful not to pass any Ruby data structures with circles as
|
|
210
224
|
# _obj_ argument, because this will cause JSON to go into an infinite loop.
|
|
211
|
-
def fast_generate(obj)
|
|
212
|
-
|
|
213
|
-
if
|
|
214
|
-
|
|
225
|
+
def fast_generate(obj, opts = nil)
|
|
226
|
+
state = FAST_STATE_PROTOTYPE.dup
|
|
227
|
+
if opts
|
|
228
|
+
if opts.respond_to? :to_hash
|
|
229
|
+
opts = opts.to_hash
|
|
230
|
+
elsif opts.respond_to? :to_h
|
|
231
|
+
opts = opts.to_h
|
|
232
|
+
else
|
|
233
|
+
raise TypeError, "can't convert #{opts.class} into Hash"
|
|
234
|
+
end
|
|
235
|
+
state.configure(opts)
|
|
215
236
|
end
|
|
216
|
-
|
|
237
|
+
state.generate(obj)
|
|
217
238
|
end
|
|
218
239
|
|
|
219
240
|
# :stopdoc:
|
|
@@ -229,13 +250,7 @@ module JSON
|
|
|
229
250
|
# The _opts_ argument can be used to configure the generator, see the
|
|
230
251
|
# generate method for a more detailed explanation.
|
|
231
252
|
def pretty_generate(obj, opts = nil)
|
|
232
|
-
state =
|
|
233
|
-
:indent => ' ',
|
|
234
|
-
:space => ' ',
|
|
235
|
-
:object_nl => "\n",
|
|
236
|
-
:array_nl => "\n",
|
|
237
|
-
:check_circular => true
|
|
238
|
-
)
|
|
253
|
+
state = PRETTY_STATE_PROTOTYPE.dup
|
|
239
254
|
if opts
|
|
240
255
|
if opts.respond_to? :to_hash
|
|
241
256
|
opts = opts.to_hash
|
|
@@ -246,11 +261,7 @@ module JSON
|
|
|
246
261
|
end
|
|
247
262
|
state.configure(opts)
|
|
248
263
|
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
|
|
264
|
+
state.generate(obj)
|
|
254
265
|
end
|
|
255
266
|
|
|
256
267
|
# :stopdoc:
|
|
@@ -360,11 +371,11 @@ module ::Kernel
|
|
|
360
371
|
#
|
|
361
372
|
# The _opts_ argument is passed through to generate/parse respectively, see
|
|
362
373
|
# generate and parse for their documentation.
|
|
363
|
-
def JSON(object,
|
|
374
|
+
def JSON(object, *args)
|
|
364
375
|
if object.respond_to? :to_str
|
|
365
|
-
JSON.parse(object.to_str,
|
|
376
|
+
JSON.parse(object.to_str, args.first)
|
|
366
377
|
else
|
|
367
|
-
JSON.generate(object,
|
|
378
|
+
JSON.generate(object, args.first)
|
|
368
379
|
end
|
|
369
380
|
end
|
|
370
381
|
end
|