%% =====================================================================
%% This module was formed by merging the following modules:
%% 
%% 		`'PKCS-1''
%% 		`asn1rt_ber_bin_v2'
%% 		`asn1rt_check'
%% 		`asn1rt_driver_handler'
%% 
%% Created by Igor 2008-06-10, 20:42:07.
%% 

-module('PKCS-1').

-export([dec_Algorithm/2, dec_AlgorithmNull/2,
	 dec_DigestInfo/2, dec_DigestInfoNull/2,
	 dec_OtherPrimeInfo/2, dec_OtherPrimeInfos/2,
	 dec_RSAPrivateKey/2, dec_RSAPublicKey/2,
	 'dec_RSASSA-PSS-params'/2, dec_TrailerField/2,
	 dec_Version/2, decode/2, decode_disp/2, enc_Algorithm/2,
	 enc_AlgorithmNull/2, enc_DigestInfo/2,
	 enc_DigestInfoNull/2, enc_OtherPrimeInfo/2,
	 enc_OtherPrimeInfos/2, enc_RSAPrivateKey/2,
	 enc_RSAPublicKey/2, 'enc_RSASSA-PSS-params'/2,
	 enc_TrailerField/2, enc_Version/2, encode/2,
	 encode_disp/2, encoding_rule/0, 'id-RSAES-OAEP'/0,
	 'id-RSASSA-PSS'/0, 'id-md2'/0, 'id-md5'/0, 'id-mgf1'/0,
	 'id-pSpecified'/0, 'id-sha1'/0, info/0,
	 md2WithRSAEncryption/0, md5WithRSAEncryption/0,
	 'pkcs-1'/0, rsaEncryption/0, sha1WithRSAEncryption/0,
	 sha256WithRSAEncryption/0, sha384WithRSAEncryption/0,
	 sha512WithRSAEncryption/0]).

