查看源代码 asn1ct (asn1 v5.3.1)

ASN.1 编译器和编译时支持函数

ASN.1 编译器接收一个 ASN.1 模块作为输入,并生成一个相应的 Erlang 模块,该模块可以编码和解码指定的数据类型。或者,编译器接收一个指定所有输入模块的规范模块,并生成一个带有编码/解码函数的模块。此外,在开发处理 ASN.1 数据(编码为 BERPER)的应用程序期间,可以使用一些通用函数。

注意

默认情况下,在 Erlang/OTP 17 中,BIT STRINGOCTET STRING 类型作为 Erlang 术语的表示方式已更改。BIT STRING 值现在是 Erlang 位字符串,而 OCTET STRING 值是二进制数据。此外,未解码的开放类型现在封装在 asn1_OPENTYPE 元组中。有关详细信息,请参阅用户指南中的 BIT STRINGOCTET STRINGASN.1 信息对象

要恢复为旧的类型表示方式,请使用选项 legacy_erlang_types

概要

函数

编译 ASN.1 模块 Asn1Module,并生成一个 Erlang 模块 Asn1Module.erl,其中包含 ASN.1 模块中定义的所有类型的编码和解码函数。

测试 Module 中所有类型的编码和解码。

测试 Module 的编码和解码。

执行对 Module 中类型的编码和解码的测试。

返回一个 Erlang 项,该项是 ASN.1 类型 Type 的有效 Erlang 表示形式值的示例。

函数

-spec compile(Asn1Module) -> ok | {error, Reason} when Asn1Module :: atom() | string(), Reason :: term().

等同于 compile(Asn1Module, [])

此函数的链接

compile(Asn1Module, Options)

查看源代码
-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.asn1File2.asn1File3.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 编码/解码的模块,也可以用作 berperuper 的补充选项,在这种情况下,将生成一个处理主要编码规则和 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 - 此选项将类型 SEQUENCESET 的表示形式更改为使用映射(而不是记录)。此选项还会禁止生成 .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 STRINGOCTET STRING

    不建议新代码使用此选项。

    有关详细信息,请参阅用户指南中的 BIT STRING 部分和 OCTET STRING 部分。

    此选项不能与选项 maps 组合使用。

  • {n2n, EnumTypeName} - 告诉编译器为指定的 EnumTypeName 生成名称(作为原子)和数字之间的转换函数,反之亦然。可以多次出现此选项以指定多个类型名称。类型名称必须在 ASN.1 规范中声明为 ENUMERATIONS

    如果 EnumTypeName 在 ASN.1 规范中不存在,则编译将停止并显示错误代码。

    生成的转换函数名为 name2num_EnumTypeName/1num2name_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/2decode/2 函数不会将成功的返回值包装在 {ok,...} 元组中。如果发生任何错误,将引发异常。

  • {macro_name_prefix, Prefix} - 编译器生成的所有宏名称都以 Prefix 为前缀。当单个模块中包含多个包含具有相同名称的宏的协议时,这很有用。

  • {record_name_prefix, Prefix} - 编译器生成的所有记录名称都以 Prefix 为前缀。当单个模块中包含多个包含具有相同名称的记录的协议时,这很有用。

  • verbose - 使编译器提供更详细的信息,描述其正在执行的操作。

  • warnings_as_errors - 将警告视为错误。

  • deterministic - 从 -asn1_info() 属性中删除所有非确定性选项。

当编译生成的 .erl 文件时,无法识别的选项会传递给 Erlang 编译器。

编译器生成以下文件

  • Asn1Module.hrl (如果定义了任何 SETSEQUENCE)
  • Asn1Module.erl - 包含编码、解码和值函数的 Erlang 模块
  • Asn1Module.asn1db - 当模块互相 IMPORT 定义时,编译器使用的中间格式。
-spec test(Module) -> ok | {error, Reason} when Module :: module(), Reason :: term().

测试 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_prefixrecord_name_prefix 选项),则 test 函数可能无法工作。

  • test/1 遍历 Module 中的所有类型。
  • test/2 使用随机值测试类型 Type
  • test/3 使用 Value 测试类型 Type

示意性地,模块中的每种类型都会发生以下情况

{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_prefixrecord_name_prefix 选项),则 value 函数可能无法工作。