oj 2.14.6 → 2.15.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.
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
  }