Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ASN.1 JER: Support decoding already decoded JSON data #9611

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions lib/asn1/doc/guides/asn1_getting_started.md
Original file line number Diff line number Diff line change
@@ -233,6 +233,32 @@ module and the NIF library in `asn1/priv_dir` are needed at runtime.
By calling function `info/0` in a generated module, you get information about
which compiler options were used.

### Special Decode Functionality for JSON Encoding Rules (JER)

When using the JSON encoding rules, it is possible to call the
`decode/2` function in the following way with data that has already
been decoded by `json:decode/1`:

```erlang
SomeModule:decode(Type, {json_decoded, Decoded}).
```

Example:

```erlang
1> asn1ct:compile("People", [jer]).
ok
2> Rockstar = {'Person',"Vince Eclipse",roving,50}.
{'Person',"Vince Eclipse",roving,50}
3> {ok,Bin} = 'People':encode('Person', Rockstar).
{ok,<<"{\"name\":\"Vince Eclipse\",\"location\":2,\"age\":50}">>}
4> 'People':decode('Person', Bin).
{ok,{'Person',"Vince Eclipse",roving,50}}
5> 'People':decode('Person', {json_decoded,json:decode(Bin)}).
{ok,{'Person',"Vince Eclipse",roving,50}}

```

### Errors

Errors detected at compile-time are displayed on the screen together with line
123 changes: 59 additions & 64 deletions lib/asn1/src/asn1ct_gen.erl
Original file line number Diff line number Diff line change
@@ -803,6 +803,7 @@ pgen_dispatcher(Gen, Types) ->
false ->
ok
end,

