oj 3.17.4 → 3.17.6
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +73 -0
- data/ext/oj/cache.c +17 -1
- data/ext/oj/cache.h +5 -0
- data/ext/oj/circarray.c +6 -2
- data/ext/oj/compat.c +2 -2
- data/ext/oj/custom.c +5 -3
- data/ext/oj/dump.c +27 -12
- data/ext/oj/dump.h +10 -0
- data/ext/oj/dump_compat.c +10 -4
- data/ext/oj/extconf.rb +1 -0
- data/ext/oj/fast.c +40 -5
- data/ext/oj/intern.c +6 -1
- data/ext/oj/object.c +15 -10
- data/ext/oj/odd.c +6 -2
- data/ext/oj/oj.c +100 -21
- data/ext/oj/oj.h +2 -1
- data/ext/oj/parse.c +8 -1
- data/ext/oj/parser.c +57 -25
- data/ext/oj/rails.c +176 -54
- data/ext/oj/reader.c +2 -2
- data/ext/oj/resolve.c +11 -2
- data/ext/oj/safe.c +62 -48
- data/ext/oj/safe.h +14 -2
- data/ext/oj/saj.c +6 -0
- data/ext/oj/sparse.c +7 -6
- data/ext/oj/string_writer.c +2 -0
- data/ext/oj/usual.c +5 -1
- data/ext/oj/util.c +27 -0
- data/ext/oj/util.h +2 -1
- data/ext/oj/val_stack.h +24 -5
- data/ext/oj/wab.c +14 -26
- data/lib/oj/version.rb +1 -1
- data/pages/Compatibility.md +1 -1
- data/pages/Custom.md +2 -3
- data/pages/InstallOptions.md +8 -6
- data/pages/Modes.md +1 -1
- data/pages/Options.md +5 -6
- data/pages/Parser.md +2 -2
- data/pages/Rails.md +6 -0
- data/pages/Security.md +21 -7
- metadata +2 -2
data/ext/oj/oj.c
CHANGED
|
@@ -299,7 +299,8 @@ static VALUE only_array_from_string(const char *str) {
|
|
|
299
299
|
* floats, 0 indicates use Ruby
|
|
300
300
|
* - *:float_format* [_String_] the C printf format string for printing floats.
|
|
301
301
|
* Default follows the float_precision and will be changed if float_precision is
|
|
302
|
-
* changed. The string can be no more than 6 bytes
|
|
302
|
+
* changed. The string can be no more than 6 bytes and can hold at most one
|
|
303
|
+
* directive, which must be one of aAeEfgG and take no argument of its own.
|
|
303
304
|
* - *:use_to_json* [_Boolean_|_nil_] call to_json() methods on dump, default is false
|
|
304
305
|
* - *:use_as_json* [_Boolean_|_nil_] call as_json() methods on dump, default is false
|
|
305
306
|
* - *:use_raw_json* [_Boolean_|_nil_] call raw_json() methods on dump, default is false
|
|
@@ -574,7 +575,8 @@ static VALUE get_def_opts(VALUE self) {
|
|
|
574
575
|
* when dumping the seconds portion of time.
|
|
575
576
|
* - *:float_format* [_String_] the C printf format string for printing floats.
|
|
576
577
|
* Default follows the float_precision and will be changed if float_precision
|
|
577
|
-
* is changed. The string can be no more than 6 bytes
|
|
578
|
+
* is changed. The string can be no more than 6 bytes and can hold at most one
|
|
579
|
+
* directive, which must be one of aAeEfgG and take no argument of its own.
|
|
578
580
|
* - *:float_precision* [_Fixnum_|_nil_] number of digits of precision when dumping floats, 0 indicates use Ruby.
|
|
579
581
|
* - *:use_to_json* [_Boolean_|_nil_] call to_json() methods on dump, default is false.
|
|
580
582
|
* - *:use_as_json* [_Boolean_|_nil_] call as_json() methods on dump, default is false.
|
|
@@ -705,6 +707,46 @@ bool set_yesno_options(VALUE key, VALUE value, Options copts) {
|
|
|
705
707
|
return false;
|
|
706
708
|
}
|
|
707
709
|
|
|
710
|
+
inline static bool in_set(const char *set, char c) {
|
|
711
|
+
return '\0' != c && NULL != strchr(set, c);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// The format is used with one double and nothing else, so a directive that
|
|
715
|
+
// asks for anything more takes it from whatever is left in the argument
|
|
716
|
+
// registers. %s reads it as a pointer and %n writes through it.
|
|
717
|
+
static void validate_float_format(const char *str, size_t len) {
|
|
718
|
+
const char *s = str;
|
|
719
|
+
const char *end = str + len;
|
|
720
|
+
int cnt = 0;
|
|
721
|
+
|
|
722
|
+
for (; s < end; s++) {
|
|
723
|
+
if ('%' != *s) {
|
|
724
|
+
continue;
|
|
725
|
+
}
|
|
726
|
+
s++;
|
|
727
|
+
if (s < end && '%' == *s) {
|
|
728
|
+
continue;
|
|
729
|
+
}
|
|
730
|
+
if (1 < ++cnt) {
|
|
731
|
+
rb_raise(rb_eArgError, ":float_format must not have more than one directive.");
|
|
732
|
+
}
|
|
733
|
+
for (; s < end && in_set("-+ #0", *s); s++) {
|
|
734
|
+
}
|
|
735
|
+
for (; s < end && '0' <= *s && *s <= '9'; s++) {
|
|
736
|
+
}
|
|
737
|
+
if (s < end && '.' == *s) {
|
|
738
|
+
for (s++; s < end && '0' <= *s && *s <= '9'; s++) {
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
if (s < end && 'l' == *s) {
|
|
742
|
+
s++;
|
|
743
|
+
}
|
|
744
|
+
if (end <= s || !in_set("aAeEfgG", *s)) {
|
|
745
|
+
rb_raise(rb_eArgError, ":float_format directive must be one of aAeEfgG and take no argument of its own.");
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
|
|
708
750
|
static const char *make_only_value(VALUE v) {
|
|
709
751
|
switch (rb_type(v)) {
|
|
710
752
|
case RUBY_T_NIL:
|
|
@@ -794,12 +836,14 @@ static const char *make_only_value(VALUE v) {
|
|
|
794
836
|
return NULL;
|
|
795
837
|
}
|
|
796
838
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
839
|
+
// Apply one key and value to copts. Returns true if the key named an option Oj
|
|
840
|
+
// knows and false if it did not. An unrecognized key is still ignored rather
|
|
841
|
+
// than an error; the return only lets a caller tell the two cases apart.
|
|
842
|
+
static bool parse_one_option(VALUE k, VALUE v, Options copts) {
|
|
843
|
+
size_t len;
|
|
800
844
|
|
|
801
845
|
if (set_yesno_options(k, v, copts)) {
|
|
802
|
-
return
|
|
846
|
+
return true;
|
|
803
847
|
}
|
|
804
848
|
if (oj_indent_sym == k) {
|
|
805
849
|
switch (rb_type(v)) {
|
|
@@ -925,7 +969,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
925
969
|
}
|
|
926
970
|
} else if (bigdecimal_load_sym == k) {
|
|
927
971
|
if (Qnil == v) {
|
|
928
|
-
return
|
|
972
|
+
return true;
|
|
929
973
|
}
|
|
930
974
|
|
|
931
975
|
if (bigdecimal_sym == v || Qtrue == v) {
|
|
@@ -941,7 +985,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
941
985
|
}
|
|
942
986
|
} else if (compat_bigdecimal_sym == k) {
|
|
943
987
|
if (Qnil == v) {
|
|
944
|
-
return
|
|
988
|
+
return true;
|
|
945
989
|
}
|
|
946
990
|
copts->compat_bigdec = (Qtrue == v);
|
|
947
991
|
} else if (oj_decimal_class_sym == k) {
|
|
@@ -953,9 +997,13 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
953
997
|
rb_raise(rb_eArgError, ":decimal_class must be BigDecimal or Float.");
|
|
954
998
|
}
|
|
955
999
|
} else if (create_id_sym == k) {
|
|
1000
|
+
// A per call copy of the options aliases the buffer the default
|
|
1001
|
+
// options own, so only the defaults may free it.
|
|
1002
|
+
bool owned = (&oj_default_options == copts && NULL != copts->create_id && oj_json_class != copts->create_id);
|
|
1003
|
+
|
|
956
1004
|
if (Qnil == v) {
|
|
957
|
-
if (
|
|
958
|
-
OJ_R_FREE((char *)
|
|
1005
|
+
if (owned) {
|
|
1006
|
+
OJ_R_FREE((char *)copts->create_id);
|
|
959
1007
|
}
|
|
960
1008
|
copts->create_id = NULL;
|
|
961
1009
|
copts->create_id_len = 0;
|
|
@@ -963,8 +1011,8 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
963
1011
|
const char *str = StringValuePtr(v);
|
|
964
1012
|
|
|
965
1013
|
len = RSTRING_LEN(v);
|
|
966
|
-
if (len != copts->create_id_len || 0 != strcmp(copts->create_id, str)) {
|
|
967
|
-
if (
|
|
1014
|
+
if (NULL == copts->create_id || len != copts->create_id_len || 0 != strcmp(copts->create_id, str)) {
|
|
1015
|
+
if (owned) {
|
|
968
1016
|
OJ_R_FREE((char *)copts->create_id);
|
|
969
1017
|
}
|
|
970
1018
|
copts->create_id = OJ_R_ALLOC_N(char, len + 1);
|
|
@@ -1032,7 +1080,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
1032
1080
|
}
|
|
1033
1081
|
} else if (nan_sym == k) {
|
|
1034
1082
|
if (Qnil == v) {
|
|
1035
|
-
return
|
|
1083
|
+
return true;
|
|
1036
1084
|
}
|
|
1037
1085
|
if (null_sym == v) {
|
|
1038
1086
|
copts->dump_opts.nan_dump = NullNan;
|
|
@@ -1049,7 +1097,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
1049
1097
|
}
|
|
1050
1098
|
} else if (omit_nil_sym == k) {
|
|
1051
1099
|
if (Qnil == v) {
|
|
1052
|
-
return
|
|
1100
|
+
return true;
|
|
1053
1101
|
}
|
|
1054
1102
|
if (Qtrue == v) {
|
|
1055
1103
|
copts->dump_opts.omit_nil = true;
|
|
@@ -1060,7 +1108,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
1060
1108
|
}
|
|
1061
1109
|
} else if (omit_null_byte_sym == k) {
|
|
1062
1110
|
if (Qnil == v) {
|
|
1063
|
-
return
|
|
1111
|
+
return true;
|
|
1064
1112
|
}
|
|
1065
1113
|
if (Qtrue == v) {
|
|
1066
1114
|
copts->dump_opts.omit_null_byte = true;
|
|
@@ -1121,7 +1169,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
1121
1169
|
}
|
|
1122
1170
|
} else if (integer_range_sym == k) {
|
|
1123
1171
|
if (Qnil == v) {
|
|
1124
|
-
return
|
|
1172
|
+
return true;
|
|
1125
1173
|
}
|
|
1126
1174
|
if (rb_obj_class(v) == rb_cRange) {
|
|
1127
1175
|
VALUE min = rb_funcall(v, oj_begin_id, 0);
|
|
@@ -1152,7 +1200,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
1152
1200
|
}
|
|
1153
1201
|
} else if (symbol_keys_sym == k || oj_symbolize_names_sym == k) {
|
|
1154
1202
|
if (Qnil == v) {
|
|
1155
|
-
return
|
|
1203
|
+
return true;
|
|
1156
1204
|
}
|
|
1157
1205
|
copts->sym_key = (Qtrue == v) ? Yes : No;
|
|
1158
1206
|
|
|
@@ -1172,6 +1220,7 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
1172
1220
|
if (6 < RSTRING_LEN(v)) {
|
|
1173
1221
|
rb_raise(rb_eArgError, ":float_format must be 6 bytes or less.");
|
|
1174
1222
|
}
|
|
1223
|
+
validate_float_format(RSTRING_PTR(v), (size_t)RSTRING_LEN(v));
|
|
1175
1224
|
strncpy(copts->float_fmt, RSTRING_PTR(v), (size_t)RSTRING_LEN(v));
|
|
1176
1225
|
copts->float_fmt[RSTRING_LEN(v)] = '\0';
|
|
1177
1226
|
} else if (only_sym == k) {
|
|
@@ -1186,21 +1235,51 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
|
1186
1235
|
OJ_R_FREE((void *)copts->dump_opts.except);
|
|
1187
1236
|
}
|
|
1188
1237
|
copts->dump_opts.except = make_only_value(v);
|
|
1238
|
+
} else {
|
|
1239
|
+
return false;
|
|
1240
|
+
}
|
|
1241
|
+
return true;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
// Collects the return of parse_one_option() over every key in a hash.
|
|
1245
|
+
struct _optsParse {
|
|
1246
|
+
Options copts;
|
|
1247
|
+
bool consumed;
|
|
1248
|
+
};
|
|
1249
|
+
|
|
1250
|
+
static int parse_options_cb(VALUE k, VALUE v, VALUE opts) {
|
|
1251
|
+
struct _optsParse *op = (struct _optsParse *)opts;
|
|
1252
|
+
|
|
1253
|
+
if (parse_one_option(k, v, op->copts)) {
|
|
1254
|
+
op->consumed = true;
|
|
1189
1255
|
}
|
|
1190
1256
|
return ST_CONTINUE;
|
|
1191
1257
|
}
|
|
1192
1258
|
|
|
1193
|
-
|
|
1259
|
+
// Apply the options in ropts to copts and report whether any key was
|
|
1260
|
+
// recognized. A hash of nothing but unknown keys leaves copts untouched and
|
|
1261
|
+
// returns false.
|
|
1262
|
+
bool oj_parse_options_consumed(VALUE ropts, Options copts) {
|
|
1263
|
+
struct _optsParse op = {copts, false};
|
|
1264
|
+
|
|
1194
1265
|
if (T_HASH != rb_type(ropts)) {
|
|
1195
|
-
return;
|
|
1266
|
+
return false;
|
|
1267
|
+
}
|
|
1268
|
+
rb_hash_foreach(ropts, parse_options_cb, (VALUE)&op);
|
|
1269
|
+
if (Qnil != rb_hash_lookup(ropts, match_string_sym)) {
|
|
1270
|
+
op.consumed = true;
|
|
1196
1271
|
}
|
|
1197
|
-
rb_hash_foreach(ropts, parse_options_cb, (VALUE)copts);
|
|
1198
1272
|
oj_parse_opt_match_string(&copts->str_rx, ropts);
|
|
1199
1273
|
|
|
1200
1274
|
copts->dump_opts.use = (0 < copts->dump_opts.indent_size || 0 < copts->dump_opts.after_size ||
|
|
1201
1275
|
0 < copts->dump_opts.before_size || 0 < copts->dump_opts.hash_size ||
|
|
1202
1276
|
0 < copts->dump_opts.array_size);
|
|
1203
|
-
|
|
1277
|
+
|
|
1278
|
+
return op.consumed;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
void oj_parse_options(VALUE ropts, Options copts) {
|
|
1282
|
+
oj_parse_options_consumed(ropts, copts);
|
|
1204
1283
|
}
|
|
1205
1284
|
|
|
1206
1285
|
// Free the option buffers that oj_parse_options() allocated for a single call.
|
data/ext/oj/oj.h
CHANGED
|
@@ -197,6 +197,7 @@ typedef struct _out {
|
|
|
197
197
|
bool allocated;
|
|
198
198
|
bool omit_nil;
|
|
199
199
|
bool omit_null_byte;
|
|
200
|
+
bool key_filter_off; // rails: suppress the :only/:except key filter for an as_json result
|
|
200
201
|
int argc;
|
|
201
202
|
VALUE *argv;
|
|
202
203
|
ROptTable ropts;
|
|
@@ -256,6 +257,7 @@ extern VALUE oj_custom_parse_cstr(int argc, VALUE *argv, char *json, size_t len)
|
|
|
256
257
|
|
|
257
258
|
extern bool oj_hash_has_key(VALUE hash, VALUE key);
|
|
258
259
|
extern void oj_parse_options(VALUE ropts, Options copts);
|
|
260
|
+
extern bool oj_parse_options_consumed(VALUE ropts, Options copts);
|
|
259
261
|
extern void oj_free_call_options(Options copts);
|
|
260
262
|
extern void oj_options_take_ownership(Options copts);
|
|
261
263
|
extern void oj_options_release(Options copts);
|
|
@@ -325,7 +327,6 @@ extern VALUE oj_max_nesting_sym;
|
|
|
325
327
|
extern VALUE oj_object_class_sym;
|
|
326
328
|
extern VALUE oj_object_nl_sym;
|
|
327
329
|
extern VALUE oj_quirks_mode_sym;
|
|
328
|
-
extern VALUE oj_skip_null_byte_sym;
|
|
329
330
|
extern VALUE oj_space_before_sym;
|
|
330
331
|
extern VALUE oj_space_sym;
|
|
331
332
|
extern VALUE oj_symbolize_names_sym;
|
data/ext/oj/parse.c
CHANGED
|
@@ -414,6 +414,11 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
|
414
414
|
|
|
415
415
|
if ('\\' == *s) {
|
|
416
416
|
s++;
|
|
417
|
+
if (pi->end <= s) {
|
|
418
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
|
|
419
|
+
buf_cleanup(&buf);
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
417
422
|
switch (*s) {
|
|
418
423
|
case 'n': buf_append(&buf, '\n'); break;
|
|
419
424
|
case 'r': buf_append(&buf, '\r'); break;
|
|
@@ -1096,7 +1101,9 @@ void oj_set_error_at(ParseInfo pi, VALUE err_clas, const char *file, int line, c
|
|
|
1096
1101
|
}
|
|
1097
1102
|
va_end(ap);
|
|
1098
1103
|
pi->err.clas = err_clas;
|
|
1099
|
-
|
|
1104
|
+
// The eight bytes below, plus the ')' and the terminator that the two bytes
|
|
1105
|
+
// held back from end are for.
|
|
1106
|
+
if (p + 8 <= end) {
|
|
1100
1107
|
*p++ = ' ';
|
|
1101
1108
|
*p++ = '(';
|
|
1102
1109
|
*p++ = 'a';
|
data/ext/oj/parser.c
CHANGED
|
@@ -892,10 +892,10 @@ static void parse(ojParser p, const byte *json, size_t len, bool more) {
|
|
|
892
892
|
case EXP_DIGIT:
|
|
893
893
|
p->map = exp_map;
|
|
894
894
|
for (; NUM_DIGIT == digit_map[*b]; b++) {
|
|
895
|
-
|
|
895
|
+
int x = p->num.exp * 10 + (*b - '0');
|
|
896
896
|
|
|
897
897
|
if (x <= MAX_EXP) {
|
|
898
|
-
p->num.exp = x;
|
|
898
|
+
p->num.exp = (int16_t)x;
|
|
899
899
|
} else {
|
|
900
900
|
big_change(p);
|
|
901
901
|
p->map = big_exp_map;
|
|
@@ -1282,7 +1282,8 @@ static int opt_cb(VALUE rkey, VALUE value, VALUE ptr) {
|
|
|
1282
1282
|
* Oj::Parser.new(:usual, cache_keys: true).
|
|
1283
1283
|
*/
|
|
1284
1284
|
static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
|
1285
|
-
ojParser
|
|
1285
|
+
ojParser p = OJ_R_ALLOC(struct _ojParser);
|
|
1286
|
+
volatile VALUE pv;
|
|
1286
1287
|
|
|
1287
1288
|
#if HAVE_RB_EXT_RACTOR_SAFE
|
|
1288
1289
|
// This doesn't seem to do anything.
|
|
@@ -1292,6 +1293,10 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
|
|
1292
1293
|
buf_init(&p->key);
|
|
1293
1294
|
buf_init(&p->buf);
|
|
1294
1295
|
p->map = value_map;
|
|
1296
|
+
// Until the parser is wrapped the GC can not free it, so the mode and the
|
|
1297
|
+
// options, both of which raise on a value they do not take, are handled
|
|
1298
|
+
// after the wrap.
|
|
1299
|
+
pv = TypedData_Wrap_Struct(parser_class, &oj_parser_type, p);
|
|
1295
1300
|
|
|
1296
1301
|
if (argc < 1) {
|
|
1297
1302
|
oj_set_parser_validator(p);
|
|
@@ -1332,7 +1337,7 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
|
|
1332
1337
|
rb_hash_foreach(ropts, opt_cb, (VALUE)p);
|
|
1333
1338
|
}
|
|
1334
1339
|
}
|
|
1335
|
-
return
|
|
1340
|
+
return pv;
|
|
1336
1341
|
}
|
|
1337
1342
|
|
|
1338
1343
|
// Create a new parser without setting the delegate. The parser is
|
|
@@ -1524,6 +1529,39 @@ static VALUE parser_load(VALUE self, VALUE reader) {
|
|
|
1524
1529
|
return p->result(p);
|
|
1525
1530
|
}
|
|
1526
1531
|
|
|
1532
|
+
struct _fileParse {
|
|
1533
|
+
ojParser p;
|
|
1534
|
+
const char *path;
|
|
1535
|
+
int fd;
|
|
1536
|
+
};
|
|
1537
|
+
|
|
1538
|
+
static VALUE file_parse(VALUE x) {
|
|
1539
|
+
struct _fileParse *fp = (struct _fileParse *)x;
|
|
1540
|
+
byte buf[16385];
|
|
1541
|
+
size_t size = sizeof(buf) - 1;
|
|
1542
|
+
ssize_t rsize;
|
|
1543
|
+
|
|
1544
|
+
while (true) {
|
|
1545
|
+
if (0 > (rsize = read(fp->fd, buf, size))) {
|
|
1546
|
+
rb_raise(rb_eIOError, "error reading from %s", fp->path);
|
|
1547
|
+
}
|
|
1548
|
+
if (0 == rsize) {
|
|
1549
|
+
break;
|
|
1550
|
+
}
|
|
1551
|
+
buf[rsize] = '\0';
|
|
1552
|
+
parse(fp->p, buf, rsize, true);
|
|
1553
|
+
}
|
|
1554
|
+
validate_document_end(fp->p);
|
|
1555
|
+
|
|
1556
|
+
return fp->p->result(fp->p);
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
static VALUE file_close(VALUE x) {
|
|
1560
|
+
close(((struct _fileParse *)x)->fd);
|
|
1561
|
+
|
|
1562
|
+
return Qnil;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1527
1565
|
/* Document-method: file(filename)
|
|
1528
1566
|
* call-seq: file(filename)
|
|
1529
1567
|
*
|
|
@@ -1532,9 +1570,10 @@ static VALUE parser_load(VALUE self, VALUE reader) {
|
|
|
1532
1570
|
* Returns the result according to the delegate of the parser.
|
|
1533
1571
|
*/
|
|
1534
1572
|
static VALUE parser_file(VALUE self, VALUE filename) {
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1573
|
+
struct _fileParse fp;
|
|
1574
|
+
ojParser p;
|
|
1575
|
+
const char *path;
|
|
1576
|
+
int fd;
|
|
1538
1577
|
|
|
1539
1578
|
TypedData_Get_Struct(self, struct _ojParser, &oj_parser_type, p);
|
|
1540
1579
|
|
|
@@ -1553,26 +1592,15 @@ static VALUE parser_file(VALUE self, VALUE filename) {
|
|
|
1553
1592
|
// Use threaded version.
|
|
1554
1593
|
// TBD only if has pthreads
|
|
1555
1594
|
// TBD parse_large(p, fd);
|
|
1595
|
+
close(fd);
|
|
1556
1596
|
return p->result(p);
|
|
1557
1597
|
}
|
|
1558
1598
|
#endif
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1599
|
+
fp.p = p;
|
|
1600
|
+
fp.path = path;
|
|
1601
|
+
fp.fd = fd;
|
|
1562
1602
|
|
|
1563
|
-
|
|
1564
|
-
if (0 < (rsize = read(fd, buf, size))) {
|
|
1565
|
-
buf[rsize] = '\0';
|
|
1566
|
-
parse(p, buf, rsize, true);
|
|
1567
|
-
}
|
|
1568
|
-
if (rsize <= 0) {
|
|
1569
|
-
if (0 != rsize) {
|
|
1570
|
-
rb_raise(rb_eIOError, "error reading from %s", path);
|
|
1571
|
-
}
|
|
1572
|
-
break;
|
|
1573
|
-
}
|
|
1574
|
-
}
|
|
1575
|
-
return p->result(p);
|
|
1603
|
+
return rb_ensure(file_parse, (VALUE)&fp, file_close, (VALUE)&fp);
|
|
1576
1604
|
}
|
|
1577
1605
|
|
|
1578
1606
|
/* Document-method: just_one
|
|
@@ -1685,15 +1713,19 @@ static VALUE parser_safe(int argc, VALUE *argv, VALUE self) {
|
|
|
1685
1713
|
options = rb_hash_new();
|
|
1686
1714
|
}
|
|
1687
1715
|
|
|
1688
|
-
ojParser
|
|
1716
|
+
ojParser p = OJ_R_ALLOC(struct _ojParser);
|
|
1717
|
+
volatile VALUE pv;
|
|
1689
1718
|
|
|
1690
1719
|
memset(p, 0, sizeof(struct _ojParser));
|
|
1691
1720
|
buf_init(&p->key);
|
|
1692
1721
|
buf_init(&p->buf);
|
|
1693
1722
|
p->map = value_map;
|
|
1723
|
+
// The limits raise on a value that is not an Integer, so the parser has to
|
|
1724
|
+
// be wrapped before they are read.
|
|
1725
|
+
pv = TypedData_Wrap_Struct(parser_class, &oj_parser_type, p);
|
|
1694
1726
|
oj_set_parser_safe(p, options);
|
|
1695
1727
|
|
|
1696
|
-
return
|
|
1728
|
+
return pv;
|
|
1697
1729
|
}
|
|
1698
1730
|
|
|
1699
1731
|
/* Document-class: Oj::Parser
|