%% =====================================================================
%% 
%% The following code stems from module `'PKCS-1''.
%% 

%% Generated by the Erlang ASN.1 BER_V2-compiler version, utilizing bit-syntax:1.5.2
%% Purpose: encoder and decoder to the types in mod PKCS-1

-record('RSAPublicKey', {modulus, publicExponent}).

-record('RSAPrivateKey',
	{version, modulus, publicExponent, privateExponent,
	 prime1, prime2, exponent1, exponent2, coefficient,
	 otherPrimeInfos = asn1_NOVALUE}).

-record('OtherPrimeInfo',
	{prime, exponent, coefficient}).

-record('Algorithm',
	{algorithm, parameters = asn1_NOVALUE}).

-record('AlgorithmNull', {algorithm, parameters}).

-record('RSASSA-PSS-params',
	{hashAlgorithm, maskGenAlgorithm,
	 saltLength = asn1_DEFAULT,
	 trailerField = asn1_DEFAULT}).

-record('DigestInfo', {digestAlgorithm, digest}).

-record('DigestInfoNull', {digestAlgorithm, digest}).

%%<<< -asn1_info([{vsn, '1.5.2'}, {module, 'PKCS-1'},
%%<<<             {options,
%%<<<              [ber_bin_v2, report_errors,
%%<<<               {cwd,
%%<<<                "/ldisk/daily_build/otp_prebuild_r12b.2008-06-"
%%<<<                "10_20/otp_src_R12B-3/lib/ssh/src"},
%%<<<               {outdir,
%%<<<                "/ldisk/daily_build/otp_prebuild_r12b.2008-06-"
%%<<<                "10_20/otp_src_R12B-3/lib/ssh/src"},
%%<<<               inline, noobj, optimize, compact_bit_string, der,
%%<<<               {i, "."},
%%<<<               {i,
%%<<<                "/ldisk/daily_build/otp_prebuild_r12b.2008-06-"
%%<<<                "10_20/otp_src_R12B-3/lib/ssh/src"}]}]).

encoding_rule() -> ber_bin_v2.

encode(Type, Data) ->
    case catch encode_disp(Type, Data) of
      {'EXIT', {error, Reason}} -> {error, Reason};
      {'EXIT', Reason} -> {error, {asn1, Reason}};
      {Bytes, _Len} -> {ok, Bytes};
      Bytes -> {ok, Bytes}
    end.

decode(Type, Data) ->
    case catch decode_disp(Type, element(1, decode(Data)))
	of
      {'EXIT', {error, Reason}} -> {error, Reason};
      {'EXIT', Reason} -> {error, {asn1, Reason}};
      Result -> {ok, Result}
    end.

encode_disp('RSAPublicKey', Data) ->
    enc_RSAPublicKey(Data);
encode_disp('RSAPrivateKey', Data) ->
    enc_RSAPrivateKey(Data);
encode_disp('Version', Data) -> enc_Version(Data);
encode_disp('OtherPrimeInfos', Data) ->
    enc_OtherPrimeInfos(Data);
encode_disp('OtherPrimeInfo', Data) ->
    enc_OtherPrimeInfo(Data);
encode_disp('Algorithm', Data) -> enc_Algorithm(Data);
encode_disp('AlgorithmNull', Data) ->
    enc_AlgorithmNull(Data);
encode_disp('RSASSA-PSS-params', Data) ->
    'enc_RSASSA-PSS-params'(Data);
encode_disp('TrailerField', Data) ->
    enc_TrailerField(Data);
encode_disp('DigestInfo', Data) -> enc_DigestInfo(Data);
encode_disp('DigestInfoNull', Data) ->
    enc_DigestInfoNull(Data);
encode_disp(Type, _Data) ->
    exit({error, {asn1, {undefined_type, Type}}}).

decode_disp('RSAPublicKey', Data) ->
    dec_RSAPublicKey(Data);
decode_disp('RSAPrivateKey', Data) ->
    dec_RSAPrivateKey(Data);
decode_disp('Version', Data) -> dec_Version(Data);
decode_disp('OtherPrimeInfos', Data) ->
    dec_OtherPrimeInfos(Data);
decode_disp('OtherPrimeInfo', Data) ->
    dec_OtherPrimeInfo(Data);
decode_disp('Algorithm', Data) -> dec_Algorithm(Data);
decode_disp('AlgorithmNull', Data) ->
    dec_AlgorithmNull(Data);
decode_disp('RSASSA-PSS-params', Data) ->
    'dec_RSASSA-PSS-params'(Data);
decode_disp('TrailerField', Data) ->
    dec_TrailerField(Data);
decode_disp('DigestInfo', Data) -> dec_DigestInfo(Data);
decode_disp('DigestInfoNull', Data) ->
    dec_DigestInfoNull(Data);
decode_disp(Type, _Data) ->
    exit({error, {asn1, {undefined_type, Type}}}).

info() ->
    case module_info() of
      MI when is_list(MI) ->
	  case lists:keysearch(attributes, 1, MI) of
	    {value, {_, Attributes}} when is_list(Attributes) ->
		case lists:keysearch(asn1_info, 1, Attributes) of
		  {value, {_, Info}} when is_list(Info) -> Info;
		  _ -> []
		end;
	    _ -> []
	  end
    end.

%%================================
%%  RSAPublicKey
%%================================
enc_RSAPublicKey(Val) ->
    enc_RSAPublicKey(Val, [<<48>>]).

enc_RSAPublicKey(Val, TagIn) ->
    {_, Cindex1, Cindex2} = Val,
    %%-------------------------------------------------
    %% attribute modulus(1) with type INTEGER
    %%-------------------------------------------------
    {EncBytes1, EncLen1} = encode_integer([], Cindex1,
					  [<<2>>]),
    %%-------------------------------------------------
    %% attribute publicExponent(2) with type INTEGER
    %%-------------------------------------------------
    {EncBytes2, EncLen2} = encode_integer([], Cindex2,
					  [<<2>>]),
    BytesSoFar = [EncBytes1, EncBytes2],
    LenSoFar = EncLen1 + EncLen2,
    encode_tags(TagIn, BytesSoFar, LenSoFar).

dec_RSAPublicKey(Tlv) -> dec_RSAPublicKey(Tlv, [16]).

dec_RSAPublicKey(Tlv, TagIn) ->
    %%-------------------------------------------------
    %% decode tag and length
    %%-------------------------------------------------
    Tlv1 = match_tags(Tlv, TagIn),
    %%-------------------------------------------------
    %% attribute modulus(1) with type INTEGER
    %%-------------------------------------------------
    [V1 | Tlv2] = Tlv1,
    Term1 = decode_integer(V1, [], [2]),
    %%-------------------------------------------------
    %% attribute publicExponent(2) with type INTEGER
    %%-------------------------------------------------
    [V2 | Tlv3] = Tlv2,
    Term2 = decode_integer(V2, [], [2]),
    case Tlv3 of
      [] -> true;
      _ ->
	  exit({error,
		{asn1, {unexpected, Tlv3}}}) % extra fields not allowed
    end,
    {'RSAPublicKey', Term1, Term2}.

%%================================
%%  RSAPrivateKey
%%================================
enc_RSAPrivateKey(Val) ->
    enc_RSAPrivateKey(Val, [<<48>>]).

enc_RSAPrivateKey(Val, TagIn) ->
    {_, Cindex1, Cindex2, Cindex3, Cindex4, Cindex5,
     Cindex6, Cindex7, Cindex8, Cindex9, Cindex10} =
	Val,
    %%-------------------------------------------------
    %% attribute version(1) with type INTEGER
    %%-------------------------------------------------
    {EncBytes1, EncLen1} = encode_integer([], Cindex1,
					  [{'two-prime', 0}, {multi, 1}],
					  [<<2>>]),
    %%-------------------------------------------------
    %% attribute modulus(2) with type INTEGER
    %%-------------------------------------------------
    {EncBytes2, EncLen2} = encode_integer([], Cindex2,
					  [<<2>>]),
    %%-------------------------------------------------
    %% attribute publicExponent(3) with type INTEGER
    %%-------------------------------------------------
    {EncBytes3, EncLen3} = encode_integer([], Cindex3,
					  [<<2>>]),
    %%-------------------------------------------------
    %% attribute privateExponent(4) with type INTEGER
    %%-------------------------------------------------
    {EncBytes4, EncLen4} = encode_integer([], Cindex4,
					  [<<2>>]),
    %%-------------------------------------------------
    %% attribute prime1(5) with type INTEGER
    %%-------------------------------------------------
    {EncBytes5, EncLen5} = encode_integer([], Cindex5,
					  [<<2>>]),
    %%-------------------------------------------------
    %% attribute prime2(6) with type INTEGER
    %%-------------------------------------------------
    {EncBytes6, EncLen6} = encode_integer([], Cindex6,
					  [<<2>>]),
    %%-------------------------------------------------
    %% attribute exponent1(7) with type INTEGER
    %%-------------------------------------------------
    {EncBytes7, EncLen7} = encode_integer([], Cindex7,
					  [<<2>>]),
    %%-------------------------------------------------
    %% attribute exponent2(8) with type INTEGER
    %%-------------------------------------------------
    {EncBytes8, EncLen8} = encode_integer([], Cindex8,
					  [<<2>>]),
    %%-------------------------------------------------
    %% attribute coefficient(9) with type INTEGER
    %%-------------------------------------------------
    {EncBytes9, EncLen9} = encode_integer([], Cindex9,
					  [<<2>>]),
    %%-------------------------------------------------
    %% attribute otherPrimeInfos(10)   External PKCS-1:OtherPrimeInfos OPTIONAL
    %%-------------------------------------------------
    {EncBytes10, EncLen10} = case Cindex10 of
			       asn1_NOVALUE -> {<<>>, 0};
			       _ -> enc_OtherPrimeInfos(Cindex10, [<<48>>])
			     end,
    BytesSoFar = [EncBytes1, EncBytes2, EncBytes3,
		  EncBytes4, EncBytes5, EncBytes6, EncBytes7, EncBytes8,
		  EncBytes9, EncBytes10],
    LenSoFar = EncLen1 + EncLen2 + EncLen3 + EncLen4 +
		 EncLen5
		 + EncLen6
		 + EncLen7
		 + EncLen8
		 + EncLen9
		 + EncLen10,
    encode_tags(TagIn, BytesSoFar, LenSoFar).

dec_RSAPrivateKey(Tlv) -> dec_RSAPrivateKey(Tlv, [16]).

dec_RSAPrivateKey(Tlv, TagIn) ->
    %%-------------------------------------------------
    %% decode tag and length
    %%-------------------------------------------------
    Tlv1 = match_tags(Tlv, TagIn),
    %%-------------------------------------------------
    %% attribute version(1) with type INTEGER
    %%-------------------------------------------------
    [V1 | Tlv2] = Tlv1,
    Term1 = decode_integer(V1, [],
			   [{'two-prime', 0}, {multi, 1}], [2]),
    %%-------------------------------------------------
    %% attribute modulus(2) with type INTEGER
    %%-------------------------------------------------
    [V2 | Tlv3] = Tlv2,
    Term2 = decode_integer(V2, [], [2]),
    %%-------------------------------------------------
    %% attribute publicExponent(3) with type INTEGER
    %%-------------------------------------------------
    [V3 | Tlv4] = Tlv3,
    Term3 = decode_integer(V3, [], [2]),
    %%-------------------------------------------------
    %% attribute privateExponent(4) with type INTEGER
    %%-------------------------------------------------
    [V4 | Tlv5] = Tlv4,
    Term4 = decode_integer(V4, [], [2]),
    %%-------------------------------------------------
    %% attribute prime1(5) with type INTEGER
    %%-------------------------------------------------
    [V5 | Tlv6] = Tlv5,
    Term5 = decode_integer(V5, [], [2]),
    %%-------------------------------------------------
    %% attribute prime2(6) with type INTEGER
    %%-------------------------------------------------
    [V6 | Tlv7] = Tlv6,
    Term6 = decode_integer(V6, [], [2]),
    %%-------------------------------------------------
    %% attribute exponent1(7) with type INTEGER
    %%-------------------------------------------------
    [V7 | Tlv8] = Tlv7,
    Term7 = decode_integer(V7, [], [2]),
    %%-------------------------------------------------
    %% attribute exponent2(8) with type INTEGER
    %%-------------------------------------------------
    [V8 | Tlv9] = Tlv8,
    Term8 = decode_integer(V8, [], [2]),
    %%-------------------------------------------------
    %% attribute coefficient(9) with type INTEGER
    %%-------------------------------------------------
    [V9 | Tlv10] = Tlv9,
    Term9 = decode_integer(V9, [], [2]),
    %%-------------------------------------------------
    %% attribute otherPrimeInfos(10)   External PKCS-1:OtherPrimeInfos OPTIONAL
    %%-------------------------------------------------
    {Term10, Tlv11} = case Tlv10 of
			[{16, V10} | TempTlv11] ->
			    {dec_OtherPrimeInfos(V10, []), TempTlv11};
			_ -> {asn1_NOVALUE, Tlv10}
		      end,
    case Tlv11 of
      [] -> true;
      _ ->
	  exit({error,
		{asn1, {unexpected, Tlv11}}}) % extra fields not allowed
    end,
    {'RSAPrivateKey', Term1, Term2, Term3, Term4, Term5,
     Term6, Term7, Term8, Term9, Term10}.

%%================================
%%  Version
%%================================
enc_Version(Val) -> enc_Version(Val, [<<2>>]).

enc_Version({'Version', Val}, TagIn) ->
    enc_Version(Val, TagIn);
enc_Version(Val, TagIn) ->
    encode_integer([], Val, [{'two-prime', 0}, {multi, 1}],
		   TagIn).

dec_Version(Tlv) -> dec_Version(Tlv, [2]).

dec_Version(Tlv, TagIn) ->
    decode_integer(Tlv, [], [{'two-prime', 0}, {multi, 1}],
		   TagIn).

%%================================
%%  OtherPrimeInfos
%%================================
enc_OtherPrimeInfos(Val) ->
    enc_OtherPrimeInfos(Val, [<<48>>]).

enc_OtherPrimeInfos({'OtherPrimeInfos', Val}, TagIn) ->
    enc_OtherPrimeInfos(Val, TagIn);
enc_OtherPrimeInfos(Val, TagIn) ->
    {EncBytes, EncLen} = enc_OtherPrimeInfos_components(Val,
							[], 0),
    encode_tags(TagIn, EncBytes, EncLen).

enc_OtherPrimeInfos_components([], AccBytes, AccLen) ->
    {lists:reverse(AccBytes), AccLen};
enc_OtherPrimeInfos_components([H | T], AccBytes,
			       AccLen) ->
    {EncBytes, EncLen} = enc_OtherPrimeInfo(H, [<<48>>]),
    enc_OtherPrimeInfos_components(T, [EncBytes | AccBytes],
				   AccLen + EncLen).

dec_OtherPrimeInfos(Tlv) ->
    dec_OtherPrimeInfos(Tlv, [16]).

dec_OtherPrimeInfos(Tlv, TagIn) ->
    %%-------------------------------------------------
    %% decode tag and length
    %%-------------------------------------------------
    Tlv1 = match_tags(Tlv, TagIn),
    [dec_OtherPrimeInfo(V1, [16]) || V1 <- Tlv1].

%%================================
%%  OtherPrimeInfo
%%================================
enc_OtherPrimeInfo(Val) ->
    enc_OtherPrimeInfo(Val, [<<48>>]).

enc_OtherPrimeInfo(Val, TagIn) ->
    {_, Cindex1, Cindex2, Cindex3} = Val,
    %%-------------------------------------------------
    %% attribute prime(1) with type INTEGER
    %%-------------------------------------------------
    {EncBytes1, EncLen1} = encode_integer([], Cindex1,
					  [<<2>>]),
    %%-------------------------------------------------
    %% attribute exponent(2) with type INTEGER
    %%-------------------------------------------------
    {EncBytes2, EncLen2} = encode_integer([], Cindex2,
					  [<<2>>]),
    %%-------------------------------------------------
    %% attribute coefficient(3) with type INTEGER
    %%-------------------------------------------------
    {EncBytes3, EncLen3} = encode_integer([], Cindex3,
					  [<<2>>]),
    BytesSoFar = [EncBytes1, EncBytes2, EncBytes3],
    LenSoFar = EncLen1 + EncLen2 + EncLen3,
    encode_tags(TagIn, BytesSoFar, LenSoFar).

dec_OtherPrimeInfo(Tlv) ->
    dec_OtherPrimeInfo(Tlv, [16]).

dec_OtherPrimeInfo(Tlv, TagIn) ->
    %%-------------------------------------------------
    %% decode tag and length
    %%-------------------------------------------------
    Tlv1 = match_tags(Tlv, TagIn),
    %%-------------------------------------------------
    %% attribute prime(1) with type INTEGER
    %%-------------------------------------------------
    [V1 | Tlv2] = Tlv1,
    Term1 = decode_integer(V1, [], [2]),
    %%-------------------------------------------------
    %% attribute exponent(2) with type INTEGER
    %%-------------------------------------------------
    [V2 | Tlv3] = Tlv2,
    Term2 = decode_integer(V2, [], [2]),
    %%-------------------------------------------------
    %% attribute coefficient(3) with type INTEGER
    %%-------------------------------------------------
    [V3 | Tlv4] = Tlv3,
    Term3 = decode_integer(V3, [], [2]),
    case Tlv4 of
      [] -> true;
      _ ->
	  exit({error,
		{asn1, {unexpected, Tlv4}}}) % extra fields not allowed
    end,
    {'OtherPrimeInfo', Term1, Term2, Term3}.

%%================================
%%  Algorithm
%%================================
enc_Algorithm(Val) -> enc_Algorithm(Val, [<<48>>]).

enc_Algorithm(Val, TagIn) ->
    {_, Cindex1, Cindex2} = Val,
    %%-------------------------------------------------
    %% attribute algorithm(1) with type OBJECT IDENTIFIER
    %%-------------------------------------------------
    {EncBytes1, EncLen1} = encode_object_identifier(Cindex1,
						    [<<6>>]),
    %%-------------------------------------------------
    %% attribute parameters(2) with type ASN1_OPEN_TYPE OPTIONAL
    %%-------------------------------------------------
    {EncBytes2, EncLen2} = case Cindex2 of
			     asn1_NOVALUE -> {<<>>, 0};
			     _ -> encode_open_type(Cindex2, [])
			   end,
    BytesSoFar = [EncBytes1, EncBytes2],
    LenSoFar = EncLen1 + EncLen2,
    encode_tags(TagIn, BytesSoFar, LenSoFar).

dec_Algorithm(Tlv) -> dec_Algorithm(Tlv, [16]).

dec_Algorithm(Tlv, TagIn) ->
    %%-------------------------------------------------
    %% decode tag and length
    %%-------------------------------------------------
    Tlv1 = match_tags(Tlv, TagIn),
    %%-------------------------------------------------
    %% attribute algorithm(1) with type OBJECT IDENTIFIER
    %%-------------------------------------------------
    [V1 | Tlv2] = Tlv1,
    Term1 = decode_object_identifier(V1, [6]),
    %%-------------------------------------------------
    %% attribute parameters(2) with type ASN1_OPEN_TYPE OPTIONAL
    %%-------------------------------------------------
    {Term2, Tlv3} = case Tlv2 of
		      [V2 | TempTlv3] ->
			  {decode_open_type_as_binary(V2, []), TempTlv3};
		      _ -> {asn1_NOVALUE, Tlv2}
		    end,
    case Tlv3 of
      [] -> true;
      _ ->
	  exit({error,
		{asn1, {unexpected, Tlv3}}}) % extra fields not allowed
    end,
    {'Algorithm', Term1, Term2}.

%%================================
%%  AlgorithmNull
%%================================
enc_AlgorithmNull(Val) ->
    enc_AlgorithmNull(Val, [<<48>>]).

enc_AlgorithmNull(Val, TagIn) ->
    {_, Cindex1, Cindex2} = Val,
    %%-------------------------------------------------
    %% attribute algorithm(1) with type OBJECT IDENTIFIER
    %%-------------------------------------------------
    {EncBytes1, EncLen1} = encode_object_identifier(Cindex1,
						    [<<6>>]),
    %%-------------------------------------------------
    %% attribute parameters(2) with type NULL
    %%-------------------------------------------------
    {EncBytes2, EncLen2} = encode_null(Cindex2, [<<5>>]),
    BytesSoFar = [EncBytes1, EncBytes2],
    LenSoFar = EncLen1 + EncLen2,
    encode_tags(TagIn, BytesSoFar, LenSoFar).

dec_AlgorithmNull(Tlv) -> dec_AlgorithmNull(Tlv, [16]).

dec_AlgorithmNull(Tlv, TagIn) ->
    %%-------------------------------------------------
    %% decode tag and length
    %%-------------------------------------------------
    Tlv1 = match_tags(Tlv, TagIn),
    %%-------------------------------------------------
    %% attribute algorithm(1) with type OBJECT IDENTIFIER
    %%-------------------------------------------------
    [V1 | Tlv2] = Tlv1,
    Term1 = decode_object_identifier(V1, [6]),
    %%-------------------------------------------------
    %% attribute parameters(2) with type NULL
    %%-------------------------------------------------
    [V2 | Tlv3] = Tlv2,
    Term2 = decode_null(V2, [5]),
    case Tlv3 of
      [] -> true;
      _ ->
	  exit({error,
		{asn1, {unexpected, Tlv3}}}) % extra fields not allowed
    end,
    {'AlgorithmNull', Term1, Term2}.

%%================================
%%  RSASSA-PSS-params
%%================================
'enc_RSASSA-PSS-params'(Val) ->
    'enc_RSASSA-PSS-params'(Val, [<<48>>]).

'enc_RSASSA-PSS-params'(Val, TagIn) ->
    {_, Cindex1, Cindex2, Cindex3, Cindex4} = Val,
    %%-------------------------------------------------
    %% attribute hashAlgorithm(1)   External PKCS-1:Algorithm
    %%-------------------------------------------------
    {EncBytes1, EncLen1} = enc_Algorithm(Cindex1,
					 [<<48>>, <<160>>]),
    %%-------------------------------------------------
    %% attribute maskGenAlgorithm(2)   External PKCS-1:Algorithm
    %%-------------------------------------------------
    {EncBytes2, EncLen2} = enc_Algorithm(Cindex2,
					 [<<48>>, <<161>>]),
    %%-------------------------------------------------
    %% attribute saltLength(3) with type INTEGER DEFAULT = 20
    %%-------------------------------------------------
    {EncBytes3, EncLen3} = case catch check_int(20, Cindex3,
						[])
			       of
			     true -> {[], 0};
			     _ -> encode_integer([], Cindex3, [<<2>>, <<162>>])
			   end,
    %%-------------------------------------------------
    %% attribute trailerField(4) with type INTEGER DEFAULT = 1
    %%-------------------------------------------------
    {EncBytes4, EncLen4} = case catch check_int(1, Cindex4,
						[{trailerFieldBC, 1}])
			       of
			     true -> {[], 0};
			     _ ->
				 encode_integer([], Cindex4,
						[{trailerFieldBC, 1}],
						[<<2>>, <<163>>])
			   end,
    BytesSoFar = [EncBytes1, EncBytes2, EncBytes3,
		  EncBytes4],
    LenSoFar = EncLen1 + EncLen2 + EncLen3 + EncLen4,
    encode_tags(TagIn, BytesSoFar, LenSoFar).

'dec_RSASSA-PSS-params'(Tlv) ->
    'dec_RSASSA-PSS-params'(Tlv, [16]).

'dec_RSASSA-PSS-params'(Tlv, TagIn) ->
    %%-------------------------------------------------
    %% decode tag and length
    %%-------------------------------------------------
    Tlv1 = match_tags(Tlv, TagIn),
    %%-------------------------------------------------
    %% attribute hashAlgorithm(1)   External PKCS-1:Algorithm
    %%-------------------------------------------------
    [V1 | Tlv2] = Tlv1,
    Term1 = dec_Algorithm(V1, [131072, 16]),
    %%-------------------------------------------------
    %% attribute maskGenAlgorithm(2)   External PKCS-1:Algorithm
    %%-------------------------------------------------
    [V2 | Tlv3] = Tlv2,
    Term2 = dec_Algorithm(V2, [131073, 16]),
    %%-------------------------------------------------
    %% attribute saltLength(3) with type INTEGER DEFAULT = 20
    %%-------------------------------------------------
    {Term3, Tlv4} = case Tlv3 of
		      [{131074, V3} | TempTlv4] ->
			  {decode_integer(V3, [], [2]), TempTlv4};
		      _ -> {20, Tlv3}
		    end,
    %%-------------------------------------------------
    %% attribute trailerField(4) with type INTEGER DEFAULT = 1
    %%-------------------------------------------------
    {Term4, Tlv5} = case Tlv4 of
		      [{131075, V4} | TempTlv5] ->
			  {decode_integer(V4, [], [{trailerFieldBC, 1}], [2]),
			   TempTlv5};
		      _ -> {1, Tlv4}
		    end,
    case Tlv5 of
      [] -> true;
      _ ->
	  exit({error,
		{asn1, {unexpected, Tlv5}}}) % extra fields not allowed
    end,
    {'RSASSA-PSS-params', Term1, Term2, Term3, Term4}.

%%================================
%%  TrailerField
%%================================
enc_TrailerField(Val) -> enc_TrailerField(Val, [<<2>>]).

enc_TrailerField({'TrailerField', Val}, TagIn) ->
    enc_TrailerField(Val, TagIn);
enc_TrailerField(Val, TagIn) ->
    encode_integer([], Val, [{trailerFieldBC, 1}], TagIn).

dec_TrailerField(Tlv) -> dec_TrailerField(Tlv, [2]).

dec_TrailerField(Tlv, TagIn) ->
    decode_integer(Tlv, [], [{trailerFieldBC, 1}], TagIn).

%%================================
%%  DigestInfo
%%================================
enc_DigestInfo(Val) -> enc_DigestInfo(Val, [<<48>>]).

enc_DigestInfo(Val, TagIn) ->
    {_, Cindex1, Cindex2} = Val,
    %%-------------------------------------------------
    %% attribute digestAlgorithm(1)   External PKCS-1:Algorithm
    %%-------------------------------------------------
    {EncBytes1, EncLen1} = enc_Algorithm(Cindex1, [<<48>>]),
    %%-------------------------------------------------
    %% attribute digest(2) with type OCTET STRING
    %%-------------------------------------------------
    {EncBytes2, EncLen2} = encode_octet_string([], Cindex2,
					       [<<4>>]),
    BytesSoFar = [EncBytes1, EncBytes2],
    LenSoFar = EncLen1 + EncLen2,
    encode_tags(TagIn, BytesSoFar, LenSoFar).

dec_DigestInfo(Tlv) -> dec_DigestInfo(Tlv, [16]).

dec_DigestInfo(Tlv, TagIn) ->
    %%-------------------------------------------------
    %% decode tag and length
    %%-------------------------------------------------
    Tlv1 = match_tags(Tlv, TagIn),
    %%-------------------------------------------------
    %% attribute digestAlgorithm(1)   External PKCS-1:Algorithm
    %%-------------------------------------------------
    [V1 | Tlv2] = Tlv1,
    Term1 = dec_Algorithm(V1, [16]),
    %%-------------------------------------------------
    %% attribute digest(2) with type OCTET STRING
    %%-------------------------------------------------
    [V2 | Tlv3] = Tlv2,
    Term2 = decode_octet_string(V2, [], [4]),
    case Tlv3 of
      [] -> true;
      _ ->
	  exit({error,
		{asn1, {unexpected, Tlv3}}}) % extra fields not allowed
    end,
    {'DigestInfo', Term1, Term2}.

%%================================
%%  DigestInfoNull
%%================================
enc_DigestInfoNull(Val) ->
    enc_DigestInfoNull(Val, [<<48>>]).

enc_DigestInfoNull(Val, TagIn) ->
    {_, Cindex1, Cindex2} = Val,
    %%-------------------------------------------------
    %% attribute digestAlgorithm(1)   External PKCS-1:AlgorithmNull
    %%-------------------------------------------------
    {EncBytes1, EncLen1} = enc_AlgorithmNull(Cindex1,
					     [<<48>>]),
    %%-------------------------------------------------
    %% attribute digest(2) with type OCTET STRING
    %%-------------------------------------------------
    {EncBytes2, EncLen2} = encode_octet_string([], Cindex2,
					       [<<4>>]),
    BytesSoFar = [EncBytes1, EncBytes2],
    LenSoFar = EncLen1 + EncLen2,
    encode_tags(TagIn, BytesSoFar, LenSoFar).

dec_DigestInfoNull(Tlv) ->
    dec_DigestInfoNull(Tlv, [16]).

dec_DigestInfoNull(Tlv, TagIn) ->
    %%-------------------------------------------------
    %% decode tag and length
    %%-------------------------------------------------
    Tlv1 = match_tags(Tlv, TagIn),
    %%-------------------------------------------------
    %% attribute digestAlgorithm(1)   External PKCS-1:AlgorithmNull
    %%-------------------------------------------------
    [V1 | Tlv2] = Tlv1,
    Term1 = dec_AlgorithmNull(V1, [16]),
    %%-------------------------------------------------
    %% attribute digest(2) with type OCTET STRING
    %%-------------------------------------------------
    [V2 | Tlv3] = Tlv2,
    Term2 = decode_octet_string(V2, [], [4]),
    case Tlv3 of
      [] -> true;
      _ ->
	  exit({error,
		{asn1, {unexpected, Tlv3}}}) % extra fields not allowed
    end,
    {'DigestInfoNull', Term1, Term2}.

'pkcs-1'() -> {1, 2, 840, 113549, 1, 1}.

rsaEncryption() -> {1, 2, 840, 113549, 1, 1, 1}.

'id-RSAES-OAEP'() -> {1, 2, 840, 113549, 1, 1, 7}.

'id-pSpecified'() -> {1, 2, 840, 113549, 1, 1, 9}.

'id-RSASSA-PSS'() -> {1, 2, 840, 113549, 1, 1, 10}.

md2WithRSAEncryption() -> {1, 2, 840, 113549, 1, 1, 2}.

md5WithRSAEncryption() -> {1, 2, 840, 113549, 1, 1, 4}.

sha1WithRSAEncryption() -> {1, 2, 840, 113549, 1, 1, 5}.

sha256WithRSAEncryption() ->
    {1, 2, 840, 113549, 1, 1, 11}.

sha384WithRSAEncryption() ->
    {1, 2, 840, 113549, 1, 1, 12}.

sha512WithRSAEncryption() ->
    {1, 2, 840, 113549, 1, 1, 13}.

'id-sha1'() -> {1, 3, 14, 3, 2, 26}.

'id-md2'() -> {1, 2, 840, 113549, 2, 2}.

'id-md5'() -> {1, 2, 840, 113549, 2, 5}.

'id-mgf1'() -> {1, 2, 840, 113549, 1, 1, 8}.

%% =====================================================================
%% 
%% The following code stems from module `asn1rt_ber_bin_v2'.
%% 

