From 61c0f023a9c0033ff8f1263d7bdd2aa9c8521091 Mon Sep 17 00:00:00 2001 From: Jose M Perez Date: Tue, 7 Apr 2020 14:49:37 +0200 Subject: [PATCH] Add validate/1,2 call --- c_src/decoder.c | 21 +++++++++++---------- src/jiffy.erl | 18 +++++++++++++++++- test/jiffy_01_yajl_tests.erl | 4 ++-- test/jiffy_15_return_trailer_tests.erl | 8 ++++++-- test/jiffy_18_partials_tests.erl | 2 +- 5 files changed, 37 insertions(+), 16 deletions(-) diff --git a/c_src/decoder.c b/c_src/decoder.c index a96fbff..deb1648 100644 --- a/c_src/decoder.c +++ b/c_src/decoder.c @@ -65,8 +65,8 @@ typedef struct { int st_size; int st_top; - unsigned int current_depth; - unsigned int max_levels; + int current_depth; + int max_levels; unsigned int level_start; unsigned int empty_element; } Decoder; @@ -105,7 +105,7 @@ dec_new(ErlNifEnv* env) } d->current_depth = 0; - d->max_levels = 0; + d->max_levels = -1; d->level_start = 0; d->empty_element = 1; @@ -199,14 +199,14 @@ dec_pop_assert(Decoder* d, char val) static void inline level_increase(Decoder* d) { - if(d->max_levels && (d->max_levels == d->current_depth++)) { + if(d->max_levels >= 0 && (d->max_levels == d->current_depth++)) { d->level_start = d->i; } } static int inline level_decrease(Decoder* d, ERL_NIF_TERM* value) { - if (d->max_levels && d->max_levels == --d->current_depth) { + if (d->max_levels >= 0 && d->max_levels == --d->current_depth) { // Only builds term in threshold unsigned ulen = d->i - d->level_start + 1; if(!d->copy_strings) { @@ -222,7 +222,7 @@ level_decrease(Decoder* d, ERL_NIF_TERM* value) { static int inline level_allows_terms(Decoder* d) { - return (!d->max_levels) || (d->max_levels >= d->current_depth); + return (d->max_levels < 0) || (d->max_levels >= d->current_depth); } int @@ -689,12 +689,12 @@ make_array(ErlNifEnv* env, ERL_NIF_TERM list) } int -get_max_levels(ErlNifEnv* env, ERL_NIF_TERM val, unsigned int* max_levels_p) +get_max_levels(ErlNifEnv* env, ERL_NIF_TERM val, int* max_levels_p) { jiffy_st* st = (jiffy_st*) enif_priv_data(env); const ERL_NIF_TERM* tuple; int arity; - unsigned int max_levels; + int max_levels; if(!enif_get_tuple(env, val, &arity, &tuple)) { return 0; @@ -708,11 +708,11 @@ get_max_levels(ErlNifEnv* env, ERL_NIF_TERM val, unsigned int* max_levels_p) return 0; } - if(!enif_get_uint(env, tuple[1], &max_levels)) { + if(!enif_get_int(env, tuple[1], &max_levels)) { return 0; } - if(max_levels == 0) { + if(max_levels < 0) { return 0; } @@ -1168,6 +1168,7 @@ decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) } decode_done: + level_decrease(d, &val); if(d->i < bin.size && d->return_trailer) { trailer = enif_make_sub_binary(env, argv[0], d->i, bin.size - d->i); diff --git a/src/jiffy.erl b/src/jiffy.erl index 68a6fa9..b701410 100644 --- a/src/jiffy.erl +++ b/src/jiffy.erl @@ -2,7 +2,7 @@ % See the LICENSE file for more information. -module(jiffy). --export([decode/1, decode/2, encode/1, encode/2]). +-export([decode/1, decode/2, encode/1, encode/2, validate/1, validate/2]). -define(NOT_LOADED, not_loaded(?LINE)). -compile([no_native]). @@ -115,6 +115,22 @@ encode(Data, Options) -> end. +-spec validate(iolist() | binary()) -> boolean() | {has_trailer, true, binary()}. +validate(Data) -> + validate(Data, []). + + +-spec validate(iolist() | binary(), decode_options()) -> boolean() | {has_trailer, true, binary()}. +validate(Data, Opts) when is_binary(Data), is_list(Opts) -> + try decode(Data, lists:keystore(max_levels, 1, Opts, {max_levels, 0})) of + {has_trailer, _FlatEJson, Trailer} -> {has_trailer, true, Trailer}; + _FlatEJson -> true + catch _:_ -> false + end; +validate(Data, Opts) when is_list(Data) -> + validate(iolist_to_binary(Data), Opts). + + finish_decode({bignum, Value}) -> list_to_integer(binary_to_list(Value)); finish_decode({bignum_e, Value}) -> diff --git a/test/jiffy_01_yajl_tests.erl b/test/jiffy_01_yajl_tests.erl index 9e99ace..4aa5069 100644 --- a/test/jiffy_01_yajl_tests.erl +++ b/test/jiffy_01_yajl_tests.erl @@ -14,9 +14,9 @@ yajl_test_() -> gen({Name, Json, {error, Erl}}) -> - {Name, ?_assertError(Erl, jiffy:decode(Json))}; + {Name, [?_assertEqual(false, jiffy:validate(Json)), ?_assertError(Erl, jiffy:decode(Json))]}; gen({Name, Json, Erl}) -> - {Name, ?_assertEqual(Erl, jiffy:decode(Json))}. + {Name, [?_assertEqual(true, jiffy:validate(Json)), ?_assertEqual(Erl, jiffy:decode(Json))]}. read_cases() -> diff --git a/test/jiffy_15_return_trailer_tests.erl b/test/jiffy_15_return_trailer_tests.erl index af80a46..c8e3ec1 100644 --- a/test/jiffy_15_return_trailer_tests.erl +++ b/test/jiffy_15_return_trailer_tests.erl @@ -15,5 +15,9 @@ trailer_test_() -> {<<"1 2 3">>, {has_trailer, 1, <<"2 3">>}} ], {"Test return_trailer", lists:map(fun({Data, Result}) -> - ?_assertEqual(Result, jiffy:decode(Data, Opts)) - end, Cases)}. \ No newline at end of file + ValidateResult = if is_tuple(Result) -> setelement(2, Result, true); + true -> Result + end, + [?_assertEqual(ValidateResult, jiffy:validate(Data, Opts)), + ?_assertEqual(Result, jiffy:decode(Data, Opts))] + end, Cases)}. diff --git a/test/jiffy_18_partials_tests.erl b/test/jiffy_18_partials_tests.erl index 29fba69..b32d489 100644 --- a/test/jiffy_18_partials_tests.erl +++ b/test/jiffy_18_partials_tests.erl @@ -12,7 +12,7 @@ decode_levels_test_() -> EJson = jiffy:decode(Json, [{max_levels, MaxLevels} | Opts]), FullEJson = to_full_json(EJson, MaxLevels, Opts), ?_assertEqual(jiffy:decode(Json, Opts), FullEJson) - end || MaxLevels <- lists:seq(1, MaxOptMaxLevels), Opts <- generate_options_groups()] + end || MaxLevels <- lists:seq(0, MaxOptMaxLevels), Opts <- generate_options_groups()] end, jsons())}. encode_resources_test_() ->