查看源代码 asn1ct (asn1 v5.3.1)
ASN.1 编译器和编译时支持函数
ASN.1 编译器接收一个 ASN.1 模块作为输入,并生成一个相应的 Erlang 模块,该模块可以编码和解码指定的数据类型。或者,编译器接收一个指定所有输入模块的规范模块,并生成一个带有编码/解码函数的模块。此外,在开发处理 ASN.1 数据(编码为 BER
或 PER
)的应用程序期间,可以使用一些通用函数。
注意
默认情况下,在 Erlang/OTP 17 中,
BIT STRING
和OCTET STRING
类型作为 Erlang 术语的表示方式已更改。BIT STRING
值现在是 Erlang 位字符串,而OCTET STRING
值是二进制数据。此外,未解码的开放类型现在封装在asn1_OPENTYPE
元组中。有关详细信息,请参阅用户指南中的 BIT STRING、OCTET STRING 和 ASN.1 信息对象。要恢复为旧的类型表示方式,请使用选项
legacy_erlang_types
。
概要
函数
编译 ASN.1 模块 Asn1Module
,并生成一个 Erlang 模块 Asn1Module.erl
,其中包含 ASN.1 模块中定义的所有类型的编码和解码函数。
测试 Module
中所有类型的编码和解码。
测试 Module
的编码和解码。
执行对 Module
中类型的编码和解码的测试。
返回一个 Erlang 项,该项是 ASN.1 类型 Type
的有效 Erlang 表示形式值的示例。
函数
-spec compile(Asn1Module, Options) -> ok | {error, Reason} when Asn1Module :: atom() | string(), Options :: [Option | OldOption], Option :: ber | per | uper | jer | der | compact_bit_string | legacy_bit_string | legacy_erlang_types | noobj | {n2n, EnumTypeName :: term()} | {outdir, Dir :: term()} | {i, IncludeDir :: term()} | asn1config | undec_rest | no_ok_wrapper | {macro_name_prefix, Prefix} | {record_name_prefix, Prefix} | verbose | warnings_as_errors | deterministic, OldOption :: ber | per, Reason :: term(), Prefix :: string().
编译 ASN.1 模块 Asn1Module
,并生成一个 Erlang 模块 Asn1Module.erl
,其中包含 ASN.1 模块中定义的所有类型的编码和解码函数。
对于模块中定义的每个 ASN.1 值,都会生成一个 Erlang 函数,该函数以 Erlang 表示形式返回该值。
如果 Asn1Module
是一个不带扩展名的文件名,则首先假定为 ".asn1"
,然后假定为 ".asn"
,最后假定为 ".py"
(以与旧的 ASN.1 编译器兼容)。Asn1Module
可以是包含扩展名或不包含扩展名的完整路径名(相对或绝对)。
如果需要将一组 ASN.1
模块编译为包含编码/解码函数的 Erlang 文件,请在一个配置文件中列出所有涉及的文件,每行一个文件。此配置文件必须具有双扩展名 ".set.asn1"
(".asn1"
也可以是 ".asn"
或 ".py"
)。如果输入文件为 File1.asn1
、File2.asn1
和 File3.asn1
,则配置文件应如下所示
File1.asn1
File2.asn1
File3.asn1
在这种情况下,输出文件的名称将从配置文件中获取。如果配置文件名为 SetOfFiles.set.asn1
,则输出文件的名称为 SetOfFiles.hrl, SetOfFiles.erl, 和 SetOfFiles.asn1db
。
有时,在 ASN.1
模块系统中,不同的模块可以具有不同的默认标记模式,例如,一个使用 AUTOMATIC
,另一个使用 IMPLICIT
。多文件编译会解析默认标记,就像单独编译模块一样。
名称冲突是多文件编译中可能发生的不良影响。编译器通过以下两种方式之一解决此问题
- 如果定义相同,则输出模块仅保留一个具有原始名称的定义。
- 如果定义具有相同的名称,但在定义中有所不同,则会重命名它们。新名称是定义名称和原始模块名称的串联。
如果发生名称冲突,编译器会报告一条 "NOTICE: ..."
消息,该消息会说明是否已重命名某个定义,以及必须用于编码/解码数据的新名称。
Options
是一个列表,其中包含特定于 ASN.1 编译器的选项和应用于 Erlang 编译器的选项。ASN.1 编译器会将任何无法识别的选项传递给 Erlang 编译器。可用的选项如下
ber | per | uper | jer
- 要使用的编码规则。支持的编码规则是基本编码规则 (ber
)、打包编码规则 (per
) 对齐、PER 未对齐 (uper
) 和 JSON 编码规则 (jer
)。jer
选项可以单独使用,以生成仅支持 JER 编码/解码的模块,也可以用作ber
、per
和uper
的补充选项,在这种情况下,将生成一个处理主要编码规则和 JER 的模块。在这种情况下,JER 的导出函数将是jer_encode(Type, Value)
和jer_decode(Type, Bytes)
。JER (ITU-T X.697) 在 OTP 22 中是实验性的。支持 X.697 标准的一个子集,例如,不支持
- JER 编码指令
- REAL 类型
更改
在 Erlang/OTP 27 及更高版本中,STDLIB 中的模块
json
用于编码和解码 JSON。在 Erlang/OTP 27 之前,需要提供外部 JSON 库。如果省略编码规则选项,则默认值为
ber
。生成的 Erlang 模块始终与 ASN.1 模块具有相同的名称。因此,在运行时,每个 ASN.1 模块只能使用一种编码规则。
der
- 使用此选项时,会选择有别编码规则 (der
)。DER 被视为 BER 编码规则的特殊变体。因此,此选项仅与选项ber
一起使用才有意义。此选项有时会在编码时添加排序和值检查,这意味着编码速度较慢。解码例程与ber
相同。maps
- 此选项将类型SEQUENCE
和SET
的表示形式更改为使用映射(而不是记录)。此选项还会禁止生成.hrl
文件。有关详细信息,请参阅用户指南中的 SEQUENCE 和 SET 的映射表示 部分。
compact_bit_string
-BIT STRING
类型被解码为“紧凑表示法”。不建议新代码使用此选项。
有关详细信息,请参阅用户指南中的 BIT STRING 部分。
此选项隐含选项
legacy_erlang_types
,并且不能与选项maps
组合使用。legacy_bit_string
-BIT STRING
类型被解码为旧格式,即零和一的列表。不建议新代码使用此选项。
有关详细信息,请参阅用户指南中的 BIT STRING 部分。
此选项隐含选项
legacy_erlang_types
,并且不能与选项maps
组合使用。legacy_erlang_types
- 使用与 Erlang/OTP R16 中相同的 Erlang 类型来表示BIT STRING
和OCTET STRING
。不建议新代码使用此选项。
有关详细信息,请参阅用户指南中的 BIT STRING 部分和 OCTET STRING 部分。
此选项不能与选项
maps
组合使用。{n2n, EnumTypeName}
- 告诉编译器为指定的EnumTypeName
生成名称(作为原子)和数字之间的转换函数,反之亦然。可以多次出现此选项以指定多个类型名称。类型名称必须在 ASN.1 规范中声明为ENUMERATIONS
。如果
EnumTypeName
在 ASN.1 规范中不存在,则编译将停止并显示错误代码。生成的转换函数名为
name2num_EnumTypeName/1
和num2name_EnumTypeName/1
。noobj
- 不编译(即不生成目标代码)生成的.erl
文件。如果省略此选项,则会编译生成的 Erlang 模块。{i, IncludeDir}
- 将IncludeDir
添加到.asn1db
和 ASN.1 源文件的搜索路径。当一个模块从另一个 ASN.1 模块导入定义时,编译器会尝试打开一个.asn1db
文件。如果未找到.asn1db
文件,则会解析 ASN.1 源文件。可以给出多个{i, IncludeDir}
。{outdir, Dir}
- 指定要放置所有生成文件的目录Dir
。如果省略此选项,则文件将放置在当前目录中。asn1config
- 使用专门的解码(独占或选择性解码)之一时,必须在配置文件中给出指令。选项asn1config
启用专门的解码,并考虑配置文件。配置文件与 ASN.1 规范具有相同的名称,但扩展名为.asn1config
。有关独占解码的说明,请参阅用户指南中的 独占解码 部分。
有关选择性解码的说明,请参阅用户指南中的 选择性解码 部分。
undec_rest
- 默认情况下,解码时,将丢弃 ASN.1 数据结构末尾后的任何字节。如果使用选项undec_rest
编译 ASN.1 模块,则解码函数会返回一个元组{ok, Value, Rest}
,其中Rest
是 ASN.1 数据结构后的字节。Rest
可以是列表或二进制数据。no_ok_wrapper
- 使用此选项时,生成的encode/2
和decode/2
函数不会将成功的返回值包装在{ok,...}
元组中。如果发生任何错误,将引发异常。{macro_name_prefix, Prefix}
- 编译器生成的所有宏名称都以Prefix
为前缀。当单个模块中包含多个包含具有相同名称的宏的协议时,这很有用。{record_name_prefix, Prefix}
- 编译器生成的所有记录名称都以Prefix
为前缀。当单个模块中包含多个包含具有相同名称的记录的协议时,这很有用。verbose
- 使编译器提供更详细的信息,描述其正在执行的操作。warnings_as_errors
- 将警告视为错误。deterministic
- 从-asn1_info()
属性中删除所有非确定性选项。
当编译生成的 .erl
文件时,无法识别的选项会传递给 Erlang 编译器。
编译器生成以下文件
Asn1Module.hrl
(如果定义了任何SET
或SEQUENCE
)Asn1Module.erl
- 包含编码、解码和值函数的 Erlang 模块Asn1Module.asn1db
- 当模块互相IMPORT
定义时,编译器使用的中间格式。
测试 Module
中所有类型的编码和解码。
有关更多详细信息,请参阅 test/3
。
-spec test(Module, Type | Options) -> ok | {error, Reason} when Module :: module(), Type :: atom(), Options :: [{i, IncludeDir :: term()}], Reason :: term().
测试 Module
的编码和解码。
如果第二个参数作为原子 Type
给出,则会测试该类型。
如果第二个参数作为列表 Options
给出,则这些选项将用于测试模块中的所有类型。
有关更多详细信息,请参阅 test/3
。
-spec test(Module, Type, Value | Options) -> ok | {error, Reason} when Module :: module(), Type :: atom(), Value :: term(), Options :: [{i, IncludeDir :: term()}], Reason :: term().
执行对 Module
中类型的编码和解码的测试。
生成的函数由此函数调用。此函数对于测试以确保生成的编码和解码函数以及常规运行时支持按预期工作很有用。
注意
目前,
test
函数有很多限制。本质上,它们主要适用于基于 1997 年 ASN.1 标准的旧规范,但不适用于大多数现代风格的应用程序。另一个限制是,如果使用了更改代码生成策略的选项(例如macro_name_prefix
和record_name_prefix
选项),则test
函数可能无法工作。
示意性地,模块中的每种类型都会发生以下情况
{ok, Value} = asn1ct:value(Module, Type),
{ok, Bytes} = Module:encode(Type, Value),
{ok, Value} = Module:decode(Type, Bytes).
test
函数使用所有包含模块的 *.asn1db
文件。如果它们位于与当前工作目录不同的目录中,请使用 include
选项添加路径。这仅在自动生成值时需要。对于使用 Value
的静态值,则不需要任何选项。
-spec value(Module, Type) -> {ok, Value} | {error, Reason} when Module :: module(), Type :: atom(), Value :: term(), Reason :: term().
返回一个 Erlang 项,该项是 ASN.1 类型 Type
的有效 Erlang 表示形式值的示例。
该值是一个随机值,并且随后调用此函数对于大多数类型将返回不同的值。
注意
目前,
value
函数有很多限制。本质上,它主要适用于基于 1997 年 ASN.1 标准的旧规范,但不适用于大多数现代风格的应用程序。另一个限制是,如果使用了更改代码生成策略的选项(例如macro_name_prefix
和record_name_prefix
选项),则value
函数可能无法工作。