%% ``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 via the world wide web 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.
%%
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
%% AB. All Rights Reserved.''
%%
%%     $Id$
%%

%% encoding / decoding of BER

-record(module,
	{pos, name, defid, tagdefault = 'EXPLICIT',
	 exports = {exports, []}, imports = {imports, []},
	 extensiondefault = empty, typeorval}).

-record('SEQUENCE',
	{pname = false, tablecinf = false, components = []}).

-record('SET',
	{pname = false, sorted = false, tablecinf = false,
	 components = []}).

-record('ComponentType',
	{pos, name, typespec, prop, tags}).

-record('ObjectClassFieldType',
	{classname, class, fieldname, type}).

-record(typedef,
	{checked = false, pos, name, typespec}).

-record(classdef,
	{checked = false, pos, name, typespec}).

-record(valuedef,
	{checked = false, pos, name, type, value}).

-record(ptypedef,
	{checked = false, pos, name, args, typespec}).

-record(pvaluedef,
	{checked = false, pos, name, args, type, value}).

-record(pvaluesetdef,
	{checked = false, pos, name, args, type, valueset}).

-record(pobjectdef,
	{checked = false, pos, name, args, class, def}).

-record(pobjectsetdef,
	{checked = false, pos, name, args, class, def}).

-record(typereference, {pos, val}).

