json 1.8.2 → 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 +5 -5
- data/.gitignore +2 -0
- data/.travis.yml +9 -9
- data/{CHANGES → CHANGES.md} +187 -89
- data/Gemfile +10 -6
- 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 +41 -40
- data/VERSION +1 -1
- data/ext/json/ext/fbuffer/fbuffer.h +0 -3
- data/ext/json/ext/generator/generator.c +145 -110
- data/ext/json/ext/generator/generator.h +18 -5
- data/ext/json/ext/parser/extconf.rb +3 -0
- data/ext/json/ext/parser/parser.c +419 -506
- data/ext/json/ext/parser/parser.h +15 -8
- data/ext/json/ext/parser/parser.rl +150 -200
- data/ext/json/extconf.rb +0 -1
- data/java/src/json/ext/ByteListTranscoder.java +1 -2
- data/java/src/json/ext/Generator.java +44 -22
- 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 +3 -56
- data/java/src/json/ext/OptionsReader.java +2 -3
- data/java/src/json/ext/Parser.java +132 -415
- data/java/src/json/ext/Parser.rl +48 -124
- 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 +16 -2
- data/json.gemspec +0 -0
- data/json_pure.gemspec +24 -26
- data/lib/json/add/bigdecimal.rb +3 -2
- data/lib/json/add/complex.rb +4 -3
- 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 +3 -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 +1 -1
- data/lib/json/common.rb +26 -54
- data/lib/json/ext.rb +0 -6
- data/lib/json/generic_object.rb +5 -4
- data/lib/json/pure/generator.rb +63 -126
- data/lib/json/pure/parser.rb +41 -81
- data/lib/json/pure.rb +2 -8
- data/lib/json/version.rb +2 -1
- data/lib/json.rb +1 -0
- data/references/rfc7159.txt +899 -0
- data/tests/fixtures/obsolete_fail1.json +1 -0
- data/tests/{test_json_addition.rb → json_addition_test.rb} +32 -25
- 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/{test_json_generate.rb → json_generator_test.rb} +123 -39
- data/tests/{test_json_generic_object.rb → json_generic_object_test.rb} +15 -8
- 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 +30 -47
- 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 -553
- data/tests/test_json_encoding.rb +0 -65
- data/tests/test_json_string_matching.rb +0 -39
- data/tests/test_json_unicode.rb +0 -72
data/Rakefile
CHANGED
|
@@ -23,12 +23,13 @@ class UndocumentedTestTask < Rake::TestTask
|
|
|
23
23
|
def desc(*) end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
which = lambda { |c|
|
|
27
|
+
w = `which #{c}`
|
|
28
|
+
break w.chomp unless w.empty?
|
|
29
|
+
}
|
|
29
30
|
|
|
30
|
-
MAKE = ENV['MAKE'] || %w[gmake make].find
|
|
31
|
-
BUNDLE = ENV['BUNDLE'] || %w[bundle].find
|
|
31
|
+
MAKE = ENV['MAKE'] || %w[gmake make].find(&which)
|
|
32
|
+
BUNDLE = ENV['BUNDLE'] || %w[bundle].find(&which)
|
|
32
33
|
PKG_NAME = 'json'
|
|
33
34
|
PKG_TITLE = 'JSON Implementation for Ruby'
|
|
34
35
|
PKG_VERSION = File.read('VERSION').chomp
|
|
@@ -51,8 +52,8 @@ JAVA_CLASSES = []
|
|
|
51
52
|
JRUBY_PARSER_JAR = File.expand_path("lib/json/ext/parser.jar")
|
|
52
53
|
JRUBY_GENERATOR_JAR = File.expand_path("lib/json/ext/generator.jar")
|
|
53
54
|
|
|
54
|
-
RAGEL_CODEGEN = %w[rlcodegen rlgen-cd ragel].find
|
|
55
|
-
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)
|
|
56
57
|
|
|
57
58
|
desc "Installing library (pure)"
|
|
58
59
|
task :install_pure => :version do
|
|
@@ -87,25 +88,25 @@ if defined?(Gem) and defined?(Gem::PackageTask)
|
|
|
87
88
|
s.files = PKG_FILES
|
|
88
89
|
|
|
89
90
|
s.require_path = 'lib'
|
|
90
|
-
s.add_development_dependency '
|
|
91
|
-
s.add_development_dependency '
|
|
92
|
-
s.add_development_dependency 'rake', '~>0.9.2'
|
|
91
|
+
s.add_development_dependency 'rake'
|
|
92
|
+
s.add_development_dependency 'test-unit', '~> 2.0'
|
|
93
93
|
|
|
94
|
-
s.extra_rdoc_files << 'README.
|
|
94
|
+
s.extra_rdoc_files << 'README.md'
|
|
95
95
|
s.rdoc_options <<
|
|
96
|
-
'--title' << 'JSON implemention for ruby' << '--main' << 'README.
|
|
96
|
+
'--title' << 'JSON implemention for ruby' << '--main' << 'README.md'
|
|
97
97
|
s.test_files.concat Dir['./tests/test_*.rb']
|
|
98
98
|
|
|
99
99
|
s.author = "Florian Frank"
|
|
100
100
|
s.email = "flori@ping.de"
|
|
101
101
|
s.homepage = "http://flori.github.com/#{PKG_NAME}"
|
|
102
102
|
s.license = 'Ruby'
|
|
103
|
+
s.required_ruby_version = '>= 1.9'
|
|
103
104
|
end
|
|
104
105
|
|
|
105
106
|
desc 'Creates a json_pure.gemspec file'
|
|
106
107
|
task :gemspec_pure => :version do
|
|
107
108
|
File.open('json_pure.gemspec', 'w') do |gemspec|
|
|
108
|
-
gemspec.write
|
|
109
|
+
gemspec.write spec_pure.to_ruby
|
|
109
110
|
end
|
|
110
111
|
end
|
|
111
112
|
|
|
@@ -125,24 +126,25 @@ if defined?(Gem) and defined?(Gem::PackageTask)
|
|
|
125
126
|
s.extensions = FileList['ext/**/extconf.rb']
|
|
126
127
|
|
|
127
128
|
s.require_path = 'lib'
|
|
128
|
-
s.add_development_dependency '
|
|
129
|
-
s.add_development_dependency '
|
|
129
|
+
s.add_development_dependency 'rake'
|
|
130
|
+
s.add_development_dependency 'test-unit', '~> 2.0'
|
|
130
131
|
|
|
131
|
-
s.extra_rdoc_files << 'README.
|
|
132
|
+
s.extra_rdoc_files << 'README.md'
|
|
132
133
|
s.rdoc_options <<
|
|
133
|
-
'--title' << 'JSON implemention for Ruby' << '--main' << 'README.
|
|
134
|
+
'--title' << 'JSON implemention for Ruby' << '--main' << 'README.md'
|
|
134
135
|
s.test_files.concat Dir['./tests/test_*.rb']
|
|
135
136
|
|
|
136
137
|
s.author = "Florian Frank"
|
|
137
138
|
s.email = "flori@ping.de"
|
|
138
139
|
s.homepage = "http://flori.github.com/#{PKG_NAME}"
|
|
139
140
|
s.license = 'Ruby'
|
|
141
|
+
s.required_ruby_version = '>= 1.9'
|
|
140
142
|
end
|
|
141
143
|
|
|
142
144
|
desc 'Creates a json.gemspec file'
|
|
143
145
|
task :gemspec_ext => :version do
|
|
144
146
|
File.open('json.gemspec', 'w') do |gemspec|
|
|
145
|
-
gemspec.write
|
|
147
|
+
gemspec.write spec_ext.to_ruby
|
|
146
148
|
end
|
|
147
149
|
end
|
|
148
150
|
|
|
@@ -161,6 +163,7 @@ task :version do
|
|
|
161
163
|
puts m
|
|
162
164
|
File.open(File.join('lib', 'json', 'version.rb'), 'w') do |v|
|
|
163
165
|
v.puts <<EOT
|
|
166
|
+
# frozen_string_literal: false
|
|
164
167
|
module JSON
|
|
165
168
|
# JSON version
|
|
166
169
|
VERSION = '#{PKG_VERSION}'
|
|
@@ -173,13 +176,17 @@ EOT
|
|
|
173
176
|
end
|
|
174
177
|
end
|
|
175
178
|
|
|
179
|
+
task :check_env do
|
|
180
|
+
ENV.key?('JSON') or fail "JSON env var is required"
|
|
181
|
+
end
|
|
182
|
+
|
|
176
183
|
desc "Testing library (pure ruby)"
|
|
177
|
-
task :test_pure => [ :clean, :do_test_pure ]
|
|
184
|
+
task :test_pure => [ :clean, :check_env, :do_test_pure ]
|
|
178
185
|
|
|
179
186
|
UndocumentedTestTask.new do |t|
|
|
180
187
|
t.name = 'do_test_pure'
|
|
181
|
-
t.libs << 'lib'
|
|
182
|
-
t.test_files = FileList['tests
|
|
188
|
+
t.libs << 'lib' << 'tests'
|
|
189
|
+
t.test_files = FileList['tests/*_test.rb']
|
|
183
190
|
t.verbose = true
|
|
184
191
|
t.options = '-v'
|
|
185
192
|
end
|
|
@@ -198,13 +205,11 @@ namespace :gems do
|
|
|
198
205
|
end
|
|
199
206
|
|
|
200
207
|
if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
ENV['JAVA_HOME'] = local_java
|
|
207
|
-
end
|
|
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) }
|
|
208
213
|
if ENV['JAVA_HOME']
|
|
209
214
|
warn " *** JAVA_HOME is set to #{ENV['JAVA_HOME'].inspect}"
|
|
210
215
|
ENV['PATH'] = ENV['PATH'].split(/:/).unshift(java_path = "#{ENV['JAVA_HOME']}/bin") * ':'
|
|
@@ -238,7 +243,7 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
|
|
|
238
243
|
classpath = (Dir['java/lib/*.jar'] << 'java/src' << JRUBY_JAR) * ':'
|
|
239
244
|
obj = src.sub(/\.java\Z/, '.class')
|
|
240
245
|
file obj => src do
|
|
241
|
-
sh 'javac', '-classpath', classpath, '-source', '1.
|
|
246
|
+
sh 'javac', '-classpath', classpath, '-source', '1.6', '-target', '1.6', src
|
|
242
247
|
end
|
|
243
248
|
JAVA_CLASSES << obj
|
|
244
249
|
end
|
|
@@ -257,12 +262,12 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
|
|
|
257
262
|
end
|
|
258
263
|
|
|
259
264
|
desc "Testing library (jruby)"
|
|
260
|
-
task :test_ext => [ :create_jar, :do_test_ext ]
|
|
265
|
+
task :test_ext => [ :check_env, :create_jar, :do_test_ext ]
|
|
261
266
|
|
|
262
267
|
UndocumentedTestTask.new do |t|
|
|
263
268
|
t.name = 'do_test_ext'
|
|
264
|
-
t.libs << 'lib'
|
|
265
|
-
t.test_files = FileList['tests
|
|
269
|
+
t.libs << 'lib' << 'tests'
|
|
270
|
+
t.test_files = FileList['tests/*_test.rb']
|
|
266
271
|
t.verbose = true
|
|
267
272
|
t.options = '-v'
|
|
268
273
|
end
|
|
@@ -331,21 +336,16 @@ else
|
|
|
331
336
|
end
|
|
332
337
|
|
|
333
338
|
desc "Testing library (extension)"
|
|
334
|
-
task :test_ext => [ :compile, :do_test_ext ]
|
|
339
|
+
task :test_ext => [ :check_env, :compile, :do_test_ext ]
|
|
335
340
|
|
|
336
341
|
UndocumentedTestTask.new do |t|
|
|
337
342
|
t.name = 'do_test_ext'
|
|
338
|
-
t.libs << 'ext' << 'lib'
|
|
339
|
-
t.test_files = FileList['tests
|
|
343
|
+
t.libs << 'ext' << 'lib' << 'tests'
|
|
344
|
+
t.test_files = FileList['tests/*_test.rb']
|
|
340
345
|
t.verbose = true
|
|
341
346
|
t.options = '-v'
|
|
342
347
|
end
|
|
343
348
|
|
|
344
|
-
desc "Create RDOC documentation"
|
|
345
|
-
task :doc => [ :version, EXT_PARSER_SRC ] do
|
|
346
|
-
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}"
|
|
347
|
-
end
|
|
348
|
-
|
|
349
349
|
desc "Generate parser with ragel"
|
|
350
350
|
task :ragel => EXT_PARSER_SRC
|
|
351
351
|
|
|
@@ -367,6 +367,7 @@ else
|
|
|
367
367
|
sh "ragel -x parser.rl | #{RAGEL_CODEGEN} -G2"
|
|
368
368
|
end
|
|
369
369
|
src = File.read("parser.c").gsub(/[ \t]+$/, '')
|
|
370
|
+
src.gsub!(/^static const int (JSON_.*=.*);$/, 'enum {\1};')
|
|
370
371
|
File.open("parser.c", "w") {|f| f.print src}
|
|
371
372
|
end
|
|
372
373
|
end
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
2.3.0
|
|
@@ -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;
|
|
@@ -274,14 +282,17 @@ static void convert_UTF8_to_JSON(FBuffer *buffer, VALUE string)
|
|
|
274
282
|
break;
|
|
275
283
|
default:
|
|
276
284
|
{
|
|
277
|
-
unsigned short clen =
|
|
278
|
-
if (
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
+
}
|
|
285
296
|
}
|
|
286
297
|
end += clen;
|
|
287
298
|
}
|
|
@@ -301,7 +312,7 @@ static char *fstrndup(const char *ptr, unsigned long len) {
|
|
|
301
312
|
char *result;
|
|
302
313
|
if (len <= 0) return NULL;
|
|
303
314
|
result = ALLOC_N(char, len);
|
|
304
|
-
|
|
315
|
+
memcpy(result, ptr, len);
|
|
305
316
|
return result;
|
|
306
317
|
}
|
|
307
318
|
|
|
@@ -342,6 +353,18 @@ static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self) {
|
|
|
342
353
|
GENERATE_JSON(array);
|
|
343
354
|
}
|
|
344
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
|
|
345
368
|
/*
|
|
346
369
|
* call-seq: to_json(*)
|
|
347
370
|
*
|
|
@@ -361,6 +384,7 @@ static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
|
|
|
361
384
|
{
|
|
362
385
|
GENERATE_JSON(bignum);
|
|
363
386
|
}
|
|
387
|
+
#endif
|
|
364
388
|
|
|
365
389
|
/*
|
|
366
390
|
* call-seq: to_json(*)
|
|
@@ -526,17 +550,11 @@ static const rb_data_type_t JSON_Generator_State_type = {
|
|
|
526
550
|
};
|
|
527
551
|
#endif
|
|
528
552
|
|
|
529
|
-
static JSON_Generator_State *State_allocate(void)
|
|
530
|
-
{
|
|
531
|
-
JSON_Generator_State *state = ALLOC(JSON_Generator_State);
|
|
532
|
-
MEMZERO(state, JSON_Generator_State, 1);
|
|
533
|
-
return state;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
553
|
static VALUE cState_s_allocate(VALUE klass)
|
|
537
554
|
{
|
|
538
|
-
JSON_Generator_State *state
|
|
539
|
-
return
|
|
555
|
+
JSON_Generator_State *state;
|
|
556
|
+
return TypedData_Make_Struct(klass, JSON_Generator_State,
|
|
557
|
+
&JSON_Generator_State_type, state);
|
|
540
558
|
}
|
|
541
559
|
|
|
542
560
|
/*
|
|
@@ -628,8 +646,6 @@ static VALUE cState_configure(VALUE self, VALUE opts)
|
|
|
628
646
|
state->allow_nan = RTEST(tmp);
|
|
629
647
|
tmp = rb_hash_aref(opts, ID2SYM(i_ascii_only));
|
|
630
648
|
state->ascii_only = RTEST(tmp);
|
|
631
|
-
tmp = rb_hash_aref(opts, ID2SYM(i_quirks_mode));
|
|
632
|
-
state->quirks_mode = RTEST(tmp);
|
|
633
649
|
return self;
|
|
634
650
|
}
|
|
635
651
|
|
|
@@ -663,7 +679,6 @@ static VALUE cState_to_h(VALUE self)
|
|
|
663
679
|
rb_hash_aset(result, ID2SYM(i_array_nl), rb_str_new(state->array_nl, state->array_nl_len));
|
|
664
680
|
rb_hash_aset(result, ID2SYM(i_allow_nan), state->allow_nan ? Qtrue : Qfalse);
|
|
665
681
|
rb_hash_aset(result, ID2SYM(i_ascii_only), state->ascii_only ? Qtrue : Qfalse);
|
|
666
|
-
rb_hash_aset(result, ID2SYM(i_quirks_mode), state->quirks_mode ? Qtrue : Qfalse);
|
|
667
682
|
rb_hash_aset(result, ID2SYM(i_max_nesting), LONG2FIX(state->max_nesting));
|
|
668
683
|
rb_hash_aset(result, ID2SYM(i_depth), LONG2FIX(state->depth));
|
|
669
684
|
rb_hash_aset(result, ID2SYM(i_buffer_initial_length), LONG2FIX(state->buffer_initial_length));
|
|
@@ -681,7 +696,7 @@ static VALUE cState_aref(VALUE self, VALUE name)
|
|
|
681
696
|
if (RTEST(rb_funcall(self, i_respond_to_p, 1, name))) {
|
|
682
697
|
return rb_funcall(self, i_send, 1, name);
|
|
683
698
|
} else {
|
|
684
|
-
return
|
|
699
|
+
return rb_attr_get(self, rb_intern_str(rb_str_concat(rb_str_new2("@"), name)));
|
|
685
700
|
}
|
|
686
701
|
}
|
|
687
702
|
|
|
@@ -704,43 +719,83 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
|
|
|
704
719
|
return Qnil;
|
|
705
720
|
}
|
|
706
721
|
|
|
707
|
-
|
|
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)
|
|
708
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
|
+
|
|
709
737
|
char *object_nl = state->object_nl;
|
|
710
738
|
long object_nl_len = state->object_nl_len;
|
|
711
739
|
char *indent = state->indent;
|
|
712
740
|
long indent_len = state->indent_len;
|
|
713
|
-
long max_nesting = state->max_nesting;
|
|
714
741
|
char *delim = FBUFFER_PTR(state->object_delim);
|
|
715
742
|
long delim_len = FBUFFER_LEN(state->object_delim);
|
|
716
743
|
char *delim2 = FBUFFER_PTR(state->object_delim2);
|
|
717
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;
|
|
718
783
|
long depth = ++state->depth;
|
|
719
|
-
int
|
|
720
|
-
|
|
784
|
+
int j;
|
|
785
|
+
struct hash_foreach_arg arg;
|
|
786
|
+
|
|
721
787
|
if (max_nesting != 0 && depth > max_nesting) {
|
|
722
788
|
fbuffer_free(buffer);
|
|
723
789
|
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
|
724
790
|
}
|
|
725
791
|
fbuffer_append_char(buffer, '{');
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
for (j = 0; j < depth; j++) {
|
|
734
|
-
fbuffer_append(buffer, indent, indent_len);
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
key = rb_ary_entry(keys, i);
|
|
738
|
-
key_to_s = rb_funcall(key, i_to_s, 0);
|
|
739
|
-
Check_Type(key_to_s, T_STRING);
|
|
740
|
-
generate_json(buffer, Vstate, state, key_to_s);
|
|
741
|
-
fbuffer_append(buffer, delim2, delim2_len);
|
|
742
|
-
generate_json(buffer, Vstate, state, rb_hash_aref(obj, key));
|
|
743
|
-
}
|
|
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
|
+
|
|
744
799
|
depth = --state->depth;
|
|
745
800
|
if (object_nl) {
|
|
746
801
|
fbuffer_append(buffer, object_nl, object_nl_len);
|
|
@@ -791,11 +846,22 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
|
|
|
791
846
|
fbuffer_append_char(buffer, ']');
|
|
792
847
|
}
|
|
793
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
|
+
|
|
794
858
|
static void generate_json_string(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
795
859
|
{
|
|
796
860
|
fbuffer_append_char(buffer, '"');
|
|
797
861
|
#ifdef HAVE_RUBY_ENCODING_H
|
|
798
|
-
|
|
862
|
+
if (!enc_utf8_compatible_p(rb_enc_get(obj))) {
|
|
863
|
+
obj = rb_str_encode(obj, CEncoding_UTF_8, 0, Qnil);
|
|
864
|
+
}
|
|
799
865
|
#endif
|
|
800
866
|
if (state->ascii_only) {
|
|
801
867
|
convert_UTF8_to_JSON_ASCII(buffer, obj);
|
|
@@ -831,6 +897,15 @@ static void generate_json_bignum(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
|
|
|
831
897
|
fbuffer_append_str(buffer, tmp);
|
|
832
898
|
}
|
|
833
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
|
|
834
909
|
static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
|
835
910
|
{
|
|
836
911
|
double value = RFLOAT_VALUE(obj);
|
|
@@ -864,9 +939,9 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
|
|
|
864
939
|
generate_json_false(buffer, Vstate, state, obj);
|
|
865
940
|
} else if (obj == Qtrue) {
|
|
866
941
|
generate_json_true(buffer, Vstate, state, obj);
|
|
867
|
-
} else if (
|
|
942
|
+
} else if (FIXNUM_P(obj)) {
|
|
868
943
|
generate_json_fixnum(buffer, Vstate, state, obj);
|
|
869
|
-
} else if (
|
|
944
|
+
} else if (RB_TYPE_P(obj, T_BIGNUM)) {
|
|
870
945
|
generate_json_bignum(buffer, Vstate, state, obj);
|
|
871
946
|
} else if (klass == rb_cFloat) {
|
|
872
947
|
generate_json_float(buffer, Vstate, state, obj);
|
|
@@ -877,7 +952,7 @@ static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *s
|
|
|
877
952
|
} else {
|
|
878
953
|
tmp = rb_funcall(obj, i_to_s, 0);
|
|
879
954
|
Check_Type(tmp, T_STRING);
|
|
880
|
-
|
|
955
|
+
generate_json_string(buffer, Vstate, state, tmp);
|
|
881
956
|
}
|
|
882
957
|
}
|
|
883
958
|
|
|
@@ -920,21 +995,6 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj)
|
|
|
920
995
|
return fbuffer_to_s(buffer);
|
|
921
996
|
}
|
|
922
997
|
|
|
923
|
-
/*
|
|
924
|
-
* This function returns true if string is either a JSON array or JSON object.
|
|
925
|
-
* It might suffer from false positives, e. g. syntactically incorrect JSON in
|
|
926
|
-
* the string or certain UTF-8 characters on the right hand side.
|
|
927
|
-
*/
|
|
928
|
-
static int isArrayOrObject(VALUE string)
|
|
929
|
-
{
|
|
930
|
-
long string_len = RSTRING_LEN(string);
|
|
931
|
-
char *p = RSTRING_PTR(string), *q = p + string_len - 1;
|
|
932
|
-
if (string_len < 2) return 0;
|
|
933
|
-
for (; p < q && isspace((unsigned char)*p); p++);
|
|
934
|
-
for (; q > p && isspace((unsigned char)*q); q--);
|
|
935
|
-
return (*p == '[' && *q == ']') || (*p == '{' && *q == '}');
|
|
936
|
-
}
|
|
937
|
-
|
|
938
998
|
/*
|
|
939
999
|
* call-seq: generate(obj)
|
|
940
1000
|
*
|
|
@@ -946,9 +1006,7 @@ static VALUE cState_generate(VALUE self, VALUE obj)
|
|
|
946
1006
|
{
|
|
947
1007
|
VALUE result = cState_partial_generate(self, obj);
|
|
948
1008
|
GET_STATE(self);
|
|
949
|
-
|
|
950
|
-
rb_raise(eGeneratorError, "only generation of JSON objects or arrays allowed");
|
|
951
|
-
}
|
|
1009
|
+
(void)state;
|
|
952
1010
|
return result;
|
|
953
1011
|
}
|
|
954
1012
|
|
|
@@ -967,8 +1025,8 @@ static VALUE cState_generate(VALUE self, VALUE obj)
|
|
|
967
1025
|
* * *allow_nan*: true if NaN, Infinity, and -Infinity should be
|
|
968
1026
|
* generated, otherwise an exception is thrown, if these values are
|
|
969
1027
|
* encountered. This options defaults to false.
|
|
970
|
-
* * *
|
|
971
|
-
*
|
|
1028
|
+
* * *ascii_only*: true if only ASCII characters should be generated. This
|
|
1029
|
+
* ontions defaults to false.
|
|
972
1030
|
* * *buffer_initial_length*: sets the initial length of the generator's
|
|
973
1031
|
* internal buffer.
|
|
974
1032
|
*/
|
|
@@ -1024,10 +1082,8 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
|
|
|
1024
1082
|
} else if (rb_obj_is_kind_of(opts, rb_cHash)) {
|
|
1025
1083
|
return rb_funcall(self, i_new, 1, opts);
|
|
1026
1084
|
} else {
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
}
|
|
1030
|
-
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);
|
|
1031
1087
|
}
|
|
1032
1088
|
}
|
|
1033
1089
|
|
|
@@ -1061,7 +1117,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
|
|
|
1061
1117
|
}
|
|
1062
1118
|
} else {
|
|
1063
1119
|
if (state->indent) ruby_xfree(state->indent);
|
|
1064
|
-
state->indent =
|
|
1120
|
+
state->indent = fstrndup(RSTRING_PTR(indent), len);
|
|
1065
1121
|
state->indent_len = len;
|
|
1066
1122
|
}
|
|
1067
1123
|
return Qnil;
|
|
@@ -1099,7 +1155,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
|
|
|
1099
1155
|
}
|
|
1100
1156
|
} else {
|
|
1101
1157
|
if (state->space) ruby_xfree(state->space);
|
|
1102
|
-
state->space =
|
|
1158
|
+
state->space = fstrndup(RSTRING_PTR(space), len);
|
|
1103
1159
|
state->space_len = len;
|
|
1104
1160
|
}
|
|
1105
1161
|
return Qnil;
|
|
@@ -1135,7 +1191,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
|
1135
1191
|
}
|
|
1136
1192
|
} else {
|
|
1137
1193
|
if (state->space_before) ruby_xfree(state->space_before);
|
|
1138
|
-
state->space_before =
|
|
1194
|
+
state->space_before = fstrndup(RSTRING_PTR(space_before), len);
|
|
1139
1195
|
state->space_before_len = len;
|
|
1140
1196
|
}
|
|
1141
1197
|
return Qnil;
|
|
@@ -1172,7 +1228,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
|
1172
1228
|
}
|
|
1173
1229
|
} else {
|
|
1174
1230
|
if (state->object_nl) ruby_xfree(state->object_nl);
|
|
1175
|
-
state->object_nl =
|
|
1231
|
+
state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
|
|
1176
1232
|
state->object_nl_len = len;
|
|
1177
1233
|
}
|
|
1178
1234
|
return Qnil;
|
|
@@ -1207,7 +1263,7 @@ static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
|
|
|
1207
1263
|
}
|
|
1208
1264
|
} else {
|
|
1209
1265
|
if (state->array_nl) ruby_xfree(state->array_nl);
|
|
1210
|
-
state->array_nl =
|
|
1266
|
+
state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
|
|
1211
1267
|
state->array_nl_len = len;
|
|
1212
1268
|
}
|
|
1213
1269
|
return Qnil;
|
|
@@ -1266,7 +1322,7 @@ static VALUE cState_allow_nan_p(VALUE self)
|
|
|
1266
1322
|
/*
|
|
1267
1323
|
* call-seq: ascii_only?
|
|
1268
1324
|
*
|
|
1269
|
-
* Returns true, if
|
|
1325
|
+
* Returns true, if only ASCII characters should be generated. Otherwise
|
|
1270
1326
|
* returns false.
|
|
1271
1327
|
*/
|
|
1272
1328
|
static VALUE cState_ascii_only_p(VALUE self)
|
|
@@ -1275,29 +1331,6 @@ static VALUE cState_ascii_only_p(VALUE self)
|
|
|
1275
1331
|
return state->ascii_only ? Qtrue : Qfalse;
|
|
1276
1332
|
}
|
|
1277
1333
|
|
|
1278
|
-
/*
|
|
1279
|
-
* call-seq: quirks_mode?
|
|
1280
|
-
*
|
|
1281
|
-
* Returns true, if quirks mode is enabled. Otherwise returns false.
|
|
1282
|
-
*/
|
|
1283
|
-
static VALUE cState_quirks_mode_p(VALUE self)
|
|
1284
|
-
{
|
|
1285
|
-
GET_STATE(self);
|
|
1286
|
-
return state->quirks_mode ? Qtrue : Qfalse;
|
|
1287
|
-
}
|
|
1288
|
-
|
|
1289
|
-
/*
|
|
1290
|
-
* call-seq: quirks_mode=(enable)
|
|
1291
|
-
*
|
|
1292
|
-
* If set to true, enables the quirks_mode mode.
|
|
1293
|
-
*/
|
|
1294
|
-
static VALUE cState_quirks_mode_set(VALUE self, VALUE enable)
|
|
1295
|
-
{
|
|
1296
|
-
GET_STATE(self);
|
|
1297
|
-
state->quirks_mode = RTEST(enable);
|
|
1298
|
-
return Qnil;
|
|
1299
|
-
}
|
|
1300
|
-
|
|
1301
1334
|
/*
|
|
1302
1335
|
* call-seq: depth
|
|
1303
1336
|
*
|
|
@@ -1357,6 +1390,7 @@ static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_l
|
|
|
1357
1390
|
*/
|
|
1358
1391
|
void Init_generator(void)
|
|
1359
1392
|
{
|
|
1393
|
+
#undef rb_intern
|
|
1360
1394
|
rb_require("json/common");
|
|
1361
1395
|
|
|
1362
1396
|
mJSON = rb_define_module("JSON");
|
|
@@ -1365,6 +1399,8 @@ void Init_generator(void)
|
|
|
1365
1399
|
|
|
1366
1400
|
eGeneratorError = rb_path2class("JSON::GeneratorError");
|
|
1367
1401
|
eNestingError = rb_path2class("JSON::NestingError");
|
|
1402
|
+
rb_gc_register_mark_object(eGeneratorError);
|
|
1403
|
+
rb_gc_register_mark_object(eNestingError);
|
|
1368
1404
|
|
|
1369
1405
|
cState = rb_define_class_under(mGenerator, "State", rb_cObject);
|
|
1370
1406
|
rb_define_alloc_func(cState, cState_s_allocate);
|
|
@@ -1386,9 +1422,6 @@ void Init_generator(void)
|
|
|
1386
1422
|
rb_define_method(cState, "check_circular?", cState_check_circular_p, 0);
|
|
1387
1423
|
rb_define_method(cState, "allow_nan?", cState_allow_nan_p, 0);
|
|
1388
1424
|
rb_define_method(cState, "ascii_only?", cState_ascii_only_p, 0);
|
|
1389
|
-
rb_define_method(cState, "quirks_mode?", cState_quirks_mode_p, 0);
|
|
1390
|
-
rb_define_method(cState, "quirks_mode", cState_quirks_mode_p, 0);
|
|
1391
|
-
rb_define_method(cState, "quirks_mode=", cState_quirks_mode_set, 1);
|
|
1392
1425
|
rb_define_method(cState, "depth", cState_depth, 0);
|
|
1393
1426
|
rb_define_method(cState, "depth=", cState_depth_set, 1);
|
|
1394
1427
|
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
|
|
@@ -1408,10 +1441,15 @@ void Init_generator(void)
|
|
|
1408
1441
|
rb_define_method(mHash, "to_json", mHash_to_json, -1);
|
|
1409
1442
|
mArray = rb_define_module_under(mGeneratorMethods, "Array");
|
|
1410
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
|
|
1411
1448
|
mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
|
|
1412
1449
|
rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
|
|
1413
1450
|
mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
|
|
1414
1451
|
rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
|
|
1452
|
+
#endif
|
|
1415
1453
|
mFloat = rb_define_module_under(mGeneratorMethods, "Float");
|
|
1416
1454
|
rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
|
|
1417
1455
|
mString = rb_define_module_under(mGeneratorMethods, "String");
|
|
@@ -1428,7 +1466,6 @@ void Init_generator(void)
|
|
|
1428
1466
|
mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
|
|
1429
1467
|
rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
|
|
1430
1468
|
|
|
1431
|
-
CRegexp_MULTILINE = rb_const_get(rb_cRegexp, rb_intern("MULTILINE"));
|
|
1432
1469
|
i_to_s = rb_intern("to_s");
|
|
1433
1470
|
i_to_json = rb_intern("to_json");
|
|
1434
1471
|
i_new = rb_intern("new");
|
|
@@ -1440,7 +1477,6 @@ void Init_generator(void)
|
|
|
1440
1477
|
i_max_nesting = rb_intern("max_nesting");
|
|
1441
1478
|
i_allow_nan = rb_intern("allow_nan");
|
|
1442
1479
|
i_ascii_only = rb_intern("ascii_only");
|
|
1443
|
-
i_quirks_mode = rb_intern("quirks_mode");
|
|
1444
1480
|
i_depth = rb_intern("depth");
|
|
1445
1481
|
i_buffer_initial_length = rb_intern("buffer_initial_length");
|
|
1446
1482
|
i_pack = rb_intern("pack");
|
|
@@ -1460,5 +1496,4 @@ void Init_generator(void)
|
|
|
1460
1496
|
i_encode = rb_intern("encode");
|
|
1461
1497
|
#endif
|
|
1462
1498
|
i_SAFE_STATE_PROTOTYPE = rb_intern("SAFE_STATE_PROTOTYPE");
|
|
1463
|
-
CJSON_SAFE_STATE_PROTOTYPE = Qnil;
|
|
1464
1499
|
}
|