From df9184eeb926f8e5c04b2a3974f9d274dcbffb04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 22 Jan 2013 19:10:02 +0100 Subject: Fix a bug where necessary alignment would be skipped --- lib/asn1/src/asn1ct_constructed_per.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl index 27070be966..e8ec49d0c2 100644 --- a/lib/asn1/src/asn1ct_constructed_per.erl +++ b/lib/asn1/src/asn1ct_constructed_per.erl @@ -1276,8 +1276,8 @@ gen_dec_comp_call(Comp, Erule, TopType, Tpos, OptTable, DecInfObj, St end}, [{group,[{safe,Comment},{safe,Preamble}, - {safe,OptOrDef}|Lines]++ - [{safe,Postamble},{safe,AdvBuffer}]}]. + OptOrDef|Lines]++ + [Postamble,{safe,AdvBuffer}]}]. is_mandatory_predef_tab_c(noext, mandatory, {"got objfun through args","ObjFun"}) -> -- cgit v1.2.3 From 60e73d24cfec506b966ff789c8420bc4f466f880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 14 Dec 2012 14:08:12 +0100 Subject: Add a mechanism for embedding run-time functions into the generated code --- lib/asn1/src/.gitignore | 1 + lib/asn1/src/Makefile | 25 ++++++++ lib/asn1/src/asn1ct_func.erl | 105 +++++++++++++++++++++++++++++++++ lib/asn1/src/asn1ct_gen.erl | 9 +++ lib/asn1/src/asn1ct_imm.erl | 5 +- lib/asn1/src/asn1rtt_per_common.erl | 44 ++++++++++++++ lib/asn1/src/prepare_templates.erl | 112 ++++++++++++++++++++++++++++++++++++ 7 files changed, 299 insertions(+), 2 deletions(-) create mode 100644 lib/asn1/src/.gitignore create mode 100644 lib/asn1/src/asn1ct_func.erl create mode 100644 lib/asn1/src/asn1rtt_per_common.erl create mode 100644 lib/asn1/src/prepare_templates.erl (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/.gitignore b/lib/asn1/src/.gitignore new file mode 100644 index 0000000000..aee890a053 --- /dev/null +++ b/lib/asn1/src/.gitignore @@ -0,0 +1 @@ +/asn1ct_rtt.erl diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile index 03e18c565b..4096dd4db6 100644 --- a/lib/asn1/src/Makefile +++ b/lib/asn1/src/Makefile @@ -47,6 +47,7 @@ CT_MODULES= \ asn1ct_check \ asn1_db \ asn1ct_pretty_format \ + asn1ct_func \ asn1ct_gen \ asn1ct_gen_per \ asn1ct_gen_per_rt2ct \ @@ -55,6 +56,7 @@ CT_MODULES= \ asn1ct_constructed_ber_bin_v2 \ asn1ct_gen_ber_bin_v2 \ asn1ct_imm \ + asn1ct_rtt \ asn1ct_value \ asn1ct_tok \ asn1ct_parser2 \ @@ -138,6 +140,9 @@ info: $(EBIN)/asn1ct.$(EMULATOR):asn1ct.erl $(V_ERLC) -b$(EMULATOR) -o$(EBIN) $(ERL_COMPILE_FLAGS) -Dvsn=\"$(VSN)\" $< +$(EBIN)/asn1ct_func.$(EMULATOR): asn1ct_func.erl + $(ERLC) -o$(EBIN) $(ERL_COMPILE_FLAGS) -I../rt_templates $< + $(APP_TARGET): $(APP_SRC) ../vsn.mk $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@ @@ -164,6 +169,25 @@ release_spec: opt release_docs_spec: +# +# Run-time library template files. +# + +RT_TEMPLATES = asn1rtt_per_common + +RT_TEMPLATES_ERL = $(RT_TEMPLATES:%=%.erl) +RT_TEMPLATES_TARGET = $(RT_TEMPLATES:%=%.$(EMULATOR)) + +asn1ct_rtt.erl: prepare_templates.$(EMULATOR) $(RT_TEMPLATES_TARGET) + erl -noshell -noinput -run prepare_templates gen_asn1ct_rtt \ + $(RT_TEMPLATES_TARGET) >asn1ct_rtt.erl + +prepare_templates.$(EMULATOR): prepare_templates.erl + erlc prepare_templates.erl + +asn1rtt_%.$(EMULATOR): asn1rtt_%.erl + erlc +debug_info $< + # # Dependencies # @@ -175,6 +199,7 @@ $(EBIN)/asn1ct_check.beam: asn1ct_check.erl asn1_records.hrl $(EBIN)/asn1ct_constructed_ber_bin_v2.beam: asn1ct_constructed_ber_bin_v2.erl \ asn1_records.hrl $(EBIN)/asn1ct_constructed_per.beam: asn1ct_constructed_per.erl asn1_records.hrl +$(EBIN)/asn1ct_func.beam: asn1ct_func.erl $(EBIN)/asn1ct_gen.beam: asn1ct_gen.erl asn1_records.hrl $(EBIN)/asn1ct_gen_ber_bin_v2.beam: asn1ct_gen_ber_bin_v2.erl asn1_records.hrl $(EBIN)/asn1ct_gen_per.beam: asn1ct_gen_per.erl asn1_records.hrl diff --git a/lib/asn1/src/asn1ct_func.erl b/lib/asn1/src/asn1ct_func.erl new file mode 100644 index 0000000000..2d221ca1b9 --- /dev/null +++ b/lib/asn1/src/asn1ct_func.erl @@ -0,0 +1,105 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(asn1ct_func). +-export([start_link/0,need/1,call/3,generate/1]). +-export([init/1,handle_call/3,handle_cast/2,terminate/2]). + +start_link() -> + {ok,Pid} = gen_server:start_link(?MODULE, [], []), + put(?MODULE, Pid), + ok. + +call(M, F, Args) -> + MFA = {M,F,length(Args)}, + need(MFA), + asn1ct_gen:emit([F,"(",call_args(Args, ""),")"]). + +need(MFA) -> + asn1ct_rtt:assert_defined(MFA), + cast({need,MFA}). + +generate(Fd) -> + req({generate,Fd}), + erase(?MODULE), + ok. + +req(Req) -> + gen_server:call(get(?MODULE), Req, infinity). + +cast(Req) -> + gen_server:cast(get(?MODULE), Req). + +%%% Internal functions. + +-record(st, {used}). + +init([]) -> + St = #st{used=gb_sets:empty()}, + {ok,St}. + +handle_cast({need,MFA}, #st{used=Used0}=St) -> + case gb_sets:is_member(MFA, Used0) of + false -> + Used = pull_in_deps(gb_sets:singleton(MFA), Used0), + {noreply,St#st{used=Used}}; + true -> + {noreply,St} + end. + +handle_call({generate,Fd}, _From, #st{used=Used}=St) -> + generate(Fd, Used), + {stop,normal,ok,St}. + +terminate(_, _) -> + ok. + +call_args([A|As], Sep) -> + [Sep,A|call_args(As, ", ")]; +call_args([], _) -> []. + +generate(Fd, Used0) -> + Used1 = gb_sets:to_list(Used0), + Used = sofs:set(Used1, [mfa]), + Code = sofs:relation(asn1ct_rtt:code(), [{mfa,code}]), + Funcs0 = sofs:image(Code, Used), + Funcs = sofs:to_external(Funcs0), + io:put_chars(Fd, Funcs). + +pull_in_deps(Ws0, Used0) -> + case gb_sets:is_empty(Ws0) of + true -> + Used0; + false -> + {MFA,Ws1} = gb_sets:take_smallest(Ws0), + Used = gb_sets:add(MFA, Used0), + Needs = asn1ct_rtt:dependencies(MFA), + Ws = update_worklist(Needs, Used, Ws1), + pull_in_deps(Ws, Used) + end. + +update_worklist([H|T], Used, Ws) -> + case gb_sets:is_member(H, Used) of + false -> + update_worklist(T, Used, gb_sets:add(H, Ws)); + true -> + update_worklist(T, Used, Ws) + end; +update_worklist([], _, Ws) -> Ws. diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl index 57b12ce186..67efbcc532 100644 --- a/lib/asn1/src/asn1ct_gen.erl +++ b/lib/asn1/src/asn1ct_gen.erl @@ -78,6 +78,7 @@ pgen_module(OutFile,Erules,Module, ErlFile = lists:concat([OutFile,".erl"]), Fid = fopen(ErlFile,[write]), put(gen_file_out,Fid), + asn1ct_func:start_link(), gen_head(Erules,Module,HrlGenerated), pgen_exports(Erules,Module,TypeOrVal), pgen_dispatcher(Erules,Module,TypeOrVal), @@ -86,6 +87,11 @@ pgen_module(OutFile,Erules,Module, pgen_partial_incomplete_decode(Erules), % gen_vars(asn1_db:mod_to_vars(Module)), % gen_tag_table(AllTypes), + emit([nl, + "%%%",nl, + "%%% Run-time functions.",nl, + "%%%",nl]), + asn1ct_func:generate(Fid), file:close(Fid), asn1ct:verbose("--~p--~n",[{generated,ErlFile}],Options). @@ -1160,6 +1166,9 @@ emit({var,Variable}) -> emit({asis,What}) -> format(get(gen_file_out),"~w",[What]); +emit({call,M,F,A}) -> + asn1ct_func:call(M, F, A); + emit(nl) -> nl(get(gen_file_out)); diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl index 34bb0b8714..d27bea98d0 100644 --- a/lib/asn1/src/asn1ct_imm.erl +++ b/lib/asn1/src/asn1ct_imm.erl @@ -129,8 +129,9 @@ dec_string({Lb,Ub}, U, Aligned) when Ub < 16#10000 -> dec_string(_, U, Aligned) -> Al = [{align,Aligned}], DecRest = fun(V, Buf) -> - emit(["?RT_PER:decode_fragmented(",V,", ", - Buf,", ",U,")"]) + asn1ct_func:call(per_common, + decode_fragmented, + [V,Buf,U]) end, {'case',[{test,{get_bits,1,[1|Al]},0, {value,{get_bits, diff --git a/lib/asn1/src/asn1rtt_per_common.erl b/lib/asn1/src/asn1rtt_per_common.erl new file mode 100644 index 0000000000..926f0fe228 --- /dev/null +++ b/lib/asn1/src/asn1rtt_per_common.erl @@ -0,0 +1,44 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(asn1rtt_per_common). + +-include("asn1_records.hrl"). + +-export([decode_fragmented/3]). +-define('16K',16384). + +decode_fragmented(SegSz0, Buf0, Unit) -> + SegSz = SegSz0 * Unit * ?'16K', + <> = Buf0, + decode_fragmented_1(Buf, Unit, Res). + +decode_fragmented_1(<<0:1,N:7,Buf0/bitstring>>, Unit, Res) -> + Sz = N*Unit, + <> = Buf0, + {<>,Buf}; +decode_fragmented_1(<<1:1,0:1,N:14,Buf0/bitstring>>, Unit, Res) -> + Sz = N*Unit, + <> = Buf0, + {<>,Buf}; +decode_fragmented_1(<<1:1,1:1,SegSz0:6,Buf0/bitstring>>, Unit, Res0) -> + SegSz = SegSz0 * Unit * ?'16K', + <> = Buf0, + Res = <>, + decode_fragmented_1(Buf, Unit, Res). diff --git a/lib/asn1/src/prepare_templates.erl b/lib/asn1/src/prepare_templates.erl new file mode 100644 index 0000000000..7242166989 --- /dev/null +++ b/lib/asn1/src/prepare_templates.erl @@ -0,0 +1,112 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(prepare_templates). +-export([gen_asn1ct_rtt/1]). + +gen_asn1ct_rtt(Ms) -> + io:format("%% Generated by ~s. DO NOT EDIT THIS FILE.\n" + "%%\n" + "%% Input files:\n", [?MODULE]), + [io:put_chars(["%% ",M,$\n]) || M <- Ms], + io:nl(), + io:put_chars("-module(asn1ct_rtt).\n" + "-export([assert_defined/1,dependencies/1,code/0]).\n" + "\n"), + Forms = lists:sort(lists:append([abstract(M) || M <- Ms])), + Exp = lists:sort(exports(Forms)), + defined(Exp), + io:nl(), + Calls = calls(Forms), + R = sofs:relation(Calls), + Fam0 = sofs:relation_to_family(R), + Fam = sofs:to_external(Fam0), + dependencies(Fam), + io:nl(), + Funcs = [begin + Bin = list_to_binary([$\n|erl_pp:function(Func)]), + {{M,F,A},Bin} + end || {M,{function,_,F,A,_}=Func} <- Forms], + io:format("code() ->\n~p.\n\n", [Funcs]), + halt(0). + +defined([H|T]) -> + io:format("assert_defined(~p) -> ok", [H]), + case T of + [] -> + io:put_chars(".\n"); + [_|_] -> + io:put_chars(";\n"), + defined(T) + end. + +dependencies([{K,V}|T]) -> + io:format("dependencies(~p) ->\n~p;\n", [K,V]), + dependencies(T); +dependencies([]) -> + io:put_chars("dependencies(_) -> [].\n"). + +abstract(File) -> + {ok,{M0,[{abstract_code,Abstract}]}} = + beam_lib:chunks(File, [abstract_code]), + {raw_abstract_v1,Forms} = Abstract, + M = module(M0), + [{M,F} || F <- Forms]. + +module(M0) -> + "asn1rtt_" ++ M = atom_to_list(M0), + list_to_atom(M). + +exports([{M,{attribute,_,export,L}}|T]) -> + [{M,F,A} || {F,A} <- L] ++ exports(T); +exports([_|T]) -> + exports(T); +exports([]) -> []. + +calls([{M,{function,_,F,A,Body}}|T]) -> + MFA = {M,F,A}, + case find_calls(Body, M) -- [MFA] of + [] -> + calls(T); + [_|_]=Calls -> + [{MFA,Callee} || Callee <- Calls] ++ calls(T) + end; +calls([_|T]) -> + calls(T); +calls([]) -> []. + +find_calls([{call,_,{atom,_,F},Args}|T], M) -> + Calls = find_calls(Args, M) ++ find_calls(T, M), + Arity = length(Args), + case is_bif(F, Arity) of + false -> + [{M,F,Arity}|Calls]; + true -> + Calls + end; +find_calls([{'fun',_,{function,F,A}}|T], M) -> + [{M,F,A}|find_calls(T, M)]; +find_calls([H|T], M) -> + find_calls(H, M) ++ find_calls(T, M); +find_calls(Tuple, M) when is_tuple(Tuple) -> + find_calls(tuple_to_list(Tuple), M); +find_calls(_, _) -> []. + +is_bif(F, Arity) -> + erl_internal:bif(F, Arity). -- cgit v1.2.3 From 8cc1f6e814fb4cfe69cb1f80138c630377d26b57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 14 Dec 2012 21:07:39 +0100 Subject: Add run-time library templates and use them The template modules (asn1rtt_*.erl) are based on the existing run-time modules, but with some simplifications and improvements, for example: The run-time functions for BER encoding took a Constraint argument which was not used. It has been eliminated, along with the unused StringType argument for the encode_restricted_string function. The Range argument for decode_enumerated() has been dropped since it was not used. --- lib/asn1/src/Makefile | 6 +- lib/asn1/src/asn1ct.erl | 4 - lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl | 85 +- lib/asn1/src/asn1ct_constructed_per.erl | 95 +- lib/asn1/src/asn1ct_gen.erl | 64 +- lib/asn1/src/asn1ct_gen_ber_bin_v2.erl | 372 +++--- lib/asn1/src/asn1ct_gen_per.erl | 200 ++- lib/asn1/src/asn1ct_gen_per_rt2ct.erl | 131 +- lib/asn1/src/asn1ct_imm.erl | 10 +- lib/asn1/src/asn1rt_ber_bin_v2.erl | 1 + lib/asn1/src/asn1rtt_ber.erl | 1619 ++++++++++++++++++++++++ lib/asn1/src/asn1rtt_per.erl | 1334 +++++++++++++++++++ lib/asn1/src/asn1rtt_real_common.erl | 292 +++++ lib/asn1/src/asn1rtt_uper.erl | 1379 ++++++++++++++++++++ 14 files changed, 5078 insertions(+), 514 deletions(-) create mode 100644 lib/asn1/src/asn1rtt_ber.erl create mode 100644 lib/asn1/src/asn1rtt_per.erl create mode 100644 lib/asn1/src/asn1rtt_real_common.erl create mode 100644 lib/asn1/src/asn1rtt_uper.erl (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile index 4096dd4db6..75ffdd66c7 100644 --- a/lib/asn1/src/Makefile +++ b/lib/asn1/src/Makefile @@ -173,7 +173,11 @@ release_docs_spec: # Run-time library template files. # -RT_TEMPLATES = asn1rtt_per_common +RT_TEMPLATES = asn1rtt_per_common \ + asn1rtt_real_common \ + asn1rtt_ber \ + asn1rtt_per \ + asn1rtt_uper RT_TEMPLATES_ERL = $(RT_TEMPLATES:%=%.erl) RT_TEMPLATES_TARGET = $(RT_TEMPLATES:%=%.$(EMULATOR)) diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl index 98877320a0..e361654a81 100644 --- a/lib/asn1/src/asn1ct.erl +++ b/lib/asn1/src/asn1ct.erl @@ -115,13 +115,11 @@ compile1(File,Options) when is_list(Options) -> DbFile = outfile(Base,"asn1db",Options), Includes = [I || {i,I} <- Options], EncodingRule = get_rule(Options), - asn1ct_table:new(asn1_functab), Continue1 = scan(File,Options), Continue2 = parse(Continue1,File,Options), Continue3 = check(Continue2,File,OutFile,Includes,EncodingRule, DbFile,Options,[]), Continue4 = generate(Continue3,OutFile,EncodingRule,Options), - asn1ct_table:delete(asn1_functab), Ret = compile_erl(Continue4,OutFile,Options), case inline(is_inline(Options), inline_output(Options,filename:rootname(File)), @@ -183,7 +181,6 @@ compile_set(SetBase,Files,Options) DbFile = outfile(SetBase,"asn1db",Options), Includes = [I || {i,I} <- Options], EncodingRule = get_rule(Options), - asn1ct_table:new(asn1_functab), ScanRes = scan_set(Files,Options), ParseRes = parse_set(ScanRes,Options), Result = @@ -208,7 +205,6 @@ compile_set(SetBase,Files,Options) {error,{'unexpected error in scan/parse phase', lists:map(fun(X)->element(3,X) end,Other)}} end, - asn1ct_table:delete(asn1_functab), Result. check_set(ParseRes,SetBase,OutFile,Includes,EncRule,DbFile, diff --git a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl index 78cb9297d8..021002c3b3 100644 --- a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl +++ b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl @@ -162,7 +162,8 @@ gen_encode_sequence(Erules,Typename,D) when is_record(D,type) -> emit([nl," BytesSoFar = "]), case SeqOrSet of 'SET' when (D#type.def)#'SET'.sorted == dynamic -> - emit("asn1rt_check:dynamicsort_SET_components(["), + asn1ct_func:need({ber,dynamicsort_SET_components,1}), + emit("dynamicsort_SET_components(["), mkvlist(asn1ct_name:all(encBytes)), emit(["]),",nl]); _ -> @@ -177,8 +178,8 @@ gen_encode_sequence(Erules,Typename,D) when is_record(D,type) -> mkvplus(AllLengths) end, emit([",",nl]), - emit(["?RT_BER:encode_tags(TagIn, BytesSoFar, LenSoFar)." - ,nl]). + call(encode_tags, ["TagIn","BytesSoFar","LenSoFar"]), + emit([".",nl]). gen_decode_sequence(Erules,Typename,D) when is_record(D,type) -> asn1ct_name:start(), @@ -207,7 +208,8 @@ gen_decode_sequence(Erules,Typename,D) when is_record(D,type) -> _ -> emit([{curr,tlv}," = "]) end, - emit(["?RT_BER:match_tags(",{prev,tlv},",TagIn), ",nl]), + call(match_tags, [{prev,tlv},"TagIn"]), + emit([com,nl]), asn1ct_name:new(tlv), asn1ct_name:new(v), @@ -371,7 +373,8 @@ gen_decode_set(Erules,Typename,D) when is_record(D,type) -> _ -> emit([{curr,tlv}," = "]) end, - emit(["?RT_BER:match_tags(",{prev,tlv},",TagIn), ",nl]), + call(match_tags, [{prev,tlv},"TagIn"]), + emit([com,nl]), asn1ct_name:new(v), @@ -492,7 +495,8 @@ gen_encode_sof(Erules,Typename,_InnerTypename,D) when is_record(D,type) -> emit([" {EncBytes,EncLen} = 'enc_",asn1ct_gen:list2name(Typename), "_components'(Val",Objfun,",[],0),",nl]), - emit([" ?RT_BER:encode_tags(TagIn, EncBytes, EncLen).",nl,nl]), + emit([" ",{call,ber,encode_tags,["TagIn","EncBytes","EncLen"]}, + ".",nl,nl]), gen_encode_sof_components(Erules,Typename,SeqOrSetOf,Cont). @@ -512,8 +516,8 @@ gen_decode_sof(Erules,TypeName,_InnerTypeName,D) when is_record(D,type) -> emit([" %%-------------------------------------------------",nl]), asn1ct_name:new(tlv), - emit([{curr,tlv}, - " = ?RT_BER:match_tags(",{prev,tlv},",TagIn), ",nl]), + emit([{curr,tlv}," = ", + {call,ber,match_tags,[{prev,tlv},"TagIn"]},com,nl]), asn1ct_name:new(v), emit(["["]), @@ -551,8 +555,9 @@ gen_encode_sof_components(Erules,Typename,SeqOrSetOf,Cont) case catch lists:member(der,get(encoding_options)) of true when SeqOrSetOf=='SET OF'-> + asn1ct_func:need({ber,dynamicsort_SETOF,1}), emit([indent(3), - "{asn1rt_check:dynamicsort_SETOF(AccBytes),AccLen};",nl,nl]); + "{dynamicsort_SETOF(AccBytes),AccLen};",nl,nl]); _ -> emit([indent(3),"{lists:reverse(AccBytes),AccLen};",nl,nl]) end, @@ -672,8 +677,9 @@ gen_dec_sequence_call2(Erules,TopType,{Root1,EList,Root2},_Ext,DecObjInf) -> %% including the first mandatory element. TagList = get_root2_taglist(Root2,[]), emit({com,nl}), - emit([{curr,tlv}," = ?RT_BER:skip_ExtensionAdditions(", - {prev,tlv},", ",{asis,TagList},"),",nl]), + emit([{curr,tlv}," = ", + {call,ber,skip_ExtensionAdditions, + [{prev,tlv},{asis,TagList}]},com,nl]), asn1ct_name:new(tlv), gen_dec_sequence_call1(Erules,TopType,Root2, length(Root1)+length(EList),noext, @@ -805,8 +811,8 @@ gen_enc_choice1(Erules,TopType,_Tag,CompList,_Ext) -> emit([" {EncBytes,EncLen} = case element(1,Val) of",nl]), gen_enc_choice2(Erules,TopType,CompList), emit([nl," end,",nl,nl]), - - emit(["?RT_BER:encode_tags(TagIn, EncBytes, EncLen).",nl]). + call(encode_tags, ["TagIn","EncBytes","EncLen"]), + emit([".",nl]). gen_enc_choice2(Erules,TopType,[H1|T]) when is_record(H1,'ComponentType') -> @@ -859,8 +865,8 @@ gen_enc_choice2(_Erules,_TopType,[]) -> gen_dec_choice(Erules,TopType, _ChTag, CompList, Ext) -> asn1ct_name:clear(), asn1ct_name:new(tlv), - emit([{curr,tlv}, - " = ?RT_BER:match_tags(",{prev,tlv},",TagIn), ",nl]), + emit([{curr,tlv}," = ", + {call,ber,match_tags,[{prev,tlv},"TagIn"]},com,nl]), asn1ct_name:new(tlv), asn1ct_name:new(v), emit(["case (case ",{prev,tlv}, @@ -876,8 +882,8 @@ gen_dec_choice(Erules,TopType, _ChTag, CompList, Ext) -> emit([indent(9),"exit({error,{asn1,{invalid_choice_tag,", {curr,else},"}}})",nl]); _ -> - emit([indent(9),"{asn1_ExtAlt, ?RT_BER:encode(",{curr,else}, - asn1ct_gen:nif_parameter(),")}",nl]) + emit([indent(9),"{asn1_ExtAlt,", + {call,ber,ber_encode,[{curr,else}]},"}",nl]) end, emit([indent(3),"end",nl]), asn1ct_name:new(tag), @@ -1018,29 +1024,20 @@ gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,Assign,EncObj) case OptOrMand of mandatory -> emit(["{",{curr,encBytes},",",{curr,encLen}, - "} = "]), - emit(["?RT_BER:encode_open_type(",{curr,tmpBytes}, - ",",{asis,Tag},")"]); + "} = ", + {call,ber,encode_open_type, + [{curr,tmpBytes},{asis,Tag}]},nl]); _ -> -% emit(["{",{next,tmpBytes},", _} = "]), emit(["{",{next,tmpBytes},",",{curr,tmpLen}, - "} = "]), - emit(["?RT_BER:encode_open_type(",{curr,tmpBytes}, - ",",{asis,Tag},"),",nl]), + "} = ", + {call,ber,encode_open_type, + [{curr,tmpBytes},{asis,Tag}]},com,nl]), emit(IndDeep), emit(["{",{next,tmpBytes},", ",{curr,tmpLen},"}"]) end; Err -> throw({asn1,{'internal error',Err}}) end; -%% {{#'ObjectClassFieldType'{type={objectfield,PrimFieldName1, -%% PFNList}},_}, -%% {componentrelation,_,_}} -> -%% %% this is when the dotted list in the FieldName has more -%% %% than one element -%% {_LeadingAttrName,Fun} = EncObj, -%% emit(["?RT_BER:encode_open_type(",Fun,"(",{asis,PrimFieldName1}, -%% ", ",Element,", ",{asis,PFNList},"))"]); _ -> case WhatKind of {primitive,bif} -> @@ -1238,15 +1235,11 @@ gen_dec_call({typefield,_},_,_,_Cname,Type,BytesVar,Tag,_,_,false,_) -> asn1ct_name:new(tmptlv), {FirstPFName,RestPFName} = -% asn1ct_gen:get_constraint(Type#type.constraint, -% tableconstraint_info), (Type#type.def)#'ObjectClassFieldType'.fieldname, emit([nl,indent(6),"begin",nl]), -% emit([indent(9),{curr,opendec}," = ?RT_BER:decode_open_type(", - emit([indent(9),{curr,tmptlv}," = ?RT_BER:decode_open_type(", - BytesVar,",",{asis,Tag},asn1ct_gen:nif_parameter(),"),",nl]), -% emit([indent(9),"{",{curr,tmptlv},",_} = ?RT_BER:decode(", -% {curr,opendec},"),",nl]), + emit([indent(9),{curr,tmptlv}," = ", + {call,ber,decode_open_type, + [BytesVar,{asis,Tag}]},com,nl]), emit([indent(9),"case (catch ObjFun(",{asis,FirstPFName}, ", ",{curr,tmptlv},", ",{asis,RestPFName}, @@ -1259,8 +1252,7 @@ gen_dec_call({typefield,_},_,_,_Cname,Type,BytesVar,Tag,_,_,false,_) -> emit([indent(9),"end",nl,indent(6),"end",nl]), []; gen_dec_call({typefield,_},_,_,Cname,Type,BytesVar,Tag,_,_,_DecObjInf,OptOrMandComp) -> - emit(["?RT_BER:decode_open_type(",BytesVar,",",{asis,Tag}, - asn1ct_gen:nif_parameter(),")"]), + call(decode_open_type, [BytesVar,{asis,Tag}]), RefedFieldName = % asn1ct_gen:get_constraint(Type#type.constraint, % tableconstraint_info), @@ -1268,8 +1260,7 @@ gen_dec_call({typefield,_},_,_,Cname,Type,BytesVar,Tag,_,_,_DecObjInf,OptOrMandC [{Cname,RefedFieldName,asn1ct_gen:mk_var(asn1ct_name:curr(term)), asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),Tag,OptOrMandComp}]; gen_dec_call({objectfield,PrimFieldName,PFNList},_,_,Cname,_,BytesVar,Tag,_,_,_,OptOrMandComp) -> - emit(["?RT_BER:decode_open_type(",BytesVar,",",{asis,Tag}, - asn1ct_gen:nif_parameter(),")"]), + call(decode_open_type, [BytesVar,{asis,Tag}]), [{Cname,{PrimFieldName,PFNList},asn1ct_gen:mk_var(asn1ct_name:curr(term)), asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),Tag,OptOrMandComp}]; gen_dec_call(InnerType,Erules,TopType,Cname,Type,BytesVar,Tag,PrimOptOrMand, @@ -1301,7 +1292,6 @@ gen_dec_call1({primitive,bif},InnerType,Erules,TopType,Cname,Type,BytesVar, asn1ct:add_generated_refed_func({[Cname|TopType],undecoded, Tag,Type}), asn1ct:update_gen_state(namelist,Rest), -% emit(["?RT_BER:match_tags(",BytesVar,",",{asis,Tag},")"]); emit(["{'",asn1ct_gen:list2name([Cname|TopType]),"',", BytesVar,"}"]); {_,{fixedtypevaluefield,_,Btype}} -> @@ -1320,7 +1310,6 @@ gen_dec_call1('ASN1_OPEN_TYPE',_InnerType,Erules,TopType,Cname,Type,BytesVar, asn1ct:update_gen_state(namelist,Rest), emit(["{'",asn1ct_gen:list2name([Cname|TopType]),"',", BytesVar,"}"]); -% emit(["?RT_BER:match_tags(",BytesVar,",",{asis,Tag},")"]); {_,#'ObjectClassFieldType'{type=OpenType}} -> ?ASN1CT_GEN_BER:gen_dec_prim(Erules,#type{def=OpenType}, BytesVar,Tag,[], @@ -1393,7 +1382,8 @@ gen_dec_call1(WhatKind,_,_Erules,TopType,Cname,Type,BytesVar, parts, [],Type}), emit(["{'",asn1ct_gen:list2name([Cname|TopType]),"',"]), - EmitDecFunCall("?RT_BER:match_tags"), + asn1ct_func:need({ber,match_tags,2}), + EmitDecFunCall("match_tags"), emit("}"); _ -> {DecFunName,_,_}= @@ -1522,3 +1512,6 @@ value_match1(Value,[],Acc,Depth) -> Acc ++ Value ++ lists:concat(lists:duplicate(Depth,")")); value_match1(Value,[{VI,_}|VIs],Acc,Depth) -> value_match1(Value,VIs,Acc++lists:concat(["element(",VI,","]),Depth+1). + +call(F, Args) -> + asn1ct_func:call(ber, F, Args). diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl index e8ec49d0c2..5520b41541 100644 --- a/lib/asn1/src/asn1ct_constructed_per.erl +++ b/lib/asn1/src/asn1ct_constructed_per.erl @@ -32,6 +32,7 @@ %-compile(export_all). -import(asn1ct_gen, [emit/1,demit/1,get_record_name_prefix/0]). +-import(asn1ct_func, [call/3]). %% ENCODE GENERATOR FOR SEQUENCE TYPE ** ********** @@ -86,7 +87,8 @@ gen_encode_constructed(Erule,Typename,D) when is_record(D,type) -> end,asn1ct_name:all(fixopt)), emit({"{",{next,val},",Opt} = {",{curr,val},",[",FixOpts,"]},",nl}); {_,_,false} -> - Fixoptcall = ",Opt} = ?RT_PER:fixoptionals(", + asn1ct_func:need({Erule,fixoptionals,3}), + Fixoptcall = ",Opt} = fixoptionals(", emit({"{",{next,val},Fixoptcall, {asis,Optionals},",",length(Optionals), ",",{curr,val},"),",nl}) @@ -121,8 +123,9 @@ gen_encode_constructed(Erule,Typename,D) when is_record(D,type) -> lists:foreach(ExtGroupFun,ExtGroupPosLenList) end, asn1ct_name:new(tmpval), - emit(["Extensions = ?RT_PER:fixextensions(",{asis,Ext},",", - {curr,val},"),",nl]); + emit(["Extensions = ", + {call,Erule,fixextensions,[{asis,Ext},{curr,val}]}, + com,nl]); _ -> true end, EncObj = @@ -191,10 +194,10 @@ gen_encode_constructed(Erule,Typename,D) when is_record(D,type) -> MaybeComma1 = case Ext of {ext,_Pos,NumExt2} when NumExt2 > 0 -> - emit({"?RT_PER:setext(Extensions =/= [])"}), + call(Erule, setext, ["Extensions =/= []"]), ", "; {ext,_Pos,_} -> - emit({"?RT_PER:setext(false)"}), + call(Erule, setext, ["false"]), ", "; _ -> "" @@ -513,7 +516,7 @@ gen_encode_sof(Erule,Typename,SeqOrSetOf,D) when is_record(D,type) -> _-> "" end, - gen_encode_length(SizeConstraint, is_optimized(Erule)), + gen_encode_length(Erule, SizeConstraint), emit({indent(3),"'enc_",asn1ct_gen:list2name(Typename), "_components'(Val",ObjFun,", [])"}), emit({nl,"].",nl}), @@ -527,7 +530,7 @@ gen_encode_sof(Erule,Typename,SeqOrSetOf,D) when is_record(D,type) -> %% Logic copied from asn1_per_bin_rt2ct:encode_constrained_number -gen_encode_length({Lb,Ub},true) when Ub =< 65535, Lb >= 0 -> +gen_encode_length(per, {Lb,Ub}) when Ub =< 65535, Lb >= 0 -> Range = Ub - Lb + 1, V2 = ["(length(Val) - ",Lb,")"], Encode = if @@ -554,12 +557,20 @@ gen_encode_length({Lb,Ub},true) when Ub =< 65535, Lb >= 0 -> Range =< 65536 -> {"[20,2,<<",V2,":16>>]"}; true -> - {"?RT_PER:encode_length(",{asis,{Lb,Ub}},",length(Val))"} + {call,per,encode_length, + [{asis,{Lb,Ub}},"length(Val)"]} end, emit({nl,Encode,",",nl}); -gen_encode_length(SizeConstraint,_) -> - emit({nl,indent(3),"?RT_PER:encode_length(", - {asis,SizeConstraint},",length(Val)),",nl}). +gen_encode_length(Erules, SizeConstraint) -> + emit([nl,indent(3), + case SizeConstraint of + undefined -> + {call,Erules,encode_length,["length(Val)"]}; + _ -> + {call,Erules,encode_length, + [{asis,SizeConstraint},"length(Val)"]} + end, + com,nl]). gen_decode_sof(Erules,Typename,SeqOrSetOf,D) when is_record(D,type) -> asn1ct_name:start(), @@ -1003,7 +1014,9 @@ gen_enc_line(Erule,TopType,Cname,Type,Element, _Pos,DynamicEnc,Ext) -> case Ext of {ext,_Ep1,_} -> - emit(["?RT_PER:encode_open_type(dummy,?RT_PER:complete("]); + asn1ct_func:need({Erule,encode_open_type,1}), + asn1ct_func:need({Erule,complete,1}), + emit(["encode_open_type(complete("]); _ -> true end, @@ -1015,7 +1028,9 @@ gen_enc_line(Erule,TopType,Cname,Type,Element, _Pos,DynamicEnc,Ext) -> {notype,T} -> throw({error,{notype,type_from_object,T}}); {Name,RestFieldNames} when is_atom(Name) -> - emit({"?RT_PER:encode_open_type([],?RT_PER:complete(",nl}), + asn1ct_func:need({Erule,complete,1}), + asn1ct_func:need({Erule,encode_open_type,1}), + emit({"encode_open_type(complete(",nl}), emit({" ",Fun,"(",{asis,Name},", ", Element,", ",{asis,RestFieldNames},")))"}); Other -> @@ -1025,8 +1040,10 @@ gen_enc_line(Erule,TopType,Cname,Type,Element, _Pos,DynamicEnc,Ext) -> {objectfield,PrimFieldName1,PFNList} -> case DynamicEnc of {_LeadingAttrName,Fun} -> - emit({"?RT_PER:encode_open_type([]," - "?RT_PER:complete(",nl}), + asn1ct_func:need({Erule,complete,1}), + asn1ct_func:need({Erule,encode_open_type,1}), + emit({"encode_open_type(" + "complete(",nl}), emit({" ",Fun,"(",{asis,PrimFieldName1}, ", ",Element,", ",{asis,PFNList},")))"}) end; @@ -1105,8 +1122,9 @@ gen_dec_components_call(Erule,TopType,CL={Root1,ExtList,Root2}, NumExtsToSkip = ext_length(ExtList), Finish = fun(St) -> - emit([{next,bytes},"= ?RT_PER:skipextensions(",{curr,bytes},",", - NumExtsToSkip+1,",Extensions)"]), + emit([{next,bytes},"= "]), + call(Erule, skipextensions, + [{curr,bytes},NumExtsToSkip+1,"Extensions"]), asn1ct_name:new(bytes), St end, @@ -1559,29 +1577,33 @@ gen_dec_prim(Ctgenmod, Erule, Type) -> end. gen_enc_choice(Erule,TopType,CompList,Ext) -> - gen_enc_choice_tag(CompList, [], Ext), + gen_enc_choice_tag(Erule, CompList, [], Ext), emit({com,nl}), emit({"case element(1,Val) of",nl}), gen_enc_choice2(Erule,TopType, CompList, Ext), emit({nl,"end"}). -gen_enc_choice_tag({C1,C2},_,_) -> +gen_enc_choice_tag(Erule, {C1,C2}, _, _) -> N1 = get_name_list(C1), N2 = get_name_list(C2), - emit(["?RT_PER:set_choice(element(1,Val),", - {asis,{N1,N2}},", ",{asis,{length(N1),length(N2)}},")"]); - -gen_enc_choice_tag({C1,C2,C3},_,_) -> + call(Erule,set_choice, + ["element(1, Val)", + {asis,{N1,N2}}, + {asis,{length(N1),length(N2)}}]); +gen_enc_choice_tag(Erule, {C1,C2,C3}, _, _) -> N1 = get_name_list(C1), N2 = get_name_list(C2), N3 = get_name_list(C3), Root = N1 ++ N3, - emit(["?RT_PER:set_choice(element(1,Val),", - {asis,{Root,N2}},", ",{asis,{length(Root),length(N2)}},")"]); -gen_enc_choice_tag(C,_,_) -> + call(Erule,set_choice, + ["element(1, Val)", + {asis,{Root,N2}}, + {asis,{length(Root),length(N2)}}]); +gen_enc_choice_tag(Erule, C, _, _) -> N = get_name_list(C), - emit(["?RT_PER:set_choice(element(1,Val),", - {asis,N},", ",{asis,length(N)},")"]). + call(Erule,set_choice, + ["element(1, Val)", + {asis,N},{asis,length(N)}]). get_name_list(L) -> get_name_list(L,[]). @@ -1650,17 +1672,18 @@ gen_enc_choice2(_Erule,_,[], _, _) -> true. gen_dec_choice(Erule,TopType,CompList,{ext,Pos,NumExt}) -> - emit({"{Ext,",{curr,bytes},"} = ?RT_PER:getbit(Bytes),",nl}), + emit(["{Ext,",{curr,bytes},"} = ", + {call,Erule,getbit,["Bytes"]},com,nl]), asn1ct_name:new(bytes), gen_dec_choice1(Erule,TopType,CompList,{ext,Pos,NumExt}); gen_dec_choice(Erule,TopType,CompList,noext) -> gen_dec_choice1(Erule,TopType,CompList,noext). gen_dec_choice1(Erule,TopType,CompList,noext) -> - emit({"{Choice,",{curr,bytes}, - "} = ?RT_PER:getchoice(",{prev,bytes},",", - length(CompList),", 0),",nl}), - emit({"{Cname,{Val,NewBytes}} = case Choice of",nl}), + emit(["{Choice,",{curr,bytes}, + "} = ",{call,Erule,getchoice, + [{prev,bytes},length(CompList),"0"]},com,nl, + "{Cname,{Val,NewBytes}} = case Choice of",nl]), gen_dec_choice2(Erule,TopType,CompList,noext), emit({nl,"end,",nl}), emit({nl,"{{Cname,Val},NewBytes}"}); @@ -1671,9 +1694,9 @@ gen_dec_choice1(Erule,TopType,{RootList,ExtList,RootList2},Ext) -> NewList = RootList ++ RootList2 ++ ExtList, gen_dec_choice1(Erule,TopType, NewList, Ext); gen_dec_choice1(Erule,TopType,CompList,{ext,ExtPos,ExtNum}) -> - emit({"{Choice,",{curr,bytes}, - "} = ?RT_PER:getchoice(",{prev,bytes},",", - length(CompList)-ExtNum,",Ext ),",nl}), + emit(["{Choice,",{curr,bytes},"} = ", + {call,Erule,getchoice, + [{prev,bytes},length(CompList)-ExtNum,"Ext"]},com,nl]), emit({"{Cname,{Val,NewBytes}} = case Choice + Ext*",ExtPos-1," of",nl}), gen_dec_choice2(Erule,TopType,CompList,{ext,ExtPos,ExtNum}), Imm = asn1ct_imm:per_dec_open_type(is_aligned(Erule)), diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl index 67efbcc532..eaca7d6ec3 100644 --- a/lib/asn1/src/asn1ct_gen.erl +++ b/lib/asn1/src/asn1ct_gen.erl @@ -46,7 +46,6 @@ un_hyphen_var/1]). -export([gen_encode_constructed/4, gen_decode_constructed/4]). --export([nif_parameter/0]). %% pgen(Outfile, Erules, Module, TypeOrVal, Options) %% Generate Erlang module (.erl) and (.hrl) file corresponding to an ASN.1 module @@ -534,7 +533,8 @@ gen_part_decode_funcs({constructed,bif},TypeName, {_Name,parts,Tag,_Type}) -> emit([" case Data of",nl, " L when is_list(L) ->",nl, - " 'dec_",TypeName,"'(lists:map(fun(X)->element(1,?RT_BER:decode(X)) end,L),",{asis,Tag},");",nl, + " 'dec_",TypeName,"'(lists:map(fun(X) -> element(1, ", + {call,ber,ber_decode_erlang,["X"]},") end, L),",{asis,Tag},");",nl, " _ ->",nl, " [Res] = 'dec_",TypeName,"'([Data],",{asis,Tag},"),",nl, " Res",nl, @@ -928,13 +928,16 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) -> {Call,BytesAsBinary} = case Erules of per -> - {["?RT_PER:complete(encode_disp(Type,Data))"],"Bytes"}; + asn1ct_func:need({Erules,complete,1}), + {["complete(encode_disp(Type, Data))"],"Bytes"}; ber -> {"encode_disp(Type,Data)","iolist_to_binary(Bytes)"}; uper when NoFinalPadding == true -> - {"?RT_PER:complete_NFP(encode_disp(Type,Data))","Bytes"}; + asn1ct_func:need({Erules,complete_NFP,1}), + {"complete_NFP(encode_disp(Type, Data))","Bytes"}; uper -> - {["?RT_PER:complete(encode_disp(Type,Data))"],"Bytes"} + asn1ct_func:need({Erules,complete,1}), + {["complete(encode_disp(Type, Data))"],"Bytes"} end, emit(["encode(Type,Data) ->",nl, "case catch ",Call," of",nl, @@ -958,12 +961,11 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) -> DecAnonymous = case {Erules,Return_rest} of {ber,false} -> - io_lib:format("~s~s~s~n", - ["element(1,?RT_BER:decode(Data", - nif_parameter(),"))"]); + asn1ct_func:need({ber,ber_decode_nif,1}), + "element(1, ber_decode_nif(Data))"; {ber,true} -> - emit(["{Data,Rest} = ?RT_BER:decode(Data0", - nif_parameter(),"),",nl]), + asn1ct_func:need({ber,ber_decode_nif,1}), + emit(["{Data,Rest} = ber_decode_nif(Data0),",nl]), "Data"; _ -> "Data" @@ -1048,16 +1050,16 @@ gen_decode_partial_incomplete(ber) -> emit(["decode_partial_incomplete(Type,Data0,", "Pattern) ->",nl]), emit([" {Data,_RestBin} =",nl, - " ?RT_BER:decode_primitive_", - "incomplete(Pattern,Data0),",nl, + " ",{call,ber,decode_primitive_incomplete, + ["Pattern","Data0"]},com,nl, " case catch decode_partial_inc_disp(Type,", "Data) of",nl]), EmitCaseClauses(), emit([".",nl,nl]), emit(["decode_part(Type, Data0) " "when is_binary(Data0) ->",nl]), - emit([" case catch decode_inc_disp(Type,element(1," - "?RT_BER:decode(Data0",nif_parameter(),"))) of",nl]), + emit([" case catch decode_inc_disp(Type,element(1, ", + {call,ber,ber_decode_nif,["Data0"]},")) of",nl]), EmitCaseClauses(), emit([";",nl]), emit(["decode_part(Type, Data0) ->",nl]), @@ -1101,9 +1103,6 @@ gen_partial_inc_dispatcher([],_) -> emit(["decode_partial_inc_disp(Type,_Data) ->",nl, " exit({error,{asn1,{undefined_type,Type}}}).",nl]). -nif_parameter() -> - ",nif". - gen_dispatcher([F1,F2|T],FuncName,Prefix,ExtraArg) -> emit([FuncName,"('",F1,"',Data) -> '",Prefix,F1,"'(Data",ExtraArg,")",";",nl]), gen_dispatcher([F2|T],FuncName,Prefix,ExtraArg); @@ -1393,23 +1392,19 @@ gen_record(_,_,_,NumRecords) -> % skip CLASS etc for now. gen_head(Erules,Mod,Hrl) -> Options = get(encoding_options), - {Rtmac,Rtmod} = case Erules of - per -> - emit({"%% Generated by the Erlang ASN.1 PER-" - "compiler version, utilizing bit-syntax:", - asn1ct:vsn(),nl}), - {"RT_PER","asn1rt_per_bin_rt2ct"}; - ber -> - emit({"%% Generated by the Erlang ASN.1 BER_V2-" - "compiler version, utilizing bit-syntax:", - asn1ct:vsn(),nl}), - {"RT_BER","asn1rt_ber_bin_v2"}; - uper -> - emit(["%% Generated by the Erlang ASN.1 UNALIGNED" - " PER-compiler version, utilizing" - " bit-syntax:", - asn1ct:vsn(),nl]), - {"RT_PER","asn1rt_uper_bin"} + case Erules of + per -> + emit(["%% Generated by the Erlang ASN.1 PER-" + "compiler version, utilizing bit-syntax:", + asn1ct:vsn(),nl]); + ber -> + emit(["%% Generated by the Erlang ASN.1 BER_V2-" + "compiler version, utilizing bit-syntax:", + asn1ct:vsn(),nl]); + uper -> + emit(["%% Generated by the Erlang ASN.1 UNALIGNED" + " PER-compiler version, utilizing bit-syntax:", + asn1ct:vsn(),nl]) end, emit({"%% Purpose: encoder and decoder to the types in mod ",Mod,nl,nl}), emit({"-module('",Mod,"').",nl}), @@ -1421,7 +1416,6 @@ gen_head(Erules,Mod,Hrl) -> _ -> emit({"-include(\"",Mod,".hrl\").",nl}) end, - emit(["-define('",Rtmac,"',",Rtmod,").",nl]), emit(["-asn1_info([{vsn,'",asn1ct:vsn(),"'},",nl, " {module,'",Mod,"'},",nl, " {options,",io_lib:format("~p",[Options]),"}]).",nl,nl]). diff --git a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl index 664dfc2086..0826384365 100644 --- a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl +++ b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl @@ -170,139 +170,84 @@ gen_encode_user(Erules,D) when is_record(D,typedef) -> end. gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) -> - -%%% Constraint is currently not used for BER (except for BitString) and therefore replaced -%%% with [] as a placeholder BitStringConstraint = D#type.constraint, - Constraint = [], asn1ct_name:new(enumval), - case D#type.def of + Type = case D#type.def of + 'OCTET STRING' -> restricted_string; + 'ObjectDescriptor'-> restricted_string; + 'NumericString' -> restricted_string; + 'TeletexString' -> restricted_string; + 'T61String' -> restricted_string; + 'VideotexString' -> restricted_string; + 'GraphicString' -> restricted_string; + 'VisibleString' -> restricted_string; + 'GeneralString' -> restricted_string; + 'PrintableString' -> restricted_string; + 'IA5String' -> restricted_string; + Other -> Other + end, + case Type of + restricted_string -> + call(encode_restricted_string, [Value,DoTag]); 'BOOLEAN' -> - emit_encode_func('boolean',Value,DoTag); + call(encode_boolean, [Value,DoTag]); 'INTEGER' -> - emit_encode_func('integer',Constraint,Value,DoTag); + call(encode_integer, [Value,DoTag]); {'INTEGER',NamedNumberList} -> - emit_encode_func('integer',Constraint,Value, - NamedNumberList,DoTag); + call(encode_integer, [Value,{asis,NamedNumberList}, DoTag]); {'ENUMERATED',NamedNumberList={_,_}} -> - emit(["case ",Value," of",nl]), emit_enc_enumerated_cases(NamedNumberList,DoTag); {'ENUMERATED',NamedNumberList} -> - emit(["case ",Value," of",nl]), emit_enc_enumerated_cases(NamedNumberList,DoTag); - 'REAL' -> - emit_encode_func('real',Constraint,Value,DoTag); - + emit([{call,ber,encode_tags, + [DoTag,{call,real_common,ber_encode_real,[Value]}]}]); {'BIT STRING',NamedNumberList} -> - emit_encode_func('bit_string',BitStringConstraint,Value, - NamedNumberList,DoTag); + call(encode_bit_string, + [{asis,BitStringConstraint},Value, + {asis,NamedNumberList},DoTag]); 'ANY' -> - emit_encode_func('open_type', Value,DoTag); + call(encode_open_type, [Value,DoTag]); 'NULL' -> - emit_encode_func('null',Value,DoTag); + call(encode_null, [Value,DoTag]); 'OBJECT IDENTIFIER' -> - emit_encode_func("object_identifier",Value,DoTag); + call(encode_object_identifier, [Value,DoTag]); 'RELATIVE-OID' -> - emit_encode_func("relative_oid",Value,DoTag); - 'ObjectDescriptor' -> - emit_encode_func('restricted_string',Constraint,Value, - ?T_ObjectDescriptor,DoTag); - 'OCTET STRING' -> - emit_encode_func('octet_string',Constraint,Value,DoTag); - 'NumericString' -> - emit_encode_func('restricted_string',Constraint,Value, - ?T_NumericString,DoTag); - TString when TString == 'TeletexString'; - TString == 'T61String' -> - emit_encode_func('restricted_string',Constraint,Value, - ?T_TeletexString,DoTag); - 'VideotexString' -> - emit_encode_func('restricted_string',Constraint,Value, - ?T_VideotexString,DoTag); - 'GraphicString' -> - emit_encode_func('restricted_string',Constraint,Value, - ?T_GraphicString,DoTag); - 'VisibleString' -> - emit_encode_func('restricted_string',Constraint,Value, - ?T_VisibleString,DoTag); - 'GeneralString' -> - emit_encode_func('restricted_string',Constraint,Value, - ?T_GeneralString,DoTag); - 'PrintableString' -> - emit_encode_func('restricted_string',Constraint,Value, - ?T_PrintableString,DoTag); - 'IA5String' -> - emit_encode_func('restricted_string',Constraint,Value, - ?T_IA5String,DoTag); + call(encode_relative_oid, [Value,DoTag]); 'UniversalString' -> - emit_encode_func('universal_string',Constraint,Value,DoTag); + call(encode_universal_string, [Value,DoTag]); 'UTF8String' -> - emit_encode_func('UTF8_string',Constraint,Value,DoTag); + call(encode_UTF8_string, [Value,DoTag]); 'BMPString' -> - emit_encode_func('BMP_string',Constraint,Value,DoTag); + call(encode_BMP_string, [Value,DoTag]); 'UTCTime' -> - emit_encode_func('utc_time',Constraint,Value,DoTag); + call(encode_utc_time, [Value,DoTag]); 'GeneralizedTime' -> - emit_encode_func('generalized_time',Constraint,Value,DoTag); + call(encode_generalized_time, [Value,DoTag]); 'ASN1_OPEN_TYPE' -> - emit_encode_func('open_type', Value,DoTag); + call(encode_open_type, [Value,DoTag]); #'ObjectClassFieldType'{} -> case asn1ct_gen:get_inner(D#type.def) of {fixedtypevaluefield,_,InnerType} -> gen_encode_prim(Erules,InnerType,DoTag,Value); 'ASN1_OPEN_TYPE' -> - emit_encode_func('open_type', Value,DoTag); - XX -> - exit({'can not encode' ,XX}) - end; - XX -> - exit({'can not encode' ,XX}) + call(encode_open_type, [Value,DoTag]) + end end. - -emit_encode_func(Name,Value,Tags) when is_atom(Name) -> - emit_encode_func(atom_to_list(Name),Value,Tags); -emit_encode_func(Name,Value,Tags) -> - Fname = "?RT_BER:encode_" ++ Name, - emit([Fname,"(",Value,", ",Tags,")"]). - -emit_encode_func(Name,Constraint,Value,Tags) when is_atom(Name) -> - emit_encode_func(atom_to_list(Name),Constraint,Value,Tags); -emit_encode_func(Name,Constraint,Value,Tags) -> - Fname = "?RT_BER:encode_" ++ Name, - emit([Fname,"(",{asis,Constraint},", ",Value,", ",Tags,")"]). - -emit_encode_func(Name,Constraint,Value,Asis,Tags) when is_atom(Name) -> - emit_encode_func(atom_to_list(Name),Constraint,Value,Asis,Tags); -emit_encode_func(Name,Constraint,Value,Asis,Tags) -> - Fname = "?RT_BER:encode_" ++ Name, - emit([Fname,"(",{asis,Constraint},", ",Value, - ", ",{asis,Asis}, - ", ",Tags,")"]). - emit_enc_enumerated_cases({L1,L2}, Tags) -> emit_enc_enumerated_cases(L1++L2, Tags, ext); emit_enc_enumerated_cases(L, Tags) -> emit_enc_enumerated_cases(L, Tags, noext). -emit_enc_enumerated_cases([{EnumName,EnumVal},H2|T], Tags, Ext) -> - emit([{asis,EnumName}," -> ?RT_BER:encode_enumerated(",EnumVal,",",Tags,");",nl]), -%% emit(["'",{asis,EnumName},"' -> ?RT_BER:encode_enumerated(",EnumVal,",",Tags,");",nl]), - emit_enc_enumerated_cases([H2|T], Tags, Ext); -emit_enc_enumerated_cases([{EnumName,EnumVal}], Tags, Ext) -> - emit([{asis,EnumName}," -> ?RT_BER:encode_enumerated(",EnumVal,",",Tags,")"]), -%% emit(["'",{asis,EnumName},"' -> ?RT_BER:encode_enumerated(",EnumVal,",",Tags,")"]), - case Ext of - noext -> emit([";",nl]); - ext -> - emit([";",nl]) -%% emit([";",nl,"{asn1_enum,",{curr,enumval},"} -> ", -%% "?RT_BER:encode_enumerated(",{curr,enumval},",",Tags,");",nl]), -%% asn1ct_name:new(enumval) - end, +emit_enc_enumerated_cases([{EnumName,EnumVal}|T], Tags, Ext) -> + emit([{asis,EnumName}," -> ", + {call,ber,encode_enumerated,[EnumVal,Tags]},";",nl]), + emit_enc_enumerated_cases(T, Tags, Ext); +emit_enc_enumerated_cases([], _Tags, _Ext) -> + %% FIXME: Should extension be handled? emit([{curr,enumval}," -> exit({error,{asn1, {enumerated_not_in_range,",{curr, enumval},"}}})"]), emit([nl,"end"]). @@ -365,9 +310,10 @@ gen_decode_selected(Erules,Type,FuncName) -> {value,{_,P}} -> P; false -> exit({error,{internal,no_pattern_saved}}) end, - emit([" case ?RT_BER:decode_selective(",{asis,Pattern},",Bin) of",nl, + emit([" case ",{call,ber,decode_selective, + [{asis,Pattern},"Bin"]}," of",nl, " {ok,Bin2} when is_binary(Bin2) ->",nl, - " {Tlv,_} = ?RT_BER:decode(Bin2",asn1ct_gen:nif_parameter(),"),",nl]), + " {Tlv,_} = ", {call,ber,ber_decode_nif,["Bin2"]},com,nl]), emit("{ok,"), gen_decode_selected_type(Erules,Type), emit(["};",nl," Err -> exit({error,{selective_decode,Err}})",nl, @@ -555,141 +501,154 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) -> % DoLength = case NewTypeName of 'BOOLEAN'-> - emit({"?RT_BER:decode_boolean(",BytesVar,","}), - add_func({decode_boolean,2}); + emit(["decode_boolean(",BytesVar,","]), + need(decode_boolean, 2); 'INTEGER' -> - emit({"?RT_BER:decode_integer(",BytesVar,",", - {asis,int_constr(SingleValue,ValueRange)},","}), - add_func({decode_integer,3}); + emit(["decode_integer(",BytesVar,",", + {asis,int_constr(SingleValue,ValueRange)},","]), + need(decode_integer, 3); {'INTEGER',NamedNumberList} -> - emit({"?RT_BER:decode_integer(",BytesVar,",", + emit(["decode_integer(",BytesVar,",", {asis,int_constr(SingleValue,ValueRange)},",", - {asis,NamedNumberList},","}), - add_func({decode_integer,4}); + {asis,NamedNumberList},","]), + need(decode_integer, 4); {'ENUMERATED',NamedNumberList} -> - emit({"?RT_BER:decode_enumerated(",BytesVar,",", - {asis,Constraint},",", - {asis,NamedNumberList},","}), - add_func({decode_enumerated,4}); + emit(["decode_enumerated(",BytesVar,",", + {asis,NamedNumberList},","]), + need(decode_enumerated, 3); 'REAL' -> - emit({"?RT_BER:decode_real(",BytesVar,","}), - add_func({decode_real,3}); + ok; {'BIT STRING',NamedNumberList} -> case get(compact_bit_string) of true -> - emit({"?RT_BER:decode_compact_bit_string(", + emit(["decode_compact_bit_string(", BytesVar,",",{asis,Constraint},",", - {asis,NamedNumberList},","}), - add_func({decode_compact_bit_string,4}); + {asis,NamedNumberList},","]), + need(decode_compact_bit_string, 4); _ -> - emit({"?RT_BER:decode_bit_string(",BytesVar,",", + emit(["decode_bit_string(",BytesVar,",", {asis,Constraint},",", - {asis,NamedNumberList},","}), - add_func({decode_bit_string,4}) + {asis,NamedNumberList},","]), + need(decode_bit_string, 4) end; 'NULL' -> - emit({"?RT_BER:decode_null(",BytesVar,","}), - add_func({decode_null,2}); + emit(["decode_null(",BytesVar,","]), + need(decode_null, 2); 'OBJECT IDENTIFIER' -> - emit({"?RT_BER:decode_object_identifier(",BytesVar,","}), - add_func({decode_object_identifier,2}); + emit(["decode_object_identifier(",BytesVar,","]), + need(decode_object_identifier, 2); 'RELATIVE-OID' -> - emit({"?RT_BER:decode_relative_oid(",BytesVar,","}), - add_func({decode_relative_oid,2}); + emit(["decode_relative_oid(",BytesVar,","]), + need(decode_relative_oid, 2); 'ObjectDescriptor' -> - emit({"?RT_BER:decode_restricted_string(", - BytesVar,",",{asis,Constraint},",",{asis,?T_ObjectDescriptor},","}), - add_func({decode_restricted_string,4}); + emit(["decode_restricted_string(", + BytesVar,",",{asis,Constraint},",", + {asis,?T_ObjectDescriptor},","]), + need(decode_restricted_string, 4); 'OCTET STRING' -> - emit({"?RT_BER:decode_octet_string",AsBin,"(",BytesVar,",",{asis,Constraint},","}), - add_func({decode_octet_string,3}); + emit(["decode_octet_string",AsBin,"(",BytesVar,",", + {asis,Constraint},","]), + need(decode_octet_string, 3); 'NumericString' -> - emit({"?RT_BER:decode_restricted_string",AsBin,"(", - BytesVar,",",{asis,Constraint},",",{asis,?T_NumericString},","}), - add_func({decode_restricted_string,4}); + emit(["decode_restricted_string",AsBin,"(", + BytesVar,",",{asis,Constraint},",", + {asis,?T_NumericString},","]), + need(decode_restricted_string, 4); TString when TString == 'TeletexString'; TString == 'T61String' -> - emit({"?RT_BER:decode_restricted_string",AsBin,"(", - BytesVar,",",{asis,Constraint},",",{asis,?T_TeletexString},","}), - add_func({decode_restricted_string,4}); + emit(["decode_restricted_string",AsBin,"(", + BytesVar,",",{asis,Constraint},",", + {asis,?T_TeletexString},","]), + need(decode_restricted_string, 4); 'VideotexString' -> - emit({"?RT_BER:decode_restricted_string",AsBin,"(", - BytesVar,",",{asis,Constraint},",",{asis,?T_VideotexString},","}), - add_func({decode_restricted_string,4}); + emit(["decode_restricted_string",AsBin,"(", + BytesVar,",",{asis,Constraint},",", + {asis,?T_VideotexString},","]), + need(decode_restricted_string, 4); 'GraphicString' -> - emit({"?RT_BER:decode_restricted_string",AsBin,"(", - BytesVar,",",{asis,Constraint},",",{asis,?T_GraphicString},","}), - add_func({decode_restricted_string,4}); + emit(["decode_restricted_string",AsBin,"(", + BytesVar,",",{asis,Constraint},",", + {asis,?T_GraphicString},","]), + need(decode_restricted_string, 4); 'VisibleString' -> - emit({"?RT_BER:decode_restricted_string",AsBin,"(", - BytesVar,",",{asis,Constraint},",",{asis,?T_VisibleString},","}), - add_func({decode_restricted_string,4}); + emit(["decode_restricted_string",AsBin,"(", + BytesVar,",",{asis,Constraint},",", + {asis,?T_VisibleString},","]), + need(decode_restricted_string, 4); 'GeneralString' -> - emit({"?RT_BER:decode_restricted_string",AsBin,"(", - BytesVar,",",{asis,Constraint},",",{asis,?T_GeneralString},","}), - add_func({decode_restricted_string,4}); + emit(["decode_restricted_string",AsBin,"(", + BytesVar,",",{asis,Constraint},",", + {asis,?T_GeneralString},","]), + need(decode_restricted_string, 4); 'PrintableString' -> - emit({"?RT_BER:decode_restricted_string",AsBin,"(", - BytesVar,",",{asis,Constraint},",",{asis,?T_PrintableString},","}), - add_func({decode_restricted_string,4}); + emit(["decode_restricted_string",AsBin,"(", + BytesVar,",",{asis,Constraint},",", + {asis,?T_PrintableString},","]), + need(decode_restricted_string, 4); 'IA5String' -> - emit({"?RT_BER:decode_restricted_string",AsBin,"(", - BytesVar,",",{asis,Constraint},",",{asis,?T_IA5String},","}), - add_func({decode_restricted_string,4}) ; + emit(["decode_restricted_string",AsBin,"(", + BytesVar,",",{asis,Constraint},",", + {asis,?T_IA5String},","]), + need(decode_restricted_string, 4); 'UniversalString' -> - emit({"?RT_BER:decode_universal_string",AsBin,"(", - BytesVar,",",{asis,Constraint},","}), - add_func({decode_universal_string,3}); + emit(["decode_universal_string",AsBin,"(", + BytesVar,",",{asis,Constraint},","]), + need(decode_universal_string, 3); 'UTF8String' -> - emit({"?RT_BER:decode_UTF8_string",AsBin,"(", - BytesVar,","}), - add_func({decode_UTF8_string,2}); + emit(["decode_UTF8_string",AsBin,"(", + BytesVar,","]), + need(decode_UTF8_string, 2); 'BMPString' -> - emit({"?RT_BER:decode_BMP_string",AsBin,"(", - BytesVar,",",{asis,Constraint},","}), - add_func({decode_BMP_string,3}); + emit(["decode_BMP_string",AsBin,"(", + BytesVar,",",{asis,Constraint},","]), + need(decode_BMP_string, 3); 'UTCTime' -> - emit({"?RT_BER:decode_utc_time",AsBin,"(", - BytesVar,",",{asis,Constraint},","}), - add_func({decode_utc_time,3}); + emit(["decode_utc_time",AsBin,"(", + BytesVar,",",{asis,Constraint},","]), + need(decode_utc_time, 3); 'GeneralizedTime' -> - emit({"?RT_BER:decode_generalized_time",AsBin,"(", - BytesVar,",",{asis,Constraint},","}), - add_func({decode_generalized_time,3}); + emit(["decode_generalized_time",AsBin,"(", + BytesVar,",",{asis,Constraint},","]), + need(decode_generalized_time, 3); 'ASN1_OPEN_TYPE' -> - emit(["?RT_BER:decode_open_type_as_binary(", + emit(["decode_open_type_as_binary(", BytesVar,","]), - add_func({decode_open_type_as_binary,3}); + need(decode_open_type_as_binary, 2); #'ObjectClassFieldType'{} -> case asn1ct_gen:get_inner(Att#type.def) of {fixedtypevaluefield,_,InnerType} -> gen_dec_prim(Erules,InnerType,BytesVar,DoTag,TagIn,Form,OptOrMand); 'ASN1_OPEN_TYPE' -> - emit(["?RT_BER:decode_open_type_as_binary(", + emit(["decode_open_type_as_binary(", BytesVar,","]), - add_func({decode_open_type_as_binary,3}); + need(decode_open_type_as_binary, 2); Other -> - exit({'can not decode' ,Other}) + exit({'cannot decode',Other}) end; Other -> - exit({'can not decode' ,Other}) + exit({'cannot decode',Other}) end, - case {DoTag,NewTypeName} of - {_,#'ObjectClassFieldType'{}} -> + TagStr = case DoTag of + {string,Tag1} -> Tag1; + _ when is_list(DoTag) -> {asis,DoTag} + end, + case NewTypeName of + 'REAL' -> + asn1ct_name:new(tmpbuf), + emit(["begin",nl, + {curr,tmpbuf}," = ", + {call,ber,match_tags,[BytesVar,TagStr]},com,nl, + {call,real_common,decode_real,[{curr,tmpbuf}]},nl, + "end",nl]); + #'ObjectClassFieldType'{} -> case asn1ct_gen:get_inner(Att#type.def) of 'ASN1_OPEN_TYPE' -> - emit([{asis,DoTag},asn1ct_gen:nif_parameter(),")"]); + emit([TagStr,")"]); _ -> ok end; - {{string,TagStr},'ASN1_OPEN_TYPE'} -> - emit([TagStr,asn1ct_gen:nif_parameter(),")"]); - {_,'ASN1_OPEN_TYPE'} -> - emit([{asis,DoTag},asn1ct_gen:nif_parameter(),")"]); - {{string,TagStr},_} -> - emit([TagStr,")"]); - _ when is_list(DoTag) -> - emit([{asis,DoTag},")"]) + _ -> + emit([TagStr,")"]) end. @@ -1015,7 +974,7 @@ emit_tlv_format_function() -> end. emit_tlv_format_function1() -> emit(["tlv_format(Bytes) when is_binary(Bytes) ->",nl, - " {Tlv,_}=?RT_BER:decode(Bytes",asn1ct_gen:nif_parameter(),"),",nl, + " {Tlv,_} = ",{call,ber,ber_decode_nif,["Bytes"]},com,nl, " Tlv;",nl, "tlv_format(Bytes) ->",nl, " Bytes.",nl]). @@ -1449,38 +1408,22 @@ gen_objset_dec(_,ObjSetName,UniqueName,[{ObjName,Val,Fields}], emit_default_getdec(ObjSetName,UniqueName), emit([".",nl,nl]), ok; -gen_objset_dec(Erules,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName, +gen_objset_dec(_,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName, _ClFields,_NthObj) -> emit(["'getdec_",ObjSetName,"'(_, _) ->",nl]), emit([indent(2),"fun(_,Bytes, _RestPrimFieldName) ->",nl]), - case Erules of - ber -> - emit([indent(4),"case Bytes of",nl, - indent(6),"Bin when is_binary(Bin) -> ",nl, - indent(8),"Bin;",nl, - indent(6),"_ ->",nl, - indent(8),"?RT_BER:encode(Bytes",driver_parameter(),")",nl, - indent(4),"end",nl]); - _ -> - emit([indent(6),"Len = case Bytes of",nl,indent(9), - "Bin when is_binary(Bin) -> size(Bin);",nl,indent(9), - "_ -> length(Bytes)",nl,indent(6),"end,"]), - emit([indent(4),"{Bytes,[],Len}",nl]) - end, + emit([indent(4),"case Bytes of",nl, + indent(6),"Bin when is_binary(Bin) -> ",nl, + indent(8),"Bin;",nl, + indent(6),"_ ->",nl, + indent(8),{call,ber,ber_encode,["Bytes"]},nl, + indent(4),"end",nl]), emit([indent(2),"end.",nl,nl]), ok; gen_objset_dec(_,_,_,[],_,_,_) -> ok. -driver_parameter() -> - Options = get(encoding_options), - case {lists:member(driver,Options),lists:member(nif,Options)} of - {true,_} -> ",nif"; - {_,true} -> ",nif"; - _ -> ",erlang" - end. - emit_default_getdec(ObjSetName,UniqueName) -> emit(["'getdec_",ObjSetName,"'(",{asis,UniqueName},", ErrV) ->",nl]), emit([indent(2), "fun(C,V,_) -> exit({{component,C},{value,V},{unique_name_and_value,",{asis,UniqueName},", ErrV}}) end"]). @@ -1771,9 +1714,6 @@ mk_object_val(0, Ack, Len) -> mk_object_val(Val, Ack, Len) -> mk_object_val(Val bsr 7, [((Val band 127) bor 128) | Ack], Len + 1). -add_func(F={_Func,_Arity}) -> - asn1ct_table:insert(asn1_functab, {F}). - %% For BER the ExtensionAdditionGroup notation has no impact on the encoding/decoding %% and therefore we only filter away the ExtensionAdditionGroup start and end markers extaddgroup2sequence(ExtList) when is_list(ExtList) -> @@ -1785,4 +1725,8 @@ extaddgroup2sequence(ExtList) when is_list(ExtList) -> true end, ExtList). +call(F, Args) -> + asn1ct_func:call(ber, F, Args). +need(F, Arity) -> + asn1ct_func:need({ber,F,Arity}). diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl index af19edb908..08b65d466d 100644 --- a/lib/asn1/src/asn1ct_gen_per.erl +++ b/lib/asn1/src/asn1ct_gen_per.erl @@ -35,6 +35,7 @@ -export([extaddgroup2sequence/1]). -import(asn1ct_gen, [emit/1,demit/1]). +-import(asn1ct_func, [call/3]). %% pgen(Erules, Module, TypeOrVal) %% Generate Erlang module (.erl) and (.hrl) file corresponding to an ASN.1 module @@ -134,14 +135,13 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) -> asn1ct_name:new(enumval), case D#type.def of 'INTEGER' -> - emit({"?RT_PER:encode_integer(", %fel - {asis,asn1ct_imm:effective_constraint(integer,Constraint)}, - ",",Value,")"}); + Args = [{asis,asn1ct_imm:effective_constraint(integer,Constraint)}, + Value], + call(Erules, encode_integer, Args); {'INTEGER',NamedNumberList} -> - emit({"?RT_PER:encode_integer(", - {asis,asn1ct_imm:effective_constraint(integer,Constraint)}, - ",",Value,",", - {asis,NamedNumberList},")"}); + Args = [{asis,asn1ct_imm:effective_constraint(integer,Constraint)}, + Value,{asis,NamedNumberList}], + call(Erules, encode_integer, Args); {'ENUMERATED',{Nlist1,Nlist2}} -> NewList = lists:concat([[{0,X}||{X,_} <- Nlist1],['EXT_MARK'],[{1,X}||{X,_} <- Nlist2]]), NewC = [{'ValueRange',{0,length(Nlist1)-1}}], @@ -153,7 +153,6 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) -> {curr,enumval},";_->", Value," end) of",nl]), asn1ct_name:new(enumval) end, -%% emit_enc_enumerated_cases(Erules,NewC, NewList++[{asn1_enum,length(Nlist1)-1}], 0); emit_enc_enumerated_cases(Erules,NewC, NewList, 0); {'ENUMERATED',NamedNumberList} -> NewList = [X||{X,_} <- NamedNumberList], @@ -168,73 +167,68 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) -> emit_enc_enumerated_cases(Erules,NewC, NewList, 0); 'REAL' -> - emit({"?RT_PER:encode_real(",Value,")"}); + emit_enc_real(Erules, Value); {'BIT STRING',NamedNumberList} -> - emit({"?RT_PER:encode_bit_string(", - {asis,Constraint},",",Value,",", - {asis,NamedNumberList},")"}); + call(Erules, encode_bit_string, + [{asis,Constraint},Value, + {asis,NamedNumberList}]); 'NULL' -> emit("[]"); 'OBJECT IDENTIFIER' -> - emit({"?RT_PER:encode_object_identifier(",Value,")"}); + call(Erules, encode_object_identifier, [Value]); 'RELATIVE-OID' -> - emit({"?RT_PER:encode_relative_oid(",Value,")"}); + call(Erules, encode_relative_oid, [Value]); 'ObjectDescriptor' -> - emit({"?RT_PER:encode_ObjectDescriptor(",{asis,Constraint}, - ",",Value,")"}); + call(Erules, encode_ObjectDescriptor, + [{asis,Constraint},Value]); 'BOOLEAN' -> - emit({"?RT_PER:encode_boolean(",Value,")"}); + call(Erules, encode_boolean, [Value]); 'OCTET STRING' -> - emit({"?RT_PER:encode_octet_string(",{asis,Constraint},",",Value,")"}); + call(Erules, encode_octet_string, [{asis,Constraint},Value]); 'NumericString' -> - emit({"?RT_PER:encode_NumericString(",{asis,Constraint},",",Value,")"}); + call(Erules, encode_NumericString, [{asis,Constraint},Value]); TString when TString == 'TeletexString'; TString == 'T61String' -> - emit({"?RT_PER:encode_TeletexString(",{asis,Constraint},",",Value,")"}); + call(Erules, encode_TeletexString, [{asis,Constraint},Value]); 'VideotexString' -> - emit({"?RT_PER:encode_VideotexString(",{asis,Constraint},",",Value,")"}); + call(Erules, encode_VideotexString, [{asis,Constraint},Value]); 'UTCTime' -> - emit({"?RT_PER:encode_VisibleString(",{asis,Constraint},",",Value,")"}); + call(Erules, encode_VisibleString, [{asis,Constraint},Value]); 'GeneralizedTime' -> - emit({"?RT_PER:encode_VisibleString(",{asis,Constraint},",",Value,")"}); + call(Erules, encode_VisibleString, [{asis,Constraint},Value]); 'GraphicString' -> - emit({"?RT_PER:encode_GraphicString(",{asis,Constraint},",",Value,")"}); + call(Erules, encode_GraphicString, [{asis,Constraint},Value]); 'VisibleString' -> - emit({"?RT_PER:encode_VisibleString(",{asis,Constraint},",",Value,")"}); + call(Erules, encode_VisibleString, [{asis,Constraint},Value]); 'GeneralString' -> - emit({"?RT_PER:encode_GeneralString(",{asis,Constraint}, - ",",Value,")"}); + call(Erules, encode_GeneralString, [{asis,Constraint},Value]); 'PrintableString' -> - emit({"?RT_PER:encode_PrintableString(",{asis,Constraint}, - ",",Value,")"}); + call(Erules, encode_PrintableString, [{asis,Constraint},Value]); 'IA5String' -> - emit({"?RT_PER:encode_IA5String(",{asis,Constraint}, - ",",Value,")"}); + call(Erules, encode_IA5String, [{asis,Constraint},Value]); 'BMPString' -> - emit({"?RT_PER:encode_BMPString(",{asis,Constraint}, - ",",Value,")"}); + call(Erules, encode_BMPString, [{asis,Constraint},Value]); 'UniversalString' -> - emit({"?RT_PER:encode_UniversalString(",{asis,Constraint}, - ",",Value,")"}); + call(Erules, encode_UniversalString, [{asis,Constraint},Value]); 'UTF8String' -> - emit({"?RT_PER:encode_UTF8String(",Value,")"}); + call(Erules, encode_UTF8String, [Value]); 'ANY' -> - emit(["?RT_PER:encode_open_type(", {asis,Constraint}, ",", - Value, ")"]); + call(Erules, encode_open_type, [Value]); 'ASN1_OPEN_TYPE' -> NewValue = case Constraint of [#'Externaltypereference'{type=Tname}] -> - io_lib:format( - "?RT_PER:complete(enc_~s(~s))",[Tname,Value]); + asn1ct_func:need({Erules,complete,1}), + io_lib:format( + "complete(enc_~s(~s))",[Tname,Value]); [#type{def=#'Externaltypereference'{type=Tname}}] -> + asn1ct_func:need({Erules,complete,1}), io_lib:format( - "?RT_PER:complete(enc_~s(~s))", + "complete(enc_~s(~s))", [Tname,Value]); _ -> Value end, - emit(["?RT_PER:encode_open_type(", {asis,Constraint}, ",", - NewValue, ")"]); + call(Erules, encode_open_type, [NewValue]); #'ObjectClassFieldType'{} -> case asn1ct_gen:get_inner(D#type.def) of {fixedtypevaluefield,_,InnerType} -> @@ -246,6 +240,15 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) -> exit({asn1_error,nyi,XX}) end. +emit_enc_real(Erules, Real) -> + asn1ct_name:new(tmpval), + asn1ct_name:new(tmplen), + emit(["begin",nl, + "{",{curr,tmpval},com,{curr,tmplen},"} = ", + {call,real_common,encode_real,[Real]},com,nl, + "[",{call,Erules,encode_length,[{curr,tmplen}]},",", + {curr,tmpval},"]",nl, + "end"]). emit_enc_enumerated_cases(Erule,C, [H], Count) -> emit_enc_enumerated_case(Erule,C, H, Count), @@ -264,27 +267,17 @@ emit_enc_enumerated_cases(Erule, C, [H1,H2|T], Count) -> emit_enc_enumerated_cases(Erule, C, [H2|T], Count+1). - -emit_enc_enumerated_case(uper,_C, {asn1_enum,High}, _) -> - emit([ - "{asn1_enum,EnumV} when is_integer(EnumV), EnumV > ",High," -> ", - "[<<1:1>>,?RT_PER:encode_small_number(EnumV)]"]); -emit_enc_enumerated_case(_Per,_C, {asn1_enum,High}, _) -> - emit([ - "{asn1_enum,EnumV} when is_integer(EnumV), EnumV > ",High," -> ", - "[{bit,1},?RT_PER:encode_small_number(EnumV)]"]); emit_enc_enumerated_case(_Erule, _C, 'EXT_MARK', _Count) -> true; -emit_enc_enumerated_case(uper,_C, {1,EnumName}, Count) -> - emit(["'",EnumName,"' -> [<<1:1>>,?RT_PER:encode_small_number(",Count,")]"]); -emit_enc_enumerated_case(_Per,_C, {1,EnumName}, Count) -> - emit(["'",EnumName,"' -> [{bit,1},?RT_PER:encode_small_number(",Count,")]"]); -emit_enc_enumerated_case(uper,C, {0,EnumName}, Count) -> - emit(["'",EnumName,"' -> [<<0:1>>,?RT_PER:encode_integer(",{asis,C},", ",Count,")]"]); -emit_enc_enumerated_case(_Per,C, {0,EnumName}, Count) -> - emit(["'",EnumName,"' -> [{bit,0},?RT_PER:encode_integer(",{asis,C},", ",Count,")]"]); -emit_enc_enumerated_case(_Erule, C, EnumName, Count) -> - emit(["'",EnumName,"' -> ?RT_PER:encode_integer(",{asis,C},", ",Count,")"]). +emit_enc_enumerated_case(uper=Erules,_C, {1,EnumName}, Count) -> + emit(["'",EnumName,"' -> [<<1:1>>,", + {call,Erules,encode_small_number,[Count]},"]"]); +emit_enc_enumerated_case(uper=Erules, C, {0,EnumName}, Count) -> + emit(["'",EnumName,"' -> [<<0:1>>,", + {call,Erules,encode_integer,[{asis,C},Count]},"]"]); +emit_enc_enumerated_case(Erules, C, EnumName, Count) -> + emit(["'",EnumName,"' -> ", + {call,Erules,encode_integer,[{asis,C},Count]}]). get_constraint([{Key,V}], Key) -> V; @@ -446,7 +439,7 @@ gen_encode_field_call(ObjName,FieldName,Type) -> Def = Type#typedef.typespec, case Type#typedef.name of {primitive,bif} -> - gen_encode_prim(per,Def,"false", + gen_encode_prim(uper,Def,"false", "Val"), []; {constructed,bif} -> @@ -584,7 +577,7 @@ gen_decode_field_call(ObjName,FieldName,Bytes,Type) -> Def = Type#typedef.typespec, case Type#typedef.name of {primitive,bif} -> - gen_dec_prim(per,Def,Bytes), + gen_dec_prim(uper, Def, Bytes), []; {constructed,bif} -> emit({" 'dec_",ObjName,'_',FieldName, @@ -845,7 +838,7 @@ emit_inner_of_fun(TDef=#typedef{name={ExtMod,Name},typespec=Type}, case {ExtMod,Name} of {primitive,bif} -> emit(indent(12)), - gen_encode_prim(per,Type,dotag,"Val"), + gen_encode_prim(uper,Type,dotag,"Val"), {[],0}; {constructed,bif} -> emit([indent(12),"'enc_", @@ -988,7 +981,7 @@ emit_inner_of_decfun(#typedef{name={ExtName,Name},typespec=Type}, case {ExtName,Name} of {primitive,bif} -> emit(indent(12)), - gen_dec_prim(per,Type,"Val"), + gen_dec_prim(uper, Type, "Val"), 0; {constructed,bif} -> emit({indent(12),"'dec_", @@ -1006,7 +999,7 @@ emit_inner_of_decfun(Type,_) when is_record(Type,type) -> case Type#type.def of Def when is_atom(Def) -> emit({indent(9),Def," ->",nl,indent(12)}), - gen_dec_prim(erules,Type,"Val"); + gen_dec_prim(uper, Type, "Val"); TRef when is_record(TRef,typereference) -> T = TRef#typereference.val, emit({indent(9),T," ->",nl,indent(12),"'dec_",T,"'(Val)"}); @@ -1120,6 +1113,8 @@ gen_dec_imm_1('OCTET STRING', Constraint, Aligned) -> SzConstr = get_constraint(Constraint, 'SizeConstraint'), Imm = asn1ct_imm:per_dec_octet_string(SzConstr, Aligned), {convert,binary_to_list,Imm}; +gen_dec_imm_1('REAL', _Constraint, Aligned) -> + asn1ct_imm:per_dec_real(Aligned); gen_dec_imm_1(_, _, _) -> no. gen_dec_prim(Erule, Type, BytesVar) -> @@ -1134,68 +1129,55 @@ gen_dec_prim_1(Erule, #type{def=Typename,constraint=Constraint}=Att, BytesVar) -> case Typename of - 'REAL' -> - emit({"?RT_PER:decode_real(",BytesVar,")"}); - {'BIT STRING',NamedNumberList} -> - case get(compact_bit_string) of - true -> - emit({"?RT_PER:decode_compact_bit_string(", - BytesVar,",",{asis,Constraint},",", - {asis,NamedNumberList},")"}); - _ -> - emit({"?RT_PER:decode_bit_string(",BytesVar,",", - {asis,Constraint},",", - {asis,NamedNumberList},")"}) - end; + Func = case get(compact_bit_string) of + true -> decode_compact_bit_string; + _ -> decode_bit_string + end, + call(Erule, Func, + [BytesVar,{asis,Constraint}, + {asis,NamedNumberList}]); 'NULL' -> emit({"{'NULL',",BytesVar,"}"}); 'OBJECT IDENTIFIER' -> - emit({"?RT_PER:decode_object_identifier(", - BytesVar,")"}); + call(Erule, decode_object_identifier, [BytesVar]); 'RELATIVE-OID' -> - emit({"?RT_PER:decode_relative_oid(", - BytesVar,")"}); + call(Erule, decode_relative_oid, [BytesVar]); 'ObjectDescriptor' -> - emit({"?RT_PER:decode_ObjectDescriptor(", - BytesVar,")"}); + call(Erule, decode_ObjectDescriptor, [BytesVar]); 'NumericString' -> - emit({"?RT_PER:decode_NumericString(",BytesVar,",", - {asis,Constraint},")"}); + call(Erule, decode_NumericString, + [BytesVar,{asis,Constraint}]); TString when TString == 'TeletexString'; TString == 'T61String' -> - emit({"?RT_PER:decode_TeletexString(",BytesVar,",", - {asis,Constraint},")"}); + call(Erule, decode_TeletexString, + [BytesVar,{asis,Constraint}]); 'VideotexString' -> - emit({"?RT_PER:decode_VideotexString(",BytesVar,",", - {asis,Constraint},")"}); + call(Erule, decode_VideotexString, + [BytesVar,{asis,Constraint}]); 'UTCTime' -> - emit({"?RT_PER:decode_VisibleString(",BytesVar,",", - {asis,Constraint},")"}); + call(Erule, decode_VisibleString, [BytesVar,{asis,Constraint}]); 'GeneralizedTime' -> - emit({"?RT_PER:decode_VisibleString(",BytesVar,",", - {asis,Constraint},")"}); + call(Erule, decode_VisibleString, [BytesVar,{asis,Constraint}]); 'GraphicString' -> - emit({"?RT_PER:decode_GraphicString(",BytesVar,",", - {asis,Constraint},")"}); + call(Erule, decode_GraphicString,[BytesVar,{asis,Constraint}]); 'VisibleString' -> - emit({"?RT_PER:decode_VisibleString(",BytesVar,",", - {asis,Constraint},")"}); + call(Erule, decode_VisibleString, [BytesVar,{asis,Constraint}]); 'GeneralString' -> - emit({"?RT_PER:decode_GeneralString(",BytesVar,",", - {asis,Constraint},")"}); + call(Erule, decode_GeneralString, [BytesVar,{asis,Constraint}]); 'PrintableString' -> - emit({"?RT_PER:decode_PrintableString(",BytesVar,",",{asis,Constraint},")"}); + call(Erule, decode_PrintableString, + [BytesVar,{asis,Constraint}]); 'IA5String' -> - emit({"?RT_PER:decode_IA5String(",BytesVar,",",{asis,Constraint},")"}); + call(Erule, decode_IA5String, [BytesVar,{asis,Constraint}]); 'BMPString' -> - emit({"?RT_PER:decode_BMPString(",BytesVar,",", - {asis,Constraint},")"}); + call(Erule, decode_BMPString, + [BytesVar,{asis,Constraint}]); 'UniversalString' -> - emit({"?RT_PER:decode_UniversalString(",BytesVar, - ",",{asis,Constraint},")"}); + call(Erule, decode_UniversalString, + [BytesVar,{asis,Constraint}]); 'UTF8String' -> - emit({"?RT_PER:decode_UTF8String(",BytesVar,")"}); + call(Erule, decode_UTF8String, [BytesVar]); #'ObjectClassFieldType'{} -> case asn1ct_gen:get_inner(Typename) of {fixedtypevaluefield,_,InnerType} -> diff --git a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl index 4f4563833f..b1ecfa135d 100644 --- a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl +++ b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl @@ -34,6 +34,7 @@ -import(asn1ct_gen, [emit/1,demit/1]). -import(asn1ct_gen_per, [is_already_generated/2,more_genfields/1, get_class_fields/1,get_object_field/2]). +-import(asn1ct_func, [call/3]). %% pgen(Erules, Module, TypeOrVal) %% Generate Erlang module (.erl) and (.hrl) file corresponding to an ASN.1 module @@ -152,26 +153,27 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) -> emit_enc_integer(Erules,NewC,NewVal); 'REAL' -> - emit({"?RT_PER:encode_real(",Value,")"}); + emit_enc_real(Erules, Value); {'BIT STRING',NamedNumberList} -> EffectiveC = effective_constraint(bitstring,Constraint), case EffectiveC of - 0 -> emit({"[]"}); + 0 -> + emit({"[]"}); _ -> - emit({"?RT_PER:encode_bit_string(", - {asis,EffectiveC},",",Value,",", - {asis,NamedNumberList},")"}) + call(Erules, encode_bit_string, + [{asis,EffectiveC},Value, + {asis,NamedNumberList}]) end; 'NULL' -> emit("[]"); 'OBJECT IDENTIFIER' -> - emit({"?RT_PER:encode_object_identifier(",Value,")"}); + call(Erules, encode_object_identifier, [Value]); 'RELATIVE-OID' -> - emit({"?RT_PER:encode_relative_oid(",Value,")"}); + call(Erules, encode_relative_oid, [Value]); 'ObjectDescriptor' -> - emit({"?RT_PER:encode_ObjectDescriptor(",{asis,Constraint}, - ",",Value,")"}); + call(Erules, encode_ObjectDescriptor, + [{asis,Constraint},Value]); 'BOOLEAN' -> emit({"case ",Value," of",nl, " true -> [1];",nl, @@ -185,19 +187,19 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) -> emit_enc_known_multiplier_string('NumericString',Constraint,Value); TString when TString == 'TeletexString'; TString == 'T61String' -> - emit({"?RT_PER:encode_TeletexString(",{asis,Constraint},",",Value,")"}); + call(Erules, encode_TeletexString, [{asis,Constraint},Value]); 'VideotexString' -> - emit({"?RT_PER:encode_VideotexString(",{asis,Constraint},",",Value,")"}); + call(Erules, encode_VideotexString, [{asis,Constraint},Value]); 'UTCTime' -> emit_enc_known_multiplier_string('VisibleString',Constraint,Value); 'GeneralizedTime' -> emit_enc_known_multiplier_string('VisibleString',Constraint,Value); 'GraphicString' -> - emit({"?RT_PER:encode_GraphicString(",{asis,Constraint},",",Value,")"}); + call(Erules, encode_GraphicString, [{asis,Constraint},Value]); 'VisibleString' -> emit_enc_known_multiplier_string('VisibleString',Constraint,Value); 'GeneralString' -> - emit({"?RT_PER:encode_GeneralString(",{asis,Constraint},",",Value,")"}); + call(Erules, encode_GeneralString, [{asis,Constraint},Value]); 'PrintableString' -> emit_enc_known_multiplier_string('PrintableString',Constraint,Value); 'IA5String' -> @@ -207,23 +209,23 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) -> 'UniversalString' -> emit_enc_known_multiplier_string('UniversalString',Constraint,Value); 'UTF8String' -> - emit({"?RT_PER:encode_UTF8String(",Value,")"}); + call(Erules, encode_UTF8String, [Value]); 'ANY' -> - emit(["?RT_PER:encode_open_type(", {asis,Constraint}, ",", - Value, ")"]); + call(Erules, encode_open_type, [Value]); 'ASN1_OPEN_TYPE' -> NewValue = case Constraint of [#'Externaltypereference'{type=Tname}] -> - io_lib:format( - "?RT_PER:complete(enc_~s(~s))",[Tname,Value]); + asn1ct_func:need({Erules,complete,1}), + io_lib:format( + "complete(enc_~s(~s))",[Tname,Value]); [#type{def=#'Externaltypereference'{type=Tname}}] -> + asn1ct_func:need({Erules,complete,1}), io_lib:format( - "?RT_PER:complete(enc_~s(~s))", + "complete(enc_~s(~s))", [Tname,Value]); _ -> Value end, - emit(["?RT_PER:encode_open_type(", {asis,Constraint}, ",", - NewValue, ")"]); + call(Erules, encode_open_type, [NewValue]); #'ObjectClassFieldType'{} -> case asn1ct_gen:get_inner(D#type.def) of {fixedtypevaluefield,_,InnerType} -> @@ -235,6 +237,17 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) -> exit({asn1_error,nyi,XX}) end. +emit_enc_real(Erules, Real) -> + asn1ct_name:new(tmpval), + asn1ct_name:new(tmplen), + emit(["begin",nl, + "{",{curr,tmpval},com,{curr,tmplen},"} = ", + {call,real_common,encode_real,[Real]},com,nl, + "[",{call,Erules,encode_length,[{curr,tmplen}]},",",nl, + {call,Erules,octets_to_complete, + [{curr,tmplen},{curr,tmpval}]},"]",nl, + "end"]). + emit_enc_known_multiplier_string(StringType,C,Value) -> SizeC = case get_constraint(C,'SizeConstraint') of @@ -254,13 +267,13 @@ emit_enc_known_multiplier_string(StringType,C,Value) -> NumBits = get_NumBits(C,StringType), CharOutTab = get_CharOutTab(C,StringType), %% NunBits and CharOutTab for chars_encode - emit_enc_k_m_string(StringType,SizeC,NumBits,CharOutTab,Value). + emit_enc_k_m_string(SizeC, NumBits, CharOutTab, Value). -emit_enc_k_m_string(_StringType,0,_NumBits,_CharOutTab,_Value) -> +emit_enc_k_m_string(0, _NumBits, _CharOutTab, _Value) -> emit({"[]"}); -emit_enc_k_m_string(StringType,SizeC,NumBits,CharOutTab,Value) -> - emit({"?RT_PER:encode_known_multiplier_string(",{asis,StringType},",", - {asis,SizeC},",",NumBits,",",{asis,CharOutTab},",",Value,")"}). +emit_enc_k_m_string(SizeC, NumBits, CharOutTab, Value) -> + call(per, encode_known_multiplier_string, + [{asis,SizeC},NumBits,{asis,CharOutTab},Value]). emit_dec_known_multiplier_string(StringType,C,BytesVar) -> SizeC = get_constraint(C,'SizeConstraint'), @@ -280,9 +293,9 @@ emit_dec_known_multiplier_string(StringType,C,BytesVar) -> 0 -> emit({"{[],",BytesVar,"}"}); _ -> - emit({"?RT_PER:decode_known_multiplier_string(", - {asis,StringType},",",{asis,SizeC},",",NumBits, - ",",{asis,CharInTab},",",BytesVar,")"}) + call(per, decode_known_multiplier_string, + [{asis,StringType},{asis,SizeC},NumBits, + {asis,CharInTab},BytesVar]) end. @@ -397,7 +410,7 @@ charbits1(NumOfChars) -> %% copied from run time module -emit_enc_octet_string(_Erules,Constraint,Value) -> +emit_enc_octet_string(Erules, Constraint, Value) -> case get_constraint(Constraint,'SizeConstraint') of 0 -> emit({" []"}); @@ -446,7 +459,8 @@ emit_enc_octet_string(_Erules,Constraint,Value) -> " end",nl, " end"]); C -> - emit({" ?RT_PER:encode_octet_string(",{asis,C},",false,",Value,")",nl}) + call(Erules, encode_octet_string, + [{asis,C},false,Value]) end. emit_enc_integer_case(Value) -> @@ -533,10 +547,8 @@ emit_enc_integer(_Erule,[{_,{Lb,Ub},Range,_}],Value) when Range =< 65536 -> nl," end",nl]), emit_enc_integer_end_case(); - -emit_enc_integer(_Erule,C,Value) -> - emit({" ?RT_PER:encode_integer(",{asis,C},",",Value,")"}). - +emit_enc_integer(Erule, C, Value) -> + call(Erule, encode_integer, [{asis,C},Value]). @@ -582,16 +594,15 @@ emit_enc_enumerated_cases(Erule, C, [H1,H2|T], Count) -> %% %% ENUMERATED with extensionmark %% %% value higher than the extension base and not %% %% present in the extension range. -%% emit(["{asn1_enum,EnumV} when is_integer(EnumV), EnumV > ",High," -> ", -%% "[1,?RT_PER:encode_small_number(EnumV)]"]); -emit_enc_enumerated_case(_Erule,_C, {1,EnumName}, Count) -> +emit_enc_enumerated_case(Erule,_C, {1,EnumName}, Count) -> %% ENUMERATED with extensionmark %% values higher than extension root - emit(["'",EnumName,"' -> [1,?RT_PER:encode_small_number(",Count,")]"]); + emit(["'",EnumName,"' -> [1,"]), + call(Erule, encode_small_number, [Count]), + emit("]"); emit_enc_enumerated_case(_Erule,C, {0,EnumName}, Count) -> %% ENUMERATED with extensionmark %% values within extension root -%% emit(["'",EnumName,"' -> [0,?RT_PER:encode_integer(",{asis,C},", ",Count,")]"]); emit(["'",EnumName,"' -> ",{asis,[0|asn1rt_per_bin_rt2ct:encode_integer(C,Count)]}]); emit_enc_enumerated_case(_Erule, _C, 'EXT_MARK', _Count) -> true. @@ -1367,7 +1378,7 @@ emit_inner_of_decfun(Type,_) when is_record(Type,type) -> case Type#type.def of Def when is_atom(Def) -> emit({indent(9),Def," ->",nl,indent(12)}), - gen_dec_prim(erules,Type,"Val"); + gen_dec_prim(per, Type, "Val"); TRef when is_record(TRef,typereference) -> T = TRef#typereference.val, emit({indent(9),T," ->",nl,indent(12),"'dec_",T,"'(Val)"}); @@ -1465,30 +1476,18 @@ gen_dec_prim(Erules,Att,BytesVar) -> {'INTEGER',_NamedNumberList} -> asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'REAL' -> - emit(["?RT_PER:decode_real(",BytesVar,")"]); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - {'BIT STRING',NamedNumberList} -> - case get(compact_bit_string) of - true -> - emit({"?RT_PER:decode_compact_bit_string(", - BytesVar,",",{asis,Constraint},",", - {asis,NamedNumberList},")"}); - _ -> - emit({"?RT_PER:decode_bit_string(",BytesVar,",", - {asis,Constraint},",", - {asis,NamedNumberList},")"}) - end; + {'BIT STRING',_} -> + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'NULL' -> emit({"{'NULL',",BytesVar,"}"}); 'OBJECT IDENTIFIER' -> - emit({"?RT_PER:decode_object_identifier(", - BytesVar,")"}); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'RELATIVE-OID' -> - emit({"?RT_PER:decode_relative_oid(", - BytesVar,")"}); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'ObjectDescriptor' -> - emit({"?RT_PER:decode_ObjectDescriptor(", - BytesVar,")"}); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); {'ENUMERATED',_} -> asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'BOOLEAN'-> @@ -1502,12 +1501,10 @@ gen_dec_prim(Erules,Att,BytesVar) -> Constraint,BytesVar); TString when TString == 'TeletexString'; TString == 'T61String' -> - emit({"?RT_PER:decode_TeletexString(",BytesVar,",", - {asis,Constraint},")"}); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'VideotexString' -> - emit({"?RT_PER:decode_VideotexString(",BytesVar,",", - {asis,Constraint},")"}); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'UTCTime' -> emit_dec_known_multiplier_string('VisibleString', @@ -1516,15 +1513,13 @@ gen_dec_prim(Erules,Att,BytesVar) -> emit_dec_known_multiplier_string('VisibleString', Constraint,BytesVar); 'GraphicString' -> - emit({"?RT_PER:decode_GraphicString(",BytesVar,",", - {asis,Constraint},")"}); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'VisibleString' -> emit_dec_known_multiplier_string('VisibleString', Constraint,BytesVar); 'GeneralString' -> - emit({"?RT_PER:decode_GeneralString(",BytesVar,",", - {asis,Constraint},")"}); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'PrintableString' -> emit_dec_known_multiplier_string('PrintableString', @@ -1540,7 +1535,7 @@ gen_dec_prim(Erules,Att,BytesVar) -> Constraint,BytesVar); 'UTF8String' -> - emit({"?RT_PER:decode_UTF8String(",BytesVar,")"}); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'ANY' -> asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'ASN1_OPEN_TYPE' -> diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl index d27bea98d0..384d4a86bb 100644 --- a/lib/asn1/src/asn1ct_imm.erl +++ b/lib/asn1/src/asn1ct_imm.erl @@ -21,7 +21,7 @@ -export([per_dec_boolean/0,per_dec_enumerated/2,per_dec_enumerated/3, per_dec_extension_map/1, per_dec_integer/2,per_dec_length/3,per_dec_named_integer/3, - per_dec_octet_string/2,per_dec_open_type/1]). + per_dec_octet_string/2,per_dec_open_type/1,per_dec_real/1]). -export([optimize_alignment/1,optimize_alignment/2, dec_slim_cg/2,dec_code_gen/2]). -export([effective_constraint/2]). @@ -107,6 +107,14 @@ per_dec_open_type(Aligned) -> {get_bits,decode_unconstrained_length(true, Aligned), [8,binary,{align,Aligned}]}. +per_dec_real(Aligned) -> + Dec = fun(V, Buf) -> + emit(["{",{call,real_common,decode_real,[V]}, + com,Buf,"}"]) + end, + {call,Dec, + {get_bits,decode_unconstrained_length(true, Aligned), + [8,binary,{align,Aligned}]}}. %%% %%% Local functions. diff --git a/lib/asn1/src/asn1rt_ber_bin_v2.erl b/lib/asn1/src/asn1rt_ber_bin_v2.erl index 92ca11cf89..10deecee6e 100644 --- a/lib/asn1/src/asn1rt_ber_bin_v2.erl +++ b/lib/asn1/src/asn1rt_ber_bin_v2.erl @@ -24,6 +24,7 @@ -export([decode/1, decode/2, match_tags/2, encode/1, encode/2]). -export([fixoptionals/2, encode_tag_val/1, + encode_tags/2, encode_tags/3, skip_ExtensionAdditions/2]). -export([encode_boolean/2,decode_boolean/2, diff --git a/lib/asn1/src/asn1rtt_ber.erl b/lib/asn1/src/asn1rtt_ber.erl new file mode 100644 index 0000000000..b374191f37 --- /dev/null +++ b/lib/asn1/src/asn1rtt_ber.erl @@ -0,0 +1,1619 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(asn1rtt_ber). + +%% encoding / decoding of BER + +-export([ber_decode_nif/1,ber_decode_erlang/1,match_tags/2,ber_encode/1]). +-export([encode_tags/2, + encode_tags/3, + skip_ExtensionAdditions/2]). +-export([encode_boolean/2,decode_boolean/2, + encode_integer/2,encode_integer/3, + decode_integer/3,decode_integer/4, + encode_enumerated/2,decode_enumerated/3, + encode_bit_string/4,decode_bit_string/4, + decode_compact_bit_string/4, + decode_octet_string/3, + encode_null/2,decode_null/2, + encode_relative_oid/2,decode_relative_oid/2, + encode_object_identifier/2,decode_object_identifier/2, + encode_restricted_string/2,decode_restricted_string/4, + encode_universal_string/2,decode_universal_string/3, + encode_UTF8_string/2,decode_UTF8_string/2, + encode_BMP_string/2,decode_BMP_string/3, + encode_generalized_time/2,decode_generalized_time/3, + encode_utc_time/2,decode_utc_time/3]). + +-export([encode_open_type/2,decode_open_type/2, + decode_open_type_as_binary/2]). + +-export([decode_primitive_incomplete/2,decode_selective/2]). + +%% For DER. +-export([dynamicsort_SET_components/1,dynamicsort_SETOF/1]). + +%% the encoding of class of tag bits 8 and 7 +-define(UNIVERSAL, 0). +-define(APPLICATION, 16#40). +-define(CONTEXT, 16#80). +-define(PRIVATE, 16#C0). + +%%% primitive or constructed encoding % bit 6 +-define(PRIMITIVE, 0). +-define(CONSTRUCTED, 2#00100000). + +%%% The tag-number for universal types +-define(N_BOOLEAN, 1). +-define(N_INTEGER, 2). +-define(N_BIT_STRING, 3). +-define(N_OCTET_STRING, 4). +-define(N_NULL, 5). +-define(N_OBJECT_IDENTIFIER, 6). +-define(N_OBJECT_DESCRIPTOR, 7). +-define(N_EXTERNAL, 8). +-define(N_REAL, 9). +-define(N_ENUMERATED, 10). +-define(N_EMBEDDED_PDV, 11). +-define(N_SEQUENCE, 16). +-define(N_SET, 17). +-define(N_NumericString, 18). +-define(N_PrintableString, 19). +-define(N_TeletexString, 20). +-define(N_VideotexString, 21). +-define(N_IA5String, 22). +-define(N_UTCTime, 23). +-define(N_GeneralizedTime, 24). +-define(N_GraphicString, 25). +-define(N_VisibleString, 26). +-define(N_GeneralString, 27). +-define(N_UniversalString, 28). +-define(N_BMPString, 30). + + +% the complete tag-word of built-in types +-define(T_BOOLEAN, ?UNIVERSAL bor ?PRIMITIVE bor 1). +-define(T_INTEGER, ?UNIVERSAL bor ?PRIMITIVE bor 2). +-define(T_BIT_STRING, ?UNIVERSAL bor ?PRIMITIVE bor 3). % can be CONSTRUCTED +-define(T_OCTET_STRING, ?UNIVERSAL bor ?PRIMITIVE bor 4). % can be CONSTRUCTED +-define(T_NULL, ?UNIVERSAL bor ?PRIMITIVE bor 5). +-define(T_OBJECT_IDENTIFIER,?UNIVERSAL bor ?PRIMITIVE bor 6). +-define(T_OBJECT_DESCRIPTOR,?UNIVERSAL bor ?PRIMITIVE bor 7). +-define(T_EXTERNAL, ?UNIVERSAL bor ?PRIMITIVE bor 8). +-define(T_REAL, ?UNIVERSAL bor ?PRIMITIVE bor 9). +-define(T_ENUMERATED, ?UNIVERSAL bor ?PRIMITIVE bor 10). +-define(T_EMBEDDED_PDV, ?UNIVERSAL bor ?PRIMITIVE bor 11). +-define(T_SEQUENCE, ?UNIVERSAL bor ?CONSTRUCTED bor 16). +-define(T_SET, ?UNIVERSAL bor ?CONSTRUCTED bor 17). +-define(T_NumericString, ?UNIVERSAL bor ?PRIMITIVE bor 18). %can be constructed +-define(T_PrintableString, ?UNIVERSAL bor ?PRIMITIVE bor 19). %can be constructed +-define(T_TeletexString, ?UNIVERSAL bor ?PRIMITIVE bor 20). %can be constructed +-define(T_VideotexString, ?UNIVERSAL bor ?PRIMITIVE bor 21). %can be constructed +-define(T_IA5String, ?UNIVERSAL bor ?PRIMITIVE bor 22). %can be constructed +-define(T_UTCTime, ?UNIVERSAL bor ?PRIMITIVE bor 23). +-define(T_GeneralizedTime, ?UNIVERSAL bor ?PRIMITIVE bor 24). +-define(T_GraphicString, ?UNIVERSAL bor ?PRIMITIVE bor 25). %can be constructed +-define(T_VisibleString, ?UNIVERSAL bor ?PRIMITIVE bor 26). %can be constructed +-define(T_GeneralString, ?UNIVERSAL bor ?PRIMITIVE bor 27). %can be constructed +-define(T_UniversalString, ?UNIVERSAL bor ?PRIMITIVE bor 28). %can be constructed +-define(T_BMPString, ?UNIVERSAL bor ?PRIMITIVE bor 30). %can be constructed + +ber_encode([Tlv]) -> + ber_encode(Tlv); +ber_encode(Tlv) when is_binary(Tlv) -> + Tlv; +ber_encode(Tlv) -> + asn1rt_nif:encode_ber_tlv(Tlv). + +ber_decode_nif(B) -> + case asn1rt_nif:decode_ber_tlv(B) of + {error, Reason} -> handle_error(Reason, B); + Else -> Else + end. + +ber_decode_erlang(B) when is_binary(B) -> + decode_primitive(B); +ber_decode_erlang(Tlv) -> + {Tlv,<<>>}. + +handle_error([],_)-> + exit({error,{asn1,{"memory allocation problem"}}}); +handle_error({$1,_},L) -> % error in nif + exit({error,{asn1,L}}); +handle_error({$2,T},L) -> % error in nif due to wrong tag + exit({error,{asn1,{"bad tag after byte:",error_pos(T),L}}}); +handle_error({$3,T},L) -> % error in driver due to length error + exit({error,{asn1,{"bad length field after byte:", + error_pos(T),L}}}); +handle_error({$4,T},L) -> % error in driver due to indefinite length error + exit({error,{asn1, + {"indefinite length without end bytes after byte:", + error_pos(T),L}}}); +handle_error({$5,T},L) -> % error in driver due to indefinite length error + exit({error,{asn1,{"bad encoded value after byte:", + error_pos(T),L}}}); +handle_error(ErrL,L) -> + exit({error,{asn1,ErrL,L}}). + +error_pos([]) -> + "unknown position"; +error_pos([B])-> + B; +error_pos([B|Bs]) -> + BS = 8 * length(Bs), + B bsl BS + error_pos(Bs). + +decode_primitive(Bin) -> + {Form,TagNo,V,Rest} = decode_tag_and_length(Bin), + case Form of + 1 -> % constructed + {{TagNo,decode_constructed(V)},Rest}; + 0 -> % primitive + {{TagNo,V},Rest}; + 2 -> % constructed indefinite + {Vlist,Rest2} = decode_constructed_indefinite(V,[]), + {{TagNo,Vlist},Rest2} + end. + +decode_constructed(Bin) when byte_size(Bin) =:= 0 -> + []; +decode_constructed(Bin) -> + {Tlv,Rest} = decode_primitive(Bin), + [Tlv|decode_constructed(Rest)]. + +decode_constructed_indefinite(<<0,0,Rest/binary>>,Acc) -> + {lists:reverse(Acc),Rest}; +decode_constructed_indefinite(Bin,Acc) -> + {Tlv,Rest} = decode_primitive(Bin), + decode_constructed_indefinite(Rest, [Tlv|Acc]). + +%% decode_primitive_incomplete/2 decodes an encoded message incomplete +%% by help of the pattern attribute (first argument). +decode_primitive_incomplete([[default,TagNo]],Bin) -> %default + case decode_tag_and_length(Bin) of + {Form,TagNo,V,Rest} -> + decode_incomplete2(Form,TagNo,V,[],Rest); + _ -> + %{asn1_DEFAULT,Bin} + asn1_NOVALUE + end; +decode_primitive_incomplete([[default,TagNo,Directives]],Bin) -> %default, constructed type, Directives points into this type + case decode_tag_and_length(Bin) of + {Form,TagNo,V,Rest} -> + decode_incomplete2(Form,TagNo,V,Directives,Rest); + _ -> + %{asn1_DEFAULT,Bin} + asn1_NOVALUE + end; +decode_primitive_incomplete([[opt,TagNo]],Bin) -> %optional + case decode_tag_and_length(Bin) of + {Form,TagNo,V,Rest} -> + decode_incomplete2(Form,TagNo,V,[],Rest); + _ -> + %{{TagNo,asn1_NOVALUE},Bin} + asn1_NOVALUE + end; +decode_primitive_incomplete([[opt,TagNo,Directives]],Bin) -> %optional + case decode_tag_and_length(Bin) of + {Form,TagNo,V,Rest} -> + decode_incomplete2(Form,TagNo,V,Directives,Rest); + _ -> + %{{TagNo,asn1_NOVALUE},Bin} + asn1_NOVALUE + end; +%% An optional that shall be undecoded +decode_primitive_incomplete([[opt_undec,Tag]],Bin) -> + case decode_tag_and_length(Bin) of + {_,Tag,_,_} -> + decode_incomplete_bin(Bin); + _ -> + asn1_NOVALUE + end; +%% A choice alternative that shall be undecoded +decode_primitive_incomplete([[alt_undec,TagNo]|RestAlts],Bin) -> + case decode_tag_and_length(Bin) of + {_,TagNo,_,_} -> + decode_incomplete_bin(Bin); + _ -> + decode_primitive_incomplete(RestAlts,Bin) + end; +decode_primitive_incomplete([[alt,TagNo]|RestAlts],Bin) -> + case decode_tag_and_length(Bin) of + {_Form,TagNo,V,Rest} -> + {{TagNo,V},Rest}; + _ -> + decode_primitive_incomplete(RestAlts,Bin) + end; +decode_primitive_incomplete([[alt,TagNo,Directives]|RestAlts],Bin) -> + case decode_tag_and_length(Bin) of + {Form,TagNo,V,Rest} -> + decode_incomplete2(Form,TagNo,V,Directives,Rest); + _ -> + decode_primitive_incomplete(RestAlts,Bin) + end; +decode_primitive_incomplete([[alt_parts,TagNo]],Bin) -> + case decode_tag_and_length(Bin) of + {_Form,TagNo,V,Rest} -> + {{TagNo,V},Rest}; + _ -> + asn1_NOVALUE + end; +decode_primitive_incomplete([[alt_parts,TagNo]|RestAlts],Bin) -> + case decode_tag_and_length(Bin) of + {_Form,TagNo,V,Rest} -> + {{TagNo,decode_parts_incomplete(V)},Rest}; + _ -> + decode_primitive_incomplete(RestAlts,Bin) + end; +decode_primitive_incomplete([[undec,_TagNo]|_RestTag],Bin) -> %incomlete decode + decode_incomplete_bin(Bin); +decode_primitive_incomplete([[parts,TagNo]|_RestTag],Bin) -> + case decode_tag_and_length(Bin) of + {_Form,TagNo,V,Rest} -> + {{TagNo,decode_parts_incomplete(V)},Rest}; + Err -> + {error,{asn1,"tag failure",TagNo,Err}} + end; +decode_primitive_incomplete([mandatory|RestTag],Bin) -> + {Form,TagNo,V,Rest} = decode_tag_and_length(Bin), + decode_incomplete2(Form,TagNo,V,RestTag,Rest); +%% A choice that is a toptype or a mandatory component of a +%% SEQUENCE or SET. +decode_primitive_incomplete([[mandatory|Directives]],Bin) -> + {Form,TagNo,V,Rest} = decode_tag_and_length(Bin), + decode_incomplete2(Form,TagNo,V,Directives,Rest); +decode_primitive_incomplete([],Bin) -> + decode_primitive(Bin). + +%% decode_parts_incomplete/1 receives a number of values encoded in +%% sequence and returns the parts as unencoded binaries +decode_parts_incomplete(<<>>) -> + []; +decode_parts_incomplete(Bin) -> + {ok,Rest} = skip_tag(Bin), + {ok,Rest2} = skip_length_and_value(Rest), + LenPart = byte_size(Bin) - byte_size(Rest2), + <> = Bin, + [Part|decode_parts_incomplete(RestBin)]. + + +%% decode_incomplete2 checks if V is a value of a constructed or +%% primitive type, and continues the decode propeerly. +decode_incomplete2(_Form=2,TagNo,V,TagMatch,_) -> + %% constructed indefinite length + {Vlist,Rest2} = decode_constr_indef_incomplete(TagMatch,V,[]), + {{TagNo,Vlist},Rest2}; +decode_incomplete2(1,TagNo,V,[TagMatch],Rest) when is_list(TagMatch) -> + {{TagNo,decode_constructed_incomplete(TagMatch,V)},Rest}; +decode_incomplete2(1,TagNo,V,TagMatch,Rest) -> + {{TagNo,decode_constructed_incomplete(TagMatch,V)},Rest}; +decode_incomplete2(0,TagNo,V,_TagMatch,Rest) -> + {{TagNo,V},Rest}. + +decode_constructed_incomplete([Tags=[Ts]],Bin) when is_list(Ts) -> + decode_constructed_incomplete(Tags,Bin); +decode_constructed_incomplete(_TagMatch,<<>>) -> + []; +decode_constructed_incomplete([mandatory|RestTag],Bin) -> + {Tlv,Rest} = decode_primitive(Bin), + [Tlv|decode_constructed_incomplete(RestTag,Rest)]; +decode_constructed_incomplete(Directives=[[Alt,_]|_],Bin) + when Alt =:= alt_undec; Alt =:= alt; Alt =:= alt_parts -> + {_Form,TagNo,V,Rest} = decode_tag_and_length(Bin), + case incomplete_choice_alt(TagNo, Directives) of + {alt_undec,_} -> + LenA = byte_size(Bin) - byte_size(Rest), + <> = Bin, + A; + {alt,InnerDirectives} -> + {Tlv,Rest} = decode_primitive_incomplete(InnerDirectives,V), + {TagNo,Tlv}; + {alt_parts,_} -> + [{TagNo,decode_parts_incomplete(V)}]; + no_match -> %% if a choice alternative was encoded that + %% was not specified in the config file, + %% thus decode component anonomous. + {Tlv,_}=decode_primitive(Bin), + Tlv + end; +decode_constructed_incomplete([TagNo|RestTag],Bin) -> + case decode_primitive_incomplete([TagNo],Bin) of + {Tlv,Rest} -> + [Tlv|decode_constructed_incomplete(RestTag,Rest)]; + asn1_NOVALUE -> + decode_constructed_incomplete(RestTag,Bin) + end; +decode_constructed_incomplete([],Bin) -> + {Tlv,Rest}=decode_primitive(Bin), + [Tlv|decode_constructed_incomplete([],Rest)]. + +decode_constr_indef_incomplete(_TagMatch,<<0,0,Rest/binary>>,Acc) -> + {lists:reverse(Acc),Rest}; +decode_constr_indef_incomplete([Tag|RestTags],Bin,Acc) -> + case decode_primitive_incomplete([Tag],Bin) of + {Tlv,Rest} -> + decode_constr_indef_incomplete(RestTags,Rest,[Tlv|Acc]); + asn1_NOVALUE -> + decode_constr_indef_incomplete(RestTags,Bin,Acc) + end. + + +decode_incomplete_bin(Bin) -> + {ok,Rest} = skip_tag(Bin), + {ok,Rest2} = skip_length_and_value(Rest), + IncLen = byte_size(Bin) - byte_size(Rest2), + <> = Bin, + {IncBin,Ret}. + +incomplete_choice_alt(TagNo,[[Alt,TagNo]|Directives]) -> + {Alt,Directives}; +incomplete_choice_alt(TagNo,[D]) when is_list(D) -> + incomplete_choice_alt(TagNo,D); +incomplete_choice_alt(TagNo,[_H|Directives]) -> + incomplete_choice_alt(TagNo,Directives); +incomplete_choice_alt(_,[]) -> + no_match. + + +%% decode_selective(Pattern, Binary) the first argument is a pattern that tells +%% what to do with the next element the second is the BER encoded +%% message as a binary +%% Returns {ok,Value} or {error,Reason} +%% Value is a binary that in turn must be decoded to get the decoded +%% value. +decode_selective([],Binary) -> + {ok,Binary}; +decode_selective([skip|RestPattern],Binary)-> + {ok,RestBinary}=skip_tag(Binary), + {ok,RestBinary2}=skip_length_and_value(RestBinary), + decode_selective(RestPattern,RestBinary2); +decode_selective([[skip_optional,Tag]|RestPattern],Binary) -> + case skip_optional_tag(Tag,Binary) of + {ok,RestBinary} -> + {ok,RestBinary2}=skip_length_and_value(RestBinary), + decode_selective(RestPattern,RestBinary2); + missing -> + decode_selective(RestPattern,Binary) + end; +decode_selective([[choosen,Tag]],Binary) -> + return_value(Tag,Binary); +decode_selective([[choosen,Tag]|RestPattern],Binary) -> + case skip_optional_tag(Tag,Binary) of + {ok,RestBinary} -> + {ok,Value} = get_value(RestBinary), + decode_selective(RestPattern,Value); + missing -> + {ok,<<>>} + end; +decode_selective(P,_) -> + {error,{asn1,{partial_decode,"bad pattern",P}}}. + +return_value(Tag,Binary) -> + {ok,{Tag,RestBinary}}=get_tag(Binary), + {ok,{LenVal,_RestBinary2}} = get_length_and_value(RestBinary), + {ok,<>}. + + +%% skip_tag and skip_length_and_value are rutines used both by +%% decode_partial_incomplete and decode_selective (decode/2). + +skip_tag(<<_:3,31:5,Rest/binary>>)-> + skip_long_tag(Rest); +skip_tag(<<_:3,_Tag:5,Rest/binary>>) -> + {ok,Rest}. + +skip_long_tag(<<1:1,_:7,Rest/binary>>) -> + skip_long_tag(Rest); +skip_long_tag(<<0:1,_:7,Rest/binary>>) -> + {ok,Rest}. + +skip_optional_tag(<<>>,Binary) -> + {ok,Binary}; +skip_optional_tag(<>,<>) -> + skip_optional_tag(RestTag,Rest); +skip_optional_tag(_,_) -> + missing. + + +skip_length_and_value(Binary) -> + case decode_length(Binary) of + {indefinite,RestBinary} -> + skip_indefinite_value(RestBinary); + {Length,RestBinary} -> + <<_:Length/unit:8,Rest/binary>> = RestBinary, + {ok,Rest} + end. + +skip_indefinite_value(<<0,0,Rest/binary>>) -> + {ok,Rest}; +skip_indefinite_value(Binary) -> + {ok,RestBinary}=skip_tag(Binary), + {ok,RestBinary2} = skip_length_and_value(RestBinary), + skip_indefinite_value(RestBinary2). + +get_value(Binary) -> + case decode_length(Binary) of + {indefinite,RestBinary} -> + get_indefinite_value(RestBinary,[]); + {Length,RestBinary} -> + <> = RestBinary, + {ok,Value} + end. + +get_indefinite_value(<<0,0,_Rest/binary>>,Acc) -> + {ok,list_to_binary(lists:reverse(Acc))}; +get_indefinite_value(Binary,Acc) -> + {ok,{Tag,RestBinary}}=get_tag(Binary), + {ok,{LenVal,RestBinary2}} = get_length_and_value(RestBinary), + get_indefinite_value(RestBinary2,[LenVal,Tag|Acc]). + +get_tag(<>) -> + case H of + <<_:3,31:5>> -> + get_long_tag(Rest,[H]); + _ -> {ok,{H,Rest}} + end. +get_long_tag(<>,Acc) -> + case H of + <<0:1,_:7>> -> + {ok,{list_to_binary(lists:reverse([H|Acc])),Rest}}; + _ -> + get_long_tag(Rest,[H|Acc]) + end. + +get_length_and_value(Bin = <<0:1,Length:7,_T/binary>>) -> + <> = Bin, + {ok,{<>, Rest}}; +get_length_and_value(Bin = <<1:1,0:7,_T/binary>>) -> + get_indefinite_length_and_value(Bin); +get_length_and_value(<<1:1,LL:7,T/binary>>) -> + <> = T, + <> = Rest, + {ok,{<<1:1,LL:7,Length:LL/unit:8,Value/binary>>,Rest2}}. + +get_indefinite_length_and_value(<>) -> + get_indefinite_length_and_value(T,[H]). + +get_indefinite_length_and_value(<<0,0,Rest/binary>>,Acc) -> + {ok,{list_to_binary(lists:reverse(Acc)),Rest}}; +get_indefinite_length_and_value(Binary,Acc) -> + {ok,{Tag,RestBinary}}=get_tag(Binary), + {ok,{LenVal,RestBinary2}}=get_length_and_value(RestBinary), + get_indefinite_length_and_value(RestBinary2,[LenVal,Tag|Acc]). + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% match_tags takes a Tlv (Tag, Length, Value) structure and matches +%% it with the tags in TagList. If the tags does not match the function +%% crashes otherwise it returns the remaining Tlv after that the tags have +%% been removed. +%% +%% match_tags(Tlv, TagList) +%% + +match_tags({T,V}, [T]) -> + V; +match_tags({T,V}, [T|Tt]) -> + match_tags(V,Tt); +match_tags([{T,V}], [T|Tt]) -> + match_tags(V, Tt); +match_tags([{T,_V}|_]=Vlist, [T]) -> + Vlist; +match_tags(Tlv, []) -> + Tlv; +match_tags({Tag,_V}=Tlv, [T|_Tt]) -> + exit({error,{asn1,{wrong_tag,{{expected,T},{got,Tag,Tlv}}}}}). + +%%% +%% skips components that do not match a tag in Tags +skip_ExtensionAdditions([], _Tags) -> + []; +skip_ExtensionAdditions([{Tag,_}|Rest]=TLV, Tags) -> + case [X || X=T <- Tags, T =:= Tag] of + [] -> + %% skip this TLV and continue with next + skip_ExtensionAdditions(Rest,Tags); + _ -> + TLV + end. + + +%%=============================================================================== +%% Decode a tag +%% +%% decode_tag(OctetListBuffer) -> {{Form, (Class bsl 16)+ TagNo}, RestOfBuffer, RemovedBytes} +%%=============================================================================== + +decode_tag_and_length(<>) when TagNo < 31 -> + {Form, (Class bsl 16) bor TagNo, V, RestBuffer}; +decode_tag_and_length(<>) when TagNo < 31 -> + {2, (Class bsl 16) + TagNo, T, <<>>}; +decode_tag_and_length(<>) when TagNo < 31 -> + {Form, (Class bsl 16) bor TagNo, V, T}; +decode_tag_and_length(<>) -> + {Form, (Class bsl 16) bor TagNo, V, RestBuffer}; +decode_tag_and_length(<>) -> + {2, (Class bsl 16) bor TagNo, T, <<>>}; +decode_tag_and_length(<>) -> + {Form, (Class bsl 16) bor TagNo, V, T}; +decode_tag_and_length(<>) -> + TagNo = (TagPart1 bsl 7) bor TagPartLast, + {Length, RestBuffer} = decode_length(Buffer), + << V:Length/binary, RestBuffer2/binary>> = RestBuffer, + {Form, (Class bsl 16) bor TagNo, V, RestBuffer2}; +decode_tag_and_length(<>) -> + {TagNo, Buffer1} = decode_tag(Buffer, 0), + {Length, RestBuffer} = decode_length(Buffer1), + << V:Length/binary, RestBuffer2/binary>> = RestBuffer, + {Form, (Class bsl 16) bor TagNo, V, RestBuffer2}. + + + +%% last partial tag +decode_tag(<<0:1,PartialTag:7, Buffer/binary>>, TagAck) -> + TagNo = (TagAck bsl 7) bor PartialTag, + {TagNo, Buffer}; +% more tags +decode_tag(<<_:1,PartialTag:7, Buffer/binary>>, TagAck) -> + TagAck1 = (TagAck bsl 7) bor PartialTag, + decode_tag(Buffer, TagAck1). + +%%======================================================================= +%% +%% Encode all tags in the list Tags and return a possibly deep list of +%% bytes with tag and length encoded +%% The taglist must be in reverse order (fixed by the asn1 compiler) +%% e.g [T1,T2] will result in +%% {[EncodedT2,EncodedT1|BytesSoFar],LenSoFar+LenT2+LenT1} +%% + +encode_tags([Tag|Trest], BytesSoFar, LenSoFar) -> + {Bytes2,L2} = encode_length(LenSoFar), + encode_tags(Trest, [Tag,Bytes2|BytesSoFar], + LenSoFar + byte_size(Tag) + L2); +encode_tags([], BytesSoFar, LenSoFar) -> + {BytesSoFar,LenSoFar}. + +encode_tags(TagIn, {BytesSoFar,LenSoFar}) -> + encode_tags(TagIn, BytesSoFar, LenSoFar). + +%%=============================================================================== +%% +%% This comment is valid for all the encode/decode functions +%% +%% C = Constraint -> typically {'ValueRange',LowerBound,UpperBound} +%% used for PER-coding but not for BER-coding. +%% +%% Val = Value. If Val is an atom then it is a symbolic integer value +%% (i.e the atom must be one of the names in the NamedNumberList). +%% The NamedNumberList is used to translate the atom to an integer value +%% before encoding. +%% +%%=============================================================================== + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% encode_open_type(Value) -> io_list (i.e nested list with integers, binaries) +%% Value = list of bytes of an already encoded value (the list must be flat) +%% | binary + +encode_open_type(Val, T) when is_list(Val) -> + encode_open_type(list_to_binary(Val), T); +encode_open_type(Val, []) -> + {Val,byte_size(Val)}; +encode_open_type(Val, Tag) -> + encode_tags(Tag, Val, byte_size(Val)). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% decode_open_type(Tlv, TagIn) -> Value +%% Tlv = {Tag,V} | V where V -> binary() +%% TagIn = [TagVal] where TagVal -> int() +%% Value = binary with decoded data (which must be decoded again as some type) +%% +decode_open_type(Tlv, TagIn) -> + case match_tags(Tlv, TagIn) of + Bin when is_binary(Bin) -> + {InnerTlv,_} = ber_decode_nif(Bin), + InnerTlv; + TlvBytes -> TlvBytes + end. + +decode_open_type_as_binary(Tlv, TagIn)-> + ber_encode(match_tags(Tlv, TagIn)). + +%%=============================================================================== +%%=============================================================================== +%%=============================================================================== +%% Boolean, ITU_T X.690 Chapter 8.2 +%%=============================================================================== +%%=============================================================================== +%%=============================================================================== + +%%=============================================================================== +%% encode_boolean(Integer, ReversedTagList) -> {[Octet],Len} +%%=============================================================================== + +encode_boolean(true, TagIn) -> + encode_tags(TagIn, [16#FF],1); +encode_boolean(false, TagIn) -> + encode_tags(TagIn, [0],1); +encode_boolean(X,_) -> + exit({error,{asn1, {encode_boolean, X}}}). + + +%%=============================================================================== +%% decode_boolean(BuffList, HasTag, TotalLen) -> {true, Remain, RemovedBytes} | +%% {false, Remain, RemovedBytes} +%%=============================================================================== +decode_boolean(Tlv,TagIn) -> + Val = match_tags(Tlv, TagIn), + case Val of + <<0:8>> -> + false; + <<_:8>> -> + true; + _ -> + exit({error,{asn1, {decode_boolean, Val}}}) + end. + + +%%=========================================================================== +%% Integer, ITU_T X.690 Chapter 8.3 + +%% encode_integer(Constraint, Value, Tag) -> [octet list] +%% encode_integer(Constraint, Name, NamedNumberList, Tag) -> [octet list] +%% Value = INTEGER | {Name,INTEGER} +%% Tag = tag | notag +%%=========================================================================== + +encode_integer(Val, Tag) when is_integer(Val) -> + encode_tags(Tag, encode_integer(Val)); +encode_integer(Val, _Tag) -> + exit({error,{asn1,{encode_integer,Val}}}). + + +encode_integer(Val, NamedNumberList, Tag) when is_atom(Val) -> + case lists:keyfind(Val, 1, NamedNumberList) of + {_, NewVal} -> + encode_tags(Tag, encode_integer(NewVal)); + _ -> + exit({error,{asn1, {encode_integer_namednumber, Val}}}) + end; +encode_integer(Val, _NamedNumberList, Tag) -> + encode_tags(Tag, encode_integer(Val)). + +encode_integer(Val) -> + Bytes = + if + Val >= 0 -> + encode_integer_pos(Val, []); + true -> + encode_integer_neg(Val, []) + end, + {Bytes,length(Bytes)}. + +encode_integer_pos(0, [B|_Acc]=L) when B < 128 -> + L; +encode_integer_pos(N, Acc) -> + encode_integer_pos((N bsr 8), [N band 16#ff| Acc]). + +encode_integer_neg(-1, [B1|_T]=L) when B1 > 127 -> + L; +encode_integer_neg(N, Acc) -> + encode_integer_neg(N bsr 8, [N band 16#ff|Acc]). + +%%=============================================================================== +%% decode integer +%% (Buffer, Range, HasTag, TotalLen) -> {Integer, Remain, RemovedBytes} +%% (Buffer, Range, NamedNumberList, HasTag, TotalLen) -> {Integer, Remain, RemovedBytes} +%%=============================================================================== + +decode_integer(Tlv, Range, NamedNumberList, TagIn) -> + V = match_tags(Tlv, TagIn), + Int = range_check_integer(decode_integer(V), Range), + number2name(Int, NamedNumberList). + +decode_integer(Tlv, Range, TagIn) -> + V = match_tags(Tlv, TagIn), + Int = decode_integer(V), + range_check_integer(Int, Range). + +decode_integer(Bin) -> + Len = byte_size(Bin), + <> = Bin, + Int. + +range_check_integer(Int, Range) -> + case Range of + [] -> % No length constraint + Int; + {Lb,Ub} when Int >= Lb, Ub >= Int -> % variable length constraint + Int; + {_,_} -> + exit({error,{asn1,{integer_range,Range,Int}}}); + Int -> % fixed value constraint + Int; + SingleValue when is_integer(SingleValue) -> + exit({error,{asn1,{integer_range,Range,Int}}}); + _ -> % some strange constraint that we don't support yet + Int + end. + +number2name(Int, []) -> + Int; +number2name(Int, NamedNumberList) -> + case lists:keyfind(Int, 2, NamedNumberList) of + {NamedVal,_} -> + NamedVal; + _ -> + Int + end. + + +%%============================================================================ +%% Enumerated value, ITU_T X.690 Chapter 8.4 + +%% encode enumerated value +%%============================================================================ +encode_enumerated(Val, TagIn) when is_integer(Val) -> + encode_tags(TagIn, encode_integer(Val)). + +%%============================================================================ +%% decode enumerated value +%% (Buffer, Range, NamedNumberList, HasTag, TotalLen) -> Value +%%=========================================================================== +decode_enumerated(Tlv, NamedNumberList, Tags) -> + Buffer = match_tags(Tlv, Tags), + decode_enumerated_notag(Buffer, NamedNumberList, Tags). + +decode_enumerated_notag(Buffer, {NamedNumberList,ExtList}, _Tags) -> + IVal = decode_integer(Buffer), + case decode_enumerated1(IVal, NamedNumberList) of + {asn1_enum,IVal} -> + decode_enumerated1(IVal,ExtList); + EVal -> + EVal + end; +decode_enumerated_notag(Buffer, NNList, _Tags) -> + IVal = decode_integer(Buffer), + case decode_enumerated1(IVal, NNList) of + {asn1_enum,_} -> + exit({error,{asn1, {illegal_enumerated, IVal}}}); + EVal -> + EVal + end. + +decode_enumerated1(Val, NamedNumberList) -> + %% it must be a named integer + case lists:keyfind(Val, 2, NamedNumberList) of + {NamedVal, _} -> + NamedVal; + _ -> + {asn1_enum,Val} + end. + + +%%============================================================================ +%% Bitstring value, ITU_T X.690 Chapter 8.6 +%% +%% encode bitstring value +%% +%% bitstring NamedBitList +%% Val can be of: +%% - [identifiers] where only named identifers are set to one, +%% the Constraint must then have some information of the +%% bitlength. +%% - [list of ones and zeroes] all bits +%% - integer value representing the bitlist +%% C is constrint Len, only valid when identifiers +%%============================================================================ + +encode_bit_string(C,Bin={Unused,BinBits},NamedBitList,TagIn) when is_integer(Unused), is_binary(BinBits) -> + encode_bin_bit_string(C,Bin,NamedBitList,TagIn); +encode_bit_string(C, [FirstVal | RestVal], NamedBitList, TagIn) when is_atom(FirstVal) -> + encode_bit_string_named(C, [FirstVal | RestVal], NamedBitList, TagIn); + +encode_bit_string(C, [{bit,X} | RestVal], NamedBitList, TagIn) -> + encode_bit_string_named(C, [{bit,X} | RestVal], NamedBitList, TagIn); + +encode_bit_string(C, [FirstVal| RestVal], NamedBitList, TagIn) when is_integer(FirstVal) -> + encode_bit_string_bits(C, [FirstVal | RestVal], NamedBitList, TagIn); + +encode_bit_string(_C, 0, _NamedBitList, TagIn) -> + encode_tags(TagIn, <<0>>,1); + +encode_bit_string(_C, [], _NamedBitList, TagIn) -> + encode_tags(TagIn, <<0>>,1); + +encode_bit_string(C, IntegerVal, NamedBitList, TagIn) when is_integer(IntegerVal) -> + BitListVal = int_to_bitlist(IntegerVal), + encode_bit_string_bits(C, BitListVal, NamedBitList, TagIn). + + +int_to_bitlist(0) -> + []; +int_to_bitlist(Int) when is_integer(Int), Int >= 0 -> + [Int band 1 | int_to_bitlist(Int bsr 1)]. + + +%%================================================================= +%% Encode BIT STRING of the form {Unused,BinBits}. +%% Unused is the number of unused bits in the last byte in BinBits +%% and BinBits is a binary representing the BIT STRING. +%%================================================================= +encode_bin_bit_string(C,{Unused,BinBits},_NamedBitList,TagIn)-> + case get_constraint(C,'SizeConstraint') of + no -> + remove_unused_then_dotag(TagIn, Unused, BinBits); + {_Min,Max} -> + BBLen = (byte_size(BinBits)*8)-Unused, + if + BBLen > Max -> + exit({error,{asn1, + {bitstring_length, + {{was,BBLen},{maximum,Max}}}}}); + true -> + remove_unused_then_dotag(TagIn, Unused, BinBits) + end; + Size -> + case ((byte_size(BinBits)*8)-Unused) of + BBSize when BBSize =< Size -> + remove_unused_then_dotag(TagIn, Unused, BinBits); + BBSize -> + exit({error,{asn1, + {bitstring_length, + {{was,BBSize},{should_be,Size}}}}}) + end + end. + +remove_unused_then_dotag(TagIn,Unused,BinBits) -> + case Unused of + 0 when byte_size(BinBits) =:= 0 -> + encode_tags(TagIn, <<0>>, 1); + 0 -> + Bin = <>, + encode_tags(TagIn,Bin,size(Bin)); + Num -> + N = byte_size(BinBits)-1, + <> = BinBits, + encode_tags(TagIn, + [Unused,binary_to_list(BBits) ++[(LastByte bsr Num) bsl Num]], + 1+byte_size(BinBits)) + end. + + +%%================================================================= +%% Encode named bits +%%================================================================= + +encode_bit_string_named(C, [FirstVal | RestVal], NamedBitList, TagIn) -> + ToSetPos = get_all_bitposes([FirstVal | RestVal], NamedBitList, []), + Size = + case get_constraint(C,'SizeConstraint') of + no -> + lists:max(ToSetPos)+1; + {_Min,Max} -> + Max; + TSize -> + TSize + end, + BitList = make_and_set_list(Size, ToSetPos, 0), + {Len, Unused, OctetList} = encode_bitstring(BitList), + encode_tags(TagIn, [Unused|OctetList],Len+1). + + +%%---------------------------------------- +%% get_all_bitposes([list of named bits to set], named_bit_db, []) -> +%% [sorted_list_of_bitpositions_to_set] +%%---------------------------------------- + +get_all_bitposes([{bit,ValPos}|Rest], NamedBitList, Ack) -> + get_all_bitposes(Rest, NamedBitList, [ValPos | Ack ]); +get_all_bitposes([Val | Rest], NamedBitList, Ack) when is_atom(Val) -> + case lists:keyfind(Val, 1, NamedBitList) of + {_ValName, ValPos} -> + get_all_bitposes(Rest, NamedBitList, [ValPos | Ack]); + _ -> + exit({error,{asn1, {bitstring_namedbit, Val}}}) + end; +get_all_bitposes([], _NamedBitList, Ack) -> + lists:sort(Ack). + + +%%---------------------------------------- +%% make_and_set_list(Len of list to return, [list of positions to set to 1])-> +%% returns list of Len length, with all in SetPos set. +%% in positioning in list the first element is 0, the second 1 etc.., but +%% Len will make a list of length Len, not Len + 1. +%% BitList = make_and_set_list(C, ToSetPos, 0), +%%---------------------------------------- + +make_and_set_list(0, [], _) -> []; +make_and_set_list(0, _, _) -> + exit({error,{asn1,bitstring_sizeconstraint}}); +make_and_set_list(Len, [XPos|SetPos], XPos) -> + [1 | make_and_set_list(Len - 1, SetPos, XPos + 1)]; +make_and_set_list(Len, [Pos|SetPos], XPos) -> + [0 | make_and_set_list(Len - 1, [Pos | SetPos], XPos + 1)]; +make_and_set_list(Len, [], XPos) -> + [0 | make_and_set_list(Len - 1, [], XPos + 1)]. + + + + + + +%%================================================================= +%% Encode bit string for lists of ones and zeroes +%%================================================================= +encode_bit_string_bits(C, BitListVal, _NamedBitList, TagIn) when is_list(BitListVal) -> + case get_constraint(C,'SizeConstraint') of + no -> + {Len, Unused, OctetList} = encode_bitstring(BitListVal), + %%add unused byte to the Len + encode_tags(TagIn, [Unused | OctetList], Len+1); + Constr={Min,_Max} when is_integer(Min) -> + %% Max may be an integer or 'MAX' + encode_constr_bit_str_bits(Constr,BitListVal,TagIn); + {Constr={_,_},[]} ->%Constr={Min,Max} + %% constraint with extension mark + encode_constr_bit_str_bits(Constr,BitListVal,TagIn); + Constr={{_,_},{_,_}} ->%{{Min1,Max1},{Min2,Max2}} + %% constraint with extension mark + encode_constr_bit_str_bits(Constr,BitListVal,TagIn); + Size -> + case length(BitListVal) of + BitSize when BitSize == Size -> + {Len, Unused, OctetList} = encode_bitstring(BitListVal), + %%add unused byte to the Len + encode_tags(TagIn, [Unused | OctetList], Len+1); + BitSize when BitSize < Size -> + PaddedList = pad_bit_list(Size-BitSize,BitListVal), + {Len, Unused, OctetList} = encode_bitstring(PaddedList), + %%add unused byte to the Len + encode_tags(TagIn, [Unused | OctetList], Len+1); + BitSize -> + exit({error,{asn1, + {bitstring_length, {{was,BitSize},{should_be,Size}}}}}) + end + + end. + +encode_constr_bit_str_bits({{_Min1,Max1},{Min2,Max2}},BitListVal,TagIn) -> + BitLen = length(BitListVal), + case BitLen of + Len when Len > Max2 -> + exit({error,{asn1,{bitstring_length,{{was,BitLen}, + {maximum,Max2}}}}}); + Len when Len > Max1, Len < Min2 -> + exit({error,{asn1,{bitstring_length,{{was,BitLen}, + {not_allowed_interval, + Max1,Min2}}}}}); + _ -> + {Len, Unused, OctetList} = encode_bitstring(BitListVal), + %%add unused byte to the Len + encode_tags(TagIn, [Unused, OctetList], Len+1) + end; +encode_constr_bit_str_bits({Min,Max},BitListVal,TagIn) -> + BitLen = length(BitListVal), + if + BitLen > Max -> + exit({error,{asn1,{bitstring_length,{{was,BitLen}, + {maximum,Max}}}}}); + BitLen < Min -> + exit({error,{asn1,{bitstring_length,{{was,BitLen}, + {minimum,Max}}}}}); + true -> + {Len, Unused, OctetList} = encode_bitstring(BitListVal), + %%add unused byte to the Len + encode_tags(TagIn, [Unused, OctetList], Len+1) + end. + + +%% returns a list of length Size + length(BitListVal), with BitListVal +%% as the most significant elements followed by padded zero elements +pad_bit_list(Size, BitListVal) -> + Tail = lists:duplicate(Size,0), + lists:append(BitListVal, Tail). + +%%================================================================= +%% Do the actual encoding +%% ([bitlist]) -> {ListLen, UnusedBits, OctetList} +%%================================================================= + +encode_bitstring([B8, B7, B6, B5, B4, B3, B2, B1 | Rest]) -> + Val = (B8 bsl 7) bor (B7 bsl 6) bor (B6 bsl 5) bor (B5 bsl 4) bor + (B4 bsl 3) bor (B3 bsl 2) bor (B2 bsl 1) bor B1, + encode_bitstring(Rest, [Val], 1); +encode_bitstring(Val) -> + {Unused, Octet} = unused_bitlist(Val, 7, 0), + {1, Unused, [Octet]}. + +encode_bitstring([B8, B7, B6, B5, B4, B3, B2, B1 | Rest], Ack, Len) -> + Val = (B8 bsl 7) bor (B7 bsl 6) bor (B6 bsl 5) bor (B5 bsl 4) bor + (B4 bsl 3) bor (B3 bsl 2) bor (B2 bsl 1) bor B1, + encode_bitstring(Rest, [Ack | [Val]], Len + 1); +%%even multiple of 8 bits.. +encode_bitstring([], Ack, Len) -> + {Len, 0, Ack}; +%% unused bits in last octet +encode_bitstring(Rest, Ack, Len) -> + {Unused, Val} = unused_bitlist(Rest, 7, 0), + {Len + 1, Unused, [Ack | [Val]]}. + +%%%%%%%%%%%%%%%%%% +%% unused_bitlist([list of ones and zeros <= 7], 7, []) -> +%% {Unused bits, Last octet with bits moved to right} +unused_bitlist([], Trail, Ack) -> + {Trail + 1, Ack}; +unused_bitlist([Bit | Rest], Trail, Ack) -> + unused_bitlist(Rest, Trail - 1, (Bit bsl Trail) bor Ack). + + +%%============================================================================ +%% decode bitstring value +%% (Buffer, Range, NamedNumberList, HasTag, TotalLen) -> {Integer, Remain, RemovedBytes} +%%============================================================================ + +decode_compact_bit_string(Buffer, Range, NamedNumberList, Tags) -> + decode_restricted_string(Buffer, Range, ?N_BIT_STRING, Tags, + NamedNumberList, bin). + +decode_bit_string(Buffer, Range, NamedNumberList, Tags) -> + decode_restricted_string(Buffer, Range, ?N_BIT_STRING, Tags, + NamedNumberList, old). + + +decode_bit_string2(<<0>>, _NamedNumberList, BinOrOld) -> + case BinOrOld of + bin -> + {0,<<>>}; + _ -> + [] + end; +decode_bit_string2(<>, NamedNumberList, BinOrOld) -> + case NamedNumberList of + [] -> + case BinOrOld of + bin -> + {Unused,Bits}; + _ -> + decode_bitstring2(byte_size(Bits), Unused, Bits) + end; + _ -> + BitString = decode_bitstring2(byte_size(Bits), Unused, Bits), + decode_bitstring_NNL(BitString, NamedNumberList) + end. + +%%---------------------------------------- +%% Decode the in buffer to bits +%%---------------------------------------- +decode_bitstring2(1, Unused, + <>) -> + lists:sublist([B7,B6,B5,B4,B3,B2,B1,B0], 8-Unused); +decode_bitstring2(Len, Unused, + <>) -> + [B7,B6,B5,B4,B3,B2,B1,B0| + decode_bitstring2(Len - 1, Unused, Buffer)]. + +%%---------------------------------------- +%% Decode the bitlist to names +%%---------------------------------------- + +decode_bitstring_NNL(BitList, NamedNumberList) -> + decode_bitstring_NNL(BitList, NamedNumberList, 0, []). + + +decode_bitstring_NNL([],_,_No,Result) -> + lists:reverse(Result); +decode_bitstring_NNL([B|BitList],[{Name,No}|NamedNumberList],No,Result) -> + if + B =:= 0 -> + decode_bitstring_NNL(BitList,NamedNumberList,No+1,Result); + true -> + decode_bitstring_NNL(BitList,NamedNumberList,No+1,[Name|Result]) + end; +decode_bitstring_NNL([1|BitList],NamedNumberList,No,Result) -> + decode_bitstring_NNL(BitList,NamedNumberList,No+1,[{bit,No}|Result]); +decode_bitstring_NNL([0|BitList],NamedNumberList,No,Result) -> + decode_bitstring_NNL(BitList,NamedNumberList,No+1,Result). + +%%============================================================================ +%% decode octet string +%% (Buffer, Range, HasTag, TotalLen) -> {String, Remain, RemovedBytes} +%% +%% Octet string is decoded as a restricted string +%%============================================================================ +decode_octet_string(Buffer, Range, Tags) -> + decode_restricted_string(Buffer, Range, ?N_OCTET_STRING, + Tags, [], old). + +%%============================================================================ +%% Null value, ITU_T X.690 Chapter 8.8 +%% +%% encode NULL value +%%============================================================================ + +encode_null(_Val, TagIn) -> + encode_tags(TagIn, [], 0). + +%%============================================================================ +%% decode NULL value +%% (Buffer, HasTag, TotalLen) -> {NULL, Remain, RemovedBytes} +%%============================================================================ + +decode_null(Tlv, Tags) -> + Val = match_tags(Tlv, Tags), + case Val of + <<>> -> + 'NULL'; + _ -> + exit({error,{asn1,{decode_null,Val}}}) + end. + +%%============================================================================ +%% Object identifier, ITU_T X.690 Chapter 8.19 +%% +%% encode Object Identifier value +%%============================================================================ + +encode_object_identifier(Val, TagIn) -> + encode_tags(TagIn, e_object_identifier(Val)). + +e_object_identifier({'OBJECT IDENTIFIER', V}) -> + e_object_identifier(V); +e_object_identifier(V) when is_tuple(V) -> + e_object_identifier(tuple_to_list(V)); + +%%%%%%%%%%%%%%% +%% e_object_identifier([List of Obect Identifiers]) -> +%% {[Encoded Octetlist of ObjIds], IntLength} +%% +e_object_identifier([E1,E2|Tail]) -> + Head = 40*E1 + E2, % wow! + {H,Lh} = mk_object_val(Head), + {R,Lr} = lists:mapfoldl(fun enc_obj_id_tail/2, 0, Tail), + {[H|R],Lh+Lr}. + +enc_obj_id_tail(H, Len) -> + {B,L} = mk_object_val(H), + {B,Len+L}. + + +%%%%%%%%%%% +%% mk_object_val(Value) -> {OctetList, Len} +%% returns a Val as a list of octets, the 8th bit is always set to one +%% except for the last octet, where it's 0 +%% + + +mk_object_val(Val) when Val =< 127 -> + {[255 band Val], 1}; +mk_object_val(Val) -> + mk_object_val(Val bsr 7, [Val band 127], 1). +mk_object_val(0, Ack, Len) -> + {Ack, Len}; +mk_object_val(Val, Ack, Len) -> + mk_object_val(Val bsr 7, [((Val band 127) bor 128) | Ack], Len + 1). + + + +%%============================================================================ +%% decode Object Identifier value +%% (Buffer, HasTag, TotalLen) -> {{ObjId}, Remain, RemovedBytes} +%%============================================================================ + +decode_object_identifier(Tlv, Tags) -> + Val = match_tags(Tlv, Tags), + [AddedObjVal|ObjVals] = dec_subidentifiers(Val,0,[]), + {Val1, Val2} = if + AddedObjVal < 40 -> + {0, AddedObjVal}; + AddedObjVal < 80 -> + {1, AddedObjVal - 40}; + true -> + {2, AddedObjVal - 80} + end, + list_to_tuple([Val1, Val2 | ObjVals]). + +dec_subidentifiers(<<>>,_Av,Al) -> + lists:reverse(Al); +dec_subidentifiers(<<1:1,H:7,T/binary>>,Av,Al) -> + dec_subidentifiers(T,(Av bsl 7) + H,Al); +dec_subidentifiers(<>,Av,Al) -> + dec_subidentifiers(T,0,[((Av bsl 7) + H)|Al]). + +%%============================================================================ +%% RELATIVE-OID, ITU_T X.690 Chapter 8.20 +%% +%% encode Relative Object Identifier +%%============================================================================ + +encode_relative_oid(Val,TagIn) when is_tuple(Val) -> + encode_relative_oid(tuple_to_list(Val),TagIn); +encode_relative_oid(Val,TagIn) -> + encode_tags(TagIn, enc_relative_oid(Val)). + +enc_relative_oid(Tuple) when is_tuple(Tuple) -> + enc_relative_oid(tuple_to_list(Tuple)); +enc_relative_oid(Val) -> + lists:mapfoldl(fun(X,AccIn) -> + {SO,L} = mk_object_val(X), + {SO,L+AccIn} + end, 0, Val). + +%%============================================================================ +%% decode Relative Object Identifier value +%% (Buffer, HasTag, TotalLen) -> {{ObjId}, Remain, RemovedBytes} +%%============================================================================ +decode_relative_oid(Tlv, Tags) -> + Val = match_tags(Tlv, Tags), + ObjVals = dec_subidentifiers(Val,0,[]), + list_to_tuple(ObjVals). + +%%============================================================================ +%% Restricted character string types, ITU_T X.690 Chapter 8.20 +%% +%% encode Numeric Printable Teletex Videotex Visible IA5 Graphic General strings +%%============================================================================ +encode_restricted_string(OctetList, TagIn) when is_binary(OctetList) -> + encode_tags(TagIn, OctetList, byte_size(OctetList)); +encode_restricted_string(OctetList, TagIn) when is_list(OctetList) -> + encode_tags(TagIn, OctetList, length(OctetList)). + +%%============================================================================ +%% decode Numeric Printable Teletex Videotex Visible IA5 Graphic General strings +%% (Buffer, Range, StringType, HasTag, TotalLen) -> +%% {String, Remain, RemovedBytes} +%%============================================================================ + +decode_restricted_string(Buffer, Range, StringType, Tags) -> + decode_restricted_string(Buffer, Range, StringType, Tags, [], old). + +decode_restricted_string(Tlv, Range, StringType, TagsIn, + NamedNumberList, BinOrOld) -> + Val = match_tags(Tlv, TagsIn), + Val2 = + case Val of + [_|_]=PartList -> % constructed val + Bin = collect_parts(PartList), + decode_restricted(Bin, StringType, + NamedNumberList, BinOrOld); + Bin -> + decode_restricted(Bin, StringType, + NamedNumberList, BinOrOld) + end, + check_and_convert_restricted_string(Val2, StringType, Range, + NamedNumberList, BinOrOld). + +decode_restricted(Bin, StringType, NamedNumberList, BinOrOld) -> + case StringType of + ?N_BIT_STRING -> + decode_bit_string2(Bin, NamedNumberList, BinOrOld); + ?N_UniversalString -> + mk_universal_string(binary_to_list(Bin)); + ?N_BMPString -> + mk_BMP_string(binary_to_list(Bin)); + _ -> + Bin + end. + + +check_and_convert_restricted_string(Val,StringType,Range,NamedNumberList,_BinOrOld) -> + {StrLen,NewVal} = case StringType of + ?N_BIT_STRING when NamedNumberList =/= [] -> + {no_check,Val}; + ?N_BIT_STRING when is_list(Val) -> + {length(Val),Val}; + ?N_BIT_STRING when is_tuple(Val) -> + {(byte_size(element(2,Val))*8) - element(1,Val),Val}; + _ when is_binary(Val) -> + {byte_size(Val),binary_to_list(Val)}; + _ when is_list(Val) -> + {length(Val), Val} + end, + case Range of + _ when StrLen =:= no_check -> + NewVal; + [] -> % No length constraint + NewVal; + {Lb,Ub} when StrLen >= Lb, Ub >= StrLen -> % variable length constraint + NewVal; + {{Lb,_Ub},[]} when StrLen >= Lb -> + NewVal; + {{Lb,_Ub},_Ext=[Min|_]} when StrLen >= Lb; StrLen >= Min -> + NewVal; + {{Lb1,Ub1},{Lb2,Ub2}} when StrLen >= Lb1, StrLen =< Ub1; + StrLen =< Ub2, StrLen >= Lb2 -> + NewVal; + StrLen -> % fixed length constraint + NewVal; + {_,_} -> + exit({error,{asn1,{length,Range,Val}}}); + _Len when is_integer(_Len) -> + exit({error,{asn1,{length,Range,Val}}}); + _ -> % some strange constraint that we don't support yet + NewVal + end. + + +%%============================================================================ +%% encode Universal string +%%============================================================================ + +encode_universal_string(Universal, TagIn) -> + OctetList = mk_uni_list(Universal), + encode_tags(TagIn, OctetList, length(OctetList)). + +mk_uni_list(In) -> + mk_uni_list(In,[]). + +mk_uni_list([],List) -> + lists:reverse(List); +mk_uni_list([{A,B,C,D}|T],List) -> + mk_uni_list(T,[D,C,B,A|List]); +mk_uni_list([H|T],List) -> + mk_uni_list(T,[H,0,0,0|List]). + +%%=========================================================================== +%% decode Universal strings +%% (Buffer, Range, StringType, HasTag, LenIn) -> +%% {String, Remain, RemovedBytes} +%%=========================================================================== + +decode_universal_string(Buffer, Range, Tags) -> + decode_restricted_string(Buffer, Range, ?N_UniversalString, + Tags, [], old). + + +mk_universal_string(In) -> + mk_universal_string(In, []). + +mk_universal_string([], Acc) -> + lists:reverse(Acc); +mk_universal_string([0,0,0,D|T], Acc) -> + mk_universal_string(T, [D|Acc]); +mk_universal_string([A,B,C,D|T], Acc) -> + mk_universal_string(T, [{A,B,C,D}|Acc]). + + +%%============================================================================ +%% encode UTF8 string +%%============================================================================ + +encode_UTF8_string(UTF8String, TagIn) when is_binary(UTF8String) -> + encode_tags(TagIn, UTF8String, byte_size(UTF8String)); +encode_UTF8_string(UTF8String, TagIn) -> + encode_tags(TagIn, UTF8String, length(UTF8String)). + + +%%============================================================================ +%% decode UTF8 string +%%============================================================================ + +decode_UTF8_string(Tlv,TagsIn) -> + Val = match_tags(Tlv, TagsIn), + case Val of + [_|_]=PartList -> % constructed val + collect_parts(PartList); + Bin -> + Bin + end. + + +%%============================================================================ +%% encode BMP string +%%============================================================================ + +encode_BMP_string(BMPString, TagIn) -> + OctetList = mk_BMP_list(BMPString), + encode_tags(TagIn, OctetList, length(OctetList)). + +mk_BMP_list(In) -> + mk_BMP_list(In, []). + +mk_BMP_list([],List) -> + lists:reverse(List); +mk_BMP_list([{0,0,C,D}|T], List) -> + mk_BMP_list(T, [D,C|List]); +mk_BMP_list([H|T], List) -> + mk_BMP_list(T, [H,0|List]). + +%%============================================================================ +%% decode (OctetList, Range(ignored), tag|notag) -> {ValList, RestList} +%% (Buffer, Range, StringType, HasTag, TotalLen) -> +%% {String, Remain, RemovedBytes} +%%============================================================================ +decode_BMP_string(Buffer, Range, Tags) -> + decode_restricted_string(Buffer, Range, ?N_BMPString, + Tags, [], old). + +mk_BMP_string(In) -> + mk_BMP_string(In,[]). + +mk_BMP_string([], US) -> + lists:reverse(US); +mk_BMP_string([0,B|T], US) -> + mk_BMP_string(T, [B|US]); +mk_BMP_string([C,D|T], US) -> + mk_BMP_string(T, [{0,0,C,D}|US]). + + +%%============================================================================ +%% Generalized time, ITU_T X.680 Chapter 39 +%% +%% encode Generalized time +%%============================================================================ + +encode_generalized_time(OctetList, TagIn) -> + encode_tags(TagIn, OctetList, length(OctetList)). + +%%============================================================================ +%% decode Generalized time +%% (Buffer, Range, HasTag, TotalLen) -> {String, Remain, RemovedBytes} +%%============================================================================ + +decode_generalized_time(Tlv, _Range, Tags) -> + Val = match_tags(Tlv, Tags), + NewVal = case Val of + [_H|_T]=PartList -> % constructed + collect_parts(PartList); + Bin -> + Bin + end, + binary_to_list(NewVal). + +%%============================================================================ +%% Universal time, ITU_T X.680 Chapter 40 +%% +%% encode UTC time +%%============================================================================ + +encode_utc_time(OctetList, TagIn) -> + encode_tags(TagIn, OctetList, length(OctetList)). + +%%============================================================================ +%% decode UTC time +%% (Buffer, Range, HasTag, TotalLen) -> {String, Remain, RemovedBytes} +%%============================================================================ + +decode_utc_time(Tlv, _Range, Tags) -> + Val = match_tags(Tlv, Tags), + NewVal = case Val of + [_|_]=PartList -> % constructed + collect_parts(PartList); + Bin -> + Bin + end, + binary_to_list(NewVal). + + +%%============================================================================ +%% Length handling +%% +%% Encode length +%% +%% encode_length(Int) -> +%% [<127]| [128 + Int (<127),OctetList] | [16#80] +%%============================================================================ + +encode_length(L) when L =< 16#7F -> + {[L],1}; +encode_length(L) -> + Oct = minimum_octets(L), + Len = length(Oct), + if + Len =< 126 -> + {[16#80 bor Len|Oct],Len+1}; + true -> + exit({error,{asn1, too_long_length_oct, Len}}) + end. + +%% Val must be >= 0 +minimum_octets(Val) -> + minimum_octets(Val, []). + +minimum_octets(0, Acc) -> + Acc; +minimum_octets(Val, Acc) -> + minimum_octets(Val bsr 8, [Val band 16#FF|Acc]). + + +%%=========================================================================== +%% Decode length +%% +%% decode_length(OctetList) -> {{indefinite, RestOctetsL}, NoRemovedBytes} | +%% {{Length, RestOctetsL}, NoRemovedBytes} +%%=========================================================================== + +decode_length(<<1:1,0:7,T/binary>>) -> + {indefinite,T}; +decode_length(<<0:1,Length:7,T/binary>>) -> + {Length,T}; +decode_length(<<1:1,LL:7,Length:LL/unit:8,T/binary>>) -> + {Length,T}. + +%% dynamicsort_SET_components(Arg) -> +%% Res Arg -> list() +%% Res -> list() +%% Sorts the elements in Arg according to the encoded tag in +%% increasing order. +dynamicsort_SET_components(ListOfEncCs) -> + TagBinL = [begin + Bin = list_to_binary(L), + {dynsort_decode_tag(Bin),Bin} + end || L <- ListOfEncCs], + [E || {_,E} <- lists:keysort(1, TagBinL)]. + +%% dynamicsort_SETOF(Arg) -> Res +%% Arg -> list() +%% Res -> list() +%% Sorts the elements in Arg in increasing size +dynamicsort_SETOF(ListOfEncVal) -> + BinL = lists:map(fun(L) when is_list(L) -> list_to_binary(L); + (B) -> B end, ListOfEncVal), + lists:sort(BinL). + +%% multiple octet tag +dynsort_decode_tag(<>) -> + TagNum = dynsort_decode_tag(Buffer, 0), + {Class,TagNum}; + +%% single tag (< 31 tags) +dynsort_decode_tag(<>) -> + {Class,TagNum}. + +dynsort_decode_tag(<<0:1,PartialTag:7,_/binary>>, TagAcc) -> + (TagAcc bsl 7) bor PartialTag; +dynsort_decode_tag(<<_:1,PartialTag:7,Buffer/binary>>, TagAcc0) -> + TagAcc = (TagAcc0 bsl 7) bor PartialTag, + dynsort_decode_tag(Buffer, TagAcc). + + +%%------------------------------------------------------------------------- +%% INTERNAL HELPER FUNCTIONS (not exported) +%%------------------------------------------------------------------------- + +get_constraint(C, Key) -> + case lists:keyfind(Key, 1, C) of + false -> + no; + {_,V} -> + V + end. + +collect_parts(TlvList) -> + collect_parts(TlvList, []). + +collect_parts([{_,L}|Rest], Acc) when is_list(L) -> + collect_parts(Rest, [collect_parts(L)|Acc]); +collect_parts([{?N_BIT_STRING,<>}|Rest], _Acc) -> + collect_parts_bit(Rest, [Bits], Unused); +collect_parts([{_T,V}|Rest], Acc) -> + collect_parts(Rest, [V|Acc]); +collect_parts([], Acc) -> + list_to_binary(lists:reverse(Acc)). + +collect_parts_bit([{?N_BIT_STRING,<>}|Rest], Acc, Uacc) -> + collect_parts_bit(Rest, [Bits|Acc], Unused+Uacc); +collect_parts_bit([], Acc, Uacc) -> + list_to_binary([Uacc|lists:reverse(Acc)]). diff --git a/lib/asn1/src/asn1rtt_per.erl b/lib/asn1/src/asn1rtt_per.erl new file mode 100644 index 0000000000..d545c8a854 --- /dev/null +++ b/lib/asn1/src/asn1rtt_per.erl @@ -0,0 +1,1334 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(asn1rtt_per). + +-export([setext/1, fixextensions/2, + skipextensions/3, getbit/1, getchoice/3, + set_choice/3,encode_integer/2, + encode_small_number/1, + encode_length/1, + encode_length/2, + decode_compact_bit_string/3, + encode_bit_string/3, decode_bit_string/3, + encode_object_identifier/1, decode_object_identifier/1, + encode_relative_oid/1, decode_relative_oid/1, + complete/1, + encode_open_type/1, + encode_GeneralString/2, decode_GeneralString/2, + encode_GraphicString/2, decode_GraphicString/2, + encode_TeletexString/2, decode_TeletexString/2, + encode_VideotexString/2, decode_VideotexString/2, + encode_ObjectDescriptor/2, decode_ObjectDescriptor/1, + encode_UTF8String/1,decode_UTF8String/1, + encode_octet_string/3, + encode_known_multiplier_string/4, + decode_known_multiplier_string/5, + octets_to_complete/2]). + +-define('16K',16384). +-define('32K',32768). +-define('64K',65536). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% setext(true|false) -> CompleteList +%% + +setext(false) -> + [0]; +setext(true) -> + [1]. + +fixextensions({ext,ExtPos,ExtNum},Val) -> + case fixextensions(ExtPos,ExtNum+ExtPos,Val,0) of + 0 -> []; + ExtBits -> + [encode_small_length(ExtNum)|pre_complete_bits(ExtNum,ExtBits)] + end. + +fixextensions(Pos,MaxPos,_,Acc) when Pos >= MaxPos -> + Acc; +fixextensions(Pos,ExtPos,Val,Acc) -> + Bit = case catch(element(Pos+1,Val)) of + asn1_NOVALUE -> + 0; + asn1_NOEXTVALUE -> + 0; + {'EXIT',_} -> + 0; + _ -> + 1 + end, + fixextensions(Pos+1,ExtPos,Val,(Acc bsl 1)+Bit). + +skipextensions(Bytes0, Nr, ExtensionBitstr) when is_bitstring(ExtensionBitstr) -> + Prev = Nr - 1, + case ExtensionBitstr of + <<_:Prev,1:1,_/bitstring>> -> + {Len,Bytes1} = decode_length(Bytes0, undefined), + <<_:Len/binary,Bytes2/bitstring>> = Bytes1, + skipextensions(Bytes2, Nr+1, ExtensionBitstr); + <<_:Prev,0:1,_/bitstring>> -> + skipextensions(Bytes0, Nr+1, ExtensionBitstr); + _ -> + Bytes0 + end. + + +getchoice(Bytes, 1, 0) -> % only 1 alternative is not encoded + {0,Bytes}; +getchoice(Bytes, _, 1) -> + decode_small_number(Bytes); +getchoice(Bytes, NumChoices, 0) -> + decode_constrained_number(Bytes, {0,NumChoices-1}). + + +%% getbits_as_binary(Num,Bytes) -> {Bin,Rest} +%% Num = integer(), +%% Bytes = bitstring(), +%% Bin = bitstring(), +%% Rest = bitstring() +getbits_as_binary(Num,Bytes) when is_bitstring(Bytes) -> + <> = Bytes, + {BS,Rest}. + +getbits_as_list(Num,Bytes) when is_bitstring(Bytes) -> + <> = Bytes, + {[ B || <> <= BitStr],Rest}. + + +getbit(Buffer) -> + <> = Buffer, + {B,Rest}. + +getbits(Buffer, Num) when is_bitstring(Buffer) -> + <> = Buffer, + {Bs,Rest}. + +align(Bin) when is_binary(Bin) -> + Bin; +align(BitStr) when is_bitstring(BitStr) -> + AlignBits = bit_size(BitStr) rem 8, + <<_:AlignBits,Rest/binary>> = BitStr, + Rest. + + +%% First align buffer, then pick the first Num octets. +%% Returns octets as an integer with bit significance as in buffer. +getoctets(Buffer, Num) when is_binary(Buffer) -> + <> = Buffer, + {Val,RestBin}; +getoctets(Buffer, Num) when is_bitstring(Buffer) -> + AlignBits = bit_size(Buffer) rem 8, + <<_:AlignBits,Val:Num/integer-unit:8,RestBin/binary>> = Buffer, + {Val,RestBin}. + + +%% First align buffer, then pick the first Num octets. +%% Returns octets as a binary +getoctets_as_bin(Bin,Num) when is_binary(Bin) -> + <> = Bin, + {Octets,RestBin}; +getoctets_as_bin(Bin,Num) when is_bitstring(Bin) -> + AlignBits = bit_size(Bin) rem 8, + <<_:AlignBits,Val:Num/binary,RestBin/binary>> = Bin, + {Val,RestBin}. + + +%% same as above but returns octets as a List +getoctets_as_list(Buffer,Num) -> + {Bin,Buffer2} = getoctets_as_bin(Buffer,Num), + {binary_to_list(Bin),Buffer2}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% set_choice(Alt,Choices,Altnum) -> ListofBitSettings +%% Alt = atom() +%% Altnum = integer() | {integer(),integer()}% number of alternatives +%% Choices = [atom()] | {[atom()],[atom()]} +%% When Choices is a tuple the first list is the Rootset and the +%% second is the Extensions and then Altnum must also be a tuple with the +%% lengths of the 2 lists +%% +set_choice(Alt,{L1,L2},{Len1,_Len2}) -> + case set_choice_tag(Alt,L1) of + N when is_integer(N), Len1 > 1 -> + [0, % the value is in the root set + encode_constrained_number({0,Len1-1},N)]; + N when is_integer(N) -> + [0]; % no encoding if only 0 or 1 alternative + false -> + [1, % extension value + case set_choice_tag(Alt, L2) of + N2 when is_integer(N2) -> + encode_small_number(N2); + false -> + unknown_choice_alt + end] + end; +set_choice(Alt, L, Len) -> + case set_choice_tag(Alt, L) of + N when is_integer(N), Len > 1 -> + encode_constrained_number({0,Len-1},N); + N when is_integer(N) -> + []; % no encoding if only 0 or 1 alternative + false -> + [unknown_choice_alt] + end. + +set_choice_tag(Alt,Choices) -> + set_choice_tag(Alt,Choices,0). + +set_choice_tag(Alt,[Alt|_Rest],Tag) -> + Tag; +set_choice_tag(Alt,[_H|Rest],Tag) -> + set_choice_tag(Alt,Rest,Tag+1); +set_choice_tag(_Alt,[],_Tag) -> + false. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% decode_fragmented_XXX; decode of values encoded fragmented according +%% to ITU-T X.691 clause 10.9.3.8. The unit (XXX) is either bits, octets, +%% characters or number of components (in a choice,sequence or similar). +%% Buffer is a buffer binary(). +%% C is the constrained length. +%% If the buffer is not aligned, this function does that. +decode_fragmented_bits(Buffer, C) when is_binary(Buffer) -> + decode_fragmented_bits(Buffer, C, []); +decode_fragmented_bits(Buffer,C) when is_bitstring(Buffer) -> + AlignBits = bit_size(Buffer) rem 8, + <<_:AlignBits,Rest/binary>> = Buffer, + decode_fragmented_bits(Rest,C,[]). + +decode_fragmented_bits(<<3:2,Len:6,Bin/binary>>, C, Acc) -> + {Value,Bin2} = split_binary(Bin, Len * ?'16K'), % Len = 1 | 2 | 3 | 4 + decode_fragmented_bits(Bin2,C,[Value|Acc]); +decode_fragmented_bits(<<0:1,0:7,Bin/binary>>, C, Acc) -> + BinBits = erlang:list_to_bitstring(lists:reverse(Acc)), + case C of + Int when is_integer(Int), C =:= bit_size(BinBits) -> + {BinBits,Bin}; + Int when is_integer(Int) -> + exit({error,{asn1,{illegal_value,C,BinBits}}}) + end; +decode_fragmented_bits(<<0:1,Len:7,Bin/binary>>, C, Acc) -> + <> = Bin, + BinBits = erlang:list_to_bitstring([Value|Acc]), + case C of + Int when is_integer(Int), C =:= bit_size(BinBits) -> + {BinBits,Rest}; + Int when is_integer(Int) -> + exit({error,{asn1,{illegal_value,C,BinBits}}}) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% encode_open_type(Constraint, Value) -> CompleteList +%% Value = list of bytes of an already encoded value (the list must be flat) +%% | binary +%% Contraint = not used in this version +%% +encode_open_type(Val) when is_list(Val) -> + Bin = list_to_binary(Val), + case byte_size(Bin) of + Size when Size > 255 -> + [encode_length(Size),21,<>,Bin]; + Size -> + [encode_length(Size),20,Size,Bin] + end; +encode_open_type(Val) when is_binary(Val) -> + case byte_size(Val) of + Size when Size > 255 -> + [encode_length(Size),21,<>,Val]; % octets implies align + Size -> + [encode_length(Size),20,Size,Val] + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% encode_integer(Constraint, Value) -> CompleteList +%% +encode_integer([{Rc,_Ec}],Val) when is_tuple(Rc) -> + try + [0|encode_integer([Rc], Val)] + catch + _:{error,{asn1,_}} -> + [1|encode_unconstrained_number(Val)] + end; +encode_integer([], Val) -> + encode_unconstrained_number(Val); +%% The constraint is the effective constraint, and in this case is a number +encode_integer([{'SingleValue',V}], V) -> + []; +encode_integer([{'ValueRange',{Lb,Ub}=VR,Range,PreEnc}],Val) + when Val >= Lb, Ub >= Val -> + %% this case when NamedNumberList + encode_constrained_number(VR, Range, PreEnc, Val); +encode_integer([{'ValueRange',{Lb,'MAX'}}], Val) -> + encode_semi_constrained_number(Lb, Val); +encode_integer([{'ValueRange',{'MIN',_}}], Val) -> + encode_unconstrained_number(Val); +encode_integer([{'ValueRange',VR={_Lb,_Ub}}], Val) -> + encode_constrained_number(VR, Val); +encode_integer(_,Val) -> + exit({error,{asn1,{illegal_value,Val}}}). + + +%% X.691:10.6 Encoding of a normally small non-negative whole number +%% Use this for encoding of CHOICE index if there is an extension marker in +%% the CHOICE +encode_small_number(Val) when Val < 64 -> + [10,7,Val]; +encode_small_number(Val) -> + [1|encode_semi_constrained_number(0, Val)]. + +decode_small_number(Bytes) -> + {Bit,Bytes2} = getbit(Bytes), + case Bit of + 0 -> + getbits(Bytes2, 6); + 1 -> + decode_semi_constrained_number(Bytes2) + end. + +%% X.691:10.7 Encoding of a semi-constrained whole number +encode_semi_constrained_number(Lb, Val) -> + Val2 = Val - Lb, + Oct = eint_positive(Val2), + Len = length(Oct), + if + Len < 128 -> + [20,Len+1,Len|Oct]; + Len < 256 -> + [encode_length(Len),20,Len|Oct]; + true -> + [encode_length(Len),21,<>|Oct] + end. + +decode_semi_constrained_number(Bytes) -> + {Len,Bytes2} = decode_length(Bytes, undefined), + getoctets(Bytes2, Len). + +encode_constrained_number({Lb,_Ub},_Range,{bits,N},Val) -> + Val2 = Val-Lb, + [10,N,Val2]; +encode_constrained_number({Lb,_Ub},_Range,{octets,N},Val) when N < 256-> + %% N is 8 or 16 (1 or 2 octets) + Val2 = Val-Lb, + [20,N,Val2]; +encode_constrained_number({Lb,_Ub},_Range,{octets,N},Val) -> % N>255 + %% N is 8 or 16 (1 or 2 octets) + Val2 = Val-Lb, + [21,<>,Val2]; +encode_constrained_number({Lb,_Ub},Range,_,Val) -> + Val2 = Val-Lb, + if + Range =< 16#1000000 -> % max 3 octets + Octs = eint_positive(Val2), + L = length(Octs), + [encode_length({1,3},L),[20,L,Octs]]; + Range =< 16#100000000 -> % max 4 octets + Octs = eint_positive(Val2), + L = length(Octs), + [encode_length({1,4},L),[20,L,Octs]]; + Range =< 16#10000000000 -> % max 5 octets + Octs = eint_positive(Val2), + L = length(Octs), + [encode_length({1,5},L),[20,L,Octs]]; + true -> + exit({not_supported,{integer_range,Range}}) + end. + +encode_constrained_number({Lb,Ub}, Val) when Val >= Lb, Ub >= Val -> + Range = Ub - Lb + 1, + Val2 = Val - Lb, + if + Range == 1 -> []; + Range == 2 -> + [Val2]; + Range =< 4 -> + [10,2,Val2]; + Range =< 8 -> + [10,3,Val2]; + Range =< 16 -> + [10,4,Val2]; + Range =< 32 -> + [10,5,Val2]; + Range =< 64 -> + [10,6,Val2]; + Range =< 128 -> + [10,7,Val2]; + Range =< 255 -> + [10,8,Val2]; + Range =< 256 -> + [20,1,Val2]; + Range =< 65536 -> + [20,2,<>]; + Range =< (1 bsl (255*8)) -> + Octs = binary:encode_unsigned(Val2), + RangeOcts = binary:encode_unsigned(Range - 1), + OctsLen = byte_size(Octs), + RangeOctsLen = byte_size(RangeOcts), + LengthBitsNeeded = minimum_bits(RangeOctsLen - 1), + [10,LengthBitsNeeded,OctsLen-1,20,OctsLen,Octs]; + true -> + exit({not_supported,{integer_range,Range}}) + end; +encode_constrained_number({_,_},Val) -> + exit({error,{asn1,{illegal_value,Val}}}). + +decode_constrained_number(Buffer,VR={Lb,Ub}) -> + Range = Ub - Lb + 1, + decode_constrained_number(Buffer,VR,Range). + +decode_constrained_number(Buffer,{Lb,_Ub},Range) -> + % Val2 = Val - Lb, + {Val,Remain} = + if + Range == 1 -> + {0,Buffer}; + Range == 2 -> + getbits(Buffer,1); + Range =< 4 -> + getbits(Buffer,2); + Range =< 8 -> + getbits(Buffer,3); + Range =< 16 -> + getbits(Buffer,4); + Range =< 32 -> + getbits(Buffer,5); + Range =< 64 -> + getbits(Buffer,6); + Range =< 128 -> + getbits(Buffer,7); + Range =< 255 -> + getbits(Buffer,8); + Range =< 256 -> + getoctets(Buffer,1); + Range =< 65536 -> + getoctets(Buffer,2); + Range =< (1 bsl (255*8)) -> + OList = binary:bin_to_list(binary:encode_unsigned(Range - 1)), + RangeOctLen = length(OList), + {Len, Bytes} = decode_length(Buffer, {1, RangeOctLen}), + {Octs, RestBytes} = getoctets_as_bin(Bytes, Len), + {binary:decode_unsigned(Octs), RestBytes}; + true -> + exit({not_supported,{integer_range,Range}}) + end, + {Val+Lb,Remain}. + +%% For some reason the minimum bits needed in the length field in +%% the encoding of constrained whole numbers must always be at least 2? +minimum_bits(N) when N < 4 -> 2; +minimum_bits(N) when N < 8 -> 3; +minimum_bits(N) when N < 16 -> 4; +minimum_bits(N) when N < 32 -> 5; +minimum_bits(N) when N < 64 -> 6; +minimum_bits(N) when N < 128 -> 7; +minimum_bits(_N) -> 8. + +%% X.691:10.8 Encoding of an unconstrained whole number + +encode_unconstrained_number(Val) -> + Oct = if + Val >= 0 -> + eint(Val, []); + true -> + enint(Val, []) + end, + Len = length(Oct), + if + Len < 128 -> + [20,Len + 1,Len|Oct]; + Len < 256 -> + [20,Len + 2,<<2:2,Len:14>>|Oct]; + true -> + [encode_length(Len),21,<>|Oct] + end. + +%% used for positive Values which don't need a sign bit +%% returns a list +eint_positive(Val) -> + case eint(Val,[]) of + [0,B1|T] -> + [B1|T]; + T -> + T + end. + + +eint(0, [B|Acc]) when B < 128 -> + [B|Acc]; +eint(N, Acc) -> + eint(N bsr 8, [N band 16#ff| Acc]). + +enint(-1, [B1|T]) when B1 > 127 -> + [B1|T]; +enint(N, Acc) -> + enint(N bsr 8, [N band 16#ff|Acc]). + +%% X.691:10.9 Encoding of a length determinant +%%encode_small_length(undefined,Len) -> % null means no UpperBound +%% encode_small_number(Len). + +%% X.691:10.9.3.5 +%% X.691:10.9.3.7 +encode_length(Len) -> % unconstrained + if + Len < 128 -> + [20,1,Len]; + Len < 16384 -> + <<20,2,2:2,Len:14>>; + true -> % should be able to endode length >= 16384 i.e. fragmented length + exit({error,{asn1,{encode_length,{nyi,above_16k}}}}) + end. + +encode_length(undefined, Len) -> % un-constrained + encode_length(Len); +encode_length({0,'MAX'},Len) -> + encode_length(undefined,Len); +encode_length({Lb,Ub}=Vr, Len) when Ub =< 65535 ,Lb >= 0 -> % constrained + encode_constrained_number(Vr,Len); +encode_length({Lb,_Ub}, Len) when is_integer(Lb), Lb >= 0 -> % Ub > 65535 + encode_length(Len); +encode_length({{Lb,Ub}=Vr,Ext}, Len) + when Ub =< 65535 ,Lb >= 0,Len= + %% constrained extensible + [0|encode_constrained_number(Vr,Len)]; +encode_length({{Lb,_},Ext},Len) when is_list(Ext) -> + [1|encode_semi_constrained_number(Lb, Len)]; +encode_length(SingleValue, _Len) when is_integer(SingleValue) -> + []. + +%% X.691 10.9.3.4 (only used for length of bitmap that prefixes extension +%% additions in a sequence or set +encode_small_length(Len) when Len =< 64 -> + [10,7,Len-1]; +encode_small_length(Len) -> + [1,encode_length(Len)]. + + +decode_length(Buffer, undefined) -> % un-constrained + case align(Buffer) of + <<0:1,Oct:7,Rest/binary>> -> + {Oct,Rest}; + <<2:2,Val:14,Rest/binary>> -> + {Val,Rest}; + <<3:2,_Val:14,_Rest/binary>> -> + %% this case should be fixed + exit({error,{asn1,{decode_length,{nyi,above_16k}}}}) + end; + +decode_length(Buffer, {Lb,Ub}) when Ub =< 65535 ,Lb >= 0 -> % constrained + decode_constrained_number(Buffer, {Lb,Ub}); +decode_length(Buffer, {Lb,_Ub}) when is_integer(Lb), Lb >= 0 -> % Ub > 65535 + decode_length(Buffer,undefined); +decode_length(Buffer, {{Lb,Ub},Ext}) when is_list(Ext) -> + case getbit(Buffer) of + {0,Buffer2} -> + decode_length(Buffer2, {Lb,Ub}); + {1,Buffer2} -> + decode_length(Buffer2, undefined) + end; + +%When does this case occur with {_,_Lb,Ub} ?? +% X.691:10.9.3.5 +decode_length(Bin, {_,_Lb,_Ub}) -> % Unconstrained or large Ub NOTE! this case does not cover case when Ub > 65535 + case Bin of + <<0:1,Val:7,Rest/bitstring>> -> + {Val,Rest}; + _ -> + case align(Bin) of + <<2:2,Val:14,Rest/binary>> -> + {Val,Rest}; + <<3:2,_:14,_Rest/binary>> -> + exit({error,{asn1,{decode_length,{nyi,length_above_64K}}}}) + end + end; +decode_length(Buffer, SingleValue) when is_integer(SingleValue) -> + {SingleValue,Buffer}. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% bitstring NamedBitList +%% Val can be of: +%% - [identifiers] where only named identifers are set to one, +%% the Constraint must then have some information of the +%% bitlength. +%% - [list of ones and zeroes] all bits +%% - integer value representing the bitlist +%% C is constraint Len, only valid when identifiers + + +%% when the value is a list of {Unused,BinBits}, where +%% Unused = integer(), +%% BinBits = binary(). + +encode_bit_string(C, {Unused,BinBits}=Bin, NamedBitList) + when is_integer(Unused), is_binary(BinBits) -> + encode_bin_bit_string(C,Bin,NamedBitList); + +%% when the value is a list of named bits + +encode_bit_string(C, LoNB=[FirstVal | _RestVal], NamedBitList) when is_atom(FirstVal) -> + ToSetPos = get_all_bitposes(LoNB, NamedBitList, []), + BitList = make_and_set_list(ToSetPos,0), + encode_bit_string(C,BitList,NamedBitList);% consider the constraint + +encode_bit_string(C, BL=[{bit,_} | _RestVal], NamedBitList) -> + ToSetPos = get_all_bitposes(BL, NamedBitList, []), + BitList = make_and_set_list(ToSetPos,0), + encode_bit_string(C,BitList,NamedBitList); + +%% when the value is a list of ones and zeroes +encode_bit_string(Int, BitListValue, _) + when is_list(BitListValue),is_integer(Int),Int =< 16 -> + %% The type is constrained by a single value size constraint + %% range_check(Int,length(BitListValue)), + [40,Int,length(BitListValue),BitListValue]; +encode_bit_string(Int, BitListValue, _) + when is_list(BitListValue),is_integer(Int), Int =< 255 -> + %% The type is constrained by a single value size constraint + %% range_check(Int,length(BitListValue)), + [2,40,Int,length(BitListValue),BitListValue]; +encode_bit_string(Int, BitListValue, _) + when is_list(BitListValue),is_integer(Int), Int < ?'64K' -> + {Code,DesiredLength,Length} = + case length(BitListValue) of + B1 when B1 > Int -> + exit({error,{'BIT_STRING_length_greater_than_SIZE', + Int,BitListValue}}); + B1 when B1 =< 255,Int =< 255 -> + {40,Int,B1}; + B1 when B1 =< 255 -> + {42,<>,B1}; + B1 -> + {43,<>,<>} + end, + %% The type is constrained by a single value size constraint + [2,Code,DesiredLength,Length,BitListValue]; +encode_bit_string(no, BitListValue,[]) + when is_list(BitListValue) -> + [encode_length(length(BitListValue)), + 2|BitListValue]; +encode_bit_string({{Fix,Fix},Ext}, BitListValue,[]) + when is_integer(Fix), is_list(Ext) -> + case length(BitListValue) of + Len when Len =< Fix -> + [0|encode_bit_string(Fix, BitListValue, [])]; + _ -> + [1|encode_bit_string(no, BitListValue, [])] + end; +encode_bit_string(C, BitListValue,[]) + when is_list(BitListValue) -> + [encode_length(C, length(BitListValue)), + 2|BitListValue]; +encode_bit_string(no, BitListValue,_NamedBitList) + when is_list(BitListValue) -> + %% this case with an unconstrained BIT STRING can be made more efficient + %% if the complete driver can take a special code so the length field + %% is encoded there. + NewBitLVal = lists:reverse(lists:dropwhile(fun(0)->true;(1)->false end, + lists:reverse(BitListValue))), + [encode_length(length(NewBitLVal)),2|NewBitLVal]; +encode_bit_string({{Fix,Fix},Ext}, BitListValue, NamedBitList) + when is_integer(Fix), is_list(Ext) -> + case length(BitListValue) of + Len when Len =< Fix -> + [0|encode_bit_string(Fix, BitListValue, NamedBitList)]; + _ -> + [1|encode_bit_string(no, BitListValue, NamedBitList)] + end; +encode_bit_string(C, BitListValue, _NamedBitList) + when is_list(BitListValue) -> % C = {_,'MAX'} + NewBitLVal = bit_string_trailing_zeros(BitListValue, C), + [encode_length(C, length(NewBitLVal)),2|NewBitLVal]; + + +%% when the value is an integer +encode_bit_string(C, IntegerVal, NamedBitList) when is_integer(IntegerVal)-> + BitList = int_to_bitlist(IntegerVal), + encode_bit_string(C,BitList,NamedBitList). + +bit_string_trailing_zeros(BitList,C) when is_integer(C) -> + bit_string_trailing_zeros1(BitList,C,C); +bit_string_trailing_zeros(BitList,{Lb,Ub}) when is_integer(Lb) -> + bit_string_trailing_zeros1(BitList,Lb,Ub); +bit_string_trailing_zeros(BitList,{{Lb,Ub},_}) when is_integer(Lb) -> + bit_string_trailing_zeros1(BitList,Lb,Ub); +bit_string_trailing_zeros(BitList,_) -> + BitList. + +bit_string_trailing_zeros1(BitList,Lb,Ub) -> + case length(BitList) of + Lb -> BitList; + B when B < Lb -> BitList++lists:duplicate(Lb-B, 0); + D -> F = fun(L,LB,LB,_,_)->lists:reverse(L); + ([0|R],L1,LB,UB,Fun)->Fun(R,L1-1,LB,UB,Fun); + (L,L1,_,UB,_)when L1 =< UB -> lists:reverse(L); + (_,_L1,_,_,_) ->exit({error,{list_length_BIT_STRING, + BitList}}) end, + F(lists:reverse(BitList),D,Lb,Ub,F) + end. + +%% encode_bin_bit_string/3, when value is a tuple of Unused and BinBits. +%% Unused = integer(),i.e. number unused bits in least sign. byte of +%% BinBits = binary(). +encode_bin_bit_string(C, {Unused,BinBits}, _NamedBitList) + when is_integer(C),C=<16 -> + range_check(C, bit_size(BinBits) - Unused), + [45,C,size(BinBits),BinBits]; +encode_bin_bit_string(C, {Unused,BinBits}, _NamedBitList) + when is_integer(C), C =< 255 -> + range_check(C, bit_size(BinBits) - Unused), + [2,45,C,size(BinBits),BinBits]; +encode_bin_bit_string(C, {Unused,BinBits}, _NamedBitList) + when is_integer(C), C =< 65535 -> + range_check(C, bit_size(BinBits) - Unused), + case byte_size(BinBits) of + Size when Size =< 255 -> + [2,46,<>,Size,BinBits]; + Size -> + [2,47,<>,<>,BinBits] + end; +encode_bin_bit_string(C,UnusedAndBin={_,_},NamedBitList) -> + {Unused1,Bin1} = + %% removes all trailing bits if NamedBitList is not empty + remove_trailing_bin(NamedBitList,UnusedAndBin), + case C of + {Lb,Ub} when is_integer(Lb),is_integer(Ub) -> + Size = byte_size(Bin1), + [encode_length({Lb,Ub}, Size*8 - Unused1), + 2,octets_unused_to_complete(Unused1,Size,Bin1)]; + no -> + Size = byte_size(Bin1), + [encode_length(Size*8 - Unused1), + 2|octets_unused_to_complete(Unused1, Size, Bin1)]; + {{Fix,Fix},Ext} when is_integer(Fix),is_list(Ext) -> + case byte_size(Bin1)*8 - Unused1 of + Size when Size =< Fix -> + [0|encode_bin_bit_string(Fix,UnusedAndBin,NamedBitList)]; + _Size -> + [1|encode_bin_bit_string(no,UnusedAndBin,NamedBitList)] + end; + Sc -> + Size = byte_size(Bin1), + [encode_length(Sc, Size*8 - Unused1), + 2|octets_unused_to_complete(Unused1,Size,Bin1)] + end. + +range_check(C,C) when is_integer(C) -> + ok; +range_check(C1,C2) when is_integer(C1) -> + exit({error,{asn1,{bit_string_out_of_range,{C1,C2}}}}). + +remove_trailing_bin([], {Unused,Bin}) -> + {Unused,Bin}; +remove_trailing_bin(_NamedNumberList,{_Unused,<<>>}) -> + {0,<<>>}; +remove_trailing_bin(NamedNumberList, {_Unused,Bin}) -> + Size = byte_size(Bin)-1, + <> = Bin, + %% clear the Unused bits to be sure + Unused1 = trailingZeroesInNibble(LastByte band 15), + Unused2 = + case Unused1 of + 4 -> + 4 + trailingZeroesInNibble(LastByte bsr 4); + _ -> Unused1 + end, + case Unused2 of + 8 -> + remove_trailing_bin(NamedNumberList,{0,Bfront}); + _ -> + {Unused2,Bin} + end. + + +trailingZeroesInNibble(0) -> + 4; +trailingZeroesInNibble(1) -> + 0; +trailingZeroesInNibble(2) -> + 1; +trailingZeroesInNibble(3) -> + 0; +trailingZeroesInNibble(4) -> + 2; +trailingZeroesInNibble(5) -> + 0; +trailingZeroesInNibble(6) -> + 1; +trailingZeroesInNibble(7) -> + 0; +trailingZeroesInNibble(8) -> + 3; +trailingZeroesInNibble(9) -> + 0; +trailingZeroesInNibble(10) -> + 1; +trailingZeroesInNibble(11) -> + 0; +trailingZeroesInNibble(12) -> %#1100 + 2; +trailingZeroesInNibble(13) -> + 0; +trailingZeroesInNibble(14) -> + 1; +trailingZeroesInNibble(15) -> + 0. + +%%%%%%%%%%%%%%% +%% The result is presented as a list of named bits (if possible) +%% else as a tuple {Unused,Bits}. Unused is the number of unused +%% bits, least significant bits in the last byte of Bits. Bits is +%% the BIT STRING represented as a binary. +%% +decode_compact_bit_string(Buffer, C, NamedNumberList) -> + case get_constraint(C,'SizeConstraint') of + 0 -> % fixed length + {{8,0},Buffer}; + V when is_integer(V),V=<16 -> %fixed length 16 bits or less + compact_bit_string(Buffer,V,NamedNumberList); + V when is_integer(V),V=<65536 -> %fixed length > 16 bits + Bytes2 = align(Buffer), + compact_bit_string(Bytes2,V,NamedNumberList); + V when is_integer(V) -> % V > 65536 => fragmented value + {BitStr,Buffer2} = decode_fragmented_bits(Buffer,V), + case bit_size(BitStr) band 7 of + 0 -> {{0,BitStr},Buffer2}; + N -> {{8-N,<>},Buffer2} + end; + {Lb,Ub} when is_integer(Lb),is_integer(Ub) -> + %% This case may demand decoding of fragmented length/value + {Len,Bytes2} = decode_length(Buffer, {Lb,Ub}), + Bytes3 = align(Bytes2), + compact_bit_string(Bytes3,Len,NamedNumberList); + no -> + %% This case may demand decoding of fragmented length/value + {Len,Bytes2} = decode_length(Buffer, undefined), + Bytes3 = align(Bytes2), + compact_bit_string(Bytes3,Len,NamedNumberList); + {{Fix,Fix},Ext} = Sc when is_integer(Fix), is_list(Ext) -> + case decode_length(Buffer,Sc) of + {Len,Bytes2} when Len > Fix -> + Bytes3 = align(Bytes2), + compact_bit_string(Bytes3,Len,NamedNumberList); + {Len,Bytes2} when Len > 16 -> + Bytes3 = align(Bytes2), + compact_bit_string(Bytes3,Len,NamedNumberList); + {Len,Bytes2} -> + compact_bit_string(Bytes2,Len,NamedNumberList) + end; + Sc -> + {Len,Bytes2} = decode_length(Buffer,Sc), + Bytes3 = align(Bytes2), + compact_bit_string(Bytes3,Len,NamedNumberList) + end. + + +%%%%%%%%%%%%%%% +%% The result is presented as a list of named bits (if possible) +%% else as a list of 0 and 1. +%% +decode_bit_string(Buffer, C, NamedNumberList) -> + case get_constraint(C,'SizeConstraint') of + {Lb,Ub} when is_integer(Lb),is_integer(Ub) -> + {Len,Bytes2} = decode_length(Buffer,{Lb,Ub}), + Bytes3 = align(Bytes2), + bit_list_or_named(Bytes3,Len,NamedNumberList); + no -> + {Len,Bytes2} = decode_length(Buffer,undefined), + Bytes3 = align(Bytes2), + bit_list_or_named(Bytes3,Len,NamedNumberList); + 0 -> % fixed length + {[],Buffer}; % nothing to encode + V when is_integer(V),V=<16 -> % fixed length 16 bits or less + bit_list_or_named(Buffer,V,NamedNumberList); + V when is_integer(V),V=<65536 -> + Bytes2 = align(Buffer), + bit_list_or_named(Bytes2,V,NamedNumberList); + V when is_integer(V) -> + Bytes2 = align(Buffer), + {BinBits,_Bytes3} = decode_fragmented_bits(Bytes2,V), + bit_list_or_named(BinBits,V,NamedNumberList); + {{Fix,Fix},Ext} =Sc when is_integer(Fix), is_list(Ext) -> + case decode_length(Buffer,Sc) of + {Len,Bytes2} when Len > Fix -> + Bytes3 = align(Bytes2), + bit_list_or_named(Bytes3,Len,NamedNumberList); + {Len,Bytes2} when Len > 16 -> + Bytes3 = align(Bytes2), + bit_list_or_named(Bytes3,Len,NamedNumberList); + {Len,Bytes2} -> + bit_list_or_named(Bytes2,Len,NamedNumberList) + end; + Sc -> % extension marker + {Len,Bytes2} = decode_length(Buffer,Sc), + Bytes3 = align(Bytes2), + bit_list_or_named(Bytes3,Len,NamedNumberList) + end. + + +%% if no named bits are declared we will return a +%% {Unused,Bits}. Unused = integer(), +%% Bits = binary(). +compact_bit_string(Buffer,Len,[]) -> + {BitStr,Rest} = getbits_as_binary(Len,Buffer), % {{Unused,BinBits},NewBuffer} + PadLen = (8 - (bit_size(BitStr) rem 8)) rem 8, + {{PadLen,<>},Rest}; +compact_bit_string(Buffer,Len,NamedNumberList) -> + bit_list_or_named(Buffer,Len,NamedNumberList). + + +%% if no named bits are declared we will return a +%% BitList = [0 | 1] + +bit_list_or_named(Buffer,Len,[]) -> + getbits_as_list(Len,Buffer); + +%% if there are named bits declared we will return a named +%% BitList where the names are atoms and unnamed bits represented +%% as {bit,Pos} +%% BitList = [atom() | {bit,Pos}] +%% Pos = integer() + +bit_list_or_named(Buffer,Len,NamedNumberList) -> + {BitList,Rest} = getbits_as_list(Len,Buffer), + {bit_list_or_named1(0,BitList,NamedNumberList,[]), Rest}. + +bit_list_or_named1(Pos,[0|Bt],Names,Acc) -> + bit_list_or_named1(Pos+1,Bt,Names,Acc); +bit_list_or_named1(Pos,[1|Bt],Names,Acc) -> + case lists:keyfind(Pos, 2, Names) of + {Name,_} -> + bit_list_or_named1(Pos+1,Bt,Names,[Name|Acc]); + false -> + bit_list_or_named1(Pos+1,Bt,Names,[{bit,Pos}|Acc]) + end; +bit_list_or_named1(_Pos,[],_Names,Acc) -> + lists:reverse(Acc). + + + +%%%%%%%%%%%%%%% +%% + +int_to_bitlist(Int) when is_integer(Int), Int > 0 -> + [Int band 1 | int_to_bitlist(Int bsr 1)]; +int_to_bitlist(0) -> + []. + + +%%%%%%%%%%%%%%%%%% +%% get_all_bitposes([list of named bits to set], named_bit_db, []) -> +%% [sorted_list_of_bitpositions_to_set] + +get_all_bitposes([{bit,ValPos}|Rest], NamedBitList, Ack) -> + get_all_bitposes(Rest, NamedBitList, [ValPos | Ack ]); + +get_all_bitposes([Val | Rest], NamedBitList, Ack) -> + case lists:keyfind(Val, 1, NamedBitList) of + {_ValName, ValPos} -> + get_all_bitposes(Rest, NamedBitList, [ValPos | Ack]); + false -> + exit({error,{asn1, {bitstring_namedbit, Val}}}) + end; +get_all_bitposes([], _NamedBitList, Ack) -> + lists:sort(Ack). + +%%%%%%%%%%%%%%%%%% +%% make_and_set_list([list of positions to set to 1])-> +%% returns list with all in SetPos set. +%% in positioning in list the first element is 0, the second 1 etc.., but +%% + +make_and_set_list([XPos|SetPos], XPos) -> + [1 | make_and_set_list(SetPos, XPos + 1)]; +make_and_set_list([Pos|SetPos], XPos) -> + [0 | make_and_set_list([Pos | SetPos], XPos + 1)]; +make_and_set_list([], _) -> + []. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% X.691:16 +%% encode_octet_string(Constraint,ExtensionMarker,Val) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +encode_octet_string(_C, true, _Val) -> + exit({error,{asn1,{'not_supported',extensionmarker}}}); +encode_octet_string({_,_}=SZ, false, Val) -> + Len = length(Val), + try + [encode_length(SZ, Len),2|octets_to_complete(Len, Val)] + catch + exit:{error,{asn1,{encode_length,_}}} -> + encode_fragmented_octet_string(Val) + end; +encode_octet_string(SZ, false, Val) when is_list(SZ) -> + Len = length(Val), + try + [encode_length({hd(SZ),lists:max(SZ)},Len),2| + octets_to_complete(Len,Val)] + catch + exit:{error,{asn1,{encode_length,_}}} -> + encode_fragmented_octet_string(Val) + end; +encode_octet_string(Sv, false, Val) when is_integer(Sv) -> + encode_fragmented_octet_string(Val); +encode_octet_string(no, false, Val) -> + Len = length(Val), + try + [encode_length(Len),2|octets_to_complete(Len, Val)] + catch + exit:{error,{asn1,{encode_length,_}}} -> + encode_fragmented_octet_string(Val) + end; +encode_octet_string(C, _, _) -> + exit({error,{not_implemented,C}}). + +encode_fragmented_octet_string(Val) -> + Bin = iolist_to_binary(Val), + efos_1(Bin). + +efos_1(<>) -> + [20,1,<<3:2,4:6>>, + octets_to_complete(16#C000, B1), + octets_to_complete(16#4000, B2)|efos_1(T)]; +efos_1(<>) -> + [20,1,<<3:2,3:6>>,octets_to_complete(16#C000, B)|efos_1(T)]; +efos_1(<>) -> + [20,1,<<3:2,2:6>>,octets_to_complete(16#8000, B)|efos_1(T)]; +efos_1(<>) -> + [20,1,<<3:2,1:6>>,octets_to_complete(16#4000, B)|efos_1(T)]; +efos_1(<<>>) -> + [20,1,0]; +efos_1(<>) -> + Len = byte_size(B), + [encode_length(Len)|octets_to_complete(Len, B)]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Restricted char string types +%% (NumericString, PrintableString,VisibleString,IA5String,BMPString,UniversalString) +%% X.691:26 and X.680:34-36 + +encode_restricted_string(Val) when is_list(Val)-> + Len = length(Val), + [encode_length(Len)|octets_to_complete(Len, Val)]. + +encode_known_multiplier_string(SizeC, NumBits, CharOutTab, Val) -> + Result = chars_encode2(Val, NumBits, CharOutTab), + case SizeC of + Ub when is_integer(Ub), Ub*NumBits =< 16 -> + Result; + Ub when is_integer(Ub), Ub =<65535 -> % fixed length + [2,Result]; + {Ub,Lb} -> + [encode_length({Ub,Lb},length(Val)),2,Result]; + no -> + [encode_length(length(Val)),2,Result] + end. + +decode_restricted_string(Bytes,aligned) -> + {Len,Bytes2} = decode_length(Bytes,undefined), + getoctets_as_list(Bytes2,Len). + +decode_known_multiplier_string(StringType,SizeC,NumBits,CharInTab,Bytes) -> + case SizeC of + Ub when is_integer(Ub), Ub*NumBits =< 16 -> + chars_decode(Bytes,NumBits,StringType,CharInTab,Ub); + Ub when is_integer(Ub),Ub =<65535 -> % fixed length + Bytes1 = align(Bytes), + chars_decode(Bytes1,NumBits,StringType,CharInTab,Ub); + Vl when is_list(Vl) -> + {Len,Bytes1} = decode_length(Bytes,{hd(Vl),lists:max(Vl)}), + Bytes2 = align(Bytes1), + chars_decode(Bytes2,NumBits,StringType,CharInTab,Len); + no -> + {Len,Bytes1} = decode_length(Bytes,undefined), + Bytes2 = align(Bytes1), + chars_decode(Bytes2,NumBits,StringType,CharInTab,Len); + {Lb,Ub}-> + {Len,Bytes1} = decode_length(Bytes,{Lb,Ub}), + Bytes2 = align(Bytes1), + chars_decode(Bytes2,NumBits,StringType,CharInTab,Len) + end. + +encode_GeneralString(_C,Val) -> + encode_restricted_string(Val). +decode_GeneralString(Bytes,_C) -> + decode_restricted_string(Bytes,aligned). + +encode_GraphicString(_C,Val) -> + encode_restricted_string(Val). +decode_GraphicString(Bytes,_C) -> + decode_restricted_string(Bytes,aligned). + +encode_ObjectDescriptor(_C,Val) -> + encode_restricted_string(Val). +decode_ObjectDescriptor(Bytes) -> + decode_restricted_string(Bytes,aligned). + +encode_TeletexString(_C,Val) -> % equivalent with T61String + encode_restricted_string(Val). +decode_TeletexString(Bytes,_C) -> + decode_restricted_string(Bytes,aligned). + +encode_VideotexString(_C,Val) -> + encode_restricted_string(Val). +decode_VideotexString(Bytes,_C) -> + decode_restricted_string(Bytes,aligned). + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% getBMPChars(Bytes,Len) ->{BMPcharList,RemainingBytes} +%% +getBMPChars(<>, 0, Acc) -> + {lists:reverse(Acc),T}; +getBMPChars(<<0,O2,Bytes1/bitstring>>, Len, Acc) -> + getBMPChars(Bytes1,Len-1,[O2|Acc]); +getBMPChars(<>, Len, Acc) -> + getBMPChars(Bytes1,Len-1,[{0,0,O1,O2}|Acc]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% chars_encode(C,StringType,Value) -> ValueList +%% +%% encodes chars according to the per rules taking the constraint +%% PermittedAlphabet into account. +%% +%% This function only encodes the value part and NOT the length. + +chars_encode2([H|T],NumBits,T1={Min,Max,notab}) when H =< Max, H >= Min -> + [pre_complete_bits(NumBits,H-Min)|chars_encode2(T,NumBits,T1)]; +chars_encode2([H|T],NumBits,T1={Min,Max,Tab}) when H =< Max, H >= Min -> + [pre_complete_bits(NumBits,exit_if_false(H,element(H-Min+1,Tab)))| + chars_encode2(T,NumBits,T1)]; +chars_encode2([{A,B,C,D}|T],NumBits,T1={Min,_Max,notab}) -> + %% no value range check here (ought to be, but very expensive) + [pre_complete_bits(NumBits, + ((((((A bsl 8)+B) bsl 8)+C) bsl 8)+D)-Min)| + chars_encode2(T,NumBits,T1)]; +chars_encode2([H={A,B,C,D}|T],NumBits,{Min,Max,Tab}) -> + %% no value range check here (ought to be, but very expensive) + [pre_complete_bits(NumBits,exit_if_false(H,element(((((((A bsl 8)+B) bsl 8)+C) bsl 8)+D)-Min,Tab)))|chars_encode2(T,NumBits,{Min,Max,notab})]; +chars_encode2([H|_T],_NumBits,{_Min,_Max,_Tab}) -> + exit({error,{asn1,{illegal_char_value,H}}}); +chars_encode2([],_,_) -> + []. + +exit_if_false(V,false)-> + exit({error,{asn1,{"illegal value according to Permitted alphabet constraint",V}}}); +exit_if_false(_,V) ->V. + +pre_complete_bits(NumBits,Val) when NumBits =< 8 -> + [10,NumBits,Val]; +pre_complete_bits(NumBits,Val) when NumBits =< 16 -> + [10,NumBits-8,Val bsr 8,10,8,(Val band 255)]; +pre_complete_bits(NumBits,Val) when NumBits =< 2040 -> % 255 * 8 + Unused = (8 - (NumBits rem 8)) rem 8, + Len = NumBits + Unused, + [30,Unused,Len div 8,<<(Val bsl Unused):Len>>]. + + +chars_decode(Bytes,_,'BMPString',_,Len) -> + getBMPChars(Bytes,Len,[]); +chars_decode(Bytes,NumBits,_StringType,CharInTab,Len) -> + chars_decode2(Bytes,CharInTab,NumBits,Len). + + +chars_decode2(Bytes,CharInTab,NumBits,Len) -> + chars_decode2(Bytes,CharInTab,NumBits,Len,[]). + +chars_decode2(Bytes,_CharInTab,_NumBits,0,Acc) -> + {lists:reverse(Acc),Bytes}; +chars_decode2(Bytes,{Min,Max,notab},NumBits,Len,Acc) when NumBits > 8 -> + {Char,Bytes2} = getbits(Bytes,NumBits), + Result = + if + Char < 256 -> Char; + true -> + list_to_tuple(binary_to_list(<>)) + end, + chars_decode2(Bytes2,{Min,Max,notab},NumBits,Len -1,[Result|Acc]); +chars_decode2(Bytes,{Min,Max,notab},NumBits,Len,Acc) -> + {Char,Bytes2} = getbits(Bytes,NumBits), + chars_decode2(Bytes2,{Min,Max,notab},NumBits,Len -1,[Char+Min|Acc]); + +%% BMPString and UniversalString with PermittedAlphabet is currently not supported +chars_decode2(Bytes,{Min,Max,CharInTab},NumBits,Len,Acc) -> + {Char,Bytes2} = getbits(Bytes,NumBits), + chars_decode2(Bytes2,{Min,Max,CharInTab},NumBits,Len -1,[element(Char+1,CharInTab)|Acc]). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% encode_UTF8String(Val) -> CompleteList +%% Val -> <> +%% CompleteList -> [apropriate codes and values for driver complete] +%% +encode_UTF8String(Val) when is_binary(Val) -> + Sz = byte_size(Val), + [encode_length(Sz),octets_to_complete(Sz, Val)]; +encode_UTF8String(Val) -> + encode_UTF8String(list_to_binary(Val)). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% decode_UTF8String(Bytes) -> {Utf8Binary,RemainingBytes} +%% Utf8Binary -> <> +%% RemainingBytes -> <> +decode_UTF8String(Bytes) -> + {Len,Bytes2} = decode_length(Bytes, undefined), + {_Bin,_Bytes3} = getoctets_as_bin(Bytes2, Len). + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% encode_object_identifier(Val) -> CompleteList +%% encode_object_identifier({Name,Val}) -> CompleteList +%% Val -> {Int1,Int2,...,IntN} % N >= 2 +%% Name -> atom() +%% Int1 -> integer(0..2) +%% Int2 -> integer(0..39) when Int1 (0..1) else integer() +%% Int3-N -> integer() +%% CompleteList -> [{bits,8,Val}|{octets,Ol}|align|...] +%% +encode_object_identifier(Val) -> + OctetList = e_object_identifier(Val), + Octets = list_to_binary(OctetList), + Sz = byte_size(Octets), + [encode_length(Sz), + octets_to_complete(Sz, Octets)]. + +e_object_identifier({'OBJECT IDENTIFIER',V}) -> + e_object_identifier(V); +e_object_identifier(V) when is_tuple(V) -> + e_object_identifier(tuple_to_list(V)); + +%% E1 = 0|1|2 and (E2 < 40 when E1 = 0|1) +e_object_identifier([E1,E2|Tail]) when E1 >= 0, E1 < 2, E2 < 40 ; E1==2 -> + Head = 40*E1 + E2, % weird + e_object_elements([Head|Tail],[]); +e_object_identifier(Oid=[_,_|_Tail]) -> + exit({error,{asn1,{'illegal_value',Oid}}}). + +e_object_elements([],Acc) -> + lists:reverse(Acc); +e_object_elements([H|T],Acc) -> + e_object_elements(T,[e_object_element(H)|Acc]). + +e_object_element(Num) when Num < 128 -> + [Num]; +e_object_element(Num) -> + [e_o_e(Num bsr 7)|[Num band 2#1111111]]. +e_o_e(Num) when Num < 128 -> + Num bor 2#10000000; +e_o_e(Num) -> + [e_o_e(Num bsr 7)|[(Num band 2#1111111) bor 2#10000000]]. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% decode_object_identifier(Bytes) -> {ObjId,RemainingBytes} +%% ObjId -> {integer(),integer(),...} % at least 2 integers +%% RemainingBytes -> [integer()] when integer() (0..255) +decode_object_identifier(Bytes) -> + {Len,Bytes2} = decode_length(Bytes,undefined), + {Octs,Bytes3} = getoctets_as_list(Bytes2,Len), + [First|Rest] = dec_subidentifiers(Octs,0,[]), + Idlist = if + First < 40 -> + [0,First|Rest]; + First < 80 -> + [1,First - 40|Rest]; + true -> + [2,First - 80|Rest] + end, + {list_to_tuple(Idlist),Bytes3}. + +dec_subidentifiers([H|T],Av,Al) when H >=16#80 -> + dec_subidentifiers(T,(Av bsl 7) + (H band 16#7F),Al); +dec_subidentifiers([H|T],Av,Al) -> + dec_subidentifiers(T,0,[(Av bsl 7) + H |Al]); +dec_subidentifiers([],_Av,Al) -> + lists:reverse(Al). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% encode_relative_oid(Val) -> CompleteList +%% encode_relative_oid({Name,Val}) -> CompleteList +encode_relative_oid(Val) when is_tuple(Val) -> + encode_relative_oid(tuple_to_list(Val)); +encode_relative_oid(Val) when is_list(Val) -> + Octets = list_to_binary([e_object_element(X)||X <- Val]), + Sz = byte_size(Octets), + [encode_length(Sz)|octets_to_complete(Sz, Octets)]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% decode_relative_oid(Val) -> CompleteList +%% decode_relative_oid({Name,Val}) -> CompleteList +decode_relative_oid(Bytes) -> + {Len,Bytes2} = decode_length(Bytes,undefined), + {Octs,Bytes3} = getoctets_as_list(Bytes2,Len), + ObjVals = dec_subidentifiers(Octs,0,[]), + {list_to_tuple(ObjVals),Bytes3}. + + +get_constraint([{Key,V}],Key) -> + V; +get_constraint([],_) -> + no; +get_constraint(C,Key) -> + case lists:keyfind(Key, 1, C) of + false -> + no; + {_,V} -> + V + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% complete(InList) -> ByteList +%% Takes a coded list with bits and bytes and converts it to a list of bytes +%% Should be applied as the last step at encode of a complete ASN.1 type +%% + +complete(L) -> + case asn1rt_nif:encode_per_complete(L) of + {error, Reason} -> handle_error(Reason, L); + Else when is_binary(Else) -> Else + end. + +handle_error([],_)-> + exit({error,{asn1,{"memory allocation problem in driver"}}}); +handle_error($1,L) -> % error in complete in driver + exit({error,{asn1,L}}); +handle_error(ErrL,L) -> + exit({error,{asn1,ErrL,L}}). + +octets_to_complete(Len,Val) when Len < 256 -> + [20,Len,Val]; +octets_to_complete(Len,Val) -> + [21,<>,Val]. + +octets_unused_to_complete(Unused,Len,Val) when Len < 256 -> + [30,Unused,Len,Val]; +octets_unused_to_complete(Unused,Len,Val) -> + [31,Unused,<>,Val]. diff --git a/lib/asn1/src/asn1rtt_real_common.erl b/lib/asn1/src/asn1rtt_real_common.erl new file mode 100644 index 0000000000..540f0d60a5 --- /dev/null +++ b/lib/asn1/src/asn1rtt_real_common.erl @@ -0,0 +1,292 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(asn1rtt_real_common). + +-export([encode_real/1,decode_real/1, + ber_encode_real/1]). + +%%============================================================================ +%% +%% Real value, ITU_T X.690 Chapter 8.5 +%%============================================================================ +%% +%% encode real value +%%============================================================================ + +ber_encode_real(0) -> + {[],0}; +ber_encode_real('PLUS-INFINITY') -> + {[64],1}; +ber_encode_real('MINUS-INFINITY') -> + {[65],1}; +ber_encode_real(Val) when is_tuple(Val); is_list(Val) -> + encode_real(Val). + +%%%%%%%%%%%%%% +%% only base 2 encoding! +%% binary encoding: +%% +------------+ +------------+ +-+-+-+-+---+---+ +%% | (tag)9 | | n + p + 1 | |1|S|BB |FF |EE | +%% +------------+ +------------+ +-+-+-+-+---+---+ +%% +%% +------------+ +------------+ +%% | | | | +%% +------------+ ...+------------+ +%% n octets for exponent +%% +%% +------------+ +------------+ +%% | | | | +%% +------------+ ...+------------+ +%% p octets for pos mantissa +%% +%% S is 0 for positive sign +%% 1 for negative sign +%% BB: encoding base, 00 = 2, (01 = 8, 10 = 16) +%% 01 and 10 not used +%% FF: scale factor 00 = 0 (used in base 2 encoding) +%% EE: encoding of the exponent: +%% 00 - on the following octet +%% 01 - on the 2 following octets +%% 10 - on the 3 following octets +%% 11 - encoding of the length of the two's-complement encoding of +%% exponent on the following octet, and two's-complement +%% encoding of exponent on the other octets. +%% +%% In DER and base 2 encoding the mantissa is encoded as value 0 or +%% bit shifted until it is an odd number. Thus, do this for BER as +%% well. + +encode_real(Real) -> + encode_real([], Real). + +encode_real(_C, {Mantissa, Base, Exponent}) when Base =:= 2 -> +%% io:format("Mantissa: ~w Base: ~w, Exp: ~w~n",[Man, Base, Exp]), + {Man,ExpAdd} = truncate_zeros(Mantissa), %% DER adjustment + Exp = Exponent + ExpAdd, + OctExp = if Exp >= 0 -> list_to_binary(encode_pos_integer(Exp, [])); + true -> list_to_binary(encode_neg_integer(Exp, [])) + end, +%% ok = io:format("OctExp: ~w~n",[OctExp]), + SignBit = if Man > 0 -> 0; % bit 7 is pos or neg, no Zeroval + true -> 1 + end, +%% ok = io:format("SignBitMask: ~w~n",[SignBitMask]), + SFactor = 0, + OctExpLen = size(OctExp), + if OctExpLen > 255 -> + exit({error,{asn1, {to_big_exp_in_encode_real, OctExpLen}}}); + true -> true %% make real assert later.. + end, + {LenCode, EOctets} = case OctExpLen of % bit 2,1 + 1 -> {0, OctExp}; + 2 -> {1, OctExp}; + 3 -> {2, OctExp}; + _ -> {3, <>} + end, + BB = 0, %% 00 for base 2 + FirstOctet = <<1:1,SignBit:1,BB:2,SFactor:2,LenCode:2>>, + OctMantissa = if Man > 0 -> list_to_binary(real_mininum_octets(Man)); + true -> list_to_binary(real_mininum_octets(-(Man))) % signbit keeps track of sign + end, + %% ok = io:format("LenMask: ~w EOctets: ~w~nFirstOctet: ~w OctMantissa: ~w OctExpLen: ~w~n", [LenMask, EOctets, FirstOctet, OctMantissa, OctExpLen]), + Bin = <>, + {Bin, size(Bin)}; +encode_real(C, {Mantissa,Base,Exponent}) + when Base =:= 10, is_integer(Mantissa), is_integer(Exponent) -> + %% always encode as NR3 due to DER on the format + %% mmmm.Eseeee where + %% m := digit + %% s := '-' | '+' | [] + %% '+' only allowed in +0 + %% e := digit + %% ex: 1234.E-5679 + ManStr = integer_to_list(Mantissa), + + encode_real_as_string(C,ManStr,Exponent); +encode_real(_C, {_,Base,_}) -> + exit({error,{asn1, {encode_real_non_supported_encoding, Base}}}); +%% base 10 +encode_real(C, Real) when is_list(Real) -> + %% The Real string may come in as a NR1, NR2 or NR3 string. + {Mantissa, Exponent} = + case string:tokens(Real,"Ee") of + [NR2] -> + {NR2,0}; + [NR3MB,NR3E] -> + %% remove beginning zeros + {NR3MB,list_to_integer(NR3E)} + end, + + %% .Decimal | Number | Number.Decimal + ZeroDecimal = + fun("0") -> ""; + (L) -> L + end, + {NewMantissa,LenDecimal} = + case Mantissa of + [$.|Dec] -> + NewMan = remove_trailing_zeros(Dec), + {NewMan,length(ZeroDecimal(NewMan))}; + _ -> + case string:tokens(Mantissa,",.") of + [Num] -> %% No decimal-mark + {integer_to_list(list_to_integer(Num)),0}; + [Num,Dec] -> + NewDec = ZeroDecimal(remove_trailing_zeros(Dec)), + NewMan = integer_to_list(list_to_integer(Num)) ++ NewDec, + {integer_to_list(list_to_integer(NewMan)), + length(NewDec)} + end + end, + + encode_real_as_string(C, NewMantissa, Exponent - LenDecimal). + +encode_real_as_string(_C, Mantissa, Exponent) + when is_list(Mantissa), is_integer(Exponent) -> + %% Remove trailing zeros in Mantissa and add this to Exponent + TruncMant = remove_trailing_zeros(Mantissa), + + ExpIncr = length(Mantissa) - length(TruncMant), + + ExpStr = integer_to_list(Exponent + ExpIncr), + + ExpBin = + case ExpStr of + "0" -> + <<"E+0">>; + _ -> + ExpB = list_to_binary(ExpStr), + <<$E,ExpB/binary>> + end, + ManBin = list_to_binary(TruncMant), + NR3 = 3, + {<>, + 2 + byte_size(ManBin) + byte_size(ExpBin)}. + +remove_trailing_zeros(IntStr) -> + case lists:dropwhile(fun($0)-> true; + (_) -> false + end, lists:reverse(IntStr)) of + [] -> + "0"; + ReversedIntStr -> + lists:reverse(ReversedIntStr) + end. + +truncate_zeros(Num) -> + truncate_zeros(Num, 0). +truncate_zeros(0, Sum) -> + {0,Sum}; +truncate_zeros(M, Sum) -> + case M band 16#f =:= M band 16#e of + true -> truncate_zeros(M bsr 1, Sum+1); + _ -> {M,Sum} + end. + + +%%============================================================================ +%% decode real value +%% +%% decode_real([OctetBufferList], tuple|value, tag|notag) -> +%% {{Mantissa, Base, Exp} | realval | PLUS-INFINITY | MINUS-INFINITY | 0, +%% RestBuff} +%% +%% only for base 2 decoding sofar!! +%%============================================================================ + +decode_real(Buffer) -> + Sz = byte_size(Buffer), + {RealVal,<<>>,Sz} = decode_real2(Buffer, [], Sz, 0), + RealVal. + +decode_real2(Buffer, _C, 0, _RemBytes) -> + {0,Buffer}; +decode_real2(Buffer0, _C, Len, RemBytes1) -> + <> = Buffer0, + if + First =:= 2#01000000 -> {'PLUS-INFINITY', Buffer2}; + First =:= 2#01000001 -> {'MINUS-INFINITY', Buffer2}; + First =:= 1 orelse First =:= 2 orelse First =:= 3 -> + %% charcter string encoding of base 10 + {NRx,Rest} = split_binary(Buffer2,Len-1), + {binary_to_list(NRx),Rest,Len}; + true -> + %% have some check here to verify only supported bases (2) + %% not base 8 or 16 + <<_B7:1,Sign:1,BB:2,_FF:2,EE:2>> = <>, + Base = + case BB of + 0 -> 2; % base 2, only one so far + _ -> exit({error,{asn1, {non_supported_base, BB}}}) + end, + {FirstLen, {Exp, Buffer3,_Rb2}, RemBytes2} = + case EE of + 0 -> {2, decode_integer2(1, Buffer2, RemBytes1), RemBytes1+1}; + 1 -> {3, decode_integer2(2, Buffer2, RemBytes1), RemBytes1+2}; + 2 -> {4, decode_integer2(3, Buffer2, RemBytes1), RemBytes1+3}; + 3 -> + <> = Buffer2, + { ExpLen1 + 2, + decode_integer2(ExpLen1, RestBuffer, RemBytes1), + RemBytes1+ExpLen1} + end, + %% io:format("FirstLen: ~w, Exp: ~w, Buffer3: ~w ~n", + + Length = Len - FirstLen, + <> = Buffer3, + {{Mantissa, Buffer4}, RemBytes3} = + if Sign =:= 0 -> + %% io:format("sign plus~n"), + {{LongInt, RestBuff}, 1 + Length}; + true -> + %% io:format("sign minus~n"), + {{-LongInt, RestBuff}, 1 + Length} + end, + {{Mantissa, Base, Exp}, Buffer4, RemBytes2+RemBytes3} + end. + +encode_pos_integer(0, [B|_Acc]=L) when B < 128 -> + L; +encode_pos_integer(N, Acc) -> + encode_pos_integer(N bsr 8, [N band 16#ff| Acc]). + +encode_neg_integer(-1, [B1|_T]=L) when B1 > 127 -> + L; +encode_neg_integer(N, Acc) -> + encode_neg_integer(N bsr 8, [N band 16#ff|Acc]). + + +%% Val must be >= 0 +real_mininum_octets(Val) -> + real_mininum_octets(Val, []). + +real_mininum_octets(0, Acc) -> + Acc; +real_mininum_octets(Val, Acc) -> + real_mininum_octets(Val bsr 8, [Val band 16#FF | Acc]). + +%% decoding postitive integer values. +decode_integer2(Len, <<0:1,_:7,_Bs/binary>> = Bin, RemovedBytes) -> + <> = Bin, + {Int,Buffer2,RemovedBytes}; +%% decoding negative integer values. +decode_integer2(Len, <<1:1,B2:7,Bs/binary>>, RemovedBytes) -> + <> = <>, + Int = N - (1 bsl (8 * Len - 1)), + {Int,Buffer2,RemovedBytes}. diff --git a/lib/asn1/src/asn1rtt_uper.erl b/lib/asn1/src/asn1rtt_uper.erl new file mode 100644 index 0000000000..bcc11da63a --- /dev/null +++ b/lib/asn1/src/asn1rtt_uper.erl @@ -0,0 +1,1379 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(asn1rtt_uper). + +-export([setext/1, fixoptionals/3, + fixextensions/2, + skipextensions/3, getbit/1, getchoice/3 ]). +-export([set_choice/3, encode_integer/2, encode_integer/3]). +-export([encode_small_number/1, encode_boolean/1, + encode_length/1, encode_length/2, + decode_compact_bit_string/3]). +-export([encode_bit_string/3, decode_bit_string/3]). +-export([encode_octet_string/2, + encode_relative_oid/1, decode_relative_oid/1, + encode_object_identifier/1, decode_object_identifier/1, + complete/1, complete_NFP/1]). + + -export([encode_open_type/1]). + + -export([encode_UniversalString/2, decode_UniversalString/2, + encode_PrintableString/2, decode_PrintableString/2, + encode_GeneralString/2, decode_GeneralString/2, + encode_GraphicString/2, decode_GraphicString/2, + encode_TeletexString/2, decode_TeletexString/2, + encode_VideotexString/2, decode_VideotexString/2, + encode_VisibleString/2, decode_VisibleString/2, + encode_UTF8String/1, decode_UTF8String/1, + encode_BMPString/2, decode_BMPString/2, + encode_IA5String/2, decode_IA5String/2, + encode_NumericString/2, decode_NumericString/2, + encode_ObjectDescriptor/2, decode_ObjectDescriptor/1 + ]). + +-define('16K',16384). +-define('32K',32768). +-define('64K',65536). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% setext(true|false) -> CompleteList +%% + +setext(false) -> + <<0:1>>; +setext(true) -> + <<1:1>>. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% This is the new fixoptionals/3 which is used by the new generates +%% +fixoptionals(OptList,OptLength,Val) when is_tuple(Val) -> + Bits = fixoptionals(OptList,Val,0), + {Val,<>}; + +fixoptionals([],_Val,Acc) -> + %% Optbits + Acc; +fixoptionals([{Pos,DefVal}|Ot],Val,Acc) -> + case element(Pos,Val) of + asn1_DEFAULT -> fixoptionals(Ot,Val,Acc bsl 1); + DefVal -> fixoptionals(Ot,Val,Acc bsl 1); + _ -> fixoptionals(Ot,Val,(Acc bsl 1) + 1) + end; +fixoptionals([Pos|Ot],Val,Acc) -> + case element(Pos,Val) of + asn1_NOVALUE -> fixoptionals(Ot,Val,Acc bsl 1); + asn1_DEFAULT -> fixoptionals(Ot,Val,Acc bsl 1); + _ -> fixoptionals(Ot,Val,(Acc bsl 1) + 1) + end. + + +fixextensions({ext,ExtPos,ExtNum},Val) -> + case fixextensions(ExtPos,ExtNum+ExtPos,Val,0) of + 0 -> []; + ExtBits -> + [encode_small_length(ExtNum),<>] + end. + +fixextensions(Pos,MaxPos,_,Acc) when Pos >= MaxPos -> + Acc; +fixextensions(Pos,ExtPos,Val,Acc) -> + Bit = case catch(element(Pos+1,Val)) of + asn1_NOVALUE -> + 0; + asn1_NOEXTVALUE -> + 0; + {'EXIT',_} -> + 0; + _ -> + 1 + end, + fixextensions(Pos+1,ExtPos,Val,(Acc bsl 1)+Bit). + +skipextensions(Bytes0, Nr, ExtensionBitstr) when is_bitstring(ExtensionBitstr) -> + Prev = Nr - 1, + case ExtensionBitstr of + <<_:Prev,1:1,_/bitstring>> -> + {Len,Bytes1} = decode_length(Bytes0, undefined), + <<_:Len/binary,Bytes2/bitstring>> = Bytes1, + skipextensions(Bytes2, Nr+1, ExtensionBitstr); + <<_:Prev,0:1,_/bitstring>> -> + skipextensions(Bytes0, Nr+1, ExtensionBitstr); + _ -> + Bytes0 + end. + + +getchoice(Bytes,1,0) -> % only 1 alternative is not encoded + {0,Bytes}; +getchoice(Bytes,_,1) -> + decode_small_number(Bytes); +getchoice(Bytes,NumChoices,0) -> + decode_constrained_number(Bytes,{0,NumChoices-1}). + + +%% getbits_as_binary(Num,Bytes) -> {{Unused,BinBits},RestBytes}, +%% Num = integer(), +%% Bytes = list() | tuple(), +%% Unused = integer(), +%% BinBits = binary(), +%% RestBytes = tuple() +getbits_as_binary(Num,Bytes) when is_bitstring(Bytes) -> + <> = Bytes, + {BS,Rest}. + +getbits_as_list(Num, Bytes) when is_bitstring(Bytes) -> + <> = Bytes, + {[B || <> <= BitStr],Rest}. + +getbit(Buffer) -> + <> = Buffer, + {B,Rest}. + +getbits(Buffer, Num) when is_bitstring(Buffer) -> + <> = Buffer, + {Bs,Rest}. + + +%% Pick the first Num octets. +%% Returns octets as an integer with bit significance as in buffer. +getoctets(Buffer, Num) when is_bitstring(Buffer) -> + <> = Buffer, + {Val,RestBitStr}. + +%% Pick the first Num octets. +%% Returns octets as a binary +getoctets_as_bin(Bin,Num) when is_bitstring(Bin) -> + <> = Bin, + {Octets,RestBin}. + +%% same as above but returns octets as a List +getoctets_as_list(Buffer,Num) -> + {Bin,Buffer2} = getoctets_as_bin(Buffer, Num), + {binary_to_list(Bin),Buffer2}. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% set_choice(Alt,Choices,Altnum) -> ListofBitSettings +%% Alt = atom() +%% Altnum = integer() | {integer(),integer()}% number of alternatives +%% Choices = [atom()] | {[atom()],[atom()]} +%% When Choices is a tuple the first list is the Rootset and the +%% second is the Extensions and then Altnum must also be a tuple with the +%% lengths of the 2 lists +%% +set_choice(Alt, {L1,L2}, {Len1,_Len2}) -> + case set_choice_tag(Alt, L1) of + N when is_integer(N), Len1 > 1 -> + [<<0:1>>, % the value is in the root set + encode_integer([{'ValueRange',{0,Len1-1}}],N)]; + N when is_integer(N) -> + <<0:1>>; % no encoding if only 0 or 1 alternative + false -> + [<<1:1>>, % extension value + case set_choice_tag(Alt,L2) of + N2 when is_integer(N2) -> + encode_small_number(N2); + false -> + unknown_choice_alt + end] + end; +set_choice(Alt,L,Len) -> + case set_choice_tag(Alt,L) of + N when is_integer(N), Len > 1 -> + encode_integer([{'ValueRange',{0,Len-1}}],N); + N when is_integer(N) -> + []; % no encoding if only 0 or 1 alternative + false -> + [unknown_choice_alt] + end. + +set_choice_tag(Alt,Choices) -> + set_choice_tag(Alt,Choices,0). + +set_choice_tag(Alt,[Alt|_Rest],Tag) -> + Tag; +set_choice_tag(Alt,[_H|Rest],Tag) -> + set_choice_tag(Alt,Rest,Tag+1); +set_choice_tag(_Alt,[],_Tag) -> + false. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% decode_fragmented_XXX; decode of values encoded fragmented according +%% to ITU-T X.691 clause 10.9.3.8. The unit (XXX) is either bits, octets, +%% characters or number of components (in a choice,sequence or similar). +%% Buffer is a buffer {Used, Bin}. +%% C is the constrained length. +%% If the buffer is not aligned, this function does that. +decode_fragmented_bits(Buffer,C) -> + decode_fragmented_bits(Buffer,C,[]). +decode_fragmented_bits(<<3:2,Len:6,BitStr/bitstring>>,C,Acc) -> + FragLen = (Len*?'16K') div 8, + <> = BitStr, + decode_fragmented_bits(BitStr2,C,[Value|Acc]); +decode_fragmented_bits(<<0:1,0:7,BitStr/bitstring>>,C,Acc) -> + BinBits = list_to_binary(lists:reverse(Acc)), + case C of + Int when is_integer(Int),C =:= byte_size(BinBits) -> + {BinBits,BitStr}; + Int when is_integer(Int) -> + exit({error,{asn1,{illegal_value,C,BinBits}}}) + end; +decode_fragmented_bits(<<0:1,Len:7,BitStr/bitstring>>,C,Acc) -> + <> = BitStr, + ResBitStr = list_to_bitstring(lists:reverse([Val|Acc])), + case C of + Int when is_integer(Int),C == bit_size(ResBitStr) -> + {ResBitStr,Rest}; + Int when is_integer(Int) -> + exit({error,{asn1,{illegal_value,C,ResBitStr}}}) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% encode_open_type(Constraint, Value) -> CompleteList +%% Value = list of bytes of an already encoded value (the list must be flat) +%% | binary +%% Contraint = not used in this version +%% +encode_open_type(Val) when is_list(Val) -> + encode_open_type(list_to_binary(Val)); +encode_open_type(Val) when is_binary(Val) -> + [encode_length(byte_size(Val)),Val]. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% encode_integer(Constraint,Value,NamedNumberList) -> CompleteList +%% encode_integer(Constraint,Value) -> CompleteList +%% encode_integer(Constraint,{Name,Value}) -> CompleteList +%% +%% +encode_integer(C, V, NamedNumberList) when is_atom(V) -> + case lists:keyfind(V, 1, NamedNumberList) of + {_,NewV} -> + encode_integer(C, NewV); + false -> + exit({error,{asn1,{namednumber,V}}}) + end; +encode_integer(C, V, _NamedNumberList) when is_integer(V) -> + encode_integer(C, V). + +encode_integer([{Rc,_Ec}],Val) when is_tuple(Rc) -> + try + [<<0:1>>,encode_integer([Rc], Val)] + catch + _:{error,{asn1,_}} -> + [<<1:1>>,encode_unconstrained_number(Val)] + end; +encode_integer(C, Val) when is_list(C) -> + case get_constraint(C, 'SingleValue') of + no -> + encode_integer1(C,Val); + V when is_integer(V), V =:= Val -> + []; % a type restricted to a single value encodes to nothing + V when is_list(V) -> + case lists:member(Val,V) of + true -> + encode_integer1(C,Val); + _ -> + exit({error,{asn1,{illegal_value,Val}}}) + end; + _ -> + exit({error,{asn1,{illegal_value,Val}}}) + end. + +encode_integer1(C, Val) -> + case VR = get_constraint(C, 'ValueRange') of + no -> + encode_unconstrained_number(Val); + {Lb,'MAX'} -> + encode_semi_constrained_number(Lb, Val); + %% positive with range + {Lb,Ub} when Val >= Lb, Ub >= Val -> + encode_constrained_number(VR,Val); + _ -> + exit({error,{asn1,{illegal_value,VR,Val}}}) + end. + +%% X.691:10.6 Encoding of a normally small non-negative whole number +%% Use this for encoding of CHOICE index if there is an extension marker in +%% the CHOICE +encode_small_number(Val) when Val < 64 -> + <>; +encode_small_number(Val) -> + [<<1:1>>|encode_semi_constrained_number(0, Val)]. + +decode_small_number(Bytes) -> + {Bit,Bytes2} = getbit(Bytes), + case Bit of + 0 -> + getbits(Bytes2,6); + 1 -> + decode_semi_constrained_number(Bytes2) + end. + +%% X.691:10.7 Encoding of a semi-constrained whole number +encode_semi_constrained_number(Lb, Val) -> + %% encoding in minimum number of octets preceeded by a length + Val2 = Val - Lb, + Bin = eint_bin_positive(Val2), + Size = byte_size(Bin), + if + Size < 128 -> + [<>,Bin]; + Size < 16384 -> + [<<2:2,Size:14>>,Bin]; + true -> + [encode_length(Size),Bin] + end. + +decode_semi_constrained_number(Bytes) -> + {Len,Bytes2} = decode_length(Bytes, undefined), + {V,Bytes3} = getoctets(Bytes2,Len), + {V,Bytes3}. + +encode_constrained_number({Lb,Ub}, Val) when Val >= Lb, Ub >= Val -> + Range = Ub - Lb + 1, + Val2 = Val - Lb, + NumBits = num_bits(Range), + <>; +encode_constrained_number(Range,Val) -> + exit({error,{asn1,{integer_range,Range,value,Val}}}). + + +decode_constrained_number(Buffer, {Lb,Ub}) -> + Range = Ub - Lb + 1, + NumBits = num_bits(Range), + {Val,Remain} = getbits(Buffer,NumBits), + {Val+Lb,Remain}. + +%% X.691:10.8 Encoding of an unconstrained whole number + +encode_unconstrained_number(Val) when Val >= 0 -> + Oct = eint_bin_2Cs(Val), + Len = byte_size(Oct), + if + Len < 128 -> + [<>,Oct]; % equiv with encode_length(undefined,Len) but faster + Len < 16384 -> + [<<2:2,Len:14>>,Oct]; + true -> + [encode_length(Len),<>,Oct] + end; +encode_unconstrained_number(Val) -> % negative + Oct = enint(Val,[]), + Len = byte_size(Oct), + if + Len < 128 -> + [<>,Oct]; % equiv with encode_length(undefined,Len) but faster + Len < 16384 -> + [<<2:2,Len:14>>,Oct]; + true -> + [encode_length(Len),Oct] + end. + + +eint_bin_2Cs(Int) -> + case eint_bin_positive(Int) of + <> = Bin when B > 16#7f -> + <<0,Bin/binary>>; + Bin -> Bin + end. + +%% returns the integer as a binary +eint_bin_positive(Val) when Val < 16#100 -> + <>; +eint_bin_positive(Val) when Val < 16#10000 -> + <>; +eint_bin_positive(Val) when Val < 16#1000000 -> + <>; +eint_bin_positive(Val) when Val < 16#100000000 -> + <>; +eint_bin_positive(Val) -> + list_to_binary([eint_bin_positive2(Val bsr 32),<>]). + +eint_bin_positive2(Val) when Val < 16#100 -> + <>; +eint_bin_positive2(Val) when Val < 16#10000 -> + <>; +eint_bin_positive2(Val) when Val < 16#1000000 -> + <>; +eint_bin_positive2(Val) when Val < 16#100000000 -> + <>; +eint_bin_positive2(Val) -> + [eint_bin_positive2(Val bsr 32),<>]. + + + + +enint(-1, [B1|T]) when B1 > 127 -> + list_to_binary([B1|T]); +enint(N, Acc) -> + enint(N bsr 8, [N band 16#ff|Acc]). + + +%% X.691:10.9 Encoding of a length determinant +%%encode_small_length(undefined,Len) -> % null means no UpperBound +%% encode_small_number(Len). + +%% X.691:10.9.3.5 +%% X.691:10.9.3.7 +encode_length(Len) -> % un-constrained + if + Len < 128 -> + <>; + Len < 16384 -> + <<2:2,Len:14>>; + true -> % should be able to endode length >= 16384 + error({error,{asn1,{encode_length,{nyi,above_16k}}}}) + end. + +encode_length(undefined, Len) -> % unconstrained + encode_length(Len); +encode_length({0,'MAX'},Len) -> + encode_length(undefined, Len); +encode_length({Lb,Ub}=Vr, Len) when Ub =< 65535, Lb >= 0 -> % constrained + encode_constrained_number(Vr,Len); +encode_length({Lb,_Ub}, Len) when is_integer(Lb), Lb >= 0 -> % Ub > 65535 + encode_length(Len); +encode_length({{Lb,Ub}=Vr,Ext},Len) + when Ub =< 65535, Lb >= 0, Len =< Ub, is_list(Ext) -> + %% constrained extensible + [<<0:1>>,encode_constrained_number(Vr,Len)]; +encode_length({{Lb,_Ub},Ext}, Len) when is_list(Ext) -> + [<<1:1>>,encode_semi_constrained_number(Lb, Len)]; +encode_length(SingleValue, _Len) when is_integer(SingleValue) -> + []. + +%% X.691 10.9.3.4 (only used for length of bitmap that prefixes extension +%% additions in a sequence or set +encode_small_length(Len) when Len =< 64 -> + <<(Len-1):7>>; +encode_small_length(Len) -> + [<<1:1>>,encode_length(Len)]. + + +%% un-constrained +decode_length(<<0:1,Oct:7,Rest/bitstring>>,undefined) -> + {Oct,Rest}; +decode_length(<<2:2,Val:14,Rest/bitstring>>,undefined) -> + {Val,Rest}; +decode_length(<<3:2,_:14,_Rest/bitstring>>,undefined) -> + exit({error,{asn1,{decode_length,{nyi,above_16k}}}}); + +decode_length(Buffer,{Lb,Ub}) when Ub =< 65535, Lb >= 0 -> % constrained + decode_constrained_number(Buffer,{Lb,Ub}); +decode_length(Buffer,{Lb,_}) when is_integer(Lb), Lb >= 0 -> % Ub > 65535 + decode_length(Buffer,undefined); +decode_length(Buffer,{VR={_Lb,_Ub},Ext}) when is_list(Ext) -> + {0,Buffer2} = getbit(Buffer), + decode_length(Buffer2, VR); + + +%When does this case occur with {_,_Lb,Ub} ?? +% X.691:10.9.3.5 +decode_length(Bin,{_,_Lb,_Ub}) -> %when Len =< 127 -> % Unconstrained or large Ub NOTE! this case does not cover case when Ub > 65535 + case Bin of + <<0:1,Val:7,Rest/bitstring>> -> + {Val,Rest}; + <<2:2,Val:14,Rest/bitstring>> -> + {Val,Rest}; + <<3:2,_:14,_Rest/bitstring>> -> + exit({error,{asn1,{decode_length,{nyi,length_above_64K}}}}) + end; +decode_length(Buffer,SingleValue) when is_integer(SingleValue) -> + {SingleValue,Buffer}. + + + % X.691:11 +encode_boolean(true) -> + <<1:1>>; +encode_boolean(false) -> + <<0:1>>; +encode_boolean(Val) -> + exit({error,{asn1,{encode_boolean,Val}}}). + + +%%============================================================================ +%%============================================================================ +%% Bitstring value, ITU_T X.690 Chapter 8.5 +%%============================================================================ +%%============================================================================ + +%%============================================================================ +%% encode bitstring value +%%============================================================================ + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% bitstring NamedBitList +%% Val can be of: +%% - [identifiers] where only named identifers are set to one, +%% the Constraint must then have some information of the +%% bitlength. +%% - [list of ones and zeroes] all bits +%% - integer value representing the bitlist +%% C is constraint Len, only valid when identifiers are present + + +%% when the value is a list of {Unused,BinBits}, where +%% Unused = integer(), +%% BinBits = binary(). + +encode_bit_string(C, {Unused,BinBits}=Bin, NamedBitList) + when is_integer(Unused), is_binary(BinBits) -> + encode_bin_bit_string(get_constraint(C,'SizeConstraint'),Bin,NamedBitList); + +encode_bit_string(C, BitListVal, NamedBitList) -> + encode_bit_string1(get_constraint(C, 'SizeConstraint'), BitListVal, NamedBitList). + +%% when the value is a list of named bits +encode_bit_string1(C, [FirstVal|_RestVal]=LoNB, NamedBitList) + when is_atom(FirstVal) -> + ToSetPos = get_all_bitposes(LoNB, NamedBitList, []), + BitList = make_and_set_list(ToSetPos, 0), + encode_bit_string1(C, BitList, NamedBitList); +encode_bit_string1(C, [{bit,_No}|_RestVal]=BL, NamedBitList) -> + ToSetPos = get_all_bitposes(BL, NamedBitList, []), + BitList = make_and_set_list(ToSetPos, 0), + encode_bit_string1(C, BitList, NamedBitList); +%% when the value is a list of ones and zeroes +encode_bit_string1(Int, BitListValue, _) + when is_list(BitListValue), is_integer(Int) -> + %% The type is constrained by a single value size constraint + bit_list2bitstr(Int, BitListValue); +encode_bit_string1(no, BitListValue, []) + when is_list(BitListValue) -> + Len = length(BitListValue), + [encode_length(Len),bit_list2bitstr(Len,BitListValue)]; +encode_bit_string1(C, BitListValue,[]) + when is_list(BitListValue) -> + Len = length(BitListValue), + [encode_length(C, Len),bit_list2bitstr(Len,BitListValue)]; +encode_bit_string1(no, BitListValue,_NamedBitList) + when is_list(BitListValue) -> + NewBitLVal = lists:reverse(lists:dropwhile(fun(0)->true;(1)->false end, + lists:reverse(BitListValue))), + Len = length(NewBitLVal), + [encode_length(Len),bit_list2bitstr(Len,NewBitLVal)]; +encode_bit_string1(C, BitListValue, _NamedBitList) + when is_list(BitListValue) ->% C = {_,'MAX'} + NewBitStr = bitstr_trailing_zeros(BitListValue, C), + [encode_length(C, bit_size(NewBitStr)),NewBitStr]; + + +%% when the value is an integer +encode_bit_string1(C, IntegerVal, NamedBitList) when is_integer(IntegerVal)-> + BitList = int_to_bitlist(IntegerVal), + encode_bit_string1(C, BitList, NamedBitList). + +bit_list2bitstr(Len,BitListValue) -> + case length(BitListValue) of + Len -> + << <> || B <- BitListValue>>; + L when L > Len -> % truncate + <<(<< <> || B <- BitListValue>>):Len/bitstring>>; + L -> % Len > L -> pad + <<(<< <> || B <- BitListValue>>)/bitstring,0:(Len-L)>> + end. + +adjust_trailing_zeros(Len, Bin) when Len =:= bit_size(Bin) -> + Bin; +adjust_trailing_zeros(Len, Bin) when Len > bit_size(Bin) -> + <>; +adjust_trailing_zeros(Len,Bin) -> + <>. + +bitstr_trailing_zeros(BitList, C) when is_integer(C) -> + bitstr_trailing_zeros1(BitList, C, C); +bitstr_trailing_zeros(BitList, {Lb,Ub}) when is_integer(Lb) -> + bitstr_trailing_zeros1(BitList,Lb,Ub); +bitstr_trailing_zeros(BitList, {{Lb,Ub},_}) when is_integer(Lb) -> + bitstr_trailing_zeros1(BitList, Lb, Ub); +bitstr_trailing_zeros(BitList, _) -> + bit_list2bitstr(length(BitList), BitList). + +bitstr_trailing_zeros1(BitList, Lb, Ub) -> + case length(BitList) of + Lb -> bit_list2bitstr(Lb, BitList); + B when B < Lb -> bit_list2bitstr(Lb, BitList); + D -> F = fun(L,LB,LB,_,_)->bit_list2bitstr(LB,lists:reverse(L)); + ([0|R],L1,LB,UB,Fun)->Fun(R,L1-1,LB,UB,Fun); + (L,L1,_,UB,_)when L1 =< UB -> + bit_list2bitstr(L1,lists:reverse(L)); + (_,_L1,_,_,_) ->exit({error,{list_length_BIT_STRING, + BitList}}) end, + F(lists:reverse(BitList),D,Lb,Ub,F) + end. + +%% encode_bin_bit_string/3, when value is a tuple of Unused and BinBits. +%% Unused = integer(),i.e. number unused bits in least sign. byte of +%% BinBits = binary(). +encode_bin_bit_string(C, {_,BinBits}, _NamedBitList) + when is_integer(C), C =< 16 -> + adjust_trailing_zeros(C, BinBits); +encode_bin_bit_string(C, {_Unused,BinBits}, _NamedBitList) + when is_integer(C) -> + adjust_trailing_zeros(C, BinBits); +encode_bin_bit_string(C, {_,_}=UnusedAndBin, NamedBitList) -> + %% removes all trailing bits if NamedBitList is not empty + BitStr = remove_trailing_bin(NamedBitList, UnusedAndBin), + case C of + {Lb,Ub} when is_integer(Lb),is_integer(Ub) -> + [encode_length({Lb,Ub},bit_size(BitStr)),BitStr]; + no -> + [encode_length(bit_size(BitStr)),BitStr]; + Sc -> + [encode_length(Sc,bit_size(BitStr)),BitStr] + end. + + +remove_trailing_bin([], {Unused,Bin}) -> + BS = bit_size(Bin)-Unused, + <> = Bin, + BitStr; +remove_trailing_bin(_NamedNumberList, {_Unused,<<>>}) -> + <<>>; +remove_trailing_bin(NamedNumberList, {_Unused,Bin}) -> + Size = byte_size(Bin)-1, + <> = Bin, + + %% clear the Unused bits to be sure + Unused1 = trailingZeroesInNibble(LastByte band 15), + Unused2 = + case Unused1 of + 4 -> + 4 + trailingZeroesInNibble(LastByte bsr 4); + _ -> Unused1 + end, + case Unused2 of + 8 -> + remove_trailing_bin(NamedNumberList,{0,Bfront}); + _ -> + BS = bit_size(Bin) - Unused2, + <> = Bin, + BitStr + end. + +trailingZeroesInNibble(0) -> + 4; +trailingZeroesInNibble(1) -> + 0; +trailingZeroesInNibble(2) -> + 1; +trailingZeroesInNibble(3) -> + 0; +trailingZeroesInNibble(4) -> + 2; +trailingZeroesInNibble(5) -> + 0; +trailingZeroesInNibble(6) -> + 1; +trailingZeroesInNibble(7) -> + 0; +trailingZeroesInNibble(8) -> + 3; +trailingZeroesInNibble(9) -> + 0; +trailingZeroesInNibble(10) -> + 1; +trailingZeroesInNibble(11) -> + 0; +trailingZeroesInNibble(12) -> %#1100 + 2; +trailingZeroesInNibble(13) -> + 0; +trailingZeroesInNibble(14) -> + 1; +trailingZeroesInNibble(15) -> + 0. + +%%%%%%%%%%%%%%% +%% The result is presented as a list of named bits (if possible) +%% else as a tuple {Unused,Bits}. Unused is the number of unused +%% bits, least significant bits in the last byte of Bits. Bits is +%% the BIT STRING represented as a binary. +%% +decode_compact_bit_string(Buffer, C, NamedNumberList) -> + case get_constraint(C, 'SizeConstraint') of + 0 -> % fixed length + {{8,0},Buffer}; + V when is_integer(V),V=<16 -> %fixed length 16 bits or less + compact_bit_string(Buffer,V,NamedNumberList); + V when is_integer(V),V=<65536 -> %fixed length > 16 bits + compact_bit_string(Buffer,V,NamedNumberList); + V when is_integer(V) -> % V > 65536 => fragmented value + {Bin,Buffer2} = decode_fragmented_bits(Buffer,V), + PadLen = (8 - (bit_size(Bin) rem 8)) rem 8, + {{PadLen,<>},Buffer2}; + {Lb,Ub} when is_integer(Lb),is_integer(Ub) -> + %% This case may demand decoding of fragmented length/value + {Len,Bytes2} = decode_length(Buffer,{Lb,Ub}), + compact_bit_string(Bytes2,Len,NamedNumberList); + no -> + %% This case may demand decoding of fragmented length/value + {Len,Bytes2} = decode_length(Buffer,undefined), + compact_bit_string(Bytes2,Len,NamedNumberList); + Sc -> + {Len,Bytes2} = decode_length(Buffer,Sc), + compact_bit_string(Bytes2,Len,NamedNumberList) + end. + + +%%%%%%%%%%%%%%% +%% The result is presented as a list of named bits (if possible) +%% else as a list of 0 and 1. +%% +decode_bit_string(Buffer, C, NamedNumberList) -> + case get_constraint(C,'SizeConstraint') of + {Lb,Ub} when is_integer(Lb),is_integer(Ub) -> + {Len,Bytes2} = decode_length(Buffer,{Lb,Ub}), + bit_list_or_named(Bytes2,Len,NamedNumberList); + no -> + {Len,Bytes2} = decode_length(Buffer,undefined), + bit_list_or_named(Bytes2,Len,NamedNumberList); + 0 -> % fixed length + {[],Buffer}; % nothing to encode + V when is_integer(V),V=<16 -> % fixed length 16 bits or less + bit_list_or_named(Buffer,V,NamedNumberList); + V when is_integer(V),V=<65536 -> + bit_list_or_named(Buffer,V,NamedNumberList); + V when is_integer(V) -> + {BinBits,_} = decode_fragmented_bits(Buffer,V), + bit_list_or_named(BinBits,V,NamedNumberList); + Sc -> % extension marker + {Len,Bytes2} = decode_length(Buffer,Sc), + bit_list_or_named(Bytes2,Len,NamedNumberList) + end. + + +%% if no named bits are declared we will return a +%% {Unused,Bits}. Unused = integer(), +%% Bits = binary(). +compact_bit_string(Buffer, Len, []) -> + {BitStr,Rest} = getbits_as_binary(Len,Buffer), % {{Unused,BinBits},NewBuffer} + PadLen = (8 - (bit_size(BitStr) rem 8)) rem 8, + {{PadLen,<>},Rest}; +compact_bit_string(Buffer, Len, NamedNumberList) -> + bit_list_or_named(Buffer, Len, NamedNumberList). + + +%% if no named bits are declared we will return a +%% BitList = [0 | 1] + +bit_list_or_named(Buffer,Len,[]) -> + getbits_as_list(Len,Buffer); + +%% if there are named bits declared we will return a named +%% BitList where the names are atoms and unnamed bits represented +%% as {bit,Pos} +%% BitList = [atom() | {bit,Pos}] +%% Pos = integer() + +bit_list_or_named(Buffer,Len,NamedNumberList) -> + {BitList,Rest} = getbits_as_list(Len,Buffer), + {bit_list_or_named1(0,BitList,NamedNumberList,[]), Rest}. + +bit_list_or_named1(Pos,[0|Bt],Names,Acc) -> + bit_list_or_named1(Pos+1,Bt,Names,Acc); +bit_list_or_named1(Pos,[1|Bt],Names,Acc) -> + case lists:keyfind(Pos, 2, Names) of + {Name,_} -> + bit_list_or_named1(Pos+1,Bt,Names,[Name|Acc]); + false -> + bit_list_or_named1(Pos+1,Bt,Names,[{bit,Pos}|Acc]) + end; +bit_list_or_named1(_,[],_,Acc) -> + lists:reverse(Acc). + + + +%%%%%%%%%%%%%%% +%% + +int_to_bitlist(Int) when is_integer(Int), Int > 0 -> + [Int band 1 | int_to_bitlist(Int bsr 1)]; +int_to_bitlist(0) -> + []. + + +%%%%%%%%%%%%%%%%%% +%% get_all_bitposes([list of named bits to set], named_bit_db, []) -> +%% [sorted_list_of_bitpositions_to_set] + +get_all_bitposes([{bit,ValPos}|Rest], NamedBitList, Ack) -> + get_all_bitposes(Rest, NamedBitList, [ValPos | Ack ]); + +get_all_bitposes([Val | Rest], NamedBitList, Ack) -> + case lists:keyfind(Val, 1, NamedBitList) of + {_ValName, ValPos} -> + get_all_bitposes(Rest, NamedBitList, [ValPos | Ack]); + false -> + exit({error,{asn1, {bitstring_namedbit, Val}}}) + end; +get_all_bitposes([], _NamedBitList, Ack) -> + lists:sort(Ack). + +%%%%%%%%%%%%%%%%%% +%% make_and_set_list([list of positions to set to 1])-> +%% returns list with all in SetPos set. +%% in positioning in list the first element is 0, the second 1 etc.., but +%% + +make_and_set_list([XPos|SetPos], XPos) -> + [1 | make_and_set_list(SetPos, XPos + 1)]; +make_and_set_list([Pos|SetPos], XPos) -> + [0 | make_and_set_list([Pos | SetPos], XPos + 1)]; +make_and_set_list([], _) -> + []. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% X.691:16 +%% encode_octet_string(Constraint,Val) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +encode_octet_string(C,Val) -> + case get_constraint(C,'SizeConstraint') of + 0 -> + <<>>; + 1 -> + list_to_binary(Val); + 2 -> + list_to_binary(Val); + {_,_}=VR -> + try + [encode_length(VR, length(Val)),list_to_binary(Val)] + catch + error:{error,{asn1,{encode_length,_}}} -> + encode_fragmented_octet_string(Val) + end; + Sv when is_integer(Sv), Sv =:= length(Val) -> % fixed length + if + Sv =< 65535 -> + list_to_binary(Val); + true -> + encode_fragmented_octet_string(Val) + end; + Sv when is_list(Sv) -> + try + [encode_length({hd(Sv),lists:max(Sv)}, + length(Val)),list_to_binary(Val)] + catch + error:{error,{asn1,{encode_length,_}}} -> + encode_fragmented_octet_string(Val) + end; + no -> + try + [encode_length(length(Val)),list_to_binary(Val)] + catch + error:{error,{asn1,{encode_length,_}}} -> + encode_fragmented_octet_string(Val) + end + end. + +encode_fragmented_octet_string(Val) -> + Bin = list_to_binary(Val), + efos_1(Bin). + +efos_1(<>) -> + [<<3:2,4:6>>,B|efos_1(T)]; +efos_1(<>) -> + [<<3:2,3:6>>,B|efos_1(T)]; +efos_1(<>) -> + [<<3:2,2:6>>,B|efos_1(T)]; +efos_1(<>) -> + [<<3:2,1:6>>,B|efos_1(T)]; +efos_1(<>) -> + Len = byte_size(B), + [encode_length(Len),B]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Restricted char string types +%% (NumericString, PrintableString,VisibleString,IA5String,BMPString,UniversalString) +%% X.691:26 and X.680:34-36 +%%encode_restricted_string('BMPString',Constraints,Extension,Val) + + +encode_restricted_string(Val) when is_list(Val)-> + [encode_length(length(Val)),list_to_binary(Val)]. + +encode_known_multiplier_string(StringType, C, Val) -> + Result = chars_encode(C, StringType, Val), + NumBits = get_NumBits(C, StringType), + case get_constraint(C, 'SizeConstraint') of + Ub when is_integer(Ub), Ub*NumBits =< 16 -> + Result; + 0 -> + []; + Ub when is_integer(Ub),Ub =<65535 -> % fixed length + Result; + {Ub,Lb} -> + [encode_length({Ub,Lb}, length(Val)),Result]; + Vl when is_list(Vl) -> + [encode_length({lists:min(Vl),lists:max(Vl)}, length(Val)),Result]; + no -> + [encode_length(length(Val)),Result] + end. + +decode_restricted_string(Bytes) -> + {Len,Bytes2} = decode_length(Bytes, undefined), + getoctets_as_list(Bytes2,Len). + +decode_known_multiplier_string(Bytes, StringType, C, _Ext) -> + NumBits = get_NumBits(C, StringType), + case get_constraint(C, 'SizeConstraint') of + Ub when is_integer(Ub), Ub*NumBits =< 16 -> + chars_decode(Bytes, NumBits, StringType, C, Ub); + Ub when is_integer(Ub), Ub =<65535 -> % fixed length + chars_decode(Bytes,NumBits,StringType,C,Ub); + 0 -> + {[],Bytes}; + Vl when is_list(Vl) -> + {Len,Bytes1} = decode_length(Bytes,{hd(Vl),lists:max(Vl)}), + chars_decode(Bytes1,NumBits,StringType,C,Len); + no -> + {Len,Bytes1} = decode_length(Bytes,undefined), + chars_decode(Bytes1,NumBits,StringType,C,Len); + {Lb,Ub}-> + {Len,Bytes1} = decode_length(Bytes,{Lb,Ub}), + chars_decode(Bytes1,NumBits,StringType,C,Len) + end. + + +encode_NumericString(C,Val) -> + encode_known_multiplier_string('NumericString',C,Val). +decode_NumericString(Bytes,C) -> + decode_known_multiplier_string(Bytes,'NumericString',C,false). + +encode_PrintableString(C,Val) -> + encode_known_multiplier_string('PrintableString',C,Val). +decode_PrintableString(Bytes,C) -> + decode_known_multiplier_string(Bytes,'PrintableString',C,false). + +encode_VisibleString(C,Val) -> % equivalent with ISO646String + encode_known_multiplier_string('VisibleString',C,Val). +decode_VisibleString(Bytes,C) -> + decode_known_multiplier_string(Bytes,'VisibleString',C,false). + +encode_IA5String(C,Val) -> + encode_known_multiplier_string('IA5String',C,Val). +decode_IA5String(Bytes,C) -> + decode_known_multiplier_string(Bytes,'IA5String',C,false). + +encode_BMPString(C,Val) -> + encode_known_multiplier_string('BMPString',C,Val). +decode_BMPString(Bytes,C) -> + decode_known_multiplier_string(Bytes,'BMPString',C,false). + +encode_UniversalString(C,Val) -> + encode_known_multiplier_string('UniversalString',C,Val). +decode_UniversalString(Bytes,C) -> + decode_known_multiplier_string(Bytes,'UniversalString',C,false). + + +%% end of known-multiplier strings for which PER visible constraints are +%% applied + +encode_GeneralString(_C,Val) -> + encode_restricted_string(Val). +decode_GeneralString(Bytes,_C) -> + decode_restricted_string(Bytes). + +encode_GraphicString(_C,Val) -> + encode_restricted_string(Val). +decode_GraphicString(Bytes,_C) -> + decode_restricted_string(Bytes). + +encode_ObjectDescriptor(_C,Val) -> + encode_restricted_string(Val). +decode_ObjectDescriptor(Bytes) -> + decode_restricted_string(Bytes). + +encode_TeletexString(_C,Val) -> % equivalent with T61String + encode_restricted_string(Val). +decode_TeletexString(Bytes,_C) -> + decode_restricted_string(Bytes). + +encode_VideotexString(_C,Val) -> + encode_restricted_string(Val). +decode_VideotexString(Bytes,_C) -> + decode_restricted_string(Bytes). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% getBMPChars(Bytes, Len) -> {BMPcharList,RemainingBytes} +%% +getBMPChars(Bytes, 1) -> + {O1,Bytes2} = getbits(Bytes, 8), + {O2,Bytes3} = getbits(Bytes2, 8), + if + O1 == 0 -> + {[O2],Bytes3}; + true -> + {[{0,0,O1,O2}],Bytes3} + end; +getBMPChars(Bytes, Len) -> + getBMPChars(Bytes, Len, []). + +getBMPChars(Bytes, 0, Acc) -> + {lists:reverse(Acc),Bytes}; +getBMPChars(Bytes, Len, Acc) -> + {Octs,Bytes1} = getoctets_as_list(Bytes,2), + case Octs of + [0,O2] -> + getBMPChars(Bytes1, Len-1, [O2|Acc]); + [O1,O2]-> + getBMPChars(Bytes1, Len-1, [{0,0,O1,O2}|Acc]) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% chars_encode(C,StringType,Value) -> ValueList +%% +%% encodes chars according to the per rules taking the constraint PermittedAlphabet +%% into account. +%% This function does only encode the value part and NOT the length + +chars_encode(C,StringType,Value) -> + case {StringType,get_constraint(C,'PermittedAlphabet')} of + {'UniversalString',{_,_Sv}} -> + exit({error,{asn1,{'not implemented',"UniversalString with PermittedAlphabet constraint"}}}); + {'BMPString',{_,_Sv}} -> + exit({error,{asn1,{'not implemented',"BMPString with PermittedAlphabet constraint"}}}); + _ -> + {NumBits,CharOutTab} = {get_NumBits(C,StringType),get_CharOutTab(C,StringType)}, + chars_encode2(Value,NumBits,CharOutTab) + end. + +chars_encode2([H|T],NumBits,{Min,Max,notab}) when H =< Max, H >= Min -> + [<<(H-Min):NumBits>>|chars_encode2(T,NumBits,{Min,Max,notab})]; +chars_encode2([H|T],NumBits,{Min,Max,Tab}) when H =< Max, H >= Min -> + Ch = exit_if_false(H,element(H-Min+1,Tab)), + [<>|chars_encode2(T,NumBits,{Min,Max,Tab})]; +chars_encode2([{A,B,C,D}|T],NumBits,{Min,Max,notab}) -> + %% no value range check here (ought to be, but very expensive) + Ch = ((((((A bsl 8)+B) bsl 8)+C) bsl 8)+D)-Min, + [<>|chars_encode2(T,NumBits,{Min,Max,notab})]; +chars_encode2([{A,B,C,D}|T],NumBits,{Min,Max,Tab}) -> + %% no value range check here (ought to be, but very expensive) + Ch = exit_if_false({A,B,C,D},element(((((((A bsl 8)+B) bsl 8)+C) bsl 8)+D)-Min,Tab)), + [<>|chars_encode2(T,NumBits,{Min,Max,notab})]; +chars_encode2([H|_T],_,{_,_,_}) -> + exit({error,{asn1,{illegal_char_value,H}}}); +chars_encode2([],_,_) -> + []. + +exit_if_false(V,false)-> + exit({error,{asn1,{"illegal value according to Permitted alphabet constraint",V}}}); +exit_if_false(_,V) ->V. + + +get_NumBits(C,StringType) -> + case get_constraint(C,'PermittedAlphabet') of + {'SingleValue',Sv} -> + charbits(length(Sv)); + no -> + case StringType of + 'IA5String' -> + charbits(128); % 16#00..16#7F + 'VisibleString' -> + charbits(95); % 16#20..16#7E + 'PrintableString' -> + charbits(74); % [$\s,$',$(,$),$+,$,,$-,$.,$/,"0123456789",$:,$=,$?,$A..$Z,$a..$z + 'NumericString' -> + charbits(11); % $ ,"0123456789" + 'UniversalString' -> + 32; + 'BMPString' -> + 16 + end + end. + +get_CharOutTab(C,StringType) -> + get_CharTab(C,StringType,out). + +get_CharInTab(C,StringType) -> + get_CharTab(C,StringType,in). + +get_CharTab(C,StringType,InOut) -> + case get_constraint(C,'PermittedAlphabet') of + {'SingleValue',Sv} -> + get_CharTab2(C,StringType,hd(Sv),lists:max(Sv),Sv,InOut); + no -> + case StringType of + 'IA5String' -> + {0,16#7F,notab}; + 'VisibleString' -> + get_CharTab2(C,StringType,16#20,16#7F,notab,InOut); + 'PrintableString' -> + Chars = lists:sort( + " '()+,-./0123456789:=?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), + get_CharTab2(C,StringType,hd(Chars),lists:max(Chars),Chars,InOut); + 'NumericString' -> + get_CharTab2(C,StringType,16#20,$9," 0123456789",InOut); + 'UniversalString' -> + {0,16#FFFFFFFF,notab}; + 'BMPString' -> + {0,16#FFFF,notab} + end + end. + +get_CharTab2(C,StringType,Min,Max,Chars,InOut) -> + BitValMax = (1 bsl get_NumBits(C,StringType))-1, + if + Max =< BitValMax -> + {0,Max,notab}; + true -> + case InOut of + out -> + {Min,Max,create_char_tab(Min,Chars)}; + in -> + {Min,Max,list_to_tuple(Chars)} + end + end. + +create_char_tab(Min,L) -> + list_to_tuple(create_char_tab(Min,L,0)). +create_char_tab(Min,[Min|T],V) -> + [V|create_char_tab(Min+1,T,V+1)]; +create_char_tab(_Min,[],_V) -> + []; +create_char_tab(Min,L,V) -> + [false|create_char_tab(Min+1,L,V)]. + +%% See Table 20.3 in Dubuisson +charbits(NumOfChars) when NumOfChars =< 2 -> 1; +charbits(NumOfChars) when NumOfChars =< 4 -> 2; +charbits(NumOfChars) when NumOfChars =< 8 -> 3; +charbits(NumOfChars) when NumOfChars =< 16 -> 4; +charbits(NumOfChars) when NumOfChars =< 32 -> 5; +charbits(NumOfChars) when NumOfChars =< 64 -> 6; +charbits(NumOfChars) when NumOfChars =< 128 -> 7; +charbits(NumOfChars) when NumOfChars =< 256 -> 8; +charbits(NumOfChars) when NumOfChars =< 512 -> 9; +charbits(NumOfChars) when NumOfChars =< 1024 -> 10; +charbits(NumOfChars) when NumOfChars =< 2048 -> 11; +charbits(NumOfChars) when NumOfChars =< 4096 -> 12; +charbits(NumOfChars) when NumOfChars =< 8192 -> 13; +charbits(NumOfChars) when NumOfChars =< 16384 -> 14; +charbits(NumOfChars) when NumOfChars =< 32768 -> 15; +charbits(NumOfChars) when NumOfChars =< 65536 -> 16; +charbits(NumOfChars) when is_integer(NumOfChars) -> + 16 + charbits1(NumOfChars bsr 16). + +charbits1(0) -> + 0; +charbits1(NumOfChars) -> + 1 + charbits1(NumOfChars bsr 1). + + +chars_decode(Bytes,_,'BMPString',C,Len) -> + case get_constraint(C,'PermittedAlphabet') of + no -> + getBMPChars(Bytes,Len); + _ -> + exit({error,{asn1, + {'not implemented', + "BMPString with PermittedAlphabet constraint"}}}) + end; +chars_decode(Bytes,NumBits,StringType,C,Len) -> + CharInTab = get_CharInTab(C,StringType), + chars_decode2(Bytes,CharInTab,NumBits,Len). + + +chars_decode2(Bytes,CharInTab,NumBits,Len) -> + chars_decode2(Bytes,CharInTab,NumBits,Len,[]). + +chars_decode2(Bytes,_CharInTab,_NumBits,0,Acc) -> + {lists:reverse(Acc),Bytes}; +chars_decode2(Bytes,{Min,Max,notab},NumBits,Len,Acc) when NumBits > 8 -> + {Char,Bytes2} = getbits(Bytes,NumBits), + Result = + if + Char < 256 -> Char; + true -> + list_to_tuple(binary_to_list(<>)) + end, + chars_decode2(Bytes2,{Min,Max,notab},NumBits,Len -1,[Result|Acc]); +chars_decode2(Bytes,{Min,Max,notab},NumBits,Len,Acc) -> + {Char,Bytes2} = getbits(Bytes,NumBits), + chars_decode2(Bytes2,{Min,Max,notab},NumBits,Len -1,[Char+Min|Acc]); + +%% BMPString and UniversalString with PermittedAlphabet is currently not supported +chars_decode2(Bytes,{Min,Max,CharInTab},NumBits,Len,Acc) -> + {Char,Bytes2} = getbits(Bytes,NumBits), + chars_decode2(Bytes2,{Min,Max,CharInTab},NumBits,Len -1,[element(Char+1,CharInTab)|Acc]). + + +%% UTF8String +encode_UTF8String(Val) when is_binary(Val) -> + [encode_length(byte_size(Val)),Val]; +encode_UTF8String(Val) -> + Bin = list_to_binary(Val), + encode_UTF8String(Bin). + +decode_UTF8String(Bytes) -> + {Len,Bytes2} = decode_length(Bytes, undefined), + getoctets_as_bin(Bytes2,Len). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% encode_object_identifier(Val) -> CompleteList +%% encode_object_identifier({Name,Val}) -> CompleteList +%% Val -> {Int1,Int2,...,IntN} % N >= 2 +%% Name -> atom() +%% Int1 -> integer(0..2) +%% Int2 -> integer(0..39) when Int1 (0..1) else integer() +%% Int3-N -> integer() +%% CompleteList -> [binary()|bitstring()|list()] +%% +encode_object_identifier(Val) -> + OctetList = e_object_identifier(Val), + Octets = list_to_binary(OctetList), % performs a flatten at the same time + [encode_length(byte_size(Octets)),Octets]. + +%% This code is copied from asn1_encode.erl (BER) and corrected and modified + +e_object_identifier({'OBJECT IDENTIFIER',V}) -> + e_object_identifier(V); +e_object_identifier(V) when is_tuple(V) -> + e_object_identifier(tuple_to_list(V)); + +%% E1 = 0|1|2 and (E2 < 40 when E1 = 0|1) +e_object_identifier([E1,E2|Tail]) when E1 >= 0, E1 < 2, E2 < 40 ; E1==2 -> + Head = 40*E1 + E2, % weird + e_object_elements([Head|Tail],[]); +e_object_identifier(Oid=[_,_|_Tail]) -> + exit({error,{asn1,{'illegal_value',Oid}}}). + +e_object_elements([],Acc) -> + lists:reverse(Acc); +e_object_elements([H|T],Acc) -> + e_object_elements(T,[e_object_element(H)|Acc]). + +e_object_element(Num) when Num < 128 -> + [Num]; +e_object_element(Num) -> + [e_o_e(Num bsr 7)|[Num band 2#1111111]]. +e_o_e(Num) when Num < 128 -> + Num bor 2#10000000; +e_o_e(Num) -> + [e_o_e(Num bsr 7)|[(Num band 2#1111111) bor 2#10000000]]. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% decode_object_identifier(Bytes) -> {ObjId,RemainingBytes} +%% ObjId -> {integer(),integer(),...} % at least 2 integers +%% RemainingBytes -> [integer()] when integer() (0..255) +decode_object_identifier(Bytes) -> + {Len,Bytes2} = decode_length(Bytes,undefined), + {Octs,Bytes3} = getoctets_as_list(Bytes2,Len), + [First|Rest] = dec_subidentifiers(Octs,0,[]), + Idlist = if + First < 40 -> + [0,First|Rest]; + First < 80 -> + [1,First - 40|Rest]; + true -> + [2,First - 80|Rest] + end, + {list_to_tuple(Idlist),Bytes3}. + +dec_subidentifiers([H|T],Av,Al) when H >=16#80 -> + dec_subidentifiers(T, (Av bsl 7) + (H band 16#7F),Al); +dec_subidentifiers([H|T],Av,Al) -> + dec_subidentifiers(T,0, [(Av bsl 7) + H |Al]); +dec_subidentifiers([],_Av,Al) -> + lists:reverse(Al). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% encode_relative_oid(Val) -> CompleteList +%% encode_relative_oid({Name,Val}) -> CompleteList +encode_relative_oid(Val) when is_tuple(Val) -> + encode_relative_oid(tuple_to_list(Val)); +encode_relative_oid(Val) when is_list(Val) -> + Octets = list_to_binary([e_object_element(X)||X <- Val]), + [encode_length(byte_size(Octets)),Octets]. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% decode_relative_oid(Val) -> CompleteList +%% decode_relative_oid({Name,Val}) -> CompleteList +decode_relative_oid(Bytes) -> + {Len,Bytes2} = decode_length(Bytes,undefined), + {Octs,Bytes3} = getoctets_as_list(Bytes2,Len), + ObjVals = dec_subidentifiers(Octs,0,[]), + {list_to_tuple(ObjVals),Bytes3}. + + +get_constraint([{Key,V}],Key) -> + V; +get_constraint([],_Key) -> + no; +get_constraint(C,Key) -> + case lists:keyfind(Key, 1, C) of + false -> + no; + {_,V} -> + V + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% complete(InList) -> ByteList +%% Takes a coded list with bits and bytes and converts it to a list of bytes +%% Should be applied as the last step at encode of a complete ASN.1 type +%% +complete(InList) when is_list(InList) -> + case complete1(InList) of + <<>> -> + <<0>>; + Res -> + case bit_size(Res) band 7 of + 0 -> Res; + Bits -> <> + end + end; +complete(InList) when is_binary(InList) -> + InList; +complete(InList) when is_bitstring(InList) -> + PadLen = 8 - (bit_size(InList) band 7), + <>. + +complete1(L) when is_list(L) -> + list_to_bitstring(L). + +%% Special version of complete that does not align the completed message. +complete_NFP(InList) when is_list(InList) -> + list_to_bitstring(InList); +complete_NFP(InList) when is_bitstring(InList) -> + InList. + +%% unaligned helpers + +%% 10.5.6 NOTE: If "range" satisfies the inequality 2^m < "range" =< +%% 2^(m+1) then the number of bits = m + 1 + +num_bits(N) -> num_bits(N, 1, 0). + +num_bits(N,T,B) when N =< T -> B; +num_bits(N,T,B) -> num_bits(N, T bsl 1, B+1). -- cgit v1.2.3 From 14ccfeb0453e296395cb54400f95712b1be6f615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 18 Dec 2012 12:12:20 +0100 Subject: Add and use asn1rtt_check --- lib/asn1/src/Makefile | 3 +- lib/asn1/src/asn1ct_gen.erl | 47 +++---- lib/asn1/src/asn1rtt_check.erl | 276 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 297 insertions(+), 29 deletions(-) create mode 100644 lib/asn1/src/asn1rtt_check.erl (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile index 75ffdd66c7..a9806c13a4 100644 --- a/lib/asn1/src/Makefile +++ b/lib/asn1/src/Makefile @@ -173,7 +173,8 @@ release_docs_spec: # Run-time library template files. # -RT_TEMPLATES = asn1rtt_per_common \ +RT_TEMPLATES = asn1rtt_check \ + asn1rtt_per_common \ asn1rtt_real_common \ asn1rtt_ber \ asn1rtt_per \ diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl index eaca7d6ec3..ce15e01d32 100644 --- a/lib/asn1/src/asn1ct_gen.erl +++ b/lib/asn1/src/asn1ct_gen.erl @@ -1496,50 +1496,41 @@ gen_check_call(TopType,Cname,Type,InnerType,WhatKind,DefaultValue,Element) -> emit(["fun() -> true end ()"]) end. -gen_prim_check_call(PrimType,DefaultValue,Element,Type) -> +gen_prim_check_call(PrimType, Default, Element, Type) -> case unify_if_string(PrimType) of 'BOOLEAN' -> - emit({"asn1rt_check:check_bool(",DefaultValue,", ", - Element,")"}); + check_call(check_bool, [Default,Element]); 'INTEGER' -> - NNL = - case Type#type.def of - {_,NamedNumberList} -> NamedNumberList; - _ -> [] - end, - emit({"asn1rt_check:check_int(",DefaultValue,", ", - Element,", ",{asis,NNL},")"}); + NNL = case Type#type.def of + {_,NamedNumberList} -> NamedNumberList; + _ -> [] + end, + check_call(check_int, [Default,Element,{asis,NNL}]); 'BIT STRING' -> {_,NBL} = Type#type.def, - emit({"asn1rt_check:check_bitstring(",DefaultValue,", ", - Element,", ",{asis,NBL},")"}); + check_call(check_bitstring, [Default,Element,{asis,NBL}]); 'OCTET STRING' -> - emit({"asn1rt_check:check_octetstring(",DefaultValue,", ", - Element,")"}); + check_call(check_octetstring, [Default,Element]); 'NULL' -> - emit({"asn1rt_check:check_null(",DefaultValue,", ", - Element,")"}); + check_call(check_null, [Default,Element]); 'OBJECT IDENTIFIER' -> - emit({"asn1rt_check:check_objectidentifier(",DefaultValue, - ", ",Element,")"}); + check_call(check_objectidentifier, [Default,Element]); 'RELATIVE-OID' -> - emit({"asn1rt_check:check_objectidentifier(",DefaultValue, - ", ",Element,")"}); + check_call(check_objectidentifier, [Default,Element]); 'ObjectDescriptor' -> - emit({"asn1rt_check:check_objectdescriptor(",DefaultValue, - ", ",Element,")"}); + check_call(check_objectdescriptor, [Default,Element]); 'REAL' -> - emit({"asn1rt_check:check_real(",DefaultValue, - ", ",Element,")"}); + check_call(check_real, [Default,Element]); 'ENUMERATED' -> {_,Enumerations} = Type#type.def, - emit({"asn1rt_check:check_enum(",DefaultValue, - ", ",Element,", ",{asis,Enumerations},")"}); + check_call(check_enum, [Default,Element,{asis,Enumerations}]); restrictedstring -> - emit({"asn1rt_check:check_restrictedstring(",DefaultValue, - ", ",Element,")"}) + check_call(check_restrictedstring, [Default,Element]) end. +check_call(F, Args) -> + asn1ct_func:call(check, F, Args). + %% lokahead_innertype/3 traverses Type and checks if check functions %% have to be generated, i.e. for all constructed or referenced types. lookahead_innertype(Name,'SEQUENCE',Type) -> diff --git a/lib/asn1/src/asn1rtt_check.erl b/lib/asn1/src/asn1rtt_check.erl new file mode 100644 index 0000000000..e78b65a8fb --- /dev/null +++ b/lib/asn1/src/asn1rtt_check.erl @@ -0,0 +1,276 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(asn1rtt_check). + +-export([check_bool/2, + check_int/3, + check_bitstring/3, + check_octetstring/2, + check_null/2, + check_objectidentifier/2, + check_objectdescriptor/2, + check_real/2, + check_enum/3, + check_restrictedstring/2]). + +check_bool(_Bool, asn1_DEFAULT) -> + true; +check_bool(Bool, Bool) when is_boolean(Bool) -> + true; +check_bool(_Bool1, Bool2) -> + throw({error,Bool2}). + +check_int(_, asn1_DEFAULT, _) -> + true; +check_int(Value, Value, _) when is_integer(Value) -> + true; +check_int(DefValue, Value, NNL) when is_atom(Value) -> + case lists:keyfind(Value, 1, NNL) of + {_,DefValue} -> + true; + _ -> + throw({error,DefValue}) + end; +check_int(DefaultValue, _Value, _) -> + throw({error,DefaultValue}). + +%% Two equal lists or integers +check_bitstring(_, asn1_DEFAULT, _) -> + true; +check_bitstring(V, V, _) -> + true; +%% Default value as a list of 1 and 0 and user value as an integer +check_bitstring(L=[H|T], Int, _) when is_integer(Int), is_integer(H) -> + case bit_list_to_int(L, length(T)) of + Int -> true; + _ -> throw({error,L,Int}) + end; +%% Default value as an integer, val as list +check_bitstring(Int, Val, NBL) when is_integer(Int), is_list(Val) -> + BL = int_to_bit_list(Int, [], length(Val)), + check_bitstring(BL, Val, NBL); +%% Default value and user value as lists of ones and zeros +check_bitstring(L1=[H1|_T1], L2=[H2|_T2], NBL=[_H|_T]) when is_integer(H1), is_integer(H2) -> + L2new = remove_trailing_zeros(L2), + check_bitstring(L1, L2new, NBL); +%% Default value as a list of 1 and 0 and user value as a list of atoms +check_bitstring(L1=[H1|_T1], L2=[H2|_T2], NBL) when is_integer(H1), is_atom(H2) -> + L3 = bit_list_to_nbl(L1, NBL, 0, []), + check_bitstring(L3, L2, NBL); +%% Both default value and user value as a list of atoms +check_bitstring(L1=[H1|T1], L2=[H2|_T2], _) + when is_atom(H1), is_atom(H2), length(L1) =:= length(L2) -> + case lists:member(H1, L2) of + true -> + check_bitstring1(T1, L2); + false -> throw({error,L2}) + end; +%% Default value as a list of atoms and user value as a list of 1 and 0 +check_bitstring(L1=[H1|_T1], L2=[H2|_T2], NBL) when is_atom(H1), is_integer(H2) -> + L3 = bit_list_to_nbl(L2, NBL, 0, []), + check_bitstring(L1, L3, NBL); +%% User value in compact format +check_bitstring(DefVal,CBS={_,_}, NBL) -> + NewVal = cbs_to_bit_list(CBS), + check_bitstring(DefVal, NewVal, NBL); +check_bitstring(DV, V, _) -> + throw({error,DV,V}). + + +bit_list_to_int([0|Bs], ShL)-> + bit_list_to_int(Bs, ShL-1) + 0; +bit_list_to_int([1|Bs], ShL) -> + bit_list_to_int(Bs, ShL-1) + (1 bsl ShL); +bit_list_to_int([], _) -> + 0. + +int_to_bit_list(0, Acc, 0) -> + Acc; +int_to_bit_list(Int, Acc, Len) -> + int_to_bit_list(Int bsr 1, [Int band 1|Acc], Len - 1). + +bit_list_to_nbl([0|T], NBL, Pos, Acc) -> + bit_list_to_nbl(T, NBL, Pos+1, Acc); +bit_list_to_nbl([1|T], NBL, Pos, Acc) -> + case lists:keyfind(Pos, 2, NBL) of + {N,_} -> + bit_list_to_nbl(T, NBL, Pos+1, [N|Acc]); + _ -> + throw({error,{no,named,element,at,pos,Pos}}) + end; +bit_list_to_nbl([], _, _, Acc) -> + Acc. + +remove_trailing_zeros(L2) -> + remove_trailing_zeros1(lists:reverse(L2)). +remove_trailing_zeros1(L) -> + lists:reverse(lists:dropwhile(fun(0)->true; + (_) ->false + end, + L)). + +check_bitstring1([H|T], NBL) -> + case lists:member(H, NBL) of + true -> check_bitstring1(T, NBL); + V -> throw({error,V}) + end; +check_bitstring1([], _) -> + true. + +cbs_to_bit_list({Unused, <>}) when byte_size(Rest) >= 1 -> + [B7,B6,B5,B4,B3,B2,B1,B0|cbs_to_bit_list({Unused,Rest})]; +cbs_to_bit_list({0,<>}) -> + [B7,B6,B5,B4,B3,B2,B1,B0]; +cbs_to_bit_list({Unused,Bin}) when byte_size(Bin) =:= 1 -> + Used = 8-Unused, + <> = Bin, + int_to_bit_list(Int, [], Used). + + +check_octetstring(_, asn1_DEFAULT) -> + true; +check_octetstring(L, L) -> + true; +check_octetstring(L, Int) when is_list(L), is_integer(Int) -> + case integer_to_octetlist(Int) of + L -> true; + V -> throw({error,V}) + end; +check_octetstring(_, V) -> + throw({error,V}). + +integer_to_octetlist(Int) -> + integer_to_octetlist(Int, []). +integer_to_octetlist(0, Acc) -> + Acc; +integer_to_octetlist(Int, Acc) -> + integer_to_octetlist(Int bsr 8, [(Int band 255)|Acc]). + +check_null(_, asn1_DEFAULT) -> + true; +check_null('NULL', 'NULL') -> + true; +check_null(_, V) -> + throw({error,V}). + +check_objectidentifier(_, asn1_DEFAULT) -> + true; +check_objectidentifier(OI, OI) -> + true; +check_objectidentifier(DOI, OI) when is_tuple(DOI), is_tuple(OI) -> + check_objectidentifier1(tuple_to_list(DOI), tuple_to_list(OI)); +check_objectidentifier(_, OI) -> + throw({error,OI}). + +check_objectidentifier1([V|Rest1], [V|Rest2]) -> + check_objectidentifier1(Rest1, Rest2, V); +check_objectidentifier1([V1|Rest1], [V2|Rest2]) -> + case reserved_objectid(V2, []) of + V1 -> + check_objectidentifier1(Rest1, Rest2, [V1]); + V -> + throw({error,V}) + end. +check_objectidentifier1([V|Rest1], [V|Rest2], Above) -> + check_objectidentifier1(Rest1, Rest2, [V|Above]); +check_objectidentifier1([V1|Rest1], [V2|Rest2], Above) -> + case reserved_objectid(V2, Above) of + V1 -> + check_objectidentifier1(Rest1, Rest2, [V1|Above]); + V -> + throw({error,V}) + end; +check_objectidentifier1([], [], _) -> + true; +check_objectidentifier1(_, V, _) -> + throw({error,object,identifier,V}). + +%% ITU-T Rec. X.680 Annex B - D +reserved_objectid('itu-t', []) -> 0; +reserved_objectid('ccitt', []) -> 0; +%% arcs below "itu-t" +reserved_objectid('recommendation', [0]) -> 0; +reserved_objectid('question', [0]) -> 1; +reserved_objectid('administration', [0]) -> 2; +reserved_objectid('network-operator', [0]) -> 3; +reserved_objectid('identified-organization', [0]) -> 4; + +reserved_objectid(iso, []) -> 1; +%% arcs below "iso", note that number 1 is not used +reserved_objectid('standard', [1]) -> 0; +reserved_objectid('member-body', [1]) -> 2; +reserved_objectid('identified-organization', [1]) -> 3; + +reserved_objectid('joint-iso-itu-t', []) -> 2; +reserved_objectid('joint-iso-ccitt', []) -> 2; + +reserved_objectid(_, _) -> false. + + +check_objectdescriptor(_, asn1_DEFAULT) -> + true; +check_objectdescriptor(OD, OD) -> + true; +check_objectdescriptor(OD, OD) -> + throw({error,{not_implemented_yet,check_objectdescriptor}}). + +check_real(_, asn1_DEFAULT) -> + true; +check_real(R, R) -> + true; +check_real(_, _) -> + throw({error,{not_implemented_yet,check_real}}). + +check_enum(_, asn1_DEFAULT, _) -> + true; +check_enum(Val, Val, _) -> + true; +check_enum(Int, Atom, Enumerations) when is_integer(Int), is_atom(Atom) -> + case lists:keyfind(Atom, 1, Enumerations) of + {_,Int} -> true; + _ -> throw({error,{enumerated,Int,Atom}}) + end; +check_enum(DefVal, Val, _) -> + throw({error,{enumerated,DefVal,Val}}). + + +check_restrictedstring(_, asn1_DEFAULT) -> + true; +check_restrictedstring(Val, Val) -> + true; +check_restrictedstring([V|Rest1], [V|Rest2]) -> + check_restrictedstring(Rest1, Rest2); +check_restrictedstring([V1|Rest1], [V2|Rest2]) -> + check_restrictedstring(V1, V2), + check_restrictedstring(Rest1, Rest2); +%% tuple format of value +check_restrictedstring({V1,V2}, [V1,V2]) -> + true; +check_restrictedstring([V1,V2], {V1,V2}) -> + true; +%% quadruple format of value +check_restrictedstring({V1,V2,V3,V4}, [V1,V2,V3,V4]) -> + true; +check_restrictedstring([V1,V2,V3,V4], {V1,V2,V3,V4}) -> + true; +%% character string list +check_restrictedstring(V1, V2) when is_list(V1), is_tuple(V2) -> + check_restrictedstring(V1, tuple_to_list(V2)); +check_restrictedstring(V1, V2) -> + throw({error,{restricted,string,V1,V2}}). -- cgit v1.2.3 From 6524db299d01e4041f02de15c1bb8eb2922408b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 19 Dec 2012 07:24:58 +0100 Subject: Add and use asn1rtt_ext --- lib/asn1/src/Makefile | 1 + lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl | 11 ++-- lib/asn1/src/asn1ct_constructed_per.erl | 13 ++--- lib/asn1/src/asn1rtt_ext.erl | 69 ++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 11 deletions(-) create mode 100644 lib/asn1/src/asn1rtt_ext.erl (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile index a9806c13a4..b54627a9b3 100644 --- a/lib/asn1/src/Makefile +++ b/lib/asn1/src/Makefile @@ -174,6 +174,7 @@ release_docs_spec: # RT_TEMPLATES = asn1rtt_check \ + asn1rtt_ext \ asn1rtt_per_common \ asn1rtt_real_common \ asn1rtt_ber \ diff --git a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl index 021002c3b3..d5097e83c5 100644 --- a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl +++ b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl @@ -66,9 +66,9 @@ gen_encode_sequence(Erules,Typename,D) when is_record(D,type) -> ValName = case Typename of ['EXTERNAL'] -> - emit([indent(4), - "NewVal = asn1rt_check:transform_to_EXTERNAL1990(Val),", - nl]), + emit([indent(4),"NewVal = ", + {call,ext,transform_to_EXTERNAL1990,["Val"]}, + com,nl]), "NewVal"; _ -> "Val" @@ -289,8 +289,9 @@ gen_decode_sequence(Erules,Typename,D) when is_record(D,type) -> "', "]), mkvlist(asn1ct_name:all(term)), emit(["},",nl]), - emit([" asn1rt_check:transform_to_EXTERNAL1994", - "(OldFormat).",nl]); + emit([" ", + {call,ext,transform_to_EXTERNAL1994, + ["OldFormat"]},".",nl]); _ -> emit([" {'",RecordName,"', "]), mkvlist(asn1ct_name:all(term)), diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl index 5520b41541..c3aa482051 100644 --- a/lib/asn1/src/asn1ct_constructed_per.erl +++ b/lib/asn1/src/asn1ct_constructed_per.erl @@ -67,9 +67,9 @@ gen_encode_constructed(Erule,Typename,D) when is_record(D,type) -> end, case Typename of ['EXTERNAL'] -> - emit({{next,val}, - " = asn1rt_check:transform_to_EXTERNAL1990(", - {curr,val},"),",nl}), + emit([{next,val}," = ", + {call,ext,transform_to_EXTERNAL1990, + [{curr,val}]},com,nl]), asn1ct_name:new(val); _ -> ok @@ -386,9 +386,10 @@ gen_dec_constructed_imm_2(Typename, CompList, "'"}), mkvlist(asn1ct_name:all(term)), emit({"},",nl}), - emit({" ASN11994Format =",nl, - " asn1rt_check:transform_to_EXTERNAL1994", - "(OldFormat),",nl}), + emit([" ASN11994Format =",nl, + " ", + {call,ext,transform_to_EXTERNAL1994, + ["OldFormat"]},com,nl]), emit(" {ASN11994Format,"); _ -> emit(["{{'",RecordName,"'"]), diff --git a/lib/asn1/src/asn1rtt_ext.erl b/lib/asn1/src/asn1rtt_ext.erl new file mode 100644 index 0000000000..59dbcc16bd --- /dev/null +++ b/lib/asn1/src/asn1rtt_ext.erl @@ -0,0 +1,69 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(asn1rtt_ext). +-export([transform_to_EXTERNAL1990/1,transform_to_EXTERNAL1994/1]). + +transform_to_EXTERNAL1990({_,_,_,_}=Val) -> + transform_to_EXTERNAL1990(tuple_to_list(Val), []); +transform_to_EXTERNAL1990(Val) when is_tuple(Val) -> + %% Data already in ASN1 1990 format + Val. + +transform_to_EXTERNAL1990(['EXTERNAL'|Rest], Acc) -> + transform_to_EXTERNAL1990(Rest, ['EXTERNAL'|Acc]); +transform_to_EXTERNAL1990([{syntax,Syntax}|Rest], Acc) -> + transform_to_EXTERNAL1990(Rest, [asn1_NOVALUE,Syntax|Acc]); +transform_to_EXTERNAL1990([{'presentation-context-id',PCid}|Rest], Acc) -> + transform_to_EXTERNAL1990(Rest, [PCid,asn1_NOVALUE|Acc]); +transform_to_EXTERNAL1990([{'context-negotiation',Context_negot}|Rest], Acc) -> + {_,Presentation_Cid,Transfer_syntax} = Context_negot, + transform_to_EXTERNAL1990(Rest, [Presentation_Cid,Transfer_syntax|Acc]); +transform_to_EXTERNAL1990([asn1_NOVALUE|Rest], Acc) -> + transform_to_EXTERNAL1990(Rest, [asn1_NOVALUE|Acc]); +transform_to_EXTERNAL1990([Data_val_desc,Data_value], Acc) + when is_list(Data_value)-> + list_to_tuple(lists:reverse([{'octet-aligned',Data_value}, + Data_val_desc|Acc])); +transform_to_EXTERNAL1990([Data_val_desc,Data_value], Acc) + when is_binary(Data_value) -> + list_to_tuple(lists:reverse([{'single-ASN1-type',Data_value}, + Data_val_desc|Acc])); +transform_to_EXTERNAL1990([Data_value], Acc) + when is_list(Data_value); is_binary(Data_value) -> + list_to_tuple(lists:reverse([{'octet-aligned',Data_value}|Acc])). + + +transform_to_EXTERNAL1994({'EXTERNAL',DRef,IndRef,Data_v_desc,Encoding}=V) -> + Identification = + case {DRef,IndRef} of + {DRef,asn1_NOVALUE} -> + {syntax,DRef}; + {asn1_NOVALUE,IndRef} -> + {'presentation-context-id',IndRef}; + _ -> + {'context-negotiation', + {'EXTERNAL_identification_context-negotiation',IndRef,DRef}} + end, + case Encoding of + {_,Val} when is_list(Val); is_binary(Val) -> + {'EXTERNAL',Identification,Data_v_desc,Val}; + _ -> + V + end. -- cgit v1.2.3 From 953b858de46f46f42e2ba45ba30a9b0b278a526d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Mon, 17 Dec 2012 16:25:59 +0100 Subject: Remove the 'inline' and '{inline,OutputFile}' options --- lib/asn1/src/asn1ct.erl | 115 ++++++-------------------------------------- lib/asn1/src/asn1ct_gen.erl | 8 ++- 2 files changed, 19 insertions(+), 104 deletions(-) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl index e361654a81..0aa6c4c6a6 100644 --- a/lib/asn1/src/asn1ct.erl +++ b/lib/asn1/src/asn1ct.erl @@ -86,10 +86,14 @@ compile(File) -> compile(File,[]). compile(File, Options0) when is_list(Options0) -> - Options1 = translate_options(Options0), - Options2 = includes(File,Options1), - Includes = strip_includes(Options2), - in_process(fun() -> compile_proc(File, Includes, Options2) end). + try translate_options(Options0) of + Options1 -> + Options2 = includes(File,Options1), + Includes = strip_includes(Options2), + in_process(fun() -> compile_proc(File, Includes, Options2) end) + catch throw:Error -> + Error + end. compile_proc(File, Includes, Options) -> case input_file_type(File, Includes) of @@ -120,56 +124,13 @@ compile1(File,Options) when is_list(Options) -> Continue3 = check(Continue2,File,OutFile,Includes,EncodingRule, DbFile,Options,[]), Continue4 = generate(Continue3,OutFile,EncodingRule,Options), - Ret = compile_erl(Continue4,OutFile,Options), - case inline(is_inline(Options), - inline_output(Options,filename:rootname(File)), - lists:concat([OutFile,".erl"]),Options) of - false -> - Ret; - InlineRet -> - InlineRet - end. + compile_erl(Continue4, OutFile, Options). %%****************************************************************************%% %% functions dealing with compiling of several input files to one output file %% %%****************************************************************************%% -%%% -%% inline/4 -%% merges the resulting erlang modules with -%% the appropriate run-time modules so the resulting module contains all -%% run-time asn1 functionality. Then compiles the resulting file to beam code. -%% The merging is done by the igor module. If this function is used in older -%% versions than R10B the igor module, part of user contribution syntax_tools, -%% must be provided. It is possible to pass options for the ASN1 compiler -%% Types: -%% Name -> atom() -%% Modules -> [filename()] -%% Options -> [term()] -%% filename() -> file:filename() -inline(true,Name,Module,Options) -> - RTmodule = get_runtime_mod(Options), - IgorOptions = igorify_options(remove_asn_flags(Options)), - IgorName = list_to_atom(filename:rootname(filename:basename(Name))), -% io:format("*****~nName: ~p~nModules: ~p~nIgorOptions: ~p~n*****~n", -% [IgorName,Modules++RTmodule,IgorOptions]), - verbose("Inlining modules: ~p in ~p~n",[[Module]++RTmodule,IgorName],Options), - case catch igor:merge(IgorName,[Module]++RTmodule,[{preprocess,true},{stubs,false},{backups,false}]++IgorOptions) of - {'EXIT',{undef,Reason}} -> %% module igor first in R10B - error("Module igor in syntax_tools must be available:~n~p~n", - [Reason],Options), - {error,'no_compilation'}; - {'EXIT',Reason} -> - error("Merge by igor module failed due to ~p~n",[Reason],Options), - {error,'no_compilation'}; - _ -> -%% io:format("compiling output module: ~p~n",[generated_file(Name,IgorOptions)]), - erl_compile(generated_file(Name,IgorOptions),Options) - end; -inline(_,_,_,_) -> - false. - %% compile_set/3 merges and compiles a number of asn1 modules %% specified in a .set.asn file to one .erl file. compile_set(SetBase,Files,Options) @@ -218,15 +179,7 @@ check_set(ParseRes,SetBase,OutFile,Includes,EncRule,DbFile, asn1ct_table:delete([renamed_defs, original_imports, automatic_tags]), - Ret = compile_erl(Continue2,OutFile,Options), - case inline(is_inline(Options), - inline_output(Options,filename:rootname(OutFile)), - lists:concat([OutFile,".erl"]),Options) of - false -> - Ret; - InlineRet -> - InlineRet - end. + compile_erl(Continue2, OutFile, Options). %% merge_modules/2 -> returns a module record where the typeorval lists are merged, %% the exports lists are merged, the imports lists are merged when the @@ -1065,18 +1018,8 @@ get_rule(Options) -> ber end. -get_runtime_mod(Options) -> - RtMod1= - case get_rule(Options) of - per -> "asn1rt_per_bin_rt2ct.erl"; - ber -> ["asn1rt_ber_bin_v2.erl"]; - uper -> ["asn1rt_uper_bin.erl"] - end, - RtMod1++["asn1rt_check.erl","asn1rt.erl"]. - %% translate_options(NewOptions) -> OldOptions %% Translate the new option names to the old option name. -%% FIXME. We should rewrite all code to handle the new option names. translate_options([ber_bin|T]) -> io:format("Warning: The option 'ber_bin' is now called 'ber'.\n"), @@ -1093,6 +1036,12 @@ translate_options([nif|T]) -> translate_options([optimize|T]) -> io:format("Warning: The option 'optimize' is no longer needed.\n"), translate_options(T); +translate_options([inline|T]) -> + io:format("Warning: The option 'inline' is no longer needed.\n"), + translate_options(T); +translate_options([{inline,_}|_]) -> + io:format("ERROR: The option {inline,OutputFilename} is no longer supported.\n"), + throw({error,{unsupported_option,inline}}); translate_options([H|T]) -> [H|translate_options(T)]; translate_options([]) -> []. @@ -1130,23 +1079,6 @@ debug_on(Options) -> true end. -igorify_options(Options) -> - case lists:keysearch(outdir,1,Options) of - {value,{_,Dir}} -> - Options1 = lists:keydelete(outdir,1,Options), - [{dir,Dir}|Options1]; - _ -> - Options - end. - -generated_file(Name,Options) -> - case lists:keysearch(dir,1,Options) of - {value,{_,Dir}} -> - filename:join([Dir,filename:basename(Name)]); - _ -> - Name - end. - debug_off(_Options) -> erase(asndebug). @@ -1187,21 +1119,6 @@ option_add(Option, Options, Fun) -> strip_includes(Includes) -> [I || {i, I} <- Includes]. -is_inline(Options) -> - case lists:member(inline,Options) of - true -> true; - _ -> - lists:keymember(inline,1,Options) - end. - -inline_output(Options,Default) -> - case [X||{inline,X}<-Options] of - [OutputName] -> - OutputName; - _ -> - Default - end. - %% compile(AbsFileName, Options) %% Compile entry point for erl_compile. diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl index ce15e01d32..5181ed1fce 100644 --- a/lib/asn1/src/asn1ct_gen.erl +++ b/lib/asn1/src/asn1ct_gen.erl @@ -1410,11 +1410,9 @@ gen_head(Erules,Mod,Hrl) -> emit({"-module('",Mod,"').",nl}), put(currmod,Mod), emit({"-compile(nowarn_unused_vars).",nl}), - case {Hrl,lists:member(inline,get(encoding_options))} of - {0,_} -> true; - {_,true} -> true; - _ -> - emit({"-include(\"",Mod,".hrl\").",nl}) + case Hrl of + 0 -> ok; + _ -> emit({"-include(\"",Mod,".hrl\").",nl}) end, emit(["-asn1_info([{vsn,'",asn1ct:vsn(),"'},",nl, " {module,'",Mod,"'},",nl, -- cgit v1.2.3 From 844e2126e3b814f9fa058be367be3af745c7a80b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 19 Dec 2012 08:06:02 +0100 Subject: Generate modules with selected run-time functions for compiler usage --- lib/asn1/src/.gitignore | 1 + lib/asn1/src/Makefile | 14 +++++++++++++- lib/asn1/src/asn1ct_eval_ext.funcs | 1 + lib/asn1/src/asn1ct_eval_per.funcs | 1 + lib/asn1/src/asn1ct_gen_per_rt2ct.erl | 2 +- lib/asn1/src/asn1ct_value.erl | 2 +- lib/asn1/src/prepare_templates.erl | 25 ++++++++++++++++++++++++- 7 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 lib/asn1/src/asn1ct_eval_ext.funcs create mode 100644 lib/asn1/src/asn1ct_eval_per.funcs (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/.gitignore b/lib/asn1/src/.gitignore index aee890a053..621f8f3623 100644 --- a/lib/asn1/src/.gitignore +++ b/lib/asn1/src/.gitignore @@ -1 +1,2 @@ /asn1ct_rtt.erl +/asn1ct_eval_*.erl diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile index b54627a9b3..398b4f6f9d 100644 --- a/lib/asn1/src/Makefile +++ b/lib/asn1/src/Makefile @@ -42,6 +42,10 @@ RELSYSDIR = $(RELEASE_PATH)/lib/asn1-$(VSN) # EBIN = ../ebin + +EVAL_CT_MODULES = asn1ct_eval_ext \ + asn1ct_eval_per + CT_MODULES= \ asn1ct \ asn1ct_check \ @@ -60,7 +64,8 @@ CT_MODULES= \ asn1ct_value \ asn1ct_tok \ asn1ct_parser2 \ - asn1ct_table + asn1ct_table \ + $(EVAL_CT_MODULES) RT_MODULES= \ asn1rt \ @@ -143,6 +148,10 @@ $(EBIN)/asn1ct.$(EMULATOR):asn1ct.erl $(EBIN)/asn1ct_func.$(EMULATOR): asn1ct_func.erl $(ERLC) -o$(EBIN) $(ERL_COMPILE_FLAGS) -I../rt_templates $< +asn1ct_eval_%.erl: asn1ct_eval_%.funcs + erl -pa $(EBIN) -noshell -noinput \ + -run prepare_templates gen_asn1ct_eval $< >$@ + $(APP_TARGET): $(APP_SRC) ../vsn.mk $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@ @@ -194,6 +203,9 @@ prepare_templates.$(EMULATOR): prepare_templates.erl asn1rtt_%.$(EMULATOR): asn1rtt_%.erl erlc +debug_info $< +$(EVAL_CT_MODULES:%=%.erl): prepare_templates.$(EMULATOR) \ + $(EBIN)/asn1ct_rtt.$(EMULATOR) + # # Dependencies # diff --git a/lib/asn1/src/asn1ct_eval_ext.funcs b/lib/asn1/src/asn1ct_eval_ext.funcs new file mode 100644 index 0000000000..5761901f89 --- /dev/null +++ b/lib/asn1/src/asn1ct_eval_ext.funcs @@ -0,0 +1 @@ +{ext,transform_to_EXTERNAL1994,1}. diff --git a/lib/asn1/src/asn1ct_eval_per.funcs b/lib/asn1/src/asn1ct_eval_per.funcs new file mode 100644 index 0000000000..353424c231 --- /dev/null +++ b/lib/asn1/src/asn1ct_eval_per.funcs @@ -0,0 +1 @@ +{per,encode_integer,2}. diff --git a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl index b1ecfa135d..7d00f2e817 100644 --- a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl +++ b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl @@ -603,7 +603,7 @@ emit_enc_enumerated_case(Erule,_C, {1,EnumName}, Count) -> emit_enc_enumerated_case(_Erule,C, {0,EnumName}, Count) -> %% ENUMERATED with extensionmark %% values within extension root - emit(["'",EnumName,"' -> ",{asis,[0|asn1rt_per_bin_rt2ct:encode_integer(C,Count)]}]); + emit(["'",EnumName,"' -> ",{asis,[0|asn1ct_eval_per:encode_integer(C, Count)]}]); emit_enc_enumerated_case(_Erule, _C, 'EXT_MARK', _Count) -> true. %% %% This clause is invoked in case of an ENUMERATED without extension mark diff --git a/lib/asn1/src/asn1ct_value.erl b/lib/asn1/src/asn1ct_value.erl index 389642c446..ed1deec2aa 100644 --- a/lib/asn1/src/asn1ct_value.erl +++ b/lib/asn1/src/asn1ct_value.erl @@ -65,7 +65,7 @@ from_type(M,Typename,Type) when is_record(Type,type) -> end; {constructed,bif} when Typename == ['EXTERNAL'] -> Val=from_type_constructed(M,Typename,InnerType,Type), - asn1rt_check:transform_to_EXTERNAL1994(Val); + asn1ct_eval_ext:transform_to_EXTERNAL1994(Val); {constructed,bif} -> from_type_constructed(M,Typename,InnerType,Type) end; diff --git a/lib/asn1/src/prepare_templates.erl b/lib/asn1/src/prepare_templates.erl index 7242166989..83155b2e52 100644 --- a/lib/asn1/src/prepare_templates.erl +++ b/lib/asn1/src/prepare_templates.erl @@ -18,7 +18,7 @@ %% -module(prepare_templates). --export([gen_asn1ct_rtt/1]). +-export([gen_asn1ct_rtt/1,gen_asn1ct_eval/1]). gen_asn1ct_rtt(Ms) -> io:format("%% Generated by ~s. DO NOT EDIT THIS FILE.\n" @@ -46,6 +46,29 @@ gen_asn1ct_rtt(Ms) -> io:format("code() ->\n~p.\n\n", [Funcs]), halt(0). +gen_asn1ct_eval([File]) -> + {ok,Funcs} = file:consult(File), + asn1ct_func:start_link(), + [asn1ct_func:need(MFA) || MFA <- Funcs], + io:format("%% Generated by ~s. DO NOT EDIT THIS FILE.\n" + "%%\n" + "%% Input file: ~s\n\n", [?MODULE,File]), + io:format("-module(~s).\n", [filename:rootname(File)]), + gen_asn1ct_eval_exp(Funcs), + asn1ct_func:generate(group_leader()), + halt(0). + +gen_asn1ct_eval_exp(Funcs) -> + io:put_chars("-export(["), + gen_asn1ct_eval_exp_1(Funcs, ""), + io:put_chars("]).\n"). + +gen_asn1ct_eval_exp_1([{_,F,A}|T], Sep) -> + io:put_chars(Sep), + io:format("~p/~p", [F,A]), + gen_asn1ct_eval_exp_1(T, ",\n"); +gen_asn1ct_eval_exp_1([], _) -> ok. + defined([H|T]) -> io:format("assert_defined(~p) -> ok", [H]), case T of -- cgit v1.2.3 From 70caf52f1a7e09569c776bb1f99b0bf4737c63c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 10 Jan 2013 12:15:43 +0100 Subject: Correct error handling for the NIF functions Also make sure that the error handling is contained within the asn1rt_nif module and does not leak out to generated code. --- lib/asn1/src/asn1rt_nif.erl | 25 +++++++++++++++++++++++-- lib/asn1/src/asn1rtt_ber.erl | 32 +------------------------------- lib/asn1/src/asn1rtt_per.erl | 12 +----------- 3 files changed, 25 insertions(+), 44 deletions(-) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1rt_nif.erl b/lib/asn1/src/asn1rt_nif.erl index de1fb94816..0b2e5a62a5 100644 --- a/lib/asn1/src/asn1rt_nif.erl +++ b/lib/asn1/src/asn1rt_nif.erl @@ -77,10 +77,31 @@ load_nif() -> Status end. -encode_per_complete(_TagValueList) -> +decode_ber_tlv(Binary) -> + case decode_ber_tlv_raw(Binary) of + {error,Reason} -> + exit({error,{asn1,Reason}}); + Other -> + Other + end. + +encode_per_complete(TagValueList) -> + case encode_per_complete_raw(TagValueList) of + {error,Reason} -> handle_error(Reason, TagValueList); + Other when is_binary(Other) -> Other + end. + +handle_error([], _)-> + exit({error,{asn1,enomem}}); +handle_error($1, L) -> % error in complete in driver + exit({error,{asn1,L}}); +handle_error(ErrL, L) -> + exit({error,{asn1,ErrL,L}}). + +encode_per_complete_raw(_TagValueList) -> erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}). -decode_ber_tlv(_Binary) -> +decode_ber_tlv_raw(_Binary) -> erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}). encode_ber_tlv(_TagValueList) -> diff --git a/lib/asn1/src/asn1rtt_ber.erl b/lib/asn1/src/asn1rtt_ber.erl index b374191f37..f3f6875eb3 100644 --- a/lib/asn1/src/asn1rtt_ber.erl +++ b/lib/asn1/src/asn1rtt_ber.erl @@ -123,43 +123,13 @@ ber_encode(Tlv) -> asn1rt_nif:encode_ber_tlv(Tlv). ber_decode_nif(B) -> - case asn1rt_nif:decode_ber_tlv(B) of - {error, Reason} -> handle_error(Reason, B); - Else -> Else - end. + asn1rt_nif:decode_ber_tlv(B). ber_decode_erlang(B) when is_binary(B) -> decode_primitive(B); ber_decode_erlang(Tlv) -> {Tlv,<<>>}. -handle_error([],_)-> - exit({error,{asn1,{"memory allocation problem"}}}); -handle_error({$1,_},L) -> % error in nif - exit({error,{asn1,L}}); -handle_error({$2,T},L) -> % error in nif due to wrong tag - exit({error,{asn1,{"bad tag after byte:",error_pos(T),L}}}); -handle_error({$3,T},L) -> % error in driver due to length error - exit({error,{asn1,{"bad length field after byte:", - error_pos(T),L}}}); -handle_error({$4,T},L) -> % error in driver due to indefinite length error - exit({error,{asn1, - {"indefinite length without end bytes after byte:", - error_pos(T),L}}}); -handle_error({$5,T},L) -> % error in driver due to indefinite length error - exit({error,{asn1,{"bad encoded value after byte:", - error_pos(T),L}}}); -handle_error(ErrL,L) -> - exit({error,{asn1,ErrL,L}}). - -error_pos([]) -> - "unknown position"; -error_pos([B])-> - B; -error_pos([B|Bs]) -> - BS = 8 * length(Bs), - B bsl BS + error_pos(Bs). - decode_primitive(Bin) -> {Form,TagNo,V,Rest} = decode_tag_and_length(Bin), case Form of diff --git a/lib/asn1/src/asn1rtt_per.erl b/lib/asn1/src/asn1rtt_per.erl index d545c8a854..8234121934 100644 --- a/lib/asn1/src/asn1rtt_per.erl +++ b/lib/asn1/src/asn1rtt_per.erl @@ -1311,17 +1311,7 @@ get_constraint(C,Key) -> %% complete(L) -> - case asn1rt_nif:encode_per_complete(L) of - {error, Reason} -> handle_error(Reason, L); - Else when is_binary(Else) -> Else - end. - -handle_error([],_)-> - exit({error,{asn1,{"memory allocation problem in driver"}}}); -handle_error($1,L) -> % error in complete in driver - exit({error,{asn1,L}}); -handle_error(ErrL,L) -> - exit({error,{asn1,ErrL,L}}). + asn1rt_nif:encode_per_complete(L). octets_to_complete(Len,Val) when Len < 256 -> [20,Len,Val]; -- cgit v1.2.3 From a822c4a25d9855381632c124ed8ca0882a792e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 19 Dec 2012 13:41:38 +0100 Subject: Remove the unused run-time modules --- lib/asn1/src/Makefile | 13 - lib/asn1/src/asn1.app.src | 5 - lib/asn1/src/asn1_records.hrl | 6 - lib/asn1/src/asn1rt_ber_bin.erl | 525 --------- lib/asn1/src/asn1rt_ber_bin_v2.erl | 1993 --------------------------------- lib/asn1/src/asn1rt_check.erl | 360 ------ lib/asn1/src/asn1rt_per_bin_rt2ct.erl | 1587 -------------------------- lib/asn1/src/asn1rt_uper_bin.erl | 1487 ------------------------ 8 files changed, 5976 deletions(-) delete mode 100644 lib/asn1/src/asn1rt_ber_bin.erl delete mode 100644 lib/asn1/src/asn1rt_ber_bin_v2.erl delete mode 100644 lib/asn1/src/asn1rt_check.erl delete mode 100644 lib/asn1/src/asn1rt_per_bin_rt2ct.erl delete mode 100644 lib/asn1/src/asn1rt_uper_bin.erl (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile index 398b4f6f9d..b1500d9ea6 100644 --- a/lib/asn1/src/Makefile +++ b/lib/asn1/src/Makefile @@ -69,20 +69,7 @@ CT_MODULES= \ RT_MODULES= \ asn1rt \ - asn1rt_ber_bin \ - asn1rt_ber_bin_v2 \ - asn1rt_per_bin_rt2ct \ - asn1rt_uper_bin \ - asn1rt_check \ asn1rt_nif -# asn1_sup \ -# asn1_app \ -# asn1_server - - -# the rt module to use is defined in asn1_records.hrl -# and must be updated when an incompatible change is done in the rt modules - MODULES= $(CT_MODULES) $(RT_MODULES) diff --git a/lib/asn1/src/asn1.app.src b/lib/asn1/src/asn1.app.src index 64b33a8a30..f2ee8deb75 100644 --- a/lib/asn1/src/asn1.app.src +++ b/lib/asn1/src/asn1.app.src @@ -3,11 +3,6 @@ {vsn, "%VSN%"}, {modules, [ asn1rt, - asn1rt_per_bin_rt2ct, - asn1rt_uper_bin, - asn1rt_ber_bin, - asn1rt_ber_bin_v2, - asn1rt_check, asn1rt_nif ]}, {registered, [ diff --git a/lib/asn1/src/asn1_records.hrl b/lib/asn1/src/asn1_records.hrl index 59a9acb7e7..c229aa0759 100644 --- a/lib/asn1/src/asn1_records.hrl +++ b/lib/asn1/src/asn1_records.hrl @@ -24,12 +24,6 @@ -define(dbg(Fmt, Args), no_debug). -endif. --define('RT_BER_BIN',"asn1rt_ber_bin"). --define('RT_PER_BIN',"asn1rt_per_bin"). - -%% Some encoding are common for BER and PER. Shared code are in RT_COMMON --define('RT_COMMON',asn1rt_ber_bin). - -define('COMPLETE_ENCODE',1). -define('TLV_DECODE',2). diff --git a/lib/asn1/src/asn1rt_ber_bin.erl b/lib/asn1/src/asn1rt_ber_bin.erl deleted file mode 100644 index ec1549804b..0000000000 --- a/lib/asn1/src/asn1rt_ber_bin.erl +++ /dev/null @@ -1,525 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2000-2010. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% --module(asn1rt_ber_bin). - --export([decode_length/1, - encode_real/2, encode_real/3, - decode_real/2, decode_real/4, - decode_tag/1]). - --include("asn1_records.hrl"). - -%% the encoding of class of tag bits 8 and 7 --define(UNIVERSAL, 0). - -%%% primitive or constructed encoding % bit 6 --define(PRIMITIVE, 0). --define(CONSTRUCTED, 2#00100000). - -%%% The tag-number for universal types --define(N_REAL, 9). - -encode_tag_val({Class, Form, TagNo}) when (TagNo =< 30) -> - <<(Class bsr 6):2,(Form bsr 5):1,TagNo:5>>; - -encode_tag_val({Class, Form, TagNo}) -> - {Octets,_Len} = mk_object_val(TagNo), - BinOct = list_to_binary(Octets), - <<(Class bsr 6):2, (Form bsr 5):1, 31:5,BinOct/binary>>. - -%%=============================================================================== -%% Decode a tag -%% -%% decode_tag(OctetListBuffer) -> {{Class, Form, TagNo}, RestOfBuffer, RemovedBytes} -%%=============================================================================== - -%% multiple octet tag -decode_tag(<>) -> - {TagNo, Buffer1, RemovedBytes} = decode_tag(Buffer, 0, 1), - {{(Class bsl 6), (Form bsl 5), TagNo}, Buffer1, RemovedBytes}; - -%% single tag (< 31 tags) -decode_tag(<>) -> - {{(Class bsl 6), (Form bsl 5), TagNo}, Buffer, 1}. - -%% last partial tag -decode_tag(<<0:1,PartialTag:7, Buffer/binary>>, TagAck, RemovedBytes) -> - TagNo = (TagAck bsl 7) bor PartialTag, - %%<> = <>, - {TagNo, Buffer, RemovedBytes+1}; -% more tags -decode_tag(<<_:1,PartialTag:7, Buffer/binary>>, TagAck, RemovedBytes) -> - TagAck1 = (TagAck bsl 7) bor PartialTag, - %%<> = <>, - decode_tag(Buffer, TagAck1, RemovedBytes+1). - -%%------------------------------------------------------------------ -%% check_tags_i is the same as check_tags except that it stops and -%% returns the remaining tags not checked when it encounters an -%% indefinite length field -%% only called internally within this module - -check_tags_i([Tag], Buffer, OptOrMand) -> % optimized very usual case - {[],check_one_tag(Tag, Buffer, OptOrMand)}; -check_tags_i(Tags, Buffer, OptOrMand) -> - check_tags_i(Tags, Buffer, 0, OptOrMand). - -check_tags_i([Tag1,Tag2|TagRest], Buffer, Rb, OptOrMand) - when Tag1#tag.type == 'IMPLICIT' -> - check_tags_i([Tag1#tag{type=Tag2#tag.type}|TagRest], Buffer, Rb, OptOrMand); - -check_tags_i([Tag1|TagRest], Buffer, Rb, OptOrMand) -> - {Form_Length,Buffer2,Rb1} = check_one_tag(Tag1, Buffer, OptOrMand), - case TagRest of - [] -> {TagRest, {Form_Length, Buffer2, Rb + Rb1}}; - _ -> - case Form_Length of - {?CONSTRUCTED,_} -> - {TagRest, {Form_Length, Buffer2, Rb + Rb1}}; - _ -> - check_tags_i(TagRest, Buffer2, Rb + Rb1, mandatory) - end - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This function is called from generated code - -check_one_tag(Tag=#tag{class=ExpectedClass,number=ExpectedNumber}, Buffer, OptOrMand) -> - case catch decode_tag(Buffer) of - {'EXIT',_Reason} -> - tag_error(no_data,Tag,Buffer,OptOrMand); - {{ExpectedClass,Form,ExpectedNumber},Buffer2,Rb} -> - {{L,Buffer3},RemBytes2} = decode_length(Buffer2), - {{Form,L}, Buffer3, RemBytes2+Rb}; - {ErrorTag,_,_} -> - tag_error(ErrorTag, Tag, Buffer, OptOrMand) - end. - -tag_error(ErrorTag, Tag, Buffer, OptOrMand) -> - case OptOrMand of - mandatory -> - exit({error,{asn1, {invalid_tag, - {ErrorTag, Tag, Buffer}}}}); - _ -> - exit({error,{asn1, {no_optional_tag, - {ErrorTag, Tag, Buffer}}}}) - end. -%%======================================================================= -%% -%% Encode all tags in the list Tags and return a possibly deep list of -%% bytes with tag and length encoded -%% -%% prepend_tags(Tags, BytesSoFar, LenSoFar) -> {Bytes, Len} -encode_tags(Tags, BytesSoFar, LenSoFar) -> - NewTags = encode_tags1(Tags, []), - %% NewTags contains the resulting tags in reverse order - encode_tags2(NewTags, BytesSoFar, LenSoFar). - -%encode_tags2([#tag{class=?UNIVERSAL,number=No}|Trest], BytesSoFar, LenSoFar) -> -% {Bytes2,L2} = encode_length(LenSoFar), -% encode_tags2(Trest,[[No|Bytes2],BytesSoFar], LenSoFar + 1 + L2); -encode_tags2([Tag|Trest], BytesSoFar, LenSoFar) -> - {Bytes1,L1} = encode_one_tag(Tag), - {Bytes2,L2} = encode_length(LenSoFar), - encode_tags2(Trest, [Bytes1,Bytes2|BytesSoFar], - LenSoFar + L1 + L2); -encode_tags2([], BytesSoFar, LenSoFar) -> - {BytesSoFar,LenSoFar}. - -encode_tags1([Tag1, Tag2| Trest], Acc) when Tag1#tag.type =:= 'IMPLICIT' -> - encode_tags1([Tag1#tag{type=Tag2#tag.type,form=Tag2#tag.form}|Trest],Acc); -encode_tags1([Tag1 | Trest], Acc) -> - encode_tags1(Trest, [Tag1|Acc]); -encode_tags1([], Acc) -> - Acc. % the resulting tags are returned in reverse order - -encode_one_tag(Bin) when is_binary(Bin) -> - {Bin,byte_size(Bin)}; -encode_one_tag(#tag{class=Class,number=No,type=Type, form = Form}) -> - NewForm = case Type of - 'EXPLICIT' -> - ?CONSTRUCTED; - _ -> - Form - end, - Bytes = encode_tag_val({Class,NewForm,No}), - {Bytes,size(Bytes)}. - -%%============================================================================ -%% -%% Real value, ITU_T X.690 Chapter 8.5 -%%============================================================================ -%% -%% encode real value -%%============================================================================ - -%% only base 2 internally so far!! -encode_real(_C,0, DoTag) -> - dotag(DoTag, ?N_REAL, {[],0}); -encode_real(_C,'PLUS-INFINITY', DoTag) -> - dotag(DoTag, ?N_REAL, {[64],1}); -encode_real(_C,'MINUS-INFINITY', DoTag) -> - dotag(DoTag, ?N_REAL, {[65],1}); -encode_real(C,Val, DoTag) when is_tuple(Val); is_list(Val) -> - dotag(DoTag, ?N_REAL, encode_real(C,Val)). - -%%%%%%%%%%%%%% -%% only base 2 encoding! -%% binary encoding: -%% +------------+ +------------+ +-+-+-+-+---+---+ -%% | (tag)9 | | n + p + 1 | |1|S|BB |FF |EE | -%% +------------+ +------------+ +-+-+-+-+---+---+ -%% -%% +------------+ +------------+ -%% | | | | -%% +------------+ ...+------------+ -%% n octets for exponent -%% -%% +------------+ +------------+ -%% | | | | -%% +------------+ ...+------------+ -%% p octets for pos mantissa -%% -%% S is 0 for positive sign -%% 1 for negative sign -%% BB: encoding base, 00 = 2, (01 = 8, 10 = 16) -%% 01 and 10 not used -%% FF: scale factor 00 = 0 (used in base 2 encoding) -%% EE: encoding of the exponent: -%% 00 - on the following octet -%% 01 - on the 2 following octets -%% 10 - on the 3 following octets -%% 11 - encoding of the length of the two's-complement encoding of -%% exponent on the following octet, and two's-complement -%% encoding of exponent on the other octets. -%% -%% In DER and base 2 encoding the mantissa is encoded as value 0 or -%% bit shifted until it is an odd number. Thus, do this for BER as -%% well. -%% This interface also used by RT_COMMON -encode_real(_C,{Mantissa, Base, Exponent}) when Base =:= 2 -> -%% io:format("Mantissa: ~w Base: ~w, Exp: ~w~n",[Man, Base, Exp]), - {Man,ExpAdd} = truncate_zeros(Mantissa), %% DER adjustment - Exp = Exponent + ExpAdd, - OctExp = if Exp >= 0 -> list_to_binary(encode_integer_pos(Exp, [])); - true -> list_to_binary(encode_integer_neg(Exp, [])) - end, -%% ok = io:format("OctExp: ~w~n",[OctExp]), - SignBit = if Man > 0 -> 0; % bit 7 is pos or neg, no Zeroval - true -> 1 - end, -%% ok = io:format("SignBitMask: ~w~n",[SignBitMask]), - SFactor = 0, - OctExpLen = size(OctExp), - if OctExpLen > 255 -> - exit({error,{asn1, {to_big_exp_in_encode_real, OctExpLen}}}); - true -> true %% make real assert later.. - end, - {LenCode, EOctets} = case OctExpLen of % bit 2,1 - 1 -> {0, OctExp}; - 2 -> {1, OctExp}; - 3 -> {2, OctExp}; - _ -> {3, <>} - end, - BB = 0, %% 00 for base 2 - FirstOctet = <<1:1,SignBit:1,BB:2,SFactor:2,LenCode:2>>, - OctMantissa = if Man > 0 -> list_to_binary(minimum_octets(Man)); - true -> list_to_binary(minimum_octets(-(Man))) % signbit keeps track of sign - end, - %% ok = io:format("LenMask: ~w EOctets: ~w~nFirstOctet: ~w OctMantissa: ~w OctExpLen: ~w~n", [LenMask, EOctets, FirstOctet, OctMantissa, OctExpLen]), - Bin = <>, - {Bin, size(Bin)}; -encode_real(C,{Mantissa,Base,Exponent}) - when Base =:= 10, is_integer(Mantissa), is_integer(Exponent) -> - %% always encode as NR3 due to DER on the format - %% mmmm.Eseeee where - %% m := digit - %% s := '-' | '+' | [] - %% '+' only allowed in +0 - %% e := digit - %% ex: 1234.E-5679 -%% {Man,AddExp} = truncate_zeros(Mantissa,0), -%% ManNum = trunc(Mantissa), -%% {TruncatedMan,NumZeros} = truncate_zeros10(Mantissa), - ManStr = integer_to_list(Mantissa), - - encode_real_as_string(C,ManStr,Exponent); -encode_real(_C,{_,Base,_}) -> - exit({error,{asn1, {encode_real_non_supported_encodeing, Base}}}); -%% base 10 -encode_real(C,Real) when is_list(Real) -> - %% The Real string may come in as a NR1, NR2 or NR3 string. - {Mantissa, Exponent} = - case string:tokens(Real,"Ee") of - [NR2] -> - {NR2,0}; - [NR3MB,NR3E] -> - %% remove beginning zeros - {NR3MB,list_to_integer(NR3E)} - end, - - %% .Decimal | Number | Number.Decimal - ZeroDecimal = - fun("0") -> ""; - (L) -> L - end, - {NewMantissa,LenDecimal} = - case Mantissa of - [$.|Dec] -> - NewMan = remove_trailing_zeros(Dec), - {NewMan,length(ZeroDecimal(NewMan))}; - _ -> - case string:tokens(Mantissa,",.") of - [Num] -> %% No decimal-mark - {integer_to_list(list_to_integer(Num)),0}; - [Num,Dec] -> - NewDec = ZeroDecimal(remove_trailing_zeros(Dec)), - NewMan = integer_to_list(list_to_integer(Num)) ++ NewDec, - {integer_to_list(list_to_integer(NewMan)), - length(NewDec)} - end - end, - -% DER_Exponent = integer_to_list(Exponent - ExpReduce), - encode_real_as_string(C,NewMantissa,Exponent - LenDecimal). - -encode_real_as_string(_C,Mantissa,Exponent) - when is_list(Mantissa), is_integer(Exponent) -> - %% Remove trailing zeros in Mantissa and add this to Exponent - TruncMant = remove_trailing_zeros(Mantissa), - - ExpIncr = length(Mantissa) - length(TruncMant), - - ExpStr = integer_to_list(Exponent + ExpIncr), - - ExpBin = - case ExpStr of - "0" -> - <<"E+0">>; - _ -> - ExpB = list_to_binary(ExpStr), - <<$E,ExpB/binary>> - end, - ManBin = list_to_binary(TruncMant), - NR3 = 3, - {<>,2 + size(ManBin) + size(ExpBin)}. - -remove_trailing_zeros(IntStr) -> - case lists:dropwhile(fun($0)-> true; - (_) -> false - end, lists:reverse(IntStr)) of - [] -> - "0"; - ReversedIntStr -> - lists:reverse(ReversedIntStr) - end. - -truncate_zeros(Num) -> - truncate_zeros(Num,0). -truncate_zeros(0,Sum) -> - {0,Sum}; -truncate_zeros(M,Sum) -> - case M band 16#f =:= M band 16#e of - true -> truncate_zeros(M bsr 1,Sum+1); - _ -> {M,Sum} - end. - - -%%============================================================================ -%% decode real value -%% -%% decode_real([OctetBufferList], tuple|value, tag|notag) -> -%% {{Mantissa, Base, Exp} | realval | PLUS-INFINITY | MINUS-INFINITY | 0, -%% RestBuff} -%% -%% only for base 2 decoding sofar!! -%%============================================================================ - -decode_real(Buffer, C, Tags, OptOrMand) -> - NewTags = new_tags(Tags,#tag{class=?UNIVERSAL,number=?N_REAL}), - decode_real_notag(Buffer, C, NewTags, OptOrMand). - -%% This interface used by RT_COMMON -decode_real(Buffer,Len) -> - decode_real2(Buffer,[],Len,0). - -decode_real_notag(Buffer, C, Tags, OptOrMand) -> - {_RestTags, {{_,Len}, Buffer0, Rb0}} = - check_tags_i(Tags, Buffer, OptOrMand), - decode_real2(Buffer0, C, Len, Rb0). - -decode_real2(Buffer, _C, 0, _RemBytes) -> - {0,Buffer}; -decode_real2(Buffer0, _C, Len, RemBytes1) -> - <> = Buffer0, - if - First =:= 2#01000000 -> {'PLUS-INFINITY', Buffer2}; - First =:= 2#01000001 -> {'MINUS-INFINITY', Buffer2}; -%% First =:= 2#00000000 -> {0, Buffer2}; - First =:= 1 orelse First =:= 2 orelse First =:= 3 -> - %% charcter string encoding of base 10 - {NRx,Rest} = split_binary(Buffer2,Len-1), - {binary_to_list(NRx),Rest,Len}; - true -> - %% have some check here to verify only supported bases (2) - %% not base 8 or 16 - <<_B7:1,Sign:1,BB:2,_FF:2,EE:2>> = <>, - Base = - case BB of - 0 -> 2; % base 2, only one so far - _ -> exit({error,{asn1, {non_supported_base, BB}}}) - end, - {FirstLen, {Exp, Buffer3,_Rb2}, RemBytes2} = - case EE of - 0 -> {2, decode_integer2(1, Buffer2, RemBytes1), RemBytes1+1}; - 1 -> {3, decode_integer2(2, Buffer2, RemBytes1), RemBytes1+2}; - 2 -> {4, decode_integer2(3, Buffer2, RemBytes1), RemBytes1+3}; - 3 -> - <> = Buffer2, - { ExpLen1 + 2, - decode_integer2(ExpLen1, RestBuffer, RemBytes1), - RemBytes1+ExpLen1} - end, - %% io:format("FirstLen: ~w, Exp: ~w, Buffer3: ~w ~n", - - Length = Len - FirstLen, - <> = Buffer3, - {{Mantissa, Buffer4}, RemBytes3} = - if Sign =:= 0 -> - %% io:format("sign plus~n"), - {{LongInt, RestBuff}, 1 + Length}; - true -> - %% io:format("sign minus~n"), - {{-LongInt, RestBuff}, 1 + Length} - end, - {{Mantissa, Base, Exp}, Buffer4, RemBytes2+RemBytes3} - end. - -encode_integer_pos(0, L=[B|_Acc]) when B < 128 -> - L; -encode_integer_pos(N, Acc) -> - encode_integer_pos((N bsr 8), [N band 16#ff| Acc]). - -encode_integer_neg(-1, L=[B1|_T]) when B1 > 127 -> - L; -encode_integer_neg(N, Acc) -> - encode_integer_neg(N bsr 8, [N band 16#ff|Acc]). - - -%%%%%%%%%%% -%% mk_object_val(Value) -> {OctetList, Len} -%% returns a Val as a list of octets, the 8 bit is allways set to one except -%% for the last octet, where its 0 -%% - - -mk_object_val(Val) when Val =< 127 -> - {[255 band Val], 1}; -mk_object_val(Val) -> - mk_object_val(Val bsr 7, [Val band 127], 1). -mk_object_val(0, Ack, Len) -> - {Ack, Len}; -mk_object_val(Val, Ack, Len) -> - mk_object_val(Val bsr 7, [((Val band 127) bor 128) | Ack], Len + 1). - - -%%============================================================================ -%% Length handling -%% -%% Encode length -%% -%% encode_length(Int | indefinite) -> -%% [<127]| [128 + Int (<127),OctetList] | [16#80] -%%============================================================================ - -encode_length(L) when L =< 16#7F -> - {[L],1}; -encode_length(L) -> - Oct = minimum_octets(L), - Len = length(Oct), - if - Len =< 126 -> - {[ (16#80+Len) | Oct ],Len+1}; - true -> - exit({error,{asn1, to_long_length_oct, Len}}) - end. - - -%% Val must be >= 0 -minimum_octets(Val) -> - minimum_octets(Val,[]). - -minimum_octets(0,Acc) -> - Acc; -minimum_octets(Val, Acc) -> - minimum_octets((Val bsr 8),[Val band 16#FF | Acc]). - - -%%=========================================================================== -%% Decode length -%% -%% decode_length(OctetList) -> {{indefinite, RestOctetsL}, NoRemovedBytes} | -%% {{Length, RestOctetsL}, NoRemovedBytes} -%%=========================================================================== - -decode_length(<<1:1,0:7,T/binary>>) -> - {{indefinite, T}, 1}; -decode_length(<<0:1,Length:7,T/binary>>) -> - {{Length,T},1}; -decode_length(<<1:1,LL:7,T/binary>>) -> - <> = T, - {{Length,Rest}, LL+1}. - - -dotag([], Tag, {Bytes,Len}) -> - dotag_universal(Tag,Bytes,Len); -dotag(Tags, Tag, {Bytes,Len}) -> - encode_tags(Tags ++ [#tag{class=?UNIVERSAL,number=Tag,form=?PRIMITIVE}], - Bytes, Len). - -dotag_universal(UniversalTag,Bytes,Len) when Len =< 16#7F-> - {[UniversalTag,Len,Bytes],2+Len}; -dotag_universal(UniversalTag,Bytes,Len) -> - {EncLen,LenLen}=encode_length(Len), - {[UniversalTag,EncLen,Bytes],1+LenLen+Len}. - -%% decoding postitive integer values. -decode_integer2(Len,Bin = <<0:1,_:7,_Bs/binary>>,RemovedBytes) -> - <> = Bin, - {Int,Buffer2,RemovedBytes}; -%% decoding negative integer values. -decode_integer2(Len,<<1:1,B2:7,Bs/binary>>,RemovedBytes) -> - <> = <>, - Int = N - (1 bsl (8 * Len - 1)), - {Int,Buffer2,RemovedBytes}. - -new_tags([],LastTag) -> - [LastTag]; -new_tags(Tags = [#tag{type='IMPLICIT'}],_LastTag) -> - Tags; -new_tags([T1 = #tag{type='IMPLICIT'},#tag{type=T2Type}|Rest],LastTag) -> - new_tags([T1#tag{type=T2Type}|Rest],LastTag); -new_tags(Tags,LastTag) -> - case lists:last(Tags) of - #tag{type='IMPLICIT'} -> - Tags; - _ -> - Tags ++ [LastTag] - end. diff --git a/lib/asn1/src/asn1rt_ber_bin_v2.erl b/lib/asn1/src/asn1rt_ber_bin_v2.erl deleted file mode 100644 index 10deecee6e..0000000000 --- a/lib/asn1/src/asn1rt_ber_bin_v2.erl +++ /dev/null @@ -1,1993 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2002-2012. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% --module(asn1rt_ber_bin_v2). - -%% encoding / decoding of BER - --export([decode/1, decode/2, match_tags/2, encode/1, encode/2]). --export([fixoptionals/2, - encode_tag_val/1, - encode_tags/2, - encode_tags/3, - skip_ExtensionAdditions/2]). --export([encode_boolean/2,decode_boolean/2, - encode_integer/3,encode_integer/4, - decode_integer/3, decode_integer/4, - encode_enumerated/2, - encode_enumerated/4,decode_enumerated/4, - encode_real/3,decode_real/2, - encode_bit_string/4,decode_bit_string/4, - decode_compact_bit_string/4, - encode_octet_string/3,decode_octet_string/3, - encode_null/2,decode_null/2, - encode_relative_oid/2,decode_relative_oid/2, - encode_object_identifier/2,decode_object_identifier/2, - encode_restricted_string/4,decode_restricted_string/4, - encode_universal_string/3,decode_universal_string/3, - encode_UTF8_string/3,decode_UTF8_string/2, - encode_BMP_string/3,decode_BMP_string/3, - encode_generalized_time/3,decode_generalized_time/3, - encode_utc_time/3,decode_utc_time/3, - encode_length/1,decode_length/1, - decode_tag_and_length/1]). - --export([encode_open_type/1,encode_open_type/2, - decode_open_type/2,decode_open_type/3, - decode_open_type_as_binary/2, - decode_open_type_as_binary/3]). - --export([decode_primitive_incomplete/2,decode_selective/2]). - -% the encoding of class of tag bits 8 and 7 --define(UNIVERSAL, 0). --define(APPLICATION, 16#40). --define(CONTEXT, 16#80). --define(PRIVATE, 16#C0). - -%%% primitive or constructed encoding % bit 6 --define(PRIMITIVE, 0). --define(CONSTRUCTED, 2#00100000). - -%%% The tag-number for universal types --define(N_BOOLEAN, 1). --define(N_INTEGER, 2). --define(N_BIT_STRING, 3). --define(N_OCTET_STRING, 4). --define(N_NULL, 5). --define(N_OBJECT_IDENTIFIER, 6). --define(N_OBJECT_DESCRIPTOR, 7). --define(N_EXTERNAL, 8). --define(N_REAL, 9). --define(N_ENUMERATED, 10). --define(N_EMBEDDED_PDV, 11). --define(N_SEQUENCE, 16). --define(N_SET, 17). --define(N_NumericString, 18). --define(N_PrintableString, 19). --define(N_TeletexString, 20). --define(N_VideotexString, 21). --define(N_IA5String, 22). --define(N_UTCTime, 23). --define(N_GeneralizedTime, 24). --define(N_GraphicString, 25). --define(N_VisibleString, 26). --define(N_GeneralString, 27). --define(N_UniversalString, 28). --define(N_BMPString, 30). - - -% the complete tag-word of built-in types --define(T_BOOLEAN, ?UNIVERSAL bor ?PRIMITIVE bor 1). --define(T_INTEGER, ?UNIVERSAL bor ?PRIMITIVE bor 2). --define(T_BIT_STRING, ?UNIVERSAL bor ?PRIMITIVE bor 3). % can be CONSTRUCTED --define(T_OCTET_STRING, ?UNIVERSAL bor ?PRIMITIVE bor 4). % can be CONSTRUCTED --define(T_NULL, ?UNIVERSAL bor ?PRIMITIVE bor 5). --define(T_OBJECT_IDENTIFIER,?UNIVERSAL bor ?PRIMITIVE bor 6). --define(T_OBJECT_DESCRIPTOR,?UNIVERSAL bor ?PRIMITIVE bor 7). --define(T_EXTERNAL, ?UNIVERSAL bor ?PRIMITIVE bor 8). --define(T_REAL, ?UNIVERSAL bor ?PRIMITIVE bor 9). --define(T_ENUMERATED, ?UNIVERSAL bor ?PRIMITIVE bor 10). --define(T_EMBEDDED_PDV, ?UNIVERSAL bor ?PRIMITIVE bor 11). --define(T_SEQUENCE, ?UNIVERSAL bor ?CONSTRUCTED bor 16). --define(T_SET, ?UNIVERSAL bor ?CONSTRUCTED bor 17). --define(T_NumericString, ?UNIVERSAL bor ?PRIMITIVE bor 18). %can be constructed --define(T_PrintableString, ?UNIVERSAL bor ?PRIMITIVE bor 19). %can be constructed --define(T_TeletexString, ?UNIVERSAL bor ?PRIMITIVE bor 20). %can be constructed --define(T_VideotexString, ?UNIVERSAL bor ?PRIMITIVE bor 21). %can be constructed --define(T_IA5String, ?UNIVERSAL bor ?PRIMITIVE bor 22). %can be constructed --define(T_UTCTime, ?UNIVERSAL bor ?PRIMITIVE bor 23). --define(T_GeneralizedTime, ?UNIVERSAL bor ?PRIMITIVE bor 24). --define(T_GraphicString, ?UNIVERSAL bor ?PRIMITIVE bor 25). %can be constructed --define(T_VisibleString, ?UNIVERSAL bor ?PRIMITIVE bor 26). %can be constructed --define(T_GeneralString, ?UNIVERSAL bor ?PRIMITIVE bor 27). %can be constructed --define(T_UniversalString, ?UNIVERSAL bor ?PRIMITIVE bor 28). %can be constructed --define(T_BMPString, ?UNIVERSAL bor ?PRIMITIVE bor 30). %can be constructed - -% encode(Tlv={_Tag={?PRIMITIVE,_},_VList}) -> -% encode_primitive(Tlv); -% encode(Tlv) -> -% encode_constructed(Tlv). - -encode(Tlv) -> - encode(Tlv,erlang). - -encode(Tlv,_) when is_binary(Tlv) -> - Tlv; -encode([Tlv],Method) -> - encode(Tlv,Method); -encode(Tlv, nif) -> - asn1rt_nif:encode_ber_tlv(Tlv); -encode(Tlv, _) -> - encode_erl(Tlv). - -encode_erl({TlvTag,TlvVal}) when is_list(TlvVal) -> - %% constructed form of value - encode_tlv(TlvTag,TlvVal,?CONSTRUCTED); -encode_erl({TlvTag,TlvVal}) -> - encode_tlv(TlvTag,TlvVal,?PRIMITIVE). - -encode_tlv(TlvTag,TlvVal,Form) -> - Tag = encode_tlv_tag(TlvTag,Form), - {Val,VLen} = encode_tlv_val(TlvVal), - {Len,_LLen} = encode_length(VLen), - BinLen = list_to_binary(Len), - <>. - -encode_tlv_tag(ClassTagNo,Form) -> - Class = ClassTagNo bsr 16, - encode_tag_val({Class bsl 6,Form,(ClassTagNo - (Class bsl 16))}). - -encode_tlv_val(TlvL) when is_list(TlvL) -> - encode_tlv_list(TlvL,[]); -encode_tlv_val(Bin) -> - {Bin,size(Bin)}. - -encode_tlv_list([Tlv|Tlvs],Acc) -> - EncTlv = encode_erl(Tlv), - encode_tlv_list(Tlvs,[EncTlv|Acc]); -encode_tlv_list([],Acc) -> - Bin=list_to_binary(lists:reverse(Acc)), - {Bin,size(Bin)}. - -decode(B) -> - decode(B, erlang). - -%% asn1-1.7 -decode(B, nif) -> - case asn1rt_nif:decode_ber_tlv(B) of - {error, Reason} -> handle_error(Reason, B); - Else -> Else - end; -decode(B,erlang) when is_binary(B) -> - decode_primitive(B); -decode(Tlv,erlang) -> - {Tlv,<<>>}. - -handle_error([],_)-> - exit({error,{asn1,{"memory allocation problem"}}}); -handle_error({$1,_},L) -> % error in nif - exit({error,{asn1,L}}); -handle_error({$2,T},L) -> % error in nif due to wrong tag - exit({error,{asn1,{"bad tag after byte:",error_pos(T),L}}}); -handle_error({$3,T},L) -> % error in driver due to length error - exit({error,{asn1,{"bad length field after byte:", - error_pos(T),L}}}); -handle_error({$4,T},L) -> % error in driver due to indefinite length error - exit({error,{asn1, - {"indefinite length without end bytes after byte:", - error_pos(T),L}}}); -handle_error({$5,T},L) -> % error in driver due to indefinite length error - exit({error,{asn1,{"bad encoded value after byte:", - error_pos(T),L}}}); -handle_error(ErrL,L) -> - exit({error,{asn1,ErrL,L}}). - -error_pos([]) -> - "unknown position"; -error_pos([B])-> - B; -error_pos([B|Bs]) -> - BS = 8 * length(Bs), - B bsl BS + error_pos(Bs). - -decode_primitive(Bin) -> - {Form,TagNo,V,Rest} = decode_tag_and_length(Bin), - case Form of - 1 -> % constructed - {{TagNo,decode_constructed(V)},Rest}; - 0 -> % primitive - {{TagNo,V},Rest}; - 2 -> % constructed indefinite - {Vlist,Rest2} = decode_constructed_indefinite(V,[]), - {{TagNo,Vlist},Rest2} - end. - -decode_constructed(Bin) when byte_size(Bin) =:= 0 -> - []; -decode_constructed(Bin) -> - {Tlv,Rest} = decode_primitive(Bin), - [Tlv|decode_constructed(Rest)]. - -decode_constructed_indefinite(<<0,0,Rest/binary>>,Acc) -> - {lists:reverse(Acc),Rest}; -decode_constructed_indefinite(Bin,Acc) -> - {Tlv,Rest} = decode_primitive(Bin), - decode_constructed_indefinite(Rest, [Tlv|Acc]). - -%% decode_primitive_incomplete/2 decodes an encoded message incomplete -%% by help of the pattern attribute (first argument). -decode_primitive_incomplete([[default,TagNo]],Bin) -> %default - case decode_tag_and_length(Bin) of - {Form,TagNo,V,Rest} -> - decode_incomplete2(Form,TagNo,V,[],Rest); - _ -> - %{asn1_DEFAULT,Bin} - asn1_NOVALUE - end; -decode_primitive_incomplete([[default,TagNo,Directives]],Bin) -> %default, constructed type, Directives points into this type - case decode_tag_and_length(Bin) of - {Form,TagNo,V,Rest} -> - decode_incomplete2(Form,TagNo,V,Directives,Rest); - _ -> - %{asn1_DEFAULT,Bin} - asn1_NOVALUE - end; -decode_primitive_incomplete([[opt,TagNo]],Bin) -> %optional - case decode_tag_and_length(Bin) of - {Form,TagNo,V,Rest} -> - decode_incomplete2(Form,TagNo,V,[],Rest); - _ -> - %{{TagNo,asn1_NOVALUE},Bin} - asn1_NOVALUE - end; -decode_primitive_incomplete([[opt,TagNo,Directives]],Bin) -> %optional - case decode_tag_and_length(Bin) of - {Form,TagNo,V,Rest} -> - decode_incomplete2(Form,TagNo,V,Directives,Rest); - _ -> - %{{TagNo,asn1_NOVALUE},Bin} - asn1_NOVALUE - end; -%% An optional that shall be undecoded -decode_primitive_incomplete([[opt_undec,Tag]],Bin) -> - case decode_tag_and_length(Bin) of - {_,Tag,_,_} -> - decode_incomplete_bin(Bin); - _ -> - asn1_NOVALUE - end; -%% A choice alternative that shall be undecoded -decode_primitive_incomplete([[alt_undec,TagNo]|RestAlts],Bin) -> -% decode_incomplete_bin(Bin); -% case decode_tlv(Bin) of - case decode_tag_and_length(Bin) of -% {{_Form,TagNo,_Len,_V},_R} -> - {_,TagNo,_,_} -> - decode_incomplete_bin(Bin); - _ -> - decode_primitive_incomplete(RestAlts,Bin) - end; -decode_primitive_incomplete([[alt,TagNo]|RestAlts],Bin) -> - case decode_tag_and_length(Bin) of - {_Form,TagNo,V,Rest} -> - {{TagNo,V},Rest}; - _ -> - decode_primitive_incomplete(RestAlts,Bin) - end; -decode_primitive_incomplete([[alt,TagNo,Directives]|RestAlts],Bin) -> - case decode_tag_and_length(Bin) of - {Form,TagNo,V,Rest} -> - decode_incomplete2(Form,TagNo,V,Directives,Rest); - _ -> - decode_primitive_incomplete(RestAlts,Bin) - end; -decode_primitive_incomplete([[alt_parts,TagNo]],Bin) -> - case decode_tag_and_length(Bin) of - {_Form,TagNo,V,Rest} -> - {{TagNo,V},Rest}; - _ -> - asn1_NOVALUE - end; -decode_primitive_incomplete([[alt_parts,TagNo]|RestAlts],Bin) -> - case decode_tag_and_length(Bin) of - {_Form,TagNo,V,Rest} -> - {{TagNo,decode_parts_incomplete(V)},Rest}; - _ -> - decode_primitive_incomplete(RestAlts,Bin) - end; -decode_primitive_incomplete([[undec,_TagNo]|_RestTag],Bin) -> %incomlete decode - decode_incomplete_bin(Bin); -decode_primitive_incomplete([[parts,TagNo]|_RestTag],Bin) -> - case decode_tag_and_length(Bin) of - {_Form,TagNo,V,Rest} -> - {{TagNo,decode_parts_incomplete(V)},Rest}; - Err -> - {error,{asn1,"tag failure",TagNo,Err}} - end; -decode_primitive_incomplete([mandatory|RestTag],Bin) -> - {Form,TagNo,V,Rest} = decode_tag_and_length(Bin), - decode_incomplete2(Form,TagNo,V,RestTag,Rest); -%% A choice that is a toptype or a mandatory component of a -%% SEQUENCE or SET. -decode_primitive_incomplete([[mandatory|Directives]],Bin) -> - {Form,TagNo,V,Rest} = decode_tag_and_length(Bin), - decode_incomplete2(Form,TagNo,V,Directives,Rest); -decode_primitive_incomplete([],Bin) -> - decode_primitive(Bin). - -%% decode_parts_incomplete/1 receives a number of values encoded in -%% sequence and returns the parts as unencoded binaries -decode_parts_incomplete(<<>>) -> - []; -decode_parts_incomplete(Bin) -> - {ok,Rest} = skip_tag(Bin), - {ok,Rest2} = skip_length_and_value(Rest), - LenPart = size(Bin) - size(Rest2), - <> = Bin, - [Part|decode_parts_incomplete(RestBin)]. - - -%% decode_incomplete2 checks if V is a value of a constructed or -%% primitive type, and continues the decode propeerly. -decode_incomplete2(_Form=2,TagNo,V,TagMatch,_) -> - %% constructed indefinite length - {Vlist,Rest2} = decode_constr_indef_incomplete(TagMatch,V,[]), - {{TagNo,Vlist},Rest2}; -decode_incomplete2(1,TagNo,V,[TagMatch],Rest) when is_list(TagMatch) -> - {{TagNo,decode_constructed_incomplete(TagMatch,V)},Rest}; -decode_incomplete2(1,TagNo,V,TagMatch,Rest) -> - {{TagNo,decode_constructed_incomplete(TagMatch,V)},Rest}; -decode_incomplete2(0,TagNo,V,_TagMatch,Rest) -> - {{TagNo,V},Rest}. - -decode_constructed_incomplete([Tags=[Ts]],Bin) when is_list(Ts) -> - decode_constructed_incomplete(Tags,Bin); -decode_constructed_incomplete(_TagMatch,<<>>) -> - []; -decode_constructed_incomplete([mandatory|RestTag],Bin) -> - {Tlv,Rest} = decode_primitive(Bin), - [Tlv|decode_constructed_incomplete(RestTag,Rest)]; -decode_constructed_incomplete(Directives=[[Alt,_]|_],Bin) - when Alt == alt_undec; Alt == alt; Alt == alt_parts -> - {_Form,TagNo,V,Rest} = decode_tag_and_length(Bin), - case incomplete_choice_alt(TagNo,Directives) of - {alt_undec,_} -> - LenA = size(Bin)-size(Rest), - <> = Bin, - A; - {alt,InnerDirectives} -> - {Tlv,Rest} = decode_primitive_incomplete(InnerDirectives,V), - {TagNo,Tlv}; - {alt_parts,_} -> - [{TagNo,decode_parts_incomplete(V)}]; - no_match -> %% if a choice alternative was encoded that - %% was not specified in the config file, - %% thus decode component anonomous. - {Tlv,_}=decode_primitive(Bin), - Tlv - end; -decode_constructed_incomplete([TagNo|RestTag],Bin) -> -%% {Tlv,Rest} = decode_primitive_incomplete([TagNo],Bin), - case decode_primitive_incomplete([TagNo],Bin) of - {Tlv,Rest} -> - [Tlv|decode_constructed_incomplete(RestTag,Rest)]; - asn1_NOVALUE -> - decode_constructed_incomplete(RestTag,Bin) - end; -decode_constructed_incomplete([],Bin) -> - {Tlv,Rest}=decode_primitive(Bin), - [Tlv|decode_constructed_incomplete([],Rest)]. - -decode_constr_indef_incomplete(_TagMatch,<<0,0,Rest/binary>>,Acc) -> - {lists:reverse(Acc),Rest}; -decode_constr_indef_incomplete([Tag|RestTags],Bin,Acc) -> -% {Tlv,Rest} = decode_primitive_incomplete([Tag],Bin), - case decode_primitive_incomplete([Tag],Bin) of - {Tlv,Rest} -> - decode_constr_indef_incomplete(RestTags,Rest,[Tlv|Acc]); - asn1_NOVALUE -> - decode_constr_indef_incomplete(RestTags,Bin,Acc) - end. - - -decode_incomplete_bin(Bin) -> - {ok,Rest} = skip_tag(Bin), - {ok,Rest2} = skip_length_and_value(Rest), - IncLen = size(Bin) - size(Rest2), - <> = Bin, - {IncBin,Ret}. - -incomplete_choice_alt(TagNo,[[Alt,TagNo]|Directives]) -> - {Alt,Directives}; -incomplete_choice_alt(TagNo,[D]) when is_list(D) -> - incomplete_choice_alt(TagNo,D); -incomplete_choice_alt(TagNo,[_H|Directives]) -> - incomplete_choice_alt(TagNo,Directives); -incomplete_choice_alt(_,[]) -> - no_match. - - - - -%% decode_selective(Pattern, Binary) the first argument is a pattern that tells -%% what to do with the next element the second is the BER encoded -%% message as a binary -%% Returns {ok,Value} or {error,Reason} -%% Value is a binary that in turn must be decoded to get the decoded -%% value. -decode_selective([],Binary) -> - {ok,Binary}; -decode_selective([skip|RestPattern],Binary)-> - {ok,RestBinary}=skip_tag(Binary), - {ok,RestBinary2}=skip_length_and_value(RestBinary), - decode_selective(RestPattern,RestBinary2); -decode_selective([[skip_optional,Tag]|RestPattern],Binary) -> - case skip_optional_tag(Tag,Binary) of - {ok,RestBinary} -> - {ok,RestBinary2}=skip_length_and_value(RestBinary), - decode_selective(RestPattern,RestBinary2); - missing -> - decode_selective(RestPattern,Binary) - end; -decode_selective([[choosen,Tag]],Binary) -> - return_value(Tag,Binary); -% case skip_optional_tag(Tag,Binary) of %may be optional/default -% {ok,RestBinary} -> -% {ok,Value} = get_value(RestBinary); -% missing -> -% {ok,<<>>} -% end; -decode_selective([[choosen,Tag]|RestPattern],Binary) -> - case skip_optional_tag(Tag,Binary) of - {ok,RestBinary} -> - {ok,Value} = get_value(RestBinary), - decode_selective(RestPattern,Value); - missing -> - {ok,<<>>} - end; -decode_selective(P,_) -> - {error,{asn1,{partial_decode,"bad pattern",P}}}. - -return_value(Tag,Binary) -> - {ok,{Tag,RestBinary}}=get_tag(Binary), - {ok,{LenVal,_RestBinary2}} = get_length_and_value(RestBinary), - {ok,<>}. - - -%% skip_tag and skip_length_and_value are rutines used both by -%% decode_partial_incomplete and decode_selective (decode/2). - -skip_tag(<<_:3,31:5,Rest/binary>>)-> - skip_long_tag(Rest); -skip_tag(<<_:3,_Tag:5,Rest/binary>>) -> - {ok,Rest}. - -skip_long_tag(<<1:1,_:7,Rest/binary>>) -> - skip_long_tag(Rest); -skip_long_tag(<<0:1,_:7,Rest/binary>>) -> - {ok,Rest}. - -skip_optional_tag(<<>>,Binary) -> - {ok,Binary}; -skip_optional_tag(<>,<>) -> - skip_optional_tag(RestTag,Rest); -skip_optional_tag(_,_) -> - missing. - - - - -skip_length_and_value(Binary) -> - case decode_length(Binary) of - {indefinite,RestBinary} -> - skip_indefinite_value(RestBinary); - {Length,RestBinary} -> - <<_:Length/unit:8,Rest/binary>> = RestBinary, - {ok,Rest} - end. - -skip_indefinite_value(<<0,0,Rest/binary>>) -> - {ok,Rest}; -skip_indefinite_value(Binary) -> - {ok,RestBinary}=skip_tag(Binary), - {ok,RestBinary2} = skip_length_and_value(RestBinary), - skip_indefinite_value(RestBinary2). - -get_value(Binary) -> - case decode_length(Binary) of - {indefinite,RestBinary} -> - get_indefinite_value(RestBinary,[]); - {Length,RestBinary} -> - <> = RestBinary, - {ok,Value} - end. - -get_indefinite_value(<<0,0,_Rest/binary>>,Acc) -> - {ok,list_to_binary(lists:reverse(Acc))}; -get_indefinite_value(Binary,Acc) -> - {ok,{Tag,RestBinary}}=get_tag(Binary), - {ok,{LenVal,RestBinary2}} = get_length_and_value(RestBinary), - get_indefinite_value(RestBinary2,[LenVal,Tag|Acc]). - -get_tag(<>) -> - case H of - <<_:3,31:5>> -> - get_long_tag(Rest,[H]); - _ -> {ok,{H,Rest}} - end. -get_long_tag(<>,Acc) -> - case H of - <<0:1,_:7>> -> - {ok,{list_to_binary(lists:reverse([H|Acc])),Rest}}; - _ -> - get_long_tag(Rest,[H|Acc]) - end. - -get_length_and_value(Bin = <<0:1,Length:7,_T/binary>>) -> - <> = Bin, - {ok,{<>, Rest}}; -get_length_and_value(Bin = <<1:1,0:7,_T/binary>>) -> - get_indefinite_length_and_value(Bin); -get_length_and_value(<<1:1,LL:7,T/binary>>) -> - <> = T, - <> = Rest, - {ok,{<<1:1,LL:7,Length:LL/unit:8,Value/binary>>,Rest2}}. - -get_indefinite_length_and_value(<>) -> - get_indefinite_length_and_value(T,[H]). - -get_indefinite_length_and_value(<<0,0,Rest/binary>>,Acc) -> - {ok,{list_to_binary(lists:reverse(Acc)),Rest}}; -get_indefinite_length_and_value(Binary,Acc) -> - {ok,{Tag,RestBinary}}=get_tag(Binary), - {ok,{LenVal,RestBinary2}}=get_length_and_value(RestBinary), - get_indefinite_length_and_value(RestBinary2,[LenVal,Tag|Acc]). - - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% match_tags takes a Tlv (Tag, Length, Value) structure and matches -%% it with the tags in TagList. If the tags does not match the function -%% crashes otherwise it returns the remaining Tlv after that the tags have -%% been removed. -%% -%% match_tags(Tlv, TagList) -%% - -match_tags({T,V},[T]) -> - V; -match_tags({T,V}, [T|Tt]) -> - match_tags(V,Tt); -match_tags([{T,V}],[T|Tt]) -> - match_tags(V, Tt); -match_tags(Vlist = [{T,_V}|_], [T]) -> - Vlist; -match_tags(Tlv, []) -> - Tlv; -match_tags(Tlv = {Tag,_V},[T|_Tt]) -> - exit({error,{asn1,{wrong_tag,{{expected,T},{got,Tag,Tlv}}}}}). - -%%% -%% skips components that do not match a tag in Tags -skip_ExtensionAdditions([],_Tags) -> - []; -skip_ExtensionAdditions(TLV=[{Tag,_}|Rest],Tags) -> - case [X||X=T<-Tags,T==Tag] of - [] -> - %% skip this TLV and continue with next - skip_ExtensionAdditions(Rest,Tags); - _ -> - TLV - end. - - -%%=============================================================================== -%%=============================================================================== -%%=============================================================================== -%% Optionals, preset not filled optionals with asn1_NOVALUE -%%=============================================================================== -%%=============================================================================== -%%=============================================================================== - -fixoptionals(OptList,Val) when is_list(Val) -> - fixoptionals(OptList,Val,1,[],[]). - -fixoptionals([{Name,Pos}|Ot],[{Name,Val}|Vt],_Opt,Acc1,Acc2) -> - fixoptionals(Ot,Vt,Pos+1,[1|Acc1],[{Name,Val}|Acc2]); -fixoptionals([{_Name,Pos}|Ot],V,Pos,Acc1,Acc2) -> - fixoptionals(Ot,V,Pos+1,[0|Acc1],[asn1_NOVALUE|Acc2]); -fixoptionals(O,[Vh|Vt],Pos,Acc1,Acc2) -> - fixoptionals(O,Vt,Pos+1,Acc1,[Vh|Acc2]); -fixoptionals([],[Vh|Vt],Pos,Acc1,Acc2) -> - fixoptionals([],Vt,Pos+1,Acc1,[Vh|Acc2]); -fixoptionals([],[],_,_Acc1,Acc2) -> - % return Val as a record - list_to_tuple([asn1_RECORDNAME|lists:reverse(Acc2)]). - - -%%encode_tag(TagClass(?UNI, APP etc), Form (?PRIM etx), TagInteger) -> -%% 8bit Int | binary -encode_tag_val({Class, Form, TagNo}) when (TagNo =< 30) -> - <<(Class bsr 6):2,(Form bsr 5):1,TagNo:5>>; - -encode_tag_val({Class, Form, TagNo}) -> - {Octets,_Len} = mk_object_val(TagNo), - BinOct = list_to_binary(Octets), - <<(Class bsr 6):2, (Form bsr 5):1, 31:5,BinOct/binary>>. - - -%%=============================================================================== -%% Decode a tag -%% -%% decode_tag(OctetListBuffer) -> {{Form, (Class bsl 16)+ TagNo}, RestOfBuffer, RemovedBytes} -%%=============================================================================== - -decode_tag_and_length(<>) when TagNo < 31 -> - {Form, (Class bsl 16) + TagNo, V, RestBuffer}; -decode_tag_and_length(<>) when TagNo < 31 -> - {2, (Class bsl 16) + TagNo, T, <<>>}; -decode_tag_and_length(<>) when TagNo < 31 -> - {Form, (Class bsl 16) + TagNo, V, T}; -decode_tag_and_length(<>) -> - {Form, (Class bsl 16) + TagNo, V, RestBuffer}; -decode_tag_and_length(<>) -> - {2, (Class bsl 16) + TagNo, T, <<>>}; -decode_tag_and_length(<>) -> - {Form, (Class bsl 16) + TagNo, V, T}; -decode_tag_and_length(<>) -> - TagNo = (TagPart1 bsl 7) bor TagPartLast, - {Length, RestBuffer} = decode_length(Buffer), - << V:Length/binary, RestBuffer2/binary>> = RestBuffer, - {Form, (Class bsl 16) + TagNo, V, RestBuffer2}; -decode_tag_and_length(<>) -> - {TagNo, Buffer1} = decode_tag(Buffer, 0), - {Length, RestBuffer} = decode_length(Buffer1), - << V:Length/binary, RestBuffer2/binary>> = RestBuffer, - {Form, (Class bsl 16) + TagNo, V, RestBuffer2}. - - - -%% last partial tag -decode_tag(<<0:1,PartialTag:7, Buffer/binary>>, TagAck) -> - TagNo = (TagAck bsl 7) bor PartialTag, - %%<> = <>, - {TagNo, Buffer}; -% more tags -decode_tag(<<_:1,PartialTag:7, Buffer/binary>>, TagAck) -> - TagAck1 = (TagAck bsl 7) bor PartialTag, - %%<> = <>, - decode_tag(Buffer, TagAck1). - - -%%======================================================================= -%% -%% Encode all tags in the list Tags and return a possibly deep list of -%% bytes with tag and length encoded -%% The taglist must be in reverse order (fixed by the asn1 compiler) -%% e.g [T1,T2] will result in -%% {[EncodedT2,EncodedT1|BytesSoFar],LenSoFar+LenT2+LenT1} -%% - -encode_tags([Tag|Trest], BytesSoFar, LenSoFar) -> -% remove {Bytes1,L1} = encode_one_tag(Tag), - {Bytes2,L2} = encode_length(LenSoFar), - encode_tags(Trest, [Tag,Bytes2|BytesSoFar], - LenSoFar + size(Tag) + L2); -encode_tags([], BytesSoFar, LenSoFar) -> - {BytesSoFar,LenSoFar}. - -encode_tags(TagIn, {BytesSoFar,LenSoFar}) -> - encode_tags(TagIn, BytesSoFar, LenSoFar). - -% encode_one_tag(#tag{class=Class,number=No,type=Type, form = Form}) -> -% NewForm = case Type of -% 'EXPLICIT' -> -% ?CONSTRUCTED; -% _ -> -% Form -% end, -% Bytes = encode_tag_val({Class,NewForm,No}), -% {Bytes,size(Bytes)}. - - -%%=============================================================================== -%% -%% This comment is valid for all the encode/decode functions -%% -%% C = Constraint -> typically {'ValueRange',LowerBound,UpperBound} -%% used for PER-coding but not for BER-coding. -%% -%% Val = Value. If Val is an atom then it is a symbolic integer value -%% (i.e the atom must be one of the names in the NamedNumberList). -%% The NamedNumberList is used to translate the atom to an integer value -%% before encoding. -%% -%%=============================================================================== - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% encode_open_type(Value) -> io_list (i.e nested list with integers, binaries) -%% Value = list of bytes of an already encoded value (the list must be flat) -%% | binary - -%% -encode_open_type(Val) when is_list(Val) -> -% {Val,length(Val)}; - encode_open_type(list_to_binary(Val)); -encode_open_type(Val) -> - {Val, size(Val)}. - -%% -encode_open_type(Val, T) when is_list(Val) -> - encode_open_type(list_to_binary(Val),T); -encode_open_type(Val,[]) -> - {Val, size(Val)}; -encode_open_type(Val,Tag) -> - encode_tags(Tag,Val, size(Val)). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_open_type(Tlv, TagIn) -> Value -%% Tlv = {Tag,V} | V where V -> binary() -%% TagIn = [TagVal] where TagVal -> int() -%% Value = binary with decoded data (which must be decoded again as some type) -%% -decode_open_type(Tlv, TagIn) -> - decode_open_type(Tlv, TagIn, erlang). -decode_open_type(Tlv, TagIn, Method) -> - case match_tags(Tlv,TagIn) of - Bin when is_binary(Bin) -> - {InnerTlv,_} = decode(Bin,Method), - InnerTlv; - TlvBytes -> TlvBytes - end. - - -decode_open_type_as_binary(Tlv, TagIn) -> - decode_open_type_as_binary(Tlv, TagIn, erlang). -decode_open_type_as_binary(Tlv,TagIn, Method)-> - case match_tags(Tlv,TagIn) of - V when is_binary(V) -> - V; - [Tlv2] -> encode(Tlv2, Method); - Tlv2 -> encode(Tlv2, Method) - end. - -%%=============================================================================== -%%=============================================================================== -%%=============================================================================== -%% Boolean, ITU_T X.690 Chapter 8.2 -%%=============================================================================== -%%=============================================================================== -%%=============================================================================== - -%%=============================================================================== -%% encode_boolean(Integer, ReversedTagList) -> {[Octet],Len} -%%=============================================================================== - -encode_boolean({Name, Val}, TagIn) when is_atom(Name) -> - encode_boolean(Val, TagIn); -encode_boolean(true, TagIn) -> - encode_tags(TagIn, [16#FF],1); -encode_boolean(false, TagIn) -> - encode_tags(TagIn, [0],1); -encode_boolean(X,_) -> - exit({error,{asn1, {encode_boolean, X}}}). - - -%%=============================================================================== -%% decode_boolean(BuffList, HasTag, TotalLen) -> {true, Remain, RemovedBytes} | -%% {false, Remain, RemovedBytes} -%%=============================================================================== -decode_boolean(Tlv,TagIn) -> - Val = match_tags(Tlv, TagIn), - case Val of - <<0:8>> -> - false; - <<_:8>> -> - true; - _ -> - exit({error,{asn1, {decode_boolean, Val}}}) - end. - - -%%=========================================================================== -%% Integer, ITU_T X.690 Chapter 8.3 - -%% encode_integer(Constraint, Value, Tag) -> [octet list] -%% encode_integer(Constraint, Name, NamedNumberList, Tag) -> [octet list] -%% Value = INTEGER | {Name,INTEGER} -%% Tag = tag | notag -%%=========================================================================== - -encode_integer(C, Val, Tag) when is_integer(Val) -> - encode_tags(Tag, encode_integer(C, Val)); -encode_integer(C,{Name,Val},Tag) when is_atom(Name) -> - encode_integer(C,Val,Tag); -encode_integer(_C, Val, _Tag) -> - exit({error,{asn1, {encode_integer, Val}}}). - - - -encode_integer(C, Val, NamedNumberList, Tag) when is_atom(Val) -> - case lists:keysearch(Val, 1, NamedNumberList) of - {value,{_, NewVal}} -> - encode_tags(Tag, encode_integer(C, NewVal)); - _ -> - exit({error,{asn1, {encode_integer_namednumber, Val}}}) - end; -encode_integer(C,{_Name,Val},NamedNumberList,Tag) -> - encode_integer(C,Val,NamedNumberList,Tag); -encode_integer(C, Val, _NamedNumberList, Tag) -> - encode_tags(Tag, encode_integer(C, Val)). - - -encode_integer(_, Val) -> - Bytes = - if - Val >= 0 -> - encode_integer_pos(Val, []); - true -> - encode_integer_neg(Val, []) - end, - {Bytes,length(Bytes)}. - -encode_integer_pos(0, L=[B|_Acc]) when B < 128 -> - L; -encode_integer_pos(N, Acc) -> - encode_integer_pos((N bsr 8), [N band 16#ff| Acc]). - -encode_integer_neg(-1, L=[B1|_T]) when B1 > 127 -> - L; -encode_integer_neg(N, Acc) -> - encode_integer_neg(N bsr 8, [N band 16#ff|Acc]). - -%%=============================================================================== -%% decode integer -%% (Buffer, Range, HasTag, TotalLen) -> {Integer, Remain, RemovedBytes} -%% (Buffer, Range, NamedNumberList, HasTag, TotalLen) -> {Integer, Remain, RemovedBytes} -%%=============================================================================== - -decode_integer(Tlv,Range,NamedNumberList,TagIn) -> - V = match_tags(Tlv,TagIn), - Int = decode_integer(V), - range_check_integer(Int,Range), - number2name(Int,NamedNumberList). - -decode_integer(Tlv,Range,TagIn) -> - V = match_tags(Tlv, TagIn), - Int = decode_integer(V), - range_check_integer(Int,Range), - Int. - -%% decoding postitive integer values. -decode_integer(Bin = <<0:1,_:7,_/binary>>) -> - Len = size(Bin), -% <> = Bin, - <> = Bin, - Int; -%% decoding negative integer values. -decode_integer(Bin = <<1:1,B2:7,Bs/binary>>) -> - Len = size(Bin), -% <> = <>, - <> = <>, - Int = N - (1 bsl (8 * Len - 1)), - Int. - -range_check_integer(Int,Range) -> - case Range of - [] -> % No length constraint - Int; - {Lb,Ub} when Int >= Lb, Ub >= Int -> % variable length constraint - Int; - Int -> % fixed value constraint - Int; - {_,_} -> - exit({error,{asn1,{integer_range,Range,Int}}}); - SingleValue when is_integer(SingleValue) -> - exit({error,{asn1,{integer_range,Range,Int}}}); - _ -> % some strange constraint that we don't support yet - Int - end. - -number2name(Int,[]) -> - Int; -number2name(Int,NamedNumberList) -> - case lists:keysearch(Int, 2, NamedNumberList) of - {value,{NamedVal, _}} -> - NamedVal; - _ -> - Int - end. - - -%%============================================================================ -%% Enumerated value, ITU_T X.690 Chapter 8.4 - -%% encode enumerated value -%%============================================================================ -encode_enumerated(Val, TagIn) when is_integer(Val)-> - encode_tags(TagIn, encode_integer(false,Val)); -encode_enumerated({Name,Val}, TagIn) when is_atom(Name) -> - encode_enumerated(Val, TagIn). - -%% The encode_enumerated functions below this line can be removed when the -%% new code generation is stable. (the functions might have to be kept here -%% a while longer for compatibility reasons) - -encode_enumerated(C, Val, {NamedNumberList,ExtList}, TagIn) when is_atom(Val) -> - case catch encode_enumerated(C, Val, NamedNumberList, TagIn) of - {'EXIT',_} -> encode_enumerated(C, Val, ExtList, TagIn); - Result -> Result - end; - -encode_enumerated(C, Val, NamedNumberList, TagIn) when is_atom(Val) -> - case lists:keysearch(Val, 1, NamedNumberList) of - {value, {_, NewVal}} -> - encode_tags(TagIn, encode_integer(C, NewVal)); - _ -> - exit({error,{asn1, {enumerated_not_in_range, Val}}}) - end; - -encode_enumerated(C, {asn1_enum, Val}, {_,_}, TagIn) when is_integer(Val) -> - encode_tags(TagIn, encode_integer(C,Val)); - -encode_enumerated(C, {Name,Val}, NamedNumberList, TagIn) when is_atom(Name) -> - encode_enumerated(C, Val, NamedNumberList, TagIn); - -encode_enumerated(_C, Val, _NamedNumberList, _TagIn) -> - exit({error,{asn1, {enumerated_not_namednumber, Val}}}). - - - -%%============================================================================ -%% decode enumerated value -%% (Buffer, Range, NamedNumberList, HasTag, TotalLen) -> Value -%%=========================================================================== -decode_enumerated(Tlv, Range, NamedNumberList, Tags) -> - Buffer = match_tags(Tlv,Tags), - decode_enumerated_notag(Buffer, Range, NamedNumberList, Tags). - -decode_enumerated_notag(Buffer, _Range, {NamedNumberList,ExtList}, _Tags) -> - - IVal = decode_integer2(size(Buffer), Buffer), - case decode_enumerated1(IVal, NamedNumberList) of - {asn1_enum,IVal} -> - decode_enumerated1(IVal,ExtList); - EVal -> - EVal - end; -decode_enumerated_notag(Buffer, _Range, NNList, _Tags) -> - IVal = decode_integer2(size(Buffer), Buffer), - case decode_enumerated1(IVal, NNList) of - {asn1_enum,_} -> - exit({error,{asn1, {illegal_enumerated, IVal}}}); - EVal -> - EVal - end. - -decode_enumerated1(Val, NamedNumberList) -> - %% it must be a named integer - case lists:keysearch(Val, 2, NamedNumberList) of - {value,{NamedVal, _}} -> - NamedVal; - _ -> - {asn1_enum,Val} - end. - - -%%============================================================================ -%% -%% Real value, ITU_T X.690 Chapter 8.5 -%%============================================================================ -%% -%% encode real value -%%============================================================================ - -%% only base 2 internally so far!! -encode_real(_C,0, TagIn) -> - encode_tags(TagIn, {[],0}); -encode_real(_C,'PLUS-INFINITY', TagIn) -> - encode_tags(TagIn, {[64],1}); -encode_real(_C,'MINUS-INFINITY', TagIn) -> - encode_tags(TagIn, {[65],1}); -encode_real(C,Val, TagIn) when is_tuple(Val); is_list(Val) -> - encode_tags(TagIn, encode_real(C,Val)). - - - -encode_real(C,Val) -> - asn1rt_ber_bin:encode_real(C,Val). - - -%%============================================================================ -%% decode real value -%% -%% decode_real([OctetBufferList], tuple|value, tag|notag) -> -%% {{Mantissa, Base, Exp} | realval | PLUS-INFINITY | MINUS-INFINITY | 0, -%% RestBuff} -%% -%% only for base 2 and 10 decoding sofar!! -%%============================================================================ - -decode_real(Tlv, Tags) -> - Buffer = match_tags(Tlv,Tags), - decode_real_notag(Buffer). - -decode_real_notag(Buffer) -> - Len = - case Buffer of - Bin when is_binary(Bin) -> - size(Bin); - {_T,_V} -> - exit({error,{asn1,{real_not_in_primitive_form,Buffer}}}) - end, - {Val,_Rest,Len} = asn1rt_ber_bin:decode_real(Buffer,Len), - Val. -%% exit({error,{asn1, {unimplemented,real}}}). -%% decode_real2(Buffer, Form, size(Buffer)). - -% decode_real2(Buffer, Form, Len) -> -% <> = Buffer, -% if -% First =:= 2#01000000 -> {'PLUS-INFINITY', Buffer2}; -% First =:= 2#01000001 -> {'MINUS-INFINITY', Buffer2}; -% First =:= 2#00000000 -> {0, Buffer2}; -% true -> -% %% have some check here to verify only supported bases (2) -% <> = <>, -% Sign = B6, -% Base = -% case B5_4 of -% 0 -> 2; % base 2, only one so far -% _ -> exit({error,{asn1, {non_supported_base, First}}}) -% end, -% ScalingFactor = -% case B3_2 of -% 0 -> 0; % no scaling so far -% _ -> exit({error,{asn1, {non_supported_scaling, First}}}) -% end, - -% {FirstLen,Exp,Buffer3} = -% case B1_0 of -% 0 -> -% <<_:1/unit:8,Buffer21/binary>> = Buffer2, -% {2, decode_integer2(1, Buffer2),Buffer21}; -% 1 -> -% <<_:2/unit:8,Buffer21/binary>> = Buffer2, -% {3, decode_integer2(2, Buffer2)}; -% 2 -> -% <<_:3/unit:8,Buffer21/binary>> = Buffer2, -% {4, decode_integer2(3, Buffer2)}; -% 3 -> -% <> = Buffer2, -% <<_:ExpLen1/unit:8,RestBuffer2/binary>> = RestBuffer, -% { ExpLen1 + 2, -% decode_integer2(ExpLen1, RestBuffer, RemBytes1), -% RestBuffer2} -% end, -% Length = Len - FirstLen, -% <> = Buffer3, -% {Mantissa, Buffer4} = -% if Sign =:= 0 -> - -% {LongInt, RestBuff};% sign plus, -% true -> - -% {-LongInt, RestBuff}% sign minus -% end, -% case Form of -% tuple -> -% {Val,Buf,RemB} = Exp, -% {{Mantissa, Base, {Val,Buf}}, Buffer4, RemBytes2+RemBytes3}; -% _value -> -% comming -% end -% end. - - -%%============================================================================ -%% Bitstring value, ITU_T X.690 Chapter 8.6 -%% -%% encode bitstring value -%% -%% bitstring NamedBitList -%% Val can be of: -%% - [identifiers] where only named identifers are set to one, -%% the Constraint must then have some information of the -%% bitlength. -%% - [list of ones and zeroes] all bits -%% - integer value representing the bitlist -%% C is constrint Len, only valid when identifiers -%%============================================================================ - -encode_bit_string(C,Bin={Unused,BinBits},NamedBitList,TagIn) when is_integer(Unused), is_binary(BinBits) -> - encode_bin_bit_string(C,Bin,NamedBitList,TagIn); -encode_bit_string(C, [FirstVal | RestVal], NamedBitList, TagIn) when is_atom(FirstVal) -> - encode_bit_string_named(C, [FirstVal | RestVal], NamedBitList, TagIn); - -encode_bit_string(C, [{bit,X} | RestVal], NamedBitList, TagIn) -> - encode_bit_string_named(C, [{bit,X} | RestVal], NamedBitList, TagIn); - -encode_bit_string(C, [FirstVal| RestVal], NamedBitList, TagIn) when is_integer(FirstVal) -> - encode_bit_string_bits(C, [FirstVal | RestVal], NamedBitList, TagIn); - -encode_bit_string(_C, 0, _NamedBitList, TagIn) -> - encode_tags(TagIn, <<0>>,1); - -encode_bit_string(_C, [], _NamedBitList, TagIn) -> - encode_tags(TagIn, <<0>>,1); - -encode_bit_string(C, IntegerVal, NamedBitList, TagIn) when is_integer(IntegerVal) -> - BitListVal = int_to_bitlist(IntegerVal), - encode_bit_string_bits(C, BitListVal, NamedBitList, TagIn); - -encode_bit_string(C, {Name,BitList}, NamedBitList, TagIn) when is_atom(Name) -> - encode_bit_string(C, BitList, NamedBitList, TagIn). - - - -int_to_bitlist(0) -> - []; -int_to_bitlist(Int) when is_integer(Int), Int >= 0 -> - [Int band 1 | int_to_bitlist(Int bsr 1)]. - - -%%================================================================= -%% Encode BIT STRING of the form {Unused,BinBits}. -%% Unused is the number of unused bits in the last byte in BinBits -%% and BinBits is a binary representing the BIT STRING. -%%================================================================= -encode_bin_bit_string(C,{Unused,BinBits},_NamedBitList,TagIn)-> - case get_constraint(C,'SizeConstraint') of - no -> - remove_unused_then_dotag(TagIn, Unused, BinBits); - {_Min,Max} -> - BBLen = (size(BinBits)*8)-Unused, - if - BBLen > Max -> - exit({error,{asn1, - {bitstring_length, - {{was,BBLen},{maximum,Max}}}}}); - true -> - remove_unused_then_dotag(TagIn, Unused, BinBits) - end; - Size -> - case ((size(BinBits)*8)-Unused) of - BBSize when BBSize =< Size -> - remove_unused_then_dotag(TagIn, Unused, BinBits); - BBSize -> - exit({error,{asn1, - {bitstring_length, - {{was,BBSize},{should_be,Size}}}}}) - end - end. - -remove_unused_then_dotag(TagIn,Unused,BinBits) -> - case Unused of - 0 when (size(BinBits) == 0) -> - encode_tags(TagIn,<<0>>,1); - 0 -> - Bin = <>, - encode_tags(TagIn,Bin,size(Bin)); - Num -> - N = (size(BinBits)-1), - <> = BinBits, - encode_tags(TagIn, - [Unused,binary_to_list(BBits) ++[(LastByte bsr Num) bsl Num]], - 1+size(BinBits)) - end. - - -%%================================================================= -%% Encode named bits -%%================================================================= - -encode_bit_string_named(C, [FirstVal | RestVal], NamedBitList, TagIn) -> - ToSetPos = get_all_bitposes([FirstVal | RestVal], NamedBitList, []), - Size = - case get_constraint(C,'SizeConstraint') of - no -> - lists:max(ToSetPos)+1; - {_Min,Max} -> - Max; - TSize -> - TSize - end, - BitList = make_and_set_list(Size, ToSetPos, 0), - {Len, Unused, OctetList} = encode_bitstring(BitList), - encode_tags(TagIn, [Unused|OctetList],Len+1). - - -%%---------------------------------------- -%% get_all_bitposes([list of named bits to set], named_bit_db, []) -> -%% [sorted_list_of_bitpositions_to_set] -%%---------------------------------------- - -get_all_bitposes([{bit,ValPos}|Rest], NamedBitList, Ack) -> - get_all_bitposes(Rest, NamedBitList, [ValPos | Ack ]); -get_all_bitposes([Val | Rest], NamedBitList, Ack) when is_atom(Val) -> - case lists:keysearch(Val, 1, NamedBitList) of - {value, {_ValName, ValPos}} -> - get_all_bitposes(Rest, NamedBitList, [ValPos | Ack]); - _ -> - exit({error,{asn1, {bitstring_namedbit, Val}}}) - end; -get_all_bitposes([], _NamedBitList, Ack) -> - lists:sort(Ack). - - -%%---------------------------------------- -%% make_and_set_list(Len of list to return, [list of positions to set to 1])-> -%% returns list of Len length, with all in SetPos set. -%% in positioning in list the first element is 0, the second 1 etc.., but -%% Len will make a list of length Len, not Len + 1. -%% BitList = make_and_set_list(C, ToSetPos, 0), -%%---------------------------------------- - -make_and_set_list(0, [], _) -> []; -make_and_set_list(0, _, _) -> - exit({error,{asn1,bitstring_sizeconstraint}}); -make_and_set_list(Len, [XPos|SetPos], XPos) -> - [1 | make_and_set_list(Len - 1, SetPos, XPos + 1)]; -make_and_set_list(Len, [Pos|SetPos], XPos) -> - [0 | make_and_set_list(Len - 1, [Pos | SetPos], XPos + 1)]; -make_and_set_list(Len, [], XPos) -> - [0 | make_and_set_list(Len - 1, [], XPos + 1)]. - - - - - - -%%================================================================= -%% Encode bit string for lists of ones and zeroes -%%================================================================= -encode_bit_string_bits(C, BitListVal, _NamedBitList, TagIn) when is_list(BitListVal) -> - case get_constraint(C,'SizeConstraint') of - no -> - {Len, Unused, OctetList} = encode_bitstring(BitListVal), - %%add unused byte to the Len - encode_tags(TagIn, [Unused | OctetList], Len+1); - Constr={Min,_Max} when is_integer(Min) -> - %% Max may be an integer or 'MAX' - encode_constr_bit_str_bits(Constr,BitListVal,TagIn); - {Constr={_,_},[]} ->%Constr={Min,Max} - %% constraint with extension mark - encode_constr_bit_str_bits(Constr,BitListVal,TagIn); - Constr={{_,_},{_,_}} ->%{{Min1,Max1},{Min2,Max2}} - %% constraint with extension mark - encode_constr_bit_str_bits(Constr,BitListVal,TagIn); - Size -> - case length(BitListVal) of - BitSize when BitSize == Size -> - {Len, Unused, OctetList} = encode_bitstring(BitListVal), - %%add unused byte to the Len - encode_tags(TagIn, [Unused | OctetList], Len+1); - BitSize when BitSize < Size -> - PaddedList = pad_bit_list(Size-BitSize,BitListVal), - {Len, Unused, OctetList} = encode_bitstring(PaddedList), - %%add unused byte to the Len - encode_tags(TagIn, [Unused | OctetList], Len+1); - BitSize -> - exit({error,{asn1, - {bitstring_length, {{was,BitSize},{should_be,Size}}}}}) - end - - end. - -encode_constr_bit_str_bits({{_Min1,Max1},{Min2,Max2}},BitListVal,TagIn) -> - BitLen = length(BitListVal), - case BitLen of - Len when Len > Max2 -> - exit({error,{asn1,{bitstring_length,{{was,BitLen}, - {maximum,Max2}}}}}); - Len when Len > Max1, Len < Min2 -> - exit({error,{asn1,{bitstring_length,{{was,BitLen}, - {not_allowed_interval, - Max1,Min2}}}}}); - _ -> - {Len, Unused, OctetList} = encode_bitstring(BitListVal), - %%add unused byte to the Len - encode_tags(TagIn, [Unused, OctetList], Len+1) - end; -encode_constr_bit_str_bits({Min,Max},BitListVal,TagIn) -> - BitLen = length(BitListVal), - if - BitLen > Max -> - exit({error,{asn1,{bitstring_length,{{was,BitLen}, - {maximum,Max}}}}}); - BitLen < Min -> - exit({error,{asn1,{bitstring_length,{{was,BitLen}, - {minimum,Max}}}}}); - true -> - {Len, Unused, OctetList} = encode_bitstring(BitListVal), - %%add unused byte to the Len - encode_tags(TagIn, [Unused, OctetList], Len+1) - end. - - -%% returns a list of length Size + length(BitListVal), with BitListVal -%% as the most significant elements followed by padded zero elements -pad_bit_list(Size,BitListVal) -> - Tail = lists:duplicate(Size,0), - lists:append(BitListVal,Tail). - -%%================================================================= -%% Do the actual encoding -%% ([bitlist]) -> {ListLen, UnusedBits, OctetList} -%%================================================================= - -encode_bitstring([B8, B7, B6, B5, B4, B3, B2, B1 | Rest]) -> - Val = (B8 bsl 7) bor (B7 bsl 6) bor (B6 bsl 5) bor (B5 bsl 4) bor - (B4 bsl 3) bor (B3 bsl 2) bor (B2 bsl 1) bor B1, - encode_bitstring(Rest, [Val], 1); -encode_bitstring(Val) -> - {Unused, Octet} = unused_bitlist(Val, 7, 0), - {1, Unused, [Octet]}. - -encode_bitstring([B8, B7, B6, B5, B4, B3, B2, B1 | Rest], Ack, Len) -> - Val = (B8 bsl 7) bor (B7 bsl 6) bor (B6 bsl 5) bor (B5 bsl 4) bor - (B4 bsl 3) bor (B3 bsl 2) bor (B2 bsl 1) bor B1, - encode_bitstring(Rest, [Ack | [Val]], Len + 1); -%%even multiple of 8 bits.. -encode_bitstring([], Ack, Len) -> - {Len, 0, Ack}; -%% unused bits in last octet -encode_bitstring(Rest, Ack, Len) -> -% io:format("uneven ~w ~w ~w~n",[Rest, Ack, Len]), - {Unused, Val} = unused_bitlist(Rest, 7, 0), - {Len + 1, Unused, [Ack | [Val]]}. - -%%%%%%%%%%%%%%%%%% -%% unused_bitlist([list of ones and zeros <= 7], 7, []) -> -%% {Unused bits, Last octet with bits moved to right} -unused_bitlist([], Trail, Ack) -> - {Trail + 1, Ack}; -unused_bitlist([Bit | Rest], Trail, Ack) -> -%% io:format("trail Bit: ~w Rest: ~w Trail: ~w Ack:~w~n",[Bit, Rest, Trail, Ack]), - unused_bitlist(Rest, Trail - 1, (Bit bsl Trail) bor Ack). - - -%%============================================================================ -%% decode bitstring value -%% (Buffer, Range, NamedNumberList, HasTag, TotalLen) -> {Integer, Remain, RemovedBytes} -%%============================================================================ - -decode_compact_bit_string(Buffer, Range, NamedNumberList, Tags) -> -% NewTags = new_tags(HasTag,#tag{class=?UNIVERSAL,number=?N_BIT_STRING}), - decode_restricted_string(Buffer, Range, ?N_BIT_STRING, Tags, - NamedNumberList,bin). - -decode_bit_string(Buffer, Range, NamedNumberList, Tags) -> -% NewTags = new_tags(HasTag,#tag{class=?UNIVERSAL,number=?N_BIT_STRING}), - decode_restricted_string(Buffer, Range, ?N_BIT_STRING, Tags, - NamedNumberList,old). - - -decode_bit_string2(<<0>>,_NamedNumberList,BinOrOld) -> - case BinOrOld of - bin -> - {0,<<>>}; - _ -> - [] - end; -decode_bit_string2(<>,NamedNumberList,BinOrOld) -> - case NamedNumberList of - [] -> - case BinOrOld of - bin -> - {Unused,Bits}; - _ -> - decode_bitstring2(size(Bits), Unused, Bits) - end; - _ -> - BitString = decode_bitstring2(size(Bits), Unused, Bits), - decode_bitstring_NNL(BitString,NamedNumberList) - end. - -%%---------------------------------------- -%% Decode the in buffer to bits -%%---------------------------------------- -decode_bitstring2(1,Unused,<>) -> - lists:sublist([B7,B6,B5,B4,B3,B2,B1,B0],8-Unused); -decode_bitstring2(Len, Unused, - <>) -> - [B7, B6, B5, B4, B3, B2, B1, B0 | - decode_bitstring2(Len - 1, Unused, Buffer)]. - -%%decode_bitstring2(1, Unused, Buffer) -> -%% make_bits_of_int(hd(Buffer), 128, 8-Unused); -%%decode_bitstring2(Len, Unused, [BitVal | Buffer]) -> -%% [B7, B6, B5, B4, B3, B2, B1, B0] = make_bits_of_int(BitVal, 128, 8), -%% [B7, B6, B5, B4, B3, B2, B1, B0 | -%% decode_bitstring2(Len - 1, Unused, Buffer)]. - - -%%make_bits_of_int(_, _, 0) -> -%% []; -%%make_bits_of_int(BitVal, MaskVal, Unused) when Unused > 0 -> -%% X = case MaskVal band BitVal of -%% 0 -> 0 ; -%% _ -> 1 -%% end, -%% [X | make_bits_of_int(BitVal, MaskVal bsr 1, Unused - 1)]. - - - -%%---------------------------------------- -%% Decode the bitlist to names -%%---------------------------------------- - - -decode_bitstring_NNL(BitList,NamedNumberList) -> - decode_bitstring_NNL(BitList,NamedNumberList,0,[]). - - -decode_bitstring_NNL([],_,_No,Result) -> - lists:reverse(Result); - -decode_bitstring_NNL([B|BitList],[{Name,No}|NamedNumberList],No,Result) -> - if - B == 0 -> - decode_bitstring_NNL(BitList,NamedNumberList,No+1,Result); - true -> - decode_bitstring_NNL(BitList,NamedNumberList,No+1,[Name|Result]) - end; -decode_bitstring_NNL([1|BitList],NamedNumberList,No,Result) -> - decode_bitstring_NNL(BitList,NamedNumberList,No+1,[{bit,No}|Result]); -decode_bitstring_NNL([0|BitList],NamedNumberList,No,Result) -> - decode_bitstring_NNL(BitList,NamedNumberList,No+1,Result). - - -%%============================================================================ -%% Octet string, ITU_T X.690 Chapter 8.7 -%% -%% encode octet string -%% The OctetList must be a flat list of integers in the range 0..255 -%% the function does not check this because it takes to much time -%%============================================================================ -encode_octet_string(_C, OctetList, TagIn) when is_binary(OctetList) -> - encode_tags(TagIn, OctetList, size(OctetList)); -encode_octet_string(_C, OctetList, TagIn) when is_list(OctetList) -> - encode_tags(TagIn, OctetList, length(OctetList)); -encode_octet_string(C, {Name,OctetList}, TagIn) when is_atom(Name) -> - encode_octet_string(C, OctetList, TagIn). - - -%%============================================================================ -%% decode octet string -%% (Buffer, Range, HasTag, TotalLen) -> {String, Remain, RemovedBytes} -%% -%% Octet string is decoded as a restricted string -%%============================================================================ -decode_octet_string(Buffer, Range, Tags) -> -% NewTags = new_tags(HasTag,#tag{class=?UNIVERSAL,number=?N_OCTET_STRING}), - decode_restricted_string(Buffer, Range, ?N_OCTET_STRING, - Tags, [], old). - -%%============================================================================ -%% Null value, ITU_T X.690 Chapter 8.8 -%% -%% encode NULL value -%%============================================================================ - -encode_null({Name, _Val}, TagIn) when is_atom(Name) -> - encode_tags(TagIn, [], 0); -encode_null(_Val, TagIn) -> - encode_tags(TagIn, [], 0). - -%%============================================================================ -%% decode NULL value -%% (Buffer, HasTag, TotalLen) -> {NULL, Remain, RemovedBytes} -%%============================================================================ - -decode_null(Tlv, Tags) -> - Val = match_tags(Tlv, Tags), - case Val of - <<>> -> - 'NULL'; - _ -> - exit({error,{asn1,{decode_null,Val}}}) - end. - -%%============================================================================ -%% Object identifier, ITU_T X.690 Chapter 8.19 -%% -%% encode Object Identifier value -%%============================================================================ - -encode_object_identifier({Name,Val}, TagIn) when is_atom(Name) -> - encode_object_identifier(Val, TagIn); -encode_object_identifier(Val, TagIn) -> - encode_tags(TagIn, e_object_identifier(Val)). - -e_object_identifier({'OBJECT IDENTIFIER', V}) -> - e_object_identifier(V); -e_object_identifier({Cname, V}) when is_atom(Cname), is_tuple(V) -> - e_object_identifier(tuple_to_list(V)); -e_object_identifier({Cname, V}) when is_atom(Cname), is_list(V) -> - e_object_identifier(V); -e_object_identifier(V) when is_tuple(V) -> - e_object_identifier(tuple_to_list(V)); - -%%%%%%%%%%%%%%% -%% e_object_identifier([List of Obect Identifiers]) -> -%% {[Encoded Octetlist of ObjIds], IntLength} -%% -e_object_identifier([E1, E2 | Tail]) -> - Head = 40*E1 + E2, % wow! - {H,Lh} = mk_object_val(Head), - {R,Lr} = lists:mapfoldl(fun enc_obj_id_tail/2,0,Tail), - {[H|R], Lh+Lr}. - -enc_obj_id_tail(H, Len) -> - {B, L} = mk_object_val(H), - {B,Len+L}. - - -%%%%%%%%%%% -%% mk_object_val(Value) -> {OctetList, Len} -%% returns a Val as a list of octets, the 8 bit is allways set to one except -%% for the last octet, where its 0 -%% - - -mk_object_val(Val) when Val =< 127 -> - {[255 band Val], 1}; -mk_object_val(Val) -> - mk_object_val(Val bsr 7, [Val band 127], 1). -mk_object_val(0, Ack, Len) -> - {Ack, Len}; -mk_object_val(Val, Ack, Len) -> - mk_object_val(Val bsr 7, [((Val band 127) bor 128) | Ack], Len + 1). - - - -%%============================================================================ -%% decode Object Identifier value -%% (Buffer, HasTag, TotalLen) -> {{ObjId}, Remain, RemovedBytes} -%%============================================================================ - -decode_object_identifier(Tlv, Tags) -> - Val = match_tags(Tlv, Tags), - [AddedObjVal|ObjVals] = dec_subidentifiers(Val,0,[]), - {Val1, Val2} = if - AddedObjVal < 40 -> - {0, AddedObjVal}; - AddedObjVal < 80 -> - {1, AddedObjVal - 40}; - true -> - {2, AddedObjVal - 80} - end, - list_to_tuple([Val1, Val2 | ObjVals]). - -dec_subidentifiers(<<>>,_Av,Al) -> - lists:reverse(Al); -dec_subidentifiers(<<1:1,H:7,T/binary>>,Av,Al) -> - dec_subidentifiers(T,(Av bsl 7) + H,Al); -dec_subidentifiers(<>,Av,Al) -> - dec_subidentifiers(T,0,[((Av bsl 7) + H)|Al]). - -%%============================================================================ -%% RELATIVE-OID, ITU_T X.690 Chapter 8.20 -%% -%% encode Relative Object Identifier -%%============================================================================ -encode_relative_oid({Name,Val},TagIn) when is_atom(Name) -> - encode_relative_oid(Val,TagIn); -encode_relative_oid(Val,TagIn) when is_tuple(Val) -> - encode_relative_oid(tuple_to_list(Val),TagIn); -encode_relative_oid(Val,TagIn) -> - encode_tags(TagIn, enc_relative_oid(Val)). - -enc_relative_oid(Tuple) when is_tuple(Tuple) -> - enc_relative_oid(tuple_to_list(Tuple)); -enc_relative_oid(Val) -> - lists:mapfoldl(fun(X,AccIn) -> - {SO,L}=mk_object_val(X), - {SO,L+AccIn} - end - ,0,Val). - -%%============================================================================ -%% decode Relative Object Identifier value -%% (Buffer, HasTag, TotalLen) -> {{ObjId}, Remain, RemovedBytes} -%%============================================================================ -decode_relative_oid(Tlv, Tags) -> - Val = match_tags(Tlv, Tags), - ObjVals = dec_subidentifiers(Val,0,[]), - list_to_tuple(ObjVals). - -%%============================================================================ -%% Restricted character string types, ITU_T X.690 Chapter 8.20 -%% -%% encode Numeric Printable Teletex Videotex Visible IA5 Graphic General strings -%%============================================================================ -%% The StringType arg is kept for future use but might be removed -encode_restricted_string(_C, OctetList, _StringType, TagIn) - when is_binary(OctetList) -> - encode_tags(TagIn, OctetList, size(OctetList)); -encode_restricted_string(_C, OctetList, _StringType, TagIn) - when is_list(OctetList) -> - encode_tags(TagIn, OctetList, length(OctetList)); -encode_restricted_string(C,{Name,OctetL}, StringType, TagIn) when is_atom(Name)-> - encode_restricted_string(C, OctetL, StringType, TagIn). - -%%============================================================================ -%% decode Numeric Printable Teletex Videotex Visible IA5 Graphic General strings -%% (Buffer, Range, StringType, HasTag, TotalLen) -> -%% {String, Remain, RemovedBytes} -%%============================================================================ - -decode_restricted_string(Buffer, Range, StringType, Tags) -> - decode_restricted_string(Buffer, Range, StringType, Tags, [], old). - - -decode_restricted_string(Tlv, Range, StringType, TagsIn, - NamedNumberList, BinOrOld) -> - Val = match_tags(Tlv, TagsIn), - Val2 = - case Val of - PartList = [_H|_T] -> % constructed val - Bin = collect_parts(PartList), - decode_restricted(Bin, StringType, - NamedNumberList, BinOrOld); - Bin -> - decode_restricted(Bin, StringType, - NamedNumberList, BinOrOld) - end, - check_and_convert_restricted_string(Val2,StringType,Range,NamedNumberList,BinOrOld). - - - -% case StringType of -% ?N_BIT_STRING when BinOrOld == bin -> -% {concat_bit_binaries(AccVal, Val), AccRb+Rb}; -% _ when is_binary(Val),is_binary(AccVal) -> -% {<>,AccRb+Rb}; -% _ when is_binary(Val), AccVal==[] -> -% {Val,AccRb+Rb}; -% _ -> -% {AccVal++Val, AccRb+Rb} -% end, - - - -decode_restricted(Bin, StringType, NamedNumberList,BinOrOld) -> - case StringType of - ?N_BIT_STRING -> - decode_bit_string2(Bin, NamedNumberList, BinOrOld); - ?N_UniversalString -> - mk_universal_string(binary_to_list(Bin)); - ?N_BMPString -> - mk_BMP_string(binary_to_list(Bin)); - _ -> - Bin - end. - - -check_and_convert_restricted_string(Val,StringType,Range,NamedNumberList,_BinOrOld) -> - {StrLen,NewVal} = case StringType of - ?N_BIT_STRING when NamedNumberList /= [] -> - {no_check,Val}; - ?N_BIT_STRING when is_list(Val) -> - {length(Val),Val}; - ?N_BIT_STRING when is_tuple(Val) -> - {(size(element(2,Val))*8) - element(1,Val),Val}; - _ when is_binary(Val) -> - {size(Val),binary_to_list(Val)}; - _ when is_list(Val) -> - {length(Val), Val} - end, - case Range of - _ when StrLen == no_check -> - NewVal; - [] -> % No length constraint - NewVal; - {Lb,Ub} when StrLen >= Lb, Ub >= StrLen -> % variable length constraint - NewVal; - {{Lb,_Ub},[]} when StrLen >= Lb -> - NewVal; - {{Lb,_Ub},_Ext=[Min|_]} when StrLen >= Lb; StrLen >= Min -> - NewVal; - {{Lb1,Ub1},{Lb2,Ub2}} when StrLen >= Lb1, StrLen =< Ub1; - StrLen =< Ub2, StrLen >= Lb2 -> - NewVal; - StrLen -> % fixed length constraint - NewVal; - {_,_} -> - exit({error,{asn1,{length,Range,Val}}}); - _Len when is_integer(_Len) -> - exit({error,{asn1,{length,Range,Val}}}); - _ -> % some strange constraint that we don't support yet - NewVal - end. - - -%%============================================================================ -%% encode Universal string -%%============================================================================ - -encode_universal_string(C, {Name, Universal}, TagIn) when is_atom(Name) -> - encode_universal_string(C, Universal, TagIn); -encode_universal_string(_C, Universal, TagIn) -> - OctetList = mk_uni_list(Universal), - encode_tags(TagIn, OctetList, length(OctetList)). - -mk_uni_list(In) -> - mk_uni_list(In,[]). - -mk_uni_list([],List) -> - lists:reverse(List); -mk_uni_list([{A,B,C,D}|T],List) -> - mk_uni_list(T,[D,C,B,A|List]); -mk_uni_list([H|T],List) -> - mk_uni_list(T,[H,0,0,0|List]). - -%%=========================================================================== -%% decode Universal strings -%% (Buffer, Range, StringType, HasTag, LenIn) -> -%% {String, Remain, RemovedBytes} -%%=========================================================================== - -decode_universal_string(Buffer, Range, Tags) -> - decode_restricted_string(Buffer, Range, ?N_UniversalString, - Tags, [], old). - - -mk_universal_string(In) -> - mk_universal_string(In,[]). - -mk_universal_string([],Acc) -> - lists:reverse(Acc); -mk_universal_string([0,0,0,D|T],Acc) -> - mk_universal_string(T,[D|Acc]); -mk_universal_string([A,B,C,D|T],Acc) -> - mk_universal_string(T,[{A,B,C,D}|Acc]). - - -%%============================================================================ -%% encode UTF8 string -%%============================================================================ - -encode_UTF8_string(_C,UTF8String,TagIn) when is_binary(UTF8String) -> - encode_tags(TagIn, UTF8String, size(UTF8String)); -encode_UTF8_string(_C,UTF8String,TagIn) -> - encode_tags(TagIn, UTF8String, length(UTF8String)). - - -%%============================================================================ -%% decode UTF8 string -%%============================================================================ - -decode_UTF8_string(Tlv,TagsIn) -> - Val = match_tags(Tlv, TagsIn), - case Val of - PartList = [_H|_T] -> % constructed val - collect_parts(PartList); - Bin -> - Bin - end. - - -%%============================================================================ -%% encode BMP string -%%============================================================================ - -encode_BMP_string(C, {Name,BMPString}, TagIn) when is_atom(Name)-> - encode_BMP_string(C, BMPString, TagIn); -encode_BMP_string(_C, BMPString, TagIn) -> - OctetList = mk_BMP_list(BMPString), - encode_tags(TagIn, OctetList, length(OctetList)). - -mk_BMP_list(In) -> - mk_BMP_list(In,[]). - -mk_BMP_list([],List) -> - lists:reverse(List); -mk_BMP_list([{0,0,C,D}|T],List) -> - mk_BMP_list(T,[D,C|List]); -mk_BMP_list([H|T],List) -> - mk_BMP_list(T,[H,0|List]). - -%%============================================================================ -%% decode (OctetList, Range(ignored), tag|notag) -> {ValList, RestList} -%% (Buffer, Range, StringType, HasTag, TotalLen) -> -%% {String, Remain, RemovedBytes} -%%============================================================================ -decode_BMP_string(Buffer, Range, Tags) -> - decode_restricted_string(Buffer, Range, ?N_BMPString, - Tags, [], old). - -mk_BMP_string(In) -> - mk_BMP_string(In,[]). - -mk_BMP_string([],US) -> - lists:reverse(US); -mk_BMP_string([0,B|T],US) -> - mk_BMP_string(T,[B|US]); -mk_BMP_string([C,D|T],US) -> - mk_BMP_string(T,[{0,0,C,D}|US]). - - -%%============================================================================ -%% Generalized time, ITU_T X.680 Chapter 39 -%% -%% encode Generalized time -%%============================================================================ - -encode_generalized_time(C, {Name,OctetList}, TagIn) when is_atom(Name) -> - encode_generalized_time(C, OctetList, TagIn); -encode_generalized_time(_C, OctetList, TagIn) -> - encode_tags(TagIn, OctetList, length(OctetList)). - -%%============================================================================ -%% decode Generalized time -%% (Buffer, Range, HasTag, TotalLen) -> {String, Remain, RemovedBytes} -%%============================================================================ - -decode_generalized_time(Tlv, _Range, Tags) -> - Val = match_tags(Tlv, Tags), - NewVal = case Val of - PartList = [_H|_T] -> % constructed - collect_parts(PartList); - Bin -> - Bin - end, - binary_to_list(NewVal). - -%%============================================================================ -%% Universal time, ITU_T X.680 Chapter 40 -%% -%% encode UTC time -%%============================================================================ - -encode_utc_time(C, {Name,OctetList}, TagIn) when is_atom(Name) -> - encode_utc_time(C, OctetList, TagIn); -encode_utc_time(_C, OctetList, TagIn) -> - encode_tags(TagIn, OctetList, length(OctetList)). - -%%============================================================================ -%% decode UTC time -%% (Buffer, Range, HasTag, TotalLen) -> {String, Remain, RemovedBytes} -%%============================================================================ - -decode_utc_time(Tlv, _Range, Tags) -> - Val = match_tags(Tlv, Tags), - NewVal = case Val of - PartList = [_H|_T] -> % constructed - collect_parts(PartList); - Bin -> - Bin - end, - binary_to_list(NewVal). - - -%%============================================================================ -%% Length handling -%% -%% Encode length -%% -%% encode_length(Int | indefinite) -> -%% [<127]| [128 + Int (<127),OctetList] | [16#80] -%%============================================================================ - -encode_length(indefinite) -> - {[16#80],1}; % 128 -encode_length(L) when L =< 16#7F -> - {[L],1}; -encode_length(L) -> - Oct = minimum_octets(L), - Len = length(Oct), - if - Len =< 126 -> - {[ (16#80+Len) | Oct ],Len+1}; - true -> - exit({error,{asn1, to_long_length_oct, Len}}) - end. - - -%% Val must be >= 0 -minimum_octets(Val) -> - minimum_octets(Val,[]). - -minimum_octets(0,Acc) -> - Acc; -minimum_octets(Val, Acc) -> - minimum_octets((Val bsr 8),[Val band 16#FF | Acc]). - - -%%=========================================================================== -%% Decode length -%% -%% decode_length(OctetList) -> {{indefinite, RestOctetsL}, NoRemovedBytes} | -%% {{Length, RestOctetsL}, NoRemovedBytes} -%%=========================================================================== - -decode_length(<<1:1,0:7,T/binary>>) -> - {indefinite, T}; -decode_length(<<0:1,Length:7,T/binary>>) -> - {Length,T}; -decode_length(<<1:1,LL:7,T/binary>>) -> - <> = T, - {Length,Rest}. - - - -%%------------------------------------------------------------------------- -%% INTERNAL HELPER FUNCTIONS (not exported) -%%------------------------------------------------------------------------- - - -%% decoding postitive integer values. -decode_integer2(Len,Bin = <<0:1,_:7,_Bs/binary>>) -> - <> = Bin, - Int; -%% decoding negative integer values. -decode_integer2(Len,<<1:1,B2:7,Bs/binary>>) -> - <> = <>, - Int = N - (1 bsl (8 * Len - 1)), - Int. - -get_constraint(C,Key) -> - case lists:keysearch(Key,1,C) of - false -> - no; - {value,{_,V}} -> - V - end. - -collect_parts(TlvList) -> - collect_parts(TlvList,[]). - -collect_parts([{_,L}|Rest],Acc) when is_list(L) -> - collect_parts(Rest,[collect_parts(L)|Acc]); -collect_parts([{?N_BIT_STRING,<>}|Rest],_Acc) -> - collect_parts_bit(Rest,[Bits],Unused); -collect_parts([{_T,V}|Rest],Acc) -> - collect_parts(Rest,[V|Acc]); -collect_parts([],Acc) -> - list_to_binary(lists:reverse(Acc)). - -collect_parts_bit([{?N_BIT_STRING,<>}|Rest],Acc,Uacc) -> - collect_parts_bit(Rest,[Bits|Acc],Unused+Uacc); -collect_parts_bit([],Acc,Uacc) -> - list_to_binary([Uacc|lists:reverse(Acc)]). - - - - - - - - - - - - - - - - - - - - diff --git a/lib/asn1/src/asn1rt_check.erl b/lib/asn1/src/asn1rt_check.erl deleted file mode 100644 index 35b993fc71..0000000000 --- a/lib/asn1/src/asn1rt_check.erl +++ /dev/null @@ -1,360 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2001-2011. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% --module(asn1rt_check). - --export([check_bool/2, - check_int/3, - check_bitstring/3, - check_octetstring/2, - check_null/2, - check_objectidentifier/2, - check_objectdescriptor/2, - check_real/2, - check_enum/3, - check_restrictedstring/2]). - --export([transform_to_EXTERNAL1990/1, - transform_to_EXTERNAL1994/1]). - --export([dynamicsort_SET_components/1, - dynamicsort_SETOF/1]). - -check_bool(_Bool,asn1_DEFAULT) -> - true; -check_bool(Bool,Bool) when Bool == true; Bool == false -> - true; -check_bool(_Bool1,Bool2) -> - throw({error,Bool2}). - -check_int(_,asn1_DEFAULT,_) -> - true; -check_int(Value,Value,_) when is_integer(Value) -> - true; -check_int(DefValue,Value,NNL) when is_atom(Value) -> - case lists:keysearch(Value,1,NNL) of - {value,{_,DefValue}} -> - true; - _ -> - throw({error,DefValue}) - end; -check_int(DefaultValue,_Value,_) -> - throw({error,DefaultValue}). - -% check_bitstring([H|T],[H|T],_) when is_integer(H) -> -% true; -% check_bitstring(V,V,_) when is_integer(V) -> -% true; -%% Two equal lists or integers -check_bitstring(_,asn1_DEFAULT,_) -> - true; -check_bitstring(V,V,_) -> - true; -%% Default value as a list of 1 and 0 and user value as an integer -check_bitstring(L=[H|T],Int,_) when is_integer(Int),is_integer(H) -> - case bit_list_to_int(L,length(T)) of - Int -> true; - _ -> throw({error,L,Int}) - end; -%% Default value as an integer, val as list -check_bitstring(Int,Val,NBL) when is_integer(Int),is_list(Val) -> - BL = int_to_bit_list(Int,[],length(Val)), - check_bitstring(BL,Val,NBL); -%% Default value and user value as lists of ones and zeros -check_bitstring(L1=[H1|_T1],L2=[H2|_T2],NBL=[_H|_T]) when is_integer(H1),is_integer(H2) -> - L2new = remove_trailing_zeros(L2), - check_bitstring(L1,L2new,NBL); -%% Default value as a list of 1 and 0 and user value as a list of atoms -check_bitstring(L1=[H1|_T1],L2=[H2|_T2],NBL) when is_integer(H1),is_atom(H2) -> - L3 = bit_list_to_nbl(L1,NBL,0,[]), - check_bitstring(L3,L2,NBL); -%% Both default value and user value as a list of atoms -check_bitstring(L1=[H1|T1],L2=[H2|_T2],_) - when is_atom(H1),is_atom(H2),length(L1) == length(L2) -> - case lists:member(H1,L2) of - true -> - check_bitstring1(T1,L2); - false -> throw({error,L2}) - end; -%% Default value as a list of atoms and user value as a list of 1 and 0 -check_bitstring(L1=[H1|_T1],L2=[H2|_T2],NBL) when is_atom(H1),is_integer(H2) -> - L3 = bit_list_to_nbl(L2,NBL,0,[]), - check_bitstring(L1,L3,NBL); -%% User value in compact format -check_bitstring(DefVal,CBS={_,_},NBL) -> - NewVal = cbs_to_bit_list(CBS), - check_bitstring(DefVal,NewVal,NBL); -check_bitstring(DV,V,_) -> - throw({error,DV,V}). - - -bit_list_to_int([0|Bs],ShL)-> - bit_list_to_int(Bs,ShL-1) + 0; -bit_list_to_int([1|Bs],ShL) -> - bit_list_to_int(Bs,ShL-1) + (1 bsl ShL); -bit_list_to_int([],_) -> - 0. - -int_to_bit_list(0,Acc,0) -> - Acc; -int_to_bit_list(Int,Acc,Len) -> - int_to_bit_list(Int bsr 1,[Int band 1|Acc],Len - 1). - -bit_list_to_nbl([0|T],NBL,Pos,Acc) -> - bit_list_to_nbl(T,NBL,Pos+1,Acc); -bit_list_to_nbl([1|T],NBL,Pos,Acc) -> - case lists:keysearch(Pos,2,NBL) of - {value,{N,_}} -> - bit_list_to_nbl(T,NBL,Pos+1,[N|Acc]); - _ -> - throw({error,{no,named,element,at,pos,Pos}}) - end; -bit_list_to_nbl([],_,_,Acc) -> - Acc. - -remove_trailing_zeros(L2) -> - remove_trailing_zeros1(lists:reverse(L2)). -remove_trailing_zeros1(L) -> - lists:reverse(lists:dropwhile(fun(0)->true; - (_) ->false - end, - L)). - -check_bitstring1([H|T],NBL) -> - case lists:member(H,NBL) of - true -> - check_bitstring1(T,NBL); - V -> throw({error,V}) - end; -check_bitstring1([],_) -> - true. - -cbs_to_bit_list({Unused,<>}) when size(Rest) >= 1 -> - [B7,B6,B5,B4,B3,B2,B1,B0|cbs_to_bit_list({Unused,Rest})]; -cbs_to_bit_list({0,<>}) -> - [B7,B6,B5,B4,B3,B2,B1,B0]; -cbs_to_bit_list({Unused,Bin}) when size(Bin) == 1 -> - Used = 8-Unused, - <> = Bin, - int_to_bit_list(Int,[],Used). - - -check_octetstring(_,asn1_DEFAULT) -> - true; -check_octetstring(L,L) -> - true; -check_octetstring(L,Int) when is_list(L),is_integer(Int) -> - case integer_to_octetlist(Int) of - L -> true; - V -> throw({error,V}) - end; -check_octetstring(_,V) -> - throw({error,V}). - -integer_to_octetlist(Int) -> - integer_to_octetlist(Int,[]). -integer_to_octetlist(0,Acc) -> - Acc; -integer_to_octetlist(Int,Acc) -> - integer_to_octetlist(Int bsr 8,[(Int band 255)|Acc]). - -check_null(_,asn1_DEFAULT) -> - true; -check_null('NULL','NULL') -> - true; -check_null(_,V) -> - throw({error,V}). - -check_objectidentifier(_,asn1_DEFAULT) -> - true; -check_objectidentifier(OI,OI) -> - true; -check_objectidentifier(DOI,OI) when is_tuple(DOI),is_tuple(OI) -> - check_objectidentifier1(tuple_to_list(DOI),tuple_to_list(OI)); -check_objectidentifier(_,OI) -> - throw({error,OI}). - -check_objectidentifier1([V|Rest1],[V|Rest2]) -> - check_objectidentifier1(Rest1,Rest2,V); -check_objectidentifier1([V1|Rest1],[V2|Rest2]) -> - case reserved_objectid(V2,[]) of - V1 -> - check_objectidentifier1(Rest1,Rest2,[V1]); - V -> - throw({error,V}) - end. -check_objectidentifier1([V|Rest1],[V|Rest2],Above) -> - check_objectidentifier1(Rest1,Rest2,[V|Above]); -check_objectidentifier1([V1|Rest1],[V2|Rest2],Above) -> - case reserved_objectid(V2,Above) of - V1 -> - check_objectidentifier1(Rest1,Rest2,[V1|Above]); - V -> - throw({error,V}) - end; -check_objectidentifier1([],[],_) -> - true; -check_objectidentifier1(_,V,_) -> - throw({error,object,identifier,V}). - -%% ITU-T Rec. X.680 Annex B - D -reserved_objectid('itu-t',[]) -> 0; -reserved_objectid('ccitt',[]) -> 0; -%% arcs below "itu-t" -reserved_objectid('recommendation',[0]) -> 0; -reserved_objectid('question',[0]) -> 1; -reserved_objectid('administration',[0]) -> 2; -reserved_objectid('network-operator',[0]) -> 3; -reserved_objectid('identified-organization',[0]) -> 4; - -reserved_objectid(iso,[]) -> 1; -%% arcs below "iso", note that number 1 is not used -reserved_objectid('standard',[1]) -> 0; -reserved_objectid('member-body',[1]) -> 2; -reserved_objectid('identified-organization',[1]) -> 3; - -reserved_objectid('joint-iso-itu-t',[]) -> 2; -reserved_objectid('joint-iso-ccitt',[]) -> 2; - -reserved_objectid(_,_) -> false. - - -check_objectdescriptor(_,asn1_DEFAULT) -> - true; -check_objectdescriptor(OD,OD) -> - true; -check_objectdescriptor(OD,OD) -> - throw({error,{not_implemented_yet,check_objectdescriptor}}). - -check_real(_,asn1_DEFAULT) -> - true; -check_real(R,R) -> - true; -check_real(_,_) -> - throw({error,{not_implemented_yet,check_real}}). - -check_enum(_,asn1_DEFAULT,_) -> - true; -check_enum(Val,Val,_) -> - true; -check_enum(Int,Atom,Enumerations) when is_integer(Int),is_atom(Atom) -> - case lists:keysearch(Atom,1,Enumerations) of - {value,{_,Int}} -> true; - _ -> throw({error,{enumerated,Int,Atom}}) - end; -check_enum(DefVal,Val,_) -> - throw({error,{enumerated,DefVal,Val}}). - - -check_restrictedstring(_,asn1_DEFAULT) -> - true; -check_restrictedstring(Val,Val) -> - true; -check_restrictedstring([V|Rest1],[V|Rest2]) -> - check_restrictedstring(Rest1,Rest2); -check_restrictedstring([V1|Rest1],[V2|Rest2]) -> - check_restrictedstring(V1,V2), - check_restrictedstring(Rest1,Rest2); -%% tuple format of value -check_restrictedstring({V1,V2},[V1,V2]) -> - true; -check_restrictedstring([V1,V2],{V1,V2}) -> - true; -%% quadruple format of value -check_restrictedstring({V1,V2,V3,V4},[V1,V2,V3,V4]) -> - true; -check_restrictedstring([V1,V2,V3,V4],{V1,V2,V3,V4}) -> - true; -%% character string list -check_restrictedstring(V1,V2) when is_list(V1),is_tuple(V2) -> - check_restrictedstring(V1,tuple_to_list(V2)); -check_restrictedstring(V1,V2) -> - throw({error,{restricted,string,V1,V2}}). - -transform_to_EXTERNAL1990(Val) when is_tuple(Val),size(Val) == 4 -> - transform_to_EXTERNAL1990(tuple_to_list(Val),[]); -transform_to_EXTERNAL1990(Val) when is_tuple(Val) -> - %% Data already in ASN1 1990 format - Val. - -transform_to_EXTERNAL1990(['EXTERNAL'|Rest],Acc) -> - transform_to_EXTERNAL1990(Rest,['EXTERNAL'|Acc]); -transform_to_EXTERNAL1990([{syntax,Syntax}|Rest],Acc) -> - transform_to_EXTERNAL1990(Rest,[asn1_NOVALUE,Syntax|Acc]); -transform_to_EXTERNAL1990([{'presentation-context-id',PCid}|Rest],Acc) -> - transform_to_EXTERNAL1990(Rest,[PCid,asn1_NOVALUE|Acc]); -transform_to_EXTERNAL1990([{'context-negotiation',Context_negot}|Rest],Acc) -> - {_,Presentation_Cid,Transfer_syntax} = Context_negot, - transform_to_EXTERNAL1990(Rest,[Presentation_Cid,Transfer_syntax|Acc]); -transform_to_EXTERNAL1990([asn1_NOVALUE|Rest],Acc) -> - transform_to_EXTERNAL1990(Rest,[asn1_NOVALUE|Acc]); -transform_to_EXTERNAL1990([Data_val_desc,Data_value],Acc) when is_list(Data_value)-> - list_to_tuple(lists:reverse([{'octet-aligned',Data_value}, - Data_val_desc|Acc])); -transform_to_EXTERNAL1990([Data_val_desc,Data_value],Acc) - when is_binary(Data_value)-> - list_to_tuple(lists:reverse([{'single-ASN1-type',Data_value}, - Data_val_desc|Acc])); -transform_to_EXTERNAL1990([Data_value],Acc) - when is_list(Data_value); is_binary(Data_value) -> - list_to_tuple(lists:reverse([{'octet-aligned',Data_value}|Acc])). - - -transform_to_EXTERNAL1994(V={'EXTERNAL',DRef,IndRef,Data_v_desc,Encoding}) -> - Identification = - case {DRef,IndRef} of - {DRef,asn1_NOVALUE} -> - {syntax,DRef}; - {asn1_NOVALUE,IndRef} -> - {'presentation-context-id',IndRef}; - _ -> - {'context-negotiation', - {'EXTERNAL_identification_context-negotiation',IndRef,DRef}} - end, - case Encoding of - {_,Val} when is_list(Val);is_binary(Val) -> - {'EXTERNAL',Identification,Data_v_desc,Val}; - - _ -> - V - end. - - -%% dynamicsort_SET_components(Arg) -> -%% Res Arg -> list() -%% Res -> list() -%% Sorts the elements in Arg according to the encoded tag in -%% increasing order. -dynamicsort_SET_components(ListOfEncCs) -> - BinL = lists:map(fun(X) -> list_to_binary(X) end,ListOfEncCs), - TagBinL = lists:map(fun(X) -> - {{T,_,TN},_,_} = asn1rt_ber_bin:decode_tag(X), - {{T,TN},X} - end,BinL), - ClassTagNoSorted = lists:keysort(1,TagBinL), - lists:map(fun({_,El}) -> El end,ClassTagNoSorted). - -%% dynamicsort_SETOF(Arg) -> Res -%% Arg -> list() -%% Res -> list() -%% Sorts the elements in Arg in increasing size -dynamicsort_SETOF(ListOfEncVal) -> - BinL = lists:map(fun(L) when is_list(L) -> list_to_binary(L); - (B) -> B end,ListOfEncVal), - lists:sort(BinL). diff --git a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl deleted file mode 100644 index 5997232f13..0000000000 --- a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl +++ /dev/null @@ -1,1587 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2002-2012. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% --module(asn1rt_per_bin_rt2ct). -%% encoding / decoding of PER aligned - --include("asn1_records.hrl"). - --export([decode_fragmented/3]). --export([setchoiceext/1, setext/1, fixoptionals/3, fixextensions/2, - skipextensions/3, getbit/1, getchoice/3 ]). --export([set_choice/3, encode_integer/2, encode_integer/3 ]). --export([encode_small_number/1, - encode_length/2, - encode_small_length/1, - decode_compact_bit_string/3]). --export([encode_bit_string/3, decode_bit_string/3 ]). --export([encode_octet_string/2, - encode_object_identifier/1, decode_object_identifier/1, - encode_real/1, decode_real/1, - encode_relative_oid/1, decode_relative_oid/1, - complete/1]). - --export([encode_open_type/2, decode_open_type/2]). - --export([encode_GeneralString/2, decode_GeneralString/2, - encode_GraphicString/2, decode_GraphicString/2, - encode_TeletexString/2, decode_TeletexString/2, - encode_VideotexString/2, decode_VideotexString/2, - encode_ObjectDescriptor/2, decode_ObjectDescriptor/1, - encode_UTF8String/1,decode_UTF8String/1 - ]). - --export([encode_unconstrained_number/1, - encode_octet_string/3, - encode_known_multiplier_string/5, - decode_known_multiplier_string/5]). - - --export([eint_positive/1]). --export([pre_complete_bits/2]). - --define('16K',16384). --define('32K',32768). --define('64K',65536). - -%%-------------------------------------------------------- -%% setchoiceext(InRootSet) -> [{bit,X}] -%% X is set to 1 when InRootSet==false -%% X is set to 0 when InRootSet==true -%% -setchoiceext(true) -> - [0]; -setchoiceext(false) -> - [1]. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% setext(true|false) -> CompleteList -%% - -setext(false) -> -% [{debug,ext},{bits,1,0}]; - [0]; -setext(true) -> -% [{debug,ext},{bits,1,1}]; - [1]. - -fixoptionals(OptList,_OptLength,Val) when is_tuple(Val) -> -% Bits = fixoptionals(OptList,Val,0), -% {Val,{bits,OptLength,Bits}}; -% {Val,[10,OptLength,Bits]}; - {Val,fixoptionals(OptList,Val,[])}; - -fixoptionals([],_,Acc) -> - %% Optbits - lists:reverse(Acc); -fixoptionals([{Pos,DefVal}|Ot],Val,Acc) -> - case element(Pos,Val) of - asn1_DEFAULT -> fixoptionals(Ot,Val,[0|Acc]); - DefVal -> fixoptionals(Ot,Val,[0|Acc]); - _ -> fixoptionals(Ot,Val,[1|Acc]) - end; -fixoptionals([Pos|Ot],Val,Acc) -> - case element(Pos,Val) of - asn1_NOVALUE -> fixoptionals(Ot,Val,[0|Acc]); - asn1_DEFAULT -> fixoptionals(Ot,Val,[0|Acc]); - _ -> fixoptionals(Ot,Val,[1|Acc]) - end. - - -fixextensions({ext,ExtPos,ExtNum},Val) -> - case fixextensions(ExtPos,ExtNum+ExtPos,Val,0) of - 0 -> []; - ExtBits -> - [encode_small_length(ExtNum),pre_complete_bits(ExtNum,ExtBits)] - end. - -fixextensions(Pos,MaxPos,_,Acc) when Pos >= MaxPos -> - Acc; -fixextensions(Pos,ExtPos,Val,Acc) -> - Bit = case catch(element(Pos+1,Val)) of - asn1_NOVALUE -> - 0; - asn1_NOEXTVALUE -> - 0; - {'EXIT',_} -> - 0; - _ -> - 1 - end, - fixextensions(Pos+1,ExtPos,Val,(Acc bsl 1)+Bit). - -skipextensions(Bytes,Nr,ExtensionBitstr) when is_bitstring(ExtensionBitstr) -> - Prev = Nr - 1, - case ExtensionBitstr of - <<_:Prev,1:1,_/bitstring>> -> - {_,Bytes2} = decode_open_type(Bytes,[]), - skipextensions(Bytes2, Nr+1, ExtensionBitstr); - <<_:Prev,0:1,_/bitstring>> -> - skipextensions(Bytes, Nr+1, ExtensionBitstr); - _ -> - Bytes - end. - - -getchoice(Bytes,1,0) -> % only 1 alternative is not encoded - {0,Bytes}; -getchoice(Bytes,_,1) -> - decode_small_number(Bytes); -getchoice(Bytes,NumChoices,0) -> - decode_constrained_number(Bytes,{0,NumChoices-1}). - - -%% getbits_as_binary(Num,Bytes) -> {Bin,Rest} -%% Num = integer(), -%% Bytes = bitstring(), -%% Bin = bitstring(), -%% Rest = bitstring() -getbits_as_binary(Num,Bytes) when is_bitstring(Bytes) -> - <> = Bytes, - {BS,Rest}. - -getbits_as_list(Num,Bytes) when is_bitstring(Bytes) -> - <> = Bytes, - {[ B || <> <= BitStr],Rest}. - - -getbit(Buffer) -> - <> = Buffer, - {B,Rest}. - - -getbits(Buffer,Num) when is_bitstring(Buffer) -> - <> = Buffer, - {Bs,Rest}. - -align(Bin) when is_binary(Bin) -> - Bin; -align(BitStr) when is_bitstring(BitStr) -> - AlignBits = bit_size(BitStr) rem 8, - <<_:AlignBits,Rest/binary>> = BitStr, - Rest. - - -%% First align buffer, then pick the first Num octets. -%% Returns octets as an integer with bit significance as in buffer. -getoctets(Buffer,Num) when is_binary(Buffer) -> - <> = Buffer, - {Val,RestBin}; -getoctets(Buffer,Num) when is_bitstring(Buffer) -> - AlignBits = bit_size(Buffer) rem 8, - <<_:AlignBits,Val:Num/integer-unit:8,RestBin/binary>> = Buffer, - {Val,RestBin}. - - -%% First align buffer, then pick the first Num octets. -%% Returns octets as a binary -getoctets_as_bin(Bin,Num) when is_binary(Bin) -> - <> = Bin, - {Octets,RestBin}; -getoctets_as_bin(Bin,Num) when is_bitstring(Bin) -> - AlignBits = bit_size(Bin) rem 8, - <<_:AlignBits,Val:Num/binary,RestBin/binary>> = Bin, - {Val,RestBin}. - - -%% same as above but returns octets as a List -getoctets_as_list(Buffer,Num) -> - {Bin,Buffer2} = getoctets_as_bin(Buffer,Num), - {binary_to_list(Bin),Buffer2}. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% set_choice(Alt,Choices,Altnum) -> ListofBitSettings -%% Alt = atom() -%% Altnum = integer() | {integer(),integer()}% number of alternatives -%% Choices = [atom()] | {[atom()],[atom()]} -%% When Choices is a tuple the first list is the Rootset and the -%% second is the Extensions and then Altnum must also be a tuple with the -%% lengths of the 2 lists -%% -set_choice(Alt,{L1,L2},{Len1,_Len2}) -> - case set_choice_tag(Alt,L1) of - N when is_integer(N), Len1 > 1 -> -% [{bits,1,0}, % the value is in the root set -% encode_constrained_number({0,Len1-1},N)]; - [0, % the value is in the root set - encode_constrained_number({0,Len1-1},N)]; - N when is_integer(N) -> -% [{bits,1,0}]; % no encoding if only 0 or 1 alternative - [0]; % no encoding if only 0 or 1 alternative - false -> -% [{bits,1,1}, % extension value - [1, % extension value - case set_choice_tag(Alt,L2) of - N2 when is_integer(N2) -> - encode_small_number(N2); - false -> - unknown_choice_alt - end] - end; -set_choice(Alt,L,Len) -> - case set_choice_tag(Alt,L) of - N when is_integer(N), Len > 1 -> - encode_constrained_number({0,Len-1},N); - N when is_integer(N) -> - []; % no encoding if only 0 or 1 alternative - false -> - [unknown_choice_alt] - end. - -set_choice_tag(Alt,Choices) -> - set_choice_tag(Alt,Choices,0). - -set_choice_tag(Alt,[Alt|_Rest],Tag) -> - Tag; -set_choice_tag(Alt,[_H|Rest],Tag) -> - set_choice_tag(Alt,Rest,Tag+1); -set_choice_tag(_Alt,[],_Tag) -> - false. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_fragmented_XXX; decode of values encoded fragmented according -%% to ITU-T X.691 clause 10.9.3.8. The unit (XXX) is either bits, octets, -%% characters or number of components (in a choice,sequence or similar). -%% Buffer is a buffer binary(). -%% C is the constrained length. -%% If the buffer is not aligned, this function does that. -decode_fragmented_bits(Buffer,C) when is_binary(Buffer) -> - decode_fragmented_bits(Buffer,C,[]); -decode_fragmented_bits(Buffer,C) when is_bitstring(Buffer) -> - AlignBits = bit_size(Buffer) rem 8, - <<_:AlignBits,Rest/binary>> = Buffer, - decode_fragmented_bits(Rest,C,[]). - -decode_fragmented_bits(<<3:2,Len:6,Bin/binary>>,C,Acc) -> - {Value,Bin2} = split_binary(Bin, Len * ?'16K'), % Len = 1 | 2 | 3 | 4 - decode_fragmented_bits(Bin2,C,[Value|Acc]); -decode_fragmented_bits(<<0:1,0:7,Bin/binary>>,C,Acc) -> - BinBits = erlang:list_to_bitstring(lists:reverse(Acc)), - case C of - Int when is_integer(Int),C == bit_size(BinBits) -> - {BinBits,Bin}; - Int when is_integer(Int) -> - exit({error,{asn1,{illegal_value,C,BinBits}}}) - end; -decode_fragmented_bits(<<0:1,Len:7,Bin/binary>>,C,Acc) -> - <> = Bin, - BinBits = erlang:list_to_bitstring([Value|Acc]), - case C of - Int when is_integer(Int),C == bit_size(BinBits) -> - {BinBits,Rest}; - Int when is_integer(Int) -> - exit({error,{asn1,{illegal_value,C,BinBits}}}) - end. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% encode_open_type(Constraint, Value) -> CompleteList -%% Value = list of bytes of an already encoded value (the list must be flat) -%% | binary -%% Contraint = not used in this version -%% -encode_open_type(_Constraint, Val) when is_list(Val) -> - Bin = list_to_binary(Val), - case size(Bin) of - Size when Size>255 -> - [encode_length(undefined,Size),[21,<>,Bin]]; - Size -> - [encode_length(undefined,Size),[20,Size,Bin]] - end; -encode_open_type(_Constraint, Val) when is_binary(Val) -> - case size(Val) of - Size when Size>255 -> - [encode_length(undefined,size(Val)),[21,<>,Val]]; % octets implies align - Size -> - [encode_length(undefined,Size),[20,Size,Val]] - end. -%% the binary_to_list is not optimal but compatible with the current solution - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_open_type(Buffer,Constraint) -> Value -%% Constraint is not used in this version -%% Buffer = [byte] with PER encoded data -%% Value = [byte] with decoded data (which must be decoded again as some type) -%% -decode_open_type(Bytes, _Constraint) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - getoctets_as_bin(Bytes2,Len). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% encode_integer(Constraint,Value,NamedNumberList) -> CompleteList -%% encode_integer(Constraint,Value) -> CompleteList -%% encode_integer(Constraint,{Name,Value}) -> CompleteList -%% -%% -encode_integer(C,V,NamedNumberList) when is_atom(V) -> - case lists:keysearch(V,1,NamedNumberList) of - {value,{_,NewV}} -> - encode_integer(C,NewV); - _ -> - exit({error,{asn1,{namednumber,V}}}) - end; -encode_integer(C,V,_NamedNumberList) when is_integer(V) -> - encode_integer(C,V); -encode_integer(C,{Name,V},NamedNumberList) when is_atom(Name) -> - encode_integer(C,V,NamedNumberList). - -encode_integer(C,{Name,Val}) when is_atom(Name) -> - encode_integer(C,Val); - -encode_integer([{Rc,_Ec}],Val) when is_tuple(Rc) -> % XXX when is this invoked? First argument most often a list,...Ok this is the extension case...but it doesn't work. - case (catch encode_integer([Rc],Val)) of - {'EXIT',{error,{asn1,_}}} -> -% [{bits,1,1},encode_unconstrained_number(Val)]; - [1,encode_unconstrained_number(Val)]; - Encoded -> -% [{bits,1,0},Encoded] - [0,Encoded] - end; - -encode_integer([],Val) -> - encode_unconstrained_number(Val); -%% The constraint is the effective constraint, and in this case is a number -encode_integer([{'SingleValue',V}],V) -> - []; -encode_integer([{'ValueRange',VR={Lb,Ub},Range,PreEnc}],Val) when Val >= Lb, - Ub >= Val -> - %% this case when NamedNumberList - encode_constrained_number(VR,Range,PreEnc,Val); -encode_integer([{'ValueRange',{Lb,'MAX'}}],Val) -> - encode_semi_constrained_number(Lb,Val); -encode_integer([{'ValueRange',{'MIN',_}}],Val) -> - encode_unconstrained_number(Val); -encode_integer([{'ValueRange',VR={_Lb,_Ub}}],Val) -> - encode_constrained_number(VR,Val); -encode_integer(_,Val) -> - exit({error,{asn1,{illegal_value,Val}}}). - - -%% X.691:10.6 Encoding of a normally small non-negative whole number -%% Use this for encoding of CHOICE index if there is an extension marker in -%% the CHOICE -encode_small_number({Name,Val}) when is_atom(Name) -> - encode_small_number(Val); -encode_small_number(Val) when Val =< 63 -> -% [{bits,1,0},{bits,6,Val}]; -% [{bits,7,Val}]; % same as above but more efficient - [10,7,Val]; % same as above but more efficient -encode_small_number(Val) -> -% [{bits,1,1},encode_semi_constrained_number(0,Val)]. - [1,encode_semi_constrained_number(0,Val)]. - -decode_small_number(Bytes) -> - {Bit,Bytes2} = getbit(Bytes), - case Bit of - 0 -> - getbits(Bytes2,6); - 1 -> - decode_semi_constrained_number(Bytes2) - end. - -%% X.691:10.7 Encoding of a semi-constrained whole number -%% might be an optimization encode_semi_constrained_number(0,Val) -> -encode_semi_constrained_number(C,{Name,Val}) when is_atom(Name) -> - encode_semi_constrained_number(C,Val); -encode_semi_constrained_number({Lb,'MAX'},Val) -> - encode_semi_constrained_number(Lb,Val); -encode_semi_constrained_number(Lb,Val) -> - Val2 = Val - Lb, - Oct = eint_positive(Val2), - Len = length(Oct), - if - Len < 128 -> - %{octets,[Len|Oct]}; % equiv with encode_length(undefined,Len) but faster - [20,Len+1,[Len|Oct]]; - Len < 256 -> - [encode_length(undefined,Len),[20,Len,Oct]]; - true -> - [encode_length(undefined,Len),[21,<>,Oct]] - end. - -decode_semi_constrained_number(Bytes) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - {V,Bytes3} = getoctets(Bytes2,Len), - {V,Bytes3}. - -encode_constrained_number({Lb,_Ub},_Range,{bits,N},Val) -> - Val2 = Val-Lb, -% {bits,N,Val2}; - [10,N,Val2]; -encode_constrained_number({Lb,_Ub},_Range,{octets,N},Val) when N < 256-> - %% N is 8 or 16 (1 or 2 octets) - Val2 = Val-Lb, -% {octets,<>}; - [20,N,Val2]; -encode_constrained_number({Lb,_Ub},_Range,{octets,N},Val) -> % N>255 - %% N is 8 or 16 (1 or 2 octets) - Val2 = Val-Lb, -% {octets,<>}; - [21,<>,Val2]; -encode_constrained_number({Lb,_Ub},Range,_,Val) -> - Val2 = Val-Lb, - if - Range =< 16#1000000 -> % max 3 octets - Octs = eint_positive(Val2), -% [encode_length({1,3},size(Octs)),{octets,Octs}]; - L = length(Octs), - [encode_length({1,3},L),[20,L,Octs]]; - Range =< 16#100000000 -> % max 4 octets - Octs = eint_positive(Val2), -% [encode_length({1,4},size(Octs)),{octets,Octs}]; - L = length(Octs), - [encode_length({1,4},L),[20,L,Octs]]; - Range =< 16#10000000000 -> % max 5 octets - Octs = eint_positive(Val2), -% [encode_length({1,5},size(Octs)),{octets,Octs}]; - L = length(Octs), - [encode_length({1,5},L),[20,L,Octs]]; - true -> - exit({not_supported,{integer_range,Range}}) - end. - -encode_constrained_number(Range,{Name,Val}) when is_atom(Name) -> - encode_constrained_number(Range,Val); -encode_constrained_number({Lb,Ub},Val) when Val >= Lb, Ub >= Val -> - Range = Ub - Lb + 1, - Val2 = Val - Lb, - if - Range == 1 -> []; - Range == 2 -> -% Size = {bits,1,Val2}; - [Val2]; - Range =< 4 -> -% Size = {bits,2,Val2}; - [10,2,Val2]; - Range =< 8 -> - [10,3,Val2]; - Range =< 16 -> - [10,4,Val2]; - Range =< 32 -> - [10,5,Val2]; - Range =< 64 -> - [10,6,Val2]; - Range =< 128 -> - [10,7,Val2]; - Range =< 255 -> - [10,8,Val2]; - Range =< 256 -> -% Size = {octets,[Val2]}; - [20,1,Val2]; - Range =< 65536 -> -% Size = {octets,<>}; - [20,2,<>]; - Range =< (1 bsl (255*8)) -> - Octs = binary:encode_unsigned(Val2), - RangeOcts = binary:encode_unsigned(Range - 1), - OctsLen = erlang:byte_size(Octs), - RangeOctsLen = erlang:byte_size(RangeOcts), - LengthBitsNeeded = minimum_bits(RangeOctsLen - 1), - [10,LengthBitsNeeded,OctsLen-1,20,OctsLen,Octs]; - true -> - exit({not_supported,{integer_range,Range}}) - end; -encode_constrained_number({_,_},Val) -> - exit({error,{asn1,{illegal_value,Val}}}). - -decode_constrained_number(Buffer,VR={Lb,Ub}) -> - Range = Ub - Lb + 1, - decode_constrained_number(Buffer,VR,Range). - -decode_constrained_number(Buffer,{Lb,_Ub},Range) -> - % Val2 = Val - Lb, - {Val,Remain} = - if - Range == 1 -> - {0,Buffer}; - Range == 2 -> - getbits(Buffer,1); - Range =< 4 -> - getbits(Buffer,2); - Range =< 8 -> - getbits(Buffer,3); - Range =< 16 -> - getbits(Buffer,4); - Range =< 32 -> - getbits(Buffer,5); - Range =< 64 -> - getbits(Buffer,6); - Range =< 128 -> - getbits(Buffer,7); - Range =< 255 -> - getbits(Buffer,8); - Range =< 256 -> - getoctets(Buffer,1); - Range =< 65536 -> - getoctets(Buffer,2); - Range =< (1 bsl (255*8)) -> - OList = binary:bin_to_list(binary:encode_unsigned(Range - 1)), - RangeOctLen = length(OList), - {Len, Bytes} = decode_length(Buffer, {1, RangeOctLen}), - {Octs, RestBytes} = getoctets_as_bin(Bytes, Len), - {binary:decode_unsigned(Octs), RestBytes}; - true -> - exit({not_supported,{integer_range,Range}}) - end, - {Val+Lb,Remain}. - -%% For some reason the minimum bits needed in the length field in -%% the encoding of constrained whole numbers must always be at least 2? -minimum_bits(N) when N < 4 -> 2; -minimum_bits(N) when N < 8 -> 3; -minimum_bits(N) when N < 16 -> 4; -minimum_bits(N) when N < 32 -> 5; -minimum_bits(N) when N < 64 -> 6; -minimum_bits(N) when N < 128 -> 7; -minimum_bits(_N) -> 8. - -%% X.691:10.8 Encoding of an unconstrained whole number - -encode_unconstrained_number(Val) when Val >= 0 -> - Oct = eint(Val,[]), - Len = length(Oct), - if - Len < 128 -> - %{octets,[Len|Oct]}; % equiv with encode_length(undefined,Len) but faster - [20,Len+1,[Len|Oct]]; - Len < 256 -> -% [encode_length(undefined,Len),20,Len,Oct]; - [20,Len+2,<<2:2,Len:14>>,Oct];% equiv with encode_length(undefined,Len) but faster - true -> -% [encode_length(undefined,Len),{octets,Oct}] - [encode_length(undefined,Len),[21,<>,Oct]] - end; -encode_unconstrained_number(Val) -> % negative - Oct = enint(Val,[]), - Len = length(Oct), - if - Len < 128 -> -% {octets,[Len|Oct]}; % equiv with encode_length(undefined,Len) but faster - [20,Len+1,[Len|Oct]];% equiv with encode_length(undefined,Len) but faster - Len < 256 -> -% [encode_length(undefined,Len),20,Len,Oct]; - [20,Len+2,<<2:2,Len:14>>,Oct];% equiv with encode_length(undefined,Len) but faster - true -> - %[encode_length(undefined,Len),{octets,Oct}] - [encode_length(undefined,Len),[21,<>,Oct]] - end. - - -%% used for positive Values which don't need a sign bit -%% returns a list -eint_positive(Val) -> - case eint(Val,[]) of - [0,B1|T] -> - [B1|T]; - T -> - T - end. - - -eint(0, [B|Acc]) when B < 128 -> - [B|Acc]; -eint(N, Acc) -> - eint(N bsr 8, [N band 16#ff| Acc]). - -enint(-1, [B1|T]) when B1 > 127 -> - [B1|T]; -enint(N, Acc) -> - enint(N bsr 8, [N band 16#ff|Acc]). - -%% X.691:10.9 Encoding of a length determinant -%%encode_small_length(undefined,Len) -> % null means no UpperBound -%% encode_small_number(Len). - -%% X.691:10.9.3.5 -%% X.691:10.9.3.7 -encode_length(undefined,Len) -> % un-constrained - if - Len < 128 -> -% {octets,[Len]}; - [20,1,Len]; - Len < 16384 -> - %{octets,<<2:2,Len:14>>}; - [20,2,<<2:2,Len:14>>]; - true -> % should be able to endode length >= 16384 i.e. fragmented length - exit({error,{asn1,{encode_length,{nyi,above_16k}}}}) - end; - -encode_length({0,'MAX'},Len) -> - encode_length(undefined,Len); -encode_length(Vr={Lb,Ub},Len) when Ub =< 65535 ,Lb >= 0 -> % constrained - encode_constrained_number(Vr,Len); -encode_length({Lb,_Ub},Len) when is_integer(Lb), Lb >= 0 -> % Ub > 65535 - encode_length(undefined,Len); -encode_length({Vr={Lb,Ub},Ext},Len) - when Ub =< 65535 ,Lb >= 0,Len= - %% constrained extensible - [0,encode_constrained_number(Vr,Len)]; -encode_length({{Lb,_},Ext},Len) when is_list(Ext) -> - [1,encode_semi_constrained_number(Lb,Len)]; -encode_length(SingleValue,_Len) when is_integer(SingleValue) -> - []. - -%% X.691 10.9.3.4 (only used for length of bitmap that prefixes extension -%% additions in a sequence or set -encode_small_length(Len) when Len =< 64 -> -%% [{bits,1,0},{bits,6,Len-1}]; -% {bits,7,Len-1}; % the same as above but more efficient - [10,7,Len-1]; -encode_small_length(Len) -> -% [{bits,1,1},encode_length(undefined,Len)]. - [1,encode_length(undefined,Len)]. - - -decode_length(Buffer,undefined) -> % un-constrained - case align(Buffer) of - <<0:1,Oct:7,Rest/binary>> -> - {Oct,Rest}; - <<2:2,Val:14,Rest/binary>> -> - {Val,Rest}; - <<3:2,_Val:14,_Rest/binary>> -> - %% this case should be fixed - exit({error,{asn1,{decode_length,{nyi,above_16k}}}}) - end; - -decode_length(Buffer,{Lb,Ub}) when Ub =< 65535 ,Lb >= 0 -> % constrained - decode_constrained_number(Buffer,{Lb,Ub}); -decode_length(Buffer,{Lb,_Ub}) when is_integer(Lb), Lb >= 0 -> % Ub > 65535 - decode_length(Buffer,undefined); -decode_length(Buffer,{{Lb,Ub},Ext}) when is_list(Ext) -> - case getbit(Buffer) of - {0,Buffer2} -> - decode_length(Buffer2, {Lb,Ub}); - {1,Buffer2} -> - decode_length(Buffer2, undefined) - end; - - -%When does this case occur with {_,_Lb,Ub} ?? -% X.691:10.9.3.5 -decode_length(Bin,{_,_Lb,_Ub}) -> % Unconstrained or large Ub NOTE! this case does not cover case when Ub > 65535 - case Bin of - <<0:1,Val:7,Rest/bitstring>> -> - {Val,Rest}; - _ -> - case align(Bin) of - <<2:2,Val:14,Rest/binary>> -> - {Val,Rest}; - <<3:2,_:14,_Rest/binary>> -> - exit({error,{asn1,{decode_length,{nyi,length_above_64K}}}}) - end - end; -decode_length(Buffer,SingleValue) when is_integer(SingleValue) -> - {SingleValue,Buffer}. - - - -%%=============================================================================== -%%=============================================================================== -%%=============================================================================== -%% Bitstring value, ITU_T X.690 Chapter 8.5 -%%=============================================================================== -%%=============================================================================== -%%=============================================================================== - -%%=============================================================================== -%% encode bitstring value -%%=============================================================================== - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% bitstring NamedBitList -%% Val can be of: -%% - [identifiers] where only named identifers are set to one, -%% the Constraint must then have some information of the -%% bitlength. -%% - [list of ones and zeroes] all bits -%% - integer value representing the bitlist -%% C is constraint Len, only valid when identifiers - - -%% when the value is a list of {Unused,BinBits}, where -%% Unused = integer(), -%% BinBits = binary(). - -encode_bit_string(C,Bin={Unused,BinBits},NamedBitList) when is_integer(Unused), - is_binary(BinBits) -> - encode_bin_bit_string(C,Bin,NamedBitList); - -%% when the value is a list of named bits - -encode_bit_string(C, LoNB=[FirstVal | _RestVal], NamedBitList) when is_atom(FirstVal) -> - ToSetPos = get_all_bitposes(LoNB, NamedBitList, []), - BitList = make_and_set_list(ToSetPos,0), - encode_bit_string(C,BitList,NamedBitList);% consider the constraint - -encode_bit_string(C, BL=[{bit,_} | _RestVal], NamedBitList) -> - ToSetPos = get_all_bitposes(BL, NamedBitList, []), - BitList = make_and_set_list(ToSetPos,0), - encode_bit_string(C,BitList,NamedBitList); - -%% when the value is a list of ones and zeroes -encode_bit_string(Int, BitListValue, _) - when is_list(BitListValue),is_integer(Int),Int =< 16 -> - %% The type is constrained by a single value size constraint - %% range_check(Int,length(BitListValue)), - [40,Int,length(BitListValue),BitListValue]; -encode_bit_string(Int, BitListValue, _) - when is_list(BitListValue),is_integer(Int), Int =< 255 -> - %% The type is constrained by a single value size constraint - %% range_check(Int,length(BitListValue)), - [2,40,Int,length(BitListValue),BitListValue]; -encode_bit_string(Int, BitListValue, _) - when is_list(BitListValue),is_integer(Int), Int < ?'64K' -> - {Code,DesiredLength,Length} = - case length(BitListValue) of - B1 when B1 > Int -> - exit({error,{'BIT_STRING_length_greater_than_SIZE', - Int,BitListValue}}); - B1 when B1 =< 255,Int =< 255 -> - {40,Int,B1}; - B1 when B1 =< 255 -> - {42,<>,B1}; - B1 -> - {43,<>,<>} - end, - %% The type is constrained by a single value size constraint - [2,Code,DesiredLength,Length,BitListValue]; -encode_bit_string(no, BitListValue,[]) - when is_list(BitListValue) -> - [encode_length(undefined,length(BitListValue)), - 2,BitListValue]; -encode_bit_string({{Fix,Fix},Ext}, BitListValue,[]) - when is_integer(Fix), is_list(Ext) -> - case length(BitListValue) of - Len when Len =< Fix -> - [0,encode_bit_string(Fix,BitListValue,[])]; - _ -> - [1,encode_bit_string(no,BitListValue,[])] - end; -encode_bit_string(C, BitListValue,[]) - when is_list(BitListValue) -> - [encode_length(C,length(BitListValue)), - 2,BitListValue]; -encode_bit_string(no, BitListValue,_NamedBitList) - when is_list(BitListValue) -> - %% this case with an unconstrained BIT STRING can be made more efficient - %% if the complete driver can take a special code so the length field - %% is encoded there. - NewBitLVal = lists:reverse(lists:dropwhile(fun(0)->true;(1)->false end, - lists:reverse(BitListValue))), - [encode_length(undefined,length(NewBitLVal)), - 2,NewBitLVal]; -encode_bit_string({{Fix,Fix},Ext}, BitListValue,_NamedBitList) - when is_integer(Fix), is_list(Ext) -> - case length(BitListValue) of - Len when Len =< Fix -> - [0,encode_bit_string(Fix,BitListValue,_NamedBitList)]; - _ -> - [1,encode_bit_string(no,BitListValue,_NamedBitList)] - end; -encode_bit_string(C,BitListValue,_NamedBitList) - when is_list(BitListValue) ->% C = {_,'MAX'} -% NewBitLVal = lists:reverse(lists:dropwhile(fun(0)->true;(1)->false end, -% lists:reverse(BitListValue))), - NewBitLVal = bit_string_trailing_zeros(BitListValue,C), - [encode_length(C,length(NewBitLVal)), - 2,NewBitLVal]; - - -%% when the value is an integer -encode_bit_string(C, IntegerVal, NamedBitList) when is_integer(IntegerVal)-> - BitList = int_to_bitlist(IntegerVal), - encode_bit_string(C,BitList,NamedBitList); - -%% when the value is a tuple -encode_bit_string(C,{Name,Val}, NamedBitList) when is_atom(Name) -> - encode_bit_string(C,Val,NamedBitList). - -bit_string_trailing_zeros(BitList,C) when is_integer(C) -> - bit_string_trailing_zeros1(BitList,C,C); -bit_string_trailing_zeros(BitList,{Lb,Ub}) when is_integer(Lb) -> - bit_string_trailing_zeros1(BitList,Lb,Ub); -bit_string_trailing_zeros(BitList,{{Lb,Ub},_}) when is_integer(Lb) -> - bit_string_trailing_zeros1(BitList,Lb,Ub); -bit_string_trailing_zeros(BitList,_) -> - BitList. - -bit_string_trailing_zeros1(BitList,Lb,Ub) -> - case length(BitList) of - Lb -> BitList; - B when B BitList++lists:duplicate(Lb-B,0); - D -> F = fun(L,LB,LB,_,_)->lists:reverse(L); - ([0|R],L1,LB,UB,Fun)->Fun(R,L1-1,LB,UB,Fun); - (L,L1,_,UB,_)when L1 =< UB -> lists:reverse(L); - (_,_L1,_,_,_) ->exit({error,{list_length_BIT_STRING, - BitList}}) end, - F(lists:reverse(BitList),D,Lb,Ub,F) - end. - -%% encode_bin_bit_string/3, when value is a tuple of Unused and BinBits. -%% Unused = integer(),i.e. number unused bits in least sign. byte of -%% BinBits = binary(). -encode_bin_bit_string(C,{Unused,BinBits},_NamedBitList) - when is_integer(C),C=<16 -> - range_check(C,bit_size(BinBits) - Unused), - [45,C,size(BinBits),BinBits]; -encode_bin_bit_string(C,{Unused,BinBits},_NamedBitList) - when is_integer(C), C =< 255 -> - range_check(C,bit_size(BinBits) - Unused), - [2,45,C,size(BinBits),BinBits]; -encode_bin_bit_string(C,{Unused,BinBits},_NamedBitList) - when is_integer(C), C =< 65535 -> - range_check(C,bit_size(BinBits) - Unused), - case size(BinBits) of - Size when Size =< 255 -> - [2,46,<>,Size,BinBits]; - Size -> - [2,47,<>,<>,BinBits] - end; -%% encode_bin_bit_string(C,{_Unused,BinBits},_NamedBitList) -%% when is_integer(C) -> -%% exit({error,{asn1, {bitstring_size, not_supported, C}}}); -encode_bin_bit_string(C,UnusedAndBin={_,_},NamedBitList) -> -% UnusedAndBin1 = {Unused1,Bin1} = - {Unused1,Bin1} = - %% removes all trailing bits if NamedBitList is not empty - remove_trailing_bin(NamedBitList,UnusedAndBin), - case C of - {Lb,Ub} when is_integer(Lb),is_integer(Ub) -> -% [encode_length({Lb,Ub},size(Bin1)*8 - Unused1), -% align,UnusedAndBin1]; - Size=size(Bin1), - [encode_length({Lb,Ub},Size*8 - Unused1), - 2,octets_unused_to_complete(Unused1,Size,Bin1)]; - no -> - Size=size(Bin1), - [encode_length(undefined,Size*8 - Unused1), - 2,octets_unused_to_complete(Unused1,Size,Bin1)]; - {{Fix,Fix},Ext} when is_integer(Fix),is_list(Ext) -> - %%[encode_length(Sc,size(Bin1)*8 - Unused1), - case size(Bin1)*8 - Unused1 of - Size when Size =< Fix -> - [0,encode_bin_bit_string(Fix,UnusedAndBin,NamedBitList)]; - _Size -> - [1,encode_bin_bit_string(no,UnusedAndBin,NamedBitList)] - end; - Sc -> - Size=size(Bin1), - [encode_length(Sc,Size*8 - Unused1), - 2,octets_unused_to_complete(Unused1,Size,Bin1)] - end. - -range_check(C,C) when is_integer(C) -> - ok; -range_check(C1,C2) when is_integer(C1) -> - exit({error,{asn1,{bit_string_out_of_range,{C1,C2}}}}). - -remove_trailing_bin([], {Unused,Bin}) -> - {Unused,Bin}; -remove_trailing_bin(_NamedNumberList,{_Unused,<<>>}) -> - {0,<<>>}; -remove_trailing_bin(NamedNumberList, {_Unused,Bin}) -> - Size = size(Bin)-1, - <> = Bin, - %% clear the Unused bits to be sure -% LastByte1 = LastByte band (((1 bsl Unused) -1) bxor 255),% why this??? - Unused1 = trailingZeroesInNibble(LastByte band 15), - Unused2 = - case Unused1 of - 4 -> - 4 + trailingZeroesInNibble(LastByte bsr 4); - _ -> Unused1 - end, - case Unused2 of - 8 -> - remove_trailing_bin(NamedNumberList,{0,Bfront}); - _ -> - {Unused2,Bin} - end. - - -trailingZeroesInNibble(0) -> - 4; -trailingZeroesInNibble(1) -> - 0; -trailingZeroesInNibble(2) -> - 1; -trailingZeroesInNibble(3) -> - 0; -trailingZeroesInNibble(4) -> - 2; -trailingZeroesInNibble(5) -> - 0; -trailingZeroesInNibble(6) -> - 1; -trailingZeroesInNibble(7) -> - 0; -trailingZeroesInNibble(8) -> - 3; -trailingZeroesInNibble(9) -> - 0; -trailingZeroesInNibble(10) -> - 1; -trailingZeroesInNibble(11) -> - 0; -trailingZeroesInNibble(12) -> %#1100 - 2; -trailingZeroesInNibble(13) -> - 0; -trailingZeroesInNibble(14) -> - 1; -trailingZeroesInNibble(15) -> - 0. - -%%%%%%%%%%%%%%% -%% The result is presented as a list of named bits (if possible) -%% else as a tuple {Unused,Bits}. Unused is the number of unused -%% bits, least significant bits in the last byte of Bits. Bits is -%% the BIT STRING represented as a binary. -%% -decode_compact_bit_string(Buffer, C, NamedNumberList) -> - case get_constraint(C,'SizeConstraint') of - 0 -> % fixed length - {{8,0},Buffer}; - V when is_integer(V),V=<16 -> %fixed length 16 bits or less - compact_bit_string(Buffer,V,NamedNumberList); - V when is_integer(V),V=<65536 -> %fixed length > 16 bits - Bytes2 = align(Buffer), - compact_bit_string(Bytes2,V,NamedNumberList); - V when is_integer(V) -> % V > 65536 => fragmented value - {BitStr,Buffer2} = decode_fragmented_bits(Buffer,V), - case bit_size(BitStr) band 7 of - 0 -> {{0,BitStr},Buffer2}; - N -> {{8-N,<>},Buffer2} - end; - {Lb,Ub} when is_integer(Lb),is_integer(Ub) -> - %% This case may demand decoding of fragmented length/value - {Len,Bytes2} = decode_length(Buffer,{Lb,Ub}), - Bytes3 = align(Bytes2), - compact_bit_string(Bytes3,Len,NamedNumberList); - no -> - %% This case may demand decoding of fragmented length/value - {Len,Bytes2} = decode_length(Buffer,undefined), - Bytes3 = align(Bytes2), - compact_bit_string(Bytes3,Len,NamedNumberList); - {{Fix,Fix},Ext} = Sc when is_integer(Fix), is_list(Ext) -> - case decode_length(Buffer,Sc) of - {Len,Bytes2} when Len > Fix -> - Bytes3 = align(Bytes2), - compact_bit_string(Bytes3,Len,NamedNumberList); - {Len,Bytes2} when Len > 16 -> - Bytes3 = align(Bytes2), - compact_bit_string(Bytes3,Len,NamedNumberList); - {Len,Bytes2} -> - compact_bit_string(Bytes2,Len,NamedNumberList) - end; - Sc -> - {Len,Bytes2} = decode_length(Buffer,Sc), - Bytes3 = align(Bytes2), - compact_bit_string(Bytes3,Len,NamedNumberList) - end. - - -%%%%%%%%%%%%%%% -%% The result is presented as a list of named bits (if possible) -%% else as a list of 0 and 1. -%% -decode_bit_string(Buffer, C, NamedNumberList) -> - case get_constraint(C,'SizeConstraint') of - {Lb,Ub} when is_integer(Lb),is_integer(Ub) -> - {Len,Bytes2} = decode_length(Buffer,{Lb,Ub}), - Bytes3 = align(Bytes2), - bit_list_or_named(Bytes3,Len,NamedNumberList); - no -> - {Len,Bytes2} = decode_length(Buffer,undefined), - Bytes3 = align(Bytes2), - bit_list_or_named(Bytes3,Len,NamedNumberList); - 0 -> % fixed length - {[],Buffer}; % nothing to encode - V when is_integer(V),V=<16 -> % fixed length 16 bits or less - bit_list_or_named(Buffer,V,NamedNumberList); - V when is_integer(V),V=<65536 -> - Bytes2 = align(Buffer), - bit_list_or_named(Bytes2,V,NamedNumberList); - V when is_integer(V) -> - Bytes2 = align(Buffer), - {BinBits,_Bytes3} = decode_fragmented_bits(Bytes2,V), - bit_list_or_named(BinBits,V,NamedNumberList); - {{Fix,Fix},Ext} =Sc when is_integer(Fix), is_list(Ext) -> - case decode_length(Buffer,Sc) of - {Len,Bytes2} when Len > Fix -> - Bytes3 = align(Bytes2), - bit_list_or_named(Bytes3,Len,NamedNumberList); - {Len,Bytes2} when Len > 16 -> - Bytes3 = align(Bytes2), - bit_list_or_named(Bytes3,Len,NamedNumberList); - {Len,Bytes2} -> - bit_list_or_named(Bytes2,Len,NamedNumberList) - end; - Sc -> % extension marker - {Len,Bytes2} = decode_length(Buffer,Sc), - Bytes3 = align(Bytes2), - bit_list_or_named(Bytes3,Len,NamedNumberList) - end. - - -%% if no named bits are declared we will return a -%% {Unused,Bits}. Unused = integer(), -%% Bits = binary(). -compact_bit_string(Buffer,Len,[]) -> - {BitStr,Rest} = getbits_as_binary(Len,Buffer), % {{Unused,BinBits},NewBuffer} - PadLen = (8 - (bit_size(BitStr) rem 8)) rem 8, - {{PadLen,<>},Rest}; -compact_bit_string(Buffer,Len,NamedNumberList) -> - bit_list_or_named(Buffer,Len,NamedNumberList). - - -%% if no named bits are declared we will return a -%% BitList = [0 | 1] - -bit_list_or_named(Buffer,Len,[]) -> - getbits_as_list(Len,Buffer); - -%% if there are named bits declared we will return a named -%% BitList where the names are atoms and unnamed bits represented -%% as {bit,Pos} -%% BitList = [atom() | {bit,Pos}] -%% Pos = integer() - -bit_list_or_named(Buffer,Len,NamedNumberList) -> - {BitList,Rest} = getbits_as_list(Len,Buffer), - {bit_list_or_named1(0,BitList,NamedNumberList,[]), Rest}. - -bit_list_or_named1(Pos,[0|Bt],Names,Acc) -> - bit_list_or_named1(Pos+1,Bt,Names,Acc); -bit_list_or_named1(Pos,[1|Bt],Names,Acc) -> - case lists:keysearch(Pos,2,Names) of - {value,{Name,_}} -> - bit_list_or_named1(Pos+1,Bt,Names,[Name|Acc]); - _ -> - bit_list_or_named1(Pos+1,Bt,Names,[{bit,Pos}|Acc]) - end; -bit_list_or_named1(_Pos,[],_Names,Acc) -> - lists:reverse(Acc). - - - -%%%%%%%%%%%%%%% -%% - -int_to_bitlist(Int) when is_integer(Int), Int > 0 -> - [Int band 1 | int_to_bitlist(Int bsr 1)]; -int_to_bitlist(0) -> - []. - - -%%%%%%%%%%%%%%%%%% -%% get_all_bitposes([list of named bits to set], named_bit_db, []) -> -%% [sorted_list_of_bitpositions_to_set] - -get_all_bitposes([{bit,ValPos}|Rest], NamedBitList, Ack) -> - get_all_bitposes(Rest, NamedBitList, [ValPos | Ack ]); - -get_all_bitposes([Val | Rest], NamedBitList, Ack) -> - case lists:keysearch(Val, 1, NamedBitList) of - {value, {_ValName, ValPos}} -> - get_all_bitposes(Rest, NamedBitList, [ValPos | Ack]); - _ -> - exit({error,{asn1, {bitstring_namedbit, Val}}}) - end; -get_all_bitposes([], _NamedBitList, Ack) -> - lists:sort(Ack). - -%%%%%%%%%%%%%%%%%% -%% make_and_set_list([list of positions to set to 1])-> -%% returns list with all in SetPos set. -%% in positioning in list the first element is 0, the second 1 etc.., but -%% - -make_and_set_list([XPos|SetPos], XPos) -> - [1 | make_and_set_list(SetPos, XPos + 1)]; -make_and_set_list([Pos|SetPos], XPos) -> - [0 | make_and_set_list([Pos | SetPos], XPos + 1)]; -make_and_set_list([], _) -> - []. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% X.691:16 -%% encode_octet_string(Constraint,ExtensionMarker,Val) -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -encode_octet_string(C,Val) -> - encode_octet_string(C,false,Val). - -encode_octet_string(C,Bool,{_Name,Val}) -> - encode_octet_string(C,Bool,Val); -encode_octet_string(_C,true,_Val) -> - exit({error,{asn1,{'not_supported',extensionmarker}}}); -encode_octet_string(SZ={_,_},false,Val) -> -% [encode_length(SZ,length(Val)),align, -% {octets,Val}]; - Len = length(Val), - try - [encode_length(SZ,Len),2, - octets_to_complete(Len,Val)] - catch - exit:{error,{asn1,{encode_length,_}}} -> - encode_fragmented_octet_string(Val) - end; -encode_octet_string(SZ,false,Val) when is_list(SZ) -> - Len = length(Val), - try - [encode_length({hd(SZ),lists:max(SZ)},Len),2, - octets_to_complete(Len,Val)] - catch - exit:{error,{asn1,{encode_length,_}}} -> - encode_fragmented_octet_string(Val) - end; -encode_octet_string(Sv,false,Val) when is_integer(Sv) -> - encode_fragmented_octet_string(Val); -encode_octet_string(no,false,Val) -> - Len = length(Val), - try - [encode_length(undefined,Len),2, - octets_to_complete(Len,Val)] - catch - exit:{error,{asn1,{encode_length,_}}} -> - encode_fragmented_octet_string(Val) - end; -encode_octet_string(C,_,_) -> - exit({error,{not_implemented,C}}). - -encode_fragmented_octet_string(Val) -> - Bin = iolist_to_binary(Val), - efos_1(Bin). - -efos_1(<>) -> - [20,1,<<3:2,4:6>>, - octets_to_complete(16#C000, B1), - octets_to_complete(16#4000, B2)|efos_1(T)]; -efos_1(<>) -> - [20,1,<<3:2,3:6>>,octets_to_complete(16#C000, B)|efos_1(T)]; -efos_1(<>) -> - [20,1,<<3:2,2:6>>,octets_to_complete(16#8000, B)|efos_1(T)]; -efos_1(<>) -> - [20,1,<<3:2,1:6>>,octets_to_complete(16#4000, B)|efos_1(T)]; -efos_1(<<>>) -> - [20,1,0]; -efos_1(<>) -> - Len = byte_size(B), - [encode_length(undefined, Len),octets_to_complete(Len, B)]. - -decode_fragmented(SegSz0, Buf0, Unit) -> - SegSz = SegSz0 * Unit * ?'16K', - <> = Buf0, - decode_fragmented_1(Buf, Unit, Res). - -decode_fragmented_1(<<0:1,N:7,Buf0/bitstring>>, Unit, Res) -> - Sz = N*Unit, - <> = Buf0, - {<>,Buf}; -decode_fragmented_1(<<1:1,0:1,N:14,Buf0/bitstring>>, Unit, Res) -> - Sz = N*Unit, - <> = Buf0, - {<>,Buf}; -decode_fragmented_1(<<1:1,1:1,SegSz0:6,Buf0/bitstring>>, Unit, Res0) -> - SegSz = SegSz0 * Unit * ?'16K', - <> = Buf0, - Res = <>, - decode_fragmented_1(Buf, Unit, Res). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Restricted char string types -%% (NumericString, PrintableString,VisibleString,IA5String,BMPString,UniversalString) -%% X.691:26 and X.680:34-36 -%%encode_restricted_string(aligned,'BMPString',Constraints,Extension,Val) - - -encode_restricted_string(aligned,{Name,Val}) when is_atom(Name) -> - encode_restricted_string(aligned,Val); - -encode_restricted_string(aligned,Val) when is_list(Val)-> - Len = length(Val), - [encode_length(undefined,Len),octets_to_complete(Len,Val)]. - - -encode_known_multiplier_string(StringType,SizeC,NumBits,CharOutTab,{Name,Val}) when is_atom(Name) -> - encode_known_multiplier_string(StringType,SizeC,NumBits,CharOutTab,Val); -encode_known_multiplier_string(_StringType,SizeC,NumBits,CharOutTab,Val) -> - Result = chars_encode2(Val,NumBits,CharOutTab), - case SizeC of - Ub when is_integer(Ub), Ub*NumBits =< 16 -> - Result; - Ub when is_integer(Ub),Ub =<65535 -> % fixed length - [2,Result]; - {Ub,Lb} -> - [encode_length({Ub,Lb},length(Val)),2,Result]; - no -> - [encode_length(undefined,length(Val)),2,Result] - end. - -decode_restricted_string(Bytes,aligned) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - getoctets_as_list(Bytes2,Len). - -decode_known_multiplier_string(StringType,SizeC,NumBits,CharInTab,Bytes) -> - case SizeC of - Ub when is_integer(Ub), Ub*NumBits =< 16 -> - chars_decode(Bytes,NumBits,StringType,CharInTab,Ub); - Ub when is_integer(Ub),Ub =<65535 -> % fixed length - Bytes1 = align(Bytes), - chars_decode(Bytes1,NumBits,StringType,CharInTab,Ub); - Vl when is_list(Vl) -> - {Len,Bytes1} = decode_length(Bytes,{hd(Vl),lists:max(Vl)}), - Bytes2 = align(Bytes1), - chars_decode(Bytes2,NumBits,StringType,CharInTab,Len); - no -> - {Len,Bytes1} = decode_length(Bytes,undefined), - Bytes2 = align(Bytes1), - chars_decode(Bytes2,NumBits,StringType,CharInTab,Len); - {Lb,Ub}-> - {Len,Bytes1} = decode_length(Bytes,{Lb,Ub}), - Bytes2 = align(Bytes1), - chars_decode(Bytes2,NumBits,StringType,CharInTab,Len) - end. - -encode_GeneralString(_C,Val) -> - encode_restricted_string(aligned,Val). -decode_GeneralString(Bytes,_C) -> - decode_restricted_string(Bytes,aligned). - -encode_GraphicString(_C,Val) -> - encode_restricted_string(aligned,Val). -decode_GraphicString(Bytes,_C) -> - decode_restricted_string(Bytes,aligned). - -encode_ObjectDescriptor(_C,Val) -> - encode_restricted_string(aligned,Val). -decode_ObjectDescriptor(Bytes) -> - decode_restricted_string(Bytes,aligned). - -encode_TeletexString(_C,Val) -> % equivalent with T61String - encode_restricted_string(aligned,Val). -decode_TeletexString(Bytes,_C) -> - decode_restricted_string(Bytes,aligned). - -encode_VideotexString(_C,Val) -> - encode_restricted_string(aligned,Val). -decode_VideotexString(Bytes,_C) -> - decode_restricted_string(Bytes,aligned). - - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% getBMPChars(Bytes,Len) ->{BMPcharList,RemainingBytes} -%% -getBMPChars(<>, 0, Acc) -> - {lists:reverse(Acc),T}; -getBMPChars(<<0,O2,Bytes1/bitstring>>, Len, Acc) -> - getBMPChars(Bytes1,Len-1,[O2|Acc]); -getBMPChars(<>, Len, Acc) -> - getBMPChars(Bytes1,Len-1,[{0,0,O1,O2}|Acc]). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% chars_encode(C,StringType,Value) -> ValueList -%% -%% encodes chars according to the per rules taking the constraint PermittedAlphabet -%% into account. -%% This function does only encode the value part and NOT the length - -% chars_encode(C,StringType,Value) -> -% case {StringType,get_constraint(C,'PermittedAlphabet')} of -% {'UniversalString',{_,Sv}} -> -% exit({error,{asn1,{'not implemented',"UniversalString with PermittedAlphabet constraint"}}}); -% {'BMPString',{_,Sv}} -> -% exit({error,{asn1,{'not implemented',"BMPString with PermittedAlphabet constraint"}}}); -% _ -> -% {NumBits,CharOutTab} = {get_NumBits(C,StringType),get_CharOutTab(C,StringType)}, -% chars_encode2(Value,NumBits,CharOutTab) -% end. - - -chars_encode2([H|T],NumBits,T1={Min,Max,notab}) when H =< Max, H >= Min -> -% [[10,NumBits,H-Min]|chars_encode2(T,NumBits,T1)]; - [pre_complete_bits(NumBits,H-Min)|chars_encode2(T,NumBits,T1)]; -chars_encode2([H|T],NumBits,T1={Min,Max,Tab}) when H =< Max, H >= Min -> -% [[10,NumBits,element(H-Min+1,Tab)]|chars_encode2(T,NumBits,T1)]; - [pre_complete_bits(NumBits,exit_if_false(H,element(H-Min+1,Tab)))| - chars_encode2(T,NumBits,T1)]; -chars_encode2([{A,B,C,D}|T],NumBits,T1={Min,_Max,notab}) -> - %% no value range check here (ought to be, but very expensive) -% [{bits,NumBits,(A*B*C*D)-Min}|chars_encode2(T,NumBits,{Min,Max,notab})]; -% [[10,NumBits,((((((A bsl 8)+B) bsl 8)+C) bsl 8)+D)-Min]|chars_encode2(T,NumBits,T1)]; - [pre_complete_bits(NumBits, - ((((((A bsl 8)+B) bsl 8)+C) bsl 8)+D)-Min)| - chars_encode2(T,NumBits,T1)]; -chars_encode2([H={A,B,C,D}|T],NumBits,{Min,Max,Tab}) -> - %% no value range check here (ought to be, but very expensive) - [pre_complete_bits(NumBits,exit_if_false(H,element(((((((A bsl 8)+B) bsl 8)+C) bsl 8)+D)-Min,Tab)))|chars_encode2(T,NumBits,{Min,Max,notab})]; -chars_encode2([H|_T],_NumBits,{_Min,_Max,_Tab}) -> - exit({error,{asn1,{illegal_char_value,H}}}); -chars_encode2([],_,_) -> - []. - -exit_if_false(V,false)-> - exit({error,{asn1,{"illegal value according to Permitted alphabet constraint",V}}}); -exit_if_false(_,V) ->V. - -pre_complete_bits(NumBits,Val) when NumBits =< 8 -> - [10,NumBits,Val]; -pre_complete_bits(NumBits,Val) when NumBits =< 16 -> - [10,NumBits-8,Val bsr 8,10,8,(Val band 255)]; -pre_complete_bits(NumBits,Val) when NumBits =< 2040 -> % 255 * 8 -% LBUsed = NumBits rem 8, -% {Unused,Len} = case (8 - LBUsed) of -% 8 -> {0,NumBits div 8}; -% U -> {U,(NumBits div 8) + 1} -% end, -% NewVal = Val bsr LBUsed, -% [30,Unused,Len,<>]. - Unused = (8 - (NumBits rem 8)) rem 8, - Len = NumBits + Unused, - [30,Unused,Len div 8,<<(Val bsl Unused):Len>>]. - - -chars_decode(Bytes,_,'BMPString',_,Len) -> - getBMPChars(Bytes,Len,[]); -chars_decode(Bytes,NumBits,_StringType,CharInTab,Len) -> - chars_decode2(Bytes,CharInTab,NumBits,Len). - - -chars_decode2(Bytes,CharInTab,NumBits,Len) -> - chars_decode2(Bytes,CharInTab,NumBits,Len,[]). - -chars_decode2(Bytes,_CharInTab,_NumBits,0,Acc) -> - {lists:reverse(Acc),Bytes}; -chars_decode2(Bytes,{Min,Max,notab},NumBits,Len,Acc) when NumBits > 8 -> - {Char,Bytes2} = getbits(Bytes,NumBits), - Result = - if - Char < 256 -> Char; - true -> - list_to_tuple(binary_to_list(<>)) - end, - chars_decode2(Bytes2,{Min,Max,notab},NumBits,Len -1,[Result|Acc]); -chars_decode2(Bytes,{Min,Max,notab},NumBits,Len,Acc) -> - {Char,Bytes2} = getbits(Bytes,NumBits), - chars_decode2(Bytes2,{Min,Max,notab},NumBits,Len -1,[Char+Min|Acc]); - -%% BMPString and UniversalString with PermittedAlphabet is currently not supported -chars_decode2(Bytes,{Min,Max,CharInTab},NumBits,Len,Acc) -> - {Char,Bytes2} = getbits(Bytes,NumBits), - chars_decode2(Bytes2,{Min,Max,CharInTab},NumBits,Len -1,[element(Char+1,CharInTab)|Acc]). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% encode_UTF8String(Val) -> CompleteList -%% Val -> <> -%% CompleteList -> [apropriate codes and values for driver complete] -%% -encode_UTF8String(Val) when is_binary(Val) -> - [encode_length(undefined,size(Val)), - octets_to_complete(size(Val),Val)]; -encode_UTF8String(Val) -> - encode_UTF8String(list_to_binary(Val)). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_UTF8String(Bytes) -> {Utf8Binary,RemainingBytes} -%% Utf8Binary -> <> -%% RemainingBytes -> <> -decode_UTF8String(Bytes) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - {_Bin,_Bytes3} = getoctets_as_bin(Bytes2,Len). - - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% encode_object_identifier(Val) -> CompleteList -%% encode_object_identifier({Name,Val}) -> CompleteList -%% Val -> {Int1,Int2,...,IntN} % N >= 2 -%% Name -> atom() -%% Int1 -> integer(0..2) -%% Int2 -> integer(0..39) when Int1 (0..1) else integer() -%% Int3-N -> integer() -%% CompleteList -> [{bits,8,Val}|{octets,Ol}|align|...] -%% -encode_object_identifier({Name,Val}) when is_atom(Name) -> - encode_object_identifier(Val); -encode_object_identifier(Val) -> - OctetList = e_object_identifier(Val), - Octets = list_to_binary(OctetList), - [encode_length(undefined,size(Octets)), - octets_to_complete(size(Octets),Octets)]. - -e_object_identifier({'OBJECT IDENTIFIER',V}) -> - e_object_identifier(V); -e_object_identifier({Cname,V}) when is_atom(Cname),is_tuple(V) -> - e_object_identifier(tuple_to_list(V)); -e_object_identifier({Cname,V}) when is_atom(Cname),is_list(V) -> - e_object_identifier(V); -e_object_identifier(V) when is_tuple(V) -> - e_object_identifier(tuple_to_list(V)); - -%% E1 = 0|1|2 and (E2 < 40 when E1 = 0|1) -e_object_identifier([E1,E2|Tail]) when E1 >= 0, E1 < 2, E2 < 40 ; E1==2 -> - Head = 40*E1 + E2, % weird - e_object_elements([Head|Tail],[]); -e_object_identifier(Oid=[_,_|_Tail]) -> - exit({error,{asn1,{'illegal_value',Oid}}}). - -e_object_elements([],Acc) -> - lists:reverse(Acc); -e_object_elements([H|T],Acc) -> - e_object_elements(T,[e_object_element(H)|Acc]). - -e_object_element(Num) when Num < 128 -> - [Num]; -e_object_element(Num) -> - [e_o_e(Num bsr 7)|[Num band 2#1111111]]. -e_o_e(Num) when Num < 128 -> - Num bor 2#10000000; -e_o_e(Num) -> - [e_o_e(Num bsr 7)|[(Num band 2#1111111) bor 2#10000000]]. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_object_identifier(Bytes) -> {ObjId,RemainingBytes} -%% ObjId -> {integer(),integer(),...} % at least 2 integers -%% RemainingBytes -> [integer()] when integer() (0..255) -decode_object_identifier(Bytes) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - {Octs,Bytes3} = getoctets_as_list(Bytes2,Len), - [First|Rest] = dec_subidentifiers(Octs,0,[]), - Idlist = if - First < 40 -> - [0,First|Rest]; - First < 80 -> - [1,First - 40|Rest]; - true -> - [2,First - 80|Rest] - end, - {list_to_tuple(Idlist),Bytes3}. - -dec_subidentifiers([H|T],Av,Al) when H >=16#80 -> - dec_subidentifiers(T,(Av bsl 7) + (H band 16#7F),Al); -dec_subidentifiers([H|T],Av,Al) -> - dec_subidentifiers(T,0,[(Av bsl 7) + H |Al]); -dec_subidentifiers([],_Av,Al) -> - lists:reverse(Al). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% encode_relative_oid(Val) -> CompleteList -%% encode_relative_oid({Name,Val}) -> CompleteList -encode_relative_oid({Name,Val}) when is_atom(Name) -> - encode_relative_oid(Val); -encode_relative_oid(Val) when is_tuple(Val) -> - encode_relative_oid(tuple_to_list(Val)); -encode_relative_oid(Val) when is_list(Val) -> - Octets = list_to_binary([e_object_element(X)||X <- Val]), - [encode_length(undefined,size(Octets)), - octets_to_complete(size(Octets),Octets)]. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_relative_oid(Val) -> CompleteList -%% decode_relative_oid({Name,Val}) -> CompleteList -decode_relative_oid(Bytes) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - {Octs,Bytes3} = getoctets_as_list(Bytes2,Len), - ObjVals = dec_subidentifiers(Octs,0,[]), - {list_to_tuple(ObjVals),Bytes3}. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% encode_real(Val) -> CompleteList -%% encode_real({Name,Val}) -> CompleteList -encode_real({Name,Val}) when is_atom(Name) -> - encode_real(Val); -encode_real(Real) -> - {EncVal,Len} = ?RT_COMMON:encode_real([],Real), - [encode_length(undefined,Len),octets_to_complete(size(EncVal),EncVal)]. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_real(Val) -> {REALvalue,Rest} -%% decode_real({Name,Val}) -> {REALvalue,Rest} -decode_real(Bytes) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - {RealVal,Rest,Len} = ?RT_COMMON:decode_real(Bytes2,Len), - {RealVal,Rest}. - - -get_constraint([{Key,V}],Key) -> - V; -get_constraint([],_) -> - no; -get_constraint(C,Key) -> - case lists:keysearch(Key,1,C) of - false -> - no; - {value,{_,V}} -> - V - end. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% complete(InList) -> ByteList -%% Takes a coded list with bits and bytes and converts it to a list of bytes -%% Should be applied as the last step at encode of a complete ASN.1 type -%% - --ifdef(nodriver). - -complete(L) -> - erlang_complete(L). - --else. - -%% asn1-1.7 -complete(L) -> - case asn1rt_nif:encode_per_complete(L) of - {error, Reason} -> handle_error(Reason, L); - Else when is_binary(Else) -> Else - end. - -handle_error([],_)-> - exit({error,{asn1,{"memory allocation problem in driver"}}}); -handle_error($1,L) -> % error in complete in driver - exit({error,{asn1,L}}); -handle_error(ErrL,L) -> - exit({error,{asn1,ErrL,L}}). - --endif. - - -octets_to_complete(Len,Val) when Len < 256 -> - [20,Len,Val]; -octets_to_complete(Len,Val) -> - [21,<>,Val]. - -octets_unused_to_complete(Unused,Len,Val) when Len < 256 -> - [30,Unused,Len,Val]; -octets_unused_to_complete(Unused,Len,Val) -> - [31,Unused,<>,Val]. diff --git a/lib/asn1/src/asn1rt_uper_bin.erl b/lib/asn1/src/asn1rt_uper_bin.erl deleted file mode 100644 index fc65d80245..0000000000 --- a/lib/asn1/src/asn1rt_uper_bin.erl +++ /dev/null @@ -1,1487 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% --module(asn1rt_uper_bin). - -%% encoding / decoding of PER unaligned - --include("asn1_records.hrl"). - -%%-compile(export_all). - --export([decode_fragmented/3]). --export([setext/1, fixoptionals/3, - fixextensions/2, - skipextensions/3, getbit/1, getchoice/3 ]). --export([set_choice/3, encode_integer/2, encode_integer/3]). --export([encode_small_number/1, encode_boolean/1, - encode_length/2, - encode_small_length/1, - decode_compact_bit_string/3]). --export([encode_bit_string/3, decode_bit_string/3 ]). --export([encode_octet_string/2, - encode_relative_oid/1, decode_relative_oid/1, - encode_object_identifier/1, decode_object_identifier/1, - encode_real/1, decode_real/1, - complete/1, complete_NFP/1]). - - - -export([encode_open_type/2, decode_open_type/2]). - - -export([encode_UniversalString/2, decode_UniversalString/2, - encode_PrintableString/2, decode_PrintableString/2, - encode_GeneralString/2, decode_GeneralString/2, - encode_GraphicString/2, decode_GraphicString/2, - encode_TeletexString/2, decode_TeletexString/2, - encode_VideotexString/2, decode_VideotexString/2, - encode_VisibleString/2, decode_VisibleString/2, - encode_UTF8String/1, decode_UTF8String/1, - encode_BMPString/2, decode_BMPString/2, - encode_IA5String/2, decode_IA5String/2, - encode_NumericString/2, decode_NumericString/2, - encode_ObjectDescriptor/2, decode_ObjectDescriptor/1 - ]). - --define('16K',16384). --define('32K',32768). --define('64K',65536). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% setext(true|false) -> CompleteList -%% - -setext(false) -> - <<0:1>>; -setext(true) -> - <<1:1>>. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% This is the new fixoptionals/3 which is used by the new generates -%% -fixoptionals(OptList,OptLength,Val) when is_tuple(Val) -> - Bits = fixoptionals(OptList,Val,0), - {Val,<>}; - -fixoptionals([],_Val,Acc) -> - %% Optbits - Acc; -fixoptionals([{Pos,DefVal}|Ot],Val,Acc) -> - case element(Pos,Val) of - asn1_DEFAULT -> fixoptionals(Ot,Val,Acc bsl 1); - DefVal -> fixoptionals(Ot,Val,Acc bsl 1); - _ -> fixoptionals(Ot,Val,(Acc bsl 1) + 1) - end; -fixoptionals([Pos|Ot],Val,Acc) -> - case element(Pos,Val) of - asn1_NOVALUE -> fixoptionals(Ot,Val,Acc bsl 1); - asn1_DEFAULT -> fixoptionals(Ot,Val,Acc bsl 1); - _ -> fixoptionals(Ot,Val,(Acc bsl 1) + 1) - end. - - -fixextensions({ext,ExtPos,ExtNum},Val) -> - case fixextensions(ExtPos,ExtNum+ExtPos,Val,0) of - 0 -> []; - ExtBits -> - [encode_small_length(ExtNum),<>] - end. - -fixextensions(Pos,MaxPos,_,Acc) when Pos >= MaxPos -> - Acc; -fixextensions(Pos,ExtPos,Val,Acc) -> - Bit = case catch(element(Pos+1,Val)) of - asn1_NOVALUE -> - 0; - asn1_NOEXTVALUE -> - 0; - {'EXIT',_} -> - 0; - _ -> - 1 - end, - fixextensions(Pos+1,ExtPos,Val,(Acc bsl 1)+Bit). - -skipextensions(Bytes,Nr,ExtensionBitstr) when is_bitstring(ExtensionBitstr) -> - Prev = Nr - 1, - case ExtensionBitstr of - <<_:Prev,1:1,_/bitstring>> -> - {_,Bytes2} = decode_open_type(Bytes,[]), - skipextensions(Bytes2, Nr+1, ExtensionBitstr); - <<_:Prev,0:1,_/bitstring>> -> - skipextensions(Bytes, Nr+1, ExtensionBitstr); - _ -> - Bytes - end. - - -getchoice(Bytes,1,0) -> % only 1 alternative is not encoded - {0,Bytes}; -getchoice(Bytes,_,1) -> - decode_small_number(Bytes); -getchoice(Bytes,NumChoices,0) -> - decode_constrained_number(Bytes,{0,NumChoices-1}). - - -%% getbits_as_binary(Num,Bytes) -> {{Unused,BinBits},RestBytes}, -%% Num = integer(), -%% Bytes = list() | tuple(), -%% Unused = integer(), -%% BinBits = binary(), -%% RestBytes = tuple() -getbits_as_binary(Num,Bytes) when is_bitstring(Bytes) -> - <> = Bytes, - {BS,Rest}. - -getbits_as_list(Num,Bytes) when is_bitstring(Bytes) -> - <> = Bytes, - {[ B || <> <= BitStr],Rest}. - -getbit(Buffer) -> - <> = Buffer, - {B,Rest}. - - -getbits(Buffer,Num) when is_bitstring(Buffer) -> - <> = Buffer, - {Bs,Rest}. - - - -%% Pick the first Num octets. -%% Returns octets as an integer with bit significance as in buffer. -getoctets(Buffer,Num) when is_bitstring(Buffer) -> - <> = Buffer, - {Val,RestBitStr}. - -%% Pick the first Num octets. -%% Returns octets as a binary -getoctets_as_bin(Bin,Num) when is_bitstring(Bin) -> - <> = Bin, - {Octets,RestBin}. - -%% same as above but returns octets as a List -getoctets_as_list(Buffer,Num) -> - {Bin,Buffer2} = getoctets_as_bin(Buffer,Num), - {binary_to_list(Bin),Buffer2}. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% set_choice(Alt,Choices,Altnum) -> ListofBitSettings -%% Alt = atom() -%% Altnum = integer() | {integer(),integer()}% number of alternatives -%% Choices = [atom()] | {[atom()],[atom()]} -%% When Choices is a tuple the first list is the Rootset and the -%% second is the Extensions and then Altnum must also be a tuple with the -%% lengths of the 2 lists -%% -set_choice(Alt,{L1,L2},{Len1,_Len2}) -> - case set_choice_tag(Alt,L1) of - N when is_integer(N), Len1 > 1 -> - [<<0:1>>, % the value is in the root set - encode_integer([{'ValueRange',{0,Len1-1}}],N)]; - N when is_integer(N) -> - <<0:1>>; % no encoding if only 0 or 1 alternative - false -> - [<<1:1>>, % extension value - case set_choice_tag(Alt,L2) of - N2 when is_integer(N2) -> - encode_small_number(N2); - false -> - unknown_choice_alt - end] - end; -set_choice(Alt,L,Len) -> - case set_choice_tag(Alt,L) of - N when is_integer(N), Len > 1 -> - encode_integer([{'ValueRange',{0,Len-1}}],N); - N when is_integer(N) -> - []; % no encoding if only 0 or 1 alternative - false -> - [unknown_choice_alt] - end. - -set_choice_tag(Alt,Choices) -> - set_choice_tag(Alt,Choices,0). - -set_choice_tag(Alt,[Alt|_Rest],Tag) -> - Tag; -set_choice_tag(Alt,[_H|Rest],Tag) -> - set_choice_tag(Alt,Rest,Tag+1); -set_choice_tag(_Alt,[],_Tag) -> - false. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_fragmented_XXX; decode of values encoded fragmented according -%% to ITU-T X.691 clause 10.9.3.8. The unit (XXX) is either bits, octets, -%% characters or number of components (in a choice,sequence or similar). -%% Buffer is a buffer {Used, Bin}. -%% C is the constrained length. -%% If the buffer is not aligned, this function does that. -decode_fragmented_bits(Buffer,C) -> - decode_fragmented_bits(Buffer,C,[]). -decode_fragmented_bits(<<3:2,Len:6,BitStr/bitstring>>,C,Acc) -> -%% {Value,Bin2} = split_binary(Bin, Len * ?'16K'), - FragLen = (Len*?'16K') div 8, - <> = BitStr, - decode_fragmented_bits(BitStr2,C,[Value|Acc]); -decode_fragmented_bits(<<0:1,0:7,BitStr/bitstring>>,C,Acc) -> - BinBits = list_to_binary(lists:reverse(Acc)), - case C of - Int when is_integer(Int),C == size(BinBits) -> - {BinBits,BitStr}; - Int when is_integer(Int) -> - exit({error,{asn1,{illegal_value,C,BinBits}}}) - end; -decode_fragmented_bits(<<0:1,Len:7,BitStr/bitstring>>,C,Acc) -> - <> = BitStr, -%% <> = Bin, - ResBitStr = list_to_bitstring(lists:reverse([Val|Acc])), - case C of - Int when is_integer(Int),C == bit_size(ResBitStr) -> - {ResBitStr,Rest}; - Int when is_integer(Int) -> - exit({error,{asn1,{illegal_value,C,ResBitStr}}}) - end. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% encode_open_type(Constraint, Value) -> CompleteList -%% Value = list of bytes of an already encoded value (the list must be flat) -%% | binary -%% Contraint = not used in this version -%% -encode_open_type(C, Val) when is_list(Val) -> - encode_open_type(C, list_to_binary(Val)); -encode_open_type(_C, Val) when is_binary(Val) -> - [encode_length(undefined,size(Val)),Val]. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_open_type(Buffer,Constraint) -> Value -%% Constraint is not used in this version -%% Buffer = [byte] with PER encoded data -%% Value = [byte] with decoded data (which must be decoded again as some type) -%% -decode_open_type(Bytes, _C) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - getoctets_as_bin(Bytes2,Len). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% encode_integer(Constraint,Value,NamedNumberList) -> CompleteList -%% encode_integer(Constraint,Value) -> CompleteList -%% encode_integer(Constraint,{Name,Value}) -> CompleteList -%% -%% -encode_integer(C,V,NamedNumberList) when is_atom(V) -> - case lists:keysearch(V,1,NamedNumberList) of - {value,{_,NewV}} -> - encode_integer(C,NewV); - _ -> - exit({error,{asn1,{namednumber,V}}}) - end; -encode_integer(C,V,_NamedNumberList) when is_integer(V) -> - encode_integer(C,V); -encode_integer(C,{Name,V},NamedNumberList) when is_atom(Name) -> - encode_integer(C,V,NamedNumberList). - -encode_integer(C,{Name,Val}) when is_atom(Name) -> - encode_integer(C,Val); - -encode_integer([{Rc,_Ec}],Val) when is_tuple(Rc) -> % XXX when is this invoked? First argument most often a list,...Ok this is the extension case...but it doesn't work. - case (catch encode_integer([Rc],Val)) of - {'EXIT',{error,{asn1,_}}} -> - [<<1:1>>,encode_unconstrained_number(Val)]; - Encoded -> - [<<0:1>>,Encoded] - end; -encode_integer(C,Val ) when is_list(C) -> - case get_constraint(C,'SingleValue') of - no -> - encode_integer1(C,Val); - V when is_integer(V),V == Val -> - []; % a type restricted to a single value encodes to nothing - V when is_list(V) -> - case lists:member(Val,V) of - true -> - encode_integer1(C,Val); - _ -> - exit({error,{asn1,{illegal_value,Val}}}) - end; - _ -> - exit({error,{asn1,{illegal_value,Val}}}) - end. - -encode_integer1(C, Val) -> - case VR = get_constraint(C,'ValueRange') of - no -> - encode_unconstrained_number(Val); - {Lb,'MAX'} -> - encode_semi_constrained_number(Lb,Val); - %% positive with range - {Lb,Ub} when Val >= Lb, - Ub >= Val -> - encode_constrained_number(VR,Val); - _ -> - exit({error,{asn1,{illegal_value,VR,Val}}}) - end. - -%% X.691:10.6 Encoding of a normally small non-negative whole number -%% Use this for encoding of CHOICE index if there is an extension marker in -%% the CHOICE -encode_small_number({Name,Val}) when is_atom(Name) -> - encode_small_number(Val); -encode_small_number(Val) when Val =< 63 -> - <>; -encode_small_number(Val) -> - [<<1:1>>,encode_semi_constrained_number(0,Val)]. - -decode_small_number(Bytes) -> - {Bit,Bytes2} = getbit(Bytes), - case Bit of - 0 -> - getbits(Bytes2,6); - 1 -> - decode_semi_constrained_number(Bytes2) - end. - -%% X.691:10.7 Encoding of a semi-constrained whole number -%% might be an optimization encode_semi_constrained_number(0,Val) -> -encode_semi_constrained_number(C,{Name,Val}) when is_atom(Name) -> - encode_semi_constrained_number(C,Val); -encode_semi_constrained_number({Lb,'MAX'},Val) -> - encode_semi_constrained_number(Lb,Val); -encode_semi_constrained_number(Lb,Val) -> - %% encoding in minimum no of octets preceeded by a length - Val2 = Val - Lb, -%% NumBits = num_bits(Val2), - Bin = eint_bin_positive(Val2), - Size = size(Bin), - if - Size < 128 -> - [<>,Bin]; % equiv with encode_length(undefined,Len) but faster - Size < 16384 -> - [<<2:2,Size:14>>,Bin]; - true -> - [encode_length(undefined,Size),Bin] - end. - -decode_semi_constrained_number(Bytes) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - {V,Bytes3} = getoctets(Bytes2,Len), - {V,Bytes3}. - -encode_constrained_number(Range,{Name,Val}) when is_atom(Name) -> - encode_constrained_number(Range,Val); -encode_constrained_number({Lb,Ub},Val) when Val >= Lb, Ub >= Val -> - Range = Ub - Lb + 1, - Val2 = Val - Lb, - NumBits = num_bits(Range), - <>; -encode_constrained_number(Range,Val) -> - exit({error,{asn1,{integer_range,Range,value,Val}}}). - - -decode_constrained_number(Buffer,{Lb,Ub}) -> - Range = Ub - Lb + 1, - NumBits = num_bits(Range), - {Val,Remain} = getbits(Buffer,NumBits), - {Val+Lb,Remain}. - -%% X.691:10.8 Encoding of an unconstrained whole number - -encode_unconstrained_number(Val) when Val >= 0 -> - Oct = eint_bin_2Cs(Val), - Len = size(Oct), - if - Len < 128 -> - [<>,Oct]; % equiv with encode_length(undefined,Len) but faster - Len < 16384 -> - [<<2:2,Len:14>>,Oct]; - true -> - [encode_length(undefined,Len),<>,Oct] - end; -encode_unconstrained_number(Val) -> % negative - Oct = enint(Val,[]), - Len = size(Oct), - if - Len < 128 -> - [<>,Oct]; % equiv with encode_length(undefined,Len) but faster - Len < 16384 -> - [<<2:2,Len:14>>,Oct]; - true -> - [encode_length(undefined,Len),Oct] - end. - - -eint_bin_2Cs(Int) -> - case eint_bin_positive(Int) of - Bin = <> when B > 16#7f -> - <<0,Bin/binary>>; - Bin -> Bin - end. - -%% returns the integer as a binary -eint_bin_positive(Val) when Val < 16#100 -> - <>; -eint_bin_positive(Val) when Val < 16#10000 -> - <>; -eint_bin_positive(Val) when Val < 16#1000000 -> - <>; -eint_bin_positive(Val) when Val < 16#100000000 -> - <>; -eint_bin_positive(Val) -> - list_to_binary([eint_bin_positive2(Val bsr 32)|<>]). -eint_bin_positive2(Val) when Val < 16#100 -> - <>; -eint_bin_positive2(Val) when Val < 16#10000 -> - <>; -eint_bin_positive2(Val) when Val < 16#1000000 -> - <>; -eint_bin_positive2(Val) when Val < 16#100000000 -> - <>; -eint_bin_positive2(Val) -> - [eint_bin_positive2(Val bsr 32)|<>]. - - - - -enint(-1, [B1|T]) when B1 > 127 -> - list_to_binary([B1|T]); -enint(N, Acc) -> - enint(N bsr 8, [N band 16#ff|Acc]). - - -%% X.691:10.9 Encoding of a length determinant -%%encode_small_length(undefined,Len) -> % null means no UpperBound -%% encode_small_number(Len). - -%% X.691:10.9.3.5 -%% X.691:10.9.3.7 -encode_length(undefined,Len) -> % un-constrained - if - Len < 128 -> - <>; - Len < 16384 -> - <<2:2,Len:14>>; - true -> % should be able to endode length >= 16384 - error({error,{asn1,{encode_length,{nyi,above_16k}}}}) - end; - -encode_length({0,'MAX'},Len) -> - encode_length(undefined,Len); -encode_length(Vr={Lb,Ub},Len) when Ub =< 65535 ,Lb >= 0 -> % constrained - encode_constrained_number(Vr,Len); -encode_length({Lb,_Ub},Len) when is_integer(Lb), Lb >= 0 -> % Ub > 65535 - encode_length(undefined,Len); -encode_length({Vr={Lb,Ub},Ext},Len) - when Ub =< 65535 ,Lb >= 0, Len= - %% constrained extensible - [<<0:1>>,encode_constrained_number(Vr,Len)]; -encode_length({{Lb,_Ub},Ext},Len) when is_list(Ext) -> - [<<1:1>>,encode_semi_constrained_number(Lb,Len)]; -encode_length(SingleValue,_Len) when is_integer(SingleValue) -> - []. - -%% X.691 10.9.3.4 (only used for length of bitmap that prefixes extension -%% additions in a sequence or set -encode_small_length(Len) when Len =< 64 -> - <<(Len-1):7>>; -encode_small_length(Len) -> - [<<1:1>>,encode_length(undefined,Len)]. - - -%% un-constrained -decode_length(<<0:1,Oct:7,Rest/bitstring>>,undefined) -> - {Oct,Rest}; -decode_length(<<2:2,Val:14,Rest/bitstring>>,undefined) -> - {Val,Rest}; -decode_length(<<3:2,_:14,_Rest/bitstring>>,undefined) -> - exit({error,{asn1,{decode_length,{nyi,above_16k}}}}); - -decode_length(Buffer,{Lb,Ub}) when Ub =< 65535 ,Lb >= 0 -> % constrained - decode_constrained_number(Buffer,{Lb,Ub}); -decode_length(Buffer,{Lb,_}) when is_integer(Lb), Lb >= 0 -> % Ub > 65535 - decode_length(Buffer,undefined); -decode_length(Buffer,{VR={_Lb,_Ub},Ext}) when is_list(Ext) -> - {0,Buffer2} = getbit(Buffer), - decode_length(Buffer2, VR); - - -%When does this case occur with {_,_Lb,Ub} ?? -% X.691:10.9.3.5 -decode_length(Bin,{_,_Lb,_Ub}) -> %when Len =< 127 -> % Unconstrained or large Ub NOTE! this case does not cover case when Ub > 65535 - case Bin of - <<0:1,Val:7,Rest/bitstring>> -> - {Val,Rest}; - <<2:2,Val:14,Rest/bitstring>> -> - {Val,Rest}; - <<3:2,_:14,_Rest/bitstring>> -> - exit({error,{asn1,{decode_length,{nyi,length_above_64K}}}}) - end; -decode_length(Buffer,SingleValue) when is_integer(SingleValue) -> - {SingleValue,Buffer}. - - - % X.691:11 -encode_boolean(true) -> - <<1:1>>; -encode_boolean(false) -> - <<0:1>>; -encode_boolean({Name,Val}) when is_atom(Name) -> - encode_boolean(Val); -encode_boolean(Val) -> - exit({error,{asn1,{encode_boolean,Val}}}). - - -%%============================================================================ -%%============================================================================ -%% Bitstring value, ITU_T X.690 Chapter 8.5 -%%============================================================================ -%%============================================================================ - -%%============================================================================ -%% encode bitstring value -%%============================================================================ - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% bitstring NamedBitList -%% Val can be of: -%% - [identifiers] where only named identifers are set to one, -%% the Constraint must then have some information of the -%% bitlength. -%% - [list of ones and zeroes] all bits -%% - integer value representing the bitlist -%% C is constraint Len, only valid when identifiers - - -%% when the value is a list of {Unused,BinBits}, where -%% Unused = integer(), -%% BinBits = binary(). - -encode_bit_string(C,Bin={Unused,BinBits},NamedBitList) when is_integer(Unused), - is_binary(BinBits) -> - encode_bin_bit_string(get_constraint(C,'SizeConstraint'),Bin,NamedBitList); - -encode_bit_string(C, BitListVal, NamedBitList) -> - encode_bit_string1(get_constraint(C,'SizeConstraint'), BitListVal, NamedBitList). -%% when the value is a list of named bits -encode_bit_string1(C, LoNB=[FirstVal | _RestVal], NamedBitList) when is_atom(FirstVal) -> - ToSetPos = get_all_bitposes(LoNB, NamedBitList, []), - BitList = make_and_set_list(ToSetPos,0), - encode_bit_string1(C,BitList,NamedBitList); - -encode_bit_string1(C, BL=[{bit,_No} | _RestVal], NamedBitList) -> - ToSetPos = get_all_bitposes(BL, NamedBitList, []), - BitList = make_and_set_list(ToSetPos,0), - encode_bit_string1(C,BitList,NamedBitList); -%% when the value is a list of ones and zeroes -encode_bit_string1(Int, BitListValue, _) - when is_list(BitListValue),is_integer(Int) -> - %% The type is constrained by a single value size constraint - bit_list2bitstr(Int,BitListValue); -encode_bit_string1(no, BitListValue,[]) - when is_list(BitListValue) -> - Len = length(BitListValue), - [encode_length(undefined,Len),bit_list2bitstr(Len,BitListValue)]; -encode_bit_string1(C, BitListValue,[]) - when is_list(BitListValue) -> - Len = length(BitListValue), - [encode_length(C,Len),bit_list2bitstr(Len,BitListValue)]; -encode_bit_string1(no, BitListValue,_NamedBitList) - when is_list(BitListValue) -> - %% this case with an unconstrained BIT STRING can be made more efficient - %% if the complete driver can take a special code so the length field - %% is encoded there. - NewBitLVal = lists:reverse(lists:dropwhile(fun(0)->true;(1)->false end, - lists:reverse(BitListValue))), - Len = length(NewBitLVal), - [encode_length(undefined,Len),bit_list2bitstr(Len,NewBitLVal)]; -encode_bit_string1(C,BitListValue,_NamedBitList) - when is_list(BitListValue) ->% C = {_,'MAX'} - NewBitStr = bitstr_trailing_zeros(BitListValue,C), - [encode_length(C,bit_size(NewBitStr)),NewBitStr]; - - -%% when the value is an integer -encode_bit_string1(C, IntegerVal, NamedBitList) when is_integer(IntegerVal)-> - BitList = int_to_bitlist(IntegerVal), - encode_bit_string1(C,BitList,NamedBitList); - -%% when the value is a tuple -encode_bit_string1(C,{Name,Val}, NamedBitList) when is_atom(Name) -> - encode_bit_string1(C,Val,NamedBitList). - -bit_list2bitstr(Len,BitListValue) -> - case length(BitListValue) of - Len -> - << <> ||B <- BitListValue>>; - L when L > Len -> % truncate - << << <> ||B <- BitListValue>> :Len/bitstring>>; - L -> % Len > L -> pad - << << <> ||B <- BitListValue>>/bitstring ,0:(Len-L)>> - end. - -adjust_trailing_zeros(Len,Bin) when Len == bit_size(Bin) -> - Bin; -adjust_trailing_zeros(Len,Bin) when Len > bit_size(Bin) -> - <>; -adjust_trailing_zeros(Len,Bin) -> - <>. - -bitstr_trailing_zeros(BitList,C) when is_integer(C) -> - bitstr_trailing_zeros1(BitList,C,C); -bitstr_trailing_zeros(BitList,{Lb,Ub}) when is_integer(Lb) -> - bitstr_trailing_zeros1(BitList,Lb,Ub); -bitstr_trailing_zeros(BitList,{{Lb,Ub},_}) when is_integer(Lb) -> - bitstr_trailing_zeros1(BitList,Lb,Ub); -bitstr_trailing_zeros(BitList,_) -> - bit_list2bitstr(length(BitList),BitList). - -bitstr_trailing_zeros1(BitList,Lb,Ub) -> - case length(BitList) of - Lb -> bit_list2bitstr(Lb,BitList); - B when B bit_list2bitstr(Lb,BitList); - D -> F = fun(L,LB,LB,_,_)->bit_list2bitstr(LB,lists:reverse(L)); - ([0|R],L1,LB,UB,Fun)->Fun(R,L1-1,LB,UB,Fun); - (L,L1,_,UB,_)when L1 =< UB -> - bit_list2bitstr(L1,lists:reverse(L)); - (_,_L1,_,_,_) ->exit({error,{list_length_BIT_STRING, - BitList}}) end, - F(lists:reverse(BitList),D,Lb,Ub,F) - end. - -%% encode_bin_bit_string/3, when value is a tuple of Unused and BinBits. -%% Unused = integer(),i.e. number unused bits in least sign. byte of -%% BinBits = binary(). -encode_bin_bit_string(C,{_,BinBits},_NamedBitList) - when is_integer(C),C=<16 -> - adjust_trailing_zeros(C,BinBits); -encode_bin_bit_string(C,{_Unused,BinBits},_NamedBitList) - when is_integer(C) -> - adjust_trailing_zeros(C,BinBits); -encode_bin_bit_string(C,UnusedAndBin={_,_},NamedBitList) -> - %% removes all trailing bits if NamedBitList is not empty - BitStr = remove_trailing_bin(NamedBitList,UnusedAndBin), - case C of - {Lb,Ub} when is_integer(Lb),is_integer(Ub) -> - [encode_length({Lb,Ub},bit_size(BitStr)),BitStr]; - no -> - [encode_length(undefined,bit_size(BitStr)),BitStr]; - Sc -> - [encode_length(Sc,bit_size(BitStr)),BitStr] - end. - - -remove_trailing_bin([], {Unused,Bin}) -> - BS = bit_size(Bin)-Unused, - <> = Bin, - BitStr; -remove_trailing_bin(_NamedNumberList,{_Unused,<<>>}) -> - <<>>; -remove_trailing_bin(NamedNumberList, {_Unused,Bin}) -> - Size = size(Bin)-1, - <> = Bin, - - %% clear the Unused bits to be sure - Unused1 = trailingZeroesInNibble(LastByte band 15), - Unused2 = - case Unused1 of - 4 -> - 4 + trailingZeroesInNibble(LastByte bsr 4); - _ -> Unused1 - end, - case Unused2 of - 8 -> - remove_trailing_bin(NamedNumberList,{0,Bfront}); - _ -> - BS = bit_size(Bin) - Unused2, - <> = Bin, - BitStr - end. - -trailingZeroesInNibble(0) -> - 4; -trailingZeroesInNibble(1) -> - 0; -trailingZeroesInNibble(2) -> - 1; -trailingZeroesInNibble(3) -> - 0; -trailingZeroesInNibble(4) -> - 2; -trailingZeroesInNibble(5) -> - 0; -trailingZeroesInNibble(6) -> - 1; -trailingZeroesInNibble(7) -> - 0; -trailingZeroesInNibble(8) -> - 3; -trailingZeroesInNibble(9) -> - 0; -trailingZeroesInNibble(10) -> - 1; -trailingZeroesInNibble(11) -> - 0; -trailingZeroesInNibble(12) -> %#1100 - 2; -trailingZeroesInNibble(13) -> - 0; -trailingZeroesInNibble(14) -> - 1; -trailingZeroesInNibble(15) -> - 0. - -%%%%%%%%%%%%%%% -%% The result is presented as a list of named bits (if possible) -%% else as a tuple {Unused,Bits}. Unused is the number of unused -%% bits, least significant bits in the last byte of Bits. Bits is -%% the BIT STRING represented as a binary. -%% -decode_compact_bit_string(Buffer, C, NamedNumberList) -> - case get_constraint(C,'SizeConstraint') of - 0 -> % fixed length - {{8,0},Buffer}; - V when is_integer(V),V=<16 -> %fixed length 16 bits or less - compact_bit_string(Buffer,V,NamedNumberList); - V when is_integer(V),V=<65536 -> %fixed length > 16 bits - compact_bit_string(Buffer,V,NamedNumberList); - V when is_integer(V) -> % V > 65536 => fragmented value - {Bin,Buffer2} = decode_fragmented_bits(Buffer,V), - PadLen = (8 - (bit_size(Bin) rem 8)) rem 8, - {{PadLen,<>},Buffer2}; -%% {0,_} -> {{0,Bin},Buffer2}; -%% {U,_} -> {{8-U,Bin},Buffer2} - {Lb,Ub} when is_integer(Lb),is_integer(Ub) -> - %% This case may demand decoding of fragmented length/value - {Len,Bytes2} = decode_length(Buffer,{Lb,Ub}), - compact_bit_string(Bytes2,Len,NamedNumberList); - no -> - %% This case may demand decoding of fragmented length/value - {Len,Bytes2} = decode_length(Buffer,undefined), - compact_bit_string(Bytes2,Len,NamedNumberList); - Sc -> - {Len,Bytes2} = decode_length(Buffer,Sc), - compact_bit_string(Bytes2,Len,NamedNumberList) - end. - - -%%%%%%%%%%%%%%% -%% The result is presented as a list of named bits (if possible) -%% else as a list of 0 and 1. -%% -decode_bit_string(Buffer, C, NamedNumberList) -> - case get_constraint(C,'SizeConstraint') of - {Lb,Ub} when is_integer(Lb),is_integer(Ub) -> - {Len,Bytes2} = decode_length(Buffer,{Lb,Ub}), - bit_list_or_named(Bytes2,Len,NamedNumberList); - no -> - {Len,Bytes2} = decode_length(Buffer,undefined), - bit_list_or_named(Bytes2,Len,NamedNumberList); - 0 -> % fixed length - {[],Buffer}; % nothing to encode - V when is_integer(V),V=<16 -> % fixed length 16 bits or less - bit_list_or_named(Buffer,V,NamedNumberList); - V when is_integer(V),V=<65536 -> - bit_list_or_named(Buffer,V,NamedNumberList); - V when is_integer(V) -> - {BinBits,_} = decode_fragmented_bits(Buffer,V), - bit_list_or_named(BinBits,V,NamedNumberList); - Sc -> % extension marker - {Len,Bytes2} = decode_length(Buffer,Sc), - bit_list_or_named(Bytes2,Len,NamedNumberList) - end. - - -%% if no named bits are declared we will return a -%% {Unused,Bits}. Unused = integer(), -%% Bits = binary(). -compact_bit_string(Buffer,Len,[]) -> - {BitStr,Rest} = getbits_as_binary(Len,Buffer), % {{Unused,BinBits},NewBuffer} - PadLen = (8 - (bit_size(BitStr) rem 8)) rem 8, - {{PadLen,<>},Rest}; -compact_bit_string(Buffer,Len,NamedNumberList) -> - bit_list_or_named(Buffer,Len,NamedNumberList). - - -%% if no named bits are declared we will return a -%% BitList = [0 | 1] - -bit_list_or_named(Buffer,Len,[]) -> - getbits_as_list(Len,Buffer); - -%% if there are named bits declared we will return a named -%% BitList where the names are atoms and unnamed bits represented -%% as {bit,Pos} -%% BitList = [atom() | {bit,Pos}] -%% Pos = integer() - -bit_list_or_named(Buffer,Len,NamedNumberList) -> - {BitList,Rest} = getbits_as_list(Len,Buffer), - {bit_list_or_named1(0,BitList,NamedNumberList,[]), Rest}. - -bit_list_or_named1(Pos,[0|Bt],Names,Acc) -> - bit_list_or_named1(Pos+1,Bt,Names,Acc); -bit_list_or_named1(Pos,[1|Bt],Names,Acc) -> - case lists:keysearch(Pos,2,Names) of - {value,{Name,_}} -> - bit_list_or_named1(Pos+1,Bt,Names,[Name|Acc]); - _ -> - bit_list_or_named1(Pos+1,Bt,Names,[{bit,Pos}|Acc]) - end; -bit_list_or_named1(_,[],_,Acc) -> - lists:reverse(Acc). - - - -%%%%%%%%%%%%%%% -%% - -int_to_bitlist(Int) when is_integer(Int), Int > 0 -> - [Int band 1 | int_to_bitlist(Int bsr 1)]; -int_to_bitlist(0) -> - []. - - -%%%%%%%%%%%%%%%%%% -%% get_all_bitposes([list of named bits to set], named_bit_db, []) -> -%% [sorted_list_of_bitpositions_to_set] - -get_all_bitposes([{bit,ValPos}|Rest], NamedBitList, Ack) -> - get_all_bitposes(Rest, NamedBitList, [ValPos | Ack ]); - -get_all_bitposes([Val | Rest], NamedBitList, Ack) -> - case lists:keysearch(Val, 1, NamedBitList) of - {value, {_ValName, ValPos}} -> - get_all_bitposes(Rest, NamedBitList, [ValPos | Ack]); - _ -> - exit({error,{asn1, {bitstring_namedbit, Val}}}) - end; -get_all_bitposes([], _NamedBitList, Ack) -> - lists:sort(Ack). - -%%%%%%%%%%%%%%%%%% -%% make_and_set_list([list of positions to set to 1])-> -%% returns list with all in SetPos set. -%% in positioning in list the first element is 0, the second 1 etc.., but -%% - -make_and_set_list([XPos|SetPos], XPos) -> - [1 | make_and_set_list(SetPos, XPos + 1)]; -make_and_set_list([Pos|SetPos], XPos) -> - [0 | make_and_set_list([Pos | SetPos], XPos + 1)]; -make_and_set_list([], _) -> - []. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% X.691:16 -%% encode_octet_string(Constraint,Val) -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -encode_octet_string(C,{_Name,Val}) -> - encode_octet_string(C,Val); -encode_octet_string(C,Val) -> - case get_constraint(C,'SizeConstraint') of - 0 -> - <<>>; - 1 -> - list_to_binary(Val); - 2 -> - list_to_binary(Val); - {_,_}=VR -> - try - [encode_length(VR, length(Val)),list_to_binary(Val)] - catch - error:{error,{asn1,{encode_length,_}}} -> - encode_fragmented_octet_string(Val) - end; - Sv when is_integer(Sv), Sv =:= length(Val) -> % fixed length - if - Sv =< 65535 -> - list_to_binary(Val); - true -> - encode_fragmented_octet_string(Val) - end; - Sv when is_list(Sv) -> - try - [encode_length({hd(Sv),lists:max(Sv)}, - length(Val)),list_to_binary(Val)] - catch - error:{error,{asn1,{encode_length,_}}} -> - encode_fragmented_octet_string(Val) - end; - no -> - try - [encode_length(undefined, length(Val)),list_to_binary(Val)] - catch - error:{error,{asn1,{encode_length,_}}} -> - encode_fragmented_octet_string(Val) - end - end. - -encode_fragmented_octet_string(Val) -> - Bin = list_to_binary(Val), - efos_1(Bin). - -efos_1(<>) -> - [<<3:2,4:6>>,B|efos_1(T)]; -efos_1(<>) -> - [<<3:2,3:6>>,B|efos_1(T)]; -efos_1(<>) -> - [<<3:2,2:6>>,B|efos_1(T)]; -efos_1(<>) -> - [<<3:2,1:6>>,B|efos_1(T)]; -efos_1(<>) -> - Len = byte_size(B), - [encode_length(undefined, Len),B]. - -decode_fragmented(SegSz0, Buf0, Unit) -> - SegSz = SegSz0 * Unit * ?'16K', - <> = Buf0, - decode_fragmented_1(Buf, Unit, Res). - -decode_fragmented_1(<<0:1,N:7,Buf0/bitstring>>, Unit, Res) -> - Sz = N*Unit, - <> = Buf0, - {<>,Buf}; -decode_fragmented_1(<<1:1,0:1,N:14,Buf0/bitstring>>, Unit, Res) -> - Sz = N*Unit, - <> = Buf0, - {<>,Buf}; -decode_fragmented_1(<<1:1,1:1,SegSz0:6,Buf0/bitstring>>, Unit, Res0) -> - SegSz = SegSz0 * Unit * ?'16K', - <> = Buf0, - Res = <>, - decode_fragmented_1(Buf, Unit, Res). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Restricted char string types -%% (NumericString, PrintableString,VisibleString,IA5String,BMPString,UniversalString) -%% X.691:26 and X.680:34-36 -%%encode_restricted_string('BMPString',Constraints,Extension,Val) - - -encode_restricted_string({Name,Val}) when is_atom(Name) -> - encode_restricted_string(Val); - -encode_restricted_string(Val) when is_list(Val)-> - [encode_length(undefined,length(Val)),list_to_binary(Val)]. - -encode_known_multiplier_string(StringType,C,{Name,Val}) when is_atom(Name) -> - encode_known_multiplier_string(StringType,C,Val); - -encode_known_multiplier_string(StringType,C,Val) -> - Result = chars_encode(C,StringType,Val), - NumBits = get_NumBits(C,StringType), - case get_constraint(C,'SizeConstraint') of - Ub when is_integer(Ub), Ub*NumBits =< 16 -> - Result; - 0 -> - []; - Ub when is_integer(Ub),Ub =<65535 -> % fixed length - Result; - {Ub,Lb} -> - [encode_length({Ub,Lb},length(Val)),Result]; - Vl when is_list(Vl) -> - [encode_length({lists:min(Vl),lists:max(Vl)},length(Val)),Result]; - no -> - [encode_length(undefined,length(Val)),Result] - end. - -decode_restricted_string(Bytes) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - getoctets_as_list(Bytes2,Len). - -decode_known_multiplier_string(Bytes,StringType,C,_Ext) -> - NumBits = get_NumBits(C,StringType), - case get_constraint(C,'SizeConstraint') of - Ub when is_integer(Ub), Ub*NumBits =< 16 -> - chars_decode(Bytes,NumBits,StringType,C,Ub); - Ub when is_integer(Ub),Ub =<65535 -> % fixed length - chars_decode(Bytes,NumBits,StringType,C,Ub); - 0 -> - {[],Bytes}; - Vl when is_list(Vl) -> - {Len,Bytes1} = decode_length(Bytes,{hd(Vl),lists:max(Vl)}), - chars_decode(Bytes1,NumBits,StringType,C,Len); - no -> - {Len,Bytes1} = decode_length(Bytes,undefined), - chars_decode(Bytes1,NumBits,StringType,C,Len); - {Lb,Ub}-> - {Len,Bytes1} = decode_length(Bytes,{Lb,Ub}), - chars_decode(Bytes1,NumBits,StringType,C,Len) - end. - - -encode_NumericString(C,Val) -> - encode_known_multiplier_string('NumericString',C,Val). -decode_NumericString(Bytes,C) -> - decode_known_multiplier_string(Bytes,'NumericString',C,false). - -encode_PrintableString(C,Val) -> - encode_known_multiplier_string('PrintableString',C,Val). -decode_PrintableString(Bytes,C) -> - decode_known_multiplier_string(Bytes,'PrintableString',C,false). - -encode_VisibleString(C,Val) -> % equivalent with ISO646String - encode_known_multiplier_string('VisibleString',C,Val). -decode_VisibleString(Bytes,C) -> - decode_known_multiplier_string(Bytes,'VisibleString',C,false). - -encode_IA5String(C,Val) -> - encode_known_multiplier_string('IA5String',C,Val). -decode_IA5String(Bytes,C) -> - decode_known_multiplier_string(Bytes,'IA5String',C,false). - -encode_BMPString(C,Val) -> - encode_known_multiplier_string('BMPString',C,Val). -decode_BMPString(Bytes,C) -> - decode_known_multiplier_string(Bytes,'BMPString',C,false). - -encode_UniversalString(C,Val) -> - encode_known_multiplier_string('UniversalString',C,Val). -decode_UniversalString(Bytes,C) -> - decode_known_multiplier_string(Bytes,'UniversalString',C,false). - - -%% end of known-multiplier strings for which PER visible constraints are -%% applied - -encode_GeneralString(_C,Val) -> - encode_restricted_string(Val). -decode_GeneralString(Bytes,_C) -> - decode_restricted_string(Bytes). - -encode_GraphicString(_C,Val) -> - encode_restricted_string(Val). -decode_GraphicString(Bytes,_C) -> - decode_restricted_string(Bytes). - -encode_ObjectDescriptor(_C,Val) -> - encode_restricted_string(Val). -decode_ObjectDescriptor(Bytes) -> - decode_restricted_string(Bytes). - -encode_TeletexString(_C,Val) -> % equivalent with T61String - encode_restricted_string(Val). -decode_TeletexString(Bytes,_C) -> - decode_restricted_string(Bytes). - -encode_VideotexString(_C,Val) -> - encode_restricted_string(Val). -decode_VideotexString(Bytes,_C) -> - decode_restricted_string(Bytes). - - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% getBMPChars(Bytes,Len) ->{BMPcharList,RemainingBytes} -%% -getBMPChars(Bytes,1) -> - {O1,Bytes2} = getbits(Bytes,8), - {O2,Bytes3} = getbits(Bytes2,8), - if - O1 == 0 -> - {[O2],Bytes3}; - true -> - {[{0,0,O1,O2}],Bytes3} - end; -getBMPChars(Bytes,Len) -> - getBMPChars(Bytes,Len,[]). - -getBMPChars(Bytes,0,Acc) -> - {lists:reverse(Acc),Bytes}; -getBMPChars(Bytes,Len,Acc) -> - {Octs,Bytes1} = getoctets_as_list(Bytes,2), - case Octs of - [0,O2] -> - getBMPChars(Bytes1,Len-1,[O2|Acc]); - [O1,O2]-> - getBMPChars(Bytes1,Len-1,[{0,0,O1,O2}|Acc]) - end. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% chars_encode(C,StringType,Value) -> ValueList -%% -%% encodes chars according to the per rules taking the constraint PermittedAlphabet -%% into account. -%% This function does only encode the value part and NOT the length - -chars_encode(C,StringType,Value) -> - case {StringType,get_constraint(C,'PermittedAlphabet')} of - {'UniversalString',{_,_Sv}} -> - exit({error,{asn1,{'not implemented',"UniversalString with PermittedAlphabet constraint"}}}); - {'BMPString',{_,_Sv}} -> - exit({error,{asn1,{'not implemented',"BMPString with PermittedAlphabet constraint"}}}); - _ -> - {NumBits,CharOutTab} = {get_NumBits(C,StringType),get_CharOutTab(C,StringType)}, - chars_encode2(Value,NumBits,CharOutTab) - end. - -chars_encode2([H|T],NumBits,{Min,Max,notab}) when H =< Max, H >= Min -> - %%[{bits,NumBits,H-Min}|chars_encode2(T,NumBits,{Min,Max,notab})]; - [<<(H-Min):NumBits>>|chars_encode2(T,NumBits,{Min,Max,notab})]; -chars_encode2([H|T],NumBits,{Min,Max,Tab}) when H =< Max, H >= Min -> -%% [{bits,NumBits,exit_if_false(H,element(H-Min+1,Tab))}|chars_encode2(T,NumBits,{Min,Max,Tab})]; - Ch = exit_if_false(H,element(H-Min+1,Tab)), - [<>|chars_encode2(T,NumBits,{Min,Max,Tab})]; -chars_encode2([{A,B,C,D}|T],NumBits,{Min,Max,notab}) -> - %% no value range check here (ought to be, but very expensive) -%% [{bits,NumBits,((((((A bsl 8)+B) bsl 8)+C) bsl 8)+D)-Min}|chars_encode2(T,NumBits,{Min,Max,notab})]; - Ch = ((((((A bsl 8)+B) bsl 8)+C) bsl 8)+D)-Min, - [<>|chars_encode2(T,NumBits,{Min,Max,notab})]; -chars_encode2([{A,B,C,D}|T],NumBits,{Min,Max,Tab}) -> - %% no value range check here (ought to be, but very expensive) -%% [{bits,NumBits,exit_if_false({A,B,C,D},element(((((((A bsl 8)+B) bsl 8)+C) bsl 8)+D)-Min,Tab))}|chars_encode2(T,NumBits,{Min,Max,notab})]; - Ch = exit_if_false({A,B,C,D},element(((((((A bsl 8)+B) bsl 8)+C) bsl 8)+D)-Min,Tab)), - [<>|chars_encode2(T,NumBits,{Min,Max,notab})]; -chars_encode2([H|_T],_,{_,_,_}) -> - exit({error,{asn1,{illegal_char_value,H}}}); -chars_encode2([],_,_) -> - []. - -exit_if_false(V,false)-> - exit({error,{asn1,{"illegal value according to Permitted alphabet constraint",V}}}); -exit_if_false(_,V) ->V. - - -get_NumBits(C,StringType) -> - case get_constraint(C,'PermittedAlphabet') of - {'SingleValue',Sv} -> - charbits(length(Sv)); - no -> - case StringType of - 'IA5String' -> - charbits(128); % 16#00..16#7F - 'VisibleString' -> - charbits(95); % 16#20..16#7E - 'PrintableString' -> - charbits(74); % [$\s,$',$(,$),$+,$,,$-,$.,$/,"0123456789",$:,$=,$?,$A..$Z,$a..$z - 'NumericString' -> - charbits(11); % $ ,"0123456789" - 'UniversalString' -> - 32; - 'BMPString' -> - 16 - end - end. - -get_CharOutTab(C,StringType) -> - get_CharTab(C,StringType,out). - -get_CharInTab(C,StringType) -> - get_CharTab(C,StringType,in). - -get_CharTab(C,StringType,InOut) -> - case get_constraint(C,'PermittedAlphabet') of - {'SingleValue',Sv} -> - get_CharTab2(C,StringType,hd(Sv),lists:max(Sv),Sv,InOut); - no -> - case StringType of - 'IA5String' -> - {0,16#7F,notab}; - 'VisibleString' -> - get_CharTab2(C,StringType,16#20,16#7F,notab,InOut); - 'PrintableString' -> - Chars = lists:sort( - " '()+,-./0123456789:=?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), - get_CharTab2(C,StringType,hd(Chars),lists:max(Chars),Chars,InOut); - 'NumericString' -> - get_CharTab2(C,StringType,16#20,$9," 0123456789",InOut); - 'UniversalString' -> - {0,16#FFFFFFFF,notab}; - 'BMPString' -> - {0,16#FFFF,notab} - end - end. - -get_CharTab2(C,StringType,Min,Max,Chars,InOut) -> - BitValMax = (1 bsl get_NumBits(C,StringType))-1, - if - Max =< BitValMax -> - {0,Max,notab}; - true -> - case InOut of - out -> - {Min,Max,create_char_tab(Min,Chars)}; - in -> - {Min,Max,list_to_tuple(Chars)} - end - end. - -create_char_tab(Min,L) -> - list_to_tuple(create_char_tab(Min,L,0)). -create_char_tab(Min,[Min|T],V) -> - [V|create_char_tab(Min+1,T,V+1)]; -create_char_tab(_Min,[],_V) -> - []; -create_char_tab(Min,L,V) -> - [false|create_char_tab(Min+1,L,V)]. - -%% See Table 20.3 in Dubuisson -charbits(NumOfChars) when NumOfChars =< 2 -> 1; -charbits(NumOfChars) when NumOfChars =< 4 -> 2; -charbits(NumOfChars) when NumOfChars =< 8 -> 3; -charbits(NumOfChars) when NumOfChars =< 16 -> 4; -charbits(NumOfChars) when NumOfChars =< 32 -> 5; -charbits(NumOfChars) when NumOfChars =< 64 -> 6; -charbits(NumOfChars) when NumOfChars =< 128 -> 7; -charbits(NumOfChars) when NumOfChars =< 256 -> 8; -charbits(NumOfChars) when NumOfChars =< 512 -> 9; -charbits(NumOfChars) when NumOfChars =< 1024 -> 10; -charbits(NumOfChars) when NumOfChars =< 2048 -> 11; -charbits(NumOfChars) when NumOfChars =< 4096 -> 12; -charbits(NumOfChars) when NumOfChars =< 8192 -> 13; -charbits(NumOfChars) when NumOfChars =< 16384 -> 14; -charbits(NumOfChars) when NumOfChars =< 32768 -> 15; -charbits(NumOfChars) when NumOfChars =< 65536 -> 16; -charbits(NumOfChars) when is_integer(NumOfChars) -> - 16 + charbits1(NumOfChars bsr 16). - -charbits1(0) -> - 0; -charbits1(NumOfChars) -> - 1 + charbits1(NumOfChars bsr 1). - - -chars_decode(Bytes,_,'BMPString',C,Len) -> - case get_constraint(C,'PermittedAlphabet') of - no -> - getBMPChars(Bytes,Len); - _ -> - exit({error,{asn1, - {'not implemented', - "BMPString with PermittedAlphabet constraint"}}}) - end; -chars_decode(Bytes,NumBits,StringType,C,Len) -> - CharInTab = get_CharInTab(C,StringType), - chars_decode2(Bytes,CharInTab,NumBits,Len). - - -chars_decode2(Bytes,CharInTab,NumBits,Len) -> - chars_decode2(Bytes,CharInTab,NumBits,Len,[]). - -chars_decode2(Bytes,_CharInTab,_NumBits,0,Acc) -> - {lists:reverse(Acc),Bytes}; -chars_decode2(Bytes,{Min,Max,notab},NumBits,Len,Acc) when NumBits > 8 -> - {Char,Bytes2} = getbits(Bytes,NumBits), - Result = - if - Char < 256 -> Char; - true -> - list_to_tuple(binary_to_list(<>)) - end, - chars_decode2(Bytes2,{Min,Max,notab},NumBits,Len -1,[Result|Acc]); -chars_decode2(Bytes,{Min,Max,notab},NumBits,Len,Acc) -> - {Char,Bytes2} = getbits(Bytes,NumBits), - chars_decode2(Bytes2,{Min,Max,notab},NumBits,Len -1,[Char+Min|Acc]); - -%% BMPString and UniversalString with PermittedAlphabet is currently not supported -chars_decode2(Bytes,{Min,Max,CharInTab},NumBits,Len,Acc) -> - {Char,Bytes2} = getbits(Bytes,NumBits), - chars_decode2(Bytes2,{Min,Max,CharInTab},NumBits,Len -1,[element(Char+1,CharInTab)|Acc]). - - -%% UTF8String -encode_UTF8String(Val) when is_binary(Val) -> - [encode_length(undefined,size(Val)),Val]; -encode_UTF8String(Val) -> - Bin = list_to_binary(Val), - encode_UTF8String(Bin). - -decode_UTF8String(Bytes) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - getoctets_as_bin(Bytes2,Len). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% encode_object_identifier(Val) -> CompleteList -%% encode_object_identifier({Name,Val}) -> CompleteList -%% Val -> {Int1,Int2,...,IntN} % N >= 2 -%% Name -> atom() -%% Int1 -> integer(0..2) -%% Int2 -> integer(0..39) when Int1 (0..1) else integer() -%% Int3-N -> integer() -%% CompleteList -> [binary()|bitstring()|list()] -%% -encode_object_identifier({Name,Val}) when is_atom(Name) -> - encode_object_identifier(Val); -encode_object_identifier(Val) -> - OctetList = e_object_identifier(Val), - Octets = list_to_binary(OctetList), % performs a flatten at the same time - [encode_length(undefined,size(Octets)),Octets]. - -%% This code is copied from asn1_encode.erl (BER) and corrected and modified - -e_object_identifier({'OBJECT IDENTIFIER',V}) -> - e_object_identifier(V); -e_object_identifier({Cname,V}) when is_atom(Cname),is_tuple(V) -> - e_object_identifier(tuple_to_list(V)); -e_object_identifier({Cname,V}) when is_atom(Cname),is_list(V) -> - e_object_identifier(V); -e_object_identifier(V) when is_tuple(V) -> - e_object_identifier(tuple_to_list(V)); - -%% E1 = 0|1|2 and (E2 < 40 when E1 = 0|1) -e_object_identifier([E1,E2|Tail]) when E1 >= 0, E1 < 2, E2 < 40 ; E1==2 -> - Head = 40*E1 + E2, % weird - e_object_elements([Head|Tail],[]); -e_object_identifier(Oid=[_,_|_Tail]) -> - exit({error,{asn1,{'illegal_value',Oid}}}). - -e_object_elements([],Acc) -> - lists:reverse(Acc); -e_object_elements([H|T],Acc) -> - e_object_elements(T,[e_object_element(H)|Acc]). - -e_object_element(Num) when Num < 128 -> - [Num]; -e_object_element(Num) -> - [e_o_e(Num bsr 7)|[Num band 2#1111111]]. -e_o_e(Num) when Num < 128 -> - Num bor 2#10000000; -e_o_e(Num) -> - [e_o_e(Num bsr 7)|[(Num band 2#1111111) bor 2#10000000]]. - - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_object_identifier(Bytes) -> {ObjId,RemainingBytes} -%% ObjId -> {integer(),integer(),...} % at least 2 integers -%% RemainingBytes -> [integer()] when integer() (0..255) -decode_object_identifier(Bytes) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - {Octs,Bytes3} = getoctets_as_list(Bytes2,Len), - [First|Rest] = dec_subidentifiers(Octs,0,[]), - Idlist = if - First < 40 -> - [0,First|Rest]; - First < 80 -> - [1,First - 40|Rest]; - true -> - [2,First - 80|Rest] - end, - {list_to_tuple(Idlist),Bytes3}. - -dec_subidentifiers([H|T],Av,Al) when H >=16#80 -> - dec_subidentifiers(T,(Av bsl 7) + (H band 16#7F),Al); -dec_subidentifiers([H|T],Av,Al) -> - dec_subidentifiers(T,0,[(Av bsl 7) + H |Al]); -dec_subidentifiers([],_Av,Al) -> - lists:reverse(Al). - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% encode_relative_oid(Val) -> CompleteList -%% encode_relative_oid({Name,Val}) -> CompleteList -encode_relative_oid({Name,Val}) when is_atom(Name) -> - encode_relative_oid(Val); -encode_relative_oid(Val) when is_tuple(Val) -> - encode_relative_oid(tuple_to_list(Val)); -encode_relative_oid(Val) when is_list(Val) -> - Octets = list_to_binary([e_object_element(X)||X <- Val]), - [encode_length(undefined,size(Octets)),Octets]. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_relative_oid(Val) -> CompleteList -%% decode_relative_oid({Name,Val}) -> CompleteList -decode_relative_oid(Bytes) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - {Octs,Bytes3} = getoctets_as_list(Bytes2,Len), - ObjVals = dec_subidentifiers(Octs,0,[]), - {list_to_tuple(ObjVals),Bytes3}. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% encode_real(Val) -> CompleteList -%% encode_real({Name,Val}) -> CompleteList -encode_real({Name,Val}) when is_atom(Name) -> - encode_real(Val); -encode_real(Real) -> - {EncVal,Len} = ?RT_COMMON:encode_real([],Real), - [encode_length(undefined,Len),EncVal]. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_real(Val) -> {REALvalue,Rest} -%% decode_real({Name,Val}) -> {REALvalue,Rest} -decode_real(Bytes) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - <> = Bytes2, - {RealVal,Rest,Len} = ?RT_COMMON:decode_real(Bytes3,Len), - {RealVal,Rest}. - - -get_constraint([{Key,V}],Key) -> - V; -get_constraint([],_Key) -> - no; -get_constraint(C,Key) -> - case lists:keysearch(Key,1,C) of - false -> - no; - {value,{_,V}} -> - V - end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% complete(InList) -> ByteList -%% Takes a coded list with bits and bytes and converts it to a list of bytes -%% Should be applied as the last step at encode of a complete ASN.1 type -%% -complete(InList) when is_list(InList) -> - case complete1(InList) of - <<>> -> - <<0>>; - Res -> - case bit_size(Res) band 7 of - 0 -> Res; - Bits -> <> - end - end; -complete(InList) when is_binary(InList) -> - InList; -complete(InList) when is_bitstring(InList) -> - PadLen = 8 - (bit_size(InList) band 7), - <>. - -complete1(L) when is_list(L) -> - list_to_bitstring(L). - -%% Special version of complete that does not align the completed message. -complete_NFP(InList) when is_list(InList) -> - list_to_bitstring(InList); -complete_NFP(InList) when is_bitstring(InList) -> - InList. - -%% unaligned helpers - -%% 10.5.6 NOTE: If "range" satisfies the inequality 2^m < "range" =< -%% 2^(m+1) then the number of bits = m + 1 - -num_bits(N) -> - num_bits(N,1,0). -num_bits(N,T,B) when N=B; -num_bits(N,T,B) ->num_bits(N,T bsl 1, B+1). -- cgit v1.2.3 From fbcb7fe589edbfe79d10d7fe01be8a9f77926b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 19 Dec 2012 15:46:53 +0100 Subject: Optimize encoding of ENUMERATED in per and uper Always pre-encode the values for the enumeration. Clean up the code and let the per and uper back-ends share the code. --- lib/asn1/src/Makefile | 3 +- lib/asn1/src/asn1ct_eval_per.funcs | 3 +- lib/asn1/src/asn1ct_eval_uper.funcs | 2 + lib/asn1/src/asn1ct_gen_per.erl | 84 ++++++++++++++++------------------- lib/asn1/src/asn1ct_gen_per_rt2ct.erl | 76 +------------------------------ lib/asn1/src/asn1rtt_per.erl | 1 + lib/asn1/src/asn1rtt_uper.erl | 3 +- 7 files changed, 50 insertions(+), 122 deletions(-) create mode 100644 lib/asn1/src/asn1ct_eval_uper.funcs (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile index b1500d9ea6..4bf6eabce6 100644 --- a/lib/asn1/src/Makefile +++ b/lib/asn1/src/Makefile @@ -44,7 +44,8 @@ RELSYSDIR = $(RELEASE_PATH)/lib/asn1-$(VSN) EBIN = ../ebin EVAL_CT_MODULES = asn1ct_eval_ext \ - asn1ct_eval_per + asn1ct_eval_per \ + asn1ct_eval_uper CT_MODULES= \ asn1ct \ diff --git a/lib/asn1/src/asn1ct_eval_per.funcs b/lib/asn1/src/asn1ct_eval_per.funcs index 353424c231..a1ea5cd043 100644 --- a/lib/asn1/src/asn1ct_eval_per.funcs +++ b/lib/asn1/src/asn1ct_eval_per.funcs @@ -1 +1,2 @@ -{per,encode_integer,2}. +{per,encode_constrained_number,2}. +{per,encode_small_number,1}. diff --git a/lib/asn1/src/asn1ct_eval_uper.funcs b/lib/asn1/src/asn1ct_eval_uper.funcs new file mode 100644 index 0000000000..884a486f40 --- /dev/null +++ b/lib/asn1/src/asn1ct_eval_uper.funcs @@ -0,0 +1,2 @@ +{uper,encode_constrained_number,2}. +{uper,encode_small_number,1}. diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl index 08b65d466d..5dda5e9c5d 100644 --- a/lib/asn1/src/asn1ct_gen_per.erl +++ b/lib/asn1/src/asn1ct_gen_per.erl @@ -143,28 +143,16 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) -> Value,{asis,NamedNumberList}], call(Erules, encode_integer, Args); {'ENUMERATED',{Nlist1,Nlist2}} -> - NewList = lists:concat([[{0,X}||{X,_} <- Nlist1],['EXT_MARK'],[{1,X}||{X,_} <- Nlist2]]), - NewC = [{'ValueRange',{0,length(Nlist1)-1}}], - case Erules of - uper -> - emit(["case ",Value," of",nl]); - _ -> - emit(["case (case ",Value," of {_,",{curr,enumval},"}-> ", - {curr,enumval},";_->", Value," end) of",nl]), - asn1ct_name:new(enumval) - end, - emit_enc_enumerated_cases(Erules,NewC, NewList, 0); + NewList = [{0,X} || {X,_} <- Nlist1] ++ ['EXT_MARK'] ++ + [{1,X} || {X,_} <- Nlist2], + NewC = {0,length(Nlist1)-1}, + emit(["case ",Value," of",nl]), + emit_enc_enumerated_cases(Erules, NewC, NewList, 0); {'ENUMERATED',NamedNumberList} -> - NewList = [X||{X,_} <- NamedNumberList], - NewC = [{'ValueRange',{0,length(NewList)-1}}], - case Erules of - uper -> - emit(["case ",Value," of",nl]); - _ -> - emit(["case (case ",Value," of {_,",{curr,enumval}, - "}->",{curr,enumval},";_->",Value," end) of",nl]) - end, - emit_enc_enumerated_cases(Erules,NewC, NewList, 0); + NewList = [X || {X,_} <- NamedNumberList], + NewC = {0,length(NewList)-1}, + emit(["case ",Value," of",nl]), + emit_enc_enumerated_cases(Erules, NewC, NewList, 0); 'REAL' -> emit_enc_real(Erules, Value); @@ -250,34 +238,37 @@ emit_enc_real(Erules, Real) -> {curr,tmpval},"]",nl, "end"]). -emit_enc_enumerated_cases(Erule,C, [H], Count) -> - emit_enc_enumerated_case(Erule,C, H, Count), - case H of - 'EXT_MARK' -> ok; - _ -> - emit([";",nl]) - end, - emit([nl,"EnumVal -> exit({error,{asn1, {enumerated_not_in_range, EnumVal}}})"]), - emit([nl,"end"]); -emit_enc_enumerated_cases(Erule, C, ['EXT_MARK'|T], _Count) -> - emit_enc_enumerated_cases(Erule, C, T, 0); -emit_enc_enumerated_cases(Erule, C, [H1,H2|T], Count) -> - emit_enc_enumerated_case(Erule, C, H1, Count), +emit_enc_enumerated_cases(Erules, C, ['EXT_MARK'|T], _Count) -> + %% Reset enumeration counter. + emit_enc_enumerated_cases(Erules, C, T, 0); +emit_enc_enumerated_cases(Erules, C, [H|T], Count) -> + emit_enc_enumerated_case(Erules, C, H, Count), emit([";",nl]), - emit_enc_enumerated_cases(Erule, C, [H2|T], Count+1). + emit_enc_enumerated_cases(Erules, C, T, Count+1); +emit_enc_enumerated_cases(_Erules, _, [], _Count) -> + emit(["EnumVal -> " + "exit({error,{asn1,{enumerated_not_in_range, EnumVal}}})",nl, + "end"]). - -emit_enc_enumerated_case(_Erule, _C, 'EXT_MARK', _Count) -> - true; -emit_enc_enumerated_case(uper=Erules,_C, {1,EnumName}, Count) -> - emit(["'",EnumName,"' -> [<<1:1>>,", - {call,Erules,encode_small_number,[Count]},"]"]); -emit_enc_enumerated_case(uper=Erules, C, {0,EnumName}, Count) -> - emit(["'",EnumName,"' -> [<<0:1>>,", - {call,Erules,encode_integer,[{asis,C},Count]},"]"]); +emit_enc_enumerated_case(Erules, C, {0,EnumName}, Count) -> + %% ENUMERATED with extensionmark; the value lies within then extension root + Enc = enc_ext_and_val(Erules, 0, encode_constrained_number, [C,Count]), + emit(["'",EnumName,"' -> ",{asis,Enc}]); +emit_enc_enumerated_case(Erules, _C, {1,EnumName}, Count) -> + %% ENUMERATED with extensionmark; the value is higher than extension root + Enc = enc_ext_and_val(Erules, 1, encode_small_number, [Count]), + emit(["'",EnumName,"' -> ",{asis,Enc}]); emit_enc_enumerated_case(Erules, C, EnumName, Count) -> + %% ENUMERATED without extension + EvalMod = eval_module(Erules), emit(["'",EnumName,"' -> ", - {call,Erules,encode_integer,[{asis,C},Count]}]). + {asis,EvalMod:encode_constrained_number(C, Count)}]). + +enc_ext_and_val(per, E, F, Args) -> + [E|apply(asn1ct_eval_per, F, Args)]; +enc_ext_and_val(uper, E, F, Args) -> + <>. + get_constraint([{Key,V}], Key) -> V; @@ -1262,3 +1253,6 @@ imm_dec_open_type_1(Type, Aligned) -> "end"]) end, {call,D,asn1ct_imm:per_dec_open_type(Aligned)}. + +eval_module(per) -> asn1ct_eval_per; +eval_module(uper) -> asn1ct_eval_uper. diff --git a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl index 7d00f2e817..88e9bc6020 100644 --- a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl +++ b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl @@ -138,20 +138,8 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) -> emit([" %%INTEGER with effective constraint: ", {asis,EffectiveConstr},nl]), emit_enc_integer_NNL(Erules,EffectiveConstr,Value,NamedNumberList); - {'ENUMERATED',{Nlist1,Nlist2}} -> - NewList = lists:append([[{0,X}||{X,_} <- Nlist1],['EXT_MARK'],[{1,X}||{X,_} <- Nlist2]]), - NewC = [{'ValueRange',{0,length(Nlist1)-1}}], - emit(["case ",Value," of",nl]), -%% emit_enc_enumerated_cases(Erules,NewC, NewList++[{asn1_enum,length(Nlist1)-1}], 0); - emit_enc_enumerated_cases(Erules,NewC, NewList, 0); - {'ENUMERATED',NamedNumberList} -> - NewList = [X||{X,_} <- NamedNumberList], - NewC = effective_constraint(integer, - [{'ValueRange', - {0,length(NewList)-1}}]), - NewVal = enc_enum_cases(Value,NewList), - emit_enc_integer(Erules,NewC,NewVal); - + {'ENUMERATED',_} -> + asn1ct_gen_per:gen_encode_prim(Erules, D, DoTag, Value); 'REAL' -> emit_enc_real(Erules, Value); @@ -551,66 +539,6 @@ emit_enc_integer(Erule, C, Value) -> call(Erule, encode_integer, [{asis,C},Value]). - -enc_enum_cases(Value,NewList) -> - asn1ct_name:new(tmpval), - TmpVal = asn1ct_gen:mk_var(asn1ct_name:curr(tmpval)), - Cases=enc_enum_cases1(NewList), - lists:flatten(io_lib:format("(case ~s of "++Cases++ - "~s ->exit({error," - "{asn1,{enumerated,~s}}})" - " end)", - [Value,TmpVal,TmpVal])). -enc_enum_cases1(NNL) -> - enc_enum_cases1(NNL,0). -enc_enum_cases1([H|T],Index) -> - io_lib:format("~w->~w;",[H,Index])++enc_enum_cases1(T,Index+1); -enc_enum_cases1([],_) -> - "". - - -emit_enc_enumerated_cases(Erule, C, [H], Count) -> - emit_enc_enumerated_case(Erule, C, H, Count), - case H of - 'EXT_MARK' -> - ok; - _ -> - emit([";",nl]) - end, - emit([nl,"EnumVal -> exit({error,{asn1, {enumerated_not_in_range, EnumVal}}})"]), - emit([nl,"end"]); -emit_enc_enumerated_cases(Erule, C, ['EXT_MARK'|T], _Count) -> - emit_enc_enumerated_cases(Erule, C, T, 0); -emit_enc_enumerated_cases(Erule, C, [H1,H2|T], Count) -> - emit_enc_enumerated_case(Erule, C, H1, Count), - emit([";",nl]), - emit_enc_enumerated_cases(Erule, C, [H2|T], Count+1). - - -%% The function clauses matching on tuples with first element -%% asn1_enum, 1 or 0 and the atom 'EXT_MARK' are for ENUMERATED -%% with extension mark. -%% emit_enc_enumerated_case(_Erule,_C, {asn1_enum,High}, _) -> -%% %% ENUMERATED with extensionmark -%% %% value higher than the extension base and not -%% %% present in the extension range. -emit_enc_enumerated_case(Erule,_C, {1,EnumName}, Count) -> - %% ENUMERATED with extensionmark - %% values higher than extension root - emit(["'",EnumName,"' -> [1,"]), - call(Erule, encode_small_number, [Count]), - emit("]"); -emit_enc_enumerated_case(_Erule,C, {0,EnumName}, Count) -> - %% ENUMERATED with extensionmark - %% values within extension root - emit(["'",EnumName,"' -> ",{asis,[0|asn1ct_eval_per:encode_integer(C, Count)]}]); -emit_enc_enumerated_case(_Erule, _C, 'EXT_MARK', _Count) -> - true. -%% %% This clause is invoked in case of an ENUMERATED without extension mark -%% emit_enc_enumerated_case(_Erule,_C, EnumName, Count) -> -%% emit(["'",EnumName,"' -> ",Count]). - - get_constraint([{Key,V}],Key) -> V; get_constraint([],_) -> diff --git a/lib/asn1/src/asn1rtt_per.erl b/lib/asn1/src/asn1rtt_per.erl index 8234121934..a7bbc33a19 100644 --- a/lib/asn1/src/asn1rtt_per.erl +++ b/lib/asn1/src/asn1rtt_per.erl @@ -22,6 +22,7 @@ skipextensions/3, getbit/1, getchoice/3, set_choice/3,encode_integer/2, encode_small_number/1, + encode_constrained_number/2, encode_length/1, encode_length/2, decode_compact_bit_string/3, diff --git a/lib/asn1/src/asn1rtt_uper.erl b/lib/asn1/src/asn1rtt_uper.erl index bcc11da63a..d4e2fece67 100644 --- a/lib/asn1/src/asn1rtt_uper.erl +++ b/lib/asn1/src/asn1rtt_uper.erl @@ -23,7 +23,8 @@ fixextensions/2, skipextensions/3, getbit/1, getchoice/3 ]). -export([set_choice/3, encode_integer/2, encode_integer/3]). --export([encode_small_number/1, encode_boolean/1, +-export([encode_small_number/1, encode_constrained_number/2, + encode_boolean/1, encode_length/1, encode_length/2, decode_compact_bit_string/3]). -export([encode_bit_string/3, decode_bit_string/3]). -- cgit v1.2.3 From 76ad80f52981449af3c79fdf5b298e4c8d817788 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 20 Dec 2012 12:13:47 +0100 Subject: Refactor decoding of BIT STRINGs Refactor decoding of BIT STRINGs so that the run-time code does not spend testing conditions that are known already at compile-time (which wastes time and produces unnecessary Dialyzer warnings). There are three ways to decode BIT STRINGs: 1) To a list of bit names (and {bit,Position} for unnamed positions) if the BIT STRING type has any bit names. 2a) To a list of ones and zeros if there are no named bits, and the compact_bit_string option was NOT given. 2b) To a {Unused,Bin} tuple if there are no named bits compact_bit_string option WAS given. Structure the decoding functions in the same way. --- lib/asn1/src/asn1ct_gen_ber_bin_v2.erl | 31 +++--- lib/asn1/src/asn1ct_gen_per.erl | 30 +++-- lib/asn1/src/asn1ct_imm.erl | 16 ++- lib/asn1/src/asn1rtt_ber.erl | 140 ++++++++++------------- lib/asn1/src/asn1rtt_per.erl | 198 +-------------------------------- lib/asn1/src/asn1rtt_per_common.erl | 33 +++++- lib/asn1/src/asn1rtt_uper.erl | 147 +----------------------- 7 files changed, 145 insertions(+), 450 deletions(-) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl index 0826384365..e7414a2040 100644 --- a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl +++ b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl @@ -518,19 +518,8 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) -> need(decode_enumerated, 3); 'REAL' -> ok; - {'BIT STRING',NamedNumberList} -> - case get(compact_bit_string) of - true -> - emit(["decode_compact_bit_string(", - BytesVar,",",{asis,Constraint},",", - {asis,NamedNumberList},","]), - need(decode_compact_bit_string, 4); - _ -> - emit(["decode_bit_string(",BytesVar,",", - {asis,Constraint},",", - {asis,NamedNumberList},","]), - need(decode_bit_string, 4) - end; + {'BIT STRING',_NamedNumberList} -> + ok; 'NULL' -> emit(["decode_null(",BytesVar,","]), need(decode_null, 2); @@ -634,6 +623,8 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) -> _ when is_list(DoTag) -> {asis,DoTag} end, case NewTypeName of + {'BIT STRING',NNL} -> + gen_dec_bit_string(BytesVar, Constraint, NNL, TagStr); 'REAL' -> asn1ct_name:new(tmpbuf), emit(["begin",nl, @@ -660,6 +651,20 @@ int_constr(SingleValue,[]) -> SingleValue; int_constr(SV,VR) -> [SV,VR]. + +gen_dec_bit_string(BytesVar, _Constraint, [_|_]=NNL, TagStr) -> + call(decode_named_bit_string, + [BytesVar,{asis,NNL},TagStr]); +gen_dec_bit_string(BytesVar, Constraint, [], TagStr) -> + case get(compact_bit_string) of + true -> + call(decode_compact_bit_string, + [BytesVar,{asis,Constraint},TagStr]); + _ -> + call(decode_legacy_bit_string, + [BytesVar,{asis,Constraint},TagStr]) + end. + %% Object code generating for encoding and decoding %% ------------------------------------------------ diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl index 5dda5e9c5d..b7f3a12040 100644 --- a/lib/asn1/src/asn1ct_gen_per.erl +++ b/lib/asn1/src/asn1ct_gen_per.erl @@ -1088,6 +1088,28 @@ gen_dec_imm_1('ASN1_OPEN_TYPE', Constraint, Aligned) -> imm_decode_open_type(Constraint, Aligned); gen_dec_imm_1('ANY', _Constraint, Aligned) -> imm_decode_open_type([], Aligned); +gen_dec_imm_1({'BIT STRING',NNL}, Constr0, Aligned) -> + Constr = get_constraint(Constr0, 'SizeConstraint'), + Imm = asn1ct_imm:per_dec_raw_bitstring(Constr, Aligned), + {F,A} = case NNL of + [] -> + case get(compact_bit_string) of + true -> + {decode_compact_bit_string,1}; + _ -> + {decode_legacy_bit_string,1} + end; + [_|_] -> + {decode_named_bit_string,2} + end, + Dec = fun(V, Buf) -> + As = case A of + 1 -> [V]; + 2 -> [V,{asis,NNL}] + end, + emit(["{",{call,per_common,F,As},com,Buf,"}"]) + end, + {call,Dec,Imm}; gen_dec_imm_1('BOOLEAN', _Constr, _Aligned) -> asn1ct_imm:per_dec_boolean(); gen_dec_imm_1({'ENUMERATED',{Base,Ext}}, _Constr, Aligned) -> @@ -1120,14 +1142,6 @@ gen_dec_prim_1(Erule, #type{def=Typename,constraint=Constraint}=Att, BytesVar) -> case Typename of - {'BIT STRING',NamedNumberList} -> - Func = case get(compact_bit_string) of - true -> decode_compact_bit_string; - _ -> decode_bit_string - end, - call(Erule, Func, - [BytesVar,{asis,Constraint}, - {asis,NamedNumberList}]); 'NULL' -> emit({"{'NULL',",BytesVar,"}"}); 'OBJECT IDENTIFIER' -> diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl index 384d4a86bb..7eb807aa5e 100644 --- a/lib/asn1/src/asn1ct_imm.erl +++ b/lib/asn1/src/asn1ct_imm.erl @@ -18,7 +18,8 @@ %% %% -module(asn1ct_imm). --export([per_dec_boolean/0,per_dec_enumerated/2,per_dec_enumerated/3, +-export([per_dec_raw_bitstring/2, + per_dec_boolean/0,per_dec_enumerated/2,per_dec_enumerated/3, per_dec_extension_map/1, per_dec_integer/2,per_dec_length/3,per_dec_named_integer/3, per_dec_octet_string/2,per_dec_open_type/1,per_dec_real/1]). @@ -103,6 +104,9 @@ per_dec_named_integer(Constraint, NamedList0, Aligned) -> per_dec_octet_string(Constraint, Aligned) -> dec_string(Constraint, 8, Aligned). +per_dec_raw_bitstring(Constraint, Aligned) -> + dec_string(Constraint, 1, Aligned). + per_dec_open_type(Aligned) -> {get_bits,decode_unconstrained_length(true, Aligned), [8,binary,{align,Aligned}]}. @@ -124,7 +128,7 @@ dec_string(Sv, U, _Aligned) when is_integer(Sv), U*Sv =< 16 -> {get_bits,Sv,[U,binary]}; dec_string(Sv, U, Aligned) when is_integer(Sv), Sv < 16#10000 -> {get_bits,Sv,[U,binary,{align,Aligned}]}; -dec_string(C, U, Aligned) when is_list(C) -> +dec_string([_|_]=C, U, Aligned) when is_list(C) -> dec_string({hd(C),lists:max(C)}, U, Aligned); dec_string({Sv,Sv}, U, Aligned) -> dec_string(Sv, U, Aligned); @@ -524,8 +528,6 @@ dcg_list_inside([{get_bits,{Sz,_},Fl0,{Dst,DstBuf}}|T], _) -> dcg_list_inside(T, DstBuf); dcg_list_inside(L, Dst) -> {L,Dst}. -bit_flags([1|T], Acc) -> - bit_flags(T, Acc); bit_flags([{align,_}|T], Acc) -> bit_flags(T, Acc); bit_flags([non_zero|T], Acc) -> @@ -537,7 +539,11 @@ bit_flags([H|T], Acc) -> bit_flags([], []) -> ""; bit_flags([], Acc) -> - "/" ++ bit_flags_1(Acc, ""). + case "/" ++ bit_flags_1(Acc, "") of + "/unit:1" -> []; + Opts -> Opts + end. + bit_flags_1([H|T], Sep) -> Sep ++ H ++ bit_flags_1(T, "-"); diff --git a/lib/asn1/src/asn1rtt_ber.erl b/lib/asn1/src/asn1rtt_ber.erl index f3f6875eb3..e086612818 100644 --- a/lib/asn1/src/asn1rtt_ber.erl +++ b/lib/asn1/src/asn1rtt_ber.erl @@ -29,8 +29,10 @@ encode_integer/2,encode_integer/3, decode_integer/3,decode_integer/4, encode_enumerated/2,decode_enumerated/3, - encode_bit_string/4,decode_bit_string/4, - decode_compact_bit_string/4, + encode_bit_string/4, + decode_named_bit_string/3, + decode_compact_bit_string/3, + decode_legacy_bit_string/3, decode_octet_string/3, encode_null/2,decode_null/2, encode_relative_oid/2,decode_relative_oid/2, @@ -1041,35 +1043,32 @@ unused_bitlist([Bit | Rest], Trail, Ack) -> %%============================================================================ %% decode bitstring value -%% (Buffer, Range, NamedNumberList, HasTag, TotalLen) -> {Integer, Remain, RemovedBytes} %%============================================================================ -decode_compact_bit_string(Buffer, Range, NamedNumberList, Tags) -> - decode_restricted_string(Buffer, Range, ?N_BIT_STRING, Tags, - NamedNumberList, bin). - -decode_bit_string(Buffer, Range, NamedNumberList, Tags) -> - decode_restricted_string(Buffer, Range, ?N_BIT_STRING, Tags, - NamedNumberList, old). - +decode_compact_bit_string(Buffer, Range, Tags) -> + case match_and_collect(Buffer, Tags) of + <<0>> -> + check_restricted_string({0,<<>>}, 0, Range); + <> -> + Val = {Unused,Bits}, + Len = bit_size(Bits) - Unused, + check_restricted_string(Val, Len, Range) + end. -decode_bit_string2(<<0>>, _NamedNumberList, BinOrOld) -> - case BinOrOld of - bin -> - {0,<<>>}; - _ -> - [] - end; -decode_bit_string2(<>, NamedNumberList, BinOrOld) -> - case NamedNumberList of - [] -> - case BinOrOld of - bin -> - {Unused,Bits}; - _ -> - decode_bitstring2(byte_size(Bits), Unused, Bits) - end; - _ -> +decode_legacy_bit_string(Buffer, Range, Tags) -> + Val = case match_and_collect(Buffer, Tags) of + <<0>> -> + []; + <> -> + decode_bitstring2(byte_size(Bits), Unused, Bits) + end, + check_restricted_string(Val, length(Val), Range). + +decode_named_bit_string(Buffer, NamedNumberList, Tags) -> + case match_and_collect(Buffer, Tags) of + <<0>> -> + []; + <> -> BitString = decode_bitstring2(byte_size(Bits), Unused, Bits), decode_bitstring_NNL(BitString, NamedNumberList) end. @@ -1114,8 +1113,7 @@ decode_bitstring_NNL([0|BitList],NamedNumberList,No,Result) -> %% Octet string is decoded as a restricted string %%============================================================================ decode_octet_string(Buffer, Range, Tags) -> - decode_restricted_string(Buffer, Range, ?N_OCTET_STRING, - Tags, [], old). + decode_restricted_string(Buffer, Range, ?N_OCTET_STRING, Tags). %%============================================================================ %% Null value, ITU_T X.690 Chapter 8.8 @@ -1252,33 +1250,15 @@ encode_restricted_string(OctetList, TagIn) when is_list(OctetList) -> %%============================================================================ %% decode Numeric Printable Teletex Videotex Visible IA5 Graphic General strings -%% (Buffer, Range, StringType, HasTag, TotalLen) -> -%% {String, Remain, RemovedBytes} %%============================================================================ -decode_restricted_string(Buffer, Range, StringType, Tags) -> - decode_restricted_string(Buffer, Range, StringType, Tags, [], old). - -decode_restricted_string(Tlv, Range, StringType, TagsIn, - NamedNumberList, BinOrOld) -> - Val = match_tags(Tlv, TagsIn), - Val2 = - case Val of - [_|_]=PartList -> % constructed val - Bin = collect_parts(PartList), - decode_restricted(Bin, StringType, - NamedNumberList, BinOrOld); - Bin -> - decode_restricted(Bin, StringType, - NamedNumberList, BinOrOld) - end, - check_and_convert_restricted_string(Val2, StringType, Range, - NamedNumberList, BinOrOld). +decode_restricted_string(Tlv, Range, StringType, TagsIn) -> + Bin = match_and_collect(Tlv, TagsIn), + Val = decode_restricted(Bin, StringType), + check_and_convert_restricted_string(Val, Range). -decode_restricted(Bin, StringType, NamedNumberList, BinOrOld) -> +decode_restricted(Bin, StringType) -> case StringType of - ?N_BIT_STRING -> - decode_bit_string2(Bin, NamedNumberList, BinOrOld); ?N_UniversalString -> mk_universal_string(binary_to_list(Bin)); ?N_BMPString -> @@ -1287,42 +1267,35 @@ decode_restricted(Bin, StringType, NamedNumberList, BinOrOld) -> Bin end. +check_and_convert_restricted_string(Val0, Range) -> + {Len,Val} = if is_binary(Val0) -> + {byte_size(Val0),binary_to_list(Val0)}; + is_list(Val0) -> + {length(Val0),Val0} + end, + check_restricted_string(Val, Len, Range). -check_and_convert_restricted_string(Val,StringType,Range,NamedNumberList,_BinOrOld) -> - {StrLen,NewVal} = case StringType of - ?N_BIT_STRING when NamedNumberList =/= [] -> - {no_check,Val}; - ?N_BIT_STRING when is_list(Val) -> - {length(Val),Val}; - ?N_BIT_STRING when is_tuple(Val) -> - {(byte_size(element(2,Val))*8) - element(1,Val),Val}; - _ when is_binary(Val) -> - {byte_size(Val),binary_to_list(Val)}; - _ when is_list(Val) -> - {length(Val), Val} - end, +check_restricted_string(Val, StrLen, Range) -> case Range of - _ when StrLen =:= no_check -> - NewVal; - [] -> % No length constraint - NewVal; + [] -> % No length constraint + Val; {Lb,Ub} when StrLen >= Lb, Ub >= StrLen -> % variable length constraint - NewVal; + Val; {{Lb,_Ub},[]} when StrLen >= Lb -> - NewVal; + Val; {{Lb,_Ub},_Ext=[Min|_]} when StrLen >= Lb; StrLen >= Min -> - NewVal; + Val; {{Lb1,Ub1},{Lb2,Ub2}} when StrLen >= Lb1, StrLen =< Ub1; StrLen =< Ub2, StrLen >= Lb2 -> - NewVal; + Val; StrLen -> % fixed length constraint - NewVal; + Val; {_,_} -> exit({error,{asn1,{length,Range,Val}}}); _Len when is_integer(_Len) -> exit({error,{asn1,{length,Range,Val}}}); _ -> % some strange constraint that we don't support yet - NewVal + Val end. @@ -1351,8 +1324,7 @@ mk_uni_list([H|T],List) -> %%=========================================================================== decode_universal_string(Buffer, Range, Tags) -> - decode_restricted_string(Buffer, Range, ?N_UniversalString, - Tags, [], old). + decode_restricted_string(Buffer, Range, ?N_UniversalString, Tags). mk_universal_string(In) -> @@ -1414,8 +1386,7 @@ mk_BMP_list([H|T], List) -> %% {String, Remain, RemovedBytes} %%============================================================================ decode_BMP_string(Buffer, Range, Tags) -> - decode_restricted_string(Buffer, Range, ?N_BMPString, - Tags, [], old). + decode_restricted_string(Buffer, Range, ?N_BMPString, Tags). mk_BMP_string(In) -> mk_BMP_string(In,[]). @@ -1563,6 +1534,15 @@ dynsort_decode_tag(<<_:1,PartialTag:7,Buffer/binary>>, TagAcc0) -> %% INTERNAL HELPER FUNCTIONS (not exported) %%------------------------------------------------------------------------- +match_and_collect(Tlv, TagsIn) -> + Val = match_tags(Tlv, TagsIn), + case Val of + [_|_]=PartList -> % constructed val + collect_parts(PartList); + Bin when is_binary(Bin) -> + Bin + end. + get_constraint(C, Key) -> case lists:keyfind(Key, 1, C) of false -> diff --git a/lib/asn1/src/asn1rtt_per.erl b/lib/asn1/src/asn1rtt_per.erl index a7bbc33a19..d0a4de65e0 100644 --- a/lib/asn1/src/asn1rtt_per.erl +++ b/lib/asn1/src/asn1rtt_per.erl @@ -25,8 +25,7 @@ encode_constrained_number/2, encode_length/1, encode_length/2, - decode_compact_bit_string/3, - encode_bit_string/3, decode_bit_string/3, + encode_bit_string/3, encode_object_identifier/1, decode_object_identifier/1, encode_relative_oid/1, decode_relative_oid/1, complete/1, @@ -99,20 +98,6 @@ getchoice(Bytes, NumChoices, 0) -> decode_constrained_number(Bytes, {0,NumChoices-1}). -%% getbits_as_binary(Num,Bytes) -> {Bin,Rest} -%% Num = integer(), -%% Bytes = bitstring(), -%% Bin = bitstring(), -%% Rest = bitstring() -getbits_as_binary(Num,Bytes) when is_bitstring(Bytes) -> - <> = Bytes, - {BS,Rest}. - -getbits_as_list(Num,Bytes) when is_bitstring(Bytes) -> - <> = Bytes, - {[ B || <> <= BitStr],Rest}. - - getbit(Buffer) -> <> = Buffer, {B,Rest}. @@ -201,42 +186,6 @@ set_choice_tag(Alt,[_H|Rest],Tag) -> set_choice_tag(_Alt,[],_Tag) -> false. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_fragmented_XXX; decode of values encoded fragmented according -%% to ITU-T X.691 clause 10.9.3.8. The unit (XXX) is either bits, octets, -%% characters or number of components (in a choice,sequence or similar). -%% Buffer is a buffer binary(). -%% C is the constrained length. -%% If the buffer is not aligned, this function does that. -decode_fragmented_bits(Buffer, C) when is_binary(Buffer) -> - decode_fragmented_bits(Buffer, C, []); -decode_fragmented_bits(Buffer,C) when is_bitstring(Buffer) -> - AlignBits = bit_size(Buffer) rem 8, - <<_:AlignBits,Rest/binary>> = Buffer, - decode_fragmented_bits(Rest,C,[]). - -decode_fragmented_bits(<<3:2,Len:6,Bin/binary>>, C, Acc) -> - {Value,Bin2} = split_binary(Bin, Len * ?'16K'), % Len = 1 | 2 | 3 | 4 - decode_fragmented_bits(Bin2,C,[Value|Acc]); -decode_fragmented_bits(<<0:1,0:7,Bin/binary>>, C, Acc) -> - BinBits = erlang:list_to_bitstring(lists:reverse(Acc)), - case C of - Int when is_integer(Int), C =:= bit_size(BinBits) -> - {BinBits,Bin}; - Int when is_integer(Int) -> - exit({error,{asn1,{illegal_value,C,BinBits}}}) - end; -decode_fragmented_bits(<<0:1,Len:7,Bin/binary>>, C, Acc) -> - <> = Bin, - BinBits = erlang:list_to_bitstring([Value|Acc]), - case C of - Int when is_integer(Int), C =:= bit_size(BinBits) -> - {BinBits,Rest}; - Int when is_integer(Int) -> - exit({error,{asn1,{illegal_value,C,BinBits}}}) - end. - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% encode_open_type(Constraint, Value) -> CompleteList %% Value = list of bytes of an already encoded value (the list must be flat) @@ -793,138 +742,6 @@ trailingZeroesInNibble(14) -> trailingZeroesInNibble(15) -> 0. -%%%%%%%%%%%%%%% -%% The result is presented as a list of named bits (if possible) -%% else as a tuple {Unused,Bits}. Unused is the number of unused -%% bits, least significant bits in the last byte of Bits. Bits is -%% the BIT STRING represented as a binary. -%% -decode_compact_bit_string(Buffer, C, NamedNumberList) -> - case get_constraint(C,'SizeConstraint') of - 0 -> % fixed length - {{8,0},Buffer}; - V when is_integer(V),V=<16 -> %fixed length 16 bits or less - compact_bit_string(Buffer,V,NamedNumberList); - V when is_integer(V),V=<65536 -> %fixed length > 16 bits - Bytes2 = align(Buffer), - compact_bit_string(Bytes2,V,NamedNumberList); - V when is_integer(V) -> % V > 65536 => fragmented value - {BitStr,Buffer2} = decode_fragmented_bits(Buffer,V), - case bit_size(BitStr) band 7 of - 0 -> {{0,BitStr},Buffer2}; - N -> {{8-N,<>},Buffer2} - end; - {Lb,Ub} when is_integer(Lb),is_integer(Ub) -> - %% This case may demand decoding of fragmented length/value - {Len,Bytes2} = decode_length(Buffer, {Lb,Ub}), - Bytes3 = align(Bytes2), - compact_bit_string(Bytes3,Len,NamedNumberList); - no -> - %% This case may demand decoding of fragmented length/value - {Len,Bytes2} = decode_length(Buffer, undefined), - Bytes3 = align(Bytes2), - compact_bit_string(Bytes3,Len,NamedNumberList); - {{Fix,Fix},Ext} = Sc when is_integer(Fix), is_list(Ext) -> - case decode_length(Buffer,Sc) of - {Len,Bytes2} when Len > Fix -> - Bytes3 = align(Bytes2), - compact_bit_string(Bytes3,Len,NamedNumberList); - {Len,Bytes2} when Len > 16 -> - Bytes3 = align(Bytes2), - compact_bit_string(Bytes3,Len,NamedNumberList); - {Len,Bytes2} -> - compact_bit_string(Bytes2,Len,NamedNumberList) - end; - Sc -> - {Len,Bytes2} = decode_length(Buffer,Sc), - Bytes3 = align(Bytes2), - compact_bit_string(Bytes3,Len,NamedNumberList) - end. - - -%%%%%%%%%%%%%%% -%% The result is presented as a list of named bits (if possible) -%% else as a list of 0 and 1. -%% -decode_bit_string(Buffer, C, NamedNumberList) -> - case get_constraint(C,'SizeConstraint') of - {Lb,Ub} when is_integer(Lb),is_integer(Ub) -> - {Len,Bytes2} = decode_length(Buffer,{Lb,Ub}), - Bytes3 = align(Bytes2), - bit_list_or_named(Bytes3,Len,NamedNumberList); - no -> - {Len,Bytes2} = decode_length(Buffer,undefined), - Bytes3 = align(Bytes2), - bit_list_or_named(Bytes3,Len,NamedNumberList); - 0 -> % fixed length - {[],Buffer}; % nothing to encode - V when is_integer(V),V=<16 -> % fixed length 16 bits or less - bit_list_or_named(Buffer,V,NamedNumberList); - V when is_integer(V),V=<65536 -> - Bytes2 = align(Buffer), - bit_list_or_named(Bytes2,V,NamedNumberList); - V when is_integer(V) -> - Bytes2 = align(Buffer), - {BinBits,_Bytes3} = decode_fragmented_bits(Bytes2,V), - bit_list_or_named(BinBits,V,NamedNumberList); - {{Fix,Fix},Ext} =Sc when is_integer(Fix), is_list(Ext) -> - case decode_length(Buffer,Sc) of - {Len,Bytes2} when Len > Fix -> - Bytes3 = align(Bytes2), - bit_list_or_named(Bytes3,Len,NamedNumberList); - {Len,Bytes2} when Len > 16 -> - Bytes3 = align(Bytes2), - bit_list_or_named(Bytes3,Len,NamedNumberList); - {Len,Bytes2} -> - bit_list_or_named(Bytes2,Len,NamedNumberList) - end; - Sc -> % extension marker - {Len,Bytes2} = decode_length(Buffer,Sc), - Bytes3 = align(Bytes2), - bit_list_or_named(Bytes3,Len,NamedNumberList) - end. - - -%% if no named bits are declared we will return a -%% {Unused,Bits}. Unused = integer(), -%% Bits = binary(). -compact_bit_string(Buffer,Len,[]) -> - {BitStr,Rest} = getbits_as_binary(Len,Buffer), % {{Unused,BinBits},NewBuffer} - PadLen = (8 - (bit_size(BitStr) rem 8)) rem 8, - {{PadLen,<>},Rest}; -compact_bit_string(Buffer,Len,NamedNumberList) -> - bit_list_or_named(Buffer,Len,NamedNumberList). - - -%% if no named bits are declared we will return a -%% BitList = [0 | 1] - -bit_list_or_named(Buffer,Len,[]) -> - getbits_as_list(Len,Buffer); - -%% if there are named bits declared we will return a named -%% BitList where the names are atoms and unnamed bits represented -%% as {bit,Pos} -%% BitList = [atom() | {bit,Pos}] -%% Pos = integer() - -bit_list_or_named(Buffer,Len,NamedNumberList) -> - {BitList,Rest} = getbits_as_list(Len,Buffer), - {bit_list_or_named1(0,BitList,NamedNumberList,[]), Rest}. - -bit_list_or_named1(Pos,[0|Bt],Names,Acc) -> - bit_list_or_named1(Pos+1,Bt,Names,Acc); -bit_list_or_named1(Pos,[1|Bt],Names,Acc) -> - case lists:keyfind(Pos, 2, Names) of - {Name,_} -> - bit_list_or_named1(Pos+1,Bt,Names,[Name|Acc]); - false -> - bit_list_or_named1(Pos+1,Bt,Names,[{bit,Pos}|Acc]) - end; -bit_list_or_named1(_Pos,[],_Names,Acc) -> - lists:reverse(Acc). - - %%%%%%%%%%%%%%% %% @@ -1292,19 +1109,6 @@ decode_relative_oid(Bytes) -> {list_to_tuple(ObjVals),Bytes3}. -get_constraint([{Key,V}],Key) -> - V; -get_constraint([],_) -> - no; -get_constraint(C,Key) -> - case lists:keyfind(Key, 1, C) of - false -> - no; - {_,V} -> - V - end. - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% complete(InList) -> ByteList %% Takes a coded list with bits and bytes and converts it to a list of bytes diff --git a/lib/asn1/src/asn1rtt_per_common.erl b/lib/asn1/src/asn1rtt_per_common.erl index 926f0fe228..2edd240baf 100644 --- a/lib/asn1/src/asn1rtt_per_common.erl +++ b/lib/asn1/src/asn1rtt_per_common.erl @@ -21,7 +21,11 @@ -include("asn1_records.hrl"). --export([decode_fragmented/3]). +-export([decode_fragmented/3, + decode_compact_bit_string/1, + decode_legacy_bit_string/1, + decode_named_bit_string/2]). + -define('16K',16384). decode_fragmented(SegSz0, Buf0, Unit) -> @@ -42,3 +46,30 @@ decode_fragmented_1(<<1:1,1:1,SegSz0:6,Buf0/bitstring>>, Unit, Res0) -> <> = Buf0, Res = <>, decode_fragmented_1(Buf, Unit, Res). + +decode_named_bit_string(Val, NNL) -> + Bits = [B || <> <= Val], + decode_named_bit_string_1(0, Bits, NNL, []). + +decode_legacy_bit_string(Val) -> + [B || <> <= Val]. + +decode_compact_bit_string(Val) -> + PadLen = (8 - (bit_size(Val) band 7)) band 7, + {PadLen,<>}. + +%%% +%%% Internal functions. +%%% + +decode_named_bit_string_1(Pos, [0|Bt], Names, Acc) -> + decode_named_bit_string_1(Pos+1, Bt, Names, Acc); +decode_named_bit_string_1(Pos, [1|Bt], Names, Acc) -> + case lists:keyfind(Pos, 2, Names) of + {Name,_} -> + decode_named_bit_string_1(Pos+1, Bt, Names, [Name|Acc]); + false -> + decode_named_bit_string_1(Pos+1, Bt, Names, [{bit,Pos}|Acc]) + end; +decode_named_bit_string_1(_Pos, [], _Names, Acc) -> + lists:reverse(Acc). diff --git a/lib/asn1/src/asn1rtt_uper.erl b/lib/asn1/src/asn1rtt_uper.erl index d4e2fece67..34971f09e3 100644 --- a/lib/asn1/src/asn1rtt_uper.erl +++ b/lib/asn1/src/asn1rtt_uper.erl @@ -26,8 +26,7 @@ -export([encode_small_number/1, encode_constrained_number/2, encode_boolean/1, encode_length/1, encode_length/2, - decode_compact_bit_string/3]). --export([encode_bit_string/3, decode_bit_string/3]). + encode_bit_string/3]). -export([encode_octet_string/2, encode_relative_oid/1, decode_relative_oid/1, encode_object_identifier/1, decode_object_identifier/1, @@ -132,20 +131,6 @@ getchoice(Bytes,NumChoices,0) -> decode_constrained_number(Bytes,{0,NumChoices-1}). -%% getbits_as_binary(Num,Bytes) -> {{Unused,BinBits},RestBytes}, -%% Num = integer(), -%% Bytes = list() | tuple(), -%% Unused = integer(), -%% BinBits = binary(), -%% RestBytes = tuple() -getbits_as_binary(Num,Bytes) when is_bitstring(Bytes) -> - <> = Bytes, - {BS,Rest}. - -getbits_as_list(Num, Bytes) when is_bitstring(Bytes) -> - <> = Bytes, - {[B || <> <= BitStr],Rest}. - getbit(Buffer) -> <> = Buffer, {B,Rest}. @@ -217,37 +202,6 @@ set_choice_tag(Alt,[_H|Rest],Tag) -> set_choice_tag(_Alt,[],_Tag) -> false. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_fragmented_XXX; decode of values encoded fragmented according -%% to ITU-T X.691 clause 10.9.3.8. The unit (XXX) is either bits, octets, -%% characters or number of components (in a choice,sequence or similar). -%% Buffer is a buffer {Used, Bin}. -%% C is the constrained length. -%% If the buffer is not aligned, this function does that. -decode_fragmented_bits(Buffer,C) -> - decode_fragmented_bits(Buffer,C,[]). -decode_fragmented_bits(<<3:2,Len:6,BitStr/bitstring>>,C,Acc) -> - FragLen = (Len*?'16K') div 8, - <> = BitStr, - decode_fragmented_bits(BitStr2,C,[Value|Acc]); -decode_fragmented_bits(<<0:1,0:7,BitStr/bitstring>>,C,Acc) -> - BinBits = list_to_binary(lists:reverse(Acc)), - case C of - Int when is_integer(Int),C =:= byte_size(BinBits) -> - {BinBits,BitStr}; - Int when is_integer(Int) -> - exit({error,{asn1,{illegal_value,C,BinBits}}}) - end; -decode_fragmented_bits(<<0:1,Len:7,BitStr/bitstring>>,C,Acc) -> - <> = BitStr, - ResBitStr = list_to_bitstring(lists:reverse([Val|Acc])), - case C of - Int when is_integer(Int),C == bit_size(ResBitStr) -> - {ResBitStr,Rest}; - Int when is_integer(Int) -> - exit({error,{asn1,{illegal_value,C,ResBitStr}}}) - end. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% encode_open_type(Constraint, Value) -> CompleteList @@ -708,105 +662,6 @@ trailingZeroesInNibble(14) -> trailingZeroesInNibble(15) -> 0. -%%%%%%%%%%%%%%% -%% The result is presented as a list of named bits (if possible) -%% else as a tuple {Unused,Bits}. Unused is the number of unused -%% bits, least significant bits in the last byte of Bits. Bits is -%% the BIT STRING represented as a binary. -%% -decode_compact_bit_string(Buffer, C, NamedNumberList) -> - case get_constraint(C, 'SizeConstraint') of - 0 -> % fixed length - {{8,0},Buffer}; - V when is_integer(V),V=<16 -> %fixed length 16 bits or less - compact_bit_string(Buffer,V,NamedNumberList); - V when is_integer(V),V=<65536 -> %fixed length > 16 bits - compact_bit_string(Buffer,V,NamedNumberList); - V when is_integer(V) -> % V > 65536 => fragmented value - {Bin,Buffer2} = decode_fragmented_bits(Buffer,V), - PadLen = (8 - (bit_size(Bin) rem 8)) rem 8, - {{PadLen,<>},Buffer2}; - {Lb,Ub} when is_integer(Lb),is_integer(Ub) -> - %% This case may demand decoding of fragmented length/value - {Len,Bytes2} = decode_length(Buffer,{Lb,Ub}), - compact_bit_string(Bytes2,Len,NamedNumberList); - no -> - %% This case may demand decoding of fragmented length/value - {Len,Bytes2} = decode_length(Buffer,undefined), - compact_bit_string(Bytes2,Len,NamedNumberList); - Sc -> - {Len,Bytes2} = decode_length(Buffer,Sc), - compact_bit_string(Bytes2,Len,NamedNumberList) - end. - - -%%%%%%%%%%%%%%% -%% The result is presented as a list of named bits (if possible) -%% else as a list of 0 and 1. -%% -decode_bit_string(Buffer, C, NamedNumberList) -> - case get_constraint(C,'SizeConstraint') of - {Lb,Ub} when is_integer(Lb),is_integer(Ub) -> - {Len,Bytes2} = decode_length(Buffer,{Lb,Ub}), - bit_list_or_named(Bytes2,Len,NamedNumberList); - no -> - {Len,Bytes2} = decode_length(Buffer,undefined), - bit_list_or_named(Bytes2,Len,NamedNumberList); - 0 -> % fixed length - {[],Buffer}; % nothing to encode - V when is_integer(V),V=<16 -> % fixed length 16 bits or less - bit_list_or_named(Buffer,V,NamedNumberList); - V when is_integer(V),V=<65536 -> - bit_list_or_named(Buffer,V,NamedNumberList); - V when is_integer(V) -> - {BinBits,_} = decode_fragmented_bits(Buffer,V), - bit_list_or_named(BinBits,V,NamedNumberList); - Sc -> % extension marker - {Len,Bytes2} = decode_length(Buffer,Sc), - bit_list_or_named(Bytes2,Len,NamedNumberList) - end. - - -%% if no named bits are declared we will return a -%% {Unused,Bits}. Unused = integer(), -%% Bits = binary(). -compact_bit_string(Buffer, Len, []) -> - {BitStr,Rest} = getbits_as_binary(Len,Buffer), % {{Unused,BinBits},NewBuffer} - PadLen = (8 - (bit_size(BitStr) rem 8)) rem 8, - {{PadLen,<>},Rest}; -compact_bit_string(Buffer, Len, NamedNumberList) -> - bit_list_or_named(Buffer, Len, NamedNumberList). - - -%% if no named bits are declared we will return a -%% BitList = [0 | 1] - -bit_list_or_named(Buffer,Len,[]) -> - getbits_as_list(Len,Buffer); - -%% if there are named bits declared we will return a named -%% BitList where the names are atoms and unnamed bits represented -%% as {bit,Pos} -%% BitList = [atom() | {bit,Pos}] -%% Pos = integer() - -bit_list_or_named(Buffer,Len,NamedNumberList) -> - {BitList,Rest} = getbits_as_list(Len,Buffer), - {bit_list_or_named1(0,BitList,NamedNumberList,[]), Rest}. - -bit_list_or_named1(Pos,[0|Bt],Names,Acc) -> - bit_list_or_named1(Pos+1,Bt,Names,Acc); -bit_list_or_named1(Pos,[1|Bt],Names,Acc) -> - case lists:keyfind(Pos, 2, Names) of - {Name,_} -> - bit_list_or_named1(Pos+1,Bt,Names,[Name|Acc]); - false -> - bit_list_or_named1(Pos+1,Bt,Names,[{bit,Pos}|Acc]) - end; -bit_list_or_named1(_,[],_,Acc) -> - lists:reverse(Acc). - - %%%%%%%%%%%%%%% %% -- cgit v1.2.3 From 34baa02a2c41cfbc8c0f53da93157ec28e0c9d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Sat, 22 Dec 2012 06:48:01 +0100 Subject: BER run-time: Refactor decoding of string data types In the BER run-time code (asn1rtt_ber), there is a general function for decoding a string: decode_restricted_string(Tlv, Range, StringType, TagsIn) But the StringType argument is not important. It is only used internally in asn1rtt_ber to distinguish universal strings and BMP strings from other strings. By slightly refactoring the string decoding code, we can eliminate the StringType argument and a subsequent run-time test on the string type. That will slightly reduce code size, slightly increase speed, and eliminate Dialyzer warnings. --- lib/asn1/src/asn1ct_gen_ber_bin_v2.erl | 74 +++++++++++----------------------- lib/asn1/src/asn1rtt_ber.erl | 49 ++++++---------------- 2 files changed, 36 insertions(+), 87 deletions(-) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl index e7414a2040..fe5b5031b6 100644 --- a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl +++ b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl @@ -495,10 +495,19 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) -> _ -> "" end, NewTypeName = case Typename of - 'ANY' -> 'ASN1_OPEN_TYPE'; - _ -> Typename + 'ANY' -> 'ASN1_OPEN_TYPE'; + 'OCTET STRING' -> restricted_string; + 'NumericString' -> restricted_string; + 'TeletexString' -> restricted_string; + 'T61String' -> restricted_string; + 'VideotexString' -> restricted_string; + 'GraphicString' -> restricted_string; + 'VisibleString' -> restricted_string; + 'GeneralString' -> restricted_string; + 'PrintableString' -> restricted_string; + 'IA5String' -> restricted_string; + _ -> Typename end, -% DoLength = case NewTypeName of 'BOOLEAN'-> emit(["decode_boolean(",BytesVar,","]), @@ -531,54 +540,17 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) -> need(decode_relative_oid, 2); 'ObjectDescriptor' -> emit(["decode_restricted_string(", - BytesVar,",",{asis,Constraint},",", - {asis,?T_ObjectDescriptor},","]), - need(decode_restricted_string, 4); - 'OCTET STRING' -> - emit(["decode_octet_string",AsBin,"(",BytesVar,",", - {asis,Constraint},","]), - need(decode_octet_string, 3); - 'NumericString' -> - emit(["decode_restricted_string",AsBin,"(", - BytesVar,",",{asis,Constraint},",", - {asis,?T_NumericString},","]), - need(decode_restricted_string, 4); - TString when TString == 'TeletexString'; - TString == 'T61String' -> - emit(["decode_restricted_string",AsBin,"(", - BytesVar,",",{asis,Constraint},",", - {asis,?T_TeletexString},","]), - need(decode_restricted_string, 4); - 'VideotexString' -> - emit(["decode_restricted_string",AsBin,"(", - BytesVar,",",{asis,Constraint},",", - {asis,?T_VideotexString},","]), - need(decode_restricted_string, 4); - 'GraphicString' -> - emit(["decode_restricted_string",AsBin,"(", - BytesVar,",",{asis,Constraint},",", - {asis,?T_GraphicString},","]), - need(decode_restricted_string, 4); - 'VisibleString' -> - emit(["decode_restricted_string",AsBin,"(", - BytesVar,",",{asis,Constraint},",", - {asis,?T_VisibleString},","]), - need(decode_restricted_string, 4); - 'GeneralString' -> - emit(["decode_restricted_string",AsBin,"(", - BytesVar,",",{asis,Constraint},",", - {asis,?T_GeneralString},","]), - need(decode_restricted_string, 4); - 'PrintableString' -> - emit(["decode_restricted_string",AsBin,"(", - BytesVar,",",{asis,Constraint},",", - {asis,?T_PrintableString},","]), - need(decode_restricted_string, 4); - 'IA5String' -> - emit(["decode_restricted_string",AsBin,"(", - BytesVar,",",{asis,Constraint},",", - {asis,?T_IA5String},","]), - need(decode_restricted_string, 4); + BytesVar,",",{asis,Constraint},","]), + need(decode_restricted_string, 3); + restricted_string -> + emit(["decode_restricted_string",AsBin,"(",BytesVar,","]), + case Constraint of + [] -> + need(decode_restricted_string, 2); + _ -> + emit([{asis,Constraint},","]), + need(decode_restricted_string, 3) + end; 'UniversalString' -> emit(["decode_universal_string",AsBin,"(", BytesVar,",",{asis,Constraint},","]), diff --git a/lib/asn1/src/asn1rtt_ber.erl b/lib/asn1/src/asn1rtt_ber.erl index e086612818..3c6ab3e1c4 100644 --- a/lib/asn1/src/asn1rtt_ber.erl +++ b/lib/asn1/src/asn1rtt_ber.erl @@ -33,11 +33,11 @@ decode_named_bit_string/3, decode_compact_bit_string/3, decode_legacy_bit_string/3, - decode_octet_string/3, encode_null/2,decode_null/2, encode_relative_oid/2,decode_relative_oid/2, encode_object_identifier/2,decode_object_identifier/2, - encode_restricted_string/2,decode_restricted_string/4, + encode_restricted_string/2, + decode_restricted_string/2,decode_restricted_string/3, encode_universal_string/2,decode_universal_string/3, encode_UTF8_string/2,decode_UTF8_string/2, encode_BMP_string/2,decode_BMP_string/3, @@ -1106,15 +1106,6 @@ decode_bitstring_NNL([1|BitList],NamedNumberList,No,Result) -> decode_bitstring_NNL([0|BitList],NamedNumberList,No,Result) -> decode_bitstring_NNL(BitList,NamedNumberList,No+1,Result). -%%============================================================================ -%% decode octet string -%% (Buffer, Range, HasTag, TotalLen) -> {String, Remain, RemovedBytes} -%% -%% Octet string is decoded as a restricted string -%%============================================================================ -decode_octet_string(Buffer, Range, Tags) -> - decode_restricted_string(Buffer, Range, ?N_OCTET_STRING, Tags). - %%============================================================================ %% Null value, ITU_T X.690 Chapter 8.8 %% @@ -1252,33 +1243,16 @@ encode_restricted_string(OctetList, TagIn) when is_list(OctetList) -> %% decode Numeric Printable Teletex Videotex Visible IA5 Graphic General strings %%============================================================================ -decode_restricted_string(Tlv, Range, StringType, TagsIn) -> +decode_restricted_string(Tlv, TagsIn) -> Bin = match_and_collect(Tlv, TagsIn), - Val = decode_restricted(Bin, StringType), - check_and_convert_restricted_string(Val, Range). - -decode_restricted(Bin, StringType) -> - case StringType of - ?N_UniversalString -> - mk_universal_string(binary_to_list(Bin)); - ?N_BMPString -> - mk_BMP_string(binary_to_list(Bin)); - _ -> - Bin - end. + binary_to_list(Bin). -check_and_convert_restricted_string(Val0, Range) -> - {Len,Val} = if is_binary(Val0) -> - {byte_size(Val0),binary_to_list(Val0)}; - is_list(Val0) -> - {length(Val0),Val0} - end, - check_restricted_string(Val, Len, Range). +decode_restricted_string(Tlv, Range, TagsIn) -> + Bin = match_and_collect(Tlv, TagsIn), + check_restricted_string(binary_to_list(Bin), byte_size(Bin), Range). check_restricted_string(Val, StrLen, Range) -> case Range of - [] -> % No length constraint - Val; {Lb,Ub} when StrLen >= Lb, Ub >= StrLen -> % variable length constraint Val; {{Lb,_Ub},[]} when StrLen >= Lb -> @@ -1324,8 +1298,9 @@ mk_uni_list([H|T],List) -> %%=========================================================================== decode_universal_string(Buffer, Range, Tags) -> - decode_restricted_string(Buffer, Range, ?N_UniversalString, Tags). - + Bin = match_and_collect(Buffer, Tags), + Val = mk_universal_string(binary_to_list(Bin)), + check_restricted_string(Val, length(Val), Range). mk_universal_string(In) -> mk_universal_string(In, []). @@ -1386,7 +1361,9 @@ mk_BMP_list([H|T], List) -> %% {String, Remain, RemovedBytes} %%============================================================================ decode_BMP_string(Buffer, Range, Tags) -> - decode_restricted_string(Buffer, Range, ?N_BMPString, Tags). + Bin = match_and_collect(Buffer, Tags), + Val = mk_BMP_string(binary_to_list(Bin)), + check_restricted_string(Val, length(Val), Range). mk_BMP_string(In) -> mk_BMP_string(In,[]). -- cgit v1.2.3 From 53210f62a94126b643666886dfbefb8bae9e86a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 21 Dec 2012 09:59:29 +0100 Subject: Slightly optimize per encoding of large INTEGERs with constraints --- lib/asn1/src/asn1ct_gen_per_rt2ct.erl | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl index 88e9bc6020..bf08494c5c 100644 --- a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl +++ b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl @@ -535,6 +535,10 @@ emit_enc_integer(_Erule,[{_,{Lb,Ub},Range,_}],Value) when Range =< 65536 -> nl," end",nl]), emit_enc_integer_end_case(); +emit_enc_integer(Erule, [{'ValueRange',{Lb,Ub}=VR}], Value) + when is_integer(Lb), is_integer(Ub) -> + call(Erule, encode_constrained_number, [{asis,VR},Value]); + emit_enc_integer(Erule, C, Value) -> call(Erule, encode_integer, [{asis,C},Value]). -- cgit v1.2.3 From 3f8be66021a5b3ce764181a2f9685ed7bfc81607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 21 Dec 2012 11:09:31 +0100 Subject: Enumeration decoding: Don't emit a default clause if it cannot match Dialyzer will warn for default clauses that cannot possible match. --- lib/asn1/src/asn1ct_imm.erl | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl index 7eb807aa5e..d0459ae60b 100644 --- a/lib/asn1/src/asn1ct_imm.erl +++ b/lib/asn1/src/asn1ct_imm.erl @@ -60,9 +60,17 @@ per_dec_boolean() -> {map,{get_bits,1,[1]},[{0,false},{1,true}]}. per_dec_enumerated(NamedList0, Aligned) -> - Constraint = [{'ValueRange',{0,length(NamedList0)-1}}], - NamedList = per_dec_enumerated_fix_list(NamedList0, [enum_error], 0), + Ub = length(NamedList0) - 1, + Constraint = [{'ValueRange',{0,Ub}}], Int = per_dec_integer(Constraint, Aligned), + EnumTail = case matched_range(Int) of + {0,Ub} -> + %% The error case can never happen. + []; + _ -> + [enum_error] + end, + NamedList = per_dec_enumerated_fix_list(NamedList0, EnumTail, 0), {map,Int,NamedList}. per_dec_enumerated(BaseNamedList, NamedListExt0, Aligned) -> @@ -241,6 +249,16 @@ per_num_bits(N) when N =< 64 -> 6; per_num_bits(N) when N =< 128 -> 7; per_num_bits(N) when N =< 255 -> 8. +matched_range({get_bits,Bits0,[U|Flags]}) when is_integer(U) -> + case lists:member(signed, Flags) of + false -> + Bits = U*Bits0, + {0,(1 bsl Bits) - 1}; + true -> + unknown + end; +matched_range(_Op) -> unknown. + %%% %%% Remove unnecessary aligning to octet boundaries. %%% -- cgit v1.2.3 From 2e57d4603575f492f54409e8235806ee6702944c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 21 Dec 2012 15:08:59 +0100 Subject: uper: Look up some SizeConstraints at compile-time --- lib/asn1/src/asn1ct_gen_per.erl | 12 ++++++++++-- lib/asn1/src/asn1rtt_uper.erl | 31 ++++++++++++++++--------------- 2 files changed, 26 insertions(+), 17 deletions(-) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl index b7f3a12040..a43975a308 100644 --- a/lib/asn1/src/asn1ct_gen_per.erl +++ b/lib/asn1/src/asn1ct_gen_per.erl @@ -158,8 +158,9 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) -> emit_enc_real(Erules, Value); {'BIT STRING',NamedNumberList} -> + SizeConstr = get_constraint(Constraint, 'SizeConstraint'), call(Erules, encode_bit_string, - [{asis,Constraint},Value, + [{asis,SizeConstr},Value, {asis,NamedNumberList}]); 'NULL' -> emit("[]"); @@ -173,7 +174,14 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) -> 'BOOLEAN' -> call(Erules, encode_boolean, [Value]); 'OCTET STRING' -> - call(Erules, encode_octet_string, [{asis,Constraint},Value]); + case get_constraint(Constraint, 'SizeConstraint') of + 0 -> + emit("[]"); + no -> + call(Erules, encode_octet_string, [Value]); + C -> + call(Erules, encode_octet_string, [{asis,C},Value]) + end; 'NumericString' -> call(Erules, encode_NumericString, [{asis,Constraint},Value]); TString when TString == 'TeletexString'; diff --git a/lib/asn1/src/asn1rtt_uper.erl b/lib/asn1/src/asn1rtt_uper.erl index 34971f09e3..a9479471eb 100644 --- a/lib/asn1/src/asn1rtt_uper.erl +++ b/lib/asn1/src/asn1rtt_uper.erl @@ -27,7 +27,7 @@ encode_boolean/1, encode_length/1, encode_length/2, encode_bit_string/3]). --export([encode_octet_string/2, +-export([encode_octet_string/1,encode_octet_string/2, encode_relative_oid/1, decode_relative_oid/1, encode_object_identifier/1, decode_object_identifier/1, complete/1, complete_NFP/1]). @@ -496,10 +496,10 @@ encode_boolean(Val) -> encode_bit_string(C, {Unused,BinBits}=Bin, NamedBitList) when is_integer(Unused), is_binary(BinBits) -> - encode_bin_bit_string(get_constraint(C,'SizeConstraint'),Bin,NamedBitList); + encode_bin_bit_string(C, Bin, NamedBitList); encode_bit_string(C, BitListVal, NamedBitList) -> - encode_bit_string1(get_constraint(C, 'SizeConstraint'), BitListVal, NamedBitList). + encode_bit_string1(C, BitListVal, NamedBitList). %% when the value is a list of named bits encode_bit_string1(C, [FirstVal|_RestVal]=LoNB, NamedBitList) @@ -704,13 +704,20 @@ make_and_set_list([], _) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% X.691:16 -%% encode_octet_string(Constraint,Val) +%% encode_octet_string(Val) +%% encode_octet_string(Constraint, Val) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -encode_octet_string(C,Val) -> - case get_constraint(C,'SizeConstraint') of - 0 -> - <<>>; +encode_octet_string(Val) -> + try + [encode_length(length(Val)),list_to_binary(Val)] + catch + error:{error,{asn1,{encode_length,_}}} -> + encode_fragmented_octet_string(Val) + end. + +encode_octet_string(C, Val) -> + case C of 1 -> list_to_binary(Val); 2 -> @@ -736,16 +743,10 @@ encode_octet_string(C,Val) -> catch error:{error,{asn1,{encode_length,_}}} -> encode_fragmented_octet_string(Val) - end; - no -> - try - [encode_length(length(Val)),list_to_binary(Val)] - catch - error:{error,{asn1,{encode_length,_}}} -> - encode_fragmented_octet_string(Val) end end. + encode_fragmented_octet_string(Val) -> Bin = list_to_binary(Val), efos_1(Bin). -- cgit v1.2.3 From 986e51aa44e78c6fcc566cc8a08827b46325739f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 11 Jan 2013 11:02:40 +0100 Subject: Fix EXTERNAL 1990/1994 conversion information loss There are two different definitions of the EXTERNAL data type in ASN.1: the original from 1990 and an updated from 1994. Both defintions are encoded in the same way (in BER). There are still systems in use that use the old definition of EXTERNAL, so the asn1 application must still support both. It has been decided that the asn1 application should handle both the forms without any compiler options. Internally the asn1 application uses the 1990 definition. The encode functions will accept both definitions, but translate the 1994 format to the 1990 format if needed. When decoding, it will decode to the 1990 definition format first and then translate to the 1994 defintion format. One problem with this approach is that the conversion to the 1994 format may not be loss-less (where the 1990 defintion had a CHOICE between an OPEN TYPE, OCTET STRING, or BIT STRING, the 1994 definition only supports an OCTET STRING), and therefore it might not be possible to correctly re-encode the data in the 1990 format. It seems that the only reliable way to handle that problem is to not do the conversion to the 1994 format if the conversion is not loss-less. (There is an attempt when translating to the 1990 format to recover the CHOICE alternative based on the Erlang type of the data value, but that is neither reliable nor future-proof.) That is, when decoding an EXTERNAL value, the resulting tuple could either conform to the 1990 or 1994 definition, and applications must be prepared to handle that. The mail conversation where this issue was first reported can be found here: http://erlang.org/pipermail/erlang-questions/2011-April/057697.html Reported-by: Harald Welte --- lib/asn1/src/asn1rtt_ext.erl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1rtt_ext.erl b/lib/asn1/src/asn1rtt_ext.erl index 59dbcc16bd..7510b01f17 100644 --- a/lib/asn1/src/asn1rtt_ext.erl +++ b/lib/asn1/src/asn1rtt_ext.erl @@ -62,8 +62,11 @@ transform_to_EXTERNAL1994({'EXTERNAL',DRef,IndRef,Data_v_desc,Encoding}=V) -> {'EXTERNAL_identification_context-negotiation',IndRef,DRef}} end, case Encoding of - {_,Val} when is_list(Val); is_binary(Val) -> + {'octet-aligned',Val} when is_list(Val); is_binary(Val) -> + %% Transform to the EXTERNAL 1994 definition. {'EXTERNAL',Identification,Data_v_desc,Val}; _ -> + %% Keep the EXTERNAL 1990 definition to avoid losing + %% information. V end. -- cgit v1.2.3 From 625d2b01dcaa0b15cc9ff7f98438bcd81a5bddc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 8 Jan 2013 12:29:36 +0100 Subject: Teach encode functions to accept a bitstring term for a BIT STRING We do it in the simplest possible way by converting the bitstring to a compact bitstring tuple. The encoding of BIT STRINGs should be cleaned up and optimized. --- lib/asn1/src/asn1rtt_ber.erl | 4 ++++ lib/asn1/src/asn1rtt_per.erl | 4 ++++ lib/asn1/src/asn1rtt_uper.erl | 4 ++++ 3 files changed, 12 insertions(+) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1rtt_ber.erl b/lib/asn1/src/asn1rtt_ber.erl index 3c6ab3e1c4..7998c24465 100644 --- a/lib/asn1/src/asn1rtt_ber.erl +++ b/lib/asn1/src/asn1rtt_ber.erl @@ -799,6 +799,10 @@ decode_enumerated1(Val, NamedNumberList) -> %% C is constrint Len, only valid when identifiers %%============================================================================ +encode_bit_string(C, Bits, NamedBitList, TagIn) when is_bitstring(Bits) -> + PadLen = (8 - (bit_size(Bits) band 7)) band 7, + Compact = {PadLen,<>}, + encode_bin_bit_string(C, Compact, NamedBitList, TagIn); encode_bit_string(C,Bin={Unused,BinBits},NamedBitList,TagIn) when is_integer(Unused), is_binary(BinBits) -> encode_bin_bit_string(C,Bin,NamedBitList,TagIn); encode_bit_string(C, [FirstVal | RestVal], NamedBitList, TagIn) when is_atom(FirstVal) -> diff --git a/lib/asn1/src/asn1rtt_per.erl b/lib/asn1/src/asn1rtt_per.erl index d0a4de65e0..7903dcf9e9 100644 --- a/lib/asn1/src/asn1rtt_per.erl +++ b/lib/asn1/src/asn1rtt_per.erl @@ -528,6 +528,10 @@ decode_length(Buffer, SingleValue) when is_integer(SingleValue) -> %% Unused = integer(), %% BinBits = binary(). +encode_bit_string(C, Bits, NamedBitList) when is_bitstring(Bits) -> + PadLen = (8 - (bit_size(Bits) band 7)) band 7, + Compact = {PadLen,<>}, + encode_bin_bit_string(C, Compact, NamedBitList); encode_bit_string(C, {Unused,BinBits}=Bin, NamedBitList) when is_integer(Unused), is_binary(BinBits) -> encode_bin_bit_string(C,Bin,NamedBitList); diff --git a/lib/asn1/src/asn1rtt_uper.erl b/lib/asn1/src/asn1rtt_uper.erl index a9479471eb..2d91e0df24 100644 --- a/lib/asn1/src/asn1rtt_uper.erl +++ b/lib/asn1/src/asn1rtt_uper.erl @@ -494,6 +494,10 @@ encode_boolean(Val) -> %% Unused = integer(), %% BinBits = binary(). +encode_bit_string(C, Bits, NamedBitList) when is_bitstring(Bits) -> + PadLen = (8 - (bit_size(Bits) band 7)) band 7, + Compact = {PadLen,<>}, + encode_bit_string(C, Compact, NamedBitList); encode_bit_string(C, {Unused,BinBits}=Bin, NamedBitList) when is_integer(Unused), is_binary(BinBits) -> encode_bin_bit_string(C, Bin, NamedBitList); -- cgit v1.2.3 From 74cee7dc1cc5b0332cd851da4953ebbb98224b5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 8 Jan 2013 10:56:27 +0100 Subject: By default, encode BIT STRING to bitstrings Add the option 'legacy_bit_string' to decode to the old list format. --- lib/asn1/src/asn1ct.erl | 31 +++++++++++++++++---- lib/asn1/src/asn1ct_gen.erl | 13 +++++---- lib/asn1/src/asn1ct_gen_ber_bin_v2.erl | 9 ++++-- lib/asn1/src/asn1ct_gen_per.erl | 51 +++++++++++++++++++++------------- lib/asn1/src/asn1ct_value.erl | 43 ++++++++++++++++++---------- lib/asn1/src/asn1rtt_ber.erl | 11 ++++++++ 6 files changed, 111 insertions(+), 47 deletions(-) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl index 0aa6c4c6a6..46602a3071 100644 --- a/lib/asn1/src/asn1ct.erl +++ b/lib/asn1/src/asn1ct.erl @@ -41,6 +41,7 @@ maybe_rename_function/3,latest_sindex/0,current_sindex/0, set_current_sindex/1,next_sindex/0,maybe_saved_sindex/2, parse_and_save/2,verbose/3,warning/3,warning/4,error/3]). +-export([get_bit_string_format/0]). -include("asn1_records.hrl"). -include_lib("stdlib/include/erl_compile.hrl"). @@ -766,12 +767,9 @@ check({true,M},File,OutFile,Includes,EncodingRule,DbFile,Options,InputMods) -> check({false,M},_,_,_,_,_,_,_) -> {false,M}. -generate({true,{M,_Module,GenTOrV}},OutFile,EncodingRule,Options) -> +generate({true,{M,_Module,GenTOrV}}, OutFile, EncodingRule, Options) -> debug_on(Options), - case lists:member(compact_bit_string,Options) of - true -> put(compact_bit_string,true); - _ -> ok - end, + setup_bit_string_format(Options), put(encoding_options,Options), asn1ct_table:new(check_functions), @@ -793,8 +791,8 @@ generate({true,{M,_Module,GenTOrV}},OutFile,EncodingRule,Options) -> ok end, debug_off(Options), - put(compact_bit_string,false), erase(encoding_options), + cleanup_bit_string_format(), erase(tlv_format), % used in ber erase(class_default_type),% used in ber asn1ct_table:delete(check_functions), @@ -812,6 +810,26 @@ generate({true,{M,_Module,GenTOrV}},OutFile,EncodingRule,Options) -> generate({false,M},_,_,_) -> {false,M}. +setup_bit_string_format(Opts) -> + Format = case {lists:member(compact_bit_string, Opts), + lists:member(legacy_bit_string, Opts)} of + {false,false} -> bitstring; + {true,false} -> compact; + {false,true} -> legacy; + {true,true} -> + Message = "Contradicting options given: " + "compact_bit_string and legacy_bit_string", + exit({error,{asn1,Message}}) + end, + put(bit_string_format, Format). + +cleanup_bit_string_format() -> + erase(bit_string_format). + +get_bit_string_format() -> + get(bit_string_format). + + %% parse_and_save parses an asn1 spec and saves the unchecked parse %% tree in a data base file. %% Does not support multifile compilation files @@ -1067,6 +1085,7 @@ remove_asn_flags(Options) -> X /= get_rule(Options), X /= optimize, X /= compact_bit_string, + X /= legacy_bit_string, X /= debug, X /= asn1config, X /= record_name_prefix]. diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl index 5181ed1fce..c2590d1e44 100644 --- a/lib/asn1/src/asn1ct_gen.erl +++ b/lib/asn1/src/asn1ct_gen.erl @@ -808,7 +808,7 @@ gen_decode_constructed(Erules,Typename,InnerType,D) when is_record(D,typedef) -> pgen_exports(Erules,_Module,{Types,Values,_,_,Objects,ObjectSets}) -> - emit({"-export([encoding_rule/0]).",nl}), + emit(["-export([encoding_rule/0,bit_string_format/0]).",nl]), case Types of [] -> ok; _ -> @@ -918,12 +918,10 @@ gen_selected_decode_exports1([{FuncName,_}|Rest]) -> gen_selected_decode_exports1(Rest). pgen_dispatcher(Erules,_Module,{[],_Values,_,_,_Objects,_ObjectSets}) -> - emit(["encoding_rule() ->",nl]), - emit([{asis,Erules},".",nl,nl]); + gen_info_functions(Erules); pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) -> emit(["-export([encode/2,decode/2,encode_disp/2,decode_disp/2]).",nl,nl]), - emit(["encoding_rule() ->",nl]), - emit([" ",{asis,Erules},".",nl,nl]), + gen_info_functions(Erules), NoFinalPadding = lists:member(no_final_padding,get(encoding_options)), {Call,BytesAsBinary} = case Erules of @@ -1028,6 +1026,11 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) -> emit([nl]), emit({nl,nl}). +gen_info_functions(Erules) -> + emit(["encoding_rule() -> ", + {asis,Erules},".",nl,nl, + "bit_string_format() -> ", + {asis,asn1ct:get_bit_string_format()},".",nl,nl]). gen_decode_partial_incomplete(ber) -> case {asn1ct:read_config_data(partial_incomplete_decode), diff --git a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl index fe5b5031b6..121f452da8 100644 --- a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl +++ b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl @@ -628,12 +628,15 @@ gen_dec_bit_string(BytesVar, _Constraint, [_|_]=NNL, TagStr) -> call(decode_named_bit_string, [BytesVar,{asis,NNL},TagStr]); gen_dec_bit_string(BytesVar, Constraint, [], TagStr) -> - case get(compact_bit_string) of - true -> + case asn1ct:get_bit_string_format() of + compact -> call(decode_compact_bit_string, [BytesVar,{asis,Constraint},TagStr]); - _ -> + legacy -> call(decode_legacy_bit_string, + [BytesVar,{asis,Constraint},TagStr]); + bitstring -> + call(decode_native_bit_string, [BytesVar,{asis,Constraint},TagStr]) end. diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl index a43975a308..b38af3306a 100644 --- a/lib/asn1/src/asn1ct_gen_per.erl +++ b/lib/asn1/src/asn1ct_gen_per.erl @@ -1099,25 +1099,26 @@ gen_dec_imm_1('ANY', _Constraint, Aligned) -> gen_dec_imm_1({'BIT STRING',NNL}, Constr0, Aligned) -> Constr = get_constraint(Constr0, 'SizeConstraint'), Imm = asn1ct_imm:per_dec_raw_bitstring(Constr, Aligned), - {F,A} = case NNL of - [] -> - case get(compact_bit_string) of - true -> - {decode_compact_bit_string,1}; - _ -> - {decode_legacy_bit_string,1} - end; - [_|_] -> - {decode_named_bit_string,2} - end, - Dec = fun(V, Buf) -> - As = case A of - 1 -> [V]; - 2 -> [V,{asis,NNL}] - end, - emit(["{",{call,per_common,F,As},com,Buf,"}"]) - end, - {call,Dec,Imm}; + case NNL of + [] -> + case asn1ct:get_bit_string_format() of + compact -> + gen_dec_bit_string(decode_compact_bit_string, + Imm); + legacy -> + gen_dec_bit_string(decode_legacy_bit_string, + Imm); + bitstring -> + gen_dec_copy_bitstring(Imm) + end; + [_|_] -> + D = fun(V, Buf) -> + As = [V,{asis,NNL}], + Call = {call,per_common,decode_named_bit_string,As}, + emit(["{",Call,com,Buf,"}"]) + end, + {call,D,Imm} + end; gen_dec_imm_1('BOOLEAN', _Constr, _Aligned) -> asn1ct_imm:per_dec_boolean(); gen_dec_imm_1({'ENUMERATED',{Base,Ext}}, _Constr, Aligned) -> @@ -1138,6 +1139,18 @@ gen_dec_imm_1('REAL', _Constraint, Aligned) -> asn1ct_imm:per_dec_real(Aligned); gen_dec_imm_1(_, _, _) -> no. +gen_dec_bit_string(F, Imm) -> + D = fun(V, Buf) -> + emit(["{",{call,per_common,F,[V]},com,Buf,"}"]) + end, + {call,D,Imm}. + +gen_dec_copy_bitstring(Imm) -> + D = fun(V, Buf) -> + emit(["{list_to_bitstring([",V,"]),",Buf,"}"]) + end, + {call,D,Imm}. + gen_dec_prim(Erule, Type, BytesVar) -> case gen_dec_imm(Erule, Type) of no -> diff --git a/lib/asn1/src/asn1ct_value.erl b/lib/asn1/src/asn1ct_value.erl index ed1deec2aa..8f3dc1d8b8 100644 --- a/lib/asn1/src/asn1ct_value.erl +++ b/lib/asn1/src/asn1ct_value.erl @@ -54,7 +54,7 @@ from_type(M,Typename,Type) when is_record(Type,type) -> {notype,_} -> true; {primitive,bif} -> - from_type_prim(Type); + from_type_prim(M, Type); 'ASN1_OPEN_TYPE' -> case Type#type.constraint of [#'Externaltypereference'{type=TrefConstraint}] -> @@ -164,7 +164,7 @@ gen_list(_,_,_,0) -> gen_list(M,Typename,Oftype,N) -> [from_type(M,Typename,Oftype)|gen_list(M,Typename,Oftype,N-1)]. -from_type_prim(D) -> +from_type_prim(M, D) -> C = D#type.constraint, case D#type.def of 'INTEGER' -> @@ -212,18 +212,7 @@ from_type_prim(D) -> NN = [X||{X,_} <- NamedNumberList], case NN of [] -> - Bl1 =lists:reverse(adjust_list(size_random(C),[1,0,1,1])), - Bl2 = lists:reverse(lists:dropwhile(fun(0)->true;(1)->false end,Bl1)), - case {length(Bl2),get_constraint(C,'SizeConstraint')} of - {Len,Len} -> - Bl2; - {_Len,Int} when is_integer(Int) -> - Bl1; - {Len,{Min,_}} when Min > Len -> - Bl1; - _ -> - Bl2 - end; + random_unnamed_bit_string(M, C); _ -> [lists:nth(random(length(NN)),NN)] end; @@ -320,6 +309,32 @@ c_string(C,Default) -> Default end. +random_unnamed_bit_string(M, C) -> + Bl1 = lists:reverse(adjust_list(size_random(C), [1,0,1,1])), + Bl2 = lists:reverse(lists:dropwhile(fun(0)-> true; + (1) -> false + end,Bl1)), + Val = case {length(Bl2),get_constraint(C, 'SizeConstraint')} of + {Len,Len} -> + Bl2; + {_Len,Int} when is_integer(Int) -> + Bl1; + {Len,{Min,_}} when Min > Len -> + Bl1; + _ -> + Bl2 + end, + case M:bit_string_format() of + legacy -> + Val; + bitstring -> + << <> || B <- Val >>; + compact -> + BitString = << <> || B <- Val >>, + PadLen = (8 - (bit_size(BitString) band 7)) band 7, + {PadLen,<>} + end. + %% FIXME: %% random_sign(integer) -> %% case random(2) of diff --git a/lib/asn1/src/asn1rtt_ber.erl b/lib/asn1/src/asn1rtt_ber.erl index 7998c24465..889a421e4f 100644 --- a/lib/asn1/src/asn1rtt_ber.erl +++ b/lib/asn1/src/asn1rtt_ber.erl @@ -33,6 +33,7 @@ decode_named_bit_string/3, decode_compact_bit_string/3, decode_legacy_bit_string/3, + decode_native_bit_string/3, encode_null/2,decode_null/2, encode_relative_oid/2,decode_relative_oid/2, encode_object_identifier/2,decode_object_identifier/2, @@ -1068,6 +1069,16 @@ decode_legacy_bit_string(Buffer, Range, Tags) -> end, check_restricted_string(Val, length(Val), Range). +decode_native_bit_string(Buffer, Range, Tags) -> + case match_and_collect(Buffer, Tags) of + <<0>> -> + check_restricted_string(<<>>, 0, Range); + <> -> + Size = bit_size(Bits) - Unused, + <> = Bits, + check_restricted_string(Val, Size, Range) + end. + decode_named_bit_string(Buffer, NamedNumberList, Tags) -> case match_and_collect(Buffer, Tags) of <<0>> -> -- cgit v1.2.3 From 79c59e5d6199ca3410d97aac47bac3be4f5d3089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Mon, 21 Jan 2013 16:04:39 +0100 Subject: per,uper: Optimize decoding of the string data types --- lib/asn1/src/asn1ct_gen_per.erl | 39 +++++----- lib/asn1/src/asn1ct_gen_per_rt2ct.erl | 75 +++++-------------- lib/asn1/src/asn1ct_imm.erl | 97 ++++++++++++++++++++++++- lib/asn1/src/asn1rtt_per.erl | 64 ---------------- lib/asn1/src/asn1rtt_per_common.erl | 31 +++++++- lib/asn1/src/asn1rtt_uper.erl | 133 +++------------------------------- 6 files changed, 176 insertions(+), 263 deletions(-) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl index b38af3306a..25b0d46295 100644 --- a/lib/asn1/src/asn1ct_gen_per.erl +++ b/lib/asn1/src/asn1ct_gen_per.erl @@ -1131,6 +1131,22 @@ gen_dec_imm_1({'INTEGER',NamedNumberList}, Constraint, Aligned) -> asn1ct_imm:per_dec_named_integer(Constraint, NamedNumberList, Aligned); +gen_dec_imm_1('BMPString'=Type, Constraint, Aligned) -> + gen_dec_k_m_string(Type, Constraint, Aligned); +gen_dec_imm_1('NumericString'=Type, Constraint, Aligned) -> + gen_dec_k_m_string(Type, Constraint, Aligned); +gen_dec_imm_1('PrintableString'=Type, Constraint, Aligned) -> + gen_dec_k_m_string(Type, Constraint, Aligned); +gen_dec_imm_1('VisibleString'=Type, Constraint, Aligned) -> + gen_dec_k_m_string(Type, Constraint, Aligned); +gen_dec_imm_1('IA5String'=Type, Constraint, Aligned) -> + gen_dec_k_m_string(Type, Constraint, Aligned); +gen_dec_imm_1('UniversalString'=Type, Constraint, Aligned) -> + gen_dec_k_m_string(Type, Constraint, Aligned); +gen_dec_imm_1('UTCTime', Constraint, Aligned) -> + gen_dec_k_m_string('VisibleString', Constraint, Aligned); +gen_dec_imm_1('GeneralizedTime', Constraint, Aligned) -> + gen_dec_k_m_string('VisibleString', Constraint, Aligned); gen_dec_imm_1('OCTET STRING', Constraint, Aligned) -> SzConstr = get_constraint(Constraint, 'SizeConstraint'), Imm = asn1ct_imm:per_dec_octet_string(SzConstr, Aligned), @@ -1151,6 +1167,9 @@ gen_dec_copy_bitstring(Imm) -> end, {call,D,Imm}. +gen_dec_k_m_string(Type, Constraint, Aligned) -> + asn1ct_imm:per_dec_k_m_string(Type, Constraint, Aligned). + gen_dec_prim(Erule, Type, BytesVar) -> case gen_dec_imm(Erule, Type) of no -> @@ -1171,9 +1190,6 @@ gen_dec_prim_1(Erule, call(Erule, decode_relative_oid, [BytesVar]); 'ObjectDescriptor' -> call(Erule, decode_ObjectDescriptor, [BytesVar]); - 'NumericString' -> - call(Erule, decode_NumericString, - [BytesVar,{asis,Constraint}]); TString when TString == 'TeletexString'; TString == 'T61String' -> call(Erule, decode_TeletexString, @@ -1181,27 +1197,10 @@ gen_dec_prim_1(Erule, 'VideotexString' -> call(Erule, decode_VideotexString, [BytesVar,{asis,Constraint}]); - 'UTCTime' -> - call(Erule, decode_VisibleString, [BytesVar,{asis,Constraint}]); - 'GeneralizedTime' -> - call(Erule, decode_VisibleString, [BytesVar,{asis,Constraint}]); 'GraphicString' -> call(Erule, decode_GraphicString,[BytesVar,{asis,Constraint}]); - 'VisibleString' -> - call(Erule, decode_VisibleString, [BytesVar,{asis,Constraint}]); 'GeneralString' -> call(Erule, decode_GeneralString, [BytesVar,{asis,Constraint}]); - 'PrintableString' -> - call(Erule, decode_PrintableString, - [BytesVar,{asis,Constraint}]); - 'IA5String' -> - call(Erule, decode_IA5String, [BytesVar,{asis,Constraint}]); - 'BMPString' -> - call(Erule, decode_BMPString, - [BytesVar,{asis,Constraint}]); - 'UniversalString' -> - call(Erule, decode_UniversalString, - [BytesVar,{asis,Constraint}]); 'UTF8String' -> call(Erule, decode_UTF8String, [BytesVar]); #'ObjectClassFieldType'{} -> diff --git a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl index bf08494c5c..b6be3a1a8f 100644 --- a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl +++ b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl @@ -263,54 +263,26 @@ emit_enc_k_m_string(SizeC, NumBits, CharOutTab, Value) -> call(per, encode_known_multiplier_string, [{asis,SizeC},NumBits,{asis,CharOutTab},Value]). -emit_dec_known_multiplier_string(StringType,C,BytesVar) -> - SizeC = get_constraint(C,'SizeConstraint'), - PAlphabC = get_constraint(C,'PermittedAlphabet'), - case {StringType,PAlphabC} of - {'BMPString',{_,_}} -> - exit({error,{asn1, - {'not implemented', - "BMPString with PermittedAlphabet " - "constraint"}}}); - _ -> - ok - end, - NumBits = get_NumBits(C,StringType), - CharInTab = get_CharInTab(C,StringType), - case SizeC of - 0 -> - emit({"{[],",BytesVar,"}"}); - _ -> - call(per, decode_known_multiplier_string, - [{asis,StringType},{asis,SizeC},NumBits, - {asis,CharInTab},BytesVar]) - end. - %% copied from run time module -get_CharOutTab(C,StringType) -> - get_CharTab(C,StringType,out). - -get_CharInTab(C,StringType) -> - get_CharTab(C,StringType,in). - -get_CharTab(C,StringType,InOut) -> +get_CharOutTab(C, StringType) -> case get_constraint(C,'PermittedAlphabet') of {'SingleValue',Sv} -> - get_CharTab2(C,StringType,hd(Sv),lists:max(Sv),Sv,InOut); + get_CharTab2(C, StringType, hd(Sv), lists:max(Sv), Sv); no -> case StringType of 'IA5String' -> {0,16#7F,notab}; 'VisibleString' -> - get_CharTab2(C,StringType,16#20,16#7F,notab,InOut); + get_CharTab2(C, StringType, 16#20, 16#7F, notab); 'PrintableString' -> Chars = lists:sort( " '()+,-./0123456789:=?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), - get_CharTab2(C,StringType,hd(Chars),lists:max(Chars),Chars,InOut); + get_CharTab2(C, StringType, hd(Chars), + lists:max(Chars), Chars); 'NumericString' -> - get_CharTab2(C,StringType,16#20,$9," 0123456789",InOut); + get_CharTab2(C, StringType, 16#20, $9, " 0123456789"); 'UniversalString' -> {0,16#FFFFFFFF,notab}; 'BMPString' -> @@ -318,18 +290,13 @@ get_CharTab(C,StringType,InOut) -> end end. -get_CharTab2(C,StringType,Min,Max,Chars,InOut) -> +get_CharTab2(C, StringType, Min, Max, Chars) -> BitValMax = (1 bsl get_NumBits(C,StringType))-1, if Max =< BitValMax -> {0,Max,notab}; true -> - case InOut of - out -> - {Min,Max,create_char_tab(Min,Chars)}; - in -> - {Min,Max,list_to_tuple(Chars)} - end + {Min,Max,create_char_tab(Min,Chars)} end. create_char_tab(Min,L) -> @@ -1401,7 +1368,6 @@ gen_decode_user(Erules,D) when is_record(D,typedef) -> gen_dec_prim(Erules,Att,BytesVar) -> Typename = Att#type.def, - Constraint = Att#type.constraint, case Typename of 'INTEGER' -> asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); @@ -1429,8 +1395,7 @@ gen_dec_prim(Erules,Att,BytesVar) -> asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'NumericString' -> - emit_dec_known_multiplier_string('NumericString', - Constraint,BytesVar); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); TString when TString == 'TeletexString'; TString == 'T61String' -> asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); @@ -1439,32 +1404,30 @@ gen_dec_prim(Erules,Att,BytesVar) -> asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'UTCTime' -> - emit_dec_known_multiplier_string('VisibleString', - Constraint,BytesVar); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); + 'GeneralizedTime' -> - emit_dec_known_multiplier_string('VisibleString', - Constraint,BytesVar); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); + 'GraphicString' -> asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'VisibleString' -> - emit_dec_known_multiplier_string('VisibleString', - Constraint,BytesVar); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); + 'GeneralString' -> asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'PrintableString' -> - emit_dec_known_multiplier_string('PrintableString', - Constraint,BytesVar); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'IA5String' -> - emit_dec_known_multiplier_string('IA5String',Constraint,BytesVar); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'BMPString' -> - emit_dec_known_multiplier_string('BMPString',Constraint,BytesVar); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'UniversalString' -> - emit_dec_known_multiplier_string('UniversalString', - Constraint,BytesVar); + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); 'UTF8String' -> asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl index d0459ae60b..fca85fd778 100644 --- a/lib/asn1/src/asn1ct_imm.erl +++ b/lib/asn1/src/asn1ct_imm.erl @@ -21,7 +21,8 @@ -export([per_dec_raw_bitstring/2, per_dec_boolean/0,per_dec_enumerated/2,per_dec_enumerated/3, per_dec_extension_map/1, - per_dec_integer/2,per_dec_length/3,per_dec_named_integer/3, + per_dec_integer/2,per_dec_k_m_string/3, + per_dec_length/3,per_dec_named_integer/3, per_dec_octet_string/2,per_dec_open_type/1,per_dec_real/1]). -export([optimize_alignment/1,optimize_alignment/2, dec_slim_cg/2,dec_code_gen/2]). @@ -109,6 +110,13 @@ per_dec_named_integer(Constraint, NamedList0, Aligned) -> NamedList = [{K,V} || {V,K} <- NamedList0] ++ [integer_default], {map,Int,NamedList}. +per_dec_k_m_string(StringType, Constraint, Aligned) -> + SzConstr = get_constraint(Constraint, 'SizeConstraint'), + N = string_num_bits(StringType, Constraint, Aligned), + Imm = dec_string(SzConstr, N, Aligned), + Chars = char_tab(Constraint, StringType, N), + convert_string(N, Chars, Imm). + per_dec_octet_string(Constraint, Aligned) -> dec_string(Constraint, 8, Aligned). @@ -259,6 +267,93 @@ matched_range({get_bits,Bits0,[U|Flags]}) when is_integer(U) -> end; matched_range(_Op) -> unknown. +string_num_bits(StringType, Constraint, Aligned) -> + case get_constraint(Constraint, 'PermittedAlphabet') of + {'SingleValue',Sv} -> + charbits(length(Sv), Aligned); + no -> + case StringType of + 'IA5String' -> + charbits(128, Aligned); + 'VisibleString' -> + charbits(95, Aligned); + 'PrintableString' -> + charbits(74, Aligned); + 'NumericString' -> + charbits(11, Aligned); + 'UniversalString' -> + 32; + 'BMPString' -> + 16 + end + end. + +charbits(NumChars, false) -> + uper_num_bits(NumChars); +charbits(NumChars, true) -> + 1 bsl uper_num_bits(uper_num_bits(NumChars)). + +convert_string(8, notab, Imm) -> + {convert,binary_to_list,Imm}; +convert_string(NumBits, notab, Imm) when NumBits < 8 -> + Dec = fun(V, Buf) -> + emit(["{",{call,per_common,decode_chars, + [V,NumBits]},com,Buf,"}"]) + end, + {call,Dec,Imm}; +convert_string(NumBits, notab, Imm) when NumBits =:= 16 -> + Dec = fun(V, Buf) -> + emit(["{",{call,per_common,decode_chars_16bit, + [V]},com,Buf,"}"]) + end, + {call,Dec,Imm}; +convert_string(NumBits, notab, Imm) -> + Dec = fun(V, Buf) -> + emit(["{",{call,per_common,decode_big_chars, + [V,NumBits]},com,Buf,"}"]) + end, + {call,Dec,Imm}; +convert_string(NumBits, Chars, Imm) -> + Dec = fun(V, Buf) -> + emit(["{",{call,per_common,decode_chars, + [V,NumBits,{asis,Chars}]},com,Buf,"}"]) + end, + {call,Dec,Imm}. + +char_tab(C, StringType, NumBits) -> + case get_constraint(C, 'PermittedAlphabet') of + {'SingleValue',Sv} -> + char_tab_1(Sv, NumBits); + no -> + case StringType of + 'IA5String' -> + notab; + 'VisibleString' -> + notab; + 'PrintableString' -> + Chars = " '()+,-./0123456789:=?" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz", + char_tab_1(Chars, NumBits); + 'NumericString' -> + char_tab_1(" 0123456789", NumBits); + 'UniversalString' -> + notab; + 'BMPString' -> + notab + end + end. + +char_tab_1(Chars, NumBits) -> + Max = lists:max(Chars), + BitValMax = (1 bsl NumBits) - 1, + if + Max =< BitValMax -> + notab; + true -> + list_to_tuple(lists:sort(Chars)) + end. + %%% %%% Remove unnecessary aligning to octet boundaries. %%% diff --git a/lib/asn1/src/asn1rtt_per.erl b/lib/asn1/src/asn1rtt_per.erl index 7903dcf9e9..bcd74d9da7 100644 --- a/lib/asn1/src/asn1rtt_per.erl +++ b/lib/asn1/src/asn1rtt_per.erl @@ -38,7 +38,6 @@ encode_UTF8String/1,decode_UTF8String/1, encode_octet_string/3, encode_known_multiplier_string/4, - decode_known_multiplier_string/5, octets_to_complete/2]). -define('16K',16384). @@ -871,27 +870,6 @@ decode_restricted_string(Bytes,aligned) -> {Len,Bytes2} = decode_length(Bytes,undefined), getoctets_as_list(Bytes2,Len). -decode_known_multiplier_string(StringType,SizeC,NumBits,CharInTab,Bytes) -> - case SizeC of - Ub when is_integer(Ub), Ub*NumBits =< 16 -> - chars_decode(Bytes,NumBits,StringType,CharInTab,Ub); - Ub when is_integer(Ub),Ub =<65535 -> % fixed length - Bytes1 = align(Bytes), - chars_decode(Bytes1,NumBits,StringType,CharInTab,Ub); - Vl when is_list(Vl) -> - {Len,Bytes1} = decode_length(Bytes,{hd(Vl),lists:max(Vl)}), - Bytes2 = align(Bytes1), - chars_decode(Bytes2,NumBits,StringType,CharInTab,Len); - no -> - {Len,Bytes1} = decode_length(Bytes,undefined), - Bytes2 = align(Bytes1), - chars_decode(Bytes2,NumBits,StringType,CharInTab,Len); - {Lb,Ub}-> - {Len,Bytes1} = decode_length(Bytes,{Lb,Ub}), - Bytes2 = align(Bytes1), - chars_decode(Bytes2,NumBits,StringType,CharInTab,Len) - end. - encode_GeneralString(_C,Val) -> encode_restricted_string(Val). decode_GeneralString(Bytes,_C) -> @@ -918,18 +896,6 @@ decode_VideotexString(Bytes,_C) -> decode_restricted_string(Bytes,aligned). - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% getBMPChars(Bytes,Len) ->{BMPcharList,RemainingBytes} -%% -getBMPChars(<>, 0, Acc) -> - {lists:reverse(Acc),T}; -getBMPChars(<<0,O2,Bytes1/bitstring>>, Len, Acc) -> - getBMPChars(Bytes1,Len-1,[O2|Acc]); -getBMPChars(<>, Len, Acc) -> - getBMPChars(Bytes1,Len-1,[{0,0,O1,O2}|Acc]). - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% chars_encode(C,StringType,Value) -> ValueList %% @@ -970,36 +936,6 @@ pre_complete_bits(NumBits,Val) when NumBits =< 2040 -> % 255 * 8 [30,Unused,Len div 8,<<(Val bsl Unused):Len>>]. -chars_decode(Bytes,_,'BMPString',_,Len) -> - getBMPChars(Bytes,Len,[]); -chars_decode(Bytes,NumBits,_StringType,CharInTab,Len) -> - chars_decode2(Bytes,CharInTab,NumBits,Len). - - -chars_decode2(Bytes,CharInTab,NumBits,Len) -> - chars_decode2(Bytes,CharInTab,NumBits,Len,[]). - -chars_decode2(Bytes,_CharInTab,_NumBits,0,Acc) -> - {lists:reverse(Acc),Bytes}; -chars_decode2(Bytes,{Min,Max,notab},NumBits,Len,Acc) when NumBits > 8 -> - {Char,Bytes2} = getbits(Bytes,NumBits), - Result = - if - Char < 256 -> Char; - true -> - list_to_tuple(binary_to_list(<>)) - end, - chars_decode2(Bytes2,{Min,Max,notab},NumBits,Len -1,[Result|Acc]); -chars_decode2(Bytes,{Min,Max,notab},NumBits,Len,Acc) -> - {Char,Bytes2} = getbits(Bytes,NumBits), - chars_decode2(Bytes2,{Min,Max,notab},NumBits,Len -1,[Char+Min|Acc]); - -%% BMPString and UniversalString with PermittedAlphabet is currently not supported -chars_decode2(Bytes,{Min,Max,CharInTab},NumBits,Len,Acc) -> - {Char,Bytes2} = getbits(Bytes,NumBits), - chars_decode2(Bytes2,{Min,Max,CharInTab},NumBits,Len -1,[element(Char+1,CharInTab)|Acc]). - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% encode_UTF8String(Val) -> CompleteList %% Val -> <> diff --git a/lib/asn1/src/asn1rtt_per_common.erl b/lib/asn1/src/asn1rtt_per_common.erl index 2edd240baf..cd6e9e2c99 100644 --- a/lib/asn1/src/asn1rtt_per_common.erl +++ b/lib/asn1/src/asn1rtt_per_common.erl @@ -24,7 +24,10 @@ -export([decode_fragmented/3, decode_compact_bit_string/1, decode_legacy_bit_string/1, - decode_named_bit_string/2]). + decode_named_bit_string/2, + decode_chars/2,decode_chars/3, + decode_chars_16bit/1, + decode_big_chars/2]). -define('16K',16384). @@ -58,6 +61,20 @@ decode_compact_bit_string(Val) -> PadLen = (8 - (bit_size(Val) band 7)) band 7, {PadLen,<>}. +decode_chars(Val, N) -> + [C || <> <= Val]. + +decode_chars(Val, N, Chars) -> + [element(C+1, Chars) || <> <= Val]. + +decode_chars_16bit(Val) -> + Cs = [C || <> <= Val], + decode_chars_16bit_1(Cs). + +decode_big_chars(Val, N) -> + decode_big_chars_1(decode_chars(Val, N)). + + %%% %%% Internal functions. %%% @@ -73,3 +90,15 @@ decode_named_bit_string_1(Pos, [1|Bt], Names, Acc) -> end; decode_named_bit_string_1(_Pos, [], _Names, Acc) -> lists:reverse(Acc). + +decode_chars_16bit_1([H|T]) when H < 256 -> + [H|decode_chars_16bit_1(T)]; +decode_chars_16bit_1([H|T]) -> + [{0,0,H bsr 8,H band 255}|decode_chars_16bit_1(T)]; +decode_chars_16bit_1([]) -> []. + +decode_big_chars_1([H|T]) when H < 256 -> + [H|decode_big_chars_1(T)]; +decode_big_chars_1([H|T]) -> + [list_to_tuple(binary_to_list(<>))|decode_big_chars_1(T)]; +decode_big_chars_1([]) -> []. diff --git a/lib/asn1/src/asn1rtt_uper.erl b/lib/asn1/src/asn1rtt_uper.erl index 2d91e0df24..92c8d44402 100644 --- a/lib/asn1/src/asn1rtt_uper.erl +++ b/lib/asn1/src/asn1rtt_uper.erl @@ -34,17 +34,17 @@ -export([encode_open_type/1]). - -export([encode_UniversalString/2, decode_UniversalString/2, - encode_PrintableString/2, decode_PrintableString/2, + -export([encode_UniversalString/2, + encode_PrintableString/2, encode_GeneralString/2, decode_GeneralString/2, encode_GraphicString/2, decode_GraphicString/2, encode_TeletexString/2, decode_TeletexString/2, encode_VideotexString/2, decode_VideotexString/2, - encode_VisibleString/2, decode_VisibleString/2, + encode_VisibleString/2, encode_UTF8String/1, decode_UTF8String/1, - encode_BMPString/2, decode_BMPString/2, - encode_IA5String/2, decode_IA5String/2, - encode_NumericString/2, decode_NumericString/2, + encode_BMPString/2, + encode_IA5String/2, + encode_NumericString/2, encode_ObjectDescriptor/2, decode_ObjectDescriptor/1 ]). @@ -799,56 +799,23 @@ decode_restricted_string(Bytes) -> {Len,Bytes2} = decode_length(Bytes, undefined), getoctets_as_list(Bytes2,Len). -decode_known_multiplier_string(Bytes, StringType, C, _Ext) -> - NumBits = get_NumBits(C, StringType), - case get_constraint(C, 'SizeConstraint') of - Ub when is_integer(Ub), Ub*NumBits =< 16 -> - chars_decode(Bytes, NumBits, StringType, C, Ub); - Ub when is_integer(Ub), Ub =<65535 -> % fixed length - chars_decode(Bytes,NumBits,StringType,C,Ub); - 0 -> - {[],Bytes}; - Vl when is_list(Vl) -> - {Len,Bytes1} = decode_length(Bytes,{hd(Vl),lists:max(Vl)}), - chars_decode(Bytes1,NumBits,StringType,C,Len); - no -> - {Len,Bytes1} = decode_length(Bytes,undefined), - chars_decode(Bytes1,NumBits,StringType,C,Len); - {Lb,Ub}-> - {Len,Bytes1} = decode_length(Bytes,{Lb,Ub}), - chars_decode(Bytes1,NumBits,StringType,C,Len) - end. - - encode_NumericString(C,Val) -> encode_known_multiplier_string('NumericString',C,Val). -decode_NumericString(Bytes,C) -> - decode_known_multiplier_string(Bytes,'NumericString',C,false). encode_PrintableString(C,Val) -> encode_known_multiplier_string('PrintableString',C,Val). -decode_PrintableString(Bytes,C) -> - decode_known_multiplier_string(Bytes,'PrintableString',C,false). encode_VisibleString(C,Val) -> % equivalent with ISO646String encode_known_multiplier_string('VisibleString',C,Val). -decode_VisibleString(Bytes,C) -> - decode_known_multiplier_string(Bytes,'VisibleString',C,false). encode_IA5String(C,Val) -> encode_known_multiplier_string('IA5String',C,Val). -decode_IA5String(Bytes,C) -> - decode_known_multiplier_string(Bytes,'IA5String',C,false). encode_BMPString(C,Val) -> encode_known_multiplier_string('BMPString',C,Val). -decode_BMPString(Bytes,C) -> - decode_known_multiplier_string(Bytes,'BMPString',C,false). encode_UniversalString(C,Val) -> encode_known_multiplier_string('UniversalString',C,Val). -decode_UniversalString(Bytes,C) -> - decode_known_multiplier_string(Bytes,'UniversalString',C,false). %% end of known-multiplier strings for which PER visible constraints are @@ -880,33 +847,6 @@ decode_VideotexString(Bytes,_C) -> decode_restricted_string(Bytes). -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% getBMPChars(Bytes, Len) -> {BMPcharList,RemainingBytes} -%% -getBMPChars(Bytes, 1) -> - {O1,Bytes2} = getbits(Bytes, 8), - {O2,Bytes3} = getbits(Bytes2, 8), - if - O1 == 0 -> - {[O2],Bytes3}; - true -> - {[{0,0,O1,O2}],Bytes3} - end; -getBMPChars(Bytes, Len) -> - getBMPChars(Bytes, Len, []). - -getBMPChars(Bytes, 0, Acc) -> - {lists:reverse(Acc),Bytes}; -getBMPChars(Bytes, Len, Acc) -> - {Octs,Bytes1} = getoctets_as_list(Bytes,2), - case Octs of - [0,O2] -> - getBMPChars(Bytes1, Len-1, [O2|Acc]); - [O1,O2]-> - getBMPChars(Bytes1, Len-1, [{0,0,O1,O2}|Acc]) - end. - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% chars_encode(C,StringType,Value) -> ValueList %% @@ -970,27 +910,21 @@ get_NumBits(C,StringType) -> end. get_CharOutTab(C,StringType) -> - get_CharTab(C,StringType,out). - -get_CharInTab(C,StringType) -> - get_CharTab(C,StringType,in). - -get_CharTab(C,StringType,InOut) -> case get_constraint(C,'PermittedAlphabet') of {'SingleValue',Sv} -> - get_CharTab2(C,StringType,hd(Sv),lists:max(Sv),Sv,InOut); + get_CharTab2(C,StringType,hd(Sv),lists:max(Sv),Sv); no -> case StringType of 'IA5String' -> {0,16#7F,notab}; 'VisibleString' -> - get_CharTab2(C,StringType,16#20,16#7F,notab,InOut); + get_CharTab2(C,StringType,16#20,16#7F,notab); 'PrintableString' -> Chars = lists:sort( " '()+,-./0123456789:=?ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), - get_CharTab2(C,StringType,hd(Chars),lists:max(Chars),Chars,InOut); + get_CharTab2(C,StringType,hd(Chars),lists:max(Chars),Chars); 'NumericString' -> - get_CharTab2(C,StringType,16#20,$9," 0123456789",InOut); + get_CharTab2(C,StringType,16#20,$9," 0123456789"); 'UniversalString' -> {0,16#FFFFFFFF,notab}; 'BMPString' -> @@ -998,18 +932,13 @@ get_CharTab(C,StringType,InOut) -> end end. -get_CharTab2(C,StringType,Min,Max,Chars,InOut) -> +get_CharTab2(C,StringType,Min,Max,Chars) -> BitValMax = (1 bsl get_NumBits(C,StringType))-1, if Max =< BitValMax -> {0,Max,notab}; true -> - case InOut of - out -> - {Min,Max,create_char_tab(Min,Chars)}; - in -> - {Min,Max,list_to_tuple(Chars)} - end + {Min,Max,create_char_tab(Min,Chars)} end. create_char_tab(Min,L) -> @@ -1047,44 +976,6 @@ charbits1(NumOfChars) -> 1 + charbits1(NumOfChars bsr 1). -chars_decode(Bytes,_,'BMPString',C,Len) -> - case get_constraint(C,'PermittedAlphabet') of - no -> - getBMPChars(Bytes,Len); - _ -> - exit({error,{asn1, - {'not implemented', - "BMPString with PermittedAlphabet constraint"}}}) - end; -chars_decode(Bytes,NumBits,StringType,C,Len) -> - CharInTab = get_CharInTab(C,StringType), - chars_decode2(Bytes,CharInTab,NumBits,Len). - - -chars_decode2(Bytes,CharInTab,NumBits,Len) -> - chars_decode2(Bytes,CharInTab,NumBits,Len,[]). - -chars_decode2(Bytes,_CharInTab,_NumBits,0,Acc) -> - {lists:reverse(Acc),Bytes}; -chars_decode2(Bytes,{Min,Max,notab},NumBits,Len,Acc) when NumBits > 8 -> - {Char,Bytes2} = getbits(Bytes,NumBits), - Result = - if - Char < 256 -> Char; - true -> - list_to_tuple(binary_to_list(<>)) - end, - chars_decode2(Bytes2,{Min,Max,notab},NumBits,Len -1,[Result|Acc]); -chars_decode2(Bytes,{Min,Max,notab},NumBits,Len,Acc) -> - {Char,Bytes2} = getbits(Bytes,NumBits), - chars_decode2(Bytes2,{Min,Max,notab},NumBits,Len -1,[Char+Min|Acc]); - -%% BMPString and UniversalString with PermittedAlphabet is currently not supported -chars_decode2(Bytes,{Min,Max,CharInTab},NumBits,Len,Acc) -> - {Char,Bytes2} = getbits(Bytes,NumBits), - chars_decode2(Bytes2,{Min,Max,CharInTab},NumBits,Len -1,[element(Char+1,CharInTab)|Acc]). - - %% UTF8String encode_UTF8String(Val) when is_binary(Val) -> [encode_length(byte_size(Val)),Val]; -- cgit v1.2.3 From 26182a5c8cf96fa6d255e23a6d4cd0d2c5248a69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 22 Jan 2013 13:12:20 +0100 Subject: Share all code for dec_gen_prim/3 between per/uper back-ends --- lib/asn1/src/asn1ct_gen_per_rt2ct.erl | 81 +---------------------------------- 1 file changed, 2 insertions(+), 79 deletions(-) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl index b6be3a1a8f..e39af78147 100644 --- a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl +++ b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl @@ -1366,85 +1366,8 @@ gen_decode_user(Erules,D) when is_record(D,typedef) -> -gen_dec_prim(Erules,Att,BytesVar) -> - Typename = Att#type.def, - case Typename of - 'INTEGER' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - {'INTEGER',_NamedNumberList} -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - 'REAL' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - - {'BIT STRING',_} -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - 'NULL' -> - emit({"{'NULL',",BytesVar,"}"}); - 'OBJECT IDENTIFIER' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - 'RELATIVE-OID' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - 'ObjectDescriptor' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - {'ENUMERATED',_} -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - 'BOOLEAN'-> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - - 'OCTET STRING' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - - 'NumericString' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - TString when TString == 'TeletexString'; - TString == 'T61String' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - - 'VideotexString' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - - 'UTCTime' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - - 'GeneralizedTime' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - - 'GraphicString' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - - 'VisibleString' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - - 'GeneralString' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - - 'PrintableString' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - 'IA5String' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - - 'BMPString' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - - 'UniversalString' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - - 'UTF8String' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - 'ANY' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - 'ASN1_OPEN_TYPE' -> - asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar); - #'ObjectClassFieldType'{} -> - case asn1ct_gen:get_inner(Att#type.def) of - {fixedtypevaluefield,_,InnerType} -> - gen_dec_prim(Erules,InnerType,BytesVar); - T -> - gen_dec_prim(Erules,Att#type{def=T},BytesVar) - end; - Other -> - exit({'cant decode' ,Other}) - end. +gen_dec_prim(Erules, Att, BytesVar) -> + asn1ct_gen_per:gen_dec_prim(Erules, Att, BytesVar). %% For PER the ExtensionAdditionGroup notation has significance for the encoding and decoding %% the components within the ExtensionAdditionGroup is treated in a similar way as if they -- cgit v1.2.3 From dc17110cd88153a74900d71d35df608f5d58c0f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 22 Jan 2013 16:48:41 +0100 Subject: per,uper: Optimize decoding of the remaining string types --- lib/asn1/src/asn1ct_gen_per.erl | 35 +++++++++++++++++++---------------- lib/asn1/src/asn1ct_imm.erl | 8 +++++++- lib/asn1/src/asn1rtt_per.erl | 37 ++++++------------------------------- lib/asn1/src/asn1rtt_uper.erl | 30 ++++++------------------------ 4 files changed, 38 insertions(+), 72 deletions(-) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl index 25b0d46295..ddfa39486a 100644 --- a/lib/asn1/src/asn1ct_gen_per.erl +++ b/lib/asn1/src/asn1ct_gen_per.erl @@ -1151,6 +1151,20 @@ gen_dec_imm_1('OCTET STRING', Constraint, Aligned) -> SzConstr = get_constraint(Constraint, 'SizeConstraint'), Imm = asn1ct_imm:per_dec_octet_string(SzConstr, Aligned), {convert,binary_to_list,Imm}; +gen_dec_imm_1('TeletexString', _Constraint, Aligned) -> + gen_dec_restricted_string(Aligned); +gen_dec_imm_1('T61String', _Constraint, Aligned) -> + gen_dec_restricted_string(Aligned); +gen_dec_imm_1('VideotexString', _Constraint, Aligned) -> + gen_dec_restricted_string(Aligned); +gen_dec_imm_1('GraphicString', _Constraint, Aligned) -> + gen_dec_restricted_string(Aligned); +gen_dec_imm_1('GeneralString', _Constraint, Aligned) -> + gen_dec_restricted_string(Aligned); +gen_dec_imm_1('ObjectDescriptor', _Constraint, Aligned) -> + gen_dec_restricted_string(Aligned); +gen_dec_imm_1('UTF8String', _Constraint, Aligned) -> + asn1ct_imm:per_dec_restricted_string(Aligned); gen_dec_imm_1('REAL', _Constraint, Aligned) -> asn1ct_imm:per_dec_real(Aligned); gen_dec_imm_1(_, _, _) -> no. @@ -1170,6 +1184,10 @@ gen_dec_copy_bitstring(Imm) -> gen_dec_k_m_string(Type, Constraint, Aligned) -> asn1ct_imm:per_dec_k_m_string(Type, Constraint, Aligned). +gen_dec_restricted_string(Aligned) -> + Imm = asn1ct_imm:per_dec_restricted_string(Aligned), + {convert,binary_to_list,Imm}. + gen_dec_prim(Erule, Type, BytesVar) -> case gen_dec_imm(Erule, Type) of no -> @@ -1179,7 +1197,7 @@ gen_dec_prim(Erule, Type, BytesVar) -> end. gen_dec_prim_1(Erule, - #type{def=Typename,constraint=Constraint}=Att, + #type{def=Typename}=Att, BytesVar) -> case Typename of 'NULL' -> @@ -1188,21 +1206,6 @@ gen_dec_prim_1(Erule, call(Erule, decode_object_identifier, [BytesVar]); 'RELATIVE-OID' -> call(Erule, decode_relative_oid, [BytesVar]); - 'ObjectDescriptor' -> - call(Erule, decode_ObjectDescriptor, [BytesVar]); - TString when TString == 'TeletexString'; - TString == 'T61String' -> - call(Erule, decode_TeletexString, - [BytesVar,{asis,Constraint}]); - 'VideotexString' -> - call(Erule, decode_VideotexString, - [BytesVar,{asis,Constraint}]); - 'GraphicString' -> - call(Erule, decode_GraphicString,[BytesVar,{asis,Constraint}]); - 'GeneralString' -> - call(Erule, decode_GeneralString, [BytesVar,{asis,Constraint}]); - 'UTF8String' -> - call(Erule, decode_UTF8String, [BytesVar]); #'ObjectClassFieldType'{} -> case asn1ct_gen:get_inner(Typename) of {fixedtypevaluefield,_,InnerType} -> diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl index fca85fd778..87eadac073 100644 --- a/lib/asn1/src/asn1ct_imm.erl +++ b/lib/asn1/src/asn1ct_imm.erl @@ -23,7 +23,8 @@ per_dec_extension_map/1, per_dec_integer/2,per_dec_k_m_string/3, per_dec_length/3,per_dec_named_integer/3, - per_dec_octet_string/2,per_dec_open_type/1,per_dec_real/1]). + per_dec_octet_string/2,per_dec_open_type/1,per_dec_real/1, + per_dec_restricted_string/1]). -export([optimize_alignment/1,optimize_alignment/2, dec_slim_cg/2,dec_code_gen/2]). -export([effective_constraint/2]). @@ -136,6 +137,11 @@ per_dec_real(Aligned) -> {get_bits,decode_unconstrained_length(true, Aligned), [8,binary,{align,Aligned}]}}. +per_dec_restricted_string(Aligned) -> + DecLen = decode_unconstrained_length(true, Aligned), + {get_bits,DecLen,[8,binary]}. + + %%% %%% Local functions. %%% diff --git a/lib/asn1/src/asn1rtt_per.erl b/lib/asn1/src/asn1rtt_per.erl index bcd74d9da7..2bcf459330 100644 --- a/lib/asn1/src/asn1rtt_per.erl +++ b/lib/asn1/src/asn1rtt_per.erl @@ -30,12 +30,12 @@ encode_relative_oid/1, decode_relative_oid/1, complete/1, encode_open_type/1, - encode_GeneralString/2, decode_GeneralString/2, - encode_GraphicString/2, decode_GraphicString/2, - encode_TeletexString/2, decode_TeletexString/2, - encode_VideotexString/2, decode_VideotexString/2, - encode_ObjectDescriptor/2, decode_ObjectDescriptor/1, - encode_UTF8String/1,decode_UTF8String/1, + encode_GeneralString/2, + encode_GraphicString/2, + encode_TeletexString/2, + encode_VideotexString/2, + encode_ObjectDescriptor/2, + encode_UTF8String/1, encode_octet_string/3, encode_known_multiplier_string/4, octets_to_complete/2]). @@ -866,34 +866,20 @@ encode_known_multiplier_string(SizeC, NumBits, CharOutTab, Val) -> [encode_length(length(Val)),2,Result] end. -decode_restricted_string(Bytes,aligned) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - getoctets_as_list(Bytes2,Len). - encode_GeneralString(_C,Val) -> encode_restricted_string(Val). -decode_GeneralString(Bytes,_C) -> - decode_restricted_string(Bytes,aligned). encode_GraphicString(_C,Val) -> encode_restricted_string(Val). -decode_GraphicString(Bytes,_C) -> - decode_restricted_string(Bytes,aligned). encode_ObjectDescriptor(_C,Val) -> encode_restricted_string(Val). -decode_ObjectDescriptor(Bytes) -> - decode_restricted_string(Bytes,aligned). encode_TeletexString(_C,Val) -> % equivalent with T61String encode_restricted_string(Val). -decode_TeletexString(Bytes,_C) -> - decode_restricted_string(Bytes,aligned). encode_VideotexString(_C,Val) -> encode_restricted_string(Val). -decode_VideotexString(Bytes,_C) -> - decode_restricted_string(Bytes,aligned). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -948,17 +934,6 @@ encode_UTF8String(Val) -> encode_UTF8String(list_to_binary(Val)). -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_UTF8String(Bytes) -> {Utf8Binary,RemainingBytes} -%% Utf8Binary -> <> -%% RemainingBytes -> <> -decode_UTF8String(Bytes) -> - {Len,Bytes2} = decode_length(Bytes, undefined), - {_Bin,_Bytes3} = getoctets_as_bin(Bytes2, Len). - - - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% encode_object_identifier(Val) -> CompleteList %% encode_object_identifier({Name,Val}) -> CompleteList diff --git a/lib/asn1/src/asn1rtt_uper.erl b/lib/asn1/src/asn1rtt_uper.erl index 92c8d44402..fa4f08363b 100644 --- a/lib/asn1/src/asn1rtt_uper.erl +++ b/lib/asn1/src/asn1rtt_uper.erl @@ -36,16 +36,16 @@ -export([encode_UniversalString/2, encode_PrintableString/2, - encode_GeneralString/2, decode_GeneralString/2, - encode_GraphicString/2, decode_GraphicString/2, - encode_TeletexString/2, decode_TeletexString/2, - encode_VideotexString/2, decode_VideotexString/2, + encode_GeneralString/2, + encode_GraphicString/2, + encode_TeletexString/2, + encode_VideotexString/2, encode_VisibleString/2, - encode_UTF8String/1, decode_UTF8String/1, + encode_UTF8String/1, encode_BMPString/2, encode_IA5String/2, encode_NumericString/2, - encode_ObjectDescriptor/2, decode_ObjectDescriptor/1 + encode_ObjectDescriptor/2 ]). -define('16K',16384). @@ -795,10 +795,6 @@ encode_known_multiplier_string(StringType, C, Val) -> [encode_length(length(Val)),Result] end. -decode_restricted_string(Bytes) -> - {Len,Bytes2} = decode_length(Bytes, undefined), - getoctets_as_list(Bytes2,Len). - encode_NumericString(C,Val) -> encode_known_multiplier_string('NumericString',C,Val). @@ -823,28 +819,18 @@ encode_UniversalString(C,Val) -> encode_GeneralString(_C,Val) -> encode_restricted_string(Val). -decode_GeneralString(Bytes,_C) -> - decode_restricted_string(Bytes). encode_GraphicString(_C,Val) -> encode_restricted_string(Val). -decode_GraphicString(Bytes,_C) -> - decode_restricted_string(Bytes). encode_ObjectDescriptor(_C,Val) -> encode_restricted_string(Val). -decode_ObjectDescriptor(Bytes) -> - decode_restricted_string(Bytes). encode_TeletexString(_C,Val) -> % equivalent with T61String encode_restricted_string(Val). -decode_TeletexString(Bytes,_C) -> - decode_restricted_string(Bytes). encode_VideotexString(_C,Val) -> encode_restricted_string(Val). -decode_VideotexString(Bytes,_C) -> - decode_restricted_string(Bytes). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -983,10 +969,6 @@ encode_UTF8String(Val) -> Bin = list_to_binary(Val), encode_UTF8String(Bin). -decode_UTF8String(Bytes) -> - {Len,Bytes2} = decode_length(Bytes, undefined), - getoctets_as_bin(Bytes2,Len). - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% encode_object_identifier(Val) -> CompleteList -- cgit v1.2.3 From f16f43446a04c459486356c0b4ad517cc9201895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 22 Jan 2013 17:25:09 +0100 Subject: per,uper: Optimize decoding of the remaining data types --- lib/asn1/src/asn1ct_constructed_per.erl | 19 +++--------- lib/asn1/src/asn1ct_gen_per.erl | 52 +++++++++++++++------------------ lib/asn1/src/asn1ct_imm.erl | 4 +++ lib/asn1/src/asn1rtt_per.erl | 47 ++--------------------------- lib/asn1/src/asn1rtt_per_common.erl | 24 ++++++++++++++- lib/asn1/src/asn1rtt_uper.erl | 51 ++------------------------------ 6 files changed, 58 insertions(+), 139 deletions(-) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl index c3aa482051..3c59c73108 100644 --- a/lib/asn1/src/asn1ct_constructed_per.erl +++ b/lib/asn1/src/asn1ct_constructed_per.erl @@ -1518,7 +1518,6 @@ gen_dec_line_dec_inf(Comp, DecInfObj) -> gen_dec_line_other(Erule, Atype, TopType, Comp) -> #'ComponentType'{name=Cname,typespec=Type} = Comp, CurrMod = get(currmod), - Ctgenmod = asn1ct_gen:ct_gen_module(Erule), case asn1ct_gen:type(Atype) of #'Externaltypereference'{module=CurrMod,type=EType} -> fun(BytesVar) -> @@ -1532,16 +1531,16 @@ gen_dec_line_other(Erule, Atype, TopType, Comp) -> {primitive,bif} -> case Atype of {fixedtypevaluefield,_,Btype} -> - gen_dec_prim(Ctgenmod, Erule, Btype); + asn1ct_gen_per:gen_dec_imm(Erule, Btype); _ -> - gen_dec_prim(Ctgenmod, Erule, Type) + asn1ct_gen_per:gen_dec_imm(Erule, Type) end; 'ASN1_OPEN_TYPE' -> case Type#type.def of #'ObjectClassFieldType'{type=OpenType} -> - gen_dec_prim(Ctgenmod, Erule, #type{def=OpenType}); + asn1ct_gen_per:gen_dec_imm(Erule, #type{def=OpenType}); _ -> - gen_dec_prim(Ctgenmod, Erule, Type) + asn1ct_gen_per:gen_dec_imm(Erule, Type) end; #typereference{val=Dname} -> fun(BytesVar) -> @@ -1567,16 +1566,6 @@ gen_dec_line_other(Erule, Atype, TopType, Comp) -> end end. -gen_dec_prim(Ctgenmod, Erule, Type) -> - case asn1ct_gen_per:gen_dec_imm(Erule, Type) of - no -> - fun(BytesVar) -> - Ctgenmod:gen_dec_prim(Erule, Type, BytesVar) - end; - Imm -> - Imm - end. - gen_enc_choice(Erule,TopType,CompList,Ext) -> gen_enc_choice_tag(Erule, CompList, [], Ext), emit({com,nl}), diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl index ddfa39486a..c7509b57af 100644 --- a/lib/asn1/src/asn1ct_gen_per.erl +++ b/lib/asn1/src/asn1ct_gen_per.erl @@ -1119,6 +1119,8 @@ gen_dec_imm_1({'BIT STRING',NNL}, Constr0, Aligned) -> end, {call,D,Imm} end; +gen_dec_imm_1('NULL', _Constr, _Aligned) -> + {value,'NULL'}; gen_dec_imm_1('BOOLEAN', _Constr, _Aligned) -> asn1ct_imm:per_dec_boolean(); gen_dec_imm_1({'ENUMERATED',{Base,Ext}}, _Constr, Aligned) -> @@ -1163,11 +1165,29 @@ gen_dec_imm_1('GeneralString', _Constraint, Aligned) -> gen_dec_restricted_string(Aligned); gen_dec_imm_1('ObjectDescriptor', _Constraint, Aligned) -> gen_dec_restricted_string(Aligned); +gen_dec_imm_1('OBJECT IDENTIFIER', _Constraint, Aligned) -> + Dec = fun(V, Buf) -> + emit(["{",{call,per_common,decode_oid,[V]},com, + Buf,"}"]) + end, + {call,Dec,gen_dec_restricted_string(Aligned)}; +gen_dec_imm_1('RELATIVE-OID', _Constraint, Aligned) -> + Dec = fun(V, Buf) -> + emit(["{",{call,per_common,decode_relative_oid,[V]},com, + Buf,"}"]) + end, + {call,Dec,gen_dec_restricted_string(Aligned)}; gen_dec_imm_1('UTF8String', _Constraint, Aligned) -> asn1ct_imm:per_dec_restricted_string(Aligned); gen_dec_imm_1('REAL', _Constraint, Aligned) -> asn1ct_imm:per_dec_real(Aligned); -gen_dec_imm_1(_, _, _) -> no. +gen_dec_imm_1(#'ObjectClassFieldType'{}=TypeName, Constraint, Aligned) -> + case asn1ct_gen:get_inner(TypeName) of + {fixedtypevaluefield,_,InnerType} -> + gen_dec_imm_1(InnerType, Constraint, Aligned); + T -> + gen_dec_imm_1(T, Constraint, Aligned) + end. gen_dec_bit_string(F, Imm) -> D = fun(V, Buf) -> @@ -1189,34 +1209,8 @@ gen_dec_restricted_string(Aligned) -> {convert,binary_to_list,Imm}. gen_dec_prim(Erule, Type, BytesVar) -> - case gen_dec_imm(Erule, Type) of - no -> - gen_dec_prim_1(Erule, Type, BytesVar); - Imm -> - asn1ct_imm:dec_code_gen(Imm, BytesVar) - end. - -gen_dec_prim_1(Erule, - #type{def=Typename}=Att, - BytesVar) -> - case Typename of - 'NULL' -> - emit({"{'NULL',",BytesVar,"}"}); - 'OBJECT IDENTIFIER' -> - call(Erule, decode_object_identifier, [BytesVar]); - 'RELATIVE-OID' -> - call(Erule, decode_relative_oid, [BytesVar]); - #'ObjectClassFieldType'{} -> - case asn1ct_gen:get_inner(Typename) of - {fixedtypevaluefield,_,InnerType} -> - gen_dec_prim(Erule, InnerType, BytesVar); - T -> - gen_dec_prim(Erule, Att#type{def=T}, BytesVar) - end; - Other -> - exit({'cant decode' ,Other}) - end. - + Imm = gen_dec_imm(Erule, Type), + asn1ct_imm:dec_code_gen(Imm, BytesVar). is_already_generated(Operation,Name) -> case get(class_default_type) of diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl index 87eadac073..5bdaed8f4f 100644 --- a/lib/asn1/src/asn1ct_imm.erl +++ b/lib/asn1/src/asn1ct_imm.erl @@ -391,6 +391,8 @@ opt_al({'case',Cs0}, A0) -> opt_al({map,E0,Cs}, A0) -> {E,A} = opt_al(E0, A0), {{map,E,Cs},A}; +opt_al('NULL'=Null, A) -> + {Null,A}; opt_al(I, A) when is_integer(I) -> {I,A}. @@ -478,6 +480,8 @@ flatten({map,E0,Cs0}, Buf0, St0) -> {Dst,St2} = new_var("Int", St1), Cs = flatten_map_cs(Cs0, E), {{Dst,DstBuf},Pre++[{'map',E,Cs,{Dst,DstBuf}}],St2}; +flatten({value,'NULL'}, Buf0, St0) -> + {{"'NULL'",Buf0},[],St0}; flatten({value,V0}, Buf0, St0) when is_integer(V0) -> {{V0,Buf0},[],St0}; flatten({value,V0}, Buf0, St0) -> diff --git a/lib/asn1/src/asn1rtt_per.erl b/lib/asn1/src/asn1rtt_per.erl index 2bcf459330..7194e8d127 100644 --- a/lib/asn1/src/asn1rtt_per.erl +++ b/lib/asn1/src/asn1rtt_per.erl @@ -26,8 +26,8 @@ encode_length/1, encode_length/2, encode_bit_string/3, - encode_object_identifier/1, decode_object_identifier/1, - encode_relative_oid/1, decode_relative_oid/1, + encode_object_identifier/1, + encode_relative_oid/1, complete/1, encode_open_type/1, encode_GeneralString/2, @@ -134,12 +134,6 @@ getoctets_as_bin(Bin,Num) when is_bitstring(Bin) -> <<_:AlignBits,Val:Num/binary,RestBin/binary>> = Bin, {Val,RestBin}. - -%% same as above but returns octets as a List -getoctets_as_list(Buffer,Num) -> - {Bin,Buffer2} = getoctets_as_bin(Buffer,Num), - {binary_to_list(Bin),Buffer2}. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% set_choice(Alt,Choices,Altnum) -> ListofBitSettings %% Alt = atom() @@ -977,33 +971,6 @@ e_o_e(Num) when Num < 128 -> e_o_e(Num) -> [e_o_e(Num bsr 7)|[(Num band 2#1111111) bor 2#10000000]]. - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_object_identifier(Bytes) -> {ObjId,RemainingBytes} -%% ObjId -> {integer(),integer(),...} % at least 2 integers -%% RemainingBytes -> [integer()] when integer() (0..255) -decode_object_identifier(Bytes) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - {Octs,Bytes3} = getoctets_as_list(Bytes2,Len), - [First|Rest] = dec_subidentifiers(Octs,0,[]), - Idlist = if - First < 40 -> - [0,First|Rest]; - First < 80 -> - [1,First - 40|Rest]; - true -> - [2,First - 80|Rest] - end, - {list_to_tuple(Idlist),Bytes3}. - -dec_subidentifiers([H|T],Av,Al) when H >=16#80 -> - dec_subidentifiers(T,(Av bsl 7) + (H band 16#7F),Al); -dec_subidentifiers([H|T],Av,Al) -> - dec_subidentifiers(T,0,[(Av bsl 7) + H |Al]); -dec_subidentifiers([],_Av,Al) -> - lists:reverse(Al). - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% encode_relative_oid(Val) -> CompleteList %% encode_relative_oid({Name,Val}) -> CompleteList @@ -1014,16 +981,6 @@ encode_relative_oid(Val) when is_list(Val) -> Sz = byte_size(Octets), [encode_length(Sz)|octets_to_complete(Sz, Octets)]. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_relative_oid(Val) -> CompleteList -%% decode_relative_oid({Name,Val}) -> CompleteList -decode_relative_oid(Bytes) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - {Octs,Bytes3} = getoctets_as_list(Bytes2,Len), - ObjVals = dec_subidentifiers(Octs,0,[]), - {list_to_tuple(ObjVals),Bytes3}. - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% complete(InList) -> ByteList %% Takes a coded list with bits and bytes and converts it to a list of bytes diff --git a/lib/asn1/src/asn1rtt_per_common.erl b/lib/asn1/src/asn1rtt_per_common.erl index cd6e9e2c99..a7d359a288 100644 --- a/lib/asn1/src/asn1rtt_per_common.erl +++ b/lib/asn1/src/asn1rtt_per_common.erl @@ -27,7 +27,8 @@ decode_named_bit_string/2, decode_chars/2,decode_chars/3, decode_chars_16bit/1, - decode_big_chars/2]). + decode_big_chars/2, + decode_oid/1,decode_relative_oid/1]). -define('16K',16384). @@ -74,6 +75,20 @@ decode_chars_16bit(Val) -> decode_big_chars(Val, N) -> decode_big_chars_1(decode_chars(Val, N)). +decode_oid(Octets) -> + [First|Rest] = dec_subidentifiers(Octets, 0, []), + Idlist = if + First < 40 -> + [0,First|Rest]; + First < 80 -> + [1,First - 40|Rest]; + true -> + [2,First - 80|Rest] + end, + list_to_tuple(Idlist). + +decode_relative_oid(Octets) -> + list_to_tuple(dec_subidentifiers(Octets, 0, [])). %%% %%% Internal functions. @@ -102,3 +117,10 @@ decode_big_chars_1([H|T]) when H < 256 -> decode_big_chars_1([H|T]) -> [list_to_tuple(binary_to_list(<>))|decode_big_chars_1(T)]; decode_big_chars_1([]) -> []. + +dec_subidentifiers([H|T], Av, Al) when H >=16#80 -> + dec_subidentifiers(T, (Av bsl 7) bor (H band 16#7F), Al); +dec_subidentifiers([H|T], Av, Al) -> + dec_subidentifiers(T, 0, [(Av bsl 7) bor H|Al]); +dec_subidentifiers([], _Av, Al) -> + lists:reverse(Al). diff --git a/lib/asn1/src/asn1rtt_uper.erl b/lib/asn1/src/asn1rtt_uper.erl index fa4f08363b..d78116cc92 100644 --- a/lib/asn1/src/asn1rtt_uper.erl +++ b/lib/asn1/src/asn1rtt_uper.erl @@ -28,8 +28,8 @@ encode_length/1, encode_length/2, encode_bit_string/3]). -export([encode_octet_string/1,encode_octet_string/2, - encode_relative_oid/1, decode_relative_oid/1, - encode_object_identifier/1, decode_object_identifier/1, + encode_relative_oid/1, + encode_object_identifier/1, complete/1, complete_NFP/1]). -export([encode_open_type/1]). @@ -146,17 +146,6 @@ getoctets(Buffer, Num) when is_bitstring(Buffer) -> <> = Buffer, {Val,RestBitStr}. -%% Pick the first Num octets. -%% Returns octets as a binary -getoctets_as_bin(Bin,Num) when is_bitstring(Bin) -> - <> = Bin, - {Octets,RestBin}. - -%% same as above but returns octets as a List -getoctets_as_list(Buffer,Num) -> - {Bin,Buffer2} = getoctets_as_bin(Buffer, Num), - {binary_to_list(Bin),Buffer2}. - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% set_choice(Alt,Choices,Altnum) -> ListofBitSettings %% Alt = atom() @@ -1014,32 +1003,6 @@ e_o_e(Num) -> [e_o_e(Num bsr 7)|[(Num band 2#1111111) bor 2#10000000]]. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_object_identifier(Bytes) -> {ObjId,RemainingBytes} -%% ObjId -> {integer(),integer(),...} % at least 2 integers -%% RemainingBytes -> [integer()] when integer() (0..255) -decode_object_identifier(Bytes) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - {Octs,Bytes3} = getoctets_as_list(Bytes2,Len), - [First|Rest] = dec_subidentifiers(Octs,0,[]), - Idlist = if - First < 40 -> - [0,First|Rest]; - First < 80 -> - [1,First - 40|Rest]; - true -> - [2,First - 80|Rest] - end, - {list_to_tuple(Idlist),Bytes3}. - -dec_subidentifiers([H|T],Av,Al) when H >=16#80 -> - dec_subidentifiers(T, (Av bsl 7) + (H band 16#7F),Al); -dec_subidentifiers([H|T],Av,Al) -> - dec_subidentifiers(T,0, [(Av bsl 7) + H |Al]); -dec_subidentifiers([],_Av,Al) -> - lists:reverse(Al). - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% encode_relative_oid(Val) -> CompleteList %% encode_relative_oid({Name,Val}) -> CompleteList @@ -1050,16 +1013,6 @@ encode_relative_oid(Val) when is_list(Val) -> [encode_length(byte_size(Octets)),Octets]. -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% decode_relative_oid(Val) -> CompleteList -%% decode_relative_oid({Name,Val}) -> CompleteList -decode_relative_oid(Bytes) -> - {Len,Bytes2} = decode_length(Bytes,undefined), - {Octs,Bytes3} = getoctets_as_list(Bytes2,Len), - ObjVals = dec_subidentifiers(Octs,0,[]), - {list_to_tuple(ObjVals),Bytes3}. - - get_constraint([{Key,V}],Key) -> V; get_constraint([],_Key) -> -- cgit v1.2.3 From 13694772383b66b6fad2ba8e17662a0e71b05110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 23 Jan 2013 06:56:14 +0100 Subject: Simplify the functions for decoding lengths Now that the decoding of all types are generated inline, we can take out most of the code for decoding lengths. --- lib/asn1/src/asn1rtt_per.erl | 37 ++++++------------------------------- lib/asn1/src/asn1rtt_uper.erl | 36 ++++++------------------------------ 2 files changed, 12 insertions(+), 61 deletions(-) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1rtt_per.erl b/lib/asn1/src/asn1rtt_per.erl index 7194e8d127..4713125ffc 100644 --- a/lib/asn1/src/asn1rtt_per.erl +++ b/lib/asn1/src/asn1rtt_per.erl @@ -79,7 +79,7 @@ skipextensions(Bytes0, Nr, ExtensionBitstr) when is_bitstring(ExtensionBitstr) - Prev = Nr - 1, case ExtensionBitstr of <<_:Prev,1:1,_/bitstring>> -> - {Len,Bytes1} = decode_length(Bytes0, undefined), + {Len,Bytes1} = decode_length(Bytes0), <<_:Len/binary,Bytes2/bitstring>> = Bytes1, skipextensions(Bytes2, Nr+1, ExtensionBitstr); <<_:Prev,0:1,_/bitstring>> -> @@ -262,7 +262,7 @@ encode_semi_constrained_number(Lb, Val) -> end. decode_semi_constrained_number(Bytes) -> - {Len,Bytes2} = decode_length(Bytes, undefined), + {Len,Bytes2} = decode_length(Bytes), getoctets(Bytes2, Len). encode_constrained_number({Lb,_Ub},_Range,{bits,N},Val) -> @@ -465,7 +465,7 @@ encode_small_length(Len) -> [1,encode_length(Len)]. -decode_length(Buffer, undefined) -> % un-constrained +decode_length(Buffer) -> % un-constrained case align(Buffer) of <<0:1,Oct:7,Rest/binary>> -> {Oct,Rest}; @@ -474,37 +474,12 @@ decode_length(Buffer, undefined) -> % un-constrained <<3:2,_Val:14,_Rest/binary>> -> %% this case should be fixed exit({error,{asn1,{decode_length,{nyi,above_16k}}}}) - end; + end. -decode_length(Buffer, {Lb,Ub}) when Ub =< 65535 ,Lb >= 0 -> % constrained +decode_length(Buffer, {Lb,Ub}) when Ub =< 65535, Lb >= 0 -> % constrained decode_constrained_number(Buffer, {Lb,Ub}); decode_length(Buffer, {Lb,_Ub}) when is_integer(Lb), Lb >= 0 -> % Ub > 65535 - decode_length(Buffer,undefined); -decode_length(Buffer, {{Lb,Ub},Ext}) when is_list(Ext) -> - case getbit(Buffer) of - {0,Buffer2} -> - decode_length(Buffer2, {Lb,Ub}); - {1,Buffer2} -> - decode_length(Buffer2, undefined) - end; - -%When does this case occur with {_,_Lb,Ub} ?? -% X.691:10.9.3.5 -decode_length(Bin, {_,_Lb,_Ub}) -> % Unconstrained or large Ub NOTE! this case does not cover case when Ub > 65535 - case Bin of - <<0:1,Val:7,Rest/bitstring>> -> - {Val,Rest}; - _ -> - case align(Bin) of - <<2:2,Val:14,Rest/binary>> -> - {Val,Rest}; - <<3:2,_:14,_Rest/binary>> -> - exit({error,{asn1,{decode_length,{nyi,length_above_64K}}}}) - end - end; -decode_length(Buffer, SingleValue) when is_integer(SingleValue) -> - {SingleValue,Buffer}. - + decode_length(Buffer). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% bitstring NamedBitList diff --git a/lib/asn1/src/asn1rtt_uper.erl b/lib/asn1/src/asn1rtt_uper.erl index d78116cc92..b5e8a3c3bb 100644 --- a/lib/asn1/src/asn1rtt_uper.erl +++ b/lib/asn1/src/asn1rtt_uper.erl @@ -113,7 +113,7 @@ skipextensions(Bytes0, Nr, ExtensionBitstr) when is_bitstring(ExtensionBitstr) - Prev = Nr - 1, case ExtensionBitstr of <<_:Prev,1:1,_/bitstring>> -> - {Len,Bytes1} = decode_length(Bytes0, undefined), + {Len,Bytes1} = decode_length(Bytes0), <<_:Len/binary,Bytes2/bitstring>> = Bytes1, skipextensions(Bytes2, Nr+1, ExtensionBitstr); <<_:Prev,0:1,_/bitstring>> -> @@ -290,7 +290,7 @@ encode_semi_constrained_number(Lb, Val) -> end. decode_semi_constrained_number(Bytes) -> - {Len,Bytes2} = decode_length(Bytes, undefined), + {Len,Bytes2} = decode_length(Bytes), {V,Bytes3} = getoctets(Bytes2,Len), {V,Bytes3}. @@ -416,36 +416,12 @@ encode_small_length(Len) -> %% un-constrained -decode_length(<<0:1,Oct:7,Rest/bitstring>>,undefined) -> +decode_length(<<0:1,Oct:7,Rest/bitstring>>) -> {Oct,Rest}; -decode_length(<<2:2,Val:14,Rest/bitstring>>,undefined) -> +decode_length(<<2:2,Val:14,Rest/bitstring>>) -> {Val,Rest}; -decode_length(<<3:2,_:14,_Rest/bitstring>>,undefined) -> - exit({error,{asn1,{decode_length,{nyi,above_16k}}}}); - -decode_length(Buffer,{Lb,Ub}) when Ub =< 65535, Lb >= 0 -> % constrained - decode_constrained_number(Buffer,{Lb,Ub}); -decode_length(Buffer,{Lb,_}) when is_integer(Lb), Lb >= 0 -> % Ub > 65535 - decode_length(Buffer,undefined); -decode_length(Buffer,{VR={_Lb,_Ub},Ext}) when is_list(Ext) -> - {0,Buffer2} = getbit(Buffer), - decode_length(Buffer2, VR); - - -%When does this case occur with {_,_Lb,Ub} ?? -% X.691:10.9.3.5 -decode_length(Bin,{_,_Lb,_Ub}) -> %when Len =< 127 -> % Unconstrained or large Ub NOTE! this case does not cover case when Ub > 65535 - case Bin of - <<0:1,Val:7,Rest/bitstring>> -> - {Val,Rest}; - <<2:2,Val:14,Rest/bitstring>> -> - {Val,Rest}; - <<3:2,_:14,_Rest/bitstring>> -> - exit({error,{asn1,{decode_length,{nyi,length_above_64K}}}}) - end; -decode_length(Buffer,SingleValue) when is_integer(SingleValue) -> - {SingleValue,Buffer}. - +decode_length(<<3:2,_:14,_Rest/bitstring>>) -> + exit({error,{asn1,{decode_length,{nyi,above_16k}}}}). % X.691:11 encode_boolean(true) -> -- cgit v1.2.3 From b344d2bd350f32b340cb5a4997fdab020954f5bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 24 Jan 2013 11:29:04 +0100 Subject: Remove vestiges of support for the {TypeName,Value} notation Support in BER was removed in 3d1279f3cebfdd2483c3afea9f225613fe45cd00. --- lib/asn1/src/asn1ct_gen_per.erl | 7 ------- lib/asn1/src/asn1ct_gen_per_rt2ct.erl | 7 ------- 2 files changed, 14 deletions(-) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl index c7509b57af..3b320065d2 100644 --- a/lib/asn1/src/asn1ct_gen_per.erl +++ b/lib/asn1/src/asn1ct_gen_per.erl @@ -93,13 +93,6 @@ gen_encode_user(Erules,D) when is_record(D,typedef) -> Typename = [D#typedef.name], Def = D#typedef.typespec, InnerType = asn1ct_gen:get_inner(Def#type.def), - case InnerType of - 'SET' -> true; - 'SEQUENCE' -> true; - _ -> - emit({nl,"'enc_",asn1ct_gen:list2name(Typename),"'({'",asn1ct_gen:list2name(Typename),"',Val}) ->",nl}), - emit({"'enc_",asn1ct_gen:list2name(Typename),"'(Val);",nl,nl}) - end, emit({"'enc_",asn1ct_gen:list2name(Typename),"'(Val) ->",nl}), case asn1ct_gen:type(InnerType) of {primitive,bif} -> diff --git a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl index e39af78147..8dd0297f89 100644 --- a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl +++ b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl @@ -83,13 +83,6 @@ gen_encode_user(Erules,D) when is_record(D,typedef) -> Typename = [D#typedef.name], Def = D#typedef.typespec, InnerType = asn1ct_gen:get_inner(Def#type.def), - case InnerType of - 'SET' -> true; - 'SEQUENCE' -> true; - _ -> - emit({nl,"'enc_",asn1ct_gen:list2name(Typename),"'({'",asn1ct_gen:list2name(Typename),"',Val}) ->",nl}), - emit({"'enc_",asn1ct_gen:list2name(Typename),"'(Val);",nl,nl}) - end, emit({"'enc_",asn1ct_gen:list2name(Typename),"'(Val) ->",nl}), case asn1ct_gen:type(InnerType) of {primitive,bif} -> -- cgit v1.2.3 From b06cbaf8cf12a9b6dcbdc6eab873a6212206ef58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Thu, 24 Jan 2013 11:32:00 +0100 Subject: Don't export encode_disp/2 and decode_disp/2 in generated modules Those functions were exported for no good reason. --- lib/asn1/src/asn1ct_gen.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/asn1/src') diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl index c2590d1e44..79f0593c37 100644 --- a/lib/asn1/src/asn1ct_gen.erl +++ b/lib/asn1/src/asn1ct_gen.erl @@ -920,7 +920,7 @@ gen_selected_decode_exports1([{FuncName,_}|Rest]) -> pgen_dispatcher(Erules,_Module,{[],_Values,_,_,_Objects,_ObjectSets}) -> gen_info_functions(Erules); pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) -> - emit(["-export([encode/2,decode/2,encode_disp/2,decode_disp/2]).",nl,nl]), + emit(["-export([encode/2,decode/2]).",nl,nl]), gen_info_functions(Erules), NoFinalPadding = lists:member(no_final_padding,get(encoding_options)), {Call,BytesAsBinary} = -- cgit v1.2.3