-record(identifier, {pos, val}).

-record(constraint, {c, e}).

-record('Constraint',
	{'SingleValue' = no, 'SizeConstraint' = no,
	 'ValueRange' = no, 'PermittedAlphabet' = no,
	 'ContainedSubtype' = no, 'TypeConstraint' = no,
	 'InnerSubtyping' = no, e = no, 'Other' = no}).

-record(simpletableattributes,
	{objectsetname, c_name, c_index, usedclassfield,
	 uniqueclassfield, valueindex}).

-record(type,
	{tag = [], def, constraint = [], tablecinf = [],
	 inlined = no}).

-record(objectclass, {fields = [], syntax}).

-record('Object', {classname, gen = true, def}).

-record('ObjectSet',
	{class, gen = true, uniquefname, set}).

-record(tag, {class, number, type, form = 32}).

-record(cmap,
	{single_value = no, contained_subtype = no,
	 value_range = no, size = no, permitted_alphabet = no,
	 type_constraint = no, inner_subtyping = no}).

-record('EXTENSIONMARK', {pos, val}).

-record('SymbolsFromModule', {symbols, module, objid}).

-record('Externaltypereference', {pos, module, type}).

-record('Externalvaluereference', {pos, module, value}).

-record(state,
	{module, mname, type, tname, value, vname, erule,
	 parameters = [], inputmodules, abscomppath = [],
	 recordtopname = [], options, sourcedir}).