%% DECODER
ReturnRest = proplists:get_bool(undec_rest, Gen#gen.options),
Data = case Gen#gen.erule =:= ber andalso ReturnRest of
@@ -811,92 +812,86 @@ pgen_dispatcher(Gen, Types) ->
end,

emit(["decode(Type, ",Data,") ->",nl]),
pgen_dispatcher_decode(Gen, ReturnRest, NoOkWrapper),

case Gen#gen.jer of
true ->
emit(["jer_decode(Type, ",Data,") ->",nl]),
pgen_dispatcher_decode(Gen#gen{erule=jer},
ReturnRest, NoOkWrapper);
false ->
ok
end,

%% REST of MODULE
gen_decode_partial_incomplete(Gen, NoOkWrapper),
gen_partial_inc_dispatcher(Gen),

case Gen of
#gen{erule=jer} ->
ok;
_ ->
gen_dispatcher(Types, "encode_disp", "enc_"),
gen_dispatcher(Types, "decode_disp", "dec_")
end.

pgen_dispatcher_decode(Gen, ReturnRest, NoOkWrapper) ->
CurrMod = lists:concat(["'",get(currmod),"'"]),

case NoOkWrapper of
false -> emit(["try",nl]);
true -> ok
end,

DecWrap =
case {Gen,ReturnRest} of
{#gen{erule=ber},false} ->
asn1ct_func:need({ber,ber_decode_nif,1}),
"element(1, ber_decode_nif(Data))";
{#gen{erule=ber},true} ->
asn1ct_func:need({ber,ber_decode_nif,1}),
emit([" {Data,Rest} = ber_decode_nif(Data0),",nl]),
"Data";
{#gen{erule=jer},false} ->
"json:decode(Data)";
{#gen{erule=jer},true} ->
exit("JER + return rest not supported");
{_,_} ->
"Data"
end,
case {Gen,ReturnRest} of
{#gen{erule=ber},false} ->
asn1ct_func:need({ber,ber_decode_nif,1}),
"element(1, ber_decode_nif(Data))";
{#gen{erule=ber},true} ->
asn1ct_func:need({ber,ber_decode_nif,1}),
emit([" {Data,Rest} = ber_decode_nif(Data0),",nl]),
"Data";
{#gen{erule=jer},false} ->
~S"""
case Data of
{json_decoded,Decoded} -> Decoded;
_ -> json:decode(Data)
end
""";
{#gen{erule=jer},true} ->
exit("JER + return rest not supported");
{_,_} ->
"Data"
end,

DecodeDisp = ["decode_disp(Type, ",DecWrap,")"],
case {Gen,ReturnRest} of
{#gen{erule=ber},true} ->
emit([" Result = ",DecodeDisp,",",nl]),
{#gen{erule=ber},true} ->
emit([" Result = ",DecodeDisp,",",nl]),
result_line(NoOkWrapper, ["Result","Rest"]);
{#gen{erule=ber},false} ->
emit([" Result = ",DecodeDisp,",",nl]),
{#gen{erule=ber},false} ->
emit([" Result = ",DecodeDisp,",",nl]),
result_line(NoOkWrapper, ["Result"]);
{#gen{erule=jer},false} ->
emit([" Result = ",{call,jer,decode_jer,[CurrMod,"Type",DecWrap]},",",nl]),
{#gen{erule=JER},false} when JER =:= jer ->
emit([" Result = ",{call,jer,decode_jer,[CurrMod,"Type",DecWrap]},",",nl]),
result_line(NoOkWrapper, ["Result"]);


{#gen{erule=per},true} ->
emit([" {Result,Rest} = ",DecodeDisp,",",nl]),
{#gen{erule=per},true} ->
emit([" {Result,Rest} = ",DecodeDisp,",",nl]),
result_line(NoOkWrapper, ["Result","Rest"]);
{#gen{erule=per},false} ->
emit([" {Result,_Rest} = ",DecodeDisp,",",nl]),
{#gen{erule=per},false} ->
emit([" {Result,_Rest} = ",DecodeDisp,",",nl]),
result_line(NoOkWrapper, ["Result"])
end,

case NoOkWrapper of
false ->
emit([nl,try_catch(),".",nl,nl]);
true ->
emit([".",nl,nl])
end,

case Gen#gen.jer of
true ->
emit(["jer_decode(Type, ",Data,") ->",nl]),
case NoOkWrapper of
false -> emit(["try",nl]);
true -> ok
end,
JerDecWrap = "json:decode(Data)",
emit([" Result = ",
{call,jer,
decode_jer,
[CurrMod,"Type",JerDecWrap]},",",nl]),
result_line(false, ["Result"]),
case NoOkWrapper of
false ->
emit([nl,try_catch(),".",nl,nl]);
true ->
emit([".",nl,nl])
end;
false ->
emit([nl,try_catch()]);
true ->
ok
end,


%% REST of MODULE
gen_decode_partial_incomplete(Gen, NoOkWrapper),
gen_partial_inc_dispatcher(Gen),

case Gen of
#gen{erule=jer} ->
ok;
_ ->
gen_dispatcher(Types, "encode_disp", "enc_"),
gen_dispatcher(Types, "decode_disp", "dec_")
end.
emit([".",nl,nl]).

result_line(NoOkWrapper, Items) ->
S = [" "|case NoOkWrapper of
14 changes: 11 additions & 3 deletions lib/asn1/test/asn1_test_lib.erl
Original file line number Diff line number Diff line change
@@ -197,7 +197,7 @@ roundtrip_enc(Mod, Type, Value, ExpectedValue) ->
ExpectedValue = Mod:decode(Type, Encoded)
end,
map_roundtrip(Mod, Type, Encoded),
test_ber_indefinite(Mod, Type, Encoded, ExpectedValue),
test_special(Mod, Type, Encoded, ExpectedValue),
Encoded.

map_roundtrip(Mod, Type, Encoded) ->
@@ -248,17 +248,25 @@ match_value_tuple(I, T1, T2) when I =< tuple_size(T1) ->
match_value_tuple(_, _, _) ->
ok.

test_ber_indefinite(Mod, Type, Encoded, ExpectedValue) ->
test_special(Mod, Type, Encoded, ExpectedValue) ->
case Mod:encoding_rule() of
ber ->
%% Test indefinite decoding for BER.
Indefinite = iolist_to_binary(ber_indefinite(Encoded)),
case Mod:decode(Type, Indefinite) of
{ok,ExpectedValue} ->
ok;
ExpectedValue ->
ok
end;
_ ->
jer ->
%% Test already decoded JSON for JER.
JsonDecoded = json:decode(Encoded),
case Mod:decode(Type, {json_decoded,JsonDecoded}) of
{ok,ExpectedValue} -> ok;
ExpectedValue -> ok
end;
_ ->
ok
end.