oj 3.7.12 → 3.9.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -21,7 +21,7 @@ extern "C" {
21
21
  #include <stdint.h>
22
22
  #include <stdbool.h>
23
23
 
24
- #if HAVE_LIBPTHREAD
24
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
25
25
  #include <pthread.h>
26
26
  #endif
27
27
  #include "cache8.h"
@@ -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,8 +368,9 @@ 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
- #if HAVE_LIBPTHREAD
373
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
370
374
  extern pthread_mutex_t oj_cache_mutex;
371
375
  #else
372
376
  extern VALUE 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.
@@ -1048,6 +1049,10 @@ CLEANUP:
1048
1049
  msg = rb_str_append(msg, oj_encode(rb_str_new2(pi->json)));
1049
1050
  }
1050
1051
  args[0] = msg;
1052
+ if (pi->err.clas == oj_parse_error_class) {
1053
+ // The error was an Oj::ParseError so change to a JSON::ParseError.
1054
+ pi->err.clas = oj_json_parser_error_class;
1055
+ }
1051
1056
  rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
1052
1057
  } else {
1053
1058
  oj_err_raise(&pi->err);
@@ -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
  }
@@ -1067,6 +1071,8 @@ rails_set_encoder(VALUE self) {
1067
1071
  rb_undef_method(encoding, "use_standard_json_time_format=");
1068
1072
  rb_define_module_function(encoding, "use_standard_json_time_format=", rails_use_standard_json_time_format, 1);
1069
1073
 
1074
+ pv = rb_iv_get(encoding, "@escape_html_entities_in_json");
1075
+ escape_html = Qtrue == pv;
1070
1076
  rb_undef_method(encoding, "escape_html_entities_in_json=");
1071
1077
  rb_define_module_function(encoding, "escape_html_entities_in_json=", rails_escape_html_entities_in_json, 1);
1072
1078
 
@@ -1401,6 +1407,8 @@ dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
1401
1407
 
1402
1408
  if (NULL != (ro = oj_rails_get_opt(out->ropts, rb_obj_class(obj))) && ro->on) {
1403
1409
  ro->dump(obj, depth, out, as_ok);
1410
+ } else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
1411
+ oj_dump_raw_json(obj, depth, out);
1404
1412
  } else if (rb_respond_to(obj, oj_as_json_id)) {
1405
1413
  dump_as_json(obj, depth, out, true);
1406
1414
  } else if (rb_respond_to(obj, oj_to_hash_id)) {
@@ -1408,6 +1416,8 @@ dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
1408
1416
  } else {
1409
1417
  oj_dump_obj_to_s(obj, out);
1410
1418
  }
1419
+ } else if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
1420
+ oj_dump_raw_json(obj, depth, out);
1411
1421
  } else if (rb_respond_to(obj, oj_to_hash_id)) {
1412
1422
  // Always attempt to_hash.
1413
1423
  dump_to_hash(obj, depth, out);
@@ -6,7 +6,7 @@
6
6
  #include <stdlib.h>
7
7
  #include <stdio.h>
8
8
  #include <string.h>
9
- #if HAVE_LIBPTHREAD
9
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
10
10
  #include <pthread.h>
11
11
  #endif
12
12
 
@@ -75,7 +75,7 @@ oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE
75
75
  if (No == pi->options.class_cache) {
76
76
  return resolve_classpath(pi, name, len, auto_define, error_class);
77
77
  }
78
- #if HAVE_LIBPTHREAD
78
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
79
79
  pthread_mutex_lock(&oj_cache_mutex);
80
80
  #else
81
81
  rb_mutex_lock(oj_cache_mutex);
@@ -85,7 +85,7 @@ oj_name2class(ParseInfo pi, const char *name, size_t len, int auto_define, VALUE
85
85
  *slot = clas;
86
86
  }
87
87
  }
88
- #if HAVE_LIBPTHREAD
88
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
89
89
  pthread_mutex_unlock(&oj_cache_mutex);
90
90
  #else
91
91
  rb_mutex_unlock(oj_cache_mutex);
@@ -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
@@ -898,6 +898,10 @@ CLEANUP:
898
898
  // idea.
899
899
  VALUE args[] = { oj_encode(rb_str_new2(pi->err.msg)) };
900
900
 
901
+ if (pi->err.clas == oj_parse_error_class) {
902
+ // The error was an Oj::ParseError so change to a JSON::ParseError.
903
+ pi->err.clas = oj_json_parser_error_class;
904
+ }
901
905
  rb_exc_raise(rb_class_new_instance(1, args, pi->err.clas));
902
906
  } else {
903
907
  oj_err_raise(&pi->err);
@@ -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
  }
@@ -110,7 +110,7 @@ sec_as_time(int64_t secs, TimeInfo ti) {
110
110
  }
111
111
  }
112
112
  }
113
- ti->year = (qc - shift) * 400 + c * 100 + qy * 4 + y;
113
+ ti->year = (int)((qc - (int64_t)shift) * 400 + c * 100 + qy * 4 + y);
114
114
  if (leap) {
115
115
  ms = eom_leap_secs;
116
116
  } else {
@@ -125,12 +125,12 @@ sec_as_time(int64_t secs, TimeInfo ti) {
125
125
  break;
126
126
  }
127
127
  }