-record(gen_state,
	{active = false, prefix, inc_tag_pattern, tag_pattern,
	 inc_type_pattern, type_pattern, func_name, namelist,
	 tobe_refed_funcs = [], gen_refed_funcs = [],
	 generated_functions = [], suffix_index = 1,
	 current_suffix_index}).

% the encoding of class of tag bits 8 and 7

%%% primitive or constructed encoding % bit 6

%%% The tag-number for universal types

% the complete tag-word of built-in types

                                                              % can be CONSTRUCTED

                                                              % can be CONSTRUCTED

                                                               %can be constructed

                                                               %can be constructed

                                                               %can be constructed

                                                               %can be constructed

                                                               %can be constructed

                                                               %can be constructed

                                                               %can be constructed

                                                               %can be constructed

                                                               %can be constructed

                                                               %can be constructed

% encode(Tlv={_Tag={?PRIMITIVE,_},_VList}) ->
%     encode_primitive(Tlv);
% encode(Tlv) ->
%     encode_constructed(Tlv).

encode([Tlv]) -> encode(Tlv);
encode({TlvTag, TlvVal}) when is_list(TlvVal) ->
    %% constructed form of value
    encode_tlv(TlvTag, TlvVal, 32);
encode({TlvTag, TlvVal}) ->
    encode_tlv(TlvTag, TlvVal, 0);
