anchor.diff:      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(Buffer, Tags, OptOrMand) ->
  -    NewTags = new_tags(Tags,#tag{class=?UNIVERSAL,
  -				 number=?N_OBJECT_IDENTIFIER}),
  -    decode_object_identifier_notag(Buffer, NewTags, OptOrMand).
  -
  -decode_object_identifier_notag(Buffer, Tags, OptOrMand) ->
  -    {RestTags, {FormLen, Buffer0, Rb0}} =
  -	check_tags_i(Tags, Buffer, OptOrMand),
  -
  -    case FormLen of
  -	{?CONSTRUCTED,Len} ->
  -	    {Buffer00,RestBytes} = split_list(Buffer0,Len),
  -	    {Val01, Buffer01, Rb01} =
  -		decode_object_identifier_notag(Buffer00,
  -					       RestTags, OptOrMand),
  -	    {Buffer02, Rb02} = restbytes2(RestBytes,Buffer01,noext),
  -	    {Val01, Buffer02, Rb0+Rb01+Rb02};
  -	{_,Len} ->
  -	    {[AddedObjVal|ObjVals],Buffer01} =
  -		dec_subidentifiers(Buffer0,0,[],Len),
  -	    {Val1, Val2} = if
  -			       AddedObjVal < 40 ->
  -				   {0, AddedObjVal};
  -			       AddedObjVal < 80 ->
  -				   {1, AddedObjVal - 40};
  -			       true ->
  -				   {2, AddedObjVal - 80}
  -			   end,
  -	    {list_to_tuple([Val1, Val2 | ObjVals]), Buffer01,
  -	     Rb0+Len}
  -    end.
  -
  -dec_subidentifiers(Buffer,_Av,Al,0) ->
  -    {lists:reverse(Al),Buffer};
  -dec_subidentifiers(<<1:1,H:7,T/binary>>,Av,Al,Len) ->
  -    dec_subidentifiers(T,(Av bsl 7) + H,Al,Len-1);
  -dec_subidentifiers(<<H,T/binary>>,Av,Al,Len) ->
  -    dec_subidentifiers(T,0,[((Av bsl 7) + H)|Al],Len-1).
  -
  -%%============================================================================
  -%% 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,[]) ->
  -    {EncVal,Len} = enc_relative_oid(Val),
  -    dotag_universal(?'N_RELATIVE-OID',EncVal,Len);
  -encode_relative_oid(Val, DoTag) ->
  -    dotag(DoTag, ?'N_RELATIVE-OID', enc_relative_oid(Val)).
  -
  -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(Buffer, Tags, OptOrMand) ->
  -    NewTags = new_tags(Tags,#tag{class=?UNIVERSAL,
  -				 number=?'N_RELATIVE-OID'}),
  -    decode_relative_oid_notag(Buffer, NewTags, OptOrMand).
  -
  -decode_relative_oid_notag(Buffer, Tags, OptOrMand) ->
  -    {_RestTags, {_FormLen={_,Len}, Buffer0, Rb0}} =
  -	check_tags_i(Tags, Buffer, OptOrMand),
  -    {ObjVals,Buffer01} =
  -	dec_subidentifiers(Buffer0,0,[],Len),
  -    {list_to_tuple(ObjVals), Buffer01, Rb0+Len}.
  -
  -%%============================================================================
  -%% Restricted character string types, ITU_T X.690 Chapter 8.21
  -%%
  -%% encode Numeric Printable Teletex Videotex Visible IA5 Graphic General strings
  -%%============================================================================
  -encode_restricted_string(_C, OctetList, StringType, [])
  -  when is_binary(OctetList) ->
  -    dotag_universal(StringType, OctetList, byte_size(OctetList));
  -encode_restricted_string(_C, OctetList, StringType, DoTag)
  -  when is_binary(OctetList) ->
  -    dotag(DoTag, StringType, {OctetList, byte_size(OctetList)});
  -encode_restricted_string(_C, OctetList, StringType, [])
  -  when is_list(OctetList) ->
  -    dotag_universal(StringType, OctetList, length(OctetList));
  -encode_restricted_string(_C, OctetList, StringType, DoTag)
  -  when is_list(OctetList) ->
  -    dotag(DoTag, StringType, {OctetList, length(OctetList)});
  -encode_restricted_string(C,{Name,OctetL},StringType,DoTag) when is_atom(Name) ->
  -    encode_restricted_string(C, OctetL, StringType, DoTag).
  -
  -%%============================================================================
  -%% 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, LenIn, OptOrMand) ->
  -    {Val,Buffer2,Rb} =
  -	decode_restricted_string_tag(Buffer, Range, StringType, Tags,
  -				  LenIn, [], OptOrMand,old),
  -    {check_and_convert_restricted_string(Val,StringType,Range,[],old),
  -     Buffer2,Rb}.
  -
  -
  -decode_restricted_string(Buffer, Range, StringType, Tags, LenIn, NNList, OptOrMand, BinOrOld ) ->
  -    {Val,Buffer2,Rb} =
  -	decode_restricted_string_tag(Buffer, Range, StringType, Tags,
  -			     LenIn, NNList, OptOrMand, BinOrOld),
  -    {check_and_convert_restricted_string(Val,StringType,Range,NNList,BinOrOld),
  -     Buffer2,Rb}.
  -
  -decode_restricted_string_tag(Buffer, Range, StringType, TagsIn, LenIn, NNList, OptOrMand, BinOrOld ) ->
  -    NewTags = new_tags(TagsIn, #tag{class=?UNIVERSAL,number=StringType}),
  -    decode_restricted_string_notag(Buffer, Range, StringType, NewTags,
  -				   LenIn, NNList, OptOrMand, BinOrOld).
  -
  -
  -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) ->
  -			      {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=[MinExt|_]} when StrLen >= Lb; StrLen >= MinExt ->
  -	    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.
  -
  -%%=============================================================================
  -%% Common routines for several string types including bit string
  -%% handles indefinite length
  -%%=============================================================================
  -
  -
  -decode_restricted_string_notag(Buffer, _Range, StringType, TagsIn,
  -			       _, NamedNumberList, OptOrMand, BinOrOld) ->
  -    %%-----------------------------------------------------------
  -    %% Get inner (the implicit tag or no tag) and
  -    %%     outer (the explicit tag) lengths.
  -    %%-----------------------------------------------------------
  -    {RestTags, {FormLength={_,_Len01}, Buffer0, Rb0}} =
  -	check_tags_i(TagsIn, Buffer, OptOrMand),
  -
  -    case FormLength of
  -	{?CONSTRUCTED,Len} ->
  -	    {Buffer00, RestBytes} = split_list(Buffer0,Len),
  -	    {Val01, Buffer01, Rb01} =
  -		decode_restricted_parts(Buffer00, RestBytes, [], StringType,
  -					RestTags,
  -					Len, NamedNumberList,
  -					OptOrMand,
  -					BinOrOld, 0, []),
  -	    {Val01, Buffer01, Rb0+Rb01};
  -	{_, Len} ->
  -	    {Val01, Buffer01, Rb01} =
  -		decode_restricted(Buffer0, Len, StringType,
  -				  NamedNumberList, BinOrOld),
  -	    {Val01, Buffer01, Rb0+Rb01}
  -    end.
  -
  -
  -decode_restricted_parts(Buffer, RestBytes, [], StringType, RestTags, Len, NNList,
  -			OptOrMand, BinOrOld, AccRb, AccVal) ->
  -    DecodeFun = case RestTags of
  -		    [] -> fun decode_restricted_string_tag/8;
  -		    _ -> fun decode_restricted_string_notag/8
  -		end,
  -    {Val, Buffer1, Rb} =
  -	DecodeFun(Buffer, [], StringType, RestTags,
  -		  no_length, NNList,
  -		  OptOrMand, BinOrOld),
  -    {Buffer2,More} =
  -	case Buffer1 of
  -	    <<0,0,Buffer10/binary>> when Len == indefinite ->
  -		{Buffer10,false};
  -	    <<>> ->
  -		{RestBytes,false};
  -	    _ ->
  -		{Buffer1,true}
  -	end,
  -    {NewVal, NewRb} =
  -	case StringType of
  -	    ?N_BIT_STRING when BinOrOld == bin ->
  -		{concat_bit_binaries(AccVal, Val), AccRb+Rb};
  -	    _ when is_binary(Val),is_binary(AccVal) ->
  -		{<<AccVal/binary,Val/binary>>,AccRb+Rb};
  -	    _ when is_binary(Val), AccVal =:= [] ->
  -		{Val,AccRb+Rb};
  -	    _ ->
  -		{AccVal++Val, AccRb+Rb}
  -	end,
  -    case More of
  -	false ->
  -	    {NewVal, Buffer2, NewRb};
  -	true ->
  -	    decode_restricted_parts(Buffer2, RestBytes, [], StringType, RestTags, Len, NNList,
  -				    OptOrMand, BinOrOld, NewRb, NewVal)
  -    end.
  -
  -
  -
  -decode_restricted(Buffer, InnerLen, StringType, NamedNumberList,BinOrOld) ->
  -
  -    case StringType of
  -	?N_BIT_STRING ->
  -	    decode_bit_string2(InnerLen,Buffer,NamedNumberList,InnerLen,BinOrOld);
  -
  -	?N_UniversalString ->
  -	    <<PreBuff:InnerLen/binary,RestBuff/binary>> = Buffer,%%added for binary
  -	    UniString = mk_universal_string(binary_to_list(PreBuff)),
  -	    {UniString,RestBuff,InnerLen};
  -	?N_BMPString ->
  -	    <<PreBuff:InnerLen/binary,RestBuff/binary>> = Buffer,%%added for binary
  -	    BMP = mk_BMP_string(binary_to_list(PreBuff)),
  -	    {BMP,RestBuff,InnerLen};
  -	_ ->
  -	    <<PreBuff:InnerLen/binary,RestBuff/binary>> = Buffer,%%added for binary
  -	    {PreBuff, RestBuff, InnerLen}
  -    end.
  -
  -
  -
  -%%============================================================================
  -%% encode Universal string
  -%%============================================================================
  -
  -encode_universal_string(C, {Name, Universal}, DoTag) when is_atom(Name) ->
  -    encode_universal_string(C, Universal, DoTag);
  -encode_universal_string(_C, Universal, []) ->
  -    OctetList = mk_uni_list(Universal),
  -    dotag_universal(?N_UniversalString,OctetList,length(OctetList));
  -encode_universal_string(_C, Universal, DoTag) ->
  -    OctetList = mk_uni_list(Universal),
  -    dotag(DoTag, ?N_UniversalString, {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, LenIn, OptOrMand) ->
  -%    NewTags = new_tags(HasTag, #tag{class=?UNIVERSAL,number=?N_UniversalString}),
  -    decode_restricted_string(Buffer, Range, ?N_UniversalString,
  -			     Tags, LenIn, [], OptOrMand,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,[]) when is_binary(UTF8String) ->
  -    dotag_universal(?N_UTF8String,UTF8String,byte_size(UTF8String));
  -encode_UTF8_string(_,UTF8String,DoTag) when is_binary(UTF8String) ->
  -    dotag(DoTag,?N_UTF8String,{UTF8String,byte_size(UTF8String)});
  -encode_UTF8_string(_,UTF8String,[]) ->
  -    dotag_universal(?N_UTF8String,UTF8String,length(UTF8String));
  -encode_UTF8_string(_,UTF8String,DoTag) ->
  -    dotag(DoTag,?N_UTF8String,{UTF8String,length(UTF8String)}).
  -
  -%%============================================================================
  -%% decode UTF8 string
  -%%============================================================================
  -
  -decode_UTF8_string(Buffer, Tags, OptOrMand) ->
  -    NewTags = new_tags(Tags, #tag{class=?UNIVERSAL,number=?N_UTF8String}),
  -    decode_UTF8_string_notag(Buffer, NewTags, OptOrMand).
  -
  -decode_UTF8_string_notag(Buffer, Tags, OptOrMand) ->
  -    {RestTags, {FormLen, Buffer0, Rb0}} =
  -	check_tags_i(Tags, Buffer, OptOrMand),
  -    case FormLen of
  -	{?CONSTRUCTED,Len} ->
  -	    %% an UTF8String may be encoded as a constructed type
  -	    {Buffer00,RestBytes} = split_list(Buffer0,Len),
  -	    {Val01, Buffer01, Rb01} =
  -		decode_UTF8_string_notag(Buffer00,RestTags,OptOrMand),
  -	    {Buffer02, Rb02} = restbytes2(RestBytes,Buffer01,noext),
  -	    {Val01, Buffer02, Rb0+Rb01+Rb02};
  -	{_,Len} ->
  -	    <<Result:Len/binary,RestBuff/binary>> = Buffer0,
  -	    {Result,RestBuff,Rb0 + Len}
  -    end.
  -
  -
  -%%============================================================================
  -%% encode BMP string
  -%%============================================================================
  -
  -encode_BMP_string(C, {Name,BMPString}, DoTag) when is_atom(Name) ->
  -    encode_BMP_string(C, BMPString, DoTag);
  -encode_BMP_string(_C, BMPString, []) ->
  -    OctetList = mk_BMP_list(BMPString),
  -    dotag_universal(?N_BMPString,OctetList,length(OctetList));
  -encode_BMP_string(_C, BMPString, DoTag) ->
  -    OctetList = mk_BMP_list(BMPString),
  -    dotag(DoTag, ?N_BMPString, {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, LenIn, OptOrMand) ->
  -%    NewTags = new_tags(HasTag, #tag{class=?UNIVERSAL,number=?N_BMPString}),
  -    decode_restricted_string(Buffer, Range, ?N_BMPString,
  -			     Tags, LenIn, [], OptOrMand,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}, DoTag) when is_atom(Name) ->
  -    encode_generalized_time(C, OctetList, DoTag);
  -encode_generalized_time(_C, OctetList, []) ->
  -    dotag_universal(?N_GeneralizedTime,OctetList,length(OctetList));
  -encode_generalized_time(_C, OctetList, DoTag) ->
  -    dotag(DoTag, ?N_GeneralizedTime, {OctetList,length(OctetList)}).
  -
  -%%============================================================================
  -%% decode Generalized time
  -%%    (Buffer, Range, HasTag, TotalLen) -> {String, Remain, RemovedBytes}
  -%%============================================================================
  -
  -decode_generalized_time(Buffer, Range, Tags, TotalLen, OptOrMand) ->
  -    NewTags = new_tags(Tags,#tag{class=?UNIVERSAL,
  -			 number=?N_GeneralizedTime}),
  -    decode_generalized_time_notag(Buffer, Range, NewTags, TotalLen, OptOrMand).
  -
  -decode_generalized_time_notag(Buffer, Range, Tags, TotalLen, OptOrMand) ->
  -    {RestTags, {FormLen, Buffer0, Rb0}} =
  -	check_tags_i(Tags, Buffer, OptOrMand),
  -
  -    case FormLen of
  -	{?CONSTRUCTED,Len} ->
  -	    {Buffer00,RestBytes} = split_list(Buffer0,Len),
  -	    {Val01, Buffer01, Rb01} =
  -		decode_generalized_time_notag(Buffer00, Range,
  -					      RestTags, TotalLen,
  -					      OptOrMand),
  -	    {Buffer02, Rb02} = restbytes2(RestBytes,Buffer01,noext),
  -	    {Val01, Buffer02, Rb0+Rb01+Rb02};
  -	{_,Len} ->
  -	    <<PreBuff:Len/binary,RestBuff/binary>> = Buffer0,
  -	    {binary_to_list(PreBuff), RestBuff, Rb0+Len}
  -    end.
  -
  -%%============================================================================
  -%% Universal time, ITU_T X.680 Chapter 40
  -%%
  -%% encode UTC time
  -%%============================================================================
  -
  -encode_utc_time(C, {Name,OctetList}, DoTag) when is_atom(Name) ->
  -    encode_utc_time(C, OctetList, DoTag);
  -encode_utc_time(_C, OctetList, []) ->
  -    dotag_universal(?N_UTCTime, OctetList,length(OctetList));
  -encode_utc_time(_C, OctetList, DoTag) ->
  -    dotag(DoTag, ?N_UTCTime, {OctetList,length(OctetList)}).
  -
  -%%============================================================================
  -%% decode UTC time
  -%%    (Buffer, Range, HasTag, TotalLen) -> {String, Remain, RemovedBytes}
  -%%============================================================================
  -
  -decode_utc_time(Buffer, Range, Tags, TotalLen, OptOrMand) ->
  -    NewTags = new_tags(Tags,#tag{class=?UNIVERSAL,number=?N_UTCTime}),
  -    decode_utc_time_notag(Buffer, Range, NewTags, TotalLen, OptOrMand).
  -
  -decode_utc_time_notag(Buffer, Range, Tags, TotalLen, OptOrMand) ->
  -    {RestTags, {FormLen, Buffer0, Rb0}} =
  -	check_tags_i(Tags, Buffer, OptOrMand),
  -
  -    case FormLen of
  -	{?CONSTRUCTED,Len} ->
  -	    {Buffer00,RestBytes} = split_list(Buffer0,Len),
  -	    {Val01, Buffer01, Rb01} =
  -		decode_utc_time_notag(Buffer00, Range,
  -				      RestTags, TotalLen,
  -				      OptOrMand),
  -	    {Buffer02, Rb02} = restbytes2(RestBytes,Buffer01,noext),
  -	    {Val01, Buffer02, Rb0+Rb01+Rb02};
  -	{_,Len} ->
  -	    <<PreBuff:Len/binary,RestBuff/binary>> = Buffer0,
  -	    {binary_to_list(PreBuff), RestBuff, Rb0+Len}
  -    end.
  -
  -
   %%============================================================================
   %% Length handling
   %%
  
positive.code:     <<Length:LL/unit:8,Rest/binary>> = T,
      {{Length,Rest}, LL+1}.
  
  %decode_length([128 | T]) ->
  %    {{indefinite, T},1};
  %decode_length([H | T]) when H =< 127 ->
  %    {{H, T},1};
  %decode_length([H | T]) ->
  %    dec_long_length(H band 16#7F, T, 0, 1).
  
  
  %%dec_long_length(0, Buffer, Acc, Len) ->
  %%    {{Acc, Buffer},Len};
  %%dec_long_length(Bytes, [H | T], Acc, Len) ->
  %%    dec_long_length(Bytes - 1, T, (Acc bsl 8) + H, Len+1).
  
  %%===========================================================================
  %% Decode tag and length
  %%
  %% decode_tag_and_length(Buffer) -> {Tag, Len, RemainingBuffer, RemovedBytes}
  %%
  %%===========================================================================
  
  decode_tag_and_length(Buffer) ->
      {Tag, Buffer2, RemBytesTag} = decode_tag(Buffer),
      {{Len, Buffer3}, RemBytesLen} = decode_length(Buffer2),
      {Tag, Len, Buffer3, RemBytesTag+RemBytesLen}.
  
  
  %%============================================================================
  %% Check if valid tag
  %%
  %% check_if_valid_tag(Tag, List_of_valid_tags, OptOrMand) -> name of the tag
  %%============================================================================
  
  check_if_valid_tag(<<0,0,_/binary>>,_,_) ->
      asn1_EOC;
  check_if_valid_tag(<<>>, _, OptOrMand) ->
      check_if_valid_tag2_error([], OptOrMand);
  check_if_valid_tag(Bytes, ListOfTags, OptOrMand) when is_binary(Bytes) ->
      {Tag, _, _} = decode_tag(Bytes),
      check_if_valid_tag(Tag, ListOfTags, OptOrMand);
  
  %% This alternative should be removed in the near future
  %% Bytes as input should be the only necessary call
  check_if_valid_tag(Tag, ListOfTags, OptOrMand) ->
      {Class, _Form, TagNo} = Tag,
      C = code_class(Class),
      T = case C of
  	    'UNIVERSAL' ->
  		code_type(TagNo);
  	    _ ->
  		TagNo
  	end,
      check_if_valid_tag2({C,T}, ListOfTags, Tag, OptOrMand).
  
  check_if_valid_tag2(_Class_TagNo, [], Tag, MandOrOpt) ->
      check_if_valid_tag2_error(Tag,MandOrOpt);
  check_if_valid_tag2(Class_TagNo, [{TagName,TagList}|T], Tag, OptOrMand) ->
      case check_if_valid_tag_loop(Class_TagNo, TagList) of
  	true ->
  	    TagName;
  	false ->
  	    check_if_valid_tag2(Class_TagNo, T, Tag, OptOrMand)
      end.
  
  -spec check_if_valid_tag2_error(term(), atom()) -> no_return().
  
  check_if_valid_tag2_error(Tag,mandatory) ->
      exit({error,{asn1,{invalid_tag,Tag}}});
  check_if_valid_tag2_error(Tag,_) ->
      exit({error,{asn1,{no_optional_tag,Tag}}}).
  
  check_if_valid_tag_loop(_Class_TagNo,[]) ->
      false;
  check_if_valid_tag_loop(Class_TagNo,[H|T]) ->
      %% It is not possible to distinguish between SEQUENCE OF and SEQUENCE, and
      %% between SET OF and SET because both are coded as 16 and 17, respectively.
      H_without_OF = case H of
  		       {C, 'SEQUENCE OF'} ->
  			   {C, 'SEQUENCE'};
  		       {C, 'SET OF'} ->
  			   {C, 'SET'};
  		       Else ->
  			   Else
  		   end,
  
      case H_without_OF of
  	Class_TagNo ->
  	    true;
  	{_,_} ->
  	    check_if_valid_tag_loop(Class_TagNo,T);
  	_ ->
  	    check_if_valid_tag_loop(Class_TagNo,H),
  	    check_if_valid_tag_loop(Class_TagNo,T)
      end.
  
  
  
  code_class(0) -> 'UNIVERSAL';
  code_class(16#40) -> 'APPLICATION';
  code_class(16#80) -> 'CONTEXT';
  code_class(16#C0) -> 'PRIVATE'.
  
  
  code_type(1) -> 'BOOLEAN';
  code_type(2) -> 'INTEGER';
  code_type(3) -> 'BIT STRING';
  code_type(4) -> 'OCTET STRING';
  code_type(5) -> 'NULL';
  code_type(6) -> 'OBJECT IDENTIFIER';
  code_type(7) -> 'ObjectDescriptor';
  code_type(8) -> 'EXTERNAL';
  code_type(9) -> 'REAL';
  code_type(10) -> 'ENUMERATED';
  code_type(11) -> 'EMBEDDED_PDV';
  code_type(16) -> 'SEQUENCE';
  % code_type(16) -> 'SEQUENCE OF';
  code_type(17) -> 'SET';
  % code_type(17) -> 'SET OF';
  code_type(18) -> 'NumericString';
  code_type(19) -> 'PrintableString';
  code_type(20) -> 'TeletexString';
  code_type(21) -> 'VideotexString';
  code_type(22) -> 'IA5String';
  code_type(23) -> 'UTCTime';
  code_type(24) -> 'GeneralizedTime';
  code_type(25) -> 'GraphicString';
  code_type(26) -> 'VisibleString';
  code_type(27) -> 'GeneralString';
  code_type(28) -> 'UniversalString';
  code_type(30) -> 'BMPString';
  code_type(Else) -> exit({error,{asn1,{unrecognized_type,Else}}}).
  
  %%-------------------------------------------------------------------------
  %% decoding of the components of a SET
  %%-------------------------------------------------------------------------
  
  decode_set(Rb, indefinite, <<0,0,Bytes/binary>>, _OptOrMand, _Fun3, Acc) ->
     {lists:reverse(Acc),Bytes,Rb+2};
  
  decode_set(Rb, indefinite, Bytes, OptOrMand, Fun3, Acc) ->
      case Fun3(Bytes, OptOrMand) of
  	{_Term, _Remain, 0} ->
  	    {lists:reverse(Acc),Bytes,Rb};
  	{Term, Remain, Rb1} ->
  	    Fun3(Bytes, OptOrMand),
  	    decode_set(Rb+Rb1, indefinite, Remain, OptOrMand, Fun3, [Term|Acc])
      end;
  %%   {Term, Remain, Rb1} = Fun3(Bytes, OptOrMand),
  %%   decode_set(Rb+Rb1, indefinite, Remain, OptOrMand, Fun3, [Term|Acc]);
  
  decode_set(Rb, Num, Bytes, _OptOrMand, _Fun3, Acc) when Num == 0 ->
     {lists:reverse(Acc), Bytes, Rb};
  
  decode_set(_, Num, _, _, _, _) when Num < 0 ->
     exit({error,{asn1,{length_error,'SET'}}});
  
  decode_set(Rb, Num, Bytes, OptOrMand, Fun3, Acc) ->
      case Fun3(Bytes, OptOrMand) of
  	{_Term, _Remain, 0} ->
  	    {lists:reverse(Acc),Bytes,Rb};
  	{Term, Remain, Rb1} ->
  	    Fun3(Bytes, OptOrMand),
  	    decode_set(Rb+Rb1, Num-Rb1, Remain, OptOrMand, Fun3, [Term|Acc])
      end.
  %%    {Term, Remain, Rb1} = Fun3(Bytes, OptOrMand),
  %%    decode_set(Rb+Rb1, Num-Rb1, Remain, OptOrMand, Fun3, [Term|Acc]).
  
  
  %%-------------------------------------------------------------------------
  %% decoding of SEQUENCE OF and SET OF
  %%-------------------------------------------------------------------------
  
  decode_components(Rb, indefinite, <<0,0,Bytes/binary>>, _Fun3, _TagIn, Acc) ->
     {lists:reverse(Acc),Bytes,Rb+2};
  
  decode_components(Rb, indefinite, Bytes, Fun3, TagIn, Acc) ->
     {Term, Remain, Rb1} = Fun3(Bytes, mandatory, TagIn),
     decode_components(Rb+Rb1, indefinite, Remain, Fun3, TagIn, [Term|Acc]);
  
  decode_components(Rb, Num, Bytes, _Fun3, _TagIn, Acc) when Num == 0 ->
     {lists:reverse(Acc), Bytes, Rb};
  
  decode_components(_, Num, _, _, _, _) when Num < 0 ->
     exit({error,{asn1,{length_error,'SET/SEQUENCE OF'}}});
  
  decode_components(Rb, Num, Bytes, Fun3, TagIn, Acc) ->
     {Term, Remain, Rb1} = Fun3(Bytes, mandatory, TagIn),
     decode_components(Rb+Rb1, Num-Rb1, Remain, Fun3, TagIn, [Term|Acc]).
  
  %%decode_components(Rb, indefinite, [0,0|Bytes], _Fun3, _TagIn, Acc) ->
  %%   {lists:reverse(Acc),Bytes,Rb+2};
  
  decode_components(Rb, indefinite, <<0,0,Bytes/binary>>, _Fun4, _TagIn, _Fun, Acc) ->
     {lists:reverse(Acc),Bytes,Rb+2};
  
  decode_components(Rb, indefinite, Bytes, _Fun4, TagIn, _Fun, Acc) ->
     {Term, Remain, Rb1} = _Fun4(Bytes, mandatory, TagIn, _Fun),
     decode_components(Rb+Rb1, indefinite, Remain, _Fun4, TagIn, _Fun, [Term|Acc]);
  
  decode_components(Rb, Num, Bytes, _Fun4, _TagIn, _Fun, Acc) when Num == 0 ->
     {lists:reverse(Acc), Bytes, Rb};
  
  decode_components(_, Num, _, _, _, _, _) when Num < 0 ->
     exit({error,{asn1,{length_error,'SET/SEQUENCE OF'}}});
  
  decode_components(Rb, Num, Bytes, _Fun4, TagIn, _Fun, Acc) ->
     {Term, Remain, Rb1} = _Fun4(Bytes, mandatory, TagIn, _Fun),
     decode_components(Rb+Rb1, Num-Rb1, Remain, _Fun4, TagIn, _Fun, [Term|Acc]).
  
  
  
  %%-------------------------------------------------------------------------
  %% INTERNAL HELPER FUNCTIONS (not exported)
  %%-------------------------------------------------------------------------
  
  
  %%==========================================================================
  %% Encode tag
  %%
  %% dotag(tag | notag, TagValpattern | TagValTuple, [Length, Value]) -> [Tag]
  %% TagValPattern is a correct bitpattern for a tag
  %% TagValTuple is a tuple of three bitpatterns, Class, Form and TagNo where
  %%     Class = UNIVERSAL | APPLICATION | CONTEXT | PRIVATE
  %%     Form  = Primitive | Constructed
  %%     TagNo = Number of tag
  %%==========================================================================
  
  
  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(Tags, Tag, Bytes) ->
      encode_tags(Tags ++ [#tag{class=?UNIVERSAL,number=Tag,form=?PRIMITIVE}],
  		Bytes, size(Bytes)).
  
  dotag_universal(UniversalTag,Bytes,Len) when Len =< 16#7F->
      {[UniversalTag,Len,Bytes],2+Len};
  
negative.code: 	   end,
      Bytes = encode_tag_val({Class,NewForm,No}),
      {Bytes,size(Bytes)}.
  
  %%============================================================================
  %%
  