oj 2.14.6 → 2.15.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -157,11 +157,26 @@ Oj.default_options = {:mode => :compat }
157
157
  * `:quirks_mode` [Boolean] Allow single JSON values instead of
158
158
  documents, default is true (allow).
159
159
 
160
+ * `:nan` [:null|:huge|:word|:raise|:auto] How to dump Infinity, -Infinity, and
161
+ NaN in null, strict, and compat mode. :null places a null, :huge places a huge
162
+ number, :word places Infinity or NaN, :raise raises and exception, :auto uses
163
+ default for each mode which are :raise for :strict, :null for :null, and :word
164
+ for :compat. Default is :auto.
165
+
160
166
  ## Releases
161
167
 
162
- **Release 2.14.6**
168
+ ** Release 2.15.0**
169
+
170
+ - Fixed bug where encoded strings could be GCed.
171
+
172
+ - :nan option added for dumping Infinity, -Infinity, and NaN. This is an
173
+ edition to the API. The default value for the :non option is :auto which uses
174
+ the previous NaN handling on dumping of non-object modes.
175
+
176
+ **Release 2.14.7**
163
177
 
164
- - Changed JSON::ParserError to inherit from JSON::JSONError which inherits from StandardError.
178
+ - Fixed bug where a comment before another JSON element caused an
179
+ error. Comments are not part of the spec but this keep support consistent.
165
180
 