encode(Bin) when is_binary(Bin) -> Bin.

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),
    <<Tag/binary, BinLen/binary, Val/binary>>.

encode_tlv_tag(ClassTagNo, Form) ->
    Class = ClassTagNo bsr 16,
    case encode_tag_val({Class bsl 6, Form,
			 ClassTagNo - (Class bsl 16)})
	of
      T when is_list(T) -> list_to_binary(T);
      T -> T
    end.

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(Tlv),
    encode_tlv_list(Tlvs, [EncTlv | Acc]);
encode_tlv_list([], Acc) ->
    Bin = list_to_binary(lists:reverse(Acc)),
    {Bin, size(Bin)}.

decode(Bin) when is_binary(Bin) ->
    decode_primitive(Bin);
decode(Tlv) -> % assume it is a tlv
    {Tlv, <<>>}.

decode_primitive(Bin) ->
    {{Form, TagNo, Len, V}, Rest} = decode_tlv(Bin),
    case Form of
      1
	  when Len == indefinite -> % constructed
	  {Vlist, Rest2} = decode_constructed_indefinite(V, []),
	  {{TagNo, Vlist}, Rest2};
      1 -> % constructed
	  {{TagNo, decode_constructed(V)}, Rest};
      0 -> % primitive
	  {{TagNo, V}, Rest}
    end.

decode_constructed(<<>>) -> [];
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_tlv(Bin) ->
    {Form, TagNo, Len, Bin2} = decode_tag_and_length(Bin),
    case Len of
      indefinite -> {{Form, TagNo, Len, Bin2}, []};
      _ ->
	  <<V:Len/binary, Bin3/binary>> = Bin2,
	  {{Form, TagNo, Len, V}, Bin3}
    end.

%% skip_tag and skip_length_and_value are rutines used both by
%% decode_partial_incomplete and decode_selective (decode/2).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% 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 | 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({Tag, _V}, [T | _Tt]) ->
    {error, {asn1, {wrong_tag, {Tag, T}}}}.

%%===============================================================================
%%===============================================================================
%%===============================================================================
%% Optionals, preset not filled optionals with asn1_NOVALUE
%%===============================================================================
%%===============================================================================
%%===============================================================================

%%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>>;
%% asumes whole correct tag bitpattern, multiple of 8
encode_tag_val(Tag) when Tag =< 255 ->
    Tag;  %% används denna funktion??!!
%% asumes correct bitpattern of 0-5
encode_tag_val(Tag) -> encode_tag_val2(Tag, []).

encode_tag_val2(Tag, OctAck) when Tag =< 255 ->
    [Tag | OctAck];
encode_tag_val2(Tag, OctAck) ->
    encode_tag_val2(Tag bsr 8, [255 band Tag | OctAck]).

%%===============================================================================
%% Decode a tag
%%
%% decode_tag(OctetListBuffer) -> {{Form, (Class bsl 16)+ TagNo}, RestOfBuffer, RemovedBytes}
%%===============================================================================

decode_tag_and_length(<<Class:2, Form:1, TagNo:5, 0:1,
			Length:7, RestBuffer/binary>>)
    when TagNo < 31 ->
    {Form, Class bsl 16 + TagNo, Length, RestBuffer};
decode_tag_and_length(<<Class:2, Form:1, TagNo:5, 1:1,
			0:7, T/binary>>)
    when TagNo < 31 ->
    {Form, Class bsl 16 + TagNo, indefinite, T};
decode_tag_and_length(<<Class:2, Form:1, TagNo:5, 1:1,
			LL:7, T/binary>>)
    when TagNo < 31 ->
    <<Length:LL/unit:8, RestBuffer/binary>> = T,
    {Form, Class bsl 16 + TagNo, Length, RestBuffer};
decode_tag_and_length(<<Class:2, Form:1, 31:5, 0:1,
			TagNo:7, 0:1, Length:7, RestBuffer/binary>>) ->
    {Form, Class bsl 16 + TagNo, Length, RestBuffer};
decode_tag_and_length(<<Class:2, Form:1, 31:5, 0:1,
			TagNo:7, 1:1, 0:7, T/binary>>) ->
    {Form, Class bsl 16 + TagNo, indefinite, T};
decode_tag_and_length(<<Class:2, Form:1, 31:5, 0:1,
			TagNo:7, 1:1, LL:7, T/binary>>) ->
    <<Length:LL/unit:8, RestBuffer/binary>> = T,
    {Form, Class bsl 16 + TagNo, Length, RestBuffer};
decode_tag_and_length(<<Class:2, Form:1, 31:5,
			Buffer/binary>>) ->
    {TagNo, Buffer1} = decode_tag(Buffer, 0),
    {Length, RestBuffer} = decode_length(Buffer1),
    {Form, Class bsl 16 + TagNo, Length, RestBuffer}.

%% last partial tag
decode_tag(<<0:1, PartialTag:7, Buffer/binary>>,
	   TagAck) ->
    TagNo = TagAck bsl 7 bor PartialTag,
    %%<<TagNo>> = <<TagAck:1, PartialTag:7>>,
    {TagNo, Buffer};
% more tags
decode_tag(<<_:1, PartialTag:7, Buffer/binary>>,
	   TagAck) ->
    TagAck1 = TagAck bsl 7 bor PartialTag,
    %%<<TagAck1:16>> = <<TagAck:1, PartialTag:7,0:8>>,
    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, 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_as_binary(Tlv, TagIn) ->
    case match_tags(Tlv, TagIn) of
      V when is_binary(V) -> V;
      [Tlv2] -> encode(Tlv2);
      Tlv2 -> encode(Tlv2)
    end.

%%===============================================================================
%%===============================================================================
%%===============================================================================
%% Boolean, ITU_T X.690 Chapter 8.2
%%===============================================================================
%%===============================================================================
%%===============================================================================

%%===============================================================================
%% encode_boolean(Integer, ReversedTagList) -> {[Octet],Len}
%%===============================================================================

%%===========================================================================
%% 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 255 | 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 255 | 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),
    %    <<Int:Len/unit:8,Buffer2/binary>> = Bin,
    <<Int:Len/unit:8>> = Bin,
    Int;