128
- ti->day = secs / 86400LL;
128
+ ti->day = (int)(secs / 86400LL);
129
129
  secs = secs - (int64_t)ti->day * 86400LL;
130
130
  ti->day++;
131
- ti->hour = secs / 3600LL;
131
+ ti->hour = (int)(secs / 3600LL);
132
132
  secs = secs - (int64_t)ti->hour * 3600LL;
133
- ti->min = secs / 60LL;
133
+ ti->min = (int)(secs / 60LL);
134
134
  secs = secs - (int64_t)ti->min * 60LL;
135
- ti->sec = secs;
135
+ ti->sec = (int)secs;
136
136
  }
@@ -1,21 +1,21 @@
1
1
  /* val_stack.c
2
2
  * Copyright (c) 2011, Peter Ohler
3
3
  * All rights reserved.
4
- *
4
+ *
5
5
  * Redistribution and use in source and binary forms, with or without
6
6
  * modification, are permitted provided that the following conditions are met:
7
- *
7
+ *
8
8
  * - Redistributions of source code must retain the above copyright notice, this
9
9
  * list of conditions and the following disclaimer.
10
- *
10
+ *
11
11
  * - Redistributions in binary form must reproduce the above copyright notice,
12
12
  * this list of conditions and the following disclaimer in the documentation
13
13
  * and/or other materials provided with the distribution.
14
- *
14
+ *
15
15
  * - Neither the name of Peter Ohler nor the names of its contributors may be
16
16
  * used to endorse or promote products derived from this software without
17
17
  * specific prior written permission.
18
- *
18
+ *
19
19
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
20
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
21
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -42,7 +42,7 @@ mark(void *ptr) {
42
42
  if (0 == ptr) {
43
43
  return;
44
44
  }
45
- #if HAVE_LIBPTHREAD
45
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
46
46
  pthread_mutex_lock(&stack->mutex);
47
47
  #else
48
48
  rb_mutex_lock(stack->mutex);
@@ -66,7 +66,7 @@ mark(void *ptr) {
66
66
  }
67
67
  }
68
68
  }
69
- #if HAVE_LIBPTHREAD
69
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
70
70
  pthread_mutex_unlock(&stack->mutex);
71
71
  #else
72
72
  rb_mutex_unlock(stack->mutex);
@@ -75,9 +75,9 @@ mark(void *ptr) {
75
75
 
76
76
  VALUE
77
77
  oj_stack_init(ValStack stack) {
78
- #if HAVE_LIBPTHREAD
78
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
79
79
  int err;
80
-
80
+
81
81
  if (0 != (err = pthread_mutex_init(&stack->mutex, 0))) {
82
82
  rb_raise(rb_eException, "failed to initialize a mutex. %s", strerror(err));
83
83
  }
@@ -1,21 +1,21 @@
1
1
  /* val_stack.h
2
2
  * Copyright (c) 2011, Peter Ohler
3
3
  * All rights reserved.
4
- *
4
+ *
5
5
  * Redistribution and use in source and binary forms, with or without
6
6
  * modification, are permitted provided that the following conditions are met:
7
- *
7
+ *
8
8
  * - Redistributions of source code must retain the above copyright notice, this
9
9
  * list of conditions and the following disclaimer.
10
- *
10
+ *
11
11
  * - Redistributions in binary form must reproduce the above copyright notice,
12
12
  * this list of conditions and the following disclaimer in the documentation
13
13
  * and/or other materials provided with the distribution.
14
- *
14
+ *
15
15
  * - Neither the name of Peter Ohler nor the names of its contributors may be
16
16
  * used to endorse or promote products derived from this software without
17
17
  * specific prior written permission.
18
- *
18
+ *
19
19
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
20
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
21
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@@ -34,7 +34,7 @@
34
34
  #include "ruby.h"
35
35
  #include "odd.h"
36
36
  #include <stdint.h>
37
- #if HAVE_LIBPTHREAD
37
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
38
38
  #include <pthread.h>
39
39
  #endif
40
40
 
@@ -72,7 +72,7 @@ typedef struct _valStack {
72
72
  Val head; // current stack
73
73
  Val end; // stack end
74
74
  Val tail; // pointer to one past last element name on stack
75
- #if HAVE_LIBPTHREAD
75
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
76
76
  pthread_mutex_t mutex;
77
77
  #else
78
78
  VALUE mutex;
@@ -110,7 +110,7 @@ stack_push(ValStack stack, VALUE val, ValNext next) {
110
110
  } else {
111
111
  REALLOC_N(head, struct _val, len + STACK_INC);
112
112
  }
113
- #if HAVE_LIBPTHREAD
113
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
114
114
  pthread_mutex_lock(&stack->mutex);
115
115
  #else
116
116
  rb_mutex_lock(stack->mutex);
@@ -118,7 +118,7 @@ stack_push(ValStack stack, VALUE val, ValNext next) {
118
118
  stack->head = head;
119
119
  stack->tail = stack->head + toff;
120
120
  stack->end = stack->head + len + STACK_INC;
121
- #if HAVE_LIBPTHREAD
121
+ #ifdef HAVE_PTHREAD_MUTEX_INIT
122
122
  pthread_mutex_unlock(&stack->mutex);
123
123
  #else
124
124
  rb_mutex_unlock(stack->mutex);
@@ -95,7 +95,7 @@ module JSON
95
95
  State = ::JSON::Ext::Generator::State unless defined?(::JSON::State)
96
96
 
97
97
  begin
98
- Object.send(:remove_const, :Parser)
98
+ send(:remove_const, :Parser)
99
99
  rescue
100
100
  end
101
101
  Parser = ::JSON::Ext::Parser unless defined?(::JSON::Parser)
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '3.7.12'
4
+ VERSION = '3.9.2'
5
5
  end
@@ -14,7 +14,7 @@ modes are:
14
14
  - `:object`
15
15
  - `:custom`
16
16
 
17
- Since modes detemine what the JSON output will look like and alternatively
17
+ Since modes determine what the JSON output will look like and alternatively
18
18
  what Oj expects when the `Oj.load()` method is called, mixing the output and
19
19
  input mode formats will most likely not behave as intended. If the object mode
20
20
  is used for producing JSON then use object mode for reading. The same is true
@@ -117,6 +117,7 @@ information.
117
117
  | :object_nl | String | | | x | x | | x | |
118
118
  | :omit_nil | Boolean | x | x | x | x | x | x | |
119
119
  | :quirks_mode | Boolean | | | 6 | | | x | |
120
+ | :safe | String | | | x | | | | |
120
121
  | :second_precision | Fixnum | | | | | x | x | |
121
122
  | :space | String | | | x | x | | x | |
122
123
  | :space_before | String | | | x | x | | x | |
@@ -124,6 +125,7 @@ information.
124
125
  | :trace | Boolean | x | x | x | x | x | x | x |
125
126
  | :time_format | Symbol | | | | | x | x | |
126
127
  | :use_as_json | Boolean | | | | | | x | |
128
+ | :use_raw_json | Boolean | | | x | x | x | x | |
127
129
  | :use_to_hash | Boolean | | | | | | x | |
128
130
  | :use_to_json | Boolean | | | | | | x | |
129
131
  --------------------------------------------------------------------------------------------------------
@@ -151,4 +153,3 @@ information.
151
153
  6. The quirks mode option is no longer supported in the most recent json
152
154
  gem. It is supported by Oj for backward compatibility with older json gem
153
155
  versions.
154
-
@@ -89,6 +89,10 @@ with the key.
89
89
  The :create_id option specifies that key is used for dumping and loading when
90
90
  specifying the class for an encoded object. The default is `json_create`.
91
91
 
92
+ In the `:custom` mode setting the `:create_id` to nil will cause Complex,
93
+ Rational, Range, and Regexp to be output as strings instead of as JSON
94
+ objects.
95
+
92
96
  ### :empty_string [Boolean]
93
97
 
94
98
  If true an empty or all whitespace input will not raise an Exception. The
@@ -149,7 +153,7 @@ integer gives better performance.
149
153
 
150
154
  ### :integer_range [Range]
151
155
 
152
- Dump integers outside range as strings.
156
+ Dump integers outside range as strings.
153
157
  Note: range bounds must be Fixnum.
154
158
 
155
159
  ### :match_string
@@ -211,6 +215,12 @@ Allow single JSON values instead of documents, default is true (allow). This
211
215
  can also be used in :compat mode to be backward compatible with older versions
212
216
  of the json gem.
213
217
 
218
+ ### :safe
219
+
220
+ The JSON gem includes the complete JSON in parse errors with no limit
221
+ on size. To break from the JSON gem behavior for this case set `:safe`
222
+ to true.
223
+
214
224
  ### :second_precision [Fixnum]
215
225
 
216
226
  The number of digits after the decimal when dumping the seconds of time.
@@ -254,6 +264,18 @@ The :time_format when dumping.
254
264
  Call `as_json()` methods on dump, default is false. The option is ignored in
255
265
  the :compat and :rails mode.
256
266
 
267
+
268
+ ### :use_raw_json [Boolean]
269
+
270
+ Call `raw_json()` methods on dump, default is false. The option is
271
+ accepted in the :compat and :rails mode even though it is not
272
+ supported by other JSON gems. It provides a means to optimize dump or
273
+ generate performance. The `raw_json(depth, indent)` method should be
274
+ called only by Oj. It is not intended for any other use. This is mean
275
+ to replace the abused `to_json` methods. Calling `Oj.dump` inside the
276
+ `raw_json` with the object itself when `:use_raw_json` is true will
277
+ result in an infinite loop.
278
+
257
279
  ### :use_to_hash [Boolean]
258
280
 
259
281
  Call `to_hash()` methods on dump, default is false. The option is ignored in
@@ -263,4 +285,3 @@ the :compat and :rails mode.
263
285
 
264
286
  Call `to_json()` methods on dump, default is false. The option is ignored in
265
287
  the :compat and :rails mode.
266
-