json 1.7.0 → 2.3.0
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.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.travis.yml +18 -10
- data/{CHANGES → CHANGES.md} +217 -69
- data/Gemfile +11 -12
- data/{COPYING-json-jruby → LICENSE} +5 -6
- data/{README-json-jruby.markdown → README-json-jruby.md} +0 -0
- data/{README.rdoc → README.md} +188 -137
- data/Rakefile +52 -37
- data/VERSION +1 -1
- data/ext/json/ext/fbuffer/fbuffer.h +38 -7
- data/ext/json/ext/generator/depend +1 -0
- data/ext/json/ext/generator/extconf.rb +1 -10
- data/ext/json/ext/generator/generator.c +239 -133
- data/ext/json/ext/generator/generator.h +35 -26
- data/ext/json/ext/parser/depend +1 -0
- data/ext/json/ext/parser/extconf.rb +2 -9
- data/ext/json/ext/parser/parser.c +446 -514
- data/ext/json/ext/parser/parser.h +23 -9
- data/ext/json/ext/parser/parser.rl +177 -208
- data/ext/json/extconf.rb +2 -0
- data/java/src/json/ext/ByteListTranscoder.java +1 -2
- data/java/src/json/ext/Generator.java +49 -20
- data/java/src/json/ext/GeneratorMethods.java +1 -2
- data/java/src/json/ext/GeneratorService.java +1 -2
- data/java/src/json/ext/GeneratorState.java +25 -57
- data/java/src/json/ext/OptionsReader.java +5 -5
- data/java/src/json/ext/Parser.java +141 -419
- data/java/src/json/ext/Parser.rl +57 -128
- data/java/src/json/ext/ParserService.java +1 -2
- data/java/src/json/ext/RuntimeInfo.java +1 -6
- data/java/src/json/ext/StringDecoder.java +1 -2
- data/java/src/json/ext/StringEncoder.java +5 -0
- data/java/src/json/ext/Utils.java +1 -2
- data/json-java.gemspec +17 -2
- data/json.gemspec +0 -0
- data/json_pure.gemspec +25 -26
- data/lib/json.rb +3 -2
- data/lib/json/add/bigdecimal.rb +10 -2
- data/lib/json/add/complex.rb +9 -2
- data/lib/json/add/core.rb +1 -0
- data/lib/json/add/date.rb +1 -1
- data/lib/json/add/date_time.rb +1 -1
- data/lib/json/add/exception.rb +1 -1
- data/lib/json/add/ostruct.rb +3 -3
- data/lib/json/add/range.rb +1 -1
- data/lib/json/add/rational.rb +8 -2
- data/lib/json/add/regexp.rb +3 -3
- data/lib/json/add/set.rb +29 -0
- data/lib/json/add/struct.rb +1 -1
- data/lib/json/add/symbol.rb +1 -1
- data/lib/json/add/time.rb +6 -3
- data/lib/json/common.rb +51 -66
- data/lib/json/ext.rb +0 -6
- data/lib/json/generic_object.rb +36 -4
- data/lib/json/pure.rb +2 -8
- data/lib/json/pure/generator.rb +106 -119
- data/lib/json/pure/parser.rb +48 -88
- data/lib/json/version.rb +2 -1
- data/references/rfc7159.txt +899 -0
- data/tests/fixtures/fail18.json +1 -1
- data/tests/fixtures/obsolete_fail1.json +1 -0
- data/tests/{test_json_addition.rb → json_addition_test.rb} +53 -38
- data/tests/json_common_interface_test.rb +126 -0
- data/tests/json_encoding_test.rb +107 -0
- data/tests/json_ext_parser_test.rb +15 -0
- data/tests/{test_json_fixtures.rb → json_fixtures_test.rb} +5 -8
- data/tests/json_generator_test.rb +421 -0
- data/tests/json_generic_object_test.rb +82 -0
- data/tests/json_parser_test.rb +472 -0
- data/tests/json_string_matching_test.rb +38 -0
- data/tests/{setup_variant.rb → test_helper.rb} +6 -0
- data/tools/diff.sh +18 -0
- data/tools/fuzz.rb +1 -9
- metadata +49 -72
- data/COPYING +0 -58
- data/GPL +0 -340
- data/TODO +0 -1
- data/data/example.json +0 -1
- data/data/index.html +0 -38
- data/data/prototype.js +0 -4184
- data/tests/fixtures/fail1.json +0 -1
- data/tests/test_json.rb +0 -539
- data/tests/test_json_encoding.rb +0 -65
- data/tests/test_json_generate.rb +0 -251
- data/tests/test_json_generic_object.rb +0 -35
- data/tests/test_json_string_matching.rb +0 -40
- data/tests/test_json_unicode.rb +0 -72
data/Rakefile
CHANGED
@@ -23,8 +23,13 @@ class UndocumentedTestTask < Rake::TestTask
|
|
23
23
|
def desc(*) end
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
|
26
|
+
which = lambda { |c|
|
27
|
+
w = `which #{c}`
|
28
|
+
break w.chomp unless w.empty?
|
29
|
+
}
|
30
|
+
|
31
|
+
MAKE = ENV['MAKE'] || %w[gmake make].find(&which)
|
32
|
+
BUNDLE = ENV['BUNDLE'] || %w[bundle].find(&which)
|
28
33
|
PKG_NAME = 'json'
|
29
34
|
PKG_TITLE = 'JSON Implementation for Ruby'
|
30
35
|
PKG_VERSION = File.read('VERSION').chomp
|
@@ -47,8 +52,8 @@ JAVA_CLASSES = []
|
|
47
52
|
JRUBY_PARSER_JAR = File.expand_path("lib/json/ext/parser.jar")
|
48
53
|
JRUBY_GENERATOR_JAR = File.expand_path("lib/json/ext/generator.jar")
|
49
54
|
|
50
|
-
RAGEL_CODEGEN = %w[rlcodegen rlgen-cd ragel].find
|
51
|
-
RAGEL_DOTGEN = %w[rlgen-dot rlgen-cd ragel].find
|
55
|
+
RAGEL_CODEGEN = %w[rlcodegen rlgen-cd ragel].find(&which)
|
56
|
+
RAGEL_DOTGEN = %w[rlgen-dot rlgen-cd ragel].find(&which)
|
52
57
|
|
53
58
|
desc "Installing library (pure)"
|
54
59
|
task :install_pure => :version do
|
@@ -83,19 +88,19 @@ if defined?(Gem) and defined?(Gem::PackageTask)
|
|
83
88
|
s.files = PKG_FILES
|
84
89
|
|
85
90
|
s.require_path = 'lib'
|
86
|
-
s.add_development_dependency '
|
87
|
-
s.add_development_dependency '
|
88
|
-
s.add_development_dependency 'rake', '~>0.9.2'
|
91
|
+
s.add_development_dependency 'rake'
|
92
|
+
s.add_development_dependency 'test-unit', '~> 2.0'
|
89
93
|
|
90
|
-
s.extra_rdoc_files << 'README.
|
94
|
+
s.extra_rdoc_files << 'README.md'
|
91
95
|
s.rdoc_options <<
|
92
|
-
'--title' << 'JSON implemention for ruby' << '--main' << 'README.
|
96
|
+
'--title' << 'JSON implemention for ruby' << '--main' << 'README.md'
|
93
97
|
s.test_files.concat Dir['./tests/test_*.rb']
|
94
98
|
|
95
99
|
s.author = "Florian Frank"
|
96
100
|
s.email = "flori@ping.de"
|
97
101
|
s.homepage = "http://flori.github.com/#{PKG_NAME}"
|
98
|
-
s.
|
102
|
+
s.license = 'Ruby'
|
103
|
+
s.required_ruby_version = '>= 1.9'
|
99
104
|
end
|
100
105
|
|
101
106
|
desc 'Creates a json_pure.gemspec file'
|
@@ -120,21 +125,20 @@ if defined?(Gem) and defined?(Gem::PackageTask)
|
|
120
125
|
|
121
126
|
s.extensions = FileList['ext/**/extconf.rb']
|
122
127
|
|
123
|
-
s.require_path =
|
124
|
-
s.
|
125
|
-
s.
|
126
|
-
s.add_development_dependency 'permutation'
|
127
|
-
s.add_development_dependency 'sdoc'
|
128
|
+
s.require_path = 'lib'
|
129
|
+
s.add_development_dependency 'rake'
|
130
|
+
s.add_development_dependency 'test-unit', '~> 2.0'
|
128
131
|
|
129
|
-
s.extra_rdoc_files << 'README.
|
132
|
+
s.extra_rdoc_files << 'README.md'
|
130
133
|
s.rdoc_options <<
|
131
|
-
'--title' << 'JSON implemention for Ruby' << '--main' << 'README.
|
134
|
+
'--title' << 'JSON implemention for Ruby' << '--main' << 'README.md'
|
132
135
|
s.test_files.concat Dir['./tests/test_*.rb']
|
133
136
|
|
134
137
|
s.author = "Florian Frank"
|
135
138
|
s.email = "flori@ping.de"
|
136
139
|
s.homepage = "http://flori.github.com/#{PKG_NAME}"
|
137
|
-
s.
|
140
|
+
s.license = 'Ruby'
|
141
|
+
s.required_ruby_version = '>= 1.9'
|
138
142
|
end
|
139
143
|
|
140
144
|
desc 'Creates a json.gemspec file'
|
@@ -159,6 +163,7 @@ task :version do
|
|
159
163
|
puts m
|
160
164
|
File.open(File.join('lib', 'json', 'version.rb'), 'w') do |v|
|
161
165
|
v.puts <<EOT
|
166
|
+
# frozen_string_literal: false
|
162
167
|
module JSON
|
163
168
|
# JSON version
|
164
169
|
VERSION = '#{PKG_VERSION}'
|
@@ -171,13 +176,17 @@ EOT
|
|
171
176
|
end
|
172
177
|
end
|
173
178
|
|
179
|
+
task :check_env do
|
180
|
+
ENV.key?('JSON') or fail "JSON env var is required"
|
181
|
+
end
|
182
|
+
|
174
183
|
desc "Testing library (pure ruby)"
|
175
|
-
task :test_pure => [ :clean, :do_test_pure ]
|
184
|
+
task :test_pure => [ :clean, :check_env, :do_test_pure ]
|
176
185
|
|
177
186
|
UndocumentedTestTask.new do |t|
|
178
187
|
t.name = 'do_test_pure'
|
179
|
-
t.libs << 'lib'
|
180
|
-
t.test_files = FileList['tests
|
188
|
+
t.libs << 'lib' << 'tests'
|
189
|
+
t.test_files = FileList['tests/*_test.rb']
|
181
190
|
t.verbose = true
|
182
191
|
t.options = '-v'
|
183
192
|
end
|
@@ -196,13 +205,18 @@ namespace :gems do
|
|
196
205
|
end
|
197
206
|
|
198
207
|
if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
208
|
+
ENV['JAVA_HOME'] ||= [
|
209
|
+
'/usr/local/java/jdk',
|
210
|
+
'/usr/lib/jvm/java-6-openjdk',
|
211
|
+
'/Library/Java/Home',
|
212
|
+
].find { |c| File.directory?(c) }
|
213
|
+
if ENV['JAVA_HOME']
|
203
214
|
warn " *** JAVA_HOME is set to #{ENV['JAVA_HOME'].inspect}"
|
204
215
|
ENV['PATH'] = ENV['PATH'].split(/:/).unshift(java_path = "#{ENV['JAVA_HOME']}/bin") * ':'
|
205
216
|
warn " *** java binaries are assumed to be in #{java_path.inspect}"
|
217
|
+
else
|
218
|
+
warn " *** JAVA_HOME was not set or could not be guessed!"
|
219
|
+
exit 1
|
206
220
|
end
|
207
221
|
|
208
222
|
file JAVA_PARSER_SRC => JAVA_RAGEL_PATH do
|
@@ -229,7 +243,7 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
|
|
229
243
|
classpath = (Dir['java/lib/*.jar'] << 'java/src' << JRUBY_JAR) * ':'
|
230
244
|
obj = src.sub(/\.java\Z/, '.class')
|
231
245
|
file obj => src do
|
232
|
-
sh 'javac', '-classpath', classpath, '-source', '1.
|
246
|
+
sh 'javac', '-classpath', classpath, '-source', '1.6', '-target', '1.6', src
|
233
247
|
end
|
234
248
|
JAVA_CLASSES << obj
|
235
249
|
end
|
@@ -248,12 +262,12 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
|
|
248
262
|
end
|
249
263
|
|
250
264
|
desc "Testing library (jruby)"
|
251
|
-
task :test_ext => [ :create_jar, :do_test_ext ]
|
265
|
+
task :test_ext => [ :check_env, :create_jar, :do_test_ext ]
|
252
266
|
|
253
267
|
UndocumentedTestTask.new do |t|
|
254
268
|
t.name = 'do_test_ext'
|
255
|
-
t.libs << 'lib'
|
256
|
-
t.test_files = FileList['tests
|
269
|
+
t.libs << 'lib' << 'tests'
|
270
|
+
t.test_files = FileList['tests/*_test.rb']
|
257
271
|
t.verbose = true
|
258
272
|
t.options = '-v'
|
259
273
|
end
|
@@ -322,21 +336,16 @@ else
|
|
322
336
|
end
|
323
337
|
|
324
338
|
desc "Testing library (extension)"
|
325
|
-
task :test_ext => [ :compile, :do_test_ext ]
|
339
|
+
task :test_ext => [ :check_env, :compile, :do_test_ext ]
|
326
340
|
|
327
341
|
UndocumentedTestTask.new do |t|
|
328
342
|
t.name = 'do_test_ext'
|
329
|
-
t.libs << 'ext' << 'lib'
|
330
|
-
t.test_files = FileList['tests
|
343
|
+
t.libs << 'ext' << 'lib' << 'tests'
|
344
|
+
t.test_files = FileList['tests/*_test.rb']
|
331
345
|
t.verbose = true
|
332
346
|
t.options = '-v'
|
333
347
|
end
|
334
348
|
|
335
|
-
desc "Create RDOC documentation"
|
336
|
-
task :doc => [ :version, EXT_PARSER_SRC ] do
|
337
|
-
sh "sdoc -o doc -t '#{PKG_TITLE}' -m README.rdoc README.rdoc lib/json.rb #{FileList['lib/json/**/*.rb']} #{EXT_PARSER_SRC} #{EXT_GENERATOR_SRC}"
|
338
|
-
end
|
339
|
-
|
340
349
|
desc "Generate parser with ragel"
|
341
350
|
task :ragel => EXT_PARSER_SRC
|
342
351
|
|
@@ -345,6 +354,11 @@ else
|
|
345
354
|
rm_rf EXT_PARSER_SRC
|
346
355
|
end
|
347
356
|
|
357
|
+
desc "Update the tags file"
|
358
|
+
task :tags do
|
359
|
+
system 'ctags', *Dir['**/*.{rb,c,h,java}']
|
360
|
+
end
|
361
|
+
|
348
362
|
file EXT_PARSER_SRC => RAGEL_PATH do
|
349
363
|
cd EXT_PARSER_DIR do
|
350
364
|
if RAGEL_CODEGEN == 'ragel'
|
@@ -353,6 +367,7 @@ else
|
|
353
367
|
sh "ragel -x parser.rl | #{RAGEL_CODEGEN} -G2"
|
354
368
|
end
|
355
369
|
src = File.read("parser.c").gsub(/[ \t]+$/, '')
|
370
|
+
src.gsub!(/^static const int (JSON_.*=.*);$/, 'enum {\1};')
|
356
371
|
File.open("parser.c", "w") {|f| f.print src}
|
357
372
|
end
|
358
373
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.3.0
|
@@ -2,9 +2,35 @@
|
|
2
2
|
#ifndef _FBUFFER_H_
|
3
3
|
#define _FBUFFER_H_
|
4
4
|
|
5
|
-
#include <assert.h>
|
6
5
|
#include "ruby.h"
|
7
6
|
|
7
|
+
#ifndef RHASH_SIZE
|
8
|
+
#define RHASH_SIZE(hsh) (RHASH(hsh)->tbl->num_entries)
|
9
|
+
#endif
|
10
|
+
|
11
|
+
#ifndef RFLOAT_VALUE
|
12
|
+
#define RFLOAT_VALUE(val) (RFLOAT(val)->value)
|
13
|
+
#endif
|
14
|
+
|
15
|
+
#ifndef RARRAY_LEN
|
16
|
+
#define RARRAY_LEN(ARRAY) RARRAY(ARRAY)->len
|
17
|
+
#endif
|
18
|
+
#ifndef RSTRING_PTR
|
19
|
+
#define RSTRING_PTR(string) RSTRING(string)->ptr
|
20
|
+
#endif
|
21
|
+
#ifndef RSTRING_LEN
|
22
|
+
#define RSTRING_LEN(string) RSTRING(string)->len
|
23
|
+
#endif
|
24
|
+
|
25
|
+
#ifdef PRIsVALUE
|
26
|
+
# define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
|
27
|
+
# define RB_OBJ_STRING(obj) (obj)
|
28
|
+
#else
|
29
|
+
# define PRIsVALUE "s"
|
30
|
+
# define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
|
31
|
+
# define RB_OBJ_STRING(obj) StringValueCStr(obj)
|
32
|
+
#endif
|
33
|
+
|
8
34
|
#ifdef HAVE_RUBY_ENCODING_H
|
9
35
|
#include "ruby/encoding.h"
|
10
36
|
#define FORCE_UTF8(obj) rb_enc_associate((obj), rb_utf8_encoding())
|
@@ -35,10 +61,14 @@ static FBuffer *fbuffer_alloc(unsigned long initial_length);
|
|
35
61
|
static void fbuffer_free(FBuffer *fb);
|
36
62
|
static void fbuffer_clear(FBuffer *fb);
|
37
63
|
static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len);
|
64
|
+
#ifdef JSON_GENERATOR
|
38
65
|
static void fbuffer_append_long(FBuffer *fb, long number);
|
66
|
+
#endif
|
39
67
|
static void fbuffer_append_char(FBuffer *fb, char newchr);
|
68
|
+
#ifdef JSON_GENERATOR
|
40
69
|
static FBuffer *fbuffer_dup(FBuffer *fb);
|
41
70
|
static VALUE fbuffer_to_s(FBuffer *fb);
|
71
|
+
#endif
|
42
72
|
|
43
73
|
static FBuffer *fbuffer_alloc(unsigned long initial_length)
|
44
74
|
{
|
@@ -87,6 +117,7 @@ static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
|
|
87
117
|
}
|
88
118
|
}
|
89
119
|
|
120
|
+
#ifdef JSON_GENERATOR
|
90
121
|
static void fbuffer_append_str(FBuffer *fb, VALUE str)
|
91
122
|
{
|
92
123
|
const char *newstr = StringValuePtr(str);
|
@@ -96,6 +127,7 @@ static void fbuffer_append_str(FBuffer *fb, VALUE str)
|
|
96
127
|
|
97
128
|
fbuffer_append(fb, newstr, len);
|
98
129
|
}
|
130
|
+
#endif
|
99
131
|
|
100
132
|
static void fbuffer_append_char(FBuffer *fb, char newchr)
|
101
133
|
{
|
@@ -104,6 +136,7 @@ static void fbuffer_append_char(FBuffer *fb, char newchr)
|
|
104
136
|
fb->len++;
|
105
137
|
}
|
106
138
|
|
139
|
+
#ifdef JSON_GENERATOR
|
107
140
|
static void freverse(char *start, char *end)
|
108
141
|
{
|
109
142
|
char c;
|
@@ -138,19 +171,17 @@ static FBuffer *fbuffer_dup(FBuffer *fb)
|
|
138
171
|
unsigned long len = fb->len;
|
139
172
|
FBuffer *result;
|
140
173
|
|
141
|
-
|
142
|
-
|
143
|
-
result = fbuffer_alloc(len);
|
144
|
-
fbuffer_append(result, FBUFFER_PAIR(fb));
|
145
|
-
}
|
174
|
+
result = fbuffer_alloc(len);
|
175
|
+
fbuffer_append(result, FBUFFER_PAIR(fb));
|
146
176
|
return result;
|
147
177
|
}
|
148
178
|
|
149
179
|
static VALUE fbuffer_to_s(FBuffer *fb)
|
150
180
|
{
|
151
|
-
VALUE result = rb_str_new(
|
181
|
+
VALUE result = rb_str_new(FBUFFER_PTR(fb), FBUFFER_LEN(fb));
|
152
182
|
fbuffer_free(fb);
|
153
183
|
FORCE_UTF8(result);
|
154
184
|
return result;
|
155
185
|
}
|
156
186
|
#endif
|
187
|
+
#endif
|
@@ -0,0 +1 @@
|
|
1
|
+
generator.o: generator.c generator.h $(srcdir)/../fbuffer/fbuffer.h
|
@@ -1,13 +1,4 @@
|
|
1
1
|
require 'mkmf'
|
2
2
|
|
3
|
-
|
4
|
-
$CFLAGS << ' -O3'
|
5
|
-
end
|
6
|
-
if CONFIG['CC'] =~ /gcc/
|
7
|
-
$CFLAGS << ' -Wall'
|
8
|
-
unless $DEBUG && !$CFLAGS.gsub!(/ -O[\dsz]?/, ' -O0 -ggdb')
|
9
|
-
$CFLAGS << ' -O0 -ggdb'
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
3
|
+
$defs << "-DJSON_GENERATOR"
|
13
4
|
create_makefile 'json/ext/generator'
|
@@ -7,14 +7,20 @@ static ID i_encoding, i_encode;
|
|
7
7
|
#endif
|
8
8
|
|
9
9
|
static VALUE mJSON, mExt, mGenerator, cState, mGeneratorMethods, mObject,
|
10
|
-
mHash, mArray,
|
10
|
+
mHash, mArray,
|
11
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
12
|
+
mInteger,
|
13
|
+
#else
|
14
|
+
mFixnum, mBignum,
|
15
|
+
#endif
|
16
|
+
mFloat, mString, mString_Extend,
|
11
17
|
mTrueClass, mFalseClass, mNilClass, eGeneratorError,
|
12
|
-
eNestingError,
|
18
|
+
eNestingError,
|
13
19
|
i_SAFE_STATE_PROTOTYPE;
|
14
20
|
|
15
21
|
static ID i_to_s, i_to_json, i_new, i_indent, i_space, i_space_before,
|
16
22
|
i_object_nl, i_array_nl, i_max_nesting, i_allow_nan, i_ascii_only,
|
17
|
-
|
23
|
+
i_pack, i_unpack, i_create_id, i_extend, i_key_p,
|
18
24
|
i_aref, i_send, i_respond_to_p, i_match, i_keys, i_depth,
|
19
25
|
i_buffer_initial_length, i_dup;
|
20
26
|
|
@@ -216,6 +222,7 @@ static void convert_UTF8_to_JSON_ASCII(FBuffer *buffer, VALUE string)
|
|
216
222
|
unicode_escape_to_buffer(buffer, buf, (UTF16)((ch & halfMask) + UNI_SUR_LOW_START));
|
217
223
|
}
|
218
224
|
}
|
225
|
+
RB_GC_GUARD(string);
|
219
226
|
}
|
220
227
|
|
221
228
|
/* Converts string to a JSON string in FBuffer buffer, where only the
|
@@ -230,6 +237,7 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
|
|
230
237
|
int escape_len;
|
231
238
|
unsigned char c;
|
232
239
|
char buf[6] = { '\\', 'u' };
|
240
|
+
int ascii_only = rb_enc_str_asciionly_p(string);
|
233
241
|
|
234
242
|
for (start = 0, end = 0; end < len;) {
|
235
243
|
p = ptr + end;
|
@@ -273,7 +281,21 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
|
|
273
281
|
escape_len = 2;
|
274
282
|
break;
|
275
283
|
default:
|
276
|
-
|
284
|
+
{
|
285
|
+
unsigned short clen = 1;
|
286
|
+
if (!ascii_only) {
|
287
|
+
clen += trailingBytesForUTF8[c];
|
288
|
+
if (end + clen > len) {
|
289
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
290
|
+
"partial character in source, but hit end");
|
291
|
+
}
|
292
|
+
if (!isLegalUTF8((UTF8 *) p, clen)) {
|
293
|
+
rb_raise(rb_path2class("JSON::GeneratorError"),
|
294
|
+
"source sequence is illegal/malformed utf-8");
|
295
|
+
}
|
296
|
+
}
|
297
|
+
end += clen;
|
298
|
+
}
|
277
299
|
continue;
|
278
300
|
break;
|
279
301
|
}
|
@@ -290,7 +312,7 @@ static char *fstrndup(const char *ptr, unsigned long len) {
|
|
290
312
|
char *result;
|
291
313
|
if (len <= 0) return NULL;
|
292
314
|
result = ALLOC_N(char, len);
|
293
|
-
|
315
|
+
memcpy(result, ptr, len);
|
294
316
|
return result;
|
295
317
|
}
|
296
318
|
|
@@ -331,6 +353,18 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
|
|
331
353
|
GENERATE_JSON(array);
|
332
354
|
}
|
333
355
|
|
356
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
357
|
+
/*
|
358
|
+
* call-seq: to_json(*)
|
359
|
+
*
|
360
|
+
* Returns a JSON string representation for this Integer number.
|
361
|
+
*/
|
362
|
+
static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
|
363
|
+
{
|
364
|
+
GENERATE_JSON(integer);
|
365
|
+
}
|
366
|
+
|
367
|
+
#else
|
334
368
|
/*
|
335
369
|
* call-seq: to_json(*)
|
336
370
|
*
|
@@ -350,6 +384,7 @@ static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
|
|
350
384
|
{
|
351
385
|
GENERATE_JSON(bignum);
|
352
386
|
}
|
387
|
+
#endif
|
353
388
|
|
354
389
|
/*
|
355
390
|
* call-seq: to_json(*)
|
@@ -475,8 +510,9 @@ static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
|
|
475
510
|
return cState_partial_generate(state, string);
|
476
511
|
}
|
477
512
|
|
478
|
-
static void State_free(
|
513
|
+
static void State_free(void *ptr)
|
479
514
|
{
|
515
|
+
JSON_Generator_State *state = ptr;
|
480
516
|
if (state->indent) ruby_xfree(state->indent);
|
481
517
|
if (state->space) ruby_xfree(state->space);
|
482
518
|
if (state->space_before) ruby_xfree(state->space_before);
|
@@ -488,17 +524,37 @@ static void State_free(JSON_Generator_State *state)
|
|
488
524
|
ruby_xfree(state);
|
489
525
|
}
|
490
526
|
|
491
|
-
static
|
527
|
+
static size_t State_memsize(const void *ptr)
|
492
528
|
{
|
493
|
-
JSON_Generator_State *state =
|
494
|
-
|
495
|
-
|
496
|
-
|
529
|
+
const JSON_Generator_State *state = ptr;
|
530
|
+
size_t size = sizeof(*state);
|
531
|
+
if (state->indent) size += state->indent_len + 1;
|
532
|
+
if (state->space) size += state->space_len + 1;
|
533
|
+
if (state->space_before) size += state->space_before_len + 1;
|
534
|
+
if (state->object_nl) size += state->object_nl_len + 1;
|
535
|
+
if (state->array_nl) size += state->array_nl_len + 1;
|
536
|
+
if (state->array_delim) size += FBUFFER_CAPA(state->array_delim);
|
537
|
+
if (state->object_delim) size += FBUFFER_CAPA(state->object_delim);
|
538
|
+
if (state->object_delim2) size += FBUFFER_CAPA(state->object_delim2);
|
539
|
+
return size;
|
540
|
+
}
|
541
|
+
|
542
|
+
#ifdef NEW_TYPEDDATA_WRAPPER
|
543
|
+
static const rb_data_type_t JSON_Generator_State_type = {
|
544
|
+
"JSON/Generator/State",
|
545
|
+
{NULL, State_free, State_memsize,},
|
546
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
547
|
+
0, 0,
|
548
|
+
RUBY_TYPED_FREE_IMMEDIATELY,
|
549
|
+
#endif
|
550
|
+
};
|
551
|
+
#endif
|
497
552
|
|
498
553
|
static VALUE cState_s_allocate(VALUE klass)
|
499
554
|
{
|
500
|
-
JSON_Generator_State *state
|
501
|
-
return
|
555
|
+
JSON_Generator_State *state;
|
556
|
+
return TypedData_Make_Struct(klass, JSON_Generator_State,
|
557
|
+
&JSON_Generator_State_type, state);
|
502
558
|
}
|
503
559
|
|
504
560
|
/*
|
@@ -511,18 +567,15 @@ static VALUE cState_configure(VALUE self, VALUE opts)
|
|
511
567
|
{
|
512
568
|
VALUE tmp;
|
513
569
|
GET_STATE(self);
|
514
|
-
tmp =
|
570
|
+
tmp = rb_check_convert_type(opts, T_HASH, "Hash", "to_hash");
|
515
571
|
if (NIL_P(tmp)) tmp = rb_convert_type(opts, T_HASH, "Hash", "to_h");
|
516
|
-
if (NIL_P(tmp)) {
|
517
|
-
rb_raise(rb_eArgError, "opts has to be hash like or convertable into a hash");
|
518
|
-
}
|
519
572
|
opts = tmp;
|
520
573
|
tmp = rb_hash_aref(opts, ID2SYM(i_indent));
|
521
574
|
if (RTEST(tmp)) {
|
522
575
|
unsigned long len;
|
523
576
|
Check_Type(tmp, T_STRING);
|
524
577
|
len = RSTRING_LEN(tmp);
|
525
|
-
state->indent = fstrndup(RSTRING_PTR(tmp), len);
|
578
|
+
state->indent = fstrndup(RSTRING_PTR(tmp), len + 1);
|
526
579
|
state->indent_len = len;
|
527
580
|
}
|
528
581
|
tmp = rb_hash_aref(opts, ID2SYM(i_space));
|
@@ -530,7 +583,7 @@ static VALUE cState_configure(VALUE self, VALUE opts)
|
|
530
583
|
unsigned long len;
|
531
584
|
Check_Type(tmp, T_STRING);
|
532
585
|
len = RSTRING_LEN(tmp);
|
533
|
-
state->space = fstrndup(RSTRING_PTR(tmp), len);
|
586
|
+
state->space = fstrndup(RSTRING_PTR(tmp), len + 1);
|
534
587
|
state->space_len = len;
|
535
588
|
}
|
536
589
|
tmp = rb_hash_aref(opts, ID2SYM(i_space_before));
|
@@ -538,7 +591,7 @@ static VALUE cState_configure(VALUE self, VALUE opts)
|
|
538
591
|
unsigned long len;
|
539
592
|
Check_Type(tmp, T_STRING);
|
540
593
|
len = RSTRING_LEN(tmp);
|
541
|
-
state->space_before = fstrndup(RSTRING_PTR(tmp), len);
|
594
|
+
state->space_before = fstrndup(RSTRING_PTR(tmp), len + 1);
|
542
595
|
state->space_before_len = len;
|
543
596
|
}
|
544
597
|
tmp = rb_hash_aref(opts, ID2SYM(i_array_nl));
|
@@ -546,7 +599,7 @@ static VALUE cState_configure(VALUE self, VALUE opts)
|
|
546
599
|
unsigned long len;
|
547
600
|
Check_Type(tmp, T_STRING);
|
548
601
|
len = RSTRING_LEN(tmp);
|
549
|
-
state->array_nl = fstrndup(RSTRING_PTR(tmp), len);
|
602
|
+
state->array_nl = fstrndup(RSTRING_PTR(tmp), len + 1);
|
550
603
|
state->array_nl_len = len;
|
551
604
|
}
|
552
605
|
tmp = rb_hash_aref(opts, ID2SYM(i_object_nl));
|
@@ -554,11 +607,11 @@ static VALUE cState_configure(VALUE self, VALUE opts)
|
|
554
607
|
unsigned long len;
|
555
608
|
Check_Type(tmp, T_STRING);
|
556
609
|
len = RSTRING_LEN(tmp);
|
557
|
-
state->object_nl = fstrndup(RSTRING_PTR(tmp), len);
|
610
|
+
state->object_nl = fstrndup(RSTRING_PTR(tmp), len + 1);
|
558
611
|
state->object_nl_len = len;
|
559
612
|
}
|
560
613
|
tmp = ID2SYM(i_max_nesting);
|
561
|
-
state->max_nesting =
|
614
|
+
state->max_nesting = 100;
|
562
615
|
if (option_given_p(opts, tmp)) {
|
563
616
|
VALUE max_nesting = rb_hash_aref(opts, tmp);
|
564
617
|
if (RTEST(max_nesting)) {
|
@@ -593,11 +646,21 @@ static VALUE cState_configure(VALUE self, VALUE opts)
|
|
593
646
|
state->allow_nan = RTEST(tmp);
|
594
647
|
tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
|
595
648
|
state->ascii_only = RTEST(tmp);
|
596
|
-
tmp = rb_hash_aref(opts, ID2SYM(i_quirks_mode));
|
597
|
-
state->quirks_mode = RTEST(tmp);
|
598
649
|
return self;
|
599
650
|
}
|
600
651
|
|
652
|
+
static void set_state_ivars(VALUE hash, VALUE state)
|
653
|
+
{
|
654
|
+
VALUE ivars = rb_obj_instance_variables(state);
|
655
|
+
int i = 0;
|
656
|
+
for (i = 0; i < RARRAY_LEN(ivars); i++) {
|
657
|
+
VALUE key = rb_funcall(rb_ary_entry(ivars, i), i_to_s, 0);
|
658
|
+
long key_len = RSTRING_LEN(key);
|
659
|
+
VALUE value = rb_iv_get(state, StringValueCStr(key));
|
660
|
+
rb_hash_aset(hash, rb_str_intern(rb_str_substr(key, 1, key_len - 1)), value);
|
661
|
+
}
|
662
|
+
}
|
663
|
+
|
601
664
|
/*
|
602
665
|
* call-seq: to_h
|
603
666
|
*
|
@@ -608,6 +671,7 @@ static VALUE cState_to_h(VALUE self)
|
|
608
671
|
{
|
609
672
|
VALUE result = rb_hash_new();
|
610
673
|
GET_STATE(self);
|
674
|
+
set_state_ivars(result, self);
|
611
675
|
rb_hash_aset(result, ID2SYM(i_indent), rb_str_new(state->indent, state->indent_len));
|
612
676
|
rb_hash_aset(result, ID2SYM(i_space), rb_str_new(state->space, state->space_len));
|
613
677
|
rb_hash_aset(result, ID2SYM(i_space_before), rb_str_new(state->space_before, state->space_before_len));
|
@@ -615,7 +679,6 @@ static VALUE cState_to_h(VALUE self)
|
|
615
679
|
rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len));
|
616
680
|
rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
|
617
681
|
rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
|
618
|
-
rb_hash_aset(result, ID2SYM(i_quirks_mode), state->quirks_mode ? Qtrue : Qfalse);
|
619
682
|
rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
|
620
683
|
rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
|
621
684
|
rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
|
@@ -625,55 +688,114 @@ static VALUE cState_to_h(VALUE self)
|
|
625
688
|
/*
|
626
689
|
* call-seq: [](name)
|
627
690
|
*
|
628
|
-
*
|
691
|
+
* Returns the value returned by method +name+.
|
629
692
|
*/
|
630
693
|
static VALUE cState_aref(VALUE self, VALUE name)
|
631
694
|
{
|
632
|
-
|
695
|
+
name = rb_funcall(name, i_to_s, 0);
|
633
696
|
if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
|
634
697
|
return rb_funcall(self, i_send, 1, name);
|
635
698
|
} else {
|
636
|
-
return
|
699
|
+
return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
|
637
700
|
}
|
638
701
|
}
|
639
702
|
|
640
|
-
|
703
|
+
/*
|
704
|
+
* call-seq: []=(name, value)
|
705
|
+
*
|
706
|
+
* Sets the attribute name to value.
|
707
|
+
*/
|
708
|
+
static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
|
641
709
|
{
|
710
|
+
VALUE name_writer;
|
711
|
+
|
712
|
+
name = rb_funcall(name, i_to_s, 0);
|
713
|
+
name_writer = rb_str_cat2(rb_str_dup(name), "=");
|
714
|
+
if (RTEST(rb_funcall(self, i_respond_to_p, 1, name_writer))) {
|
715
|
+
return rb_funcall(self, i_send, 2, name_writer, value);
|
716
|
+
} else {
|
717
|
+
rb_ivar_set(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)), value);
|
718
|
+
}
|
719
|
+
return Qnil;
|
720
|
+
}
|
721
|
+
|
722
|
+
struct hash_foreach_arg {
|
723
|
+
FBuffer *buffer;
|
724
|
+
JSON_Generator_State *state;
|
725
|
+
VALUE Vstate;
|
726
|
+
int iter;
|
727
|
+
};
|
728
|
+
|
729
|
+
static int
|
730
|
+
json_object_i(VALUE key, VALUE val, VALUE _arg)
|
731
|
+
{
|
732
|
+
struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
|
733
|
+
FBuffer *buffer = arg->buffer;
|
734
|
+
JSON_Generator_State *state = arg->state;
|
735
|
+
VALUE Vstate = arg->Vstate;
|
736
|
+
|
642
737
|
char *object_nl = state->object_nl;
|
643
738
|
long object_nl_len = state->object_nl_len;
|
644
739
|
char *indent = state->indent;
|
645
740
|
long indent_len = state->indent_len;
|
646
|
-
long max_nesting = state->max_nesting;
|
647
741
|
char *delim = FBUFFER_PTR(state->object_delim);
|
648
742
|
long delim_len = FBUFFER_LEN(state->object_delim);
|
649
743
|
char *delim2 = FBUFFER_PTR(state->object_delim2);
|
650
744
|
long delim2_len = FBUFFER_LEN(state->object_delim2);
|
745
|
+
long depth = state->depth;
|
746
|
+
int j;
|
747
|
+
VALUE klass, key_to_s;
|
748
|
+
|
749
|
+
if (arg->iter > 0) fbuffer_append(buffer, delim, delim_len);
|
750
|
+
if (object_nl) {
|
751
|
+
fbuffer_append(buffer, object_nl, object_nl_len);
|
752
|
+
}
|
753
|
+
if (indent) {
|
754
|
+
for (j = 0; j < depth; j++) {
|
755
|
+
fbuffer_append(buffer, indent, indent_len);
|
756
|
+
}
|
757
|
+
}
|
758
|
+
|
759
|
+
klass = CLASS_OF(key);
|
760
|
+
if (klass == rb_cString) {
|
761
|
+
key_to_s = key;
|
762
|
+
} else if (klass == rb_cSymbol) {
|
763
|
+
key_to_s = rb_id2str(SYM2ID(key));
|
764
|
+
} else {
|
765
|
+
key_to_s = rb_funcall(key, i_to_s, 0);
|
766
|
+
}
|
767
|
+
Check_Type(key_to_s, T_STRING);
|
768
|
+
generate_json(buffer, Vstate, state, key_to_s);
|
769
|
+
fbuffer_append(buffer, delim2, delim2_len);
|
770
|
+
generate_json(buffer, Vstate, state, val);
|
771
|
+
|
772
|
+
arg->iter++;
|
773
|
+
return ST_CONTINUE;
|
774
|
+
}
|
775
|
+
|
776
|
+
static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
777
|
+
{
|
778
|
+
char *object_nl = state->object_nl;
|
779
|
+
long object_nl_len = state->object_nl_len;
|
780
|
+
char *indent = state->indent;
|
781
|
+
long indent_len = state->indent_len;
|
782
|
+
long max_nesting = state->max_nesting;
|
651
783
|
long depth = ++state->depth;
|
652
|
-
int
|
653
|
-
|
784
|
+
int j;
|
785
|
+
struct hash_foreach_arg arg;
|
786
|
+
|
654
787
|
if (max_nesting != 0 && depth > max_nesting) {
|
655
788
|
fbuffer_free(buffer);
|
656
789
|
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
657
790
|
}
|
658
791
|
fbuffer_append_char(buffer, '{');
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
for (j = 0; j < depth; j++) {
|
667
|
-
fbuffer_append(buffer, indent, indent_len);
|
668
|
-
}
|
669
|
-
}
|
670
|
-
key = rb_ary_entry(keys, i);
|
671
|
-
key_to_s = rb_funcall(key, i_to_s, 0);
|
672
|
-
Check_Type(key_to_s, T_STRING);
|
673
|
-
generate_json(buffer, Vstate, state, key_to_s);
|
674
|
-
fbuffer_append(buffer, delim2, delim2_len);
|
675
|
-
generate_json(buffer, Vstate, state, rb_hash_aref(obj, key));
|
676
|
-
}
|
792
|
+
|
793
|
+
arg.buffer = buffer;
|
794
|
+
arg.state = state;
|
795
|
+
arg.Vstate = Vstate;
|
796
|
+
arg.iter = 0;
|
797
|
+
rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
|
798
|
+
|
677
799
|
depth = --state->depth;
|
678
800
|
if (object_nl) {
|
679
801
|
fbuffer_append(buffer, object_nl, object_nl_len);
|
@@ -724,11 +846,22 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
|
|
724
846
|
fbuffer_append_char(buffer, ']');
|
725
847
|
}
|
726
848
|
|
849
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
850
|
+
static int enc_utf8_compatible_p(rb_encoding *enc)
|
851
|
+
{
|
852
|
+
if (enc == rb_usascii_encoding()) return 1;
|
853
|
+
if (enc == rb_utf8_encoding()) return 1;
|
854
|
+
return 0;
|
855
|
+
}
|
856
|
+
#endif
|
857
|
+
|
727
858
|
static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
728
859
|
{
|
729
860
|
fbuffer_append_char(buffer, '"');
|
730
861
|
#ifdef HAVE_RUBY_ENCODING_H
|
731
|
-
|
862
|
+
if (!enc_utf8_compatible_p(rb_enc_get(obj))) {
|
863
|
+
obj = rb_str_encode(obj, CEncoding_UTF_8, 0, Qnil);
|
864
|
+
}
|
732
865
|
#endif
|
733
866
|
if (state->ascii_only) {
|
734
867
|
convert_UTF8_to_JSON_ASCII(buffer, obj);
|
@@ -764,6 +897,15 @@ static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
|
|
764
897
|
fbuffer_append_str(buffer, tmp);
|
765
898
|
}
|
766
899
|
|
900
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
901
|
+
static void generate_json_integer(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
902
|
+
{
|
903
|
+
if (FIXNUM_P(obj))
|
904
|
+
generate_json_fixnum(buffer, Vstate, state, obj);
|
905
|
+
else
|
906
|
+
generate_json_bignum(buffer, Vstate, state, obj);
|
907
|
+
}
|
908
|
+
#endif
|
767
909
|
static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
768
910
|
{
|
769
911
|
double value = RFLOAT_VALUE(obj);
|
@@ -772,10 +914,10 @@ static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
|
|
772
914
|
if (!allow_nan) {
|
773
915
|
if (isinf(value)) {
|
774
916
|
fbuffer_free(buffer);
|
775
|
-
rb_raise(eGeneratorError, "%u: %
|
917
|
+
rb_raise(eGeneratorError, "%u: %"PRIsVALUE" not allowed in JSON", __LINE__, RB_OBJ_STRING(tmp));
|
776
918
|
} else if (isnan(value)) {
|
777
919
|
fbuffer_free(buffer);
|
778
|
-
rb_raise(eGeneratorError, "%u: %
|
920
|
+
rb_raise(eGeneratorError, "%u: %"PRIsVALUE" not allowed in JSON", __LINE__, RB_OBJ_STRING(tmp));
|
779
921
|
}
|
780
922
|
}
|
781
923
|
fbuffer_append_str(buffer, tmp);
|
@@ -797,9 +939,9 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
|
|
797
939
|
generate_json_false(buffer, Vstate, state, obj);
|
798
940
|
} else if (obj == Qtrue) {
|
799
941
|
generate_json_true(buffer, Vstate, state, obj);
|
800
|
-
} else if (
|
942
|
+
} else if (FIXNUM_P(obj)) {
|
801
943
|
generate_json_fixnum(buffer, Vstate, state, obj);
|
802
|
-
} else if (
|
944
|
+
} else if (RB_TYPE_P(obj, T_BIGNUM)) {
|
803
945
|
generate_json_bignum(buffer, Vstate, state, obj);
|
804
946
|
} else if (klass == rb_cFloat) {
|
805
947
|
generate_json_float(buffer, Vstate, state, obj);
|
@@ -810,7 +952,7 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
|
|
810
952
|
} else {
|
811
953
|
tmp = rb_funcall(obj, i_to_s, 0);
|
812
954
|
Check_Type(tmp, T_STRING);
|
813
|
-
|
955
|
+
generate_json_string(buffer, Vstate, state, tmp);
|
814
956
|
}
|
815
957
|
}
|
816
958
|
|
@@ -831,6 +973,7 @@ static FBuffer *cState_prepare_buffer(VALUE self)
|
|
831
973
|
} else {
|
832
974
|
state->object_delim2 = fbuffer_alloc(16);
|
833
975
|
}
|
976
|
+
if (state->space_before) fbuffer_append(state->object_delim2, state->space_before, state->space_before_len);
|
834
977
|
fbuffer_append_char(state->object_delim2, ':');
|
835
978
|
if (state->space) fbuffer_append(state->object_delim2, state->space, state->space_len);
|
836
979
|
|
@@ -852,21 +995,6 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj)
|
|
852
995
|
return fbuffer_to_s(buffer);
|
853
996
|
}
|
854
997
|
|
855
|
-
/*
|
856
|
-
* This function returns true if string is either a JSON array or JSON object.
|
857
|
-
* It might suffer from false positives, e. g. syntactically incorrect JSON in
|
858
|
-
* the string or certain UTF-8 characters on the right hand side.
|
859
|
-
*/
|
860
|
-
static int isArrayOrObject(VALUE string)
|
861
|
-
{
|
862
|
-
long string_len = RSTRING_LEN(string);
|
863
|
-
char *p = RSTRING_PTR(string), *q = p + string_len - 1;
|
864
|
-
if (string_len < 2) return 0;
|
865
|
-
for (; p < q && isspace(*p); p++);
|
866
|
-
for (; q > p && isspace(*q); q--);
|
867
|
-
return *p == '[' && *q == ']' || *p == '{' && *q == '}';
|
868
|
-
}
|
869
|
-
|
870
998
|
/*
|
871
999
|
* call-seq: generate(obj)
|
872
1000
|
*
|
@@ -878,9 +1006,7 @@ static VALUE cState_generate(VALUE self, VALUE obj)
|
|
878
1006
|
{
|
879
1007
|
VALUE result = cState_partial_generate(self, obj);
|
880
1008
|
GET_STATE(self);
|
881
|
-
|
882
|
-
rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed");
|
883
|
-
}
|
1009
|
+
(void)state;
|
884
1010
|
return result;
|
885
1011
|
}
|
886
1012
|
|
@@ -899,8 +1025,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
|
|
899
1025
|
* * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
900
1026
|
* generated, otherwise an exception is thrown, if these values are
|
901
1027
|
* encountered. This options defaults to false.
|
902
|
-
* * *
|
903
|
-
*
|
1028
|
+
* * *ascii_only*: true if only ASCII characters should be generated. This
|
1029
|
+
* ontions defaults to false.
|
904
1030
|
* * *buffer_initial_length*: sets the initial length of the generator's
|
905
1031
|
* internal buffer.
|
906
1032
|
*/
|
@@ -908,7 +1034,7 @@ static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
|
|
908
1034
|
{
|
909
1035
|
VALUE opts;
|
910
1036
|
GET_STATE(self);
|
911
|
-
state->max_nesting =
|
1037
|
+
state->max_nesting = 100;
|
912
1038
|
state->buffer_initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
|
913
1039
|
rb_scan_args(argc, argv, "01", &opts);
|
914
1040
|
if (!NIL_P(opts)) cState_configure(self, opts);
|
@@ -918,15 +1044,16 @@ static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
|
|
918
1044
|
/*
|
919
1045
|
* call-seq: initialize_copy(orig)
|
920
1046
|
*
|
921
|
-
* Initializes this object from orig if it
|
1047
|
+
* Initializes this object from orig if it can be duplicated/cloned and returns
|
922
1048
|
* it.
|
923
1049
|
*/
|
924
1050
|
static VALUE cState_init_copy(VALUE obj, VALUE orig)
|
925
1051
|
{
|
926
1052
|
JSON_Generator_State *objState, *origState;
|
927
1053
|
|
928
|
-
|
929
|
-
|
1054
|
+
if (obj == orig) return obj;
|
1055
|
+
GET_STATE_TO(obj, objState);
|
1056
|
+
GET_STATE_TO(orig, origState);
|
930
1057
|
if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
|
931
1058
|
|
932
1059
|
MEMCPY(objState, origState, JSON_Generator_State, 1);
|
@@ -955,28 +1082,26 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
|
|
955
1082
|
} else if (rb_obj_is_kind_of(opts, rb_cHash)) {
|
956
1083
|
return rb_funcall(self, i_new, 1, opts);
|
957
1084
|
} else {
|
958
|
-
|
959
|
-
|
960
|
-
}
|
961
|
-
return rb_funcall(CJSON_SAFE_STATE_PROTOTYPE, i_dup, 0);
|
1085
|
+
VALUE prototype = rb_const_get(mJSON, i_SAFE_STATE_PROTOTYPE);
|
1086
|
+
return rb_funcall(prototype, i_dup, 0);
|
962
1087
|
}
|
963
1088
|
}
|
964
1089
|
|
965
1090
|
/*
|
966
1091
|
* call-seq: indent()
|
967
1092
|
*
|
968
|
-
*
|
1093
|
+
* Returns the string that is used to indent levels in the JSON text.
|
969
1094
|
*/
|
970
1095
|
static VALUE cState_indent(VALUE self)
|
971
1096
|
{
|
972
1097
|
GET_STATE(self);
|
973
|
-
return state->indent ?
|
1098
|
+
return state->indent ? rb_str_new(state->indent, state->indent_len) : rb_str_new2("");
|
974
1099
|
}
|
975
1100
|
|
976
1101
|
/*
|
977
1102
|
* call-seq: indent=(indent)
|
978
1103
|
*
|
979
|
-
*
|
1104
|
+
* Sets the string that is used to indent levels in the JSON text.
|
980
1105
|
*/
|
981
1106
|
static VALUE cState_indent_set(VALUE self, VALUE indent)
|
982
1107
|
{
|
@@ -992,7 +1117,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
|
|
992
1117
|
}
|
993
1118
|
} else {
|
994
1119
|
if (state->indent) ruby_xfree(state->indent);
|
995
|
-
state->indent =
|
1120
|
+
state->indent = fstrndup(RSTRING_PTR(indent), len);
|
996
1121
|
state->indent_len = len;
|
997
1122
|
}
|
998
1123
|
return Qnil;
|
@@ -1001,19 +1126,19 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
|
|
1001
1126
|
/*
|
1002
1127
|
* call-seq: space()
|
1003
1128
|
*
|
1004
|
-
*
|
1129
|
+
* Returns the string that is used to insert a space between the tokens in a JSON
|
1005
1130
|
* string.
|
1006
1131
|
*/
|
1007
1132
|
static VALUE cState_space(VALUE self)
|
1008
1133
|
{
|
1009
1134
|
GET_STATE(self);
|
1010
|
-
return state->space ?
|
1135
|
+
return state->space ? rb_str_new(state->space, state->space_len) : rb_str_new2("");
|
1011
1136
|
}
|
1012
1137
|
|
1013
1138
|
/*
|
1014
1139
|
* call-seq: space=(space)
|
1015
1140
|
*
|
1016
|
-
*
|
1141
|
+
* Sets _space_ to the string that is used to insert a space between the tokens in a JSON
|
1017
1142
|
* string.
|
1018
1143
|
*/
|
1019
1144
|
static VALUE cState_space_set(VALUE self, VALUE space)
|
@@ -1030,7 +1155,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
|
|
1030
1155
|
}
|
1031
1156
|
} else {
|
1032
1157
|
if (state->space) ruby_xfree(state->space);
|
1033
|
-
state->space =
|
1158
|
+
state->space = fstrndup(RSTRING_PTR(space), len);
|
1034
1159
|
state->space_len = len;
|
1035
1160
|
}
|
1036
1161
|
return Qnil;
|
@@ -1039,18 +1164,18 @@ static VALUE cState_space_set(VALUE self, VALUE space)
|
|
1039
1164
|
/*
|
1040
1165
|
* call-seq: space_before()
|
1041
1166
|
*
|
1042
|
-
*
|
1167
|
+
* Returns the string that is used to insert a space before the ':' in JSON objects.
|
1043
1168
|
*/
|
1044
1169
|
static VALUE cState_space_before(VALUE self)
|
1045
1170
|
{
|
1046
1171
|
GET_STATE(self);
|
1047
|
-
return state->space_before ?
|
1172
|
+
return state->space_before ? rb_str_new(state->space_before, state->space_before_len) : rb_str_new2("");
|
1048
1173
|
}
|
1049
1174
|
|
1050
1175
|
/*
|
1051
1176
|
* call-seq: space_before=(space_before)
|
1052
1177
|
*
|
1053
|
-
*
|
1178
|
+
* Sets the string that is used to insert a space before the ':' in JSON objects.
|
1054
1179
|
*/
|
1055
1180
|
static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
1056
1181
|
{
|
@@ -1066,7 +1191,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
1066
1191
|
}
|
1067
1192
|
} else {
|
1068
1193
|
if (state->space_before) ruby_xfree(state->space_before);
|
1069
|
-
state->space_before =
|
1194
|
+
state->space_before = fstrndup(RSTRING_PTR(space_before), len);
|
1070
1195
|
state->space_before_len = len;
|
1071
1196
|
}
|
1072
1197
|
return Qnil;
|
@@ -1081,7 +1206,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
1081
1206
|
static VALUE cState_object_nl(VALUE self)
|
1082
1207
|
{
|
1083
1208
|
GET_STATE(self);
|
1084
|
-
return state->object_nl ?
|
1209
|
+
return state->object_nl ? rb_str_new(state->object_nl, state->object_nl_len) : rb_str_new2("");
|
1085
1210
|
}
|
1086
1211
|
|
1087
1212
|
/*
|
@@ -1103,7 +1228,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
1103
1228
|
}
|
1104
1229
|
} else {
|
1105
1230
|
if (state->object_nl) ruby_xfree(state->object_nl);
|
1106
|
-
state->object_nl =
|
1231
|
+
state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
|
1107
1232
|
state->object_nl_len = len;
|
1108
1233
|
}
|
1109
1234
|
return Qnil;
|
@@ -1117,7 +1242,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
1117
1242
|
static VALUE cState_array_nl(VALUE self)
|
1118
1243
|
{
|
1119
1244
|
GET_STATE(self);
|
1120
|
-
return state->array_nl ?
|
1245
|
+
return state->array_nl ? rb_str_new(state->array_nl, state->array_nl_len) : rb_str_new2("");
|
1121
1246
|
}
|
1122
1247
|
|
1123
1248
|
/*
|
@@ -1138,7 +1263,7 @@ static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
|
|
1138
1263
|
}
|
1139
1264
|
} else {
|
1140
1265
|
if (state->array_nl) ruby_xfree(state->array_nl);
|
1141
|
-
state->array_nl =
|
1266
|
+
state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
|
1142
1267
|
state->array_nl_len = len;
|
1143
1268
|
}
|
1144
1269
|
return Qnil;
|
@@ -1197,7 +1322,7 @@ static VALUE cState_allow_nan_p(VALUE self)
|
|
1197
1322
|
/*
|
1198
1323
|
* call-seq: ascii_only?
|
1199
1324
|
*
|
1200
|
-
* Returns true, if
|
1325
|
+
* Returns true, if only ASCII characters should be generated. Otherwise
|
1201
1326
|
* returns false.
|
1202
1327
|
*/
|
1203
1328
|
static VALUE cState_ascii_only_p(VALUE self)
|
@@ -1206,29 +1331,6 @@ static VALUE cState_ascii_only_p(VALUE self)
|
|
1206
1331
|
return state->ascii_only ? Qtrue : Qfalse;
|
1207
1332
|
}
|
1208
1333
|
|
1209
|
-
/*
|
1210
|
-
* call-seq: quirks_mode?
|
1211
|
-
*
|
1212
|
-
* Returns true, if quirks mode is enabled. Otherwise returns false.
|
1213
|
-
*/
|
1214
|
-
static VALUE cState_quirks_mode_p(VALUE self)
|
1215
|
-
{
|
1216
|
-
GET_STATE(self);
|
1217
|
-
return state->quirks_mode ? Qtrue : Qfalse;
|
1218
|
-
}
|
1219
|
-
|
1220
|
-
/*
|
1221
|
-
* call-seq: quirks_mode=(enable)
|
1222
|
-
*
|
1223
|
-
* If set to true, enables the quirks_mode mode.
|
1224
|
-
*/
|
1225
|
-
static VALUE cState_quirks_mode_set(VALUE self, VALUE enable)
|
1226
|
-
{
|
1227
|
-
GET_STATE(self);
|
1228
|
-
state->quirks_mode = RTEST(enable);
|
1229
|
-
return Qnil;
|
1230
|
-
}
|
1231
|
-
|
1232
1334
|
/*
|
1233
1335
|
* call-seq: depth
|
1234
1336
|
*
|
@@ -1257,7 +1359,7 @@ static VALUE cState_depth_set(VALUE self, VALUE depth)
|
|
1257
1359
|
/*
|
1258
1360
|
* call-seq: buffer_initial_length
|
1259
1361
|
*
|
1260
|
-
* This integer returns the current
|
1362
|
+
* This integer returns the current initial length of the buffer.
|
1261
1363
|
*/
|
1262
1364
|
static VALUE cState_buffer_initial_length(VALUE self)
|
1263
1365
|
{
|
@@ -1286,8 +1388,9 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
|
|
1286
1388
|
/*
|
1287
1389
|
*
|
1288
1390
|
*/
|
1289
|
-
void Init_generator()
|
1391
|
+
void Init_generator(void)
|
1290
1392
|
{
|
1393
|
+
#undef rb_intern
|
1291
1394
|
rb_require("json/common");
|
1292
1395
|
|
1293
1396
|
mJSON = rb_define_module("JSON");
|
@@ -1296,6 +1399,8 @@ void Init_generator()
|
|
1296
1399
|
|
1297
1400
|
eGeneratorError = rb_path2class("JSON::GeneratorError");
|
1298
1401
|
eNestingError = rb_path2class("JSON::NestingError");
|
1402
|
+
rb_gc_register_mark_object(eGeneratorError);
|
1403
|
+
rb_gc_register_mark_object(eNestingError);
|
1299
1404
|
|
1300
1405
|
cState = rb_define_class_under(mGenerator, "State", rb_cObject);
|
1301
1406
|
rb_define_alloc_func(cState, cState_s_allocate);
|
@@ -1317,9 +1422,6 @@ void Init_generator()
|
|
1317
1422
|
rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
|
1318
1423
|
rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
|
1319
1424
|
rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
|
1320
|
-
rb_define_method(cState, "quirks_mode?", cState_quirks_mode_p, 0);
|
1321
|
-
rb_define_method(cState, "quirks_mode", cState_quirks_mode_p, 0);
|
1322
|
-
rb_define_method(cState, "quirks_mode=", cState_quirks_mode_set, 1);
|
1323
1425
|
rb_define_method(cState, "depth", cState_depth, 0);
|
1324
1426
|
rb_define_method(cState, "depth=", cState_depth_set, 1);
|
1325
1427
|
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
|
@@ -1327,7 +1429,9 @@ void Init_generator()
|
|
1327
1429
|
rb_define_method(cState, "configure", cState_configure, 1);
|
1328
1430
|
rb_define_alias(cState, "merge", "configure");
|
1329
1431
|
rb_define_method(cState, "to_h", cState_to_h, 0);
|
1432
|
+
rb_define_alias(cState, "to_hash", "to_h");
|
1330
1433
|
rb_define_method(cState, "[]", cState_aref, 1);
|
1434
|
+
rb_define_method(cState, "[]=", cState_aset, 2);
|
1331
1435
|
rb_define_method(cState, "generate", cState_generate, 1);
|
1332
1436
|
|
1333
1437
|
mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
|
@@ -1337,10 +1441,15 @@ void Init_generator()
|
|
1337
1441
|
rb_define_method(mHash, "to_json", mHash_to_json, -1);
|
1338
1442
|
mArray = rb_define_module_under(mGeneratorMethods, "Array");
|
1339
1443
|
rb_define_method(mArray, "to_json", mArray_to_json, -1);
|
1444
|
+
#ifdef RUBY_INTEGER_UNIFICATION
|
1445
|
+
mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
|
1446
|
+
rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
|
1447
|
+
#else
|
1340
1448
|
mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
|
1341
1449
|
rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
|
1342
1450
|
mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
|
1343
1451
|
rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
|
1452
|
+
#endif
|
1344
1453
|
mFloat = rb_define_module_under(mGeneratorMethods, "Float");
|
1345
1454
|
rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
|
1346
1455
|
mString = rb_define_module_under(mGeneratorMethods, "String");
|
@@ -1357,7 +1466,6 @@ void Init_generator()
|
|
1357
1466
|
mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
|
1358
1467
|
rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
|
1359
1468
|
|
1360
|
-
CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
|
1361
1469
|
i_to_s = rb_intern("to_s");
|
1362
1470
|
i_to_json = rb_intern("to_json");
|
1363
1471
|
i_new = rb_intern("new");
|
@@ -1369,7 +1477,6 @@ void Init_generator()
|
|
1369
1477
|
i_max_nesting = rb_intern("max_nesting");
|
1370
1478
|
i_allow_nan = rb_intern("allow_nan");
|
1371
1479
|
i_ascii_only = rb_intern("ascii_only");
|
1372
|
-
i_quirks_mode = rb_intern("quirks_mode");
|
1373
1480
|
i_depth = rb_intern("depth");
|
1374
1481
|
i_buffer_initial_length = rb_intern("buffer_initial_length");
|
1375
1482
|
i_pack = rb_intern("pack");
|
@@ -1389,5 +1496,4 @@ void Init_generator()
|
|
1389
1496
|
i_encode = rb_intern("encode");
|
1390
1497
|
#endif
|
1391
1498
|
i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
|
1392
|
-
CJSON_SAFE_STATE_PROTOTYPE = Qnil;
|
1393
1499
|
}
|