%% decoding negative integer values.
decode_integer(Bin = <<1:1, B2:7, Bs/binary>>) ->
    Len = size(Bin),
    %    <<N:Len/unit:8,Buffer2/binary>> = <<B2,Bs/binary>>,
    <<N:Len/unit:8>> = <<B2, Bs/binary>>,
    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

%% 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)

%%============================================================================
%%
%% Real value, ITU_T X.690 Chapter 8.5
%%============================================================================
%%
%% encode real value
%%============================================================================

%%============================================================================
%% 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_real2(Buffer, Form, size(Buffer)).

% decode_real2(Buffer, Form, Len) ->
%     <<First, Buffer2/binary>> = 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)
% 	    <<B7:1,B6:1,B5_4:2,B3_2:2,B1_0:2>> = <<First>>,
% 		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 ->
% 			<<ExpLen1,RestBuffer/binary>> = Buffer2,
% 			<<_:ExpLen1/unit:8,RestBuffer2/binary>> = RestBuffer,
% 			{ ExpLen1 + 2,
% 			  decode_integer2(ExpLen1, RestBuffer, RemBytes1),
% 			  RestBuffer2}
% 		end,
% 	    Length = Len - FirstLen,
% 	    <<LongInt:Length/unit:8,RestBuff/binary>> = 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 named bits
%%=================================================================

%%----------------------------------------
%% get_all_bitposes([list of named bits to set], named_bit_db, []) ->
%%   [sorted_list_of_bitpositions_to_set]
%%----------------------------------------

%%----------------------------------------
%% 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),
%%----------------------------------------

%%=================================================================
%% Do the actual encoding
%%     ([bitlist]) -> {ListLen, UnusedBits, OctetList}
%%=================================================================

%%============================================================================
%% decode bitstring value
%%    (Buffer, Range, NamedNumberList, HasTag, TotalLen) -> {Integer, Remain, RemovedBytes}
%%============================================================================

decode_bit_string2(<<0>>, _NamedNumberList, BinOrOld) ->
    case BinOrOld of
      bin -> {0, <<>>};
      _ -> []
    end;
decode_bit_string2(<<Unused, Bits/binary>>,
		   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,
		  <<B7:1, B6:1, B5:1, B4:1, B3:1, B2:1, B1:1, B0:1,
		    _/binary>>) ->
    lists:sublist([B7, B6, B5, B4, B3, B2, B1, B0],
		  8 - Unused);
decode_bitstring2(Len, Unused,
		  <<B7:1, B6:1, B5:1, B4:1, B3:1, B2:1, B1:1, B0:1,
		    Buffer/binary>>) ->
    [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, 4, 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} = enc_obj_id_tail(Tail, [], 0),
    {[H | R], Lh + Lr}.

enc_obj_id_tail([], Ack, Len) ->
    {lists:reverse(Ack), Len};
enc_obj_id_tail([H | T], Ack, Len) ->
    {B, L} = mk_object_val(H),
    enc_obj_id_tail(T, [B | Ack], Len + L).

%% e_object_identifier([List of Obect Identifiers]) ->
%% {[Encoded Octetlist of ObjIds], IntLength}
%%
%%e_object_identifier([E1, E2 | Tail]) ->
%%    Head = 40*E1 + E2,  % wow!
%%    F = fun(Val, AckLen) ->
%%		{L, Ack} = mk_object_val(Val),
%%		{L, Ack + AckLen}
%%	end,
%%    {Octets, Len} = lists:mapfoldl(F, 0, [Head | Tail]).

%%%%%%%%%%%
%% 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(<<H, T/binary>>, Av, Al) ->
    dec_subidentifiers(T, 0, [Av bsl 7 + H | Al]).

%%============================================================================
%% decode Numeric Printable Teletex Videotex Visible IA5 Graphic General strings
%%    (Buffer, Range, StringType, HasTag, TotalLen) ->
%%                                  {String, Remain, RemovedBytes}
%%============================================================================

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 binary(Val),binary(AccVal) ->
% 		{<<AccVal/binary,Val/binary>>,AccRb+Rb};
% 	    _ when binary(Val), AccVal==[] ->
% 		{Val,AccRb+Rb};				
% 	    _ ->	
% 		{AccVal++Val, AccRb+Rb}
% 	end,

decode_restricted(Bin, StringType, NamedNumberList,
		  BinOrOld) ->
    case StringType of
      3 -> decode_bit_string2(Bin, NamedNumberList, BinOrOld);
      28 -> mk_universal_string(binary_to_list(Bin));
      30 -> mk_BMP_string(binary_to_list(Bin));
      _ -> Bin
    end.

check_and_convert_restricted_string(Val, StringType,
				    Range, NamedNumberList, _BinOrOld) ->
    {StrLen, NewVal} = case StringType of
			 3 when NamedNumberList /= [] -> {no_check, Val};
			 3 when is_list(Val) -> {length(Val), Val};
			 3 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
%%============================================================================

%%===========================================================================
%% decode Universal strings
%%    (Buffer, Range, StringType, HasTag, LenIn) ->
%%                           {String, Remain, RemovedBytes}
%%===========================================================================

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
%%============================================================================

%%============================================================================
%% decode UTF8 string
%%============================================================================

%%============================================================================
%% encode BMP string
%%============================================================================

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
%%============================================================================

%%============================================================================
%% decode Generalized time
%%    (Buffer, Range, HasTag, TotalLen) -> {String, Remain, RemovedBytes}
%%============================================================================

%%============================================================================
%% Universal time, ITU_T X.680 Chapter 40
%%
%% encode UTC time
%%============================================================================

%%============================================================================
%% decode UTC time
%%    (Buffer, Range, HasTag, TotalLen) -> {String, Remain, RemovedBytes}
%%============================================================================

