oj 3.7.12 → 3.8.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.
@@ -53,6 +53,7 @@ ID oj_length_id;
53
53
  ID oj_new_id;
54
54
  ID oj_parse_id;
55
55
  ID oj_pos_id;
56
+ ID oj_raw_json_id;
56
57
  ID oj_read_id;
57
58
  ID oj_readpartial_id;
58
59
  ID oj_replace_id;
@@ -94,6 +95,7 @@ VALUE oj_hash_class_sym;
94
95
  VALUE oj_indent_sym;
95
96
  VALUE oj_object_class_sym;
96
97
  VALUE oj_quirks_mode_sym;
98
+ VALUE oj_safe_sym;
97
99
  VALUE oj_trace_sym;
98
100
 
99
101
  static VALUE allow_blank_sym;
@@ -137,6 +139,7 @@ static VALUE unicode_xss_sym;
137
139
  static VALUE unix_sym;
138
140
  static VALUE unix_zone_sym;
139
141
  static VALUE use_as_json_sym;
142
+ static VALUE use_raw_json_sym;
140
143
  static VALUE use_to_hash_sym;
141
144
  static VALUE use_to_json_sym;
142
145
  static VALUE wab_sym;
@@ -168,6 +171,7 @@ struct _options oj_default_options = {
168
171
  No, // to_hash
169
172
  No, // to_json
170
173
  No, // as_json
174
+ No, // raw_json
171
175
  No, // nilnil
172
176
  Yes, // empty_string
173
177
  Yes, // allow_gc
@@ -176,6 +180,7 @@ struct _options oj_default_options = {
176
180
  No, // create_ok
177
181
  Yes, // allow_nan
178
182
  No, // trace
183
+ No, // safe
179
184
  0, // integer_range_min
180
185
  0, // integer_range_max
181
186
  oj_json_class, // create_id
@@ -229,6 +234,7 @@ struct _options oj_default_options = {
229
234
  * - *:float_precision* [_Fixnum_|_nil_] number of digits of precision when dumping floats, 0 indicates use Ruby
230
235
  * - *:use_to_json* [_Boolean_|_nil_] call to_json() methods on dump, default is false
231
236
  * - *:use_as_json* [_Boolean_|_nil_] call as_json() methods on dump, default is false
237
+ * - *:use_raw_json* [_Boolean_|_nil_] call raw_json() methods on dump, default is false
232
238
  * - *:nilnil* [_Boolean_|_nil_] if true a nil input to load will return nil and not raise an Exception
233
239
  * - *:empty_string* [_Boolean_|_nil_] if true an empty input will not raise an Exception
234
240
  * - *:allow_gc* [_Boolean_|_nil_] allow or prohibit GC during parsing, default is true (allow)
@@ -245,8 +251,9 @@ struct _options oj_default_options = {
245
251
  * - *:array_class* [_Class_|_nil_] Class to use instead of Array on load
246
252
  * - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil values are omitted
247
253
  * - *:ignore* [_nil_|Array] either nil or an Array of classes to ignore when dumping
248
- * - *:integer_range* [_Range_] Dump integers outside range as strings.
254
+ * - *:integer_range* [_Range_] Dump integers outside range as strings.
249
255
  * - *:trace* [_true,_|_false_] Trace all load and dump calls, default is false (trace is off)
256
+ * - *:safe* [_true,_|_false_] Safe mimic breaks JSON mimic to be safer, default is false (safe is off)
250
257
  *
251
258
  * Return [_Hash_] all current option settings.
252
259
  */
@@ -269,6 +276,7 @@ get_def_opts(VALUE self) {
269
276
  rb_hash_aset(opts, use_to_json_sym, (Yes == oj_default_options.to_json) ? Qtrue : ((No == oj_default_options.to_json) ? Qfalse : Qnil));
270
277
  rb_hash_aset(opts, use_to_hash_sym, (Yes == oj_default_options.to_hash) ? Qtrue : ((No == oj_default_options.to_hash) ? Qfalse : Qnil));
271
278
  rb_hash_aset(opts, use_as_json_sym, (Yes == oj_default_options.as_json) ? Qtrue : ((No == oj_default_options.as_json) ? Qfalse : Qnil));
279
+ rb_hash_aset(opts, use_raw_json_sym, (Yes == oj_default_options.raw_json) ? Qtrue : ((No == oj_default_options.raw_json) ? Qfalse : Qnil));
272
280
  rb_hash_aset(opts, nilnil_sym, (Yes == oj_default_options.nilnil) ? Qtrue : ((No == oj_default_options.nilnil) ? Qfalse : Qnil));
273
281
  rb_hash_aset(opts, empty_string_sym, (Yes == oj_default_options.empty_string) ? Qtrue : ((No == oj_default_options.empty_string) ? Qfalse : Qnil));
274
282
  rb_hash_aset(opts, allow_gc_sym, (Yes == oj_default_options.allow_gc) ? Qtrue : ((No == oj_default_options.allow_gc) ? Qfalse : Qnil));
@@ -276,6 +284,7 @@ get_def_opts(VALUE self) {
276
284
  rb_hash_aset(opts, allow_invalid_unicode_sym, (Yes == oj_default_options.allow_invalid) ? Qtrue : ((No == oj_default_options.allow_invalid) ? Qfalse : Qnil));
277
285
  rb_hash_aset(opts, oj_allow_nan_sym, (Yes == oj_default_options.allow_nan) ? Qtrue : ((No == oj_default_options.allow_nan) ? Qfalse : Qnil));
278
286
  rb_hash_aset(opts, oj_trace_sym, (Yes == oj_default_options.trace) ? Qtrue : ((No == oj_default_options.trace) ? Qfalse : Qnil));
287
+ rb_hash_aset(opts, oj_safe_sym, (Yes == oj_default_options.safe) ? Qtrue : ((No == oj_default_options.safe) ? Qfalse : Qnil));
279
288
  rb_hash_aset(opts, float_prec_sym, INT2FIX(oj_default_options.float_prec));
280
289
  switch (oj_default_options.mode) {
281
290
  case StrictMode: rb_hash_aset(opts, mode_sym, strict_sym); break;
@@ -287,7 +296,7 @@ get_def_opts(VALUE self) {
287
296
  case WabMode: rb_hash_aset(opts, mode_sym, wab_sym); break;
288
297
  default: rb_hash_aset(opts, mode_sym, object_sym); break;
289
298
  }
290
-
299
+
291
300
  if (oj_default_options.integer_range_max != 0 || oj_default_options.integer_range_min != 0) {
292
301
  VALUE range = rb_obj_alloc(rb_cRange);
293
302
  VALUE min = LONG2FIX(oj_default_options.integer_range_min);
@@ -343,7 +352,7 @@ get_def_opts(VALUE self) {
343
352
  } else {
344
353
  VALUE *vp;
345
354
  volatile VALUE a = rb_ary_new();
346
-
355
+
347
356
  for (vp = oj_default_options.ignore; Qnil != *vp; vp++) {
348
357
  rb_ary_push(a, *vp);
349
358
  }
@@ -374,6 +383,7 @@ get_def_opts(VALUE self) {
374
383
  * - *:use_to_json* [_Boolean_|_nil_] call to_json() methods on dump, default is false.
375
384
  * - *:use_as_json* [_Boolean_|_nil_] call as_json() methods on dump, default is false.
376
385
  * - *:use_to_hash* [_Boolean_|_nil_] call to_hash() methods on dump, default is false.
386
+ * - *:use_raw_json* [_Boolean_|_nil_] call raw_json() methods on dump, default is false.
377
387
  * - *:nilnil* [_Boolean_|_nil_] if true a nil input to load will return nil and not raise an Exception.
378
388
  * - *:allow_gc* [_Boolean_|_nil_] allow or prohibit GC during parsing, default is true (allow).
379
389
  * - *:quirks_mode* [_Boolean_|_nil_] allow single JSON values instead of documents, default is true (allow).
@@ -388,8 +398,9 @@ get_def_opts(VALUE self) {
388
398
  * - *:array_class* [_Class_|_nil_] Class to use instead of Array on load.
389
399
  * - *:omit_nil* [_true_|_false_] if true Hash and Object attributes with nil values are omitted.
390
400
  * - *:ignore* [_nil_|Array] either nil or an Array of classes to ignore when dumping
391
- * - *:integer_range* [_Range_] Dump integers outside range as strings.
401
+ * - *:integer_range* [_Range_] Dump integers outside range as strings.
392
402
  * - *:trace* [_Boolean_] turn trace on or off.
403
+ * - *:safe* [_Boolean_] turn safe mimic on or off.
393
404
  */
394
405
  static VALUE
395
406
  set_def_opts(VALUE self, VALUE opts) {
@@ -410,6 +421,7 @@ oj_parse_options(VALUE ropts, Options copts) {
410
421
  { use_to_hash_sym, &copts->to_hash },
411
422
  { use_to_json_sym, &copts->to_json },
412
423
  { use_as_json_sym, &copts->as_json },
424
+ { use_raw_json_sym, &copts->raw_json },
413
425
  { nilnil_sym, &copts->nilnil },
414
426
  { allow_blank_sym, &copts->nilnil }, // same as nilnil
415
427
  { empty_string_sym, &copts->empty_string },
@@ -418,13 +430,14 @@ oj_parse_options(VALUE ropts, Options copts) {
418
430
  { allow_invalid_unicode_sym, &copts->allow_invalid },
419
431
  { oj_allow_nan_sym, &copts->allow_nan },
420
432
  { oj_trace_sym, &copts->trace },
433
+ { oj_safe_sym, &copts->safe },
421
434
  { oj_create_additions_sym, &copts->create_ok },
422
435
  { Qnil, 0 }
423
436
  };
424
437
  YesNoOpt o;
425
438
  volatile VALUE v;
426
439
  size_t len;
427
-
440
+
428
441
  if (T_HASH != rb_type(ropts)) {
429
442
  return;
430
443
  }
@@ -715,7 +728,7 @@ oj_parse_options(VALUE ropts, Options copts) {
715
728
  cnt = (int)RARRAY_LEN(v);
716
729
  if (0 < cnt) {
717
730
  int i;
718
-
731
+
719
732
  copts->ignore = ALLOC_N(VALUE, cnt + 1);
720
733
  for (i = 0; i < cnt; i++) {
721
734
  copts->ignore[i] = rb_ary_entry(v, i);
@@ -802,11 +815,10 @@ oj_parse_opt_match_string(RxClass rc, VALUE ropts) {
802
815
  *
803
816
  * - *json* [_String_|_IO_] JSON String or an Object that responds to read()
804
817
  * - *options* [_Hash_] load options (same as default_options)
805
- * - -
806
818
  * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
807
819
  * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
808
820
  * - *len* [_optional, _Integer_] length of parsed JSON for obj.
809
- *
821
+ *
810
822
  * Returns [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_]
811
823
  */
812
824
  static VALUE
@@ -889,7 +901,6 @@ load(int argc, VALUE *argv, VALUE self) {
889
901
  *
890
902
  * - *path* [_String_] to a file containing a JSON document
891
903
  * - *options* [_Hash_] load options (same as default_options)
892
- * - -
893
904
  * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
894
905
  * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
895
906
  * - *len* [_optional, _Integer_] length of parsed JSON for obj.
@@ -1064,7 +1075,7 @@ dump(int argc, VALUE *argv, VALUE self) {
1064
1075
  * Dumps an Object (obj) to a string. If the object has a to_json method that
1065
1076
  * will be called. The mode is set to :compat.
1066
1077
  * - *obj* [_Object_] Object to serialize as an JSON document String
1067
- * - *options* [_Hash_]
1078
+ * - *options* [_Hash_]
1068
1079
  * - *:max_nesting* [_boolean_] It true nesting is limited to 100. The option to detect circular references is available but is not compatible with the json gem., default is false
1069
1080
  * - *:allow_nan* [_boolean_] If true non JSON compliant words such as Nan and Infinity will be used as appropriate, default is true.
1070
1081
  * - *:quirks_mode* [_boolean_] Allow single JSON values instead of documents, default is true (allow).
@@ -1126,7 +1137,7 @@ to_json(int argc, VALUE *argv, VALUE self) {
1126
1137
  static VALUE
1127
1138
  to_file(int argc, VALUE *argv, VALUE self) {
1128
1139
  struct _options copts = oj_default_options;
1129
-
1140
+
1130
1141
  if (3 == argc) {
1131
1142
  oj_parse_options(argv[2], &copts);
1132
1143
  }
@@ -1149,7 +1160,7 @@ to_file(int argc, VALUE *argv, VALUE self) {
1149
1160
  static VALUE
1150
1161
  to_stream(int argc, VALUE *argv, VALUE self) {
1151
1162
  struct _options copts = oj_default_options;
1152
-
1163
+
1153
1164
  if (3 == argc) {
1154
1165
  oj_parse_options(argv[2], &copts);
1155
1166
  }
@@ -1265,7 +1276,6 @@ register_odd_raw(int argc, VALUE *argv, VALUE self) {
1265
1276
  *
1266
1277
  * - *json* [_String_|_IO_] JSON String or an Object that responds to read().
1267
1278
  * - *options* [_Hash_] load options (same as default_options).
1268
- * - -
1269
1279
  * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
1270
1280
  * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
1271
1281
  * - *len* [_optional, _Integer_] length of parsed JSON for obj.
@@ -1300,7 +1310,6 @@ extern VALUE oj_strict_parse(int argc, VALUE *argv, VALUE self);
1300
1310
  *
1301
1311
  * - *json* [_String_|_IO_] JSON String or an Object that responds to read().
1302
1312
  * - *options* [_Hash_] load options (same as default_options).
1303
- * - -
1304
1313
  * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
1305
1314
  * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
1306
1315
  * - *len* [_optional, _Integer_] length of parsed JSON for obj.
@@ -1331,7 +1340,6 @@ extern VALUE oj_compat_parse(int argc, VALUE *argv, VALUE self);
1331
1340
  *
1332
1341
  * - *json* [_String_|_IO_] JSON String or an Object that responds to read().
1333
1342
  * - *options* [_Hash_] load options (same as default_options).
1334
- * - -
1335
1343
  * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
1336
1344
  * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
1337
1345
  * - *len* [_optional, _Integer_] length of parsed JSON for obj.
@@ -1367,7 +1375,6 @@ extern VALUE oj_object_parse(int argc, VALUE *argv, VALUE self);
1367
1375
  *
1368
1376
  * - *json* [_String_|_IO_] JSON String or an Object that responds to read().
1369
1377
  * - *options* [_Hash_] load options (same as default_options).
1370
- * - -
1371
1378
  * - *obj* [_Hash_|_Array_|_String_|_Fixnum_|_Float_|_Boolean_|_nil_] parsed object.
1372
1379
  * - *start* [_optional, _Integer_] start position of parsed JSON for obj.
1373
1380
  * - *len* [_optional, _Integer_] length of parsed JSON for obj.
@@ -1429,16 +1436,16 @@ extern VALUE oj_define_mimic_json(int argc, VALUE *argv, VALUE self);
1429
1436
 
1430
1437
  /* Document-method: generate
1431
1438
  * call-seq: generate(obj, opts=nil)
1432
- *
1439
+ *
1433
1440
  * Encode obj as a JSON String. The obj argument must be a Hash, Array, or
1434
1441
  * respond to to_h or to_json. Options other than those listed such as
1435
1442
  * +:allow_nan+ or +:max_nesting+ are ignored.
1436
- *
1443
+ *
1437
1444
  * - *obj* [_Object__|_Hash_|_Array_] object to convert to a JSON String
1438
1445
  * - *opts* [_Hash_] options
1439
- * - - *:indent* [_String_] String to use for indentation.
1446
+ * - *:indent* [_String_] String to use for indentation.
1440
1447
  * - *:space* [_String_] String placed after a , or : delimiter
1441
- * - *:space * _before [_String_] String placed before a : delimiter
1448
+ * - *:space_before* [_String_] String placed before a : delimiter
1442
1449
  * - *:object_nl* [_String_] String placed after a JSON object
1443
1450
  * - *:array_nl* [_String_] String placed after a JSON array
1444
1451
  * - *:ascii_only* [_Boolean_] if not nil or false then use only ascii characters in the output. Note JSON.generate does support this even if it is not documented.
@@ -1481,15 +1488,15 @@ protect_require(VALUE x) {
1481
1488
  * modes are:
1482
1489
  *
1483
1490
  * - *:strict* mode will only allow the 7 basic JSON types to be serialized. Any other Object
1484
- * will raise an Exception.
1485
- *
1491
+ * will raise an Exception.
1492
+ *
1486
1493
  * - *:null* mode is similar to the :strict mode except any Object that is not
1487
1494
  * one of the JSON base types is replaced by a JSON null.
1488
- *
1495
+ *
1489
1496
  * - *:object* mode will dump any Object as a JSON Object with keys that match
1490
1497
  * the Ruby Object's variable names without the '@' character. This is the
1491
1498
  * highest performance mode.
1492
- *
1499
+ *
1493
1500
  * - *:compat* or *:json* mode is the compatible mode for the json gem. It mimics
1494
1501
  * the json gem including the options, defaults, and restrictions.
1495
1502
  *
@@ -1575,6 +1582,7 @@ Init_oj() {
1575
1582
  oj_new_id = rb_intern("new");
1576
1583
  oj_parse_id = rb_intern("parse");
1577
1584
  oj_pos_id = rb_intern("pos");
1585
+ oj_raw_json_id = rb_intern("raw_json");
1578
1586
  oj_read_id = rb_intern("read");
1579
1587
  oj_readpartial_id = rb_intern("readpartial");
1580
1588
  oj_replace_id = rb_intern("replace");
@@ -1651,6 +1659,7 @@ Init_oj() {
1651
1659
  oj_object_class_sym = ID2SYM(rb_intern("object_class")); rb_gc_register_address(&oj_object_class_sym);
1652
1660
  oj_object_nl_sym = ID2SYM(rb_intern("object_nl")); rb_gc_register_address(&oj_object_nl_sym);
1653
1661
  oj_quirks_mode_sym = ID2SYM(rb_intern("quirks_mode")); rb_gc_register_address(&oj_quirks_mode_sym);
1662
+ oj_safe_sym = ID2SYM(rb_intern("safe")); rb_gc_register_address(&oj_safe_sym);
1654
1663
  oj_space_before_sym = ID2SYM(rb_intern("space_before")); rb_gc_register_address(&oj_space_before_sym);
1655
1664
  oj_space_sym = ID2SYM(rb_intern("space")); rb_gc_register_address(&oj_space_sym);
1656
1665
  oj_trace_sym = ID2SYM(rb_intern("trace")); rb_gc_register_address(&oj_trace_sym);
@@ -1666,6 +1675,7 @@ Init_oj() {
1666
1675
  unix_sym = ID2SYM(rb_intern("unix")); rb_gc_register_address(&unix_sym);
1667
1676
  unix_zone_sym = ID2SYM(rb_intern("unix_zone")); rb_gc_register_address(&unix_zone_sym);
1668
1677
  use_as_json_sym = ID2SYM(rb_intern("use_as_json")); rb_gc_register_address(&use_as_json_sym);
1678
+ use_raw_json_sym = ID2SYM(rb_intern("use_raw_json")); rb_gc_register_address(&use_raw_json_sym);
1669
1679
  use_to_hash_sym = ID2SYM(rb_intern("use_to_hash")); rb_gc_register_address(&use_to_hash_sym);
1670
1680
  use_to_json_sym = ID2SYM(rb_intern("use_to_json")); rb_gc_register_address(&use_to_json_sym);
1671
1681
  wab_sym = ID2SYM(rb_intern("wab")); rb_gc_register_address(&wab_sym);
@@ -139,6 +139,7 @@ typedef struct _options {
139
139
  char to_hash; // YesNo
140
140
  char to_json; // YesNo
141
141
  char as_json; // YesNo
142
+ char raw_json; // YesNo
142
143
  char nilnil; // YesNo
143
144
  char empty_string; // YesNo
144
145
  char allow_gc; // allow GC during parse
@@ -147,6 +148,7 @@ typedef struct _options {
147
148
  char create_ok; // YesNo allow create_id
148
149
  char allow_nan; // YEsyNo for parsing only
149
150
  char trace; // YesNo
151
+ char safe; // YesNo
150
152
  int64_t integer_range_min; // dump numbers outside range as string
151
153
  int64_t integer_range_max;
152
154
  const char *create_id; // 0 or string
@@ -202,7 +204,7 @@ typedef struct _strWriter {
202
204
  char *types; // DumpType
203
205
  char *types_end;
204
206
  int keyWritten;
205
-
207
+
206
208
  } *StrWriter;
207
209
 
208
210
  typedef struct _streamWriter {
@@ -219,7 +221,7 @@ enum {
219
221
  COL_VAL = 0x02,
220
222
  RUBY_VAL = 0x03
221
223
  };
222
-
224
+
223
225
  typedef struct _leaf {
224
226
  struct _leaf *next;
225
227
  union {
@@ -349,6 +351,7 @@ extern ID oj_readpartial_id;
349
351
  extern ID oj_replace_id;
350
352
  extern ID oj_stat_id;
351
353
  extern ID oj_string_id;
354
+ extern ID oj_raw_json_id;
352
355
  extern ID oj_to_h_id;
353
356
  extern ID oj_to_hash_id;
354
357
  extern ID oj_to_json_id;
@@ -365,6 +368,7 @@ extern ID oj_write_id;
365
368
 
366
369
  extern bool oj_use_hash_alt;
367
370
  extern bool oj_use_array_alt;
371
+ extern bool string_writer_optimized;
368
372
 
369
373
  #if HAVE_LIBPTHREAD
370
374
  extern pthread_mutex_t oj_cache_mutex;
@@ -8,6 +8,7 @@
8
8
  #include <string.h>
9
9
  #include <unistd.h>
10
10
  #include <math.h>
11
+ #include <ruby/util.h>
11
12
 
12
13
  #include "oj.h"
13
14
  #include "encode.h"
@@ -1036,7 +1037,7 @@ CLEANUP:
1036
1037
  if (Qnil != pi->err_class) {
1037
1038
  pi->err.clas = pi->err_class;
1038
1039
  }
1039
- if (CompatMode == pi->options.mode) {
1040
+ if (CompatMode == pi->options.mode && Yes != pi->options.safe) {
1040
1041
  // The json gem requires the error message be UTF-8 encoded. In
1041
1042
  // additional the complete JSON source must be returned. There
1042
1043
  // does not seem to be a size limit.
@@ -750,6 +750,8 @@ optimize(int argc, VALUE *argv, ROptTable rot, bool on) {
750
750
  oj_rails_array_opt = on;
751
751
  } else if (rb_cFloat == *argv) {
752
752
  oj_rails_float_opt = on;
753
+ } else if (oj_string_writer_class == *argv) {
754
+ string_writer_optimized = on;
753
755
  } else if (NULL != (ro = oj_rails_get_opt(rot, *argv)) ||
754
756
  NULL != (ro = create_opt(rot, *argv))) {
755
757
  ro->on = on;
@@ -793,6 +795,7 @@ encoder_optimize(int argc, VALUE *argv, VALUE self) {
793
795
  static VALUE
794
796
  rails_optimize(int argc, VALUE *argv, VALUE self) {
795
797
  optimize(argc, argv, &ropts, true);
798
+ string_writer_optimized = true;
796
799
 
797
800
  return Qnil;
798
801
  }
@@ -844,6 +847,7 @@ encoder_deoptimize(int argc, VALUE *argv, VALUE self) {
844
847
  static VALUE
845
848
  rails_deoptimize(int argc, VALUE *argv, VALUE self) {
846
849
  optimize(argc, argv, &ropts, false);
850
+ string_writer_optimized = false;
847
851
 
848
852
  return Qnil;
849
853
  }
@@ -1401,6 +1405,8 @@ dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
1401
1405
 
1402
1406
  if (NULL != (ro = oj_rails_get_opt(out->ropts, rb_obj_class(obj))) && ro->on) {
1403
1407
  ro->dump(obj, depth, out, as_ok);
1408
+ } else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
1409
+ oj_dump_raw_json(obj, depth, out);
1404
1410
  } else if (rb_respond_to(obj, oj_as_json_id)) {
1405
1411
  dump_as_json(obj, depth, out, true);
1406
1412
  } else if (rb_respond_to(obj, oj_to_hash_id)) {
@@ -1408,6 +1414,8 @@ dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
1408
1414
  } else {
1409
1415
  oj_dump_obj_to_s(obj, out);
1410
1416
  }
1417
+ } else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
1418
+ oj_dump_raw_json(obj, depth, out);
1411
1419
  } else if (rb_respond_to(obj, oj_to_hash_id)) {
1412
1420
  // Always attempt to_hash.
1413
1421
  dump_to_hash(obj, depth, out);
@@ -632,7 +632,7 @@ oj_sparse2(ParseInfo pi) {
632
632
  while (1) {
633
633
  if (0 < pi->max_depth && pi->max_depth <= pi->stack.tail - pi->stack.head - 1) {
634
634
  VALUE err_clas = oj_get_json_err_class("NestingError");
635
-
635
+
636
636
  oj_set_error_at(pi, err_clas, __FILE__, __LINE__, "Too deeply nested.");
637
637
  pi->err_class = err_clas;
638
638
  return;
@@ -890,7 +890,7 @@ CLEANUP:
890
890
  if (Qnil != pi->err_class && 0 != pi->err_class) {
891
891
  pi->err.clas = pi->err_class;
892
892
  }
893
- if (CompatMode == pi->options.mode) {
893
+ if (CompatMode == pi->options.mode && Yes != pi->options.safe) {
894
894
  // The json gem requires the error message be UTF-8 encoded. In
895
895
  // additional the complete JSON source should be returned but that
896
896
  // is not possible without stored all the bytes read and reading
@@ -8,6 +8,8 @@
8
8
 
9
9
  extern VALUE Oj;
10
10
 
11
+ bool string_writer_optimized = false;
12
+
11
13
  static void
12
14
  key_check(StrWriter sw, const char *key) {
13
15
  DumpType type = sw->types[sw->depth];
@@ -152,7 +154,7 @@ oj_str_writer_push_array(StrWriter sw, const char *key) {
152
154
  void
153
155
  oj_str_writer_push_value(StrWriter sw, VALUE val, const char *key) {
154
156
  Out out = &sw->out;
155
-
157
+
156
158
  if (sw->keyWritten) {
157
159
  sw->keyWritten = 0;
158
160
  } else {
@@ -273,7 +275,7 @@ str_writer_free(void *ptr) {
273
275
  static VALUE
274
276
  str_writer_new(int argc, VALUE *argv, VALUE self) {
275
277
  StrWriter sw = ALLOC(struct _strWriter);
276
-
278
+
277
279
  oj_str_writer_init(sw, 0);
278
280
  if (1 == argc) {
279
281
  oj_parse_options(argv[0], &sw->opts);
@@ -487,8 +489,26 @@ str_writer_to_s(VALUE self) {
487
489
  return oj_encode(rstr);
488
490
  }
489
491
 
492
+ /* Document-method: as_json
493
+ * call-seq: as_json()
494
+ *
495
+ * Returns the contents of the writer as a JSON element. If called from inside
496
+ * an array or hash by Oj the raw buffer will be used othersize a more
497
+ * inefficient parse of the contents and a return of the result is
498
+ * completed. The parse uses the trict mode.
499
+ *
500
+ * *return* [_Hash_|_Array_|_String_|_Integer_|_Float_|_True_|_False_|_nil|)
501
+ */
502
+ static VALUE
503
+ str_writer_as_json(VALUE self) {
504
+ if (string_writer_optimized) {
505
+ return self;
506
+ }
507
+ return rb_hash_new();
508
+ }
509
+
490
510
  /* Document-class: Oj::StringWriter
491
- *
511
+ *
492
512
  * Supports building a JSON document one element at a time. Build the document
493
513
  * by pushing values into the document. Pushing an array or an object will
494
514
  * create that element in the JSON document and subsequent pushes will add the
@@ -509,4 +529,6 @@ oj_string_writer_init() {
509
529
  rb_define_method(oj_string_writer_class, "pop_all", str_writer_pop_all, 0);
510
530
  rb_define_method(oj_string_writer_class, "reset", str_writer_reset, 0);
511
531
  rb_define_method(oj_string_writer_class, "to_s", str_writer_to_s, 0);
532
+ rb_define_method(oj_string_writer_class, "raw_json", str_writer_to_s, 0);
533
+ rb_define_method(oj_string_writer_class, "as_json", str_writer_as_json, 0);
512
534
  }