json_pure 1.1.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,8 +8,12 @@
8
8
  #define EVIL 0x666
9
9
 
10
10
  static VALUE mJSON, mExt, cParser, eParserError, eNestingError;
11
+ static VALUE CNaN, CInfinity, CMinusInfinity;
11
12
 
12
- static ID i_json_creatable_p, i_json_create, i_create_id, i_chr, i_max_nesting;
13
+ static ID i_json_creatable_p, i_json_create, i_create_id, i_chr, i_max_nesting,
14
+ i_allow_nan;
15
+
16
+ #define MinusInfinity "-Infinity"
13
17
 
14
18
  typedef struct JSON_ParserStruct {
15
19
  VALUE Vsource;
@@ -19,6 +23,7 @@ typedef struct JSON_ParserStruct {
19
23
  VALUE create_id;
20
24
  int max_nesting;
21
25
  int current_nesting;
26
+ int allow_nan;
22
27
  } JSON_Parser;
23
28
 
24
29
  static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result);
@@ -47,7 +52,10 @@ static char *JSON_parse_float(JSON_Parser *json, char *p, char *pe, VALUE *resul
47
52
  Vnull = 'null';
48
53
  Vfalse = 'false';
49
54
  Vtrue = 'true';
50
- begin_value = [nft"\-[{] | digit;
55
+ VNaN = 'NaN';
56
+ VInfinity = 'Infinity';
57
+ VMinusInfinity = '-Infinity';
58
+ begin_value = [nft"\-[{NI] | digit;
51
59
  begin_object = '{';
52
60
  end_object = '}';
53
61
  begin_array = '[';
@@ -133,6 +141,20 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
133
141
  action parse_true {
134
142
  *result = Qtrue;
135
143
  }
144
+ action parse_nan {
145
+ if (json->allow_nan) {
146
+ *result = CNaN;
147
+ } else {
148
+ rb_raise(eParserError, "unexpected token at '%s'", p - 2);
149
+ }
150
+ }
151
+ action parse_infinity {
152
+ if (json->allow_nan) {
153
+ *result = CInfinity;
154
+ } else {
155
+ rb_raise(eParserError, "unexpected token at '%s'", p - 8);
156
+ }
157
+ }
136
158
  action parse_string {
137
159
  char *np = JSON_parse_string(json, fpc, pe, result);
138
160
  if (np == NULL) fbreak; else fexec np;
@@ -140,6 +162,15 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu
140
162
 
141
163
  action parse_number {
142
164
  char *np;
165
+ if(pe > fpc + 9 && !strncmp(MinusInfinity, fpc, 9)) {
166
+ if (json->allow_nan) {
167
+ *result = CMinusInfinity;
168
+ fexec p + 10;
169
+ fbreak;
170
+ } else {
171
+ rb_raise(eParserError, "unexpected token at '%s'", p);
172
+ }
173
+ }
143
174
  np = JSON_parse_float(json, fpc, pe, result);
144
175
  if (np != NULL) fexec np;
145
176
  np = JSON_parse_integer(json, fpc, pe, result);
@@ -169,6 +200,8 @@ main := (
169
200
  Vnull @parse_null |
170
201
  Vfalse @parse_false |
171
202
  Vtrue @parse_true |
203
+ VNaN @parse_nan |
204
+ VInfinity @parse_infinity |
172
205
  begin_number >parse_number |
173
206
  begin_string >parse_string |
174
207
  begin_array >parse_array |
@@ -435,7 +468,11 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu
435
468
  *
436
469
  * _opts_ can have the following keys:
437
470
  * * *max_nesting*: The maximum depth of nesting allowed in the parsed data
438
- * structures. Disable depth checking with :max_nesting => false.
471
+ * structures. Disable depth checking with :max_nesting => false|nil|0, it
472
+ * defaults to 19.
473
+ * * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
474
+ * defiance of RFC 4627 to be parsed by the Parser. This option defaults to
475
+ * false.
439
476
  */
440
477
  static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
441
478
  {
@@ -451,14 +488,15 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
451
488
  rb_raise(eParserError, "A JSON text must at least contain two octets!");
452
489
  }
453
490
  json->max_nesting = 19;
491
+ json->allow_nan = 0;
454
492
  if (!NIL_P(opts)) {
455
493
  opts = rb_convert_type(opts, T_HASH, "Hash", "to_hash");
456
494
  if (NIL_P(opts)) {
457
495
  rb_raise(rb_eArgError, "opts needs to be like a hash");
458
496
  } else {
459
- VALUE s_max_nesting = ID2SYM(i_max_nesting);
460
- if (st_lookup(RHASH(opts)->tbl, s_max_nesting, 0)) {
461
- VALUE max_nesting = rb_hash_aref(opts, s_max_nesting);
497
+ VALUE tmp = ID2SYM(i_max_nesting);
498
+ if (st_lookup(RHASH(opts)->tbl, tmp, 0)) {
499
+ VALUE max_nesting = rb_hash_aref(opts, tmp);
462
500
  if (RTEST(max_nesting)) {
463
501
  Check_Type(max_nesting, T_FIXNUM);
464
502
  json->max_nesting = FIX2INT(max_nesting);
@@ -466,6 +504,11 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self)
466
504
  json->max_nesting = 0;
467
505
  }
468
506
  }
507
+ tmp = ID2SYM(i_allow_nan);
508
+ if (st_lookup(RHASH(opts)->tbl, tmp, 0)) {
509
+ VALUE allow_nan = rb_hash_aref(opts, tmp);
510
+ if (RTEST(allow_nan)) json->allow_nan = 1;
511
+ }
469
512
  }
470
513
  }
471
514
  json->current_nesting = 0;
@@ -561,9 +604,14 @@ void Init_parser()
561
604
  rb_define_method(cParser, "parse", cParser_parse, 0);
562
605
  rb_define_method(cParser, "source", cParser_source, 0);
563
606
 
607
+ CNaN = rb_const_get(mJSON, rb_intern("NaN"));
608
+ CInfinity = rb_const_get(mJSON, rb_intern("Infinity"));
609
+ CMinusInfinity = rb_const_get(mJSON, rb_intern("MinusInfinity"));
610
+
564
611
  i_json_creatable_p = rb_intern("json_creatable?");
565
612
  i_json_create = rb_intern("json_create");
566
613
  i_create_id = rb_intern("create_id");
567
614
  i_chr = rb_intern("chr");
568
615
  i_max_nesting = rb_intern("max_nesting");
616
+ i_allow_nan = rb_intern("allow_nan");
569
617
  }
data/lib/json.rb CHANGED
@@ -47,6 +47,27 @@ require 'json/common'
47
47
  #
48
48
  # * http://json.rubyforge.org
49
49
  #
50
+ # == Usage
51
+ #
52
+ # To use JSON you can
53
+ # require 'json'
54
+ # to load the installed variant (either the extension 'json' or the pure
55
+ # variant 'json_pure'). If you have installed the extension variant, you can
56
+ # pick either the extension variant or the pure variant by typing
57
+ # require 'json/ext'
58
+ # or
59
+ # require 'json/pure'
60
+ #
61
+ # You can choose to load a set of common additions to ruby core's objects if
62
+ # you
63
+ # require 'json/add/core'
64
+ #
65
+ # To get the best compatibility to rails' JSON implementation, you can
66
+ # require 'json/add/rails'
67
+ #
68
+ # Both of the additions attempt to require 'json' (like above) first, if it has
69
+ # not been required yet.
70
+ #
50
71
  # == Speed Comparisons
51
72
  #
52
73
  # I have created some benchmark results (see the benchmarks subdir of the
@@ -207,4 +228,6 @@ module JSON
207
228
  require 'json/pure'
208
229
  end
209
230
  end
231
+
232
+ JSON_LOADED = true
210
233
  end
@@ -0,0 +1,119 @@
1
+ # This file contains implementations of ruby core's custom objects for
2
+ # serialisation/deserialisation.
3
+
4
+ unless Object.const_defined?(:JSON) and ::JSON.const_defined?(:JSON_LOADED) and
5
+ ::JSON::JSON_LOADED
6
+ require 'json'
7
+ end
8
+
9
+ class Time
10
+ def self.json_create(object)
11
+ at(*object.values_at('s', 'u'))
12
+ end
13
+
14
+ def to_json(*args)
15
+ {
16
+ 'json_class' => self.class.name,
17
+ 's' => tv_sec,
18
+ 'u' => tv_usec,
19
+ }.to_json(*args)
20
+ end
21
+ end
22
+
23
+ class Date
24
+ def self.json_create(object)
25
+ civil(*object.values_at('y', 'm', 'd', 'sg'))
26
+ end
27
+
28
+ def to_json(*args)
29
+ {
30
+ 'json_class' => self.class.name,
31
+ 'y' => year,
32
+ 'm' => month,
33
+ 'd' => day,
34
+ 'sg' => sg,
35
+ }.to_json(*args)
36
+ end
37
+ end
38
+
39
+ class DateTime
40
+ def self.json_create(object)
41
+ args = object.values_at('y', 'm', 'd', 'H', 'M', 'S')
42
+ of_a, of_b = object['of'].split('/')
43
+ args << Rational(of_a.to_i, of_b.to_i)
44
+ args << object['sg']
45
+ civil(*args)
46
+ end
47
+
48
+ def to_json(*args)
49
+ {
50
+ 'json_class' => self.class.name,
51
+ 'y' => year,
52
+ 'm' => month,
53
+ 'd' => day,
54
+ 'H' => hour,
55
+ 'M' => min,
56
+ 'S' => sec,
57
+ 'of' => offset,
58
+ 'sg' => sg,
59
+ }.to_json(*args)
60
+ end
61
+ end
62
+
63
+ class Range
64
+ def self.json_create(object)
65
+ new(*object['a'])
66
+ end
67
+
68
+ def to_json(*args)
69
+ {
70
+ 'json_class' => self.class.name,
71
+ 'a' => [ first, last, exclude_end? ]
72
+ }.to_json(*args)
73
+ end
74
+ end
75
+
76
+ class Struct
77
+ def self.json_create(object)
78
+ new(*object['v'])
79
+ end
80
+
81
+ def to_json(*args)
82
+ klass = self.class.name
83
+ klass.empty? and raise JSON::JSONError, "Only named structs are supported!"
84
+ {
85
+ 'json_class' => klass,
86
+ 'v' => values,
87
+ }.to_json(*args)
88
+ end
89
+ end
90
+
91
+ class Exception
92
+ def self.json_create(object)
93
+ result = new(object['m'])
94
+ result.set_backtrace object['b']
95
+ result
96
+ end
97
+
98
+ def to_json(*args)
99
+ {
100
+ 'json_class' => self.class.name,
101
+ 'm' => message,
102
+ 'b' => backtrace,
103
+ }.to_json(*args)
104
+ end
105
+ end
106
+
107
+ class Regexp
108
+ def self.json_create(object)
109
+ new(object['s'], object['o'])
110
+ end
111
+
112
+ def to_json(*)
113
+ {
114
+ 'json_class' => self.class.name,
115
+ 'o' => options,
116
+ 's' => source,
117
+ }.to_json
118
+ end
119
+ end
@@ -0,0 +1,52 @@
1
+ # This file contains implementations of rails custom objects for
2
+ # serialisation/deserialisation.
3
+
4
+ unless Object.const_defined?(:JSON) and ::JSON.const_defined?(:JSON_LOADED) and
5
+ ::JSON::JSON_LOADED
6
+ require 'json'
7
+ end
8
+
9
+ class Object
10
+ def self.json_create(object)
11
+ obj = new
12
+ for key, value in object
13
+ next if key == 'json_class'
14
+ instance_variable_set "@#{key}", value
15
+ end
16
+ obj
17
+ end
18
+
19
+ def to_json(*a)
20
+ result = {
21
+ 'json_class' => self.class.name
22
+ }
23
+ instance_variables.inject(result) do |r, name|
24
+ r[name[1..-1]] = instance_variable_get name
25
+ r
26
+ end
27
+ result.to_json(*a)
28
+ end
29
+ end
30
+
31
+ module Enumerable
32
+ def to_json(*a)
33
+ to_a.to_json(*a)
34
+ end
35
+ end
36
+
37
+ # class Regexp
38
+ # def to_json(*)
39
+ # inspect
40
+ # end
41
+ # end
42
+ #
43
+ # The above rails definition has some problems:
44
+ #
45
+ # 1. { 'foo' => /bar/ }.to_json # => "{foo: /bar/}"
46
+ # This isn't valid JSON, because the regular expression syntax is not
47
+ # defined in RFC 4627. (And unquoted strings are disallowed there, too.)
48
+ # Though it is valid Javascript.
49
+ #
50
+ # 2. { 'foo' => /bar/mix }.to_json # => "{foo: /bar/mix}"
51
+ # This isn't even valid Javascript.
52
+
data/lib/json/common.rb CHANGED
@@ -2,14 +2,17 @@ require 'json/version'
2
2
 
3
3
  module JSON
4
4
  class << self
5
- # If object is string like parse the string and return the parsed result as a
6
- # Ruby data structure. Otherwise generate a JSON text from the Ruby data
7
- # structure object and return it.
8
- def [](object)
5
+ # If _object_ is string like parse the string and return the parsed result
6
+ # as a Ruby data structure. Otherwise generate a JSON text from the Ruby
7
+ # data structure object and return it.
8
+ #
9
+ # The _opts_ argument is passed through to generate/parse respectively, see
10
+ # generate and parse for their documentation.
11
+ def [](object, opts = {})
9
12
  if object.respond_to? :to_str
10
- JSON.parse(object.to_str)
13
+ JSON.parse(object.to_str, opts => {})
11
14
  else
12
- JSON.generate(object)
15
+ JSON.generate(object, opts => {})
13
16
  end
14
17
  end
15
18
 
@@ -71,6 +74,12 @@ module JSON
71
74
  end
72
75
  self.create_id = 'json_class'
73
76
 
77
+ NaN = (-1.0) ** 0.5
78
+
79
+ Infinity = 1.0/0
80
+
81
+ MinusInfinity = -Infinity
82
+
74
83
  # The base exception for JSON errors.
75
84
  class JSONError < StandardError; end
76
85
 
@@ -101,29 +110,79 @@ module JSON
101
110
  # _opts_ can have the following
102
111
  # keys:
103
112
  # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
104
- # structures. Disable depth checking with :max_nesting => false.
113
+ # structures. Disable depth checking with :max_nesting => false, it defaults
114
+ # to 19.
115
+ # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
116
+ # defiance of RFC 4627 to be parsed by the Parser. This option defaults
117
+ # to false.
105
118
  def parse(source, opts = {})
106
119
  JSON.parser.new(source, opts).parse
107
120
  end
108
121
 
122
+ # Parse the JSON string _source_ into a Ruby data structure and return it.
123
+ # The bang version of the parse method, defaults to the more dangerous values
124
+ # for the _opts_ hash, so be sure only to parse trusted _source_ strings.
125
+ #
126
+ # _opts_ can have the following keys:
127
+ # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
128
+ # structures. Enable depth checking with :max_nesting => anInteger. The parse!
129
+ # methods defaults to not doing max depth checking: This can be dangerous,
130
+ # if someone wants to fill up your stack.
131
+ # * *allow_nan*: If set to true, allow NaN, Infinity, and -Infinity in
132
+ # defiance of RFC 4627 to be parsed by the Parser. This option defaults
133
+ # to true.
134
+ def parse!(source, opts = {})
135
+ opts = {
136
+ :max_nesting => false,
137
+ :allow_nan => true
138
+ }.update(opts)
139
+ JSON.parser.new(source, opts).parse
140
+ end
141
+
109
142
  # Unparse the Ruby data structure _obj_ into a single line JSON string and
110
- # return it. _state_ is a JSON::State object, that can be used to configure
111
- # the output further.
143
+ # return it. _state_ is
144
+ # * a JSON::State object,
145
+ # * or a Hash like object (responding to to_hash),
146
+ # * an object convertible into a hash by a to_h method,
147
+ # that is used as or to configure a State object.
112
148
  #
113
149
  # It defaults to a state object, that creates the shortest possible JSON text
114
- # in one line and only checks for circular data structures. If you are sure,
115
- # that the objects don't contain any circles, you can set _state_ to nil, to
116
- # disable these checks in order to create the JSON text faster. See also
117
- # fast_generate.
118
- def generate(obj, state = JSON.state.new)
150
+ # in one line, checks for circular data structures and doesn't allow NaN,
151
+ # Infinity, and -Infinity.
152
+ #
153
+ # A _state_ hash can have the following keys:
154
+ # * *indent*: a string used to indent levels (default: ''),
155
+ # * *space*: a string that is put after, a : or , delimiter (default: ''),
156
+ # * *space_before*: a string that is put before a : pair delimiter (default: ''),
157
+ # * *object_nl*: a string that is put at the end of a JSON object (default: ''),
158
+ # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
159
+ # * *check_circular*: true if checking for circular data structures
160
+ # should be done (the default), false otherwise.
161
+ # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
162
+ # generated, otherwise an exception is thrown, if these values are
163
+ # encountered. This options defaults to false.
164
+ #
165
+ # See also the fast_generate for the fastest creation method with the least
166
+ # amount of sanity checks, and the pretty_generate method for some
167
+ # defaults for a pretty output.
168
+ def generate(obj, state = nil)
169
+ if state
170
+ state = State.from_state(state)
171
+ else
172
+ state = State.new
173
+ end
119
174
  obj.to_json(state)
120
175
  end
121
176
 
177
+ # :stopdoc:
178
+ # I want to deprecate these later, so I'll first be silent about them, and later delete them.
122
179
  alias unparse generate
123
180
  module_function :unparse
181
+ # :startdoc:
124
182
 
125
183
  # Unparse the Ruby data structure _obj_ into a single line JSON string and
126
- # return it. This method disables the checks for circles in Ruby objects.
184
+ # return it. This method disables the checks for circles in Ruby objects, and
185
+ # also generates NaN, Infinity, and, -Infinity float values.
127
186
  #
128
187
  # *WARNING*: Be careful not to pass any Ruby data structures with circles as
129
188
  # _obj_ argument, because this will cause JSON to go into an infinite loop.
@@ -131,12 +190,18 @@ module JSON
131
190
  obj.to_json(nil)
132
191
  end
133
192
 
193
+ # :stopdoc:
194
+ # I want to deprecate these later, so I'll first be silent about them, and later delete them.
134
195
  alias fast_unparse fast_generate
135
196
  module_function :fast_unparse
197
+ # :startdoc:
136
198
 
137
199
  # Unparse the Ruby data structure _obj_ into a JSON string and return it. The
138
200
  # returned string is a prettier form of the string returned by #unparse.
139
- def pretty_generate(obj)
201
+ #
202
+ # The _opts_ argument can be used to configure the generator, see the
203
+ # generate method for a more detailed explanation.
204
+ def pretty_generate(obj, opts = nil)
140
205
  state = JSON.state.new(
141
206
  :indent => ' ',
142
207
  :space => ' ',
@@ -144,11 +209,94 @@ module JSON
144
209
  :array_nl => "\n",
145
210
  :check_circular => true
146
211
  )
212
+ if opts
213
+ if opts.respond_to? :to_hash
214
+ opts = opts.to_hash
215
+ elsif opts.respond_to? :to_h
216
+ opts = opts.to_h
217
+ else
218
+ raise TypeError, "can't convert #{opts.class} into Hash"
219
+ end
220
+ state.configure(opts)
221
+ end
147
222
  obj.to_json(state)
148
223
  end
149
224
 
225
+ # :stopdoc:
226
+ # I want to deprecate these later, so I'll first be silent about them, and later delete them.
150
227
  alias pretty_unparse pretty_generate
151
228
  module_function :pretty_unparse
229
+ # :startdoc:
230
+
231
+ # Load a ruby data structure from a JSON _source_ and return it. A source can
232
+ # either be a string like object, an IO like object, or an object responding
233
+ # to the read method. If _proc_ was given, it will be called with any nested
234
+ # Ruby object as an argument recursively in depth first order.
235
+ #
236
+ # This method is part of the implementation of the load/dump interface of
237
+ # Marshal and YAML.
238
+ def load(source, proc = nil)
239
+ if source.respond_to? :to_str
240
+ source = source.to_str
241
+ elsif source.respond_to? :to_io
242
+ source = source.to_io.read
243
+ else
244
+ source = source.read
245
+ end
246
+ result = parse(source, :max_nesting => false, :allow_nan => true)
247
+ recurse_proc(result, &proc) if proc
248
+ result
249
+ end
250
+
251
+ def recurse_proc(result, &proc)
252
+ case result
253
+ when Array
254
+ result.each { |x| recurse_proc x, &proc }
255
+ proc.call result
256
+ when Hash
257
+ result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc }
258
+ proc.call result
259
+ else
260
+ proc.call result
261
+ end
262
+ end
263
+ private :recurse_proc
264
+ module_function :recurse_proc
265
+
266
+ alias restore load
267
+ module_function :restore
268
+
269
+ # Dumps _obj_ as a JSON string, i.e. calls generate on the object and returns
270
+ # the result.
271
+ #
272
+ # If anIO (an IO like object or an object that responds to the write method)
273
+ # was given, the resulting JSON is written to it.
274
+ #
275
+ # If the number of nested arrays or objects exceeds _limit_ an ArgumentError
276
+ # exception is raised. This argument is similar (but not exactly the
277
+ # same!) to the _limit_ argument in Marshal.dump.
278
+ #
279
+ # This method is part of the implementation of the load/dump interface of
280
+ # Marshal and YAML.
281
+ def dump(obj, anIO = nil, limit = nil)
282
+ if anIO and limit.nil?
283
+ anIO = anIO.to_io if anIO.respond_to?(:to_io)
284
+ unless anIO.respond_to?(:write)
285
+ limit = anIO
286
+ anIO = nil
287
+ end
288
+ end
289
+ limit ||= 0
290
+ result = generate(obj, :allow_nan => true, :max_nesting => limit)
291
+ if anIO
292
+ anIO.write result
293
+ anIO
294
+ else
295
+ result
296
+ end
297
+ rescue JSON::NestingError
298
+ raise ArgumentError, "exceed depth limit"
299
+ end
152
300
  end
153
301
 
154
302
  module ::Kernel
@@ -156,7 +304,7 @@ module ::Kernel
156
304
  # one line.
157
305
  def j(*objs)
158
306
  objs.each do |obj|
159
- puts JSON::generate(obj)
307
+ puts JSON::generate(obj, :allow_nan => true, :max_nesting => false)
160
308
  end
161
309
  nil
162
310
  end
@@ -165,19 +313,22 @@ module ::Kernel
165
313
  # indentation and over many lines.
166
314
  def jj(*objs)
167
315
  objs.each do |obj|
168
- puts JSON::pretty_generate(obj)
316
+ puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
169
317
  end
170
318
  nil
171
319
  end
172
320
 
173
- # If object is string like parse the string and return the parsed result as a
174
- # Ruby data structure. Otherwise generate a JSON text from the Ruby data
321
+ # If _object_ is string like parse the string and return the parsed result as
322
+ # a Ruby data structure. Otherwise generate a JSON text from the Ruby data
175
323
  # structure object and return it.
176
- def JSON(object)
324
+ #
325
+ # The _opts_ argument is passed through to generate/parse respectively, see
326
+ # generate and parse for their documentation.
327
+ def JSON(object, opts = {})
177
328
  if object.respond_to? :to_str
178
- JSON.parse(object.to_str)
329
+ JSON.parse(object.to_str, opts)
179
330
  else
180
- JSON.generate(object)
331
+ JSON.generate(object, opts)
181
332
  end
182
333
  end
183
334
  end