%%============================================================================
%% Length handling
%%
%% Encode length
%%
%% encode_length(Int | indefinite) ->
%%          [<127]| [128 + Int (<127),OctetList] | [16#80]
%%============================================================================

encode_length(indefinite) ->
    {[128], 1}; % 128
encode_length(L) when L =< 127 -> {[L], 1};
encode_length(L) ->
    Oct = minimum_octets(L),
    Len = length(Oct),
    if Len =< 126 -> {[128 + 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 255 | 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>>) ->
    <<Length:LL/unit:8, Rest/binary>> = T, {Length, Rest}.

%%-------------------------------------------------------------------------
%% INTERNAL HELPER FUNCTIONS (not exported)
%%-------------------------------------------------------------------------

collect_parts(TlvList) -> collect_parts(TlvList, []).

collect_parts([{_, L} | Rest], Acc) when is_list(L) ->
    collect_parts(Rest, [collect_parts(L) | Acc]);
collect_parts([{3, <<Unused, Bits/binary>>} | 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([{3, <<Unused, Bits/binary>>} | Rest],
		  Acc, Uacc) ->
    collect_parts_bit(Rest, [Bits | Acc], Unused + Uacc);
collect_parts_bit([], Acc, Uacc) ->
    list_to_binary([Uacc | lists:reverse(Acc)]).

%% =====================================================================
%% 
%% The following code stems from module `asn1rt_check'.
%% 

%% ``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 via the world wide web 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.
%%
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
%% AB. All Rights Reserved.''
%%
%%     $Id$
%%

%%<<< -record(module,
%%<<<         {pos, name, defid, tagdefault = 'EXPLICIT',
%%<<<          exports = {exports, []}, imports = {imports, []},
%%<<<          extensiondefault = empty, typeorval}).

%%<<< -record('SEQUENCE',
%%<<<         {pname = false, tablecinf = false, components = []}).

%%<<< -record('SET',
%%<<<         {pname = false, sorted = false, tablecinf = false,
%%<<<          components = []}).

%%<<< -record('ComponentType',
%%<<<         {pos, name, typespec, prop, tags}).

%%<<< -record('ObjectClassFieldType',
%%<<<         {classname, class, fieldname, type}).

%%<<< -record(typedef,
%%<<<         {checked = false, pos, name, typespec}).

%%<<< -record(classdef,
%%<<<         {checked = false, pos, name, typespec}).

%%<<< -record(valuedef,
%%<<<         {checked = false, pos, name, type, value}).

%%<<< -record(ptypedef,
%%<<<         {checked = false, pos, name, args, typespec}).

%%<<< -record(pvaluedef,
%%<<<         {checked = false, pos, name, args, type, value}).

%%<<< -record(pvaluesetdef,
%%<<<         {checked = false, pos, name, args, type, valueset}).

%%<<< -record(pobjectdef,
%%<<<         {checked = false, pos, name, args, class, def}).

%%<<< -record(pobjectsetdef,
%%<<<         {checked = false, pos, name, args, class, def}).

%%<<< -record(typereference, {pos, val}).

%%<<< -record(identifier, {pos, val}).

%%<<< -record(constraint, {c, e}).

%%<<< -record('Constraint',
%%<<<         {'SingleValue' = no, 'SizeConstraint' = no,
%%<<<          'ValueRange' = no, 'PermittedAlphabet' = no,
%%<<<          'ContainedSubtype' = no, 'TypeConstraint' = no,
%%<<<          'InnerSubtyping' = no, e = no, 'Other' = no}).

%%<<< -record(simpletableattributes,
%%<<<         {objectsetname, c_name, c_index, usedclassfield,
%%<<<          uniqueclassfield, valueindex}).

%%<<< -record(type,
%%<<<         {tag = [], def, constraint = [], tablecinf = [],
%%<<<          inlined = no}).

%%<<< -record(objectclass, {fields = [], syntax}).

%%<<< -record('Object', {classname, gen = true, def}).

%%<<< -record('ObjectSet',
%%<<<         {class, gen = true, uniquefname, set}).

%%<<< -record(tag, {class, number, type, form = 32}).

%%<<< -record(cmap,
%%<<<         {single_value = no, contained_subtype = no,
%%<<<          value_range = no, size = no, permitted_alphabet = no,
%%<<<          type_constraint = no, inner_subtyping = no}).

%%<<< -record('EXTENSIONMARK', {pos, val}).

%%<<< -record('SymbolsFromModule', {symbols, module, objid}).

%%<<< -record('Externaltypereference', {pos, module, type}).

%%<<< -record('Externalvaluereference', {pos, module, value}).

%%<<< -record(state,
%%<<<         {module, mname, type, tname, value, vname, erule,
%%<<<          parameters = [], inputmodules, abscomppath = [],
%%<<<          recordtopname = [], options, sourcedir}).

%%<<< -record(gen_state,
%%<<<         {active = false, prefix, inc_tag_pattern, tag_pattern,
%%<<<          inc_type_pattern, type_pattern, func_name, namelist,
%%<<<          tobe_refed_funcs = [], gen_refed_funcs = [],
%%<<<          generated_functions = [], suffix_index = 1,
%%<<<          current_suffix_index}).

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}).

%% =====================================================================
%% 
%% The following code stems from module `asn1rt_driver_handler'.
%% 

%% ``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 via the world wide web 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.
%%
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
%% AB. All Rights Reserved.''
%%
%%     $Id$
%%

%%<<< -record(module,
%%<<<         {pos, name, defid, tagdefault = 'EXPLICIT',
%%<<<          exports = {exports, []}, imports = {imports, []},
%%<<<          extensiondefault = empty, typeorval}).

%%<<< -record('SEQUENCE',
%%<<<         {pname = false, tablecinf = false, components = []}).

%%<<< -record('SET',
%%<<<         {pname = false, sorted = false, tablecinf = false,
%%<<<          components = []}).

%%<<< -record('ComponentType',
%%<<<         {pos, name, typespec, prop, tags}).

%%<<< -record('ObjectClassFieldType',
%%<<<         {classname, class, fieldname, type}).

%%<<< -record(typedef,
%%<<<         {checked = false, pos, name, typespec}).

%%<<< -record(classdef,
%%<<<         {checked = false, pos, name, typespec}).

%%<<< -record(valuedef,
%%<<<         {checked = false, pos, name, type, value}).

%%<<< -record(ptypedef,
%%<<<         {checked = false, pos, name, args, typespec}).

%%<<< -record(pvaluedef,
%%<<<         {checked = false, pos, name, args, type, value}).

%%<<< -record(pvaluesetdef,
%%<<<         {checked = false, pos, name, args, type, valueset}).

%%<<< -record(pobjectdef,
%%<<<         {checked = false, pos, name, args, class, def}).

%%<<< -record(pobjectsetdef,
%%<<<         {checked = false, pos, name, args, class, def}).

%%<<< -record(typereference, {pos, val}).

%%<<< -record(identifier, {pos, val}).

%%<<< -record(constraint, {c, e}).

%%<<< -record('Constraint',
%%<<<         {'SingleValue' = no, 'SizeConstraint' = no,
%%<<<          'ValueRange' = no, 'PermittedAlphabet' = no,
%%<<<          'ContainedSubtype' = no, 'TypeConstraint' = no,
%%<<<          'InnerSubtyping' = no, e = no, 'Other' = no}).

%%<<< -record(simpletableattributes,
%%<<<         {objectsetname, c_name, c_index, usedclassfield,
%%<<<          uniqueclassfield, valueindex}).

%%<<< -record(type,
%%<<<         {tag = [], def, constraint = [], tablecinf = [],
%%<<<          inlined = no}).

%%<<< -record(objectclass, {fields = [], syntax}).

%%<<< -record('Object', {classname, gen = true, def}).

%%<<< -record('ObjectSet',
%%<<<         {class, gen = true, uniquefname, set}).

%%<<< -record(tag, {class, number, type, form = 32}).

%%<<< -record(cmap,
%%<<<         {single_value = no, contained_subtype = no,
%%<<<          value_range = no, size = no, permitted_alphabet = no,
%%<<<          type_constraint = no, inner_subtyping = no}).

%%<<< -record('EXTENSIONMARK', {pos, val}).

%%<<< -record('SymbolsFromModule', {symbols, module, objid}).

%%<<< -record('Externaltypereference', {pos, module, type}).

%%<<< -record('Externalvaluereference', {pos, module, value}).

%%<<< -record(state,
%%<<<         {module, mname, type, tname, value, vname, erule,
%%<<<          parameters = [], inputmodules, abscomppath = [],
%%<<<          recordtopname = [], options, sourcedir}).

%%<<< -record(gen_state,
%%<<<         {active = false, prefix, inc_tag_pattern, tag_pattern,
%%<<<          inc_type_pattern, type_pattern, func_name, namelist,
%%<<<          tobe_refed_funcs = [], gen_refed_funcs = [],
%%<<<          generated_functions = [], suffix_index = 1,
%%<<<          current_suffix_index}).