166
181
  [Older release notes](http://www.ohler.com/dev/oj_misc/release_notes.html).
167
182
 
@@ -441,13 +441,17 @@ dump_bignum(VALUE obj, Out out) {
441
441
  *out->cur = '\0';
442
442
  }
443
443
 
444
+ static const char inf_val[] = INF_VAL;
445
+ static const char ninf_val[] = NINF_VAL;
446
+ static const char nan_val[] = NAN_VAL;
447
+
444
448
  // Removed dependencies on math due to problems with CentOS 5.4.
445
449
  static void
446
450
  dump_float(VALUE obj, Out out) {
447
451
  char buf[64];
448
452
  char *b;
449
453
  double d = rb_num2dbl(obj);
450
- int cnt;
454
+ int cnt = 0;
451
455
 
452
456
  if (0.0 == d) {
453
457
  b = buf;
@@ -457,43 +461,106 @@ dump_float(VALUE obj, Out out) {
457
461
  *b++ = '\0';
458
462
  cnt = 3;
459
463
  } else if (OJ_INFINITY == d) {
460
- switch (out->opts->mode) {
461
- case StrictMode:
462
- raise_strict(obj);
463
- case NullMode:
464
- strcpy(buf, "null");
465
- cnt = 4;
466
- break;
467
- default:
468
- strcpy(buf, "Infinity");
469
- cnt = 8;
470
- break;
464
+ if (ObjectMode == out->opts->mode) {
465
+ strcpy(buf, inf_val);
466
+ cnt = sizeof(inf_val) - 1;
467
+ } else {
468
+ NanDump nd = out->opts->dump_opts.nan_dump;
469
+
470
+ if (AutoNan == nd) {
471
+ switch (out->opts->mode) {
472
+ case CompatMode: nd = WordNan; break;
473
+ case StrictMode: nd = RaiseNan; break;
474
+ case NullMode: nd = NullNan; break;
475
+ default: break;
476
+ }
477
+ }
478
+ switch (nd) {
479
+ case RaiseNan:
480
+ raise_strict(obj);
481
+ break;
482
+ case WordNan:
483
+ strcpy(buf, "Infinity");
484
+ cnt = 8;
485
+ break;
486
+ case NullNan:
487
+ strcpy(buf, "null");
488
+ cnt = 4;
489
+ break;
490
+ case HugeNan:
491
+ default:
492
+ strcpy(buf, inf_val);
493
+ cnt = sizeof(inf_val) - 1;
494
+ break;
495
+ }
471
496
  }
472
497
  } else if (-OJ_INFINITY == d) {
473
- switch (out->opts->mode) {
474
- case StrictMode:
475
- raise_strict(obj);
476
- case NullMode:
477
- strcpy(buf, "null");
478
- cnt = 4;
479
- break;
480
- default:
481
- strcpy(buf, "-Infinity");
482
- cnt = 9;
483
- break;
498
+ if (ObjectMode == out->opts->mode) {
499
+ strcpy(buf, ninf_val);
500
+ cnt = sizeof(ninf_val) - 1;
501
+ } else {
502
+ NanDump nd = out->opts->dump_opts.nan_dump;
503
+
504
+ if (AutoNan == nd) {
505
+ switch (out->opts->mode) {
506
+ case CompatMode: nd = WordNan; break;
507
+ case StrictMode: nd = RaiseNan; break;
508
+ case NullMode: nd = NullNan; break;
509
+ default: break;
510
+ }
511
+ }
512
+ switch (nd) {
513
+ case RaiseNan:
514
+ raise_strict(obj);
515
+ break;
516
+ case WordNan:
517
+ strcpy(buf, "-Infinity");
518
+ cnt = 9;
519
+ break;
520
+ case NullNan:
521
+ strcpy(buf, "null");
522
+ cnt = 4;
523
+ break;
524
+ case HugeNan:
525
+ default:
526
+ strcpy(buf, ninf_val);
527
+ cnt = sizeof(ninf_val) - 1;
528
+ break;
529
+ }
484
530
  }
485
531
  } else if (isnan(d)) {
486
- switch (out->opts->mode) {
487
- case StrictMode:
488
- raise_strict(obj);
489
- case NullMode:
490
- strcpy(buf, "null");
491
- cnt = 4;
492
- break;
493
- default:
494
- strcpy(buf, "NaN");
495
- cnt = 3;
496
- break;
532
+ if (ObjectMode == out->opts->mode) {
533
+ strcpy(buf, nan_val);
534
+ cnt = sizeof(nan_val) - 1;
535
+ } else {
536
+ NanDump nd = out->opts->dump_opts.nan_dump;
537
+
538
+ if (AutoNan == nd) {
539
+ switch (out->opts->mode) {
540
+ case CompatMode: nd = WordNan; break;
541
+ case StrictMode: nd = RaiseNan; break;
542
+ case NullMode: nd = NullNan; break;
543
+ default: break;
544
+ }
545
+ }
546
+ switch (nd) {
547
+ case RaiseNan:
548
+ raise_strict(obj);
549
+ break;
550
+ case WordNan:
551
+ strcpy(buf, "NaN");
552
+ cnt = 3;
553
+ break;
554
+ case NullNan:
555
+ strcpy(buf, "null");
556
+ cnt = 4;
557
+ break;
558
+ case HugeNan:
559
+ default:
560
+ strcpy(buf, nan_val);
561
+ cnt = sizeof(nan_val) - 1;
562
+ break;
563
+ }
497
564
  }
498
565
  } else if (d == (double)(long long int)d) {
499
566
  cnt = snprintf(buf, sizeof(buf), "%.1f", d);
@@ -120,15 +120,18 @@ static VALUE create_id_sym;
120
120
  static VALUE escape_mode_sym;
121
121
  static VALUE float_prec_sym;
122
122
  static VALUE float_sym;
123
+ static VALUE huge_sym;
123
124
  static VALUE indent_sym;
124
- static VALUE json_sym;
125
125
  static VALUE json_parser_error_class;
126
+ static VALUE json_sym;
126
127
  static VALUE mode_sym;
128
+ static VALUE nan_sym;
127
129
  static VALUE newline_sym;
128
130
  static VALUE nilnil_sym;
129
131
  static VALUE null_sym;
130
132
  static VALUE object_sym;
131
133
  static VALUE quirks_mode_sym;
134
+ static VALUE raise_sym;
132
135
  static VALUE ruby_sym;
133
136
  static VALUE sec_prec_sym;
134
137
  static VALUE strict_sym;
@@ -137,6 +140,7 @@ static VALUE time_format_sym;
137
140
  static VALUE unix_sym;
138
141
  static VALUE unix_zone_sym;
139
142
  static VALUE use_to_json_sym;
143
+ static VALUE word_sym;
140
144
  static VALUE xmlschema_sym;
141
145
  static VALUE xss_safe_sym;
142
146
 
@@ -194,6 +198,7 @@ struct _Options oj_default_options = {
194
198
  0, // after_size
195
199
  0, // hash_size
196
200
  0, // array_size
201
+ AutoNan,// nan_dump
197
202
  }
198
203
  };
199
204
 
@@ -224,6 +229,7 @@ static VALUE define_mimic_json(int argc, VALUE *argv, VALUE self);
224
229
  * - space_before: [String|nil] String to use before the colon separator in JSON object fields
225
230
  * - object_nl: [String|nil] String to use after a JSON object field value
226
231
  * - array_nl: [String|nil] String to use after a JSON array value
232
+ * - nan: [:null|:huge|:word|:raise|:auto] how to dump Infinity and NaN in null, strict, and compat mode. :null places a null, :huge places a huge number, :word places Infinity or NaN, :raise raises and exception, :auto uses default for each mode.
227
233
  * @return [Hash] all current option settings.
228
234
  */
229
235
  static VALUE
@@ -279,6 +285,14 @@ get_def_opts(VALUE self) {
279
285
  rb_hash_aset(opts, object_nl_sym, (0 == oj_default_options.dump_opts.hash_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.hash_nl));
280
286
  rb_hash_aset(opts, array_nl_sym, (0 == oj_default_options.dump_opts.array_size) ? Qnil : rb_str_new2(oj_default_options.dump_opts.array_nl));
281
287
 
288
+ switch (oj_default_options.dump_opts.nan_dump) {
289
+ case NullNan: rb_hash_aset(opts, nan_sym, null_sym); break;
290
+ case RaiseNan: rb_hash_aset(opts, nan_sym, raise_sym); break;
291
+ case WordNan: rb_hash_aset(opts, nan_sym, word_sym); break;
292
+ case HugeNan: rb_hash_aset(opts, nan_sym, huge_sym); break;
293
+ case AutoNan:
294
+ default: rb_hash_aset(opts, nan_sym, auto_sym); break;
295
+ }
282
296
  return opts;
283
297
  }
284
298
 
@@ -321,6 +335,7 @@ get_def_opts(VALUE self) {
321
335
  * @param [String|nil] :space_before String to use before the colon separator in JSON object fields
322
336
  * @param [String|nil] :object_nl String to use after a JSON object field value
323
337
  * @param [String|nil] :array_nl String to use after a JSON array value
338
+ * @param [:null|:huge|:word|:raise] :nan how to dump Infinity and NaN in null, strict, and compat mode. :null places a null, :huge places a huge number, :word places Infinity or NaN, :raise raises and exception, :auto uses default for each mode.
324
339
  * @return [nil]
325
340
  */
326
341
  static VALUE
@@ -546,6 +561,21 @@ oj_parse_options(VALUE ropts, Options copts) {
546
561
  copts->dump_opts.array_size = (uint8_t)len;
547
562
  }
548
563
  }
564
+ if (Qnil != (v = rb_hash_lookup(ropts, nan_sym))) {
565
+ if (null_sym == v) {
566
+ copts->dump_opts.nan_dump = NullNan;
567
+ } else if (huge_sym == v) {
568
+ copts->dump_opts.nan_dump = HugeNan;
569
+ } else if (word_sym == v) {
570
+ copts->dump_opts.nan_dump = WordNan;
571
+ } else if (raise_sym == v) {
572
+ copts->dump_opts.nan_dump = RaiseNan;
573
+ } else if (auto_sym == v) {
574
+ copts->dump_opts.nan_dump = AutoNan;
575
+ } else {
576
+ rb_raise(rb_eArgError, ":nan must be :null, :huge, :word, :raise, or :auto.");
577
+ }
578
+ }
549
579
  copts->dump_opts.use = (0 < copts->dump_opts.indent_size ||
550
580
  0 < copts->dump_opts.after_size ||
551
581
  0 < copts->dump_opts.before_size ||
@@ -1832,6 +1862,7 @@ static struct _Options mimic_object_to_json_options = {
1832
1862
  0, // after_size
1833
1863
  0, // hash_size
1834
1864
  0, // array_size
1865
+ AutoNan,// nan_dump
1835
1866
  }
1836
1867
  };
1837
1868
 
@@ -2120,11 +2151,11 @@ void Init_oj() {
2120
2151
  json_parser_error_class = Qnil; // replaced if mimic is called
2121
2152
 
2122
2153
  allow_gc_sym = ID2SYM(rb_intern("allow_gc")); rb_gc_register_address(&allow_gc_sym);
2154
+ array_nl_sym = ID2SYM(rb_intern("array_nl")); rb_gc_register_address(&array_nl_sym);
2123
2155
  ascii_only_sym = ID2SYM(rb_intern("ascii_only")); rb_gc_register_address(&ascii_only_sym);
2124
2156
  ascii_sym = ID2SYM(rb_intern("ascii")); rb_gc_register_address(&ascii_sym);
2125
2157
  auto_define_sym = ID2SYM(rb_intern("auto_define")); rb_gc_register_address(&auto_define_sym);
2126
2158
  auto_sym = ID2SYM(rb_intern("auto")); rb_gc_register_address(&auto_sym);
2127
- array_nl_sym = ID2SYM(rb_intern("array_nl")); rb_gc_register_address(&array_nl_sym);
2128
2159
  bigdecimal_as_decimal_sym = ID2SYM(rb_intern("bigdecimal_as_decimal"));rb_gc_register_address(&bigdecimal_as_decimal_sym);
2129
2160
  bigdecimal_load_sym = ID2SYM(rb_intern("bigdecimal_load"));rb_gc_register_address(&bigdecimal_load_sym);
2130
2161
  bigdecimal_sym = ID2SYM(rb_intern("bigdecimal")); rb_gc_register_address(&bigdecimal_sym);
@@ -2135,15 +2166,18 @@ void Init_oj() {
2135
2166
  escape_mode_sym = ID2SYM(rb_intern("escape_mode")); rb_gc_register_address(&escape_mode_sym);
2136
2167
  float_prec_sym = ID2SYM(rb_intern("float_precision"));rb_gc_register_address(&float_prec_sym);
2137
2168
  float_sym = ID2SYM(rb_intern("float")); rb_gc_register_address(&float_sym);
2169
+ huge_sym = ID2SYM(rb_intern("huge")); rb_gc_register_address(&huge_sym);
2138
2170
  indent_sym = ID2SYM(rb_intern("indent")); rb_gc_register_address(&indent_sym);
2139
2171
  json_sym = ID2SYM(rb_intern("json")); rb_gc_register_address(&json_sym);
2140
2172
  mode_sym = ID2SYM(rb_intern("mode")); rb_gc_register_address(&mode_sym);
2173
+ nan_sym = ID2SYM(rb_intern("nan")); rb_gc_register_address(&nan_sym);
2141
2174
  newline_sym = ID2SYM(rb_intern("newline")); rb_gc_register_address(&newline_sym);
2142
2175
  nilnil_sym = ID2SYM(rb_intern("nilnil")); rb_gc_register_address(&nilnil_sym);
2143
2176
  null_sym = ID2SYM(rb_intern("null")); rb_gc_register_address(&null_sym);
2144
2177
  object_nl_sym = ID2SYM(rb_intern("object_nl")); rb_gc_register_address(&object_nl_sym);
2145
2178
  object_sym = ID2SYM(rb_intern("object")); rb_gc_register_address(&object_sym);
2146
2179
  quirks_mode_sym = ID2SYM(rb_intern("quirks_mode")); rb_gc_register_address(&quirks_mode_sym);
2180
+ raise_sym = ID2SYM(rb_intern("raise")); rb_gc_register_address(&raise_sym);
2147
2181
  ruby_sym = ID2SYM(rb_intern("ruby")); rb_gc_register_address(&ruby_sym);
2148
2182
  sec_prec_sym = ID2SYM(rb_intern("second_precision"));rb_gc_register_address(&sec_prec_sym);
2149
2183
  space_before_sym = ID2SYM(rb_intern("space_before"));rb_gc_register_address(&space_before_sym);
@@ -2154,6 +2188,7 @@ void Init_oj() {
2154
2188
  unix_sym = ID2SYM(rb_intern("unix")); rb_gc_register_address(&unix_sym);
2155
2189
  unix_zone_sym = ID2SYM(rb_intern("unix_zone")); rb_gc_register_address(&unix_zone_sym);
2156
2190
  use_to_json_sym = ID2SYM(rb_intern("use_to_json")); rb_gc_register_address(&use_to_json_sym);
2191
+ word_sym = ID2SYM(rb_intern("word")); rb_gc_register_address(&word_sym);
2157
2192
  xmlschema_sym = ID2SYM(rb_intern("xmlschema")); rb_gc_register_address(&xmlschema_sym);
2158
2193
  xss_safe_sym = ID2SYM(rb_intern("xss_safe")); rb_gc_register_address(&xss_safe_sym);
2159
2194
 
@@ -68,6 +68,10 @@ enum st_retval {ST_CONTINUE = 0, ST_STOP = 1, ST_DELETE = 2, ST_CHECK};
68
68
 
69
69
  #include "err.h"
70
70
 
71
+ #define INF_VAL "3.0e14159265358979323846"
72
+ #define NINF_VAL "-3.0e14159265358979323846"
73
+ #define NAN_VAL "3.3e14159265358979323846"
74
+
71
75
  typedef enum {
72
76
  Yes = 'y',
73
77
  No = 'n',
@@ -108,6 +112,14 @@ typedef enum {
108
112
  ObjectType = 'o',
109
113
  } DumpType;
110
114
 
115
+ typedef enum {
116
+ AutoNan = 'a',
117
+ NullNan = 'n',
118
+ HugeNan = 'h',
119
+ WordNan = 'w',
120
+ RaiseNan = 'r',
121
+ } NanDump;
122
+
111
123
  typedef enum {
112
124
  STRING_IO = 'c',
113
125
  STREAM_IO = 's',
@@ -126,6 +138,7 @@ typedef struct _DumpOpts {
126
138
  uint8_t after_size;
127
139
  uint8_t hash_size;
128
140
  uint8_t array_size;
141
+ char nan_dump; // NanDump
129
142
  } *DumpOpts;
130
143
 
131
144
  typedef struct _Options {
@@ -481,6 +481,17 @@ read_num(ParseInfo pi) {
481
481
  }
482
482
  ni.len = pi->cur - ni.str;
483
483
  }
484
+ // Check for special reserved values for Infinity and NaN.
485
+ if (ni.big) {
486
+ if (0 == strcasecmp(INF_VAL, ni.str)) {
487
+ ni.infinity = 1;
488
+ } else if (0 == strcasecmp(NINF_VAL, ni.str)) {
489
+ ni.infinity = 1;
490
+ ni.neg = 1;
491
+ } else if (0 == strcasecmp(NAN_VAL, ni.str)) {
492
+ ni.nan = 1;
493
+ }
494
+ }
484
495
  if (BigDec == pi->options.bigdec_load) {
485
496
  ni.big = 1;
486
497
  }
@@ -644,6 +655,9 @@ oj_parse2(ParseInfo pi) {
644
655
  break;
645
656
  case '/':
646
657
  skip_comment(pi);
658
+ if (first) {
659
+ continue;
660
+ }
647
661
  break;
648
662
  case '\0':
649
663
  pi->cur--;
@@ -772,17 +786,18 @@ protect_parse(VALUE pip) {
772
786
  }
773
787
 
774
788
  extern int oj_utf8_index;
775
- void
776
- oj_pi_set_input_str(ParseInfo pi, volatile VALUE input) {
789
+
790
+ static void
791
+ oj_pi_set_input_str(ParseInfo pi, volatile VALUE *inputp) {
777
792
  #if HAS_ENCODING_SUPPORT
778
- rb_encoding *enc = rb_to_encoding(rb_obj_encoding(input));
793
+ rb_encoding *enc = rb_to_encoding(rb_obj_encoding(*inputp));
779
794
 
780
795
  if (rb_utf8_encoding() != enc) {
781
- input = rb_str_conv_enc(input, enc, rb_utf8_encoding());
796
+ *inputp = rb_str_conv_enc(*inputp, enc, rb_utf8_encoding());
782
797
  }
783
798
  #endif
784
- pi->json = rb_string_value_ptr((VALUE*)&input);
785
- pi->end = pi->json + RSTRING_LEN(input);
799
+ pi->json = rb_string_value_ptr((VALUE*)inputp);
800
+ pi->end = pi->json + RSTRING_LEN(*inputp);
786
801
  }
787
802
 
788
803
  VALUE
@@ -811,7 +826,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
811
826
  pi->end = json + len;
812
827
  free_json = 1;
813
828
  } else if (T_STRING == rb_type(input)) {
814
- oj_pi_set_input_str(pi, input);
829
+ oj_pi_set_input_str(pi, &input);
815
830
  } else if (Qnil == input && Yes == pi->options.nilnil) {
816
831
  return Qnil;
817
832
  } else {
@@ -820,7 +835,7 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
820
835
 
821
836
  if (oj_stringio_class == clas) {
822
837
  s = rb_funcall2(input, oj_string_id, 0, 0);
823
- oj_pi_set_input_str(pi, s);
838
+ oj_pi_set_input_str(pi, &s);
824
839
  #if !IS_WINDOWS
825
840
  } else if (rb_cFile == clas && 0 == FIX2INT(rb_funcall(input, oj_pos_id, 0))) {
826
841
  int fd = FIX2INT(rb_funcall(input, oj_fileno_id, 0));
@@ -93,7 +93,6 @@ typedef struct _ParseInfo {
93
93
 
94
94
  extern void oj_parse2(ParseInfo pi);
95
95
  extern void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char* file, int line, const char *format, ...);
96
- extern void oj_pi_set_input_str(ParseInfo pi, volatile VALUE input);
97
96
  extern VALUE oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk);
98
97
  extern VALUE oj_num_as_value(NumInfo ni);
99
98
 
@@ -487,11 +487,22 @@ read_num(ParseInfo pi) {
487
487
  reader_backup(&pi->rd);
488
488
  }
489
489
  }
490
+ ni.str = pi->rd.str;
491
+ ni.len = pi->rd.tail - pi->rd.str;
492
+ // Check for special reserved values for Infinity and NaN.
493
+ if (ni.big) {
494
+ if (0 == strcasecmp(INF_VAL, ni.str)) {
495
+ ni.infinity = 1;
496
+ } else if (0 == strcasecmp(NINF_VAL, ni.str)) {
497
+ ni.infinity = 1;
498
+ ni.neg = 1;
499
+ } else if (0 == strcasecmp(NAN_VAL, ni.str)) {
500
+ ni.nan = 1;
501
+ }
502
+ }
490
503
  if (BigDec == pi->options.bigdec_load) {
491
504
  ni.big = 1;
492
505
  }
493
- ni.str = pi->rd.str;
494
- ni.len = pi->rd.tail - pi->rd.str;
495
506
  add_num_value(pi, &ni);
496
507
  reader_release(&pi->rd);
497
508
  }