aboutsummaryrefslogtreecommitdiffstats
path: root/lib/asn1
diff options
context:
space:
mode:
Diffstat (limited to 'lib/asn1')
-rw-r--r--lib/asn1/c_src/asn1_erl_nif.c42
-rw-r--r--lib/asn1/doc/src/Makefile3
-rw-r--r--lib/asn1/doc/src/asn1_getting_started.xml83
-rw-r--r--lib/asn1/doc/src/asn1ct.xml64
-rw-r--r--lib/asn1/doc/src/asn1rt.xml135
-rw-r--r--lib/asn1/doc/src/fascicules.xml18
-rw-r--r--lib/asn1/doc/src/notes.xml145
-rw-r--r--lib/asn1/doc/src/ref_man.xml3
-rw-r--r--lib/asn1/examples/recordnames.txt2
-rw-r--r--lib/asn1/src/Makefile1
-rw-r--r--lib/asn1/src/asn1.app.src1
-rw-r--r--lib/asn1/src/asn1_db.erl28
-rw-r--r--lib/asn1/src/asn1_records.hrl25
-rw-r--r--lib/asn1/src/asn1ct.erl417
-rw-r--r--lib/asn1/src/asn1ct_check.erl173
-rw-r--r--lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl411
-rw-r--r--lib/asn1/src/asn1ct_constructed_per.erl975
-rw-r--r--lib/asn1/src/asn1ct_eval_ext.funcs1
-rw-r--r--lib/asn1/src/asn1ct_func.erl4
-rw-r--r--lib/asn1/src/asn1ct_gen.erl853
-rw-r--r--lib/asn1/src/asn1ct_gen_ber_bin_v2.erl306
-rw-r--r--lib/asn1/src/asn1ct_gen_check.erl193
-rw-r--r--lib/asn1/src/asn1ct_gen_per.erl92
-rw-r--r--lib/asn1/src/asn1ct_imm.erl97
-rw-r--r--lib/asn1/src/asn1ct_name.erl4
-rw-r--r--lib/asn1/src/asn1ct_parser2.erl4
-rw-r--r--lib/asn1/src/asn1ct_value.erl84
-rw-r--r--lib/asn1/src/asn1rt.erl184
-rw-r--r--lib/asn1/src/asn1rt_nif.erl3
-rw-r--r--lib/asn1/src/asn1rtt_ber.erl35
-rw-r--r--lib/asn1/src/asn1rtt_ext.erl64
-rw-r--r--lib/asn1/src/asn1rtt_per_common.erl5
-rw-r--r--lib/asn1/test/Makefile9
-rw-r--r--lib/asn1/test/asn1_SUITE.erl184
-rw-r--r--lib/asn1/test/asn1_SUITE_data/EnumN2N.asn122
-rw-r--r--lib/asn1/test/asn1_SUITE_data/ExtensionDefault.asn112
-rw-r--r--lib/asn1/test/asn1_SUITE_data/HighTagNumbers.asn117
-rw-r--r--lib/asn1/test/asn1_SUITE_data/ImportsFrom.asn13
-rw-r--r--lib/asn1/test/asn1_SUITE_data/ImportsFrom2.asn15
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Maps.asn117
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Prim.asn12
-rw-r--r--lib/asn1/test/asn1_SUITE_data/SeqExtension.asn111
-rw-r--r--lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl4
-rw-r--r--lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Descriptions.asn (renamed from lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Discriptions.asn)2
-rw-r--r--lib/asn1/test/asn1_SUITE_data/test_records.erl4
-rw-r--r--lib/asn1/test/asn1_SUITE_data/testobj.erl14
-rw-r--r--lib/asn1/test/asn1_app_SUITE.erl (renamed from lib/asn1/test/asn1_app_test.erl)60
-rw-r--r--lib/asn1/test/asn1_appup_test.erl58
-rw-r--r--lib/asn1/test/asn1_test_lib.erl107
-rw-r--r--lib/asn1/test/ber_decode_error.erl41
-rw-r--r--lib/asn1/test/h323test.erl31
-rw-r--r--lib/asn1/test/testChoPrim.erl10
-rw-r--r--lib/asn1/test/testContextSwitchingTypes.erl3
-rw-r--r--lib/asn1/test/testExtensionDefault.erl53
-rw-r--r--lib/asn1/test/testInfObj.erl3
-rw-r--r--lib/asn1/test/testInfObjectClass.erl24
-rw-r--r--lib/asn1/test/testMaps.erl50
-rw-r--r--lib/asn1/test/testMultipleLevels.erl8
-rw-r--r--lib/asn1/test/testNBAPsystem.erl16
-rw-r--r--lib/asn1/test/testPrim.erl49
-rw-r--r--lib/asn1/test/testPrimStrings.erl22
-rw-r--r--lib/asn1/test/testRfcs.erl52
-rw-r--r--lib/asn1/test/testSeqExtension.erl40
-rw-r--r--lib/asn1/test/testTCAP.erl3
-rw-r--r--lib/asn1/test/testTimer.erl133
-rw-r--r--lib/asn1/test/testUniqueObjectSets.erl5
-rw-r--r--lib/asn1/test/test_compile_options.erl30
-rw-r--r--lib/asn1/test/test_modified_x420.erl2
-rw-r--r--lib/asn1/vsn.mk2
69 files changed, 2992 insertions, 2571 deletions
diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c
index 4577689fc3..d5aaadb89b 100644
--- a/lib/asn1/c_src/asn1_erl_nif.c
+++ b/lib/asn1/c_src/asn1_erl_nif.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2017. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,7 +21,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include "erl_nif.h"
+#include <erl_nif.h>
/* #define ASN1_DEBUG 1 */
@@ -901,31 +901,35 @@ static int ber_decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_b
/* then get the tag number */
if ((tmp_tag = (int) INVMASK(in_buf[*ib_index],ASN1_CLASSFORM)) < 31) {
- *tag = enif_make_uint(env, tag_no + tmp_tag);
+ *tag = enif_make_uint(env, tag_no | tmp_tag);
(*ib_index)++;
} else {
- int n = 0; /* n is used to check that the 64K limit is not
- exceeded*/
-
/* should check that at least three bytes are left in
in-buffer,at least two tag byte and at least one length byte */
if ((*ib_index + 3) > in_buf_len)
return ASN1_VALUE_ERROR;
(*ib_index)++;
- /* The tag is in the following bytes in in_buf as
- 1ttttttt 1ttttttt ... 0ttttttt, where the t-bits
- is the tag number*/
- /* In practice is the tag size limited to 64K, i.e. 16 bits. If
- the tag is greater then 64K return an error */
- while (((tmp_tag = (int) in_buf[*ib_index]) >= 128) && n < 2) {
- /* m.s.b. = 1 */
- tag_no = tag_no + (MASK(tmp_tag,ASN1_LONG_TAG) << 7);
+ /*
+ * The tag is in the following bytes in in_buf as:
+ *
+ * 1ttttttt 0ttttttt
+ *
+ * or
+ *
+ * 0ttttttt
+ *
+ * where the t-bits is the tag number. If the tag does not
+ * fit in two tag bytes (16K), return an error.
+ */
+ if ((tmp_tag = (int) in_buf[*ib_index]) >= 128) {
+ tag_no = tag_no | (MASK(tmp_tag,ASN1_LONG_TAG) << 7);
(*ib_index)++;
- n++;
- };
- if ((n == 2) && in_buf[*ib_index] > 3)
- return ASN1_TAG_ERROR; /* tag number > 64K */
- tag_no = tag_no + in_buf[*ib_index];
+ }
+ tmp_tag = (int) in_buf[*ib_index];
+ if (tmp_tag >= 128) {
+ return ASN1_TAG_ERROR; /* tag number > 16K */
+ }
+ tag_no = tag_no | tmp_tag;
(*ib_index)++;
*tag = enif_make_uint(env, tag_no);
}
diff --git a/lib/asn1/doc/src/Makefile b/lib/asn1/doc/src/Makefile
index 559836116f..9a388e4e8a 100644
--- a/lib/asn1/doc/src/Makefile
+++ b/lib/asn1/doc/src/Makefile
@@ -37,8 +37,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
# Target Specs
# ----------------------------------------------------
XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = asn1ct.xml \
- asn1rt.xml
+XML_REF3_FILES = asn1ct.xml
GEN_XML = \
asn1_spec.xml
diff --git a/lib/asn1/doc/src/asn1_getting_started.xml b/lib/asn1/doc/src/asn1_getting_started.xml
index d40b294c39..907bf051d5 100644
--- a/lib/asn1/doc/src/asn1_getting_started.xml
+++ b/lib/asn1/doc/src/asn1_getting_started.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -187,6 +187,14 @@ erlc -o ../asnfiles -I ../asnfiles -I /usr/local/standards/asn1 Person.asn</pre>
<item>
<p>DER encoding rule. Only when using option <c>-ber</c>.</p>
</item>
+ <tag><c>+maps</c></tag>
+ <item>
+ <p>Use maps instead of records to represent the <c>SEQUENCE</c> and
+ <c>SET</c> types. No <c>.hrl</c> files will be generated.
+ See the Section <seealso marker="asn1_getting_started#MAP_SEQ_SET">
+ Map representation for SEQUENCE and SET</seealso>
+ for more information.</p>
+ </item>
<tag><c>+asn1config</c></tag>
<item>
<p>This functionality works together with option
@@ -258,6 +266,10 @@ asn1ct:compile("H323-MESSAGES.asn1",[per]). </pre>
<c>{error, {asn1, Description}}</c> where
<c>Description</c> is
an Erlang term describing the error.</p>
+ <p>Currently, <c>Description</c> looks like this:
+ <c>{ErrorDescription, StackTrace}</c>. Applications should
+ not depend on the exact contents of <c>Description</c> as it
+ could change in the future.</p>
</section>
</section>
@@ -766,8 +778,11 @@ Pdu ::= SEQUENCE {
b REAL,
c OBJECT IDENTIFIER,
d NULL } </pre>
- <p>This is a 4-component structure called <c>Pdu</c>. The record format
- is the major format for representation of <c>SEQUENCE</c> in Erlang.
+ <p>This is a 4-component structure called <c>Pdu</c>. By default,
+ a <c>SEQUENCE</c> is represented by a record in Erlang.
+ It can also be represented as a map; see
+ <seealso marker="asn1_getting_started#MAP_SEQ_SET">
+ Map representation for SEQUENCE and SET</seealso>.
For each <c>SEQUENCE</c> and <c>SET</c> in an ASN.1 module an Erlang
record declaration is generated. For <c>Pdu</c>, a record
like the following is defined:</p>
@@ -878,6 +893,48 @@ SExt ::= SEQUENCE {
</section>
<section>
+ <marker id="MAP_SEQ_SET"></marker>
+ <title>Map representation for SEQUENCE and SET</title>
+ <p>If the ASN.1 module has been compiled with option <c>maps</c>,
+ the types <c>SEQUENCE</c> and <c>SET</c> are represented as maps.</p>
+ <p>In the following example, this ASN.1 specification is used:</p>
+ <pre>
+File DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+Seq1 ::= SEQUENCE {
+ a INTEGER DEFAULT 42,
+ b BOOLEAN OPTIONAL,
+ c IA5String
+}
+END </pre>
+
+ <p>Optional fields are to be omitted from the map if they have
+ no value:</p>
+
+ <pre>
+1> <input>asn1ct:compile('File', [per,maps]).</input>
+ok
+2> <input>{ok,E} = 'File':encode('Seq1', #{a=>0,c=>"string"}).</input>
+{ok,&lt;&lt;128,1,0,6,115,116,114,105,110,103&gt;&gt;} </pre>
+
+ <p>When decoding, optional fields will be omitted from the map:</p>
+
+ <pre>
+3> <input>'File':decode('Seq1', E).</input>
+{ok,#{a => 0,c => "string"}} </pre>
+
+ <p>Default values can be omitted from the map:</p>
+ <pre>
+4> <input>{ok,E2} = 'File':encode('Seq1', #{c=>"string"}).</input>
+{ok,&lt;&lt;0,6,115,116,114,105,110,103&gt;&gt;}
+5> <input>'File':decode('Seq1', E2).</input>
+{ok,#{a => 42,c => "string"}} </pre>
+
+ <note><p>It is not allowed to use the atoms <c>asn1_VALUE</c> and
+ <c>asn1_DEFAULT</c> with maps.</p></note>
+ </section>
+
+ <section>
<marker id="CHOICE"></marker>
<title>CHOICE</title>
<p>The type <c>CHOICE</c> is a space saver and is similar to the
@@ -1004,11 +1061,16 @@ T ::= CHOICE {
<section>
<title>Naming of Records in .hrl Files</title>
+ <p>When the option <c>maps</c> is given, no <c>.hrl</c> files
+ will be generated. The rest of this section describes the behavior
+ of the compiler when <c>maps</c> is not used.</p>
+
<p>When an ASN.1 specification is compiled, all defined types of type
- <c>SET</c> or <c>SEQUENCE</c> result in a corresponding record in the
- generated <c>.hrl</c> file. This is because the values for
- <c>SET</c> and <c>SEQUENCE</c> are represented as records as
- mentioned earlier.</p>
+ <c>SET</c> or <c>SEQUENCE</c> result in a corresponding record in the
+ generated <c>.hrl</c> file. This is because the values for
+ <c>SET</c> and <c>SEQUENCE</c> are represented as records
+ by default.</p>
+
<p>Some special cases of this functionality are presented in the
next section.</p>
@@ -1144,9 +1206,10 @@ SS ::= SET {
<p>This example shows that a function is generated by the compiler
that returns a valid Erlang representation of the value, although
the value is of a complex type.</p>
- <p>Furthermore, a macro is generated for each value in the <c>.hrl</c>
- file. So, the defined value <c>tt</c> can also be extracted by
- <c>?tt</c> in application code.</p>
+ <p>Furthermore, if the option <c>maps</c> is not used,
+ a macro is generated for each value in the <c>.hrl</c>
+ file. So, the defined value <c>tt</c> can also be extracted by
+ <c>?tt</c> in application code.</p>
</section>
<section>
diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml
index e5a7b1bcc4..ccf07a9cc1 100644
--- a/lib/asn1/doc/src/asn1ct.xml
+++ b/lib/asn1/doc/src/asn1ct.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -170,11 +170,24 @@ File3.asn</pre>
as for <c>ber</c>.
</p>
</item>
+ <tag><c>maps</c></tag>
+ <item>
+ <p>This option changes the representation of the types
+ <c>SEQUENCE</c> and <c>SET</c> to use maps (instead of
+ records). This option also suppresses the generation of
+ <c>.hrl</c> files.</p>
+ <p>For details, see Section
+ <seealso marker="asn1_getting_started#MAP_SEQ_SET">
+ Map representation for SEQUENCE and SET</seealso>
+ in the User's Guide.
+ </p>
+ </item>
<tag><c>compact_bit_string</c></tag>
<item>
<p>
The <c>BIT STRING</c> type is decoded to "compact notation".
<em>This option is not recommended for new code.</em>
+ This option cannot be combined with the option <c>maps</c>.
</p>
<p>For details, see Section
<seealso marker="asn1_getting_started#BIT STRING">
@@ -188,6 +201,7 @@ File3.asn</pre>
The <c>BIT STRING</c> type is decoded to the legacy
format, that is, a list of zeroes and ones.
<em>This option is not recommended for new code.</em>
+ This option cannot be combined with the option <c>maps</c>.
</p>
<p>For details, see Section
<seealso marker="asn1_getting_started#BIT STRING">BIT STRING</seealso>
@@ -202,7 +216,8 @@ File3.asn</pre>
marker="asn1_getting_started#BIT STRING">BIT STRING</seealso> and Section
<seealso marker="asn1_getting_started#OCTET STRING">OCTET
STRING</seealso> in the User's Guide.</p>
- <p><em>This option is not recommended for new code.</em></p>
+ <p><em>This option is not recommended for new code.</em>
+ This option cannot be combined with the option <c>maps</c>.</p>
</item>
<tag><c>{n2n, EnumTypeName}</c></tag>
<item>
@@ -321,45 +336,6 @@ File3.asn</pre>
</func>
<func>
- <name>encode(Module, Type, Value)-> {ok, Bytes} | {error, Reason}</name>
- <fsummary>Encodes an ASN.1 value.</fsummary>
- <type>
- <v>Module = Type = atom()</v>
- <v>Value = term()</v>
- <v>Bytes = binary()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Encodes <c>Value</c> of <c>Type</c> defined in the <c>ASN.1</c> module
- <c>Module</c>. To get as fast execution as possible, the
- encode function performs only the rudimentary tests that input
- <c>Value</c> is a correct instance of <c>Type</c>. So, for example,
- the length of strings is
- not always checked. Returns <c>{ok, Bytes}</c> if successful or
- <c>{error, Reason}</c> if an error occurred.
- </p>
- <p>This function is deprecated.
- Use <c>Module:encode(Type, Value)</c> instead.</p>
- </desc>
- </func>
-
- <func>
- <name>decode(Module, Type, Bytes) -> {ok, Value} | {error, Reason}</name>
- <fsummary>Decode from Bytes into an ASN.1 value.</fsummary>
- <type>
- <v>Module = Type = atom()</v>
- <v>Value = Reason = term()</v>
- <v>Bytes = binary()</v>
- </type>
- <desc>
- <p>Decodes <c>Type</c> from <c>Module</c> from the binary
- <c>Bytes</c>. Returns <c>{ok, Value}</c> if successful.</p>
- <p>This function is deprecated.
- Use <c>Module:decode(Type, Bytes)</c> instead.</p>
- </desc>
- </func>
-
- <func>
<name>value(Module, Type) -> {ok, Value} | {error, Reason}</name>
<fsummary>Creates an ASN.1 value for test purposes.</fsummary>
<type>
@@ -424,11 +400,11 @@ File3.asn</pre>
<p>Schematically, the following occurs for each type in the module:</p>
<code type="none">
{ok, Value} = asn1ct:value(Module, Type),
-{ok, Bytes} = asn1ct:encode(Module, Type, Value),
-{ok, Value} = asn1ct:decode(Module, Type, Bytes).</code>
+{ok, Bytes} = Module:encode(Type, Value),
+{ok, Value} = Module:decode(Type, Bytes).</code>
<p>The <c>test</c> functions use the <c>*.asn1db</c> files
for all included modules. If they are located in a different
- directory than the current working directory, use the include
+ directory than the current working directory, use the <c>include</c>
option to add paths. This is only needed when automatically
generating values. For static values using <c>Value</c> no
options are needed.</p>
diff --git a/lib/asn1/doc/src/asn1rt.xml b/lib/asn1/doc/src/asn1rt.xml
deleted file mode 100644
index 3f53ca0f56..0000000000
--- a/lib/asn1/doc/src/asn1rt.xml
+++ /dev/null
@@ -1,135 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1997</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>asn1rt</title>
- <prepared>Kenneth Lundin</prepared>
- <responsible>Kenneth Lundin</responsible>
- <docno>1</docno>
- <approved>Kenneth Lundin</approved>
- <checked></checked>
- <date>97-10-04</date>
- <rev>A</rev>
- <file>asn1.sgml</file>
- </header>
- <module>asn1rt</module>
- <modulesummary>ASN.1 runtime support functions</modulesummary>
- <description>
- <warning>
- <p>
- All functions in this module are deprecated and will be
- removed in a future release.
- </p>
- </warning>
- </description>
-
- <funcs>
-
- <func>
- <name>decode(Module,Type,Bytes) -> {ok,Value}|{error,Reason}</name>
- <fsummary>Decodes from Bytes into an ASN.1 value.</fsummary>
- <type>
- <v>Module = Type = atom()</v>
- <v>Value = Reason = term()</v>
- <v>Bytes = binary</v>
- </type>
- <desc>
- <p>Decodes <c>Type</c> from <c>Module</c> from the binary <c>Bytes</c>.
- Returns <c>{ok,Value}</c> if successful.</p>
- <p>Use <c>Module:decode(Type, Bytes)</c> instead of this function.</p>
- </desc>
- </func>
-
- <func>
- <name>encode(Module,Type,Value)-> {ok,Bytes} | {error,Reason}</name>
- <fsummary>Encodes an ASN.1 value.</fsummary>
- <type>
- <v>Module = Type = atom()</v>
- <v>Value = term()</v>
- <v>Bytes = binary</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Encodes <c>Value</c> of <c>Type</c> defined in the <c>ASN.1</c>
- module <c>Module</c>. Returns a binary if successful. To get
- as fast execution as possible, the encode function performs
- only the rudimentary test that input <c>Value</c> is a correct
- instance of <c>Type</c>. For example, the length of strings is
- not always checked.</p>
- <p>Use <c>Module:encode(Type, Value)</c> instead of this function.</p>
- </desc>
- </func>
-
- <func>
- <name>info(Module) -> {ok,Info} | {error,Reason}</name>
- <fsummary>Returns compiler information about the Module.</fsummary>
- <type>
- <v>Module = atom()</v>
- <v>Info = list()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Returns the version of the <c>ASN.1</c> compiler that was
- used to compile the module. It also returns the compiler options
- that were used.</p>
- <p>Use <c>Module:info()</c> instead of this function.</p>
- </desc>
- </func>
-
- <func>
- <name>utf8_binary_to_list(UTF8Binary) -> {ok,UnicodeList} | {error,Reason}</name>
- <fsummary>Transforms an UTF8 encoded binary to a unicode list.</fsummary>
- <type>
- <v>UTF8Binary = binary()</v>
- <v>UnicodeList = [integer()]</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Transforms a UTF8 encoded binary
- to a list of integers, where each integer represents one
- character as its unicode value. The function fails if the binary
- is not a properly encoded UTF8 string.</p>
- <p>Use <seealso marker="stdlib:unicode#characters_to_list-1">unicode:characters_to_list/1</seealso> instead of this function.</p>
- </desc>
- </func>
-
- <func>
- <name>utf8_list_to_binary(UnicodeList) -> {ok,UTF8Binary} | {error,Reason}</name>
- <fsummary>Transforms an unicode list to a UTF8 binary.</fsummary>
- <type>
- <v>UnicodeList = [integer()]</v>
- <v>UTF8Binary = binary()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Transforms a list of integers,
- where each integer represents one character as its unicode
- value, to a UTF8 encoded binary.</p>
- <p>Use <seealso marker="stdlib:unicode#characters_to_binary-1">unicode:characters_to_binary/1</seealso> instead of this function.</p>
- </desc>
- </func>
-
- </funcs>
-
-</erlref>
-
diff --git a/lib/asn1/doc/src/fascicules.xml b/lib/asn1/doc/src/fascicules.xml
deleted file mode 100644
index 837b4f57f4..0000000000
--- a/lib/asn1/doc/src/fascicules.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE fascicules SYSTEM "fascicules.dtd">
-
-<fascicules>
- <fascicule file="part" href="part_frame.html">
- User's Guide
- </fascicule>
- <fascicule file="ref_man" href="ref_man_frame.html" entry="yes">
- Reference Manual
- </fascicule>
- <fascicule file="part_notes" href="part_notes_frame.html">
- Release Notes
- </fascicule>
- <fascicule file="" href="../../../../doc/print.html">
- Off-Print
- </fascicule>
-</fascicules>
-
diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml
index 499a7e40c3..bb15c9ff5f 100644
--- a/lib/asn1/doc/src/notes.xml
+++ b/lib/asn1/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,6 +32,149 @@
<p>This document describes the changes made to the asn1 application.</p>
+<section><title>Asn1 5.0.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Dialyzer suppression has been added for the generated
+ ASN.1 helper function to_bitstring/1 that previously
+ created irrelevant warnings.</p>
+ <p>
+ Own Id: OTP-13882 Aux Id: ERIERL-144 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Asn1 5.0.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ There was a issue with BER encoding and the
+ <c>undec_rest</c> option in generated decoders. An
+ exception could be thrown instead of returning an error
+ tuple.</p>
+ <p>
+ Own Id: OTP-14786 Aux Id: ERL-518 </p>
+ </item>
+ <item>
+ <p>
+ The asn1ct:test functions crashed on decoders generated
+ with options <c>no_ok_wrapper</c>, <c>undec_rest</c>.</p>
+ <p>
+ Own Id: OTP-14787 Aux Id: ERL-518 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Asn1 5.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Compiling an ASN.1 module using the option {n2n,
+ EnumTypeName} when EnumTypeName contains a hypen like for
+ example Cause-Misc caused syntax errors when compiling
+ the generated Erlang code. This is now corrected.</p>
+ <p>
+ Own Id: OTP-14495 Aux Id: ERL-437 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Asn1 5.0.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Default values now work in extension for PER, so if you
+ give the atom <c>asn1_DEFAULT</c> instead of a value it
+ will become the default value.</p>
+ <p>
+ Own Id: OTP-13011 Aux Id: ERIERL-60 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Asn1 5.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed compilation error of generated code caused by a
+ missing quotation of function names as part of an
+ external call for encoding.</p>
+ <p>
+ Own Id: OTP-14519 Aux Id: ERIERL-49 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Asn1 5.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Add compile option <c>-compile(no_native)</c> in modules
+ with <c>on_load</c> directive which is not yet supported
+ by HiPE.</p>
+ <p>
+ Own Id: OTP-14316 Aux Id: PR-1390 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>The <c>error</c> tuple returned from the <c>encode</c>
+ and <c>decode</c> functions will now include the stack
+ backtrace to make it easier to understand what went
+ wrong.</p>
+ <p>
+ Own Id: OTP-13961</p>
+ </item>
+ <item>
+ <p>The deprecated module <c>asn1rt</c> has been removed.
+ The deprecated functions <c>asn1ct:encode/3</c> and
+ <c>asn1ct:decode/3</c> have been removed. The
+ undocumented function <c>asn1ct:encode/2</c> has been
+ removed.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-14146</p>
+ </item>
+ <item>
+ <p>The new '<c>maps</c>' option changes the
+ representation of the types <c>SEQUENCE</c> and
+ <c>SET</c> to be maps (instead of records).</p>
+ <p>
+ Own Id: OTP-14219</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Asn1 4.0.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/asn1/doc/src/ref_man.xml b/lib/asn1/doc/src/ref_man.xml
index d70e2bc05f..14f6818cae 100644
--- a/lib/asn1/doc/src/ref_man.xml
+++ b/lib/asn1/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2017</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -34,6 +34,5 @@
contains modules with compile-time and runtime support for ASN.1.</p>
</description>
<xi:include href="asn1ct.xml"/>
- <xi:include href="asn1rt.xml"/>
</application>
diff --git a/lib/asn1/examples/recordnames.txt b/lib/asn1/examples/recordnames.txt
index 78e30ab510..9b890b4aa7 100644
--- a/lib/asn1/examples/recordnames.txt
+++ b/lib/asn1/examples/recordnames.txt
@@ -1,6 +1,6 @@
For each ASN1 types SET and SEQUENCE a record is generated in the .hrl
file with the same name as the corresponding type.
-A decoded value is also returned as a record with the apropriate name.
+A decoded value is also returned as a record with the appropriate name.
An internally defined type as the type in component 'a' in the
following example will result in a record with name 'Seq_a':
diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile
index 38cf2d496a..ba459f6cd3 100644
--- a/lib/asn1/src/Makefile
+++ b/lib/asn1/src/Makefile
@@ -68,7 +68,6 @@ CT_MODULES= \
$(EVAL_CT_MODULES)
RT_MODULES= \
- asn1rt \
asn1rt_nif
MODULES= $(CT_MODULES) $(RT_MODULES)
diff --git a/lib/asn1/src/asn1.app.src b/lib/asn1/src/asn1.app.src
index 1f8805ff5e..d2da727193 100644
--- a/lib/asn1/src/asn1.app.src
+++ b/lib/asn1/src/asn1.app.src
@@ -2,7 +2,6 @@
[{description, "The Erlang ASN1 compiler version %VSN%"},
{vsn, "%VSN%"},
{modules, [
- asn1rt,
asn1rt_nif
]},
{registered, [
diff --git a/lib/asn1/src/asn1_db.erl b/lib/asn1/src/asn1_db.erl
index 869ea310aa..7486fa2db9 100644
--- a/lib/asn1/src/asn1_db.erl
+++ b/lib/asn1/src/asn1_db.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -20,7 +20,7 @@
%%
-module(asn1_db).
--export([dbstart/1,dbnew/2,dbload/1,dbload/3,dbsave/2,dbput/2,
+-export([dbstart/1,dbnew/3,dbload/1,dbload/4,dbsave/2,dbput/2,
dbput/3,dbget/2]).
-export([dbstop/0]).
@@ -37,13 +37,13 @@ dbstart(Includes0) ->
put(?MODULE, spawn_link(fun() -> init(Parent, Includes) end)),
ok.
-dbload(Module, Erule, Mtime) ->
- req({load, Module, Erule, Mtime}).
+dbload(Module, Erule, Maps, Mtime) ->
+ req({load, Module, {Erule,Maps}, Mtime}).
dbload(Module) ->
req({load, Module, any, {{0,0,0},{0,0,0}}}).
-dbnew(Module, Erule) -> req({new, Module, Erule}).
+dbnew(Module, Erule, Maps) -> req({new, Module, {Erule,Maps}}).
dbsave(OutFile, Module) -> cast({save, OutFile, Module}).
dbput(Module, K, V) -> cast({set, Module, K, V}).
dbput(Module, Kvs) -> cast({set, Module, Kvs}).
@@ -110,19 +110,19 @@ loop(#state{parent = Parent, monitor = MRef, table = Table,
ok = ets:tab2file(Mtab, TempFile),
ok = file:rename(TempFile, OutFile),
loop(State);
- {From, {new, Mod, Erule}} ->
+ {From, {new, Mod, EruleMaps}} ->
[] = ets:lookup(Table, Mod), %Assertion.
ModTableId = ets:new(list_to_atom(lists:concat(["asn1_",Mod])), []),
ets:insert(Table, {Mod, ModTableId}),
- ets:insert(ModTableId, {?MAGIC_KEY, info(Erule)}),
+ ets:insert(ModTableId, {?MAGIC_KEY, info(EruleMaps)}),
reply(From, ok),
loop(State);
- {From, {load, Mod, Erule, Mtime}} ->
+ {From, {load, Mod, EruleMaps, Mtime}} ->
case ets:member(Table, Mod) of
true ->
reply(From, ok);
false ->
- case load_table(Mod, Erule, Mtime, Includes) of
+ case load_table(Mod, EruleMaps, Mtime, Includes) of
{ok, ModTableId} ->
ets:insert(Table, {Mod, ModTableId}),
reply(From, ok);
@@ -151,20 +151,20 @@ lookup(Tab, K) ->
[{K,V}] -> V
end.
-info(Erule) ->
- {asn1ct:vsn(),Erule}.
+info(EruleMaps) ->
+ {asn1ct:vsn(),EruleMaps}.
-load_table(Mod, Erule, Mtime, Includes) ->
+load_table(Mod, EruleMaps, Mtime, Includes) ->
Base = lists:concat([Mod, ".asn1db"]),
case path_find(Includes, Mtime, Base) of
error ->
error;
- {ok,ModTab} when Erule =:= any ->
+ {ok,ModTab} when EruleMaps =:= any ->
{ok,ModTab};
{ok,ModTab} ->
Vsn = asn1ct:vsn(),
case ets:lookup(ModTab, ?MAGIC_KEY) of
- [{_,{Vsn,Erule}}] ->
+ [{_,{Vsn,EruleMaps}}] ->
%% Correct version and encoding rule.
{ok,ModTab};
_ ->
diff --git a/lib/asn1/src/asn1_records.hrl b/lib/asn1/src/asn1_records.hrl
index af10c1771c..43fa61bc5b 100644
--- a/lib/asn1/src/asn1_records.hrl
+++ b/lib/asn1/src/asn1_records.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@
-define('COMPLETE_ENCODE',1).
-define('TLV_DECODE',2).
+-define(MISSING_IN_MAP, asn1__MISSING_IN_MAP).
-record(module,{pos,name,defid,tagdefault='EXPLICIT',exports={exports,[]},imports={imports,[]}, extensiondefault=empty,typeorval}).
@@ -96,6 +97,28 @@
error_context %Top-level thingie (contains line numbers)
}).
+%% Code generation parameters and options.
+-record(gen,
+ {erule=ber :: 'ber' | 'per',
+ der=false :: boolean(),
+ aligned=false :: boolean(),
+ rec_prefix="" :: string(),
+ macro_prefix="" :: string(),
+ pack=record :: 'record' | 'map',
+ options=[] :: [any()]
+ }).
+
+%% Abstract intermediate representation.
+-record(abst,
+ {name :: module(), %Name of module.
+ types, %Types.
+ values, %Values.
+ ptypes, %Parameterized types.
+ classes, %Classes.
+ objects, %Objects.
+ objsets %Object sets.
+ }).
+
%% state record used by back-end at partial decode
%% active is set to 'yes' when a partial decode function is generated.
%% prefix is set to 'dec-inc-' or 'dec-partial-' is for
diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl
index 8783b5418d..81a2735a0d 100644
--- a/lib/asn1/src/asn1ct.erl
+++ b/lib/asn1/src/asn1ct.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -20,18 +20,13 @@
%%
%%
-module(asn1ct).
--deprecated([decode/3,encode/3]).
--compile([{nowarn_deprecated_function,{asn1rt,decode,3}},
- {nowarn_deprecated_function,{asn1rt,encode,2}},
- {nowarn_deprecated_function,{asn1rt,encode,3}}]).
%% Compile Time functions for ASN.1 (e.g ASN.1 compiler).
-%%-compile(export_all).
%% Public exports
-export([compile/1, compile/2]).
--export([encode/2, encode/3, decode/3]).
-export([test/1, test/2, test/3, value/2, value/3]).
+
%% Application internal exports
-export([compile_asn/3,compile_asn1/3,compile_py/3,compile/3,
vsn/0,
@@ -80,12 +75,9 @@
-define(ALTERNATIVE,alt).
-define(ALTERNATIVE_UNDECODED,alt_undec).
-define(ALTERNATIVE_PARTS,alt_parts).
-%-define(BINARY,bin).
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This is the interface to the compiler
-%%
-%%
compile(File) ->
compile(File,[]).
@@ -198,7 +190,7 @@ check_pass(#st{code=M,file=File,includes=Includes,
erule=Erule,dbfile=DbFile,opts=Opts,
inputmodules=InputModules}=St) ->
start(Includes),
- case asn1ct_check:storeindb(#state{erule=Erule}, M) of
+ case asn1ct_check:storeindb(#state{erule=Erule,options=Opts}, M) of
ok ->
Module = asn1_db:dbget(M#module.name, 'MODULE'),
State = #state{mname=Module#module.name,
@@ -221,8 +213,8 @@ check_pass(#st{code=M,file=File,includes=Includes,
{error,St#st{error=Reason}}
end.
-save_pass(#st{code=M,erule=Erule}=St) ->
- ok = asn1ct_check:storeindb(#state{erule=Erule}, M),
+save_pass(#st{code=M,erule=Erule,opts=Opts}=St) ->
+ ok = asn1ct_check:storeindb(#state{erule=Erule,options=Opts}, M),
{ok,St}.
parse_listing(#st{code=Code,outfile=OutFile0}=St) ->
@@ -241,12 +233,8 @@ abs_listing(#st{code={M,_},outfile=OutFile}) ->
generate_pass(#st{code=Code,outfile=OutFile,erule=Erule,opts=Opts}=St0) ->
St = St0#st{code=undefined}, %Reclaim heap space
- case generate(Code, OutFile, Erule, Opts) of
- {error,Reason} ->
- {error,St#st{error=Reason}};
- ok ->
- {ok,St}
- end.
+ generate(Code, OutFile, Erule, Opts),
+ {ok,St}.
compile_pass(#st{outfile=OutFile,opts=Opts0}=St) ->
asn1_db:dbstop(), %Reclaim memory.
@@ -760,7 +748,6 @@ remove_import_doubles([]) ->
remove_import_doubles(ImportList) ->
MergedImportList =
merge_symbols_from_module(ImportList,[]),
-%% io:format("MergedImportList: ~p~n",[MergedImportList]),
delete_double_of_symbol(MergedImportList,[]).
merge_symbols_from_module([Imp|Imps],Acc) ->
@@ -778,7 +765,6 @@ merge_symbols_from_module([Imp|Imps],Acc) ->
end,
Imps),
NewImps = lists:subtract(Imps,IfromModName),
-%% io:format("Imp: ~p~nIfromModName: ~p~n",[Imp,IfromModName]),
NewImp =
Imp#'SymbolsFromModule'{
symbols = lists:append(
@@ -839,37 +825,53 @@ delete_double_of_symbol1([],Acc) ->
%%***********************************
-generate({M,GenTOrV}, OutFile, EncodingRule, Options) ->
- debug_on(Options),
+generate({M,CodeTuple}, OutFile, EncodingRule, Options) ->
+ {Types,Values,Ptypes,Classes,Objects,ObjectSets} = CodeTuple,
+ Code = #abst{name=M#module.name,
+ types=Types,values=Values,ptypes=Ptypes,
+ classes=Classes,objects=Objects,objsets=ObjectSets},
setup_bit_string_format(Options),
setup_legacy_erlang_types(Options),
- put(encoding_options,Options),
asn1ct_table:new(check_functions),
+ Gen = init_gen_record(EncodingRule, Options),
+
+ check_maps_option(Gen),
+
%% create decoding function names and taglists for partial decode
- case (catch specialized_decode_prepare(EncodingRule,M,GenTOrV,Options)) of
- {error, Reason} -> warning("Error in configuration file: ~n~p~n",
- [Reason], Options,
- "Error in configuration file");
- _ -> ok
+ try
+ specialized_decode_prepare(Gen, M)
+ catch
+ throw:{error, Reason} ->
+ warning("Error in configuration file: ~n~p~n",
+ [Reason], Options,
+ "Error in configuration file")
end,
- Result =
- case (catch asn1ct_gen:pgen(OutFile,EncodingRule,
- M#module.name,GenTOrV,Options)) of
- {'EXIT',Reason2} ->
- error("~p~n",[Reason2],Options),
- {error,Reason2};
- _ ->
- ok
- end,
- debug_off(Options),
- erase(encoding_options),
+ asn1ct_gen:pgen(OutFile, Gen, Code),
cleanup_bit_string_format(),
erase(tlv_format), % used in ber
erase(class_default_type),% used in ber
asn1ct_table:delete(check_functions),
- Result.
+ ok.
+
+init_gen_record(EncodingRule, Options) ->
+ Erule = case EncodingRule of
+ uper -> per;
+ _ -> EncodingRule
+ end,
+ Der = proplists:get_bool(der, Options),
+ Aligned = EncodingRule =:= per,
+ RecPrefix = proplists:get_value(record_name_prefix, Options, ""),
+ MacroPrefix = proplists:get_value(macro_name_prefix, Options, ""),
+ Pack = case proplists:get_value(maps, Options, false) of
+ true -> map;
+ false -> record
+ end,
+ #gen{erule=Erule,der=Der,aligned=Aligned,
+ rec_prefix=RecPrefix,macro_prefix=MacroPrefix,
+ pack=Pack,options=Options}.
+
setup_legacy_erlang_types(Opts) ->
F = case lists:member(legacy_erlang_types, Opts) of
@@ -915,6 +917,26 @@ cleanup_bit_string_format() ->
get_bit_string_format() ->
get(bit_string_format).
+check_maps_option(#gen{pack=map}) ->
+ case get_bit_string_format() of
+ bitstring ->
+ ok;
+ _ ->
+ Message1 = "The 'maps' option must not be combined with "
+ "'compact_bit_string' or 'legacy_bit_string'",
+ exit({error,{asn1,Message1}})
+ end,
+ case use_legacy_types() of
+ false ->
+ ok;
+ true ->
+ Message2 = "The 'maps' option must not be combined with "
+ "'legacy_erlang_types'",
+ exit({error,{asn1,Message2}})
+ end;
+check_maps_option(#gen{}) ->
+ ok.
+
%% parse_and_save parses an asn1 spec and saves the unchecked parse
%% tree in a data base file.
@@ -924,22 +946,27 @@ parse_and_save(Module,S) ->
SourceDir = S#state.sourcedir,
Includes = [I || {i,I} <- Options],
Erule = S#state.erule,
+ Maps = lists:member(maps, Options),
case get_input_file(Module, [SourceDir|Includes]) of
%% search for asn1 source
{file,SuffixedASN1source} ->
Mtime = filelib:last_modified(SuffixedASN1source),
- case asn1_db:dbload(Module, Erule, Mtime) of
+ case asn1_db:dbload(Module, Erule, Maps, Mtime) of
ok -> ok;
error -> parse_and_save1(S, SuffixedASN1source, Options)
end;
- Err ->
+ Err when not Maps ->
case asn1_db:dbload(Module) of
ok ->
+ %% FIXME: This should be an error.
warning("could not do a consistency check of the ~p file: no asn1 source file was found.~n",
[lists:concat([Module,".asn1db"])],Options);
error ->
ok
end,
+ {error,{asn1,input_file_error,Err}};
+ Err ->
+ %% Always fail directly when the 'maps' option is used.
{error,{asn1,input_file_error,Err}}
end.
@@ -956,12 +983,8 @@ get_input_file(Module,[]) ->
get_input_file(Module,[I|Includes]) ->
case (catch input_file_type(filename:join([I,Module]))) of
{single_file,FileName} ->
-%% case file:read_file_info(FileName) of
-%% {ok,_} ->
{file,FileName};
-%% _ -> get_input_file(Module,Includes)
-%% end;
- _ ->
+ _ ->
get_input_file(Module,Includes)
end.
@@ -1002,9 +1025,8 @@ input_file_type(File) ->
end
end;
".asn1config" ->
- case read_config_file(File,asn1_module) of
+ case read_config_file_info(File, asn1_module) of
{ok,Asn1Module} ->
-% put(asn1_config_file,File),
input_file_type(Asn1Module);
Error ->
Error
@@ -1097,30 +1119,29 @@ translate_options([H|T]) ->
translate_options([]) -> [].
remove_asn_flags(Options) ->
- [X || X <- Options,
- X /= get_rule(Options),
- X /= optimize,
- X /= compact_bit_string,
- X /= legacy_bit_string,
- X /= legacy_erlang_types,
- X /= debug,
- X /= asn1config,
- X /= record_name_prefix].
-
-debug_on(Options) ->
- case lists:member(debug,Options) of
- true ->
- put(asndebug,true);
- _ ->
- true
- end.
-
-debug_off(_Options) ->
- erase(asndebug).
+ [X || X <- Options, not is_asn1_flag(X)].
+
+is_asn1_flag(asn1config) -> true;
+is_asn1_flag(ber) -> true;
+is_asn1_flag(compact_bit_string) -> true;
+is_asn1_flag(debug) -> true;
+is_asn1_flag(der) -> true;
+is_asn1_flag(legacy_bit_string) -> true;
+is_asn1_flag({macro_name_prefix,_}) -> true;
+is_asn1_flag({n2n,_}) -> true;
+is_asn1_flag(noobj) -> true;
+is_asn1_flag(no_ok_wrapper) -> true;
+is_asn1_flag(optimize) -> true;
+is_asn1_flag(per) -> true;
+is_asn1_flag({record_name_prefix,_}) -> true;
+is_asn1_flag(undec_rec) -> true;
+is_asn1_flag(uper) -> true;
+is_asn1_flag(verbose) -> true;
+%% 'warnings_as_errors' is intentionally passed through to the compiler.
+is_asn1_flag(_) -> false.
outfile(Base, Ext, Opts) ->
-% io:format("Opts. ~p~n",[Opts]),
Obase = case lists:keysearch(outdir, 1, Opts) of
{value, {outdir, Odir}} -> filename:join(Odir, Base);
_NotFound -> Base % Not found or bad format
@@ -1171,9 +1192,6 @@ compile_py(File,OutFile,Options) ->
compile(File, _OutFile, Options) ->
case compile(File, make_erl_options(Options)) of
{error,_Reason} ->
- %% case occurs due to error in asn1ct_parser2,asn1ct_check
-%% io:format("~p~n",[_Reason]),
-%% io:format("~p~n~s~n",[_Reason,"error"]),
error;
ok ->
ok;
@@ -1271,21 +1289,6 @@ pretty2(Module,AbsFile) ->
start(Includes) when is_list(Includes) ->
asn1_db:dbstart(Includes).
-
-encode(Module,Term) ->
- asn1rt:encode(Module,Term).
-
-encode(Module,Type,Term) when is_list(Module) ->
- asn1rt:encode(list_to_atom(Module),Type,Term);
-encode(Module,Type,Term) ->
- asn1rt:encode(Module,Type,Term).
-
-decode(Module,Type,Bytes) when is_list(Module) ->
- asn1rt:decode(list_to_atom(Module),Type,Bytes);
-decode(Module,Type,Bytes) ->
- asn1rt:decode(Module,Type,Bytes).
-
-
test(Module) -> test_module(Module, []).
test(Module, [] = Options) -> test_module(Module, Options);
@@ -1330,27 +1333,41 @@ test_type(Module, Type) ->
test_value(Module, Type, Value) ->
in_process(fun() ->
- case catch encode(Module, Type, Value) of
+ case catch Module:encode(Type, Value) of
{ok, Bytes} ->
- NewBytes = prepare_bytes(Bytes),
- case decode(Module, Type, NewBytes) of
- {ok, Value} ->
- {ok, {Module, Type, Value}};
- {ok, Res} ->
- {error, {asn1,
- {encode_decode_mismatch,
- {{Module, Type, Value}, Res}}}};
- Error ->
- {error, {asn1,
- {{decode,
- {Module, Type, Value}, Error}}}}
- end;
+ test_value_decode(Module, Type, Value, Bytes);
+ Bytes when is_binary(Bytes) ->
+ test_value_decode(Module, Type, Value, Bytes);
Error ->
{error, {asn1,
{encode, {{Module, Type, Value}, Error}}}}
end
end).
+
+test_value_decode(Module, Type, Value, Bytes) ->
+ NewBytes = prepare_bytes(Bytes),
+ case Module:decode(Type, NewBytes) of
+ {ok,Value} -> {ok, {Module,Type,Value}};
+ {ok,Value,<<>>} -> {ok, {Module,Type,Value}};
+ Value -> {ok, {Module,Type,Value}};
+ {Value,<<>>} -> {ok, {Module,Type,Value}};
+
+ %% Errors:
+ {ok, Res} ->
+ {error, {asn1,
+ {encode_decode_mismatch,
+ {{Module, Type, Value}, Res}}}};
+ {ok, Res, Rest} ->
+ {error, {asn1,
+ {encode_decode_mismatch,
+ {{Module, Type, Value}, {Res,Rest}}}}};
+ Error ->
+ {error, {asn1,
+ {{decode,
+ {Module, Type, Value}, Error}}}}
+ end.
+
value(Module, Type) -> value(Module, Type, []).
value(Module, Type, Includes) ->
@@ -1390,25 +1407,26 @@ prepare_bytes(Bytes) -> list_to_binary(Bytes).
vsn() ->
?vsn.
-specialized_decode_prepare(Erule,M,TsAndVs,Options) ->
- case lists:member(asn1config,Options) of
+specialized_decode_prepare(#gen{erule=ber,options=Options}=Gen, M) ->
+ case lists:member(asn1config, Options) of
true ->
- partial_decode_prepare(Erule,M,TsAndVs,Options);
- _ ->
+ special_decode_prepare_1(Gen, M);
+ false ->
ok
- end.
+ end;
+specialized_decode_prepare(_, _) ->
+ ok.
+
%% Reads the configuration file if it exists and stores information
%% about partial decode and incomplete decode
-partial_decode_prepare(ber,M,TsAndVs,Options) when is_tuple(TsAndVs) ->
+special_decode_prepare_1(#gen{options=Options}=Gen, M) ->
%% read configure file
-
- ModName =
- case lists:keysearch(asn1config,1,Options) of
- {value,{_,MName}} -> MName;
- _ -> M#module.name
- end,
+ ModName = case lists:keyfind(asn1config, 1, Options) of
+ {_,MName} -> MName;
+ false -> M#module.name
+ end,
%% io:format("ModName: ~p~nM#module.name: ~p~n~n",[ModName,M#module.name]),
- case read_config_file(ModName) of
+ case read_config_file(Gen, ModName) of
no_config_file ->
ok;
CfgList ->
@@ -1427,11 +1445,7 @@ partial_decode_prepare(ber,M,TsAndVs,Options) when is_tuple(TsAndVs) ->
Part_inc_tlv_tags = tlv_tags(CommandList2),
save_config(partial_incomplete_decode,Part_inc_tlv_tags),
save_gen_state(exclusive_decode,ExclusiveDecode,Part_inc_tlv_tags)
- end;
-partial_decode_prepare(_,_,_,_) ->
- ok.
-
-
+ end.
%% create_partial_inc_decode_gen_info/2
%%
@@ -1486,7 +1500,8 @@ create_pdec_inc_command(_ModName,_,[],Acc) ->
create_pdec_inc_command(ModName,{Comps1,Comps2},TNL,Acc)
when is_list(Comps1),is_list(Comps2) ->
create_pdec_inc_command(ModName,Comps1 ++ Comps2,TNL,Acc);
-%% The following two functionclauses matches on the type after the top type. This one if the top type had no tag, i.e. a CHOICE
+%% The following two clauses match on the type after the top
+%% type. This one if the top type had no tag, i.e. a CHOICE.
create_pdec_inc_command(ModN,Clist,[CL|_Rest],[[]]) when is_list(CL) ->
create_pdec_inc_command(ModN,Clist,CL,[]);
create_pdec_inc_command(ModN,Clist,[CL|_Rest],Acc) when is_list(CL) ->
@@ -1497,17 +1512,14 @@ create_pdec_inc_command(ModName,
prop=Prop}|Comps],
TNL=[C1|Cs],Acc) ->
case C1 of
-% Name ->
-% %% In this case C1 is an atom
-% TagCommand = get_tag_command(TS,?MANDATORY,Prop),
-% create_pdec_inc_command(ModName,get_components(TS#type.def),Cs,[TagCommand|Acc]);
{Name,undecoded} ->
TagCommand = get_tag_command(TS,?UNDECODED,Prop),
create_pdec_inc_command(ModName,Comps,Cs,concat_sequential(TagCommand,Acc));
{Name,parts} ->
TagCommand = get_tag_command(TS,?PARTS,Prop),
create_pdec_inc_command(ModName,Comps,Cs,concat_sequential(TagCommand,Acc));
- L when is_list(L) -> % I guess this never happens due to previous function clause
+ L when is_list(L) ->
+ %% I guess this never happens due to previous clause.
%% This case is only possible as the first element after
%% the top type element, when top type is SEGUENCE or SET.
%% Follow each element in L. Must note every tag on the
@@ -1529,8 +1541,6 @@ create_pdec_inc_command(ModName,
RestPartsList,[]),
create_pdec_inc_command(ModName,Comps,Cs,
[[?MANDATORY,InnerDirectives]|Acc]);
-% create_pdec_inc_command(ModName,Comps,Cs,
-% [InnerDirectives,?MANDATORY|Acc]);
[Opt,EncTag] ->
InnerDirectives =
create_pdec_inc_command(ModName,TS#type.def,
@@ -1538,9 +1548,8 @@ create_pdec_inc_command(ModName,
create_pdec_inc_command(ModName,Comps,Cs,
[[Opt,EncTag,InnerDirectives]|Acc])
end;
-% create_pdec_inc_command(ModName,CList,RestPartsList,Acc);
-%% create_pdec_inc_command(ModName,TS#type.def,RestPartsList,Acc);
- _ -> %% this component may not be in the config list
+ _ ->
+ %% this component may not be in the config list
TagCommand = get_tag_command(TS,?MANDATORY,Prop),
create_pdec_inc_command(ModName,Comps,TNL,concat_sequential(TagCommand,Acc))
end;
@@ -1551,7 +1560,6 @@ create_pdec_inc_command(ModName,
[{C1,Directive}|Rest],Acc) ->
case Directive of
List when is_list(List) ->
-% [Command,Tag] = get_tag_command(TS,?ALTERNATIVE,Prop),
TagCommand = get_tag_command(TS,?ALTERNATIVE,Prop),
CompAcc =
create_pdec_inc_command(ModName,
@@ -1560,9 +1568,6 @@ create_pdec_inc_command(ModName,
[Command,Tag] when is_atom(Command) ->
[[Command,Tag,CompAcc]|Acc];
[L1,_L2|Rest] when is_list(L1) ->
-% [LastComm|Comms] = lists:reverse(TagCommand),
-% [concat_sequential(lists:reverse(Comms),
-% [LastComm,CompAcc])|Acc]
case lists:reverse(TagCommand) of
[Atom|Comms] when is_atom(Atom) ->
[concat_sequential(lists:reverse(Comms),
@@ -1571,12 +1576,8 @@ create_pdec_inc_command(ModName,
[concat_sequential(lists:reverse(Comms),
[[Command2,Tag2,CompAcc]])|Acc]
end
-% [concat_sequential(lists:reverse(Comms),
-% InnerCommand)|Acc]
-
end,
create_pdec_inc_command(ModName,{'CHOICE',Comps},Rest,
-% [[Command,Tag,CompAcc]|Acc]);
NewAcc);
undecoded ->
TagCommand = get_tag_command(TS,?ALTERNATIVE_UNDECODED,Prop),
@@ -1632,7 +1633,6 @@ create_partial_decode_gen_info(_M1,{M2,_}) ->
throw({error,{"wrong module name in asn1 config file",
M2}}).
-%create_partial_decode_gen_info1(ModName,{ModName,TypeList}) ->
create_partial_decode_gen_info1(ModName,{FuncName,TypeList}) ->
case TypeList of
[TopType|Rest] ->
@@ -1652,11 +1652,6 @@ create_partial_decode_gen_info1(ModName,{FuncName,TypeList}) ->
end;
create_partial_decode_gen_info1(_,_) ->
ok.
-% create_partial_decode_gen_info1(_,[]) ->
-% [];
-% create_partial_decode_gen_info1(_M1,{M2,_}) ->
-% throw({error,{"wrong module name in asn1 config file",
-% M2}}).
%% create_pdec_command/4 for each name (type or component) in the
%% third argument, TypeNameList, a command is created. The command has
@@ -1672,7 +1667,6 @@ create_pdec_command(_ModName,_,[],Acc) ->
Fun(L,[H|Res],Fun)
end,
Remove_empty_lists(Acc,[],Remove_empty_lists);
-% lists:reverse(Acc);
create_pdec_command(ModName,[#'ComponentType'{name=C1,typespec=TS}|_Comps],
[C1|Cs],Acc) ->
%% this component is a constructed type or the last in the
@@ -1721,9 +1715,7 @@ create_pdec_command(ModName,TS=#type{def=Def},[C1|Cs],Acc) ->
create_pdec_command(_,_,TNL,_) ->
throw({error,{"unexpected error when creating partial "
"decode command",TNL}}).
-
-% get_components({'CHOICE',Components}) ->
-% Components;
+
get_components(#'SEQUENCE'{components={C1,C2}}) when is_list(C1),is_list(C2) ->
C1++C2;
get_components(#'SEQUENCE'{components=Components}) ->
@@ -1794,8 +1786,6 @@ get_tag_command(#type{tag=[Tag]},Command) ->
[Command,encode_tag_val(decode_class(Tag#tag.class),Tag#tag.form,
Tag#tag.number)];
get_tag_command(T=#type{tag=[Tag|Tags]},Command) ->
-% [get_tag_command(T#type{tag=[Tag]},Command)|
-% [get_tag_command(T#type{tag=Tags},Command)]].
TC = get_tag_command(T#type{tag=[Tag]},Command),
TCs = get_tag_command(T#type{tag=Tags},Command),
case many_tags(TCs) of
@@ -1823,7 +1813,6 @@ get_tag_command(#type{tag=Tag},Command,Prop) when is_record(Tag,tag) ->
get_tag_command(#type{tag=[Tag]},Command,Prop);
get_tag_command(T=#type{tag=[Tag|Tags]},Command,Prop) ->
[get_tag_command(T#type{tag=[Tag]},Command,Prop)|[
-% get_tag_command(T#type{tag=Tags},?MANDATORY,Prop)]].
get_tag_command(T#type{tag=Tags},Command,Prop)]].
anonymous_dec_command(?UNDECODED,'OPTIONAL') ->
@@ -1883,46 +1872,38 @@ tlv_tag1(<<0:1,PartialTag:7>>,Acc) ->
tlv_tag1(<<1:1,PartialTag:7,Buffer/binary>>,Acc) ->
tlv_tag1(Buffer,(Acc bsl 7) bor PartialTag).
-%% reads the content from the configuration file and returns the
-%% selected part choosen by InfoType. Assumes that the config file
+%% Reads the content from the configuration file and returns the
+%% selected part chosen by InfoType. Assumes that the config file
%% content is an Erlang term.
-read_config_file(ModuleName,InfoType) when is_atom(InfoType) ->
- CfgList = read_config_file(ModuleName),
- get_config_info(CfgList,InfoType).
+read_config_file_info(ModuleName, InfoType) when is_atom(InfoType) ->
+ Name = ensure_ext(ModuleName, ".asn1config"),
+ CfgList = read_config_file0(Name, []),
+ get_config_info(CfgList, InfoType).
+read_config_file(#gen{options=Options}, ModuleName) ->
+ Name = ensure_ext(ModuleName, ".asn1config"),
+ Includes = [I || {i,I} <- Options],
+ read_config_file0(Name, ["."|Includes]).
-read_config_file(ModuleName) ->
- case file:consult(lists:concat([ModuleName,'.asn1config'])) of
+read_config_file0(Name, [D|Dirs]) ->
+ case file:consult(filename:join(D, Name)) of
{ok,CfgList} ->
CfgList;
{error,enoent} ->
- Options = get(encoding_options),
- Includes = [I || {i,I} <- Options],
- read_config_file1(ModuleName,Includes);
+ read_config_file0(Name, Dirs);
{error,Reason} ->
Error = "error reading asn1 config file: " ++
file:format_error(Reason),
throw({error,Error})
- end.
-read_config_file1(ModuleName,[]) ->
- case filename:extension(ModuleName) of
- ".asn1config" ->
- no_config_file;
- _ ->
- read_config_file(lists:concat([ModuleName,".asn1config"]))
end;
-read_config_file1(ModuleName,[H|T]) ->
-% File = filename:join([H,lists:concat([ModuleName,'.asn1config'])]),
- File = filename:join([H,ModuleName]),
- case file:consult(File) of
- {ok,CfgList} ->
- CfgList;
- {error,enoent} ->
- read_config_file1(ModuleName,T);
- {error,Reason} ->
- Error = "error reading asn1 config file: " ++
- file:format_error(Reason),
- throw({error,Error})
+read_config_file0(_, []) ->
+ no_config_file.
+
+ensure_ext(ModuleName, Ext) ->
+ Name = filename:join([ModuleName]),
+ case filename:extension(Name) of
+ Ext -> Name;
+ _ -> Name ++ Ext
end.
get_config_info(CfgList,InfoType) ->
@@ -1946,8 +1927,8 @@ read_config_data(Key) ->
true ->
case asn1ct_table:lookup(asn1_general,{asn1_config,Key}) of
[{_,Data}] -> Data;
- Err -> % Err is [] when nothing was saved in the ets table
-%% io:format("strange data from config file ~w~n",[Err]),
+ Err ->
+ %% Err is [] when nothing was saved in the ets table
Err
end
end.
@@ -1960,7 +1941,6 @@ read_config_data(Key) ->
%% saves input data in a new gen_state record
save_gen_state(exclusive_decode,{_,ConfList},PartIncTlvTagList) ->
- %ConfList=[{FunctionName,PatternList}|Rest]
State =
case get_gen_state() of
S when is_record(S,gen_state) -> S;
@@ -1970,14 +1950,12 @@ save_gen_state(exclusive_decode,{_,ConfList},PartIncTlvTagList) ->
inc_type_pattern=ConfList},
save_config(gen_state,StateRec);
save_gen_state(_,_,_) ->
-%% ok.
case get_gen_state() of
S when is_record(S,gen_state) -> ok;
_ -> save_config(gen_state,#gen_state{})
end.
save_gen_state(selective_decode,{_,Type_component_name_list}) ->
-%% io:format("Selective_decode: ~p~n",[Type_component_name_list]),
State =
case get_gen_state() of
S when is_record(S,gen_state) -> S;
@@ -2059,11 +2037,6 @@ update_gen_state(type_pattern,State,Data) ->
update_gen_state(func_name,State,Data) ->
save_gen_state(State#gen_state{func_name=Data});
update_gen_state(namelist,State,Data) ->
-% SData =
-% case Data of
-% [D] when is_list(D) -> D;
-% _ -> Data
-% end,
save_gen_state(State#gen_state{namelist=Data});
update_gen_state(tobe_refed_funcs,State,Data) ->
save_gen_state(State#gen_state{tobe_refed_funcs=Data});
@@ -2118,7 +2091,6 @@ get_tobe_refed_func(Name) ->
%% tuple. Do not save if it exists in generated_functions, because
%% then it will be or already is generated.
add_tobe_refed_func(Data) ->
- %%
{Name,SI,Pattern} =
fun({N,Si,P,_}) -> {N,Si,P};
(D) -> D end (Data),
@@ -2126,8 +2098,6 @@ add_tobe_refed_func(Data) ->
case SI of
I when is_integer(I) ->
fun(D) -> D end(Data);
-% fun({N,Ix,P}) -> {N,Ix+1,P};
-% ({N,Ix,P,T}) -> {N,Ix+1,P,T} end (Data);
_ ->
fun({N,_,P}) -> {N,0,P};
({N,_,P,T}) -> {N,0,P,T} end (Data)
@@ -2135,12 +2105,13 @@ add_tobe_refed_func(Data) ->
L = get_gen_state_field(generated_functions),
case generated_functions_member(get(currmod),Name,L,Pattern) of
- true -> % it exists in generated_functions, it has already
- % been generated or saved in tobe_refed_func
+ true ->
+ %% it exists in generated_functions, it has already
+ %% been generated or saved in tobe_refed_func
ok;
_ ->
add_once_tobe_refed_func(NewData),
- %%only to get it saved in generated_functions
+ %% only to get it saved in generated_functions
maybe_rename_function(tobe_refed,Name,Pattern)
end.
@@ -2155,16 +2126,13 @@ add_once_tobe_refed_func(Data) ->
({N,I,_,_}) when N==Name,I==Index -> true;
(_) -> false end,TRFL) of
[] ->
-%% case lists:keysearch(element(1,Data),1,TRFL) of
-%% false ->
update_gen_state(tobe_refed_funcs,[Data|TRFL]);
_ ->
ok
end.
-
-%% moves Name from the to be list to the generated list.
+%% Moves Name from the to be list to the generated list.
generated_refed_func(Name) ->
L = get_gen_state_field(tobe_refed_funcs),
NewL = lists:keydelete(Name,1,L),
@@ -2172,7 +2140,7 @@ generated_refed_func(Name) ->
L2 = get_gen_state_field(gen_refed_funcs),
update_gen_state(gen_refed_funcs,[Name|L2]).
-%% adds Data to gen_refed_funcs field in gen_state.
+%% Adds Data to gen_refed_funcs field in gen_state.
add_generated_refed_func(Data) ->
case is_function_generated(Data) of
true ->
@@ -2194,7 +2162,7 @@ next_refed_func() ->
reset_gen_state() ->
save_gen_state(#gen_state{}).
-%% adds Data to generated_functions field in gen_state.
+%% Adds Data to generated_functions field in gen_state.
add_generated_function(Data) ->
L = get_gen_state_field(generated_functions),
update_gen_state(generated_functions,[Data|L]).
@@ -2213,16 +2181,18 @@ maybe_rename_function(Mode,Name,Pattern) ->
{_,true} ->
L2 = generated_functions_filter(get(currmod),Name,L),
case lists:keysearch(Pattern,3,L2) of
- false -> %name existed, but not pattern
+ false ->
+ %% name existed, but not pattern
NextIndex = length(L2),
- %%rename function
+ %% rename function
Suffix = lists:concat(["_",NextIndex]),
NewName =
maybe_rename_function2(type_check(Name),Name,
Suffix),
add_generated_function({Name,NextIndex,Pattern}),
NewName;
- Value -> % name and pattern existed
+ Value ->
+ %% name and pattern existed
%% do not save any new index
Suffix = make_suffix(Value),
Name2 =
@@ -2232,9 +2202,9 @@ maybe_rename_function(Mode,Name,Pattern) ->
end,
lists:concat([Name2,Suffix])
end;
- {inc_disp,_} -> %% this is when
- %% decode_partial_inc_disp/2 is
- %% generated
+ {inc_disp,_} ->
+ %% this is when decode_partial_inc_disp/2 is
+ %% generated
add_generated_function({Name,0,Pattern}),
Name;
_ -> % this if call from add_tobe_refed_func
@@ -2280,23 +2250,12 @@ generated_functions_member(M,Name,[_|T]) ->
generated_functions_member(_,_,[]) ->
false.
-% generated_functions_member(M,Name,L) ->
-% case lists:keymember(Name,1,L) of
-% true ->
-% true;
-% _ ->
-% generated_functions_member1(M,Name,L)
-% end.
-% generated_functions_member1(M,#'Externaltypereference'{module=M,type=Name},L) ->
-% lists:keymember(Name,1,L);
-% generated_functions_member1(_,_,_) -> false.
-
generated_functions_filter(_,Name,L) when is_atom(Name);is_list(Name) ->
lists:filter(fun({N,_,_}) when N==Name -> true;
(_) -> false
end, L);
generated_functions_filter(M,#'Externaltypereference'{module=M,type=Name},L)->
- % remove toptypename from patterns
+ %% remove top typename from patterns
RemoveTType =
fun({N,I,[N,P]}) when N == Name ->
{N,I,P};
@@ -2333,8 +2292,6 @@ set_current_sindex(Index) ->
type_check(A) when is_atom(A) ->
atom;
-%% type_check(I) when is_integer(I) ->
-%% integer;
type_check(L) when is_list(L) ->
Pred = fun(X) when X=<255 ->
false;
@@ -2402,8 +2359,10 @@ format_error({write_error,File,Reason}) ->
io_lib:format("writing output file ~s failed: ~s",
[File,file:format_error(Reason)]).
-is_error(S) when is_record(S, state) ->
- is_error(S#state.options);
+is_error(#state{options=Opts}) ->
+ is_error(Opts);
+is_error(#gen{options=Opts}) ->
+ is_error(Opts);
is_error(O) ->
lists:member(errors, O) orelse is_verbose(O).
@@ -2412,8 +2371,10 @@ is_warning(S) when is_record(S, state) ->
is_warning(O) ->
lists:member(warnings, O) orelse is_verbose(O).
-is_verbose(S) when is_record(S, state) ->
- is_verbose(S#state.options);
+is_verbose(#state{options=Opts}) ->
+ is_verbose(Opts);
+is_verbose(#gen{options=Opts}) ->
+ is_verbose(Opts);
is_verbose(O) ->
lists:member(verbose, O).
diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl
index f2c895bfaa..83d12600b7 100644
--- a/lib/asn1/src/asn1ct_check.erl
+++ b/lib/asn1/src/asn1ct_check.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,10 +23,9 @@
%% Main Module for ASN.1 compile time functions
-%-compile(export_all).
-export([check/2,storeindb/2,format_error/1]).
-%-define(debug,1).
-include("asn1_records.hrl").
+
%%% The tag-number for universal types
-define(N_BOOLEAN, 1).
-define(N_INTEGER, 2).
@@ -63,7 +62,8 @@
-define(TAG_CONSTRUCTED(Num),
#tag{class='UNIVERSAL',number=Num,type='IMPLICIT',form=32}).
--record(newt,{type=unchanged,tag=unchanged,constraint=unchanged,inlined=no}). % used in check_type to update type and tag
+%% used in check_type to update type and tag
+-record(newt,{type=unchanged,tag=unchanged,constraint=unchanged,inlined=no}).
check(S,{Types,Values,ParameterizedTypes,Classes,Objects,ObjectSets}) ->
%%Predicates used to filter errors
@@ -561,7 +561,6 @@ check_class_fields(S,[F|Fields],Acc) ->
D;
{undefined,user} ->
%% neither of {primitive,bif} or {constructed,bif}
-
{_,D} = get_referenced_type(S,#'Externaltypereference'{module=S#state.mname,type=Type#type.def}),
D;
_ ->
@@ -623,7 +622,6 @@ if_current_checked_type(S,#type{def=Def}) ->
CurrentModule = S#state.mname,
CurrentCheckedName = S#state.tname,
MergedModules = S#state.inputmodules,
- % CurrentCheckedModule = S#state.mname,
case Def of
#'Externaltypereference'{module=CurrentModule,
type=CurrentCheckedName} ->
@@ -656,7 +654,6 @@ check_pobjectset(S,PObjSet) ->
ClassName = #'Externaltypereference'{module=Mod,
type=get_datastr_name(Def)},
{valueset,Set} = ValueSet,
-% ObjectSet = #'ObjectSet'{class={objectclassname,ClassName},
ObjectSet = #'ObjectSet'{class=ClassName,
set=Set},
#pobjectsetdef{pos=Pos,name=Name,args=Args,class=Type#type.def,
@@ -1696,7 +1693,7 @@ check_value(OldS,V) when is_record(V,typedef) ->
%% reference to class
check_value(OldS,V#typedef{typespec=TS#'ObjectSet'{class=Eref}});
#typedef{typespec=HostType} ->
- % an ordinary value set with a type in #typedef.typespec
+ %% an ordinary value set with a type in #typedef.typespec
ValueSet0 = TS#'ObjectSet'.set,
Constr = check_constraints(OldS, HostType, [ValueSet0]),
Type = check_type(OldS,TSDef,TSDef#typedef.typespec),
@@ -2239,12 +2236,18 @@ normalized_record(SorS,S,Value,Components,NameList) ->
case is_record_normalized(S,NewName,Value,length(Components)) of
true ->
Value;
- _ ->
+ false ->
NoComps = length(Components),
ListOfVals = normalize_seq_or_set(SorS,S,Value,Components,NameList,[]),
- NoComps = length(ListOfVals), %% Assert
- list_to_tuple([NewName|ListOfVals])
+ NoComps = length(ListOfVals), %Assertion.
+ case use_maps(S) of
+ false ->
+ list_to_tuple([NewName|ListOfVals]);
+ true ->
+ create_map_value(Components, ListOfVals)
+ end
end.
+
is_record_normalized(S,Name,V = #'Externalvaluereference'{},NumComps) ->
case get_referenced_type(S,V) of
{_M,#valuedef{type=_T1,value=V2}} ->
@@ -2253,9 +2256,20 @@ is_record_normalized(S,Name,V = #'Externalvaluereference'{},NumComps) ->
end;
is_record_normalized(_S,Name,Value,NumComps) when is_tuple(Value) ->
(tuple_size(Value) =:= (NumComps + 1)) andalso (element(1, Value) =:= Name);
+is_record_normalized(_S, _Name, Value, _NumComps) when is_map(Value) ->
+ true;
is_record_normalized(_,_,_,_) ->
false.
+use_maps(#state{options=Opts}) ->
+ lists:member(maps, Opts).
+
+create_map_value(Components, ListOfVals) ->
+ Zipped = lists:zip(Components, ListOfVals),
+ L = [{Name,V} || {#'ComponentType'{name=Name},V} <- Zipped,
+ V =/= asn1_NOVALUE],
+ maps:from_list(L).
+
normalize_seq_or_set(SorS, S,
[{#seqtag{val=Cname},V}|Vs],
[#'ComponentType'{name=Cname,typespec=TS}|Cs],
@@ -2364,15 +2378,6 @@ normalize_s_of(SorS,S,Value,Type,NameList)
%% normalize_restrictedstring handles all format of restricted strings.
-%% tuple case
-% normalize_restrictedstring(_S,[Int1,Int2],_) when is_integer(Int1),is_integer(Int2) ->
-% {Int1,Int2};
-% %% quadruple case
-% normalize_restrictedstring(_S,[Int1,Int2,Int3,Int4],_) when is_integer(Int1),
-% is_integer(Int2),
-% is_integer(Int3),
-% is_integer(Int4) ->
-% {Int1,Int2,Int3,Int4};
%% character string list case
normalize_restrictedstring(S,[H|T],CType) when is_list(H);is_tuple(H) ->
[normalize_restrictedstring(S,H,CType)|normalize_restrictedstring(S,T,CType)];
@@ -2474,7 +2479,7 @@ check_ptype(S,Type,Ts) when is_record(Ts,type) ->
Ts#type{def=TDef}
end,
Ts2;
-%parameterized class
+%% parameterized class
check_ptype(_S,_PTDef,Ts) when is_record(Ts,objectclass) ->
throw({asn1_param_class,Ts}).
@@ -2489,8 +2494,6 @@ check_formal_parameter(_, #'Externaltypereference'{}) ->
check_formal_parameter(S, #'Externalvaluereference'{value=Name}) ->
asn1_error(S, {illegal_typereference,Name}).
-% check_type(S,Type,ObjSpec={{objectclassname,_},_}) ->
- % check_class(S,ObjSpec);
check_type(_S,Type,Ts) when is_record(Type,typedef),
(Type#typedef.checked==true) ->
Ts;
@@ -2589,7 +2592,6 @@ check_type(S=#state{recordtopname=TopName},Type,Ts) when is_record(Ts,type) ->
constraint = NewC};
_ ->
%% Here we only expand the tags and keep the ext ref.
-
NewExt = ExtRef#'Externaltypereference'{module=merged_mod(S,RefMod,Ext)},
TempNewDef#newt{
type = check_externaltypereference(S,NewExt),
@@ -2732,7 +2734,6 @@ check_type(S=#state{recordtopname=TopName},Type,Ts) when is_record(Ts,type) ->
case TopName of
[] ->
[get_datastr_name(Type)];
-% [Type#typedef.name];
_ ->
TopName
end,
@@ -2756,7 +2757,6 @@ check_type(S=#state{recordtopname=TopName},Type,Ts) when is_record(Ts,type) ->
case TopName of
[] ->
[get_datastr_name(Type)];
-% [Type#typedef.name];
_ ->
TopName
end,
@@ -2881,8 +2881,6 @@ tablecinf_choose(#'SEQUENCE'{tablecinf=TCI}) ->
get_innertag(_S,#'ObjectClassFieldType'{type=Type}) ->
case Type of
-% #type{tag=Tag} -> Tag;
-% {fixedtypevaluefield,_,#type{tag=[]}=T} -> get_taglist(S,T);
{fixedtypevaluefield,_,#type{tag=Tag}} -> Tag;
{TypeFieldName,_} when is_atom(TypeFieldName) -> [];
_ -> []
@@ -3737,14 +3735,8 @@ check_reference(S,#'Externaltypereference'{pos=Pos,module=Emod,type=Name}) ->
{ok,Imodule} ->
check_imported(S,Imodule,Name),
#'Externaltypereference'{module=Imodule,type=Name};
-%% case check_imported(S,Imodule,Name) of
-%% ok ->
-%% #'Externaltypereference'{module=Imodule,type=Name};
-%% Err ->
-%% Err
-%% end;
_ ->
- %may be a renamed type in multi file compiling!
+ %% may be a renamed type in multi file compiling!
{M,T}=get_renamed_reference(S,Name,Emod),
NewName = asn1ct:get_name_of_def(T),
NewPos = asn1ct:get_pos_of_def(T),
@@ -4153,7 +4145,6 @@ iof_associated_type(S,[]) ->
def=AssociateSeq}},
asn1_db:dbput(S#state.mname,'INSTANCE OF',TypeDef),
instance_of_decl(S#state.mname);
-%% put(instance_of,{generate,S#state.mname});
_ ->
instance_of_decl(S#state.mname),
ok
@@ -4182,17 +4173,15 @@ iof_associated_type1(S,C) ->
ObjectIdentifier =
#'ObjectClassFieldType'{classname=TypeIdentifierRef,
class=[],
-%% fieldname=[{valuefieldreference,id}],
fieldname={id,[]},
type={fixedtypevaluefield,id,
#type{def='OBJECT IDENTIFIER'}}},
Typefield =
#'ObjectClassFieldType'{classname=TypeIdentifierRef,
class=[],
-%% fieldname=[{typefieldreference,'Type'}],
fieldname={'Type',[]},
type=Typefield_type},
- IOFComponents =
+ IOFComponents0 =
[#'ComponentType'{name='type-id',
typespec=#type{tag=C1TypeTag,
def=ObjectIdentifier,
@@ -4209,6 +4198,7 @@ iof_associated_type1(S,C) ->
tablecinf=Comp2tablecinf},
prop=mandatory,
tags=[{'CONTEXT',0}]}],
+ IOFComponents = textual_order(IOFComponents0),
#'SEQUENCE'{tablecinf=TableCInf,
components=simplify_comps(IOFComponents)}.
@@ -4342,11 +4332,11 @@ check_boolean(_S,_Constr) ->
check_octetstring(_S,_Constr) ->
ok.
-% check all aspects of a SEQUENCE
-% - that all component names are unique
-% - that all TAGS are ok (when TAG default is applied)
-% - that each component is of a valid type
-% - that the extension marks are valid
+%% check all aspects of a SEQUENCE
+%% - that all component names are unique
+%% - that all TAGS are ok (when TAG default is applied)
+%% - that each component is of a valid type
+%% - that the extension marks are valid
check_sequence(S,Type,Comps) ->
Components = expand_components(S,Comps),
@@ -4687,11 +4677,11 @@ check_objectidentifier(_S,_Constr) ->
check_relative_oid(_S,_Constr) ->
ok.
-% check all aspects of a CHOICE
-% - that all alternative names are unique
-% - that all TAGS are ok (when TAG default is applied)
-% - that each alternative is of a valid type
-% - that the extension marks are valid
+%% check all aspects of a CHOICE
+%% - that all alternative names are unique
+%% - that all TAGS are ok (when TAG default is applied)
+%% - that each alternative is of a valid type
+%% - that the extension marks are valid
check_choice(S,Type,Components) when is_list(Components) ->
Components1 = [C||C = #'ComponentType'{} <- Components],
case check_unique(Components1,#'ComponentType'.name) of
@@ -4930,7 +4920,7 @@ componentrelation_leadingattr(S,CompList) ->
%%FIXME expand_ExtAddGroups([C#'ExtensionAdditionGroup'{components=ExtAdds}|T],
%% CurrPos,PosAcc,CompAcc) ->
-%% expand_ExtAddGroups(T,CurrPos+ L = lenght(ExtAdds),[{CurrPos,L}|PosAcc],ExtAdds++CompAcc);
+%% expand_ExtAddGroups(T,CurrPos+ L = length(ExtAdds),[{CurrPos,L}|PosAcc],ExtAdds++CompAcc);
%% expand_ExtAddGroups([C|T],CurrPos,PosAcc,CompAcc) ->
%% expand_ExtAddGroups(T,CurrPos+ 1,PosAcc,[C|CompAcc]);
%% expand_ExtAddGroups([],_CurrPos,PosAcc,CompAcc) ->
@@ -5045,12 +5035,12 @@ remove_doubles1(El,L) ->
%% referred to in the ObjectClassFieldType, and the name of the unique
%% field of the class of the ObjectClassFieldType.
%%
-% %% The level information outermost/innermost must be kept. There are
-% %% at least two possibilities to cover here for an outermost case: 1)
-% %% Both the simple table and the component relation have a common path
-% %% at least one step below the outermost level, i.e. the leading
-% %% information shall be on a sub level. 2) They don't have any common
-% %% path.
+%% The level information outermost/innermost must be kept. There are
+%% at least two possibilities to cover here for an outermost case: 1)
+%% Both the simple table and the component relation have a common path
+%% at least one step below the outermost level, i.e. the leading
+%% information shall be on a sub level. 2) They don't have any common
+%% path.
get_simple_table_info(S, Cs, AtLists) ->
[get_simple_table_info1(S, Cs, AtList, []) || AtList <- AtLists].
@@ -5091,10 +5081,10 @@ simple_table_info(S,#'ObjectClassFieldType'{classname=ClRef,
{_FirstFieldName,FieldNames} ->
lists:last(FieldNames)
end,
- %%ObjectClassFieldName is the last element in the dotted
- %%list of the ObjectClassFieldType. The last element may
- %%be of another class, that is referenced from the class
- %%of the ObjectClassFieldType
+ %% ObjectClassFieldName is the last element in the dotted list of
+ %% the ObjectClassFieldType. The last element may be of another
+ %% class, that is referenced from the class of the
+ %% ObjectClassFieldType
ClassDef =
case ObjectClass of
[] ->
@@ -5110,7 +5100,7 @@ simple_table_info(S,#'ObjectClassFieldType'{classname=ClRef,
%% the "name path" in the at-list to the component relation constraint
%% that must refer to a simple table constraint. The list is empty if
%% no component relation constraints were found.
-%%
+%%
%% NamePath has the names of all components that are followed from the
%% beginning of the search. CNames holds the names of all components
%% of the start level, this info is used if an outermost at-notation
@@ -5123,6 +5113,7 @@ any_component_relation(S,[#'ComponentType'{name=CName,typespec=Type}|Cs],CNames,
%% whether this constraint is relevant for the level
%% where the search started
AtNot = extract_at_notation(AtNotation),
+
%% evaluate_atpath returns the relative path to the
%% simple table constraint from where the component
%% relation is found.
@@ -5228,12 +5219,10 @@ get_components(_,#'SET'{components=Cs}) ->
tuple2complist(Cs);
get_components(_,{'CHOICE',Cs}) ->
tuple2complist(Cs);
-%do not step in inlined structures
+%%do not step in inlined structures
get_components(any,{'SEQUENCE OF',T = #type{def=_Def,inlined=no}}) ->
-% get_components(any,Def);
T;
get_components(any,{'SET OF',T = #type{def=_Def,inlined=no}}) ->
-% get_components(any,Def);
T;
get_components(_,_) ->
[].
@@ -5263,15 +5252,12 @@ extract_at_notation([{Level,ValueRefs}]) ->
componentrelation1(S,C = #type{def=Def,constraint=Constraint,tablecinf=TCI},
Path) ->
Ret =
-% case Constraint of
-% [{componentrelation,{_,_,ObjectSet},AtList}|_Rest] ->
case lists:keyfind(componentrelation, 1, Constraint) of
{_,{_,_,ObjectSet},AtList} ->
[{_,AL=[#'Externalvaluereference'{}|_R1]}|_R2] = AtList,
%% Note: if Path is longer than one,i.e. it is within
%% an inner type of the actual level, then the only
%% relevant at-list is of "outermost" type.
-%% #'ObjectClassFieldType'{class=ClassDef} = Def,
ClassDef = get_ObjectClassFieldType_classdef(S,Def),
AtPath =
lists:map(fun(#'Externalvaluereference'{value=V})->V end,
@@ -5357,7 +5343,6 @@ innertype_comprel1(S,T = #type{def=Def,constraint=Cons,tablecinf=TCI},Path) ->
%% relevent here.
[{_,AL=[#'Externalvaluereference'{value=_Attr}|_R1]}|_R2]
= AtList,
-%% #'ObjectClassFieldType'{class=ClassDef} = Def,
ClassDef = get_ObjectClassFieldType_classdef(S,Def),
AtPath =
lists:map(fun(#'Externalvaluereference'{value=V})->V end,
@@ -5426,7 +5411,7 @@ leading_attr_index1(S,[C|Cs],Arg={ObjectSet,_,CDef,P},
value_match(S,C,Name,SubAttr) ->
value_match(S,C,Name,SubAttr,[]). % C has name Name
value_match(_S,#'ComponentType'{},_Name,[],Acc) ->
- Acc;% do not reverse, indexes in reverse order
+ Acc; % do not reverse, indexes in reverse order
value_match(S,#'ComponentType'{typespec=Type},Name,[At|Ats],Acc) ->
InnerType = asn1ct_gen:get_inner(Type#type.def),
Components =
@@ -5496,8 +5481,6 @@ get_tableconstraint_info(S,Type,[C=#'ComponentType'{typespec=CheckedTs}|Cs],Acc)
CheckedTs#type{
def=NewOCFT
}};
-% constraint=[{tableconstraint_info,
-% FieldRef}]}};
{'SEQUENCE OF',SOType} when is_record(SOType,type),
(element(1,SOType#type.def)=='CHOICE') ->
CTypeList = element(2,SOType#type.def),
@@ -5600,51 +5583,6 @@ get_taglist1(S,[_H|Rest]) -> % skip EXTENSIONMARK
get_taglist1(_S,[]) ->
[].
-%% def_to_tag(S,Def) ->
-%% case asn1ct_gen:def_to_tag(Def) of
-%% {'UNIVERSAL',T} ->
-%% case asn1ct_gen:prim_bif(T) of
-%% true ->
-%% ?TAG_PRIMITIVE(tag_number(T));
-%% _ ->
-%% ?TAG_CONSTRUCTED(tag_number(T))
-%% end;
-%% _ -> []
-%% end.
-%% tag_number('BOOLEAN') -> 1;
-%% tag_number('INTEGER') -> 2;
-%% tag_number('BIT STRING') -> 3;
-%% tag_number('OCTET STRING') -> 4;
-%% tag_number('NULL') -> 5;
-%% tag_number('OBJECT IDENTIFIER') -> 6;
-%% tag_number('ObjectDescriptor') -> 7;
-%% tag_number('EXTERNAL') -> 8;
-%% tag_number('INSTANCE OF') -> 8;
-%% tag_number('REAL') -> 9;
-%% tag_number('ENUMERATED') -> 10;
-%% tag_number('EMBEDDED PDV') -> 11;
-%% tag_number('UTF8String') -> 12;
-%% %%tag_number('RELATIVE-OID') -> 13;
-%% tag_number('SEQUENCE') -> 16;
-%% tag_number('SEQUENCE OF') -> 16;
-%% tag_number('SET') -> 17;
-%% tag_number('SET OF') -> 17;
-%% tag_number('NumericString') -> 18;
-%% tag_number('PrintableString') -> 19;
-%% tag_number('TeletexString') -> 20;
-%% %%tag_number('T61String') -> 20;
-%% tag_number('VideotexString') -> 21;
-%% tag_number('IA5String') -> 22;
-%% tag_number('UTCTime') -> 23;
-%% tag_number('GeneralizedTime') -> 24;
-%% tag_number('GraphicString') -> 25;
-%% tag_number('VisibleString') -> 26;
-%% %%tag_number('ISO646String') -> 26;
-%% tag_number('GeneralString') -> 27;
-%% tag_number('UniversalString') -> 28;
-%% tag_number('CHARACTER STRING') -> 29;
-%% tag_number('BMPString') -> 30.
-
merge_tags(T1, T2) when is_list(T2) ->
merge_tags2(T1 ++ T2, []);
merge_tags(T1, T2) ->
@@ -5673,7 +5611,8 @@ storeindb(S0, #module{name=ModName,typeorval=TVlist0}=M) ->
storeindb_1(S, #module{name=ModName}=M, TVlist0, TVlist) ->
NewM = M#module{typeorval=findtypes_and_values(TVlist0)},
- asn1_db:dbnew(ModName, S#state.erule),
+ Maps = lists:member(maps, S#state.options),
+ asn1_db:dbnew(ModName, S#state.erule, Maps),
asn1_db:dbput(ModName, 'MODULE', NewM),
asn1_db:dbput(ModName, TVlist),
include_default_class(S, NewM#module.name),
diff --git a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
index 325bea5879..35cf9691c7 100644
--- a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,17 +32,17 @@
-include("asn1_records.hrl").
--import(asn1ct_gen, [emit/1,demit/1,get_record_name_prefix/0]).
+-import(asn1ct_gen, [emit/1,get_record_name_prefix/1]).
-define(ASN1CT_GEN_BER,asn1ct_gen_ber_bin_v2).
-% the encoding of class of tag bits 8 and 7
+%% the encoding of class of tag bits 8 and 7
-define(UNIVERSAL, 0).
-define(APPLICATION, 16#40).
-define(CONTEXT, 16#80).
-define(PRIVATE, 16#C0).
-% primitive or constructed encoding % bit 6
+%% primitive or constructed encoding % bit 6
-define(PRIMITIVE, 0).
-define(CONSTRUCTED, 2#00100000).
@@ -57,7 +57,7 @@
%%===============================================================================
%%===============================================================================
-gen_encode_sequence(Erules,Typename,D) when is_record(D,type) ->
+gen_encode_sequence(Gen, Typename, #type{}=D) ->
asn1ct_name:start(),
asn1ct_name:new(term),
asn1ct_name:new(bytes),
@@ -67,8 +67,12 @@ gen_encode_sequence(Erules,Typename,D) when is_record(D,type) ->
ValName =
case Typename of
['EXTERNAL'] ->
+ Tr = case Gen of
+ #gen{pack=record} -> transform_to_EXTERNAL1990;
+ #gen{pack=map} -> transform_to_EXTERNAL1990_maps
+ end,
emit([indent(4),"NewVal = ",
- {call,ext,transform_to_EXTERNAL1990,["Val"]},
+ {call,ext,Tr,["Val"]},
com,nl]),
"NewVal";
_ ->
@@ -90,25 +94,15 @@ gen_encode_sequence(Erules,Typename,D) when is_record(D,type) ->
{Rl,El} -> Rl ++ El;
_ -> CompList
end,
-
-%% don't match recordname for now, because of compatibility reasons
-%% emit(["{'",asn1ct_gen:list2rname(Typename),"'"]),
- emit(["{_"]),
- case length(CompList1) of
- 0 ->
- true;
- CompListLen ->
- emit([","]),
- mkcindexlist([Tc || Tc <- lists:seq(1,CompListLen)])
- end,
- emit(["} = ",ValName,",",nl]),
+
+ enc_match_input(Gen, ValName, CompList1),
+
EncObj =
case TableConsInfo of
#simpletableattributes{usedclassfield=Used,
uniqueclassfield=Unique} when Used /= Unique ->
false;
%% ObjectSet, name of the object set in constraints
- %%
#simpletableattributes{objectsetname=ObjectSetRef,
c_name=AttrN,
c_index=N,
@@ -125,7 +119,7 @@ gen_encode_sequence(Erules,Typename,D) when is_record(D,type) ->
emit([ObjectEncode," = ",nl,
" ",{asis,ObjSetMod},":'getenc_",ObjSetName,
"'("]),
- ValueMatch = value_match(ValueIndex,
+ ValueMatch = value_match(Gen, ValueIndex,
lists:concat(["Cindex",N])),
emit([indent(35),ValueMatch,"),",nl]),
{AttrN,ObjectEncode};
@@ -144,7 +138,7 @@ gen_encode_sequence(Erules,Typename,D) when is_record(D,type) ->
end
end,
- gen_enc_sequence_call(Erules,Typename,CompList1,1,Ext,EncObj),
+ gen_enc_sequence_call(Gen, Typename, CompList1, 1, Ext, EncObj),
emit([nl," BytesSoFar = "]),
case SeqOrSet of
@@ -168,7 +162,36 @@ gen_encode_sequence(Erules,Typename,D) when is_record(D,type) ->
call(encode_tags, ["TagIn","BytesSoFar","LenSoFar"]),
emit([".",nl]).
-gen_decode_sequence(Erules,Typename,D) when is_record(D,type) ->
+enc_match_input(#gen{pack=record}, ValName, CompList) ->
+ Len = length(CompList),
+ Vars = [lists:concat(["Cindex",N]) || N <- lists:seq(1, Len)],
+ RecordName = "_",
+ emit(["{",lists:join(",", [RecordName|Vars]),"} = ",ValName,com,nl]);
+enc_match_input(#gen{pack=map}, ValName, CompList) ->
+ Len = length(CompList),
+ Vars = [lists:concat(["Cindex",N]) || N <- lists:seq(1, Len)],
+ Zipped = lists:zip(CompList, Vars),
+ M = [[{asis,Name},":=",Var] ||
+ {#'ComponentType'{prop=mandatory,name=Name},Var} <- Zipped],
+ case M of
+ [] ->
+ ok;
+ [_|_] ->
+ emit(["#{",lists:join(",", M),"} = ",ValName,com,nl])
+ end,
+ Os0 = [{Name,Var} ||
+ {#'ComponentType'{prop=Prop,name=Name},Var} <- Zipped,
+ Prop =/= mandatory],
+ F = fun({Name,Var}) ->
+ [Var," = case ",ValName," of\n"
+ " #{",{asis,Name},":=",Var,"_0} -> ",
+ Var,"_0;\n"
+ " _ -> ",atom_to_list(?MISSING_IN_MAP),"\n"
+ "end"]
+ end,
+ emit(lists:join(",\n", [F(E) || E <- Os0]++[[]])).
+
+gen_decode_sequence(Gen, Typename, #type{}=D) ->
asn1ct_name:start(),
asn1ct_name:new(tag),
#'SEQUENCE'{tablecinf=TableConsInfo,components=CList0} = D#type.def,
@@ -206,7 +229,6 @@ gen_decode_sequence(Erules,Typename,D) when is_record(D,type) ->
usedclassfield=UniqueFieldName,
uniqueclassfield=UniqueFieldName,
valueindex=ValIndex} ->
-% {ObjectSetRef,AttrN,_N,UniqueFieldName} ->%% N is index of attribute that determines constraint
F = fun(#'ComponentType'{typespec=CT})->
case {asn1ct_gen:get_constraint(CT#type.constraint,componentrelation),CT#type.tablecinf} of
{no,[{objfun,_}|_]} -> true;
@@ -225,15 +247,20 @@ gen_decode_sequence(Erules,Typename,D) when is_record(D,type) ->
_ ->
{false,false}
end,
- RecordName = lists:concat([get_record_name_prefix(),
- asn1ct_gen:list2rname(Typename)]),
- case gen_dec_sequence_call(Erules,Typename,CompList2,Ext,DecObjInf) of
- no_terms -> % an empty sequence
- emit([nl,nl]),
- demit(["Result = "]), %dbg
- %% return value as record
+ RecordName0 = lists:concat([get_record_name_prefix(Gen),
+ asn1ct_gen:list2rname(Typename)]),
+ RecordName = list_to_atom(RecordName0),
+ case gen_dec_sequence_call(Gen, Typename, CompList2, Ext, DecObjInf) of
+ no_terms -> % an empty sequence
asn1ct_name:new(rb),
- emit([" {'",RecordName,"'}.",nl,nl]);
+ case Gen of
+ #gen{pack=record} ->
+ emit([nl,nl,
+ " {'",RecordName,"'}.",nl,nl]);
+ #gen{pack=map} ->
+ emit([nl,nl,
+ " #{}.",nl,nl])
+ end;
{LeadingAttrTerm,PostponedDecArgs} ->
emit([nl]),
case {LeadingAttrTerm,PostponedDecArgs} of
@@ -243,19 +270,19 @@ gen_decode_sequence(Erules,Typename,D) when is_record(D,type) ->
ok;
{[{ObjSetRef,LeadingAttr,Term}],PostponedDecArgs} ->
DecObj = asn1ct_gen:un_hyphen_var(lists:concat(['DecObj',LeadingAttr,Term])),
- ValueMatch = value_match(ValueIndex,Term),
+ ValueMatch = value_match(Gen, ValueIndex,Term),
{ObjSetMod,ObjSetName} = ObjSetRef,
emit([DecObj," =",nl,
" ",{asis,ObjSetMod},":'getdec_",ObjSetName,"'(",
ValueMatch,"),",nl]),
gen_dec_postponed_decs(DecObj,PostponedDecArgs)
end,
- demit(["Result = "]), %dbg
%% return value as record
case Ext of
{ext,_,_} ->
emit(["case ",{prev,tlv}," of [] -> true; _ -> true end, % ... extra fields skipped",nl]);
- _ -> % noext | extensible
+ _ ->
+ %% noext | extensible
emit(["case ",{prev,tlv}," of",nl,
"[] -> true;",
"_ -> exit({error,{asn1, {unexpected,",{prev,tlv},
@@ -263,22 +290,64 @@ gen_decode_sequence(Erules,Typename,D) when is_record(D,type) ->
"end,",nl])
end,
asn1ct_name:new(rb),
- case Typename of
- ['EXTERNAL'] ->
- emit([" OldFormat={'",RecordName,
- "', "]),
- mkvlist(asn1ct_name:all(term)),
- emit(["},",nl]),
- emit([" ",
- {call,ext,transform_to_EXTERNAL1994,
- ["OldFormat"]},".",nl]);
- _ ->
- emit([" {'",RecordName,"', "]),
- mkvlist(asn1ct_name:all(term)),
- emit(["}.",nl,nl])
- end
+ gen_dec_pack(Gen, RecordName, Typename, CompList),
+ emit([".",nl])
end.
+gen_dec_pack(Gen, RecordName, Typename, CompList) ->
+ case Typename of
+ ['EXTERNAL'] ->
+ dec_external(Gen, RecordName);
+ _ ->
+ asn1ct_name:new(res),
+ gen_dec_do_pack(Gen, RecordName, CompList),
+ emit([com,nl,
+ {curr,res}])
+ end.
+
+dec_external(#gen{pack=record}, RecordName) ->
+ All = [{var,Term} || Term <- asn1ct_name:all(term)],
+ Record = [{asis,RecordName}|All],
+ emit(["OldFormat={",lists:join(",", Record),"},",nl,
+ {call,ext,transform_to_EXTERNAL1994,
+ ["OldFormat"]}]);
+dec_external(#gen{pack=map}, _RecordName) ->
+ Vars = asn1ct_name:all(term),
+ Names = ['direct-reference','indirect-reference',
+ 'data-value-descriptor',encoding],
+ Zipped = lists:zip(Names, Vars),
+ MapInit = lists:join(",", [["'",N,"'=>",{var,V}] || {N,V} <- Zipped]),
+ emit(["OldFormat = #{",MapInit,"}",com,nl,
+ "ASN11994Format =",nl,
+ {call,ext,transform_to_EXTERNAL1994_maps,
+ ["OldFormat"]}]).
+
+gen_dec_do_pack(#gen{pack=record}, RecordName, _CompList) ->
+ All = asn1ct_name:all(term),
+ L = [{asis,RecordName}|[{var,Var} || Var <- All]],
+ emit([{curr,res}," = {",lists:join(",", L),"}"]);
+gen_dec_do_pack(#gen{pack=map}, _, CompList) ->
+ Zipped = lists:zip(CompList, asn1ct_name:all(term)),
+ PF = fun({#'ComponentType'{prop='OPTIONAL'},_}) -> false;
+ ({_,_}) -> true
+ end,
+ {Mandatory,Optional} = lists:partition(PF, Zipped),
+ L = [[{asis,Name},"=>",{var,Var}] ||
+ {#'ComponentType'{name=Name},Var} <- Mandatory],
+ emit([{curr,res}," = #{",lists:join(",", L),"}"]),
+ gen_dec_map_optional(Optional).
+
+gen_dec_map_optional([{#'ComponentType'{name=Name},Var}|T]) ->
+ asn1ct_name:new(res),
+ emit([com,nl,
+ {curr,res}," = case ",{var,Var}," of",nl,
+ " asn1_NOVALUE -> ",{prev,res},";",nl,
+ " _ -> ",{prev,res},"#{",{asis,Name},"=>",{var,Var},"}",nl,
+ "end"]),
+ gen_dec_map_optional(T);
+gen_dec_map_optional([]) ->
+ ok.
+
gen_dec_postponed_decs(_,[]) ->
emit(nl);
gen_dec_postponed_decs(DecObj,[{_Cname,{FirstPFN,PFNList},Term,
@@ -327,7 +396,7 @@ emit_opt_or_mand_check(Value,TmpTerm) ->
gen_encode_set(Erules,Typename,D) when is_record(D,type) ->
gen_encode_sequence(Erules,Typename,D).
-gen_decode_set(Erules,Typename,D) when is_record(D,type) ->
+gen_decode_set(Gen, Typename, #type{}=D) ->
asn1ct_name:start(),
%% asn1ct_name:new(term),
asn1ct_name:new(tag),
@@ -360,7 +429,6 @@ gen_decode_set(Erules,Typename,D) when is_record(D,type) ->
{DecObjInf,ValueIndex} =
case TableConsInfo of
-%% {ObjectSetRef,AttrN,_N,UniqueFieldName} ->%% N is index of attribute that determines constraint
#simpletableattributes{objectsetname=ObjectSetRef,
c_name=AttrN,
usedclassfield=UniqueFieldName,
@@ -375,7 +443,8 @@ gen_decode_set(Erules,Typename,D) when is_record(D,type) ->
end
end,
case lists:any(F,CompList) of
- true -> % when component relation constraint establish
+ true ->
+ %% when component relation constraint establish
%% relation from a component to another components
%% subtype component
{{AttrN,{deep,ObjectSetRef,UniqueFieldName,ValIndex}},
@@ -393,7 +462,7 @@ gen_decode_set(Erules,Typename,D) when is_record(D,type) ->
_ ->
emit(["SetFun = fun(FunTlv) ->", nl]),
emit(["case FunTlv of ",nl]),
- NextNum = gen_dec_set_cases(Erules,Typename,CompList,1),
+ NextNum = gen_dec_set_cases(Gen, Typename, CompList, 1),
emit([indent(6), {curr,else}," -> ",nl,
indent(9),"{",NextNum,", ",{curr,else},"}",nl]),
emit([indent(3),"end",nl]),
@@ -405,14 +474,17 @@ gen_decode_set(Erules,Typename,D) when is_record(D,type) ->
asn1ct_name:new(tlv)
end,
- RecordName = lists:concat([get_record_name_prefix(),
- asn1ct_gen:list2rname(Typename)]),
- case gen_dec_sequence_call(Erules,Typename,CompList,Ext,DecObjInf) of
- no_terms -> % an empty sequence
- emit([nl,nl]),
- demit(["Result = "]), %dbg
- %% return value as record
- emit([" {'",RecordName,"'}.",nl]);
+ RecordName0 = lists:concat([get_record_name_prefix(Gen),
+ asn1ct_gen:list2rname(Typename)]),
+ RecordName = list_to_atom(RecordName0),
+ case gen_dec_sequence_call(Gen, Typename, CompList, Ext, DecObjInf) of
+ no_terms -> % an empty SET
+ case Gen of
+ #gen{pack=record} ->
+ emit([nl,nl," {'",RecordName,"'}.",nl,nl]);
+ #gen{pack=map} ->
+ emit([nl,nl," #{}.",nl,nl])
+ end;
{LeadingAttrTerm,PostponedDecArgs} ->
emit([nl]),
case {LeadingAttrTerm,PostponedDecArgs} of
@@ -422,14 +494,13 @@ gen_decode_set(Erules,Typename,D) when is_record(D,type) ->
ok;
{[{ObjSetRef,LeadingAttr,Term}],PostponedDecArgs} ->
DecObj = asn1ct_gen:un_hyphen_var(lists:concat(['DecObj',LeadingAttr,Term])),
- ValueMatch = value_match(ValueIndex,Term),
+ ValueMatch = value_match(Gen, ValueIndex, Term),
{ObjSetMod,ObjSetName} = ObjSetRef,
emit([DecObj," =",nl,
" ",{asis,ObjSetMod},":'getdec_",ObjSetName,"'(",
ValueMatch,"),",nl]),
gen_dec_postponed_decs(DecObj,PostponedDecArgs)
end,
- demit(["Result = "]), %dbg
%% return value as record
case Ext of
Extnsn when Extnsn =/= noext ->
@@ -441,9 +512,8 @@ gen_decode_set(Erules,Typename,D) when is_record(D,type) ->
"}}}) % extra fields not allowed",nl,
"end,",nl])
end,
- emit([" {'",RecordName,"', "]),
- mkvlist(asn1ct_name:all(term)),
- emit(["}.",nl])
+ gen_dec_pack(Gen, RecordName, Typename, CompList),
+ emit([".",nl])
end.
@@ -504,10 +574,8 @@ gen_decode_sof(Erules,TypeName,_InnerTypeName,D) when is_record(D,type) ->
emit([" || ",{curr,v}," <- ",{curr,tlv},"].",nl,nl,nl]).
-gen_encode_sof_components(Erules,Typename,SeqOrSetOf,Cont)
- when is_record(Cont,type)->
-
- {Objfun,Objfun_novar,EncObj} =
+gen_encode_sof_components(Gen, Typename, SeqOrSetOf, #type{}=Cont) ->
+ {Objfun,Objfun_novar,EncObj} =
case Cont#type.tablecinf of
[{objfun,_}|_R] ->
{", ObjFun",", _",{no_attr,"ObjFun"}};
@@ -517,20 +585,19 @@ gen_encode_sof_components(Erules,Typename,SeqOrSetOf,Cont)
emit(["'enc_",asn1ct_gen:list2name(Typename),
"_components'([]",Objfun_novar,", AccBytes, AccLen) -> ",nl]),
- case catch lists:member(der,get(encoding_options)) of
- true when SeqOrSetOf=='SET OF'->
+ case {Gen,SeqOrSetOf} of
+ {#gen{der=true},'SET OF'} ->
asn1ct_func:need({ber,dynamicsort_SETOF,1}),
emit([indent(3),
"{dynamicsort_SETOF(AccBytes),AccLen};",nl,nl]);
- _ ->
+ {_,_} ->
emit([indent(3),"{lists:reverse(AccBytes),AccLen};",nl,nl])
end,
emit(["'enc_",asn1ct_gen:list2name(Typename),
"_components'([H|T]",Objfun,",AccBytes, AccLen) ->",nl]),
TypeNameSuffix = asn1ct_gen:constructed_suffix(SeqOrSetOf,Cont#type.def),
- gen_enc_line(Erules,Typename,TypeNameSuffix,Cont,"H",3,
-% mandatory,"{EncBytes,EncLen} = ",EncObj),
- mandatory,EncObj),
+ gen_enc_line(Gen, Typename, TypeNameSuffix, Cont, "H", 3,
+ mandatory, EncObj),
emit([",",nl]),
emit([indent(3),"'enc_",asn1ct_gen:list2name(Typename),
"_components'(T",Objfun,","]),
@@ -652,7 +719,7 @@ gen_dec_sequence_call2(Erules,TopType,{Root1,EList,Root2},_Ext,DecObjInf) ->
length(Root1)+length(EList),noext,
DecObjInf,LA,ArgsAcc).
-%% returns a list of tags of the elements in the component (second
+%% Returns a list of tags of the elements in the component (second
%% root) list up to and including the first mandatory tag. See 24.6 in
%% X.680 (7/2002)
get_root2_taglist([],Acc) ->
@@ -741,8 +808,6 @@ gen_dec_set_cases(Erules,TopType,[Comp|RestComps],Pos) ->
[FirstTag|_] ->
[(?ASN1CT_GEN_BER:decode_class(FirstTag#tag.class) bsl 10) + FirstTag#tag.number]
end,
-% emit([indent(6),"%Tags: ",Tags,nl]),
-% emit([indent(6),"%Type#type.tag: ",Type#type.tag,nl]),
CaseFun = fun(TagList=[H|T],Fun,N) ->
Semicolon = case TagList of
[_Tag1,_|_] -> [";",nl];
@@ -757,7 +822,6 @@ gen_dec_set_cases(Erules,TopType,[Comp|RestComps],Pos) ->
emit([";",nl])
end,
CaseFun(Tags,CaseFun,0),
-%% emit([";",nl]),
gen_dec_set_cases(Erules,TopType,RestComps,Pos+1).
@@ -937,14 +1001,6 @@ gen_enc_line(Erules,TopType,Cname,
["{",{curr,encBytes},",",{curr,encLen},"} = "],
EncObj)
end;
-% gen_enc_line(Erules,TopType,Cname,
-% Type=#type{constraint=[{componentrelation,_,_}],
-% def=#'ObjectClassFieldType'{type={typefield,_}}},
-% Element,Indent,OptOrMand=mandatory,EncObj)
-% when is_list(Element) ->
-% asn1ct_name:new(tmpBytes),
-% gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,
-% ["{",{curr,tmpBytes},",_} = "],EncObj);
gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,EncObj)
when is_list(Element) ->
gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,
@@ -965,37 +1021,30 @@ gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,Assign,EncObj)
gen_optormand_case(OptOrMand, Erules, TopType, Cname, Type, Element),
case {Type,asn1ct_gen:get_constraint(Type#type.constraint,
componentrelation)} of
-% #type{constraint=[{tableconstraint_info,RefedFieldName}],
-% def={typefield,_}} ->
{#type{def=#'ObjectClassFieldType'{type={typefield,_},
fieldname=RefedFieldName}},
{componentrelation,_,_}} ->
{_LeadingAttrName,Fun} = EncObj,
- case RefedFieldName of
- {Name,RestFieldNames} when is_atom(Name) ->
- case OptOrMand of
- mandatory -> ok;
- _ ->
-% emit(["{",{curr,tmpBytes},",",{curr,tmpLen},
- emit(["{",{curr,tmpBytes},",_ } = "])
-% "} = "])
- end,
- emit([Fun,"(",{asis,Name},", ",Element,", ",
- {asis,RestFieldNames},"),",nl]),
- emit(IndDeep),
- case OptOrMand of
- mandatory ->
- emit(["{",{curr,encBytes},",",{curr,encLen},
- "} = ",
- {call,ber,encode_open_type,
- [{curr,tmpBytes},{asis,Tag}]},nl]);
- _ ->
- emit([{call,ber,encode_open_type,
- [{curr,tmpBytes},{asis,Tag}]}])
- end;
- Err ->
- throw({asn1,{'internal error',Err}})
- end;
+ {Name,RestFieldNames} = RefedFieldName,
+ true = is_atom(Name), %Assertion.
+ case OptOrMand of
+ mandatory -> ok;
+ _ ->
+ emit(["{",{curr,tmpBytes},",_ } = "])
+ end,
+ emit([Fun,"(",{asis,Name},", ",Element,", ",
+ {asis,RestFieldNames},"),",nl]),
+ emit(IndDeep),
+ case OptOrMand of
+ mandatory ->
+ emit(["{",{curr,encBytes},",",{curr,encLen},
+ "} = ",
+ {call,ber,encode_open_type,
+ [{curr,tmpBytes},{asis,Tag}]},nl]);
+ _ ->
+ emit([{call,ber,encode_open_type,
+ [{curr,tmpBytes},{asis,Tag}]}])
+ end;
_ ->
case WhatKind of
{primitive,bif} ->
@@ -1028,35 +1077,44 @@ gen_enc_line(Erules,TopType,Cname,Type,Element,Indent,OptOrMand,Assign,EncObj)
emit([nl,indent(7),"end"])
end.
-gen_optormand_case(mandatory, _Erules, _TopType, _Cname, _Type, _Element) ->
+gen_optormand_case(mandatory, _Gen, _TopType, _Cname, _Type, _Element) ->
ok;
-gen_optormand_case('OPTIONAL', Erules, _TopType, _Cname, _Type, Element) ->
+gen_optormand_case('OPTIONAL', Gen, _TopType, _Cname, _Type, Element) ->
emit([" case ",Element," of",nl]),
- emit([indent(9),"asn1_NOVALUE -> {",
- empty_lb(Erules),",0};",nl]),
+ Missing = case Gen of
+ #gen{pack=record} -> asn1_NOVALUE;
+ #gen{pack=map} -> ?MISSING_IN_MAP
+ end,
+ emit([indent(9),Missing," -> {",
+ empty_lb(Gen),",0};",nl]),
emit([indent(9),"_ ->",nl,indent(12)]);
-gen_optormand_case({'DEFAULT',DefaultValue}, Erules, _TopType,
+gen_optormand_case({'DEFAULT',DefaultValue}, Gen, _TopType,
_Cname, Type, Element) ->
CurrMod = get(currmod),
- case catch lists:member(der,get(encoding_options)) of
- true ->
- asn1ct_gen_check:emit(Type, DefaultValue, Element);
- _ ->
- emit([" case ",Element," of",nl]),
- emit([indent(9),"asn1_DEFAULT -> {",
- empty_lb(Erules),
- ",0};",nl]),
- case DefaultValue of
- #'Externalvaluereference'{module=CurrMod,
- value=V} ->
- emit([indent(9),"?",{asis,V}," -> {",
- empty_lb(Erules),",0};",nl]);
- _ ->
- emit([indent(9),{asis,
- DefaultValue}," -> {",
- empty_lb(Erules),",0};",nl])
- end,
- emit([indent(9),"_ ->",nl,indent(12)])
+ case Gen of
+ #gen{erule=ber,der=true} ->
+ asn1ct_gen_check:emit(Gen, Type, DefaultValue, Element);
+ #gen{erule=ber,der=false,pack=Pack} ->
+ Ind9 = indent(9),
+ DefMarker = case Pack of
+ record -> asn1_DEFAULT;
+ map -> ?MISSING_IN_MAP
+ end,
+ emit([" case ",Element," of",nl,
+ Ind9,{asis,DefMarker}," ->",nl,
+ Ind9,indent(3),"{",empty_lb(Gen),",0};",nl,
+ Ind9,"_ when ",Element," =:= "]),
+ Dv = case DefaultValue of
+ #'Externalvaluereference'{module=CurrMod,
+ value=V} ->
+ ["?",{asis,V}];
+ _ ->
+ [{asis,DefaultValue}]
+ end,
+ emit(Dv++[" ->",nl,
+ Ind9,indent(3),"{",empty_lb(Gen),",0};",nl,
+ Ind9,"_ ->",nl,
+ indent(12)])
end.
%% Use for SEQUENCE OF and CHOICE.
@@ -1087,7 +1145,9 @@ gen_dec_line(Erules,TopType,Cname,CTags,Type,OptOrMand,DecObjInf) ->
gen_dec_call(InnerType,Erules,TopType,Cname,Type,
BytesVar,Tag,
mandatory,", mandatory, ",DecObjInf,OptOrMand);
- _ -> %optional or default or a mandatory component after an extensionmark
+ _ ->
+ %% optional or default, or a mandatory component after
+ %% an extension marker
{FirstTag,RestTag} =
case Tag of
[] ->
@@ -1162,9 +1222,9 @@ gen_dec_line(Erules,TopType,Cname,CTags,Type,OptOrMand,DecObjInf) ->
PostponedDec
end,
case DecObjInf of
- {Cname,ObjSet} -> % this must be the component were an object is
- %% choosen from the object set according to the table
- %% constraint.
+ {Cname,ObjSet} ->
+ %% This must be the component were an object is chosen
+ %% from the object set according to the table constraint.
ObjSetName = case ObjSet of
{deep,OSName,_,_} ->
OSName;
@@ -1201,13 +1261,10 @@ gen_dec_call({typefield,_},_,_,_Cname,Type,BytesVar,Tag,_,_,false,_) ->
[];
gen_dec_call({typefield,_},_,_,Cname,Type,BytesVar,Tag,_,_,_DecObjInf,OptOrMandComp) ->
call(decode_open_type, [BytesVar,{asis,Tag}]),
- RefedFieldName =
-% asn1ct_gen:get_constraint(Type#type.constraint,
-% tableconstraint_info),
- (Type#type.def)#'ObjectClassFieldType'.fieldname,
+ RefedFieldName = (Type#type.def)#'ObjectClassFieldType'.fieldname,
[{Cname,RefedFieldName,asn1ct_gen:mk_var(asn1ct_name:curr(term)),
asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),Tag,OptOrMandComp}];
-gen_dec_call(InnerType, _Erules, TopType, Cname, Type, BytesVar,
+gen_dec_call(InnerType, Gen, TopType, Cname, Type, BytesVar,
Tag, _PrimOptOrMand, _OptOrMand, DecObjInf,_) ->
WhatKind = asn1ct_gen:type(InnerType),
gen_dec_call1(WhatKind, InnerType, TopType, Cname,
@@ -1215,7 +1272,7 @@ gen_dec_call(InnerType, _Erules, TopType, Cname, Type, BytesVar,
case DecObjInf of
{Cname,{_,OSet,_UniqueFName,ValIndex}} ->
Term = asn1ct_gen:mk_var(asn1ct_name:curr(term)),
- ValueMatch = value_match(ValIndex,Term),
+ ValueMatch = value_match(Gen, ValIndex, Term),
{ObjSetMod,ObjSetName} = OSet,
emit([",",nl,"ObjFun = ",{asis,ObjSetMod},":'getdec_",ObjSetName,
"'(",ValueMatch,")"]);
@@ -1260,8 +1317,6 @@ gen_dec_call1(WhatKind, _, TopType, Cname, Type, BytesVar, Tag) ->
emit(["{'",asn1ct_gen:list2name([Cname|TopType]),"',",
BytesVar,"}"]);
_ ->
-% {DecFunName, _DecMod, _DecFun} =
-% case {asn1ct:get_gen_state_field(namelist),WhatKind} of
EmitDecFunCall =
fun(FuncName) ->
case {WhatKind,Type#type.tablecinf} of
@@ -1277,14 +1332,11 @@ gen_dec_call1(WhatKind, _, TopType, Cname, Type, BytesVar, Tag) ->
Sindex =
case WhatKind of
#'Externaltypereference'{} ->
-% asn1ct:maybe_rename_function(WhatKind,List),
SI = asn1ct:maybe_saved_sindex(WhatKind,List),
Saves = {WhatKind,SI,List},
asn1ct:add_tobe_refed_func(Saves),
SI;
_ ->
-% asn1ct:maybe_rename_function([Cname|TopType],
-% List),
SI = asn1ct:maybe_saved_sindex([Cname|TopType],List),
Saves = {[Cname|TopType],SI,List,Type},
asn1ct:add_tobe_refed_func(Saves),
@@ -1292,8 +1344,6 @@ gen_dec_call1(WhatKind, _, TopType, Cname, Type, BytesVar, Tag) ->
end,
asn1ct:update_gen_state(namelist,Rest),
Prefix=asn1ct:get_gen_state_field(prefix),
-% Suffix =
-% lists:concat(["_",asn1ct:latest_sindex()]),
Suffix =
case Sindex of
I when is_integer(I),I>0 -> lists:concat(["_",I]);
@@ -1301,8 +1351,6 @@ gen_dec_call1(WhatKind, _, TopType, Cname, Type, BytesVar, Tag) ->
end,
{DecFunName,_,_}=
mkfuncname(TopType,Cname,WhatKind,Prefix,Suffix),
-% SuffixedName =
-% lists:concat([DecFunName,asn1ct:latest_sindex()]),
EmitDecFunCall(DecFunName);
[{Cname,parts}|Rest] ->
asn1ct:update_gen_state(namelist,Rest),
@@ -1322,13 +1370,6 @@ gen_dec_call1(WhatKind, _, TopType, Cname, Type, BytesVar, Tag) ->
mkfuncname(TopType,Cname,WhatKind,"dec_",""),
EmitDecFunCall(DecFunName)
end
-% case {WhatKind,Type#type.tablecinf} of
-% {{constructed,bif},[{objfun,_}|_Rest]} ->
-% emit([DecFunName,"(",BytesVar,", ",{asis,Tag},
-% ", ObjFun)"]);
-% _ ->
-% emit([DecFunName,"(",BytesVar,", ",{asis,Tag},")"])
-% end
end.
@@ -1340,19 +1381,6 @@ gen_dec_call1(WhatKind, _, TopType, Cname, Type, BytesVar, Tag) ->
indent(N) ->
lists:duplicate(N,32). % 32 = space
-mkcindexlist([H,T1|T], Sep) -> % Sep is a string e.g ", " or "+ "
- emit(["Cindex",H,Sep]),
- mkcindexlist([T1|T], Sep);
-mkcindexlist([H|T], Sep) ->
- emit(["Cindex",H]),
- mkcindexlist(T, Sep);
-mkcindexlist([], _) ->
- true.
-
-mkcindexlist(L) ->
- mkcindexlist(L,", ").
-
-
mkvlist([H,T1|T], Sep) -> % Sep is a string e.g ", " or "+ "
emit([{var,H},Sep]),
mkvlist([T1|T], Sep);
@@ -1398,6 +1426,9 @@ print_attribute_comment(InnerType,Pos,Cname,Prop) ->
case InnerType of
#'Externaltypereference'{module=XModule,type=Name} ->
emit([nl,"%% attribute ",Cname,"(",Pos,") External ",XModule,":",Name]);
+ _ when is_tuple(InnerType) ->
+ emit([nl,"%% attribute ",Cname,"(",Pos,") with type "|
+ tuple_to_list(InnerType)]);
_ ->
emit([nl,"%% attribute ",Cname,"(",Pos,") with type ",InnerType])
end,
@@ -1429,19 +1460,25 @@ mkfuncname(TopType,Cname,WhatKind,Prefix,Suffix) ->
{F, "?MODULE", F}
end.
-empty_lb(ber) ->
+empty_lb(#gen{erule=ber}) ->
"<<>>".
-value_match(Index,Value) when is_atom(Value) ->
- value_match(Index,atom_to_list(Value));
-value_match([],Value) ->
+value_match(#gen{pack=record}, VIs, Value) ->
+ value_match_rec(VIs, Value);
+value_match(#gen{pack=map}, VIs, Value) ->
+ value_match_map(VIs, Value).
+
+value_match_rec([], Value) ->
+ Value;
+value_match_rec([{VI,_}|VIs], Value0) ->
+ Value = value_match_rec(VIs, Value0),
+ lists:concat(["element(",VI,", ",Value,")"]).
+
+value_match_map([], Value) ->
Value;
-value_match([{VI,_}|VIs],Value) ->
- value_match1(Value,VIs,lists:concat(["element(",VI,","]),1).
-value_match1(Value,[],Acc,Depth) ->
- Acc ++ Value ++ lists:concat(lists:duplicate(Depth,")"));
-value_match1(Value,[{VI,_}|VIs],Acc,Depth) ->
- value_match1(Value,VIs,Acc++lists:concat(["element(",VI,","]),Depth+1).
+value_match_map([{_,Name}|VIs], Value0) ->
+ Value = value_match_map(VIs, Value0),
+ lists:concat(["maps:get(",Name,", ",Value,")"]).
call(F, Args) ->
asn1ct_func:call(ber, F, Args).
diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl
index a34b25182c..aff383479b 100644
--- a/lib/asn1/src/asn1ct_constructed_per.erl
+++ b/lib/asn1/src/asn1ct_constructed_per.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,19 +30,28 @@
-export([gen_decode_choice/3]).
-include("asn1_records.hrl").
-%-compile(export_all).
--import(asn1ct_gen, [emit/1,demit/1,get_record_name_prefix/0]).
--import(asn1ct_func, [call/3]).
+-import(asn1ct_gen, [emit/1,get_record_name_prefix/1]).
+
+-type type_name() :: any().
+
%% ENCODE GENERATOR FOR SEQUENCE TYPE ** **********
-gen_encode_set(Erules,TypeName,D) ->
- gen_encode_constructed(Erules,TypeName,D).
+-spec gen_encode_set(Gen, TypeName, #type{}) -> 'ok' when
+ Gen :: #gen{},
+ TypeName :: type_name().
+
+gen_encode_set(Gen, TypeName, D) ->
+ gen_encode_constructed(Gen, TypeName, D).
-gen_encode_sequence(Erules,TypeName,D) ->
- gen_encode_constructed(Erules,TypeName,D).
+-spec gen_encode_sequence(Gen, TypeName, #type{}) -> 'ok' when
+ Gen :: #gen{},
+ TypeName :: type_name().
+
+gen_encode_sequence(Gen, TypeName, D) ->
+ gen_encode_constructed(Gen, TypeName, D).
gen_encode_constructed(Erule, Typename, #type{}=D) ->
asn1ct_name:start(),
@@ -50,88 +59,23 @@ gen_encode_constructed(Erule, Typename, #type{}=D) ->
asn1ct_imm:enc_cg(Imm, is_aligned(Erule)),
emit([".",nl]).
-gen_encode_constructed_imm(Erule, Typename, #type{}=D) ->
- {ExtAddGroup,TmpCompList,TableConsInfo} =
- case D#type.def of
- #'SEQUENCE'{tablecinf=TCI,components=CL,extaddgroup=ExtAddGroup0} ->
- {ExtAddGroup0,CL,TCI};
- #'SET'{tablecinf=TCI,components=CL} ->
- {undefined,CL,TCI}
- end,
-
- CompList = case ExtAddGroup of
- undefined ->
- TmpCompList;
- _ when is_integer(ExtAddGroup) ->
- %% This is a fake SEQUENCE representing an ExtensionAdditionGroup
- %% Reset the textual order so we get the right
- %% index of the components
- [Comp#'ComponentType'{textual_order=undefined}||
- Comp<-TmpCompList]
- end,
- ExternalImm =
- case Typename of
- ['EXTERNAL'] ->
- Next = asn1ct_gen:mk_var(asn1ct_name:next(val)),
- Curr = asn1ct_gen:mk_var(asn1ct_name:curr(val)),
- asn1ct_name:new(val),
- [{call,ext,transform_to_EXTERNAL1990,[{var,Curr}],{var,Next}}];
- _ ->
- []
- end,
- Aligned = is_aligned(Erule),
- Value0 = make_var(val),
+gen_encode_constructed_imm(Gen, Typename, #type{}=D) ->
+ {CompList,TableConsInfo} = enc_complist(D),
+ ExternalImm = external_imm(Gen, Typename),
Optionals = optionals(to_textual_order(CompList)),
- ImmOptionals = [asn1ct_imm:per_enc_optional(Value0, Opt, Aligned) ||
- Opt <- Optionals],
+ ImmOptionals = enc_optionals(Gen, Optionals),
Ext = extensible_enc(CompList),
+ Aligned = is_aligned(Gen),
ExtImm = case Ext of
{ext,ExtPos,NumExt} when NumExt > 0 ->
- gen_encode_extaddgroup(CompList),
+ gen_encode_extaddgroup(Gen, CompList),
Value = make_var(val),
- asn1ct_imm:per_enc_extensions(Value, ExtPos,
- NumExt, Aligned);
+ enc_extensions(Gen, Value, ExtPos, NumExt, Aligned);
_ ->
[]
end,
- {EncObj,ObjSetImm} =
- case TableConsInfo of
- #simpletableattributes{usedclassfield=Used,
- uniqueclassfield=Unique} when Used /= Unique ->
- {false,[]};
- %% ObjectSet, name of the object set in constraints
- %%
- %%{ObjectSet,AttrN,N,UniqueFieldName} -> %% N is index of attribute that determines constraint
- #simpletableattributes{objectsetname=ObjectSet,
- c_name=AttrN,
- c_index=N,
- usedclassfield=UniqueFieldName,
- uniqueclassfield=UniqueFieldName,
- valueindex=ValueIndex0
- } -> %% N is index of attribute that determines constraint
- {Module,ObjSetName} = ObjectSet,
- #typedef{typespec=#'ObjectSet'{gen=Gen}} =
- asn1_db:dbget(Module, ObjSetName),
- case Gen of
- true ->
- ValueIndex = ValueIndex0 ++ [{N+1,top}],
- Val = make_var(val),
- {ObjSetImm0,Dst} = enc_dig_out_value(ValueIndex, Val),
- {{AttrN,Dst},ObjSetImm0};
- false ->
- {false,[]}
- end;
- _ ->
- case D#type.tablecinf of
- [{objfun,_}|_] ->
- %% when the simpletableattributes was at an outer
- %% level and the objfun has been passed through the
- %% function call
- {{"got objfun through args",{var,"ObjFun"}},[]};
- _ ->
- {false,[]}
- end
- end,
+ MatchImm = enc_map_match(Gen, CompList),
+ {EncObj,ObjSetImm} = enc_table(Gen, TableConsInfo, D),
ImmSetExt =
case Ext of
{ext,_Pos,NumExt2} when NumExt2 > 0 ->
@@ -141,38 +85,195 @@ gen_encode_constructed_imm(Erule, Typename, #type{}=D) ->
_ ->
[]
end,
- ImmBody = gen_enc_components_call(Erule, Typename, CompList, EncObj, Ext),
- ExternalImm ++ ExtImm ++ ObjSetImm ++
+ ImmBody = gen_enc_components_call(Gen, Typename, CompList, EncObj, Ext),
+ ExternalImm ++ MatchImm ++ ExtImm ++ ObjSetImm ++
asn1ct_imm:enc_append([ImmSetExt] ++ ImmOptionals ++ ImmBody).
-gen_encode_extaddgroup(CompList) ->
+external_imm(Gen, ['EXTERNAL']) ->
+ Next = asn1ct_gen:mk_var(asn1ct_name:next(val)),
+ Curr = asn1ct_gen:mk_var(asn1ct_name:curr(val)),
+ asn1ct_name:new(val),
+ F = case Gen of
+ #gen{pack=record} -> transform_to_EXTERNAL1990;
+ #gen{pack=map} -> transform_to_EXTERNAL1990_maps
+ end,
+ [{call,ext,F,[{var,Curr}],{var,Next}}];
+external_imm(_, _) ->
+ [].
+
+enc_extensions(#gen{pack=record}, Value, ExtPos, NumExt, Aligned) ->
+ asn1ct_imm:per_enc_extensions(Value, ExtPos, NumExt, Aligned);
+enc_extensions(#gen{pack=map}, Value, ExtPos, NumExt, Aligned) ->
+ Vars = [{var,lists:concat(["Input@",Pos])} ||
+ Pos <- lists:seq(ExtPos, ExtPos+NumExt-1)],
+ Undefined = atom_to_list(?MISSING_IN_MAP),
+ asn1ct_imm:per_enc_extensions_map(Value, Vars, Undefined, Aligned).
+
+enc_complist(#type{def=Def}) ->
+ case Def of
+ #'SEQUENCE'{tablecinf=TCI,components=CL0,extaddgroup=ExtAddGroup} ->
+ case ExtAddGroup of
+ undefined ->
+ {CL0,TCI};
+ _ when is_integer(ExtAddGroup) ->
+ %% This is a fake SEQUENCE representing an
+ %% ExtensionAdditionGroup. Renumber the textual
+ %% order so we get the right index of the
+ %% components.
+ CL = add_textual_order(CL0),
+ {CL,TCI}
+ end;
+ #'SET'{tablecinf=TCI,components=CL} ->
+ {CL,TCI}
+ end.
+
+enc_table(Gen, #simpletableattributes{objectsetname=ObjectSet,
+ c_name=AttrN,
+ c_index=N,
+ usedclassfield=UniqueFieldName,
+ uniqueclassfield=UniqueFieldName,
+ valueindex=ValueIndex0}, _) ->
+ {Module,ObjSetName} = ObjectSet,
+ #typedef{typespec=#'ObjectSet'{gen=MustGen}} =
+ asn1_db:dbget(Module, ObjSetName),
+ case MustGen of
+ true ->
+ ValueIndex = ValueIndex0 ++ [{N+1,'ASN1_top'}],
+ Val = make_var(val),
+ {ObjSetImm,Dst} = enc_dig_out_value(Gen, ValueIndex, Val),
+ {{AttrN,Dst},ObjSetImm};
+ false ->
+ {false,[]}
+ end;
+enc_table(_Gen, #simpletableattributes{}, _) ->
+ {false,[]};
+enc_table(_Gen, _, #type{tablecinf=TCInf}) ->
+ case TCInf of
+ [{objfun,_}|_] ->
+ %% The simpletableattributes was at an outer
+ %% level and the objfun has been passed through the
+ %% function call.
+ {{"got objfun through args",{var,"ObjFun"}},[]};
+ _ ->
+ {false,[]}
+ end.
+
+enc_optionals(Gen, Optionals) ->
+ Var = make_var(val),
+ enc_optionals_1(Gen, Optionals, Var).
+
+enc_optionals_1(#gen{pack=record}=Gen, [{Pos,DefVals}|T], Var) ->
+ {Imm0,Element} = asn1ct_imm:enc_element(Pos+1, Var),
+ Imm = asn1ct_imm:per_enc_optional(Element, DefVals),
+ [Imm0++Imm|enc_optionals_1(Gen, T, Var)];
+enc_optionals_1(#gen{pack=map}=Gen, [{Pos,DefVals0}|T], V) ->
+ Var = {var,lists:concat(["Input@",Pos])},
+ DefVals = translate_missing_value(Gen, DefVals0),
+ Imm = asn1ct_imm:per_enc_optional(Var, DefVals),
+ [Imm|enc_optionals_1(Gen, T, V)];
+enc_optionals_1(_, [], _) ->
+ [].
+
+enc_map_match(#gen{pack=record}, _Cs) ->
+ [];
+enc_map_match(#gen{pack=map}, Cs0) ->
+ Var0 = "Input",
+ Cs = enc_flatten_components(Cs0),
+ M = [[quote_atom(Name),":=",lists:concat([Var0,"@",Order])] ||
+ #'ComponentType'{prop=mandatory,name=Name,
+ textual_order=Order} <- Cs],
+ Mand = case M of
+ [] ->
+ [];
+ [_|_] ->
+ Patt = {expr,lists:flatten(["#{",lists:join(",", M),"}"])},
+ [{assign,Patt,{var,asn1ct_name:curr(val)}}]
+ end,
+
+ Os0 = [{Name,Order} ||
+ #'ComponentType'{prop=Prop,name=Name,
+ textual_order=Order} <- Cs,
+ Prop =/= mandatory],
+ {var,Val} = make_var(val),
+ F = fun({Name,Order}) ->
+ Var = lists:concat([Var0,"@",Order]),
+ P0 = ["case ",Val," of\n"
+ " #{",quote_atom(Name),":=",Var,"_0} -> ",
+ Var,"_0;\n"
+ " _ -> ",atom_to_list(?MISSING_IN_MAP),"\n"
+ "end"],
+ P = lists:flatten(P0),
+ {assign,{var,Var},P}
+ end,
+ Os = [F(O) || O <- Os0],
+ Mand ++ Os.
+
+enc_flatten_components({Root1,Ext0,Root2}=CL) ->
+ {_,Gs} = extgroup_pos_and_length(CL),
+ Ext = wrap_extensionAdditionGroups(Ext0, Gs),
+ Root1 ++ Root2 ++ [mark_optional(C) || C <- Ext];
+enc_flatten_components({Root,Ext}) ->
+ enc_flatten_components({Root,Ext,[]});
+enc_flatten_components(Cs) ->
+ Cs.
+
+gen_encode_extaddgroup(#gen{pack=record}, CompList) ->
case extgroup_pos_and_length(CompList) of
{extgrouppos,[]} ->
ok;
{extgrouppos,ExtGroupPosLenList} ->
- _ = [do_gen_encode_extaddgroup(G) || G <- ExtGroupPosLenList],
+ _ = [gen_encode_eag_record(G) ||
+ G <- ExtGroupPosLenList],
ok
- end.
+ end;
+gen_encode_extaddgroup(#gen{pack=map}, Cs0) ->
+ Cs = enc_flatten_components(Cs0),
+ gen_encode_eag_map(Cs).
+
+gen_encode_eag_map([#'ComponentType'{name=Group,typespec=Type}|Cs]) ->
+ case Type of
+ #type{def=#'SEQUENCE'{extaddgroup=G,components=GCs0}}
+ when is_integer(G) ->
+ Ns = [N || #'ComponentType'{name=N,prop=mandatory} <- GCs0],
+ test_for_mandatory(Ns, Group),
+ gen_encode_eag_map(Cs);
+ _ ->
+ gen_encode_eag_map(Cs)
+ end;
+gen_encode_eag_map([]) ->
+ ok.
+
+test_for_mandatory([Mand|_], Group) ->
+ emit([{next,val}," = case ",{curr,val}," of",nl,
+ "#{",quote_atom(Mand),":=_} -> ",
+ {curr,val},"#{",{asis,Group},"=>",{curr,val},"};",nl,
+ "#{} -> ",{curr,val},nl,
+ "end,",nl]),
+ asn1ct_name:new(val);
+test_for_mandatory([], _) ->
+ ok.
-do_gen_encode_extaddgroup({ActualGroupPos,GroupVirtualPos,GroupLen}) ->
+gen_encode_eag_record({ActualPos,VirtualPos,Len}) ->
Val = asn1ct_gen:mk_var(asn1ct_name:curr(val)),
- Elements = make_elements(GroupVirtualPos+1,
- Val,
- lists:seq(1, GroupLen)),
- Expr = any_non_value(GroupVirtualPos+1, Val, GroupLen, ""),
+ Elements = get_input_vars(Val, VirtualPos, Len),
+ Expr = any_non_value(Val, VirtualPos, Len),
emit([{next,val}," = case ",Expr," of",nl,
- "false -> setelement(",{asis,ActualGroupPos+1},", ",
+ "false -> setelement(",{asis,ActualPos+1},", ",
{curr,val},", asn1_NOVALUE);",nl,
- "true -> setelement(",{asis,ActualGroupPos+1},", ",
+ "true -> setelement(",{asis,ActualPos+1},", ",
{curr,val},", {extaddgroup,", Elements,"})",nl,
"end,",nl]),
asn1ct_name:new(val).
-any_non_value(_, _, 0, _) ->
+any_non_value(Val, Pos, N) ->
+ L = any_non_value_1(Val, Pos, N),
+ lists:join(" orelse ", L).
+
+any_non_value_1(_, _, 0) ->
[];
-any_non_value(Pos, Val, N, Sep) ->
- Sep ++ [make_element(Pos, Val)," =/= asn1_NOVALUE"] ++
- any_non_value(Pos+1, Val, N-1, [" orelse",nl]).
+any_non_value_1(Val, Pos, N) ->
+ Var = get_input_var(Val, Pos),
+ [Var ++ " =/= asn1_NOVALUE"|any_non_value_1(Val, Pos+1, N-1)].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% generate decode function for SEQUENCE and SET
@@ -255,7 +356,6 @@ gen_dec_constructed_imm(Erule, Typename, #type{}=D) ->
#'SEQUENCE'{tablecinf=TCI,components=CL} ->
{add_textual_order(CL),TCI};
#'SET'{tablecinf=TCI,components=CL} ->
-%% {add_textual_order(CL),TCI}
{CL,TCI} % the textual order is already taken care of
end,
Ext = extensible_dec(CompList),
@@ -273,13 +373,11 @@ gen_dec_constructed_imm(Erule, Typename, #type{}=D) ->
end,
ObjSetInfo =
case TableConsInfo of
-%% {ObjectSet,AttrN,N,UniqueFieldName} ->%% N is index of attribute that determines constraint
#simpletableattributes{objectsetname=ObjectSet,
c_name=AttrN,
usedclassfield=UniqueFieldName,
uniqueclassfield=UniqueFieldName,
valueindex=ValIndex} ->
-%% {AttrN,ObjectSet};
F = fun(#'ComponentType'{typespec=CT})->
case {asn1ct_gen:get_constraint(CT#type.constraint,componentrelation),CT#type.tablecinf} of
{no,[{objfun,_}|_R]} -> true;
@@ -306,55 +404,105 @@ gen_dec_constructed_imm(Erule, Typename, #type{}=D) ->
{DecObjInf,_,_} = ObjSetInfo,
EmitComp = gen_dec_components_call(Erule, Typename, CompList,
DecObjInf, Ext, length(Optionals)),
- EmitRest = fun({AccTerm,AccBytes}) ->
- gen_dec_constructed_imm_2(Erule, Typename,
- CompList,
- ObjSetInfo,
- AccTerm, AccBytes)
- end,
- [EmitExt,EmitOpt|EmitComp++[{safe,EmitRest}]].
+ EmitObjSets = gen_dec_objsets_fun(Erule, ObjSetInfo),
+ EmitPack = fun(_) ->
+ gen_dec_pack(Erule, Typename, CompList)
+ end,
+ RestGroup = {group,[{safe,EmitObjSets},{safe,EmitPack}]},
+ [EmitExt,EmitOpt|EmitComp++[RestGroup]].
+
+gen_dec_objsets_fun(Gen, ObjSetInfo) ->
+ fun({AccTerm,AccBytes}) ->
+ {_,_UniqueFName,ValueIndex} = ObjSetInfo,
+ case {AccTerm,AccBytes} of
+ {[],[]} ->
+ ok;
+ {_,[]} ->
+ ok;
+ {[{ObjSet,LeadingAttr,Term}],ListOfOpenTypes} ->
+ ValueMatch = value_match(Gen, ValueIndex, Term),
+ _ = [begin
+ gen_dec_open_type(Gen, ValueMatch, ObjSet,
+ LeadingAttr, T),
+ emit([com,nl])
+ end || T <- ListOfOpenTypes],
+ ok
+ end
+ end.
-gen_dec_constructed_imm_2(Erule, Typename, CompList,
- ObjSetInfo, AccTerm, AccBytes) ->
- {_,_UniqueFName,ValueIndex} = ObjSetInfo,
- case {AccTerm,AccBytes} of
- {[],[]} ->
- ok;
- {_,[]} ->
- ok;
- {[{ObjSet,LeadingAttr,Term}],ListOfOpenTypes} ->
- ValueMatch = value_match(ValueIndex, Term),
- _ = [begin
- gen_dec_open_type(Erule, ValueMatch, ObjSet,
- LeadingAttr, T),
- emit([com,nl])
- end || T <- ListOfOpenTypes],
- ok
- end,
- %% we don't return named lists any more Cnames = mkcnamelist(CompList),
- demit({"Result = "}), %dbg
- %% return value as record
- RecordName = record_name(Typename),
+gen_dec_pack(Gen, Typename, CompList) ->
case Typename of
['EXTERNAL'] ->
- emit({" OldFormat={'",RecordName,
- "'"}),
- mkvlist(asn1ct_name:all(term)),
- emit({"},",nl}),
- emit([" ASN11994Format =",nl,
- " ",
- {call,ext,transform_to_EXTERNAL1994,
- ["OldFormat"]},com,nl]),
- emit(" {ASN11994Format,");
+ dec_external(Gen, Typename);
_ ->
- emit(["{{'",RecordName,"'"]),
- %% CompList is used here because we don't want
- %% ExtensionAdditionGroups to be wrapped in SEQUENCES when
- %% we are ordering the fields according to textual order
- mkvlist(textual_order(to_encoding_order(CompList),asn1ct_name:all(term))),
- emit("},")
- end,
- emit({{curr,bytes},"}"}).
+ asn1ct_name:new(res),
+ gen_dec_do_pack(Gen, Typename, CompList),
+ emit([com,nl,
+ "{",{curr,res},",",{curr,bytes},"}"])
+ end.
+
+dec_external(#gen{pack=record}=Gen, Typename) ->
+ RecordName = list_to_atom(record_name(Gen, Typename)),
+ All = [{var,Term} || Term <- asn1ct_name:all(term)],
+ Record = [{asis,RecordName}|All],
+ emit(["OldFormat={",lists:join(",", Record),"},",nl,
+ "ASN11994Format =",nl,
+ {call,ext,transform_to_EXTERNAL1994,
+ ["OldFormat"]},com,nl,
+ "{ASN11994Format,",{curr,bytes},"}"]);
+dec_external(#gen{pack=map}, _Typename) ->
+ Vars = asn1ct_name:all(term),
+ Names = ['direct-reference','indirect-reference',
+ 'data-value-descriptor',encoding],
+ Zipped = lists:zip(Names, Vars),
+ MapInit = lists:join(",", [["'",N,"'=>",{var,V}] || {N,V} <- Zipped]),
+ emit(["OldFormat = #{",MapInit,"}",com,nl,
+ "ASN11994Format =",nl,
+ {call,ext,transform_to_EXTERNAL1994_maps,
+ ["OldFormat"]},com,nl,
+ "{ASN11994Format,",{curr,bytes},"}"]).
+
+gen_dec_do_pack(#gen{pack=record}=Gen, TypeName, CompList) ->
+ Zipped0 = zip_components(CompList, asn1ct_name:all(term)),
+ Zipped = textual_order(Zipped0),
+ RecordName = ["'",record_name(Gen, TypeName),"'"],
+ L = [RecordName|[{var,Var} || {_,Var} <- Zipped]],
+ emit([{curr,res}," = {",lists:join(",", L),"}"]);
+gen_dec_do_pack(#gen{pack=map}, _, CompList0) ->
+ CompList = enc_flatten_components(CompList0),
+ Zipped0 = zip_components(CompList, asn1ct_name:all(term)),
+ Zipped = textual_order(Zipped0),
+ PF = fun({#'ComponentType'{prop='OPTIONAL'},_}) -> false;
+ ({_,_}) -> true
+ end,
+ {Mandatory,Optional} = lists:partition(PF, Zipped),
+ L = [[{asis,Name},"=>",{var,Var}] ||
+ {#'ComponentType'{name=Name},Var} <- Mandatory],
+ emit([{curr,res}," = #{",lists:join(",", L),"}"]),
+ gen_dec_map_optional(Optional),
+ gen_dec_merge_maps(asn1ct_name:all(map)).
+
+gen_dec_map_optional([{#'ComponentType'{name=Name},Var}|T]) ->
+ asn1ct_name:new(res),
+ emit([com,nl,
+ {curr,res}," = case ",{var,Var}," of",nl,
+ " asn1_NOVALUE -> ",{prev,res},";",nl,
+ " _ -> ",{prev,res},"#{",{asis,Name},"=>",{var,Var},"}",nl,
+ "end"]),
+ gen_dec_map_optional(T);
+gen_dec_map_optional([]) ->
+ ok.
+
+gen_dec_merge_maps([M|Ms]) ->
+ asn1ct_name:new(res),
+ emit([com,nl,
+ {curr,res}," = maps:merge(",{prev,res},", ",{var,M},")"]),
+ gen_dec_merge_maps(Ms);
+gen_dec_merge_maps([]) ->
+ ok.
+
+quote_atom(A) when is_atom(A) ->
+ io_lib:format("~p", [A]).
%% record_name([TypeName]) -> RecordNameString
%% Construct a record name for the constructed type, ignoring any
@@ -362,10 +510,10 @@ gen_dec_constructed_imm_2(Erule, Typename, CompList,
%% group. Such fake sequences never appear as a top type, and their
%% name always start with "ExtAddGroup".
-record_name(Typename0) ->
+record_name(Gen, Typename0) ->
[TopType|Typename1] = lists:reverse(Typename0),
Typename = filter_ext_add_groups(Typename1, [TopType]),
- lists:concat([get_record_name_prefix(),
+ lists:concat([get_record_name_prefix(Gen),
asn1ct_gen:list2rname(Typename)]).
filter_ext_add_groups([H|T], Acc) when is_atom(H) ->
@@ -379,17 +527,26 @@ filter_ext_add_groups([H|T], Acc) ->
filter_ext_add_groups(T, [H|Acc]);
filter_ext_add_groups([], Acc) -> Acc.
-textual_order([#'ComponentType'{textual_order=undefined}|_],TermList) ->
- TermList;
-textual_order(CompList,TermList) when is_list(CompList) ->
- OrderList = [Ix||#'ComponentType'{textual_order=Ix} <- CompList],
- [Term||{_,Term}<-
- lists:sort(lists:zip(OrderList,
- lists:sublist(TermList,length(OrderList))))];
- %% sublist is just because Termlist can sometimes be longer than
- %% OrderList, which it really shouldn't
-textual_order({Root,Ext},TermList) ->
- textual_order(Root ++ Ext,TermList).
+zip_components({Root,Ext}, Vars) ->
+ zip_components({Root,Ext,[]}, Vars);
+zip_components({R1,Ext0,R2}, Vars) ->
+ Ext = [mark_optional(C) || C <- Ext0],
+ zip_components(R1++R2++Ext, Vars);
+zip_components(Cs, Vars) when is_list(Cs) ->
+ zip_components_1(Cs, Vars).
+
+zip_components_1([#'ComponentType'{}=C|Cs], [V|Vs]) ->
+ [{C,V}|zip_components_1(Cs, Vs)];
+zip_components_1([_|Cs], Vs) ->
+ zip_components_1(Cs, Vs);
+zip_components_1([], []) ->
+ [].
+
+textual_order([{#'ComponentType'{textual_order=undefined},_}|_]=L) ->
+ L;
+textual_order(L0) ->
+ L = [{Ix,P} || {#'ComponentType'{textual_order=Ix},_}=P <- L0],
+ [C || {_,C} <- lists:sort(L)].
to_textual_order({Root,Ext}) ->
{to_textual_order(Root),Ext};
@@ -458,7 +615,7 @@ dec_objset_default(N, _, _, true) ->
end]).
dec_objset_1(Erule, N, {Id,Obj}, RestFields, Typename) ->
- emit([{asis,N},"(Bytes, ",{asis,Id},") ->",nl]),
+ emit([{asis,N},"(Bytes, Id) when Id =:= ",{asis,Id}," ->",nl]),
dec_objset_2(Erule, Obj, RestFields, Typename).
dec_objset_2(Erule, Obj, RestFields0, Typename) ->
@@ -525,10 +682,10 @@ gen_decode_choice(Erules,Typename,D) when is_record(D,type) ->
{'CHOICE',CompList} = D#type.def,
Ext = extensible_enc(CompList),
gen_dec_choice(Erules,Typename,CompList,Ext),
- emit({".",nl}).
+ emit([".",nl]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% Encode generator for SEQUENCE OF type
+%% Encode generator for SEQUENCE OF type
gen_encode_sof(Erule, Typename, SeqOrSetOf, D) ->
asn1ct_name:start(),
@@ -595,8 +752,7 @@ do_gen_decode_sof(Erules, Typename, SeqOrSetOf, D) ->
emit([",",nl,
{asis,F},"(",Num,", ",Buf,ObjFun,", [])"]).
-is_aligned(per) -> true;
-is_aligned(uper) -> false.
+is_aligned(#gen{erule=per,aligned=Aligned}) -> Aligned.
gen_decode_length(Constraint, Erule) ->
emit(["%% Length with constraint ",{asis,Constraint},nl]),
@@ -621,41 +777,26 @@ gen_decode_sof_components(Erule, Name, Typename, SeqOrSetOf, Cont) ->
case asn1ct_gen:type(Conttype) of
{primitive,bif} ->
asn1ct_gen_per:gen_dec_prim(Erule, Cont, "Bytes"),
- emit({com,nl});
+ emit([com,nl]);
{constructed,bif} ->
NewTypename = [Constructed_Suffix|Typename],
- emit({"'dec_",asn1ct_gen:list2name(NewTypename),
- "'(Bytes",ObjFun,"),",nl});
+ emit([{asis,dec_func(asn1ct_gen:list2name(NewTypename))},
+ "(Bytes",ObjFun,"),",nl]);
#'Externaltypereference'{}=Etype ->
asn1ct_gen_per:gen_dec_external(Etype, "Bytes"),
emit([com,nl]);
'ASN1_OPEN_TYPE' ->
asn1ct_gen_per:gen_dec_prim(Erule, #type{def='ASN1_OPEN_TYPE'},
"Bytes"),
- emit({com,nl});
+ emit([com,nl]);
_ ->
- emit({"'dec_",Conttype,"'(Bytes),",nl})
+ emit([{asis,dec_func(Conttype)},"(Bytes),",nl])
end,
emit([{asis,Name},"(Num-1, Remain",ObjFun,", [Term|Acc]).",nl]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-% General and special help functions (not exported)
-
-mkvlist([H|T]) ->
- emit(","),
- mkvlist2([H|T]);
-mkvlist([]) ->
- true.
-mkvlist2([H,T1|T]) ->
- emit({{var,H},","}),
- mkvlist2([T1|T]);
-mkvlist2([H|T]) ->
- emit({{var,H}}),
- mkvlist2(T);
-mkvlist2([]) ->
- true.
-
+%% General and special help functions (not exported)
extensible_dec(CompList) when is_list(CompList) ->
noext;
@@ -728,28 +869,26 @@ gen_dec_optionals(Optionals) ->
{imm,Imm0,E}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Produce a list with positions (in the Value record) where
-%% there are optional components, start with 2 because first element
-%% is the record name
-
-optionals({L1,Ext,L2}) ->
- Opt1 = optionals(L1,[],2),
- ExtComps = length([C||C = #'ComponentType'{}<-Ext]),
- Opt2 = optionals(L2,[],2+length(L1)+ExtComps),
- Opt1 ++ Opt2;
-optionals({L,_Ext}) -> optionals(L,[],2);
-optionals(L) -> optionals(L,[],2).
-optionals([#'ComponentType'{prop='OPTIONAL'}|Rest], Acc, Pos) ->
- optionals(Rest, [Pos|Acc], Pos+1);
-optionals([#'ComponentType'{typespec=T,prop={'DEFAULT',Val}}|Rest],
- Acc, Pos) ->
+optionals({Root1,Ext,Root2}) ->
+ Opt1 = optionals(Root1, 1),
+ ExtComps = length([C || C = #'ComponentType'{} <- Ext]),
+ Opt2 = optionals(Root2, 1 + length(Root1) + ExtComps),
+ Opt1 ++ Opt2;
+optionals({L,_Ext}) ->
+ optionals(L, 1);
+optionals(L) ->
+ optionals(L, 1).
+
+optionals([#'ComponentType'{prop='OPTIONAL'}|Rest], Pos) ->
+ [{Pos,[asn1_NOVALUE]}|optionals(Rest, Pos+1)];
+optionals([#'ComponentType'{typespec=T,prop={'DEFAULT',Val}}|Cs], Pos) ->
Vals = def_values(T, Val),
- optionals(Rest, [{Pos,Vals}|Acc], Pos+1);
-optionals([#'ComponentType'{}|Rest], Acc, Pos) ->
- optionals(Rest, Acc, Pos+1);
-optionals([], Acc, _) ->
- lists:reverse(Acc).
+ [{Pos,Vals}|optionals(Cs, Pos+1)];
+optionals([#'ComponentType'{}|Rest], Pos) ->
+ optionals(Rest, Pos+1);
+optionals([], _) ->
+ [].
%%%%%%%%%%%%%%%%%%%%%%
%% create_optionality_table(Cs=[#'ComponentType'{textual_order=undefined}|_]) ->
@@ -779,13 +918,6 @@ get_optionality_pos(TextPos,OptTable) ->
no_num
end.
-to_encoding_order(Cs) when is_list(Cs) ->
- Cs;
-to_encoding_order(Cs = {_Root,_Ext}) ->
- Cs;
-to_encoding_order({R1,Ext,R2}) ->
- {R1++R2,Ext}.
-
add_textual_order(Cs) when is_list(Cs) ->
{NewCs,_} = add_textual_order1(Cs,1),
NewCs;
@@ -798,9 +930,7 @@ add_textual_order({R1,Ext,R2}) ->
{NewExt,Num2} = add_textual_order1(Ext,Num1),
{NewR2,_} = add_textual_order1(R2,Num2),
{NewR1,NewExt,NewR2}.
-%%add_textual_order1(Cs=[#'ComponentType'{textual_order=Int}|_],I)
-%% when is_integer(Int) ->
-%% {Cs,I};
+
add_textual_order1(Cs,NumIn) ->
lists:mapfoldl(fun(C=#'ComponentType'{},Num) ->
{C#'ComponentType'{textual_order=Num},
@@ -810,69 +940,83 @@ add_textual_order1(Cs,NumIn) ->
end,
NumIn,Cs).
-gen_enc_components_call(Erule,TopType,{Root,ExtList}, DynamicEnc,Ext) ->
- gen_enc_components_call(Erule,TopType,{Root,ExtList,[]}, DynamicEnc,Ext);
-gen_enc_components_call(Erule,TopType,CL={Root,ExtList,Root2}, DynamicEnc,Ext) ->
- %% The type has extensionmarker
- {Imm0,Rpos} = gen_enc_components_call1(Erule,TopType,Root++Root2,1, DynamicEnc,noext,[]),
+gen_enc_components_call(Erule, TopType, {Root,ExtList}, DynamicEnc, Ext) ->
+ gen_enc_components_call(Erule, TopType, {Root,ExtList,[]}, DynamicEnc, Ext);
+gen_enc_components_call(Erule, TopType, {R1,ExtList0,R2}=CL, DynamicEnc, Ext) ->
+ Root = R1 ++ R2,
+ Imm0 = gen_enc_components_call1(Erule, TopType, Root, DynamicEnc, noext),
ExtImm = case Ext of
{ext,_,ExtNum} when ExtNum > 0 ->
[{var,"Extensions"}];
_ ->
[]
end,
- %handle extensions
{extgrouppos,ExtGroupPosLen} = extgroup_pos_and_length(CL),
- NewExtList = wrap_extensionAdditionGroups(ExtList,ExtGroupPosLen),
- {Imm1,_} = gen_enc_components_call1(Erule,TopType,NewExtList,Rpos,DynamicEnc,Ext,[]),
+ ExtList1 = wrap_extensionAdditionGroups(ExtList0, ExtGroupPosLen),
+ ExtList = [mark_optional(C) || C <- ExtList1],
+ Imm1 = gen_enc_components_call1(Erule, TopType, ExtList, DynamicEnc, Ext),
Imm0 ++ [ExtImm|Imm1];
-gen_enc_components_call(Erule,TopType, CompList, DynamicEnc, Ext) ->
- %% The type has no extensionmarker
- {Imm,_} = gen_enc_components_call1(Erule,TopType,CompList,1,DynamicEnc,Ext,[]),
- Imm.
+gen_enc_components_call(Erule, TopType, CompList, DynamicEnc, Ext) ->
+ %% No extension marker.
+ gen_enc_components_call1(Erule, TopType, CompList, DynamicEnc, Ext).
+
+mark_optional(#'ComponentType'{prop=Prop0}=C) ->
+ Prop = case Prop0 of
+ mandatory -> 'OPTIONAL';
+ 'OPTIONAL'=Keep -> Keep;
+ {'DEFAULT',_}=Keep -> Keep
+ end,
+ C#'ComponentType'{prop=Prop};
+mark_optional(Other) ->
+ Other.
+
+gen_enc_components_call1(Gen, TopType, [C|Rest], DynamicEnc, Ext) ->
+ #'ComponentType'{name=Cname,typespec=Type,
+ prop=Prop,textual_order=Num} = C,
+ InnerType = asn1ct_gen:get_inner(Type#type.def),
+ CommentString = attribute_comment(InnerType, Num, Cname),
+ ImmComment = asn1ct_imm:enc_comment(CommentString),
-gen_enc_components_call1(Erule,TopType,
- [C=#'ComponentType'{name=Cname,typespec=Type,prop=Prop}|Rest],
- Tpos,
- DynamicEnc, Ext, Acc) ->
-
- TermNo =
- case C#'ComponentType'.textual_order of
- undefined ->
- Tpos;
- CanonicalNum ->
- CanonicalNum
- end,
- Val = make_var(val),
- {Imm0,Element} = asn1ct_imm:enc_element(TermNo+1, Val),
- Imm1 = gen_enc_line_imm(Erule, TopType, Cname, Type, Element, DynamicEnc, Ext),
- Category = case {Prop,Ext} of
- {'OPTIONAL',_} ->
- optional;
- {{'DEFAULT',DefVal},_} ->
- {default,DefVal};
- {_,{ext,ExtPos,_}} when Tpos >= ExtPos ->
- optional;
- {_,_} ->
- mandatory
- end,
- Imm2 = case Category of
+ {Imm0,Element} = enc_fetch_field(Gen, Num, Prop),
+ Imm1 = gen_enc_line_imm(Gen, TopType, Cname, Type,
+ Element, DynamicEnc, Ext),
+ Imm2 = case Prop of
mandatory ->
Imm1;
- optional ->
- asn1ct_imm:enc_absent(Element, [asn1_NOVALUE], Imm1);
- {default,Def} ->
+ 'OPTIONAL' ->
+ enc_absent(Gen, Element, [asn1_NOVALUE], Imm1);
+ {'DEFAULT',Def} when Ext =:= noext ->
DefValues = def_values(Type, Def),
- asn1ct_imm:enc_absent(Element, DefValues, Imm1)
+ enc_absent(Gen, Element, DefValues, Imm1);
+ {'DEFAULT',_} ->
+ enc_absent(Gen, Element, [asn1_DEFAULT], Imm1)
end,
Imm = case Imm2 of
[] -> [];
- _ -> Imm0 ++ Imm2
+ _ -> [ImmComment|Imm0 ++ Imm2]
end,
- gen_enc_components_call1(Erule, TopType, Rest, Tpos+1, DynamicEnc, Ext, [Imm|Acc]);
-gen_enc_components_call1(_Erule,_TopType,[],Pos,_,_, Acc) ->
- ImmList = lists:reverse(Acc),
- {ImmList,Pos}.
+ [Imm|gen_enc_components_call1(Gen, TopType, Rest, DynamicEnc, Ext)];
+gen_enc_components_call1(_Gen, _TopType, [], _, _) ->
+ [].
+
+enc_absent(Gen, Var, Absent0, Imm) ->
+ Absent = translate_missing_value(Gen, Absent0),
+ asn1ct_imm:enc_absent(Var, Absent, Imm).
+
+translate_missing_value(#gen{pack=record}, Optionals) ->
+ Optionals;
+translate_missing_value(#gen{pack=map}, Optionals) ->
+ case Optionals of
+ [asn1_NOVALUE|T] -> [?MISSING_IN_MAP|T];
+ [asn1_DEFAULT|T] -> [?MISSING_IN_MAP|T];
+ {call,_,_,_} -> Optionals
+ end.
+
+enc_fetch_field(#gen{pack=record}, Num, _Prop) ->
+ Val = make_var(val),
+ asn1ct_imm:enc_element(Num+1, Val);
+enc_fetch_field(#gen{pack=map}, Num, _) ->
+ {[],{var,lists:concat(["Input@",Num])}}.
def_values(#type{def=#'Externaltypereference'{module=Mod,type=Type}}, Def) ->
#typedef{typespec=T} = asn1_db:dbget(Mod, Type),
@@ -1115,27 +1259,31 @@ gen_dec_components_call(Erule, TopType, {Root,ExtList},
DecInfObj, Ext, NumberOfOptionals) ->
gen_dec_components_call(Erule,TopType,{Root,ExtList,[]},
DecInfObj,Ext,NumberOfOptionals);
-gen_dec_components_call(Erule,TopType,CL={Root1,ExtList,Root2},
- DecInfObj,Ext,NumberOfOptionals) ->
+gen_dec_components_call(Gen, TopType, {Root1,ExtList,Root2}=CL,
+ DecInfObj, Ext, NumberOfOptionals) ->
%% The type has extensionmarker
OptTable = create_optionality_table(Root1++Root2),
Init = {ignore,fun(_) -> {[],[]} end},
{EmitRoot,Tpos} =
- gen_dec_comp_calls(Root1++Root2, Erule, TopType, OptTable,
+ gen_dec_comp_calls(Root1++Root2, Gen, TopType, OptTable,
DecInfObj, noext, NumberOfOptionals,
1, []),
- EmitGetExt = gen_dec_get_extension(Erule),
+ EmitGetExt = gen_dec_get_extension(Gen),
{extgrouppos,ExtGroupPosLen} = extgroup_pos_and_length(CL),
NewExtList = wrap_extensionAdditionGroups(ExtList, ExtGroupPosLen),
- {EmitExts,_} = gen_dec_comp_calls(NewExtList, Erule, TopType, OptTable,
+ {EmitExts,_} = gen_dec_comp_calls(NewExtList, Gen, TopType, OptTable,
DecInfObj, Ext, NumberOfOptionals,
Tpos, []),
NumExtsToSkip = ext_length(ExtList),
Finish =
fun(St) ->
emit([{next,bytes},"= "]),
- call(Erule, skipextensions,
- [{curr,bytes},NumExtsToSkip+1,"Extensions"]),
+ Mod = case Gen of
+ #gen{erule=per,aligned=false} -> uper;
+ #gen{erule=per,aligned=true} -> per
+ end,
+ asn1ct_func:call(Mod, skipextensions,
+ [{curr,bytes},NumExtsToSkip+1,"Extensions"]),
asn1ct_name:new(bytes),
St
end,
@@ -1178,29 +1326,19 @@ gen_dec_comp_calls([C|Cs], Erule, TopType, OptTable, DecInfObj,
gen_dec_comp_calls([], _, _, _, _, _, _, Tpos, Acc) ->
{lists:append(lists:reverse(Acc)),Tpos}.
-gen_dec_comp_call(Comp, Erule, TopType, Tpos, OptTable, DecInfObj,
+gen_dec_comp_call(Comp, Gen, TopType, Tpos, OptTable, DecInfObj,
Ext, NumberOfOptionals) ->
- #'ComponentType'{typespec=Type,prop=Prop,textual_order=TextPos} = Comp,
+ #'ComponentType'{name=Cname,typespec=Type,
+ prop=Prop,textual_order=TextPos} = Comp,
Pos = case Ext of
noext -> Tpos;
{ext,Epos,_Enum} -> Tpos - Epos + 1
end,
- InnerType =
- case Type#type.def of
- #'ObjectClassFieldType'{type=InType} ->
- InType;
- Def ->
- asn1ct_gen:get_inner(Def)
- end,
+ InnerType = asn1ct_gen:get_inner(Type#type.def),
- DispType = case InnerType of
- #'Externaltypereference'{type=T} -> T;
- IT when is_tuple(IT) -> element(2,IT);
- _ -> InnerType
- end,
+ CommentString = attribute_comment(InnerType, TextPos, Cname),
Comment = fun(St) ->
- emit([nl,"%% attribute number ",TextPos,
- " with type ",DispType,nl]),
+ emit([nl,"%% ",CommentString,nl]),
St
end,
@@ -1219,15 +1357,9 @@ gen_dec_comp_call(Comp, Erule, TopType, Tpos, OptTable, DecInfObj,
_ ->
case Type of
#type{def=#'SEQUENCE'{
- extaddgroup=Number1,
- components=ExtGroupCompList1}} when is_integer(Number1)->
- fun(St) ->
- emit(["{{_,"]),
- emit_extaddgroupTerms(term,ExtGroupCompList1),
- emit(["}"]),
- emit([",",{next,bytes},"} = "]),
- St
- end;
+ extaddgroup=GroupNum,
+ components=CompList}} when is_integer(GroupNum)->
+ dec_match_extadd_fun(Gen, CompList);
_ ->
fun(St) ->
asn1ct_name:new(term),
@@ -1237,9 +1369,9 @@ gen_dec_comp_call(Comp, Erule, TopType, Tpos, OptTable, DecInfObj,
end
end
end,
- {Pre,Post} = comp_call_pre_post(Ext, Prop, Pos, Type, TextPos,
+ {Pre,Post} = comp_call_pre_post(Gen, Ext, Prop, Pos, Type, TextPos,
OptTable, NumberOfOptionals, Ext),
- Lines = gen_dec_seq_line_imm(Erule, TopType, Comp, Tpos, DecInfObj, Ext),
+ Lines = gen_dec_seq_line_imm(Gen, TopType, Comp, Tpos, DecInfObj, Ext),
AdvBuffer = {ignore,fun(St) ->
asn1ct_name:new(bytes),
St
@@ -1247,9 +1379,24 @@ gen_dec_comp_call(Comp, Erule, TopType, Tpos, OptTable, DecInfObj,
[{group,[{safe,Comment},{safe,Preamble}] ++ Pre ++
Lines ++ Post ++ [{safe,AdvBuffer}]}].
-comp_call_pre_post(noext, mandatory, _, _, _, _, _, _) ->
+dec_match_extadd_fun(#gen{pack=record}, CompList) ->
+ fun(St) ->
+ emit(["{{_,"]),
+ emit_extaddgroupTerms(term, CompList),
+ emit(["}"]),
+ emit([",",{next,bytes},"} = "]),
+ St
+ end;
+dec_match_extadd_fun(#gen{pack=map}, _CompList) ->
+ fun(St) ->
+ asn1ct_name:new(map),
+ emit(["{",{curr,map},",",{next,bytes},"} = "]),
+ St
+ end.
+
+comp_call_pre_post(_Gen, noext, mandatory, _, _, _, _, _, _) ->
{[],[]};
-comp_call_pre_post(noext, Prop, _, Type, TextPos,
+comp_call_pre_post(_Gen, noext, Prop, _, Type, TextPos,
OptTable, NumOptionals, Ext) ->
%% OPTIONAL or DEFAULT
OptPos = get_optionality_pos(TextPos, OptTable),
@@ -1273,32 +1420,53 @@ comp_call_pre_post(noext, Prop, _, Type, TextPos,
"end"]),
St
end]};
-comp_call_pre_post({ext,_,_}, Prop, Pos, Type, _, _, _, Ext) ->
+comp_call_pre_post(Gen, {ext,_,_}, Prop, Pos, Type, _, _, _, Ext) ->
%% Extension
{[fun(St) ->
emit(["case Extensions of",nl,
" <<_:",Pos-1,",1:1,_/bitstring>> ->",nl]),
St
end],
- [fun(St) ->
- emit([";",nl,
- "_ ->",nl,
- "{"]),
- case Type of
- #type{def=#'SEQUENCE'{
- extaddgroup=Number2,
- components=ExtGroupCompList2}}
- when is_integer(Number2)->
- emit("{extAddGroup,"),
- gen_dec_extaddGroup_no_val(Ext, Type, ExtGroupCompList2),
- emit("}");
- _ ->
- gen_dec_component_no_val(Ext, Type, Prop)
- end,
- emit([",",{curr,bytes},"}",nl,
- "end"]),
- St
- end]}.
+ [extadd_group_fun(Gen, Prop, Type, Ext)]}.
+
+extadd_group_fun(#gen{pack=record}, Prop, Type, Ext) ->
+ fun(St) ->
+ emit([";",nl,
+ "_ ->",nl,
+ "{"]),
+ case Type of
+ #type{def=#'SEQUENCE'{
+ extaddgroup=Number2,
+ components=ExtGroupCompList2}}
+ when is_integer(Number2)->
+ emit("{extAddGroup,"),
+ gen_dec_extaddGroup_no_val(Ext, Type, ExtGroupCompList2),
+ emit("}");
+ _ ->
+ gen_dec_component_no_val(Ext, Type, Prop)
+ end,
+ emit([",",{curr,bytes},"}",nl,
+ "end"]),
+ St
+ end;
+extadd_group_fun(#gen{pack=map}, Prop, Type, Ext) ->
+ fun(St) ->
+ emit([";",nl,
+ "_ ->",nl,
+ "{"]),
+ case Type of
+ #type{def=#'SEQUENCE'{
+ extaddgroup=Number2,
+ components=Comp}}
+ when is_integer(Number2)->
+ dec_map_extaddgroup_no_val(Ext, Type, Comp);
+ _ ->
+ gen_dec_component_no_val(Ext, Type, Prop)
+ end,
+ emit([",",{curr,bytes},"}",nl,
+ "end"]),
+ St
+ end.
is_mandatory_predef_tab_c(noext, mandatory,
{"got objfun through args","ObjFun"}) ->
@@ -1322,10 +1490,23 @@ gen_dec_component_no_val(_, Type, {'DEFAULT',DefVal0}) ->
DefVal = asn1ct_gen:conform_value(Type, DefVal0),
emit([{asis,DefVal}]);
gen_dec_component_no_val(_, _, 'OPTIONAL') ->
- emit({"asn1_NOVALUE"});
+ emit(["asn1_NOVALUE"]);
gen_dec_component_no_val({ext,_,_}, _, mandatory) ->
- emit({"asn1_NOVALUE"}).
-
+ emit(["asn1_NOVALUE"]).
+
+dec_map_extaddgroup_no_val(Ext, Type, Comp) ->
+ L0 = [dec_map_extaddgroup_no_val_1(N, P, Ext, Type) ||
+ #'ComponentType'{name=N,prop=P} <- Comp],
+ L = [E || E <- L0, E =/= []],
+ emit(["#{",lists:join(",", L),"}"]).
+
+dec_map_extaddgroup_no_val_1(Name, {'DEFAULT',DefVal0}, _Ext, Type) ->
+ DefVal = asn1ct_gen:conform_value(Type, DefVal0),
+ [Name,"=>",{asis,DefVal}];
+dec_map_extaddgroup_no_val_1(_Name, 'OPTIONAL', _, _) ->
+ [];
+dec_map_extaddgroup_no_val_1(_Name, mandatory, {ext,_,_}, _) ->
+ [].
gen_dec_choice_line(Erule, TopType, Comp, Pre) ->
Imm0 = gen_dec_line_imm(Erule, TopType, Comp, false, Pre),
@@ -1461,29 +1642,29 @@ gen_dec_line_special(Erule, {typefield,_}, _TopType, Comp,
Prop}],PrevSt}
end
end;
-gen_dec_line_special(Erule, Atype, TopType, Comp, DecInfObj) ->
- case gen_dec_line_other(Erule, Atype, TopType, Comp) of
+gen_dec_line_special(Gen, Atype, TopType, Comp, DecInfObj) ->
+ case gen_dec_line_other(Gen, Atype, TopType, Comp) of
Fun when is_function(Fun, 1) ->
fun({BytesVar,PrevSt}) ->
Fun(BytesVar),
- gen_dec_line_dec_inf(Comp, DecInfObj),
+ gen_dec_line_dec_inf(Gen,Comp, DecInfObj),
{[],PrevSt}
end;
Imm0 ->
{imm,Imm0,
fun(Imm, {BytesVar,PrevSt}) ->
asn1ct_imm:dec_code_gen(Imm, BytesVar),
- gen_dec_line_dec_inf(Comp, DecInfObj),
+ gen_dec_line_dec_inf(Gen, Comp, DecInfObj),
{[],PrevSt}
end}
end.
-gen_dec_line_dec_inf(Comp, DecInfObj) ->
+gen_dec_line_dec_inf(Gen, Comp, DecInfObj) ->
#'ComponentType'{name=Cname} = Comp,
case DecInfObj of
{Cname,{_,_OSet,_UniqueFName,ValIndex}} ->
Term = asn1ct_gen:mk_var(asn1ct_name:curr(term)),
- ValueMatch = value_match(ValIndex,Term),
+ ValueMatch = value_match(Gen, ValIndex,Term),
emit([",",nl,
"ObjFun = ",ValueMatch]);
_ ->
@@ -1508,16 +1689,15 @@ gen_dec_line_other(Erule, Atype, TopType, Comp) ->
end;
{constructed,bif} ->
NewTypename = [Cname|TopType],
+ DecFunc = dec_func(asn1ct_gen:list2name(NewTypename)),
case Type#type.tablecinf of
[{objfun,_}|_R] ->
fun(BytesVar) ->
- emit({"'dec_",asn1ct_gen:list2name(NewTypename),
- "'(",BytesVar,", ObjFun)"})
+ emit([{asis,DecFunc},"(",BytesVar,", ObjFun)"])
end;
_ ->
fun(BytesVar) ->
- emit({"'dec_",asn1ct_gen:list2name(NewTypename),
- "'(",BytesVar,")"})
+ emit([{asis,DecFunc},"(",BytesVar,")"])
end
end
end.
@@ -1705,20 +1885,17 @@ gen_dec_choice2(Erule, TopType, [H0|T], Pos, Sep0, Pre) ->
gen_dec_choice2(Erule, TopType, T, Pos+1, Sep, Pre);
gen_dec_choice2(_, _, [], _, _, _) -> ok.
-make_elements(I,Val,ExtCnames) ->
- make_elements(I,Val,ExtCnames,[]).
+get_input_vars(Val, I, N) ->
+ L = get_input_vars_1(Val, I, N),
+ lists:join(",", L).
-make_elements(I,Val,[_ExtCname],Acc)-> % the last one, no comma needed
- Element = make_element(I, Val),
- make_elements(I+1,Val,[],[Element|Acc]);
-make_elements(I,Val,[_ExtCname|Rest],Acc)->
- Element = make_element(I, Val),
- make_elements(I+1,Val,Rest,[", ",Element|Acc]);
-make_elements(_I,_,[],Acc) ->
- lists:reverse(Acc).
+get_input_vars_1(_Val, _I, 0) ->
+ [];
+get_input_vars_1(Val, I, N) ->
+ [get_input_var(Val, I)|get_input_vars_1(Val, I+1, N-1)].
-make_element(I, Val) ->
- lists:flatten(io_lib:format("element(~w, ~s)", [I,Val])).
+get_input_var(Val, I) ->
+ lists:flatten(io_lib:format("element(~w, ~s)", [I+1,Val])).
emit_extaddgroupTerms(VarSeries,[_]) ->
asn1ct_name:new(VarSeries),
@@ -1726,7 +1903,7 @@ emit_extaddgroupTerms(VarSeries,[_]) ->
ok;
emit_extaddgroupTerms(VarSeries,[_|Rest]) ->
asn1ct_name:new(VarSeries),
- emit({{curr,VarSeries},","}),
+ emit([{curr,VarSeries},","]),
emit_extaddgroupTerms(VarSeries,Rest);
emit_extaddgroupTerms(_,[]) ->
ok.
@@ -1735,63 +1912,79 @@ flat_complist({Rl1,El,Rl2}) -> Rl1 ++ El ++ Rl2;
flat_complist({Rl,El}) -> Rl ++ El;
flat_complist(CompList) -> CompList.
-%%wrap_compList({Root1,Ext,Root2}) ->
-%% {Root1,wrap_extensionAdditionGroups(Ext),Root2};
-%%wrap_compList({Root1,Ext}) ->
-%% {Root1,wrap_extensionAdditionGroups(Ext)};
-%%wrap_compList(CompList) ->
-%% CompList.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Will convert all componentTypes following 'ExtensionAdditionGroup'
+%% Convert all componentTypes following 'ExtensionAdditionGroup'
%% up to the matching 'ExtensionAdditionGroupEnd' into one componentType
-%% of type SEQUENCE with the componentTypes as components
+%% of type SEQUENCE with the componentTypes as components.
%%
-wrap_extensionAdditionGroups(ExtCompList,ExtGroupPosLen) ->
- wrap_extensionAdditionGroups(ExtCompList,ExtGroupPosLen,[],0,0).
+wrap_extensionAdditionGroups(ExtCompList, ExtGroupPosLen) ->
+ wrap_eags(ExtCompList, ExtGroupPosLen, 0, 0).
-wrap_extensionAdditionGroups([{'ExtensionAdditionGroup',_Number}|Rest],
- [{ActualPos,_,_}|ExtGroupPosLenRest],Acc,_ExtAddGroupDiff,ExtGroupNum) ->
- {ExtGroupCompList,['ExtensionAdditionGroupEnd'|Rest2]} =
+wrap_eags([{'ExtensionAdditionGroup',_Number}|T0],
+ [{ActualPos,_,_}|Gs], _ExtAddGroupDiff, ExtGroupNum) ->
+ {ExtGroupCompList,['ExtensionAdditionGroupEnd'|T]} =
lists:splitwith(fun(#'ComponentType'{}) -> true;
(_) -> false
- end,
- Rest),
- wrap_extensionAdditionGroups(Rest2,ExtGroupPosLenRest,
- [#'ComponentType'{
- name=list_to_atom("ExtAddGroup"++
- integer_to_list(ExtGroupNum+1)),
- typespec=#type{def=#'SEQUENCE'{
- extaddgroup=ExtGroupNum+1,
- components=ExtGroupCompList}},
- textual_order = ActualPos,
- prop='OPTIONAL'}|Acc],length(ExtGroupCompList)-1,
- ExtGroupNum+1);
-wrap_extensionAdditionGroups([H=#'ComponentType'{textual_order=Tord}|T],
- ExtAddGrpLenPos,Acc,ExtAddGroupDiff,ExtGroupNum) when is_integer(Tord) ->
- wrap_extensionAdditionGroups(T,ExtAddGrpLenPos,[H#'ComponentType'{
- textual_order=Tord - ExtAddGroupDiff}|Acc],ExtAddGroupDiff,ExtGroupNum);
-wrap_extensionAdditionGroups([H|T],ExtAddGrpLenPos,Acc,ExtAddGroupDiff,ExtGroupNum) ->
- wrap_extensionAdditionGroups(T,ExtAddGrpLenPos,[H|Acc],ExtAddGroupDiff,ExtGroupNum);
-wrap_extensionAdditionGroups([],_,Acc,_,_) ->
- lists:reverse(Acc).
-
-value_match(Index,Value) when is_atom(Value) ->
- value_match(Index,atom_to_list(Value));
-value_match([],Value) ->
+ end, T0),
+ Name = list_to_atom(lists:concat(["ExtAddGroup",ExtGroupNum+1])),
+ Seq = #type{def=#'SEQUENCE'{extaddgroup=ExtGroupNum+1,
+ components=ExtGroupCompList}},
+ Comp = #'ComponentType'{name=Name,
+ typespec=Seq,
+ textual_order=ActualPos,
+ prop='OPTIONAL'},
+ [Comp|wrap_eags(T, Gs, length(ExtGroupCompList)-1, ExtGroupNum+1)];
+wrap_eags([#'ComponentType'{textual_order=Tord}=H|T],
+ ExtAddGrpLenPos, ExtAddGroupDiff, ExtGroupNum)
+ when is_integer(Tord) ->
+ Comp = H#'ComponentType'{textual_order=Tord - ExtAddGroupDiff},
+ [Comp|wrap_eags(T, ExtAddGrpLenPos, ExtAddGroupDiff, ExtGroupNum)];
+wrap_eags([H|T], ExtAddGrpLenPos, ExtAddGroupDiff, ExtGroupNum) ->
+ [H|wrap_eags(T, ExtAddGrpLenPos, ExtAddGroupDiff, ExtGroupNum)];
+wrap_eags([], _, _, _) ->
+ [].
+
+value_match(#gen{pack=record}, VIs, Value) ->
+ value_match_rec(VIs, Value);
+value_match(#gen{pack=map}, VIs, Value) ->
+ value_match_map(VIs, Value).
+
+value_match_rec([], Value) ->
+ Value;
+value_match_rec([{VI,_}|VIs], Value0) ->
+ Value = value_match_rec(VIs, Value0),
+ lists:concat(["element(",VI,", ",Value,")"]).
+
+value_match_map([], Value) ->
Value;
-value_match([{VI,_}|VIs],Value) ->
- value_match1(Value,VIs,lists:concat(["element(",VI,","]),1).
-value_match1(Value,[],Acc,Depth) ->
- Acc ++ Value ++ lists:concat(lists:duplicate(Depth,")"));
-value_match1(Value,[{VI,_}|VIs],Acc,Depth) ->
- value_match1(Value,VIs,Acc++lists:concat(["element(",VI,","]),Depth+1).
-
-enc_dig_out_value([], Value) ->
+value_match_map([{_,Name}|VIs], Value0) ->
+ Value = value_match_map(VIs, Value0),
+ lists:concat(["maps:get(",Name,", ",Value,")"]).
+
+enc_dig_out_value(_Gen, [], Value) ->
{[],Value};
-enc_dig_out_value([{N,_}|T], Value) ->
- {Imm0,Dst0} = enc_dig_out_value(T, Value),
+enc_dig_out_value(#gen{pack=record}=Gen, [{N,_}|T], Value) ->
+ {Imm0,Dst0} = enc_dig_out_value(Gen, T, Value),
{Imm,Dst} = asn1ct_imm:enc_element(N, Dst0),
+ {Imm0++Imm,Dst};
+enc_dig_out_value(#gen{pack=map}, [{N,'ASN1_top'}], _Value) ->
+ {[],{var,lists:concat(["Input@",N-1])}};
+enc_dig_out_value(#gen{pack=map}=Gen, [{_,Name}|T], Value) ->
+ {Imm0,Dst0} = enc_dig_out_value(Gen, T, Value),
+ {Imm,Dst} = asn1ct_imm:enc_maps_get(Name, Dst0),
{Imm0++Imm,Dst}.
make_var(Base) ->
{var,atom_to_list(asn1ct_gen:mk_var(asn1ct_name:curr(Base)))}.
+
+attribute_comment(InnerType, TextPos, Cname) ->
+ DispType = case InnerType of
+ #'Externaltypereference'{type=T} -> T;
+ IT when is_tuple(IT) -> element(2,IT);
+ _ -> InnerType
+ end,
+ Comment = ["attribute ",Cname,"(",TextPos,") with type ",DispType],
+ lists:concat(Comment).
+
+dec_func(Tname) ->
+ list_to_atom(lists:concat(["dec_",Tname])).
diff --git a/lib/asn1/src/asn1ct_eval_ext.funcs b/lib/asn1/src/asn1ct_eval_ext.funcs
index 5761901f89..01c67e7b5a 100644
--- a/lib/asn1/src/asn1ct_eval_ext.funcs
+++ b/lib/asn1/src/asn1ct_eval_ext.funcs
@@ -1 +1,2 @@
{ext,transform_to_EXTERNAL1994,1}.
+{ext,transform_to_EXTERNAL1994_maps,1}.
diff --git a/lib/asn1/src/asn1ct_func.erl b/lib/asn1/src/asn1ct_func.erl
index 0cd72acf9d..b2ce93c17f 100644
--- a/lib/asn1/src/asn1ct_func.erl
+++ b/lib/asn1/src/asn1ct_func.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -65,7 +65,7 @@ generate(Fd) ->
Funcs = sofs:to_external(Funcs0),
ok = file:write(Fd, Funcs).
-is_used({_,_,_}=MFA) ->
+is_used({M,F,A}=MFA) when is_atom(M), is_atom(F), is_integer(A) ->
req({is_used,MFA}).
diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl
index bfaffa13bf..da9f6ac559 100644
--- a/lib/asn1/src/asn1ct_gen.erl
+++ b/lib/asn1/src/asn1ct_gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,8 +22,7 @@
-include("asn1_records.hrl").
--export([demit/1,
- emit/1,
+-export([emit/1,
open_output_file/1,close_output_file/0,
get_inner/1,type/1,def_to_tag/1,prim_bif/1,
list2name/1,
@@ -34,10 +33,10 @@
insert_once/2,
ct_gen_module/1,
index2suffix/1,
- get_record_name_prefix/0,
+ get_record_name_prefix/1,
conform_value/2,
named_bitstring_value/2]).
--export([pgen/5,
+-export([pgen/3,
mk_var/1,
un_hyphen_var/1]).
-export([gen_encode_constructed/4,
@@ -45,23 +44,19 @@
-define(SUPPRESSION_FUNC, 'dialyzer-suppressions').
+
%% pgen(Outfile, Erules, Module, TypeOrVal, Options)
-%% Generate Erlang module (.erl) and (.hrl) file corresponding to an ASN.1 module
-%% .hrl file is only generated if necessary
-%% Erules = per | ber
-%% Module = atom()
-%% TypeOrVal = {TypeList,ValueList}
-%% TypeList = ValueList = [atom()]
-%% Options = [Options] from asn1ct:compile()
-
-pgen(OutFile,Erules,Module,TypeOrVal,Options) ->
- pgen_module(OutFile,Erules,Module,TypeOrVal,Options,true).
-
-
-pgen_module(OutFile,Erules,Module,
- TypeOrVal = {Types,_Values,_Ptypes,_Classes,_Objects,_ObjectSets},
- Options,Indent) ->
- N2nConvEnums = [CName|| {n2n,CName} <- get(encoding_options)],
+%% Generate Erlang module (.erl) and (.hrl) file corresponding to
+%% an ASN.1 module. The .hrl file is only generated if necessary.
+
+-spec pgen(Outfile, Gen, Code) -> 'ok' when
+ Outfile :: any(),
+ Gen :: #gen{},
+ Code :: #abst{}.
+
+pgen(OutFile, #gen{options=Options}=Gen, Code) ->
+ #abst{name=Module,types=Types} = Code,
+ N2nConvEnums = [CName|| {n2n,CName} <- Options],
case N2nConvEnums -- Types of
[] ->
ok;
@@ -69,30 +64,30 @@ pgen_module(OutFile,Erules,Module,
exit({"Non existing ENUMERATION types used in n2n option",
UnmatchedTypes})
end,
- put(outfile,OutFile),
- HrlGenerated = pgen_hrl(Erules,Module,TypeOrVal,Options,Indent),
+ put(outfile, OutFile),
+ put(currmod, Module),
+ HrlGenerated = pgen_hrl(Gen, Code),
asn1ct_name:start(),
ErlFile = lists:concat([OutFile,".erl"]),
_ = open_output_file(ErlFile),
asn1ct_func:start_link(),
- gen_head(Erules,Module,HrlGenerated),
- pgen_exports(Erules,Module,TypeOrVal),
- pgen_dispatcher(Erules,Module,TypeOrVal),
+ gen_head(Gen, Module, HrlGenerated),
+ pgen_exports(Gen, Code),
+ pgen_dispatcher(Gen, Types),
pgen_info(),
- pgen_typeorval(Erules,Module,N2nConvEnums,TypeOrVal),
- pgen_partial_incomplete_decode(Erules),
-% gen_vars(asn1_db:mod_to_vars(Module)),
-% gen_tag_table(AllTypes),
+ pgen_typeorval(Gen, N2nConvEnums, Code),
+ pgen_partial_incomplete_decode(Gen),
emit([nl,
"%%%",nl,
"%%% Run-time functions.",nl,
"%%%",nl]),
- dialyzer_suppressions(Erules),
+ dialyzer_suppressions(Gen),
Fd = get(gen_file_out),
asn1ct_func:generate(Fd),
close_output_file(),
_ = erase(outfile),
- asn1ct:verbose("--~p--~n",[{generated,ErlFile}],Options).
+ asn1ct:verbose("--~p--~n", [{generated,ErlFile}], Gen),
+ ok.
dialyzer_suppressions(Erules) ->
emit([nl,
@@ -100,20 +95,27 @@ dialyzer_suppressions(Erules) ->
Rtmod = ct_gen_module(Erules),
Rtmod:dialyzer_suppressions(Erules).
-pgen_typeorval(Erules,Module,N2nConvEnums,{Types,Values,_Ptypes,_Classes,Objects,ObjectSets}) ->
+pgen_typeorval(Erules, N2nConvEnums, Code) ->
+ #abst{name=Module,types=Types,values=Values,
+ objects=Objects,objsets=ObjectSets} = Code,
Rtmod = ct_gen_module(Erules),
pgen_types(Rtmod,Erules,N2nConvEnums,Module,Types),
- pgen_values(Erules,Module,Values),
+ pgen_values(Values, Module),
pgen_objects(Rtmod,Erules,Module,Objects),
pgen_objectsets(Rtmod,Erules,Module,ObjectSets),
pgen_partial_decode(Rtmod,Erules,Module).
-pgen_values(_,_,[]) ->
- true;
-pgen_values(Erules,Module,[H|T]) ->
- Valuedef = asn1_db:dbget(Module,H),
- gen_value(Valuedef),
- pgen_values(Erules,Module,T).
+%% Generate a function 'V'/0 for each Value V defined in the ASN.1 module.
+%% The function returns the value in an Erlang representation which can be
+%% used as input to the runtime encode functions.
+
+pgen_values([H|T], Module) ->
+ #valuedef{name=Name,value=Value} = asn1_db:dbget(Module, H),
+ emit([{asis,Name},"() ->",nl,
+ {asis,Value},".",nl,nl]),
+ pgen_values(T, Module);
+pgen_values([], _) ->
+ ok.
pgen_types(_, _, _, _, []) ->
true;
@@ -143,27 +145,37 @@ pgen_n2nconversion(_Erules,#typedef{name=TypeName,typespec=#type{def={'ENUMERATE
pgen_n2nconversion(_Erules,_) ->
true.
-pgen_name2numfunc(_TypeName,[], _) ->
+pgen_name2numfunc(TypeNameAsAtom,Mapping,Ext) when is_atom(TypeNameAsAtom) ->
+ FuncName = list_to_atom("name2num_"++atom_to_list(TypeNameAsAtom)),
+ pgen_name2numfunc1(FuncName,Mapping,Ext).
+
+pgen_name2numfunc1(_FuncName,[], _) ->
true;
-pgen_name2numfunc(TypeName,[{Atom,Number}], extension_marker) ->
- emit(["name2num_",TypeName,"(",{asis,Atom},") ->",Number,";",nl]),
- emit(["name2num_",TypeName,"({asn1_enum, Num}) -> Num.",nl,nl]);
-pgen_name2numfunc(TypeName,[{Atom,Number}], _) ->
- emit(["name2num_",TypeName,"(",{asis,Atom},") ->",Number,".",nl,nl]);
-pgen_name2numfunc(TypeName,[{Atom,Number}|NNRest], EM) ->
- emit(["name2num_",TypeName,"(",{asis,Atom},") ->",Number,";",nl]),
- pgen_name2numfunc(TypeName,NNRest, EM).
-
-pgen_num2namefunc(_TypeName,[], _) ->
+pgen_name2numfunc1(FuncName,[{Atom,Number}], extension_marker) ->
+ emit([{asis,FuncName},"(",{asis,Atom},") ->",Number,";",nl]),
+ emit([{asis,FuncName},"({asn1_enum, Num}) -> Num.",nl,nl]);
+pgen_name2numfunc1(FuncName,[{Atom,Number}], _) ->
+ emit([{asis,FuncName},"(",{asis,Atom},") ->",Number,".",nl,nl]);
+pgen_name2numfunc1(FuncName,[{Atom,Number}|NNRest], EM) ->
+ emit([{asis,FuncName},"(",{asis,Atom},") ->",Number,";",nl]),
+ pgen_name2numfunc1(FuncName,NNRest, EM).
+
+pgen_num2namefunc(TypeNameAsAtom,Mapping,Ext) when is_atom(TypeNameAsAtom) ->
+ FuncName = list_to_atom("num2name_"++atom_to_list(TypeNameAsAtom)),
+ pgen_num2namefunc1(FuncName,Mapping,Ext).
+
+pgen_num2namefunc1(_FuncName,[], _) ->
true;
-pgen_num2namefunc(TypeName,[{Atom,Number}], extension_marker) ->
- emit(["num2name_",TypeName,"(",Number,") ->",{asis,Atom},";",nl]),
- emit(["num2name_",TypeName,"(ExtensionNum) -> {asn1_enum, ExtensionNum}.",nl,nl]);
-pgen_num2namefunc(TypeName,[{Atom,Number}], _) ->
- emit(["num2name_",TypeName,"(",Number,") ->",{asis,Atom},".",nl,nl]);
-pgen_num2namefunc(TypeName,[{Atom,Number}|NNRest], EM) ->
- emit(["num2name_",TypeName,"(",Number,") ->",{asis,Atom},";",nl]),
- pgen_num2namefunc(TypeName,NNRest, EM).
+pgen_num2namefunc1(FuncName,[{Atom,Number}], extension_marker) ->
+ emit([{asis,FuncName},"(",Number,") ->",{asis,Atom},";",nl]),
+ emit([{asis,FuncName},"(ExtensionNum) -> {asn1_enum, ExtensionNum}.",nl,nl]);
+pgen_num2namefunc1(FuncName,[{Atom,Number}], _) ->
+ emit([{asis,FuncName},"(",Number,") ->",{asis,Atom},".",nl,nl]);
+pgen_num2namefunc1(FuncName,[{Atom,Number}|NNRest], EM) ->
+ emit([{asis,FuncName},"(",Number,") ->",{asis,Atom},";",nl]),
+ pgen_num2namefunc1(FuncName,NNRest, EM).
+
+
pgen_objects(_,_,_,[]) ->
true;
@@ -181,20 +193,16 @@ pgen_objectsets(Rtmod,Erules,Module,[H|T]) ->
Rtmod:gen_objectset_code(Erules,TypeDef),
pgen_objectsets(Rtmod,Erules,Module,T).
-pgen_partial_decode(Rtmod,Erule,Module) when Erule == ber ->
- pgen_partial_inc_dec(Rtmod,Erule,Module),
- pgen_partial_dec(Rtmod,Erule,Module);
-pgen_partial_decode(_,_,_) ->
+pgen_partial_decode(Rtmod, #gen{erule=ber}=Gen, Module) ->
+ pgen_partial_inc_dec(Rtmod, Gen, Module),
+ pgen_partial_dec(Rtmod, Gen, Module);
+pgen_partial_decode(_, _, _) ->
ok.
pgen_partial_inc_dec(Rtmod,Erules,Module) ->
-% io:format("Start partial incomplete decode gen?~n"),
case asn1ct:get_gen_state_field(inc_type_pattern) of
undefined ->
-% io:format("Partial incomplete decode gen not started: ~w~n",[asn1ct:get_gen_state_field(active)]),
ok;
-% [] ->
-% ok;
ConfList ->
PatternLists=lists:map(fun({_,P}) -> P end,ConfList),
pgen_partial_inc_dec1(Rtmod,Erules,Module,PatternLists),
@@ -212,11 +220,9 @@ pgen_partial_inc_dec1(Rtmod,Erules,Module,[P|Ps]) ->
asn1ct:update_gen_state(prefix,"dec-inc-"),
case asn1ct:maybe_saved_sindex(TopTypeName,P) of
I when is_integer(I),I > 0 ->
-% io:format("Index:~p~n",[I]),
asn1ct:set_current_sindex(I);
_I ->
asn1ct:set_current_sindex(0),
-% io:format("Index=~p~n",[_I]),
ok
end,
Rtmod:gen_decode(Erules,TypeDef),
@@ -225,7 +231,7 @@ pgen_partial_inc_dec1(Rtmod,Erules,Module,[P|Ps]) ->
pgen_partial_inc_dec1(_,_,_,[]) ->
ok.
-gen_partial_inc_dec_refed_funcs(Rtmod,Erule) when Erule == ber ->
+gen_partial_inc_dec_refed_funcs(Rtmod, #gen{erule=ber}=Gen) ->
case asn1ct:next_refed_func() of
[] ->
ok;
@@ -233,39 +239,36 @@ gen_partial_inc_dec_refed_funcs(Rtmod,Erule) when Erule == ber ->
TypeDef = asn1_db:dbget(M,Name),
asn1ct:update_gen_state(namelist,Pattern),
asn1ct:set_current_sindex(Sindex),
- Rtmod:gen_inc_decode(Erule,TypeDef),
- gen_dec_part_inner_constr(Rtmod,Erule,TypeDef,[Name]),
- gen_partial_inc_dec_refed_funcs(Rtmod,Erule);
+ Rtmod:gen_inc_decode(Gen, TypeDef),
+ gen_dec_part_inner_constr(Rtmod, Gen, TypeDef, [Name]),
+ gen_partial_inc_dec_refed_funcs(Rtmod, Gen);
{Name,Sindex,Pattern,Type} ->
TypeDef=#typedef{name=asn1ct_gen:list2name(Name),typespec=Type},
asn1ct:update_gen_state(namelist,Pattern),
asn1ct:set_current_sindex(Sindex),
- Rtmod:gen_inc_decode(Erule,TypeDef),
- gen_dec_part_inner_constr(Rtmod,Erule,TypeDef,Name),
- gen_partial_inc_dec_refed_funcs(Rtmod,Erule)
- end;
-gen_partial_inc_dec_refed_funcs(_,_) ->
- ok.
+ Rtmod:gen_inc_decode(Gen, TypeDef),
+ gen_dec_part_inner_constr(Rtmod, Gen, TypeDef, Name),
+ gen_partial_inc_dec_refed_funcs(Rtmod, Gen)
+ end.
pgen_partial_dec(_Rtmod,Erules,_Module) ->
Type_pattern = asn1ct:get_gen_state_field(type_pattern),
-% io:format("Type_pattern: ~w~n",[Type_pattern]),
- %% Get the typedef of the top type and follow into the choosen components until the last type/component.
+ %% Get the typedef of the top type and follow into the choosen
+ %% components until the last type/component.
pgen_partial_types(Erules,Type_pattern),
ok.
-pgen_partial_types(Erules,Type_pattern) ->
- % until this functionality works on all back-ends
- Options = get(encoding_options),
- case lists:member(asn1config,Options) of
+pgen_partial_types(#gen{options=Options}=Gen, TypePattern) ->
+ %% until this functionality works on all back-ends
+ case lists:member(asn1config, Options) of
true ->
- pgen_partial_types1(Erules,Type_pattern);
- _ -> ok
+ pgen_partial_types1(Gen, TypePattern);
+ false ->
+ ok
end.
-
+
pgen_partial_types1(Erules,[{FuncName,[TopType|RestTypes]}|Rest]) ->
-% emit([FuncName,"(Bytes) ->",nl]),
CurrMod = get(currmod),
TypeDef = asn1_db:dbget(CurrMod,TopType),
traverse_type_structure(Erules,TypeDef,RestTypes,FuncName,
@@ -290,8 +293,9 @@ traverse_type_structure(Erules,Type,[],FuncName,TopTypeName) ->
end,
Ctmod:gen_decode_selected(Erules,TypeDef,FuncName); % what if Type is #type{}
traverse_type_structure(Erules,#type{def=Def},[[N]],FuncName,TopTypeName)
- when is_integer(N) -> % this case a decode of one of the elements in
- % the SEQUENCE OF is required.
+ when is_integer(N) ->
+ %% In this case a decode of one of the elements in the SEQUENCE OF is
+ %% required.
InnerType = asn1ct_gen:get_inner(Def),
case InnerType of
'SEQUENCE OF' ->
@@ -367,8 +371,9 @@ traverse_type_structure(Erules,#typedef{typespec=Def},[T|Ts],FuncName,
TypeDef = asn1_db:dbget(M,TName),
traverse_type_structure(Erules,TypeDef,[T|Ts],FuncName,
[TypeDef#typedef.name]);
- _ -> %this may be a referenced type that shall be traversed or
- %the selected type
+ _ ->
+ %% This may be a referenced type that shall be traversed
+ %% or the selected type
traverse_type_structure(Erules,Def,Ts,FuncName,[T|TopTypeName])
end.
@@ -383,9 +388,7 @@ get_component(Name,{C1,C2}) when is_list(C1),is_list(C2) ->
get_component(Name,[C=#'ComponentType'{name=Name}|_Cs]) ->
C;
get_component(Name,[_C|Cs]) ->
- get_component(Name,Cs);
-get_component(Name,_) ->
- throw({error,{asn1,{internal_error,Name}}}).
+ get_component(Name,Cs).
%% generate code for all inner types that are called from the top type
%% of the partial incomplete decode and are defined within the top
@@ -441,7 +444,8 @@ pgen_partial_incomplete_decode(Erule) ->
_ ->
ok
end.
-pgen_partial_incomplete_decode1(ber) ->
+
+pgen_partial_incomplete_decode1(#gen{erule=ber}) ->
case asn1ct:read_config_data(partial_incomplete_decode) of
undefined ->
ok;
@@ -449,9 +453,8 @@ pgen_partial_incomplete_decode1(ber) ->
lists:foreach(fun emit_partial_incomplete_decode/1,Data)
end,
GeneratedFs= asn1ct:get_gen_state_field(gen_refed_funcs),
-% io:format("GeneratedFs :~n~p~n",[GeneratedFs]),
gen_part_decode_funcs(GeneratedFs,0);
-pgen_partial_incomplete_decode1(_) -> ok.
+pgen_partial_incomplete_decode1(#gen{}) -> ok.
emit_partial_incomplete_decode({FuncName,TopType,Pattern}) ->
TypePattern = asn1ct:get_gen_state_field(inc_type_pattern),
@@ -578,18 +581,6 @@ un_hyphen_var([H|T]) ->
un_hyphen_var([]) ->
[].
-%% Generate value functions ***************
-%% ****************************************
-%% Generates a function 'V'/0 for each Value V defined in the ASN.1 module
-%% the function returns the value in an Erlang representation which can be
-%% used as input to the runtime encode functions
-
-gen_value(Value) when is_record(Value,valuedef) ->
-%% io:format(" ~w ",[Value#valuedef.name]),
- emit({"'",Value#valuedef.name,"'() ->",nl}),
- V = Value#valuedef.value,
- emit([{asis,V},".",nl,nl]).
-
gen_encode_constructed(Erules,Typename,InnerType,D) when is_record(D,type) ->
Rtmod = ct_constructed_module(Erules),
case InnerType of
@@ -614,9 +605,7 @@ gen_encode_constructed(Erules,Typename,InnerType,D) when is_record(D,type) ->
Rtmod:gen_encode_sof(Erules,Typename,InnerType,D),
{_,Type} = D#type.def,
NameSuffix = asn1ct_gen:constructed_suffix(InnerType,Type#type.def),
- gen_types(Erules, [NameSuffix|Typename], Type, gen_encode);
- _ ->
- exit({nyi,InnerType})
+ gen_types(Erules, [NameSuffix|Typename], Type, gen_encode)
end;
gen_encode_constructed(Erules,Typename,InnerType,D)
when is_record(D,typedef) ->
@@ -654,78 +643,32 @@ gen_decode_constructed(Erules,Typename,InnerType,D) when is_record(D,typedef) ->
gen_decode_constructed(Erules,Typename,InnerType,D#typedef.typespec).
-pgen_exports(Erules,_Module,{Types,Values,_,_,Objects,ObjectSets}) ->
- emit(["-export([encoding_rule/0,bit_string_format/0,",nl,
+pgen_exports(#gen{options=Options}=Gen, Code) ->
+ #abst{types=Types,values=Values,objects=Objects,objsets=ObjectSets} = Code,
+ emit(["-export([encoding_rule/0,maps/0,bit_string_format/0,",nl,
" legacy_erlang_types/0]).",nl]),
emit(["-export([",{asis,?SUPPRESSION_FUNC},"/1]).",nl]),
- case Types of
- [] -> ok;
- _ ->
- emit({"-export([",nl}),
- case Erules of
- ber ->
- gen_exports1(Types,"enc_",2);
- _ ->
- gen_exports1(Types,"enc_",1)
- end,
- emit({"-export([",nl}),
- case Erules of
- ber ->
- gen_exports1(Types, "dec_", 2);
- _ ->
- gen_exports1(Types, "dec_", 1)
- end
- end,
- case [X || {n2n,X} <- get(encoding_options)] of
- [] -> ok;
- A2nNames ->
- emit({"-export([",nl}),
- gen_exports1(A2nNames,"name2num_",1),
- emit({"-export([",nl}),
- gen_exports1(A2nNames,"num2name_",1)
- end,
- case Values of
- [] -> ok;
- _ ->
- emit({"-export([",nl}),
- gen_exports1(Values,"",0)
- end,
- case Objects of
- [] -> ok;
- _ ->
- case erule(Erules) of
- per ->
- ok;
- ber ->
- emit({"-export([",nl}),
- gen_exports1(Objects,"enc_",3),
- emit({"-export([",nl}),
- gen_exports1(Objects,"dec_",3)
- end
- end,
- case ObjectSets of
- [] -> ok;
- _ ->
- case erule(Erules) of
- per ->
- ok;
- ber ->
- emit({"-export([",nl}),
- gen_exports1(ObjectSets, "getenc_",1),
- emit({"-export([",nl}),
- gen_exports1(ObjectSets, "getdec_",1)
- end
+ case Gen of
+ #gen{erule=ber} ->
+ gen_exports(Types, "enc_", 2),
+ gen_exports(Types, "dec_", 2),
+ gen_exports(Objects, "enc_", 3),
+ gen_exports(Objects, "dec_", 3),
+ gen_exports(ObjectSets, "getenc_", 1),
+ gen_exports(ObjectSets, "getdec_", 1);
+ #gen{erule=per} ->
+ gen_exports(Types, "enc_", 1),
+ gen_exports(Types, "dec_", 1)
end,
- emit({"-export([info/0]).",nl}),
- gen_partial_inc_decode_exports(),
- gen_selected_decode_exports(),
- emit({nl,nl}).
-gen_exports1([F1,F2|T],Prefix,Arity) ->
- emit({"'",Prefix,F1,"'/",Arity,com,nl}),
- gen_exports1([F2|T],Prefix,Arity);
-gen_exports1([Flast|_T],Prefix,Arity) ->
- emit({"'",Prefix,Flast,"'/",Arity,nl,"]).",nl,nl}).
+ A2nNames = [X || {n2n,X} <- Options],
+ gen_exports(A2nNames, "name2num_", 1),
+ gen_exports(A2nNames, "num2name_", 1),
+
+ gen_exports(Values, "", 0),
+ emit(["-export([info/0]).",nl,nl]),
+ gen_partial_inc_decode_exports(),
+ gen_selected_decode_exports().
gen_partial_inc_decode_exports() ->
case {asn1ct:read_config_data(partial_incomplete_decode),
@@ -734,66 +677,56 @@ gen_partial_inc_decode_exports() ->
ok;
{_,undefined} ->
ok;
- {Data,_} ->
- gen_partial_inc_decode_exports(Data),
- emit(["-export([decode_part/2]).",nl])
+ {Data0,_} ->
+ Data = [Name || {Name,_,_} <- Data0],
+ gen_exports(Data, "", 1),
+ emit(["-export([decode_part/2]).",nl,nl])
end.
-gen_partial_inc_decode_exports([]) ->
- ok;
-gen_partial_inc_decode_exports([{Name,_,_}|Rest]) ->
- emit(["-export([",Name,"/1"]),
- gen_partial_inc_decode_exports1(Rest);
-gen_partial_inc_decode_exports([_|Rest]) ->
- gen_partial_inc_decode_exports(Rest).
-
-gen_partial_inc_decode_exports1([]) ->
- emit(["]).",nl]);
-gen_partial_inc_decode_exports1([{Name,_,_}|Rest]) ->
- emit([", ",Name,"/1"]),
- gen_partial_inc_decode_exports1(Rest);
-gen_partial_inc_decode_exports1([_|Rest]) ->
- gen_partial_inc_decode_exports1(Rest).
gen_selected_decode_exports() ->
case asn1ct:get_gen_state_field(type_pattern) of
undefined ->
ok;
- L ->
- gen_selected_decode_exports(L)
+ Data0 ->
+ Data = [Name || {Name,_} <- Data0],
+ gen_exports(Data, "", 1)
end.
-gen_selected_decode_exports([]) ->
+gen_exports([], _Prefix, _Arity) ->
ok;
-gen_selected_decode_exports([{FuncName,_}|Rest]) ->
- emit(["-export([",FuncName,"/1"]),
- gen_selected_decode_exports1(Rest).
-gen_selected_decode_exports1([]) ->
- emit(["]).",nl,nl]);
-gen_selected_decode_exports1([{FuncName,_}|Rest]) ->
- emit([",",nl," ",FuncName,"/1"]),
- gen_selected_decode_exports1(Rest).
-
-pgen_dispatcher(Erules,_Module,{[],_Values,_,_,_Objects,_ObjectSets}) ->
+gen_exports([_|_]=L0, Prefix, Arity) ->
+ FF = fun(F0) ->
+ F = list_to_atom(lists:concat([Prefix,F0])),
+ [{asis,F},"/",Arity]
+ end,
+ L = lists:join(",\n", [FF(F) || F <- L0]),
+ emit(["-export([",nl,
+ L,nl,
+ "]).",nl,nl]).
+
+pgen_dispatcher(Erules, []) ->
gen_info_functions(Erules);
-pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
+pgen_dispatcher(Gen, Types) ->
+ %% MODULE HEAD
emit(["-export([encode/2,decode/2]).",nl,nl]),
- gen_info_functions(Erules),
+ gen_info_functions(Gen),
- Options = get(encoding_options),
+ Options = Gen#gen.options,
NoFinalPadding = lists:member(no_final_padding, Options),
NoOkWrapper = proplists:get_bool(no_ok_wrapper, Options),
- Call = case Erules of
- per ->
- asn1ct_func:need({Erules,complete,1}),
+ %% ENCODER
+ Call = case Gen of
+ #gen{erule=per,aligned=true} ->
+ asn1ct_func:need({per,complete,1}),
"complete(encode_disp(Type, Data))";
- ber ->
+ #gen{erule=ber} ->
"iolist_to_binary(element(1, encode_disp(Type, Data)))";
- uper when NoFinalPadding == true ->
- asn1ct_func:need({Erules,complete_NFP,1}),
+ #gen{erule=per,aligned=false} when NoFinalPadding ->
+ asn1ct_func:need({uper,complete_NFP,1}),
"complete_NFP(encode_disp(Type, Data))";
- uper ->
- asn1ct_func:need({Erules,complete,1}),
+ #gen{erule=per,aligned=false} ->
+ asn1ct_func:need({uper,complete,1}),
"complete(encode_disp(Type, Data))"
end,
@@ -809,61 +742,67 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
end,
emit([nl,nl]),
- Return_rest = proplists:get_bool(undec_rest, Options),
- Data = case {Erules,Return_rest} of
- {ber,true} -> "Data0";
- _ -> "Data"
+ %% DECODER
+ ReturnRest = proplists:get_bool(undec_rest, Gen#gen.options),
+ Data = case Gen#gen.erule =:= ber andalso ReturnRest of
+ true -> "Data0";
+ false -> "Data"
end,
- emit(["decode(Type,",Data,") ->",nl]),
+ emit(["decode(Type, ",Data,") ->",nl]),
+
+ case NoOkWrapper of
+ false -> emit(["try",nl]);
+ true -> ok
+ end,
+
DecWrap =
- case {Erules,Return_rest} of
- {ber,false} ->
+ case {Gen,ReturnRest} of
+ {#gen{erule=ber},false} ->
asn1ct_func:need({ber,ber_decode_nif,1}),
"element(1, ber_decode_nif(Data))";
- {ber,true} ->
+ {#gen{erule=ber},true} ->
asn1ct_func:need({ber,ber_decode_nif,1}),
- emit(["{Data,Rest} = ber_decode_nif(Data0),",nl]),
+ emit([" {Data,Rest} = ber_decode_nif(Data0),",nl]),
"Data";
- _ ->
+ {_,_} ->
"Data"
end,
- emit([case NoOkWrapper of
- false -> "try";
- true -> "case"
- end, " decode_disp(Type, ",DecWrap,") of",nl]),
- case erule(Erules) of
- ber ->
- emit([" Result ->",nl]);
- per ->
- emit([" {Result,Rest} ->",nl])
- end,
- case Return_rest of
- false -> result_line(NoOkWrapper, ["Result"]);
- true -> result_line(NoOkWrapper, ["Result","Rest"])
+
+ DecodeDisp = ["decode_disp(Type, ",DecWrap,")"],
+ case {Gen,ReturnRest} of
+ {#gen{erule=ber},true} ->
+ emit([" Result = ",DecodeDisp,",",nl]),
+ result_line(NoOkWrapper, ["Result","Rest"]);
+ {#gen{erule=ber},false} ->
+ emit([" Result = ",DecodeDisp,",",nl]),
+ result_line(NoOkWrapper, ["Result"]);
+
+
+ {#gen{erule=per},true} ->
+ emit([" {Result,Rest} = ",DecodeDisp,",",nl]),
+ result_line(NoOkWrapper, ["Result","Rest"]);
+ {#gen{erule=per},false} ->
+ emit([" {Result,_Rest} = ",DecodeDisp,",",nl]),
+ result_line(NoOkWrapper, ["Result"])
end,
+
case NoOkWrapper of
false ->
emit([nl,try_catch(),nl,nl]);
true ->
- emit([nl,"end.",nl,nl])
+ emit([".",nl,nl])
end,
- gen_decode_partial_incomplete(Erules),
+ %% REST of MODULE
+ gen_decode_partial_incomplete(Gen),
+ gen_partial_inc_dispatcher(Gen),
- case Erules of
- ber ->
- gen_dispatcher(Types,"encode_disp","enc_",""),
- gen_dispatcher(Types,"decode_disp","dec_",""),
- gen_partial_inc_dispatcher();
- _PerOrPer_bin ->
- gen_dispatcher(Types,"encode_disp","enc_",""),
- gen_dispatcher(Types,"decode_disp","dec_","")
- end,
- emit([nl,nl]).
+ gen_dispatcher(Types, "encode_disp", "enc_"),
+ gen_dispatcher(Types, "decode_disp", "dec_").
result_line(NoOkWrapper, Items) ->
- S = [" "|case NoOkWrapper of
+ S = [" "|case NoOkWrapper of
false -> result_line_1(["ok"|Items]);
true -> result_line_1(Items)
end],
@@ -877,23 +816,35 @@ result_line_1(Items) ->
try_catch() ->
[" catch",nl,
" Class:Exception when Class =:= error; Class =:= exit ->",nl,
+ " Stk = erlang:get_stacktrace(),",nl,
" case Exception of",nl,
- " {error,Reason}=Error ->",nl,
- " Error;",nl,
+ " {error,{asn1,Reason}} ->",nl,
+ " {error,{asn1,{Reason,Stk}}};",nl,
" Reason ->",nl,
- " {error,{asn1,Reason}}",nl,
+ " {error,{asn1,{Reason,Stk}}}",nl,
" end",nl,
"end."].
-gen_info_functions(Erules) ->
+gen_info_functions(Gen) ->
+ Erule = case Gen of
+ #gen{erule=ber} -> ber;
+ #gen{erule=per,aligned=false} -> uper;
+ #gen{erule=per,aligned=true} -> per
+ end,
+ Maps = case Gen of
+ #gen{pack=record} -> false;
+ #gen{pack=map} -> true
+ end,
emit(["encoding_rule() -> ",
- {asis,Erules},".",nl,nl,
+ {asis,Erule},".",nl,nl,
+ "maps() -> ",
+ {asis,Maps},".",nl,nl,
"bit_string_format() -> ",
{asis,asn1ct:get_bit_string_format()},".",nl,nl,
"legacy_erlang_types() -> ",
{asis,asn1ct:use_legacy_types()},".",nl,nl]).
-gen_decode_partial_incomplete(ber) ->
+gen_decode_partial_incomplete(#gen{erule=ber}) ->
case {asn1ct:read_config_data(partial_incomplete_decode),
asn1ct:get_gen_state_field(inc_type_pattern)} of
{undefined,_} ->
@@ -931,10 +882,10 @@ gen_decode_partial_incomplete(ber) ->
EmitCaseClauses(),
emit([".",nl,nl])
end;
-gen_decode_partial_incomplete(_Erule) ->
+gen_decode_partial_incomplete(#gen{}) ->
ok.
-gen_partial_inc_dispatcher() ->
+gen_partial_inc_dispatcher(#gen{erule=ber}) ->
case {asn1ct:read_config_data(partial_incomplete_decode),
asn1ct:get_gen_state_field(inc_type_pattern)} of
{undefined,_} ->
@@ -942,9 +893,10 @@ gen_partial_inc_dispatcher() ->
{_,undefined} ->
ok;
{Data1,Data2} ->
-% io:format("partial_incomplete_decode: ~p~ninc_type_pattern: ~p~n",[Data,Data2]),
gen_partial_inc_dispatcher(Data1, Data2, "")
- end.
+ end;
+gen_partial_inc_dispatcher(#gen{}) ->
+ ok.
gen_partial_inc_dispatcher([{FuncName,TopType,_Pattern}|Rest], TypePattern, Sep) ->
TPattern =
@@ -968,12 +920,18 @@ gen_partial_inc_dispatcher([{FuncName,TopType,_Pattern}|Rest], TypePattern, Sep)
gen_partial_inc_dispatcher([], _, _) ->
emit([".",nl]).
-gen_dispatcher([F1,F2|T],FuncName,Prefix,ExtraArg) ->
- emit([FuncName,"('",F1,"',Data) -> '",Prefix,F1,"'(Data",ExtraArg,")",";",nl]),
- gen_dispatcher([F2|T],FuncName,Prefix,ExtraArg);
-gen_dispatcher([Flast|_T],FuncName,Prefix,ExtraArg) ->
- emit([FuncName,"('",Flast,"',Data) -> '",Prefix,Flast,"'(Data",ExtraArg,")",";",nl]),
- emit([FuncName,"(","Type",",_Data) -> exit({error,{asn1,{undefined_type,Type}}}).",nl,nl,nl]).
+gen_dispatcher(L, DispFunc, Prefix) ->
+ gen_dispatcher_1(L, DispFunc, Prefix),
+ emit([DispFunc,"(","Type",", _Data) ->"
+ " exit({error,{asn1,{undefined_type,Type}}}).",nl,nl]).
+
+gen_dispatcher_1([F|T], FuncName, Prefix) ->
+ Func = list_to_atom(lists:concat([Prefix,F])),
+ emit([FuncName,"(",{asis,F},", Data) -> ",
+ {asis,Func},"(Data)",";",nl]),
+ gen_dispatcher_1(T, FuncName, Prefix);
+gen_dispatcher_1([], _, _) ->
+ ok.
pgen_info() ->
emit(["info() ->",nl,
@@ -1009,71 +967,39 @@ hrl_protector(OutFile) ->
end || C <- P].
-%% EMIT functions ************************
-%% ***************************************
-
- % debug generation
-demit(Term) ->
- case get(asndebug) of
- true -> emit(Term);
- _ ->true
- end.
-
- % always generation
emit(Term) ->
ok = file:write(get(gen_file_out), do_emit(Term)).
-do_emit({external,_M,T}) ->
- do_emit(T);
-
do_emit({prev,Variable}) when is_atom(Variable) ->
do_emit({var,asn1ct_name:prev(Variable)});
-
do_emit({next,Variable}) when is_atom(Variable) ->
do_emit({var,asn1ct_name:next(Variable)});
-
do_emit({curr,Variable}) when is_atom(Variable) ->
do_emit({var,asn1ct_name:curr(Variable)});
-
do_emit({var,Variable}) when is_atom(Variable) ->
[Head|V] = atom_to_list(Variable),
[Head-32|V];
-
-do_emit({var,Variable}) ->
- [Head|V] = Variable,
- [Head-32|V];
-
do_emit({asis,What}) ->
io_lib:format("~w", [What]);
-
do_emit({call,M,F,A}) ->
MFA = {M,F,length(A)},
asn1ct_func:need(MFA),
[atom_to_list(F),"(",call_args(A, "")|")"];
-
do_emit(nl) ->
"\n";
-
do_emit(com) ->
",";
-
-do_emit(tab) ->
- " ";
-
+do_emit([C|_]=Str) when is_integer(C) ->
+ Str;
+do_emit([_|_]=L) ->
+ [do_emit(E) || E <- L];
+do_emit([]) ->
+ [];
do_emit(What) when is_integer(What) ->
integer_to_list(What);
-
-do_emit(What) when is_list(What), is_integer(hd(What)) ->
- What;
-
do_emit(What) when is_atom(What) ->
- atom_to_list(What);
-
-do_emit(What) when is_tuple(What) ->
- [do_emit(E) || E <- tuple_to_list(What)];
+ atom_to_list(What).
-do_emit(What) when is_list(What) ->
- [do_emit(E) || E <- What].
call_args([A|As], Sep) ->
[Sep,do_emit(A)|call_args(As, ", ")];
@@ -1092,22 +1018,21 @@ open_output_file(F) ->
close_output_file() ->
ok = file:close(erase(gen_file_out)).
-pgen_hrl(Erules,Module,TypeOrVal,Options,_Indent) ->
- put(currmod,Module),
- {Types,Values,Ptypes,_,_,_} = TypeOrVal,
+pgen_hrl(#gen{pack=record}=Gen, Code) ->
+ #abst{name=Module,types=Types,values=Values,ptypes=Ptypes} = Code,
Ret =
- case pgen_hrltypes(Erules,Module,Ptypes++Types,0) of
+ case pgen_hrltypes(Gen, Module, Ptypes++Types, 0) of
0 ->
case Values of
[] ->
0;
_ ->
- open_hrl(get(outfile),get(currmod)),
- pgen_macros(Erules,Module,Values),
+ open_hrl(get(outfile), Module),
+ pgen_macros(Gen, Module, Values),
1
end;
X ->
- pgen_macros(Erules,Module,Values),
+ pgen_macros(Gen, Module, Values),
X
end,
case Ret of
@@ -1119,70 +1044,67 @@ pgen_hrl(Erules,Module,TypeOrVal,Options,_Indent) ->
close_output_file(),
asn1ct:verbose("--~p--~n",
[{generated,lists:concat([get(outfile),".hrl"])}],
- Options),
+ Gen),
Y
- end.
+ end;
+pgen_hrl(#gen{pack=map}, _) ->
+ 0.
pgen_macros(_,_,[]) ->
true;
-pgen_macros(Erules,Module,[H|T]) ->
- Valuedef = asn1_db:dbget(Module,H),
- gen_macro(Valuedef),
- pgen_macros(Erules,Module,T).
+pgen_macros(Gen, Module, [H|T]) ->
+ Valuedef = asn1_db:dbget(Module, H),
+ gen_macro(Gen, Valuedef),
+ pgen_macros(Gen, Module, T).
pgen_hrltypes(_,_,[],NumRecords) ->
NumRecords;
-pgen_hrltypes(Erules,Module,[H|T],NumRecords) ->
-% io:format("records = ~p~n",NumRecords),
- Typedef = asn1_db:dbget(Module,H),
- AddNumRecords = gen_record(Typedef,NumRecords),
- pgen_hrltypes(Erules,Module,T,NumRecords+AddNumRecords).
+pgen_hrltypes(Gen, Module, [H|T], NumRecords) ->
+ Typedef = asn1_db:dbget(Module, H),
+ AddNumRecords = gen_record(Gen, Typedef, NumRecords),
+ pgen_hrltypes(Gen, Module, T, NumRecords+AddNumRecords).
%% Generates a macro for value Value defined in the ASN.1 module
-gen_macro(Value) when is_record(Value,valuedef) ->
- Prefix = get_macro_name_prefix(),
- emit({"-define('",Prefix,Value#valuedef.name,"', ",
- {asis,Value#valuedef.value},").",nl}).
+gen_macro(Gen, #valuedef{name=Name,value=Value}) ->
+ Prefix = get_macro_name_prefix(Gen),
+ emit(["-define('",Prefix,Name,"', ",{asis,Value},").",nl]).
%% Generate record functions **************
%% Generates an Erlang record for each named and unnamed SEQUENCE and SET in the ASN.1
%% module. If no SEQUENCE or SET is found there is no .hrl file generated
-gen_record(Tdef,NumRecords) when is_record(Tdef,typedef) ->
+gen_record(Gen, #typedef{}=Tdef, NumRecords) ->
Name = [Tdef#typedef.name],
Type = Tdef#typedef.typespec,
- gen_record(type,Name,Type,NumRecords);
-
-gen_record(Tdef,NumRecords) when is_record(Tdef,ptypedef) ->
+ gen_record(Gen, type, Name, Type, NumRecords);
+gen_record(Gen, #ptypedef{}=Tdef, NumRecords) ->
Name = [Tdef#ptypedef.name],
Type = Tdef#ptypedef.typespec,
- gen_record(ptype,Name,Type,NumRecords).
-
-gen_record(TorPtype,Name,[#'ComponentType'{name=Cname,typespec=Type}|T],Num) ->
- Num2 = gen_record(TorPtype,[Cname|Name],Type,Num),
- gen_record(TorPtype,Name,T,Num2);
-gen_record(TorPtype,Name,{Clist1,Clist2},Num)
+ gen_record(Gen, ptype, Name, Type, NumRecords).
+
+gen_record(Gen, TorPtype, Name,
+ [#'ComponentType'{name=Cname,typespec=Type}|T], Num) ->
+ Num2 = gen_record(Gen, TorPtype, [Cname|Name], Type, Num),
+ gen_record(Gen, TorPtype, Name, T, Num2);
+gen_record(Gen, TorPtype, Name, {Clist1,Clist2}, Num)
when is_list(Clist1), is_list(Clist2) ->
- gen_record(TorPtype,Name,Clist1++Clist2,Num);
-gen_record(TorPtype,Name,{Clist1,EClist,Clist2},Num)
+ gen_record(Gen, TorPtype, Name, Clist1++Clist2, Num);
+gen_record(Gen, TorPtype, Name, {Clist1,EClist,Clist2}, Num)
when is_list(Clist1), is_list(EClist), is_list(Clist2) ->
- gen_record(TorPtype,Name,Clist1++EClist++Clist2,Num);
-gen_record(TorPtype,Name,[_|T],Num) -> % skip EXTENSIONMARK
- gen_record(TorPtype,Name,T,Num);
-gen_record(_TorPtype,_Name,[],Num) ->
+ gen_record(Gen, TorPtype, Name, Clist1++EClist++Clist2, Num);
+gen_record(Gen, TorPtype, Name, [_|T], Num) -> % skip EXTENSIONMARK
+ gen_record(Gen, TorPtype, Name, T, Num);
+gen_record(_Gen, _TorPtype, _Name, [], Num) ->
Num;
-
-gen_record(TorPtype,Name,Type,Num) when is_record(Type,type) ->
+gen_record(Gen, TorPtype, Name, #type{}=Type, Num) ->
Def = Type#type.def,
Rec = case Def of
Seq when is_record(Seq,'SEQUENCE') ->
case Seq#'SEQUENCE'.pname of
false ->
{record,Seq#'SEQUENCE'.components};
-%% _Pname when TorPtype == type ->
-%% false;
_ ->
{record,Seq#'SEQUENCE'.components}
end;
@@ -1195,8 +1117,6 @@ gen_record(TorPtype,Name,Type,Num) when is_record(Type,type) ->
_ ->
{record,to_textual_order(Set#'SET'.components)}
end;
-% {'SET',{_,_CompList}} ->
-% {record,_CompList};
{'CHOICE',_CompList} -> {inner,Def};
{'SEQUENCE OF',_CompList} -> {['SEQOF'|Name],Def};
{'SET OF',_CompList} -> {['SETOF'|Name],Def};
@@ -1209,127 +1129,103 @@ gen_record(TorPtype,Name,Type,Num) when is_record(Type,type) ->
0 -> open_hrl(get(outfile),get(currmod));
_ -> true
end,
- Prefix = get_record_name_prefix(),
- emit({"-record('",Prefix,list2name(Name),"',{",nl}),
- RootList = case CompList of
- _ when is_list(CompList) ->
- CompList;
- {Rl,_} -> Rl;
- {Rl1,_Ext,_Rl2} -> Rl1
- end,
- gen_record2(Name,'SEQUENCE',RootList),
- NewCompList =
+ do_gen_record(Gen, Name, CompList),
+ NewCompList =
case CompList of
{CompList1,[]} ->
- emit({"}). % with extension mark",nl,nl}),
CompList1;
{Tr,ExtensionList2} ->
- case Tr of
- [] -> true;
- _ -> emit({",",nl})
- end,
- emit({"%% with extensions",nl}),
- gen_record2(Name, 'SEQUENCE', ExtensionList2,
- "", ext),
- emit({"}).",nl,nl}),
Tr ++ ExtensionList2;
{Rootl1,Extl,Rootl2} ->
- case Rootl1 =/= [] andalso Extl++Rootl2 =/= [] of
- true -> emit([com]);
- false -> ok
- end,
- case Rootl1 of
- [_|_] -> emit([nl]);
- [] -> ok
- end,
- emit(["%% with extensions",nl]),
- gen_record2(Name,'SEQUENCE',Extl,"",ext),
- case Extl =/= [] andalso Rootl2 =/= [] of
- true -> emit([com]);
- false -> ok
- end,
- case Extl of
- [_|_] -> emit([nl]);
- [] -> ok
- end,
- emit(["%% end of extensions",nl]),
- gen_record2(Name,'SEQUENCE',Rootl2,"",noext),
- emit(["}).",nl,nl]),
Rootl1++Extl++Rootl2;
- _ ->
- emit({"}).",nl,nl}),
+ _ ->
CompList
end,
- gen_record(TorPtype,Name,NewCompList,Num+1);
+ gen_record(Gen, TorPtype, Name, NewCompList, Num+1);
{inner,{'CHOICE', CompList}} ->
- gen_record(TorPtype,Name,CompList,Num);
+ gen_record(Gen, TorPtype, Name, CompList, Num);
{NewName,{_, CompList}} ->
- gen_record(TorPtype,NewName,CompList,Num)
+ gen_record(Gen, TorPtype, NewName, CompList, Num)
end;
-gen_record(_,_,_,NumRecords) -> % skip CLASS etc for now.
+gen_record(_, _, _, _, NumRecords) -> % skip CLASS etc for now.
NumRecords.
-
-gen_head(Erules,Mod,Hrl) ->
- Options = get(encoding_options),
- case Erules of
- per ->
- emit(["%% Generated by the Erlang ASN.1 PER-"
- "compiler version, utilizing bit-syntax:",
- asn1ct:vsn(),nl]);
- ber ->
- emit(["%% Generated by the Erlang ASN.1 BER_V2-"
- "compiler version, utilizing bit-syntax:",
- asn1ct:vsn(),nl]);
- uper ->
- emit(["%% Generated by the Erlang ASN.1 UNALIGNED"
- " PER-compiler version, utilizing bit-syntax:",
- asn1ct:vsn(),nl])
+
+do_gen_record(Gen, Name, CL0) ->
+ CL = case CL0 of
+ {Root,[]} ->
+ Root ++ [{comment,"with extension mark"}];
+ {Root,Ext} ->
+ Root ++ [{comment,"with exensions"}] ++
+ only_components(Ext);
+ {Root1,Ext,Root2} ->
+ Root1 ++ [{comment,"with exensions"}] ++
+ only_components(Ext) ++
+ [{comment,"end of extensions"}] ++ Root2;
+ _ when is_list(CL0) ->
+ CL0
+ end,
+ Prefix = get_record_name_prefix(Gen),
+ emit(["-record('",Prefix,list2name(Name),"', {"] ++
+ do_gen_record_1(CL) ++
+ [nl,"}).",nl,nl]).
+
+only_components(CL) ->
+ [C || #'ComponentType'{}=C <- CL].
+
+do_gen_record_1([#'ComponentType'{name=Name,prop=Prop}|T]) ->
+ Val = case Prop of
+ 'OPTIONAL' ->
+ " = asn1_NOVALUE";
+ {'DEFAULT',_} ->
+ " = asn1_DEFAULT";
+ _ ->
+ []
+ end,
+ Com = case needs_trailing_comma(T) of
+ true -> [com];
+ false -> []
end,
- emit({"%% Purpose: encoder and decoder to the types in mod ",Mod,nl,nl}),
- emit({"-module('",Mod,"').",nl}),
- put(currmod,Mod),
- emit({"-compile(nowarn_unused_vars).",nl}),
- emit({"-dialyzer(no_improper_lists).",nl}),
+ [nl," ",{asis,Name},Val,Com|do_gen_record_1(T)];
+do_gen_record_1([{comment,Text}|T]) ->
+ [nl," %% ",Text|do_gen_record_1(T)];
+do_gen_record_1([]) ->
+ [].
+
+needs_trailing_comma([#'ComponentType'{}|_]) -> true;
+needs_trailing_comma([_|T]) -> needs_trailing_comma(T);
+needs_trailing_comma([]) -> false.
+
+gen_head(#gen{options=Options}=Gen, Mod, Hrl) ->
+ Name = case Gen of
+ #gen{erule=per,aligned=false} ->
+ "PER (unaligned)";
+ #gen{erule=per,aligned=true} ->
+ "PER (aligned)";
+ #gen{erule=ber} ->
+ "BER"
+ end,
+ emit(["%% Generated by the Erlang ASN.1 ",Name,
+ " compiler. Version: ",asn1ct:vsn(),nl,
+ "%% Purpose: Encoding and decoding of the types in ",
+ Mod,".",nl,nl,
+ "-module('",Mod,"').",nl,
+ "-compile(nowarn_unused_vars).",nl,
+ "-dialyzer(no_improper_lists).",nl]),
case Hrl of
0 -> ok;
- _ -> emit({"-include(\"",Mod,".hrl\").",nl})
+ _ -> emit(["-include(\"",Mod,".hrl\").",nl])
end,
emit(["-asn1_info([{vsn,'",asn1ct:vsn(),"'},",nl,
" {module,'",Mod,"'},",nl,
" {options,",io_lib:format("~p",[Options]),"}]).",nl,nl]).
-
-
-gen_hrlhead(Mod) ->
- emit({"%% Generated by the Erlang ASN.1 compiler version:",asn1ct:vsn(),nl}),
- emit({"%% Purpose: Erlang record definitions for each named and unnamed",nl}),
- emit({"%% SEQUENCE and SET, and macro definitions for each value",nl}),
- emit({"%% definition,in module ",Mod,nl,nl}),
- emit({nl,nl}).
-gen_record2(Name,SeqOrSet,Comps) ->
- gen_record2(Name,SeqOrSet,Comps,"",noext).
-gen_record2(_Name,_SeqOrSet,[],_Com,_Extension) ->
- true;
-gen_record2(_Name,_SeqOrSet,[H = #'ComponentType'{name=Cname}],Com,Extension) ->
- emit(Com),
- emit({asis,Cname}),
- gen_record_default(H, Extension);
-gen_record2(Name,SeqOrSet,[H = #'ComponentType'{name=Cname}|T],Com, Extension) ->
- emit(Com),
- emit({asis,Cname}),
- gen_record_default(H, Extension),
- gen_record2(Name,SeqOrSet,T,", ", Extension);
-gen_record2(Name,SeqOrSet,[_|T],Com,Extension) ->
- %% skip EXTENSIONMARK, ExtensionAdditionGroup and other markers
- gen_record2(Name,SeqOrSet,T,Com,Extension).
-
-gen_record_default(#'ComponentType'{prop='OPTIONAL'}, _)->
- emit(" = asn1_NOVALUE");
-gen_record_default(#'ComponentType'{prop={'DEFAULT',_}}, _)->
- emit(" = asn1_DEFAULT");
-gen_record_default(_, _) ->
- true.
+gen_hrlhead(Mod) ->
+ emit(["%% Generated by the Erlang ASN.1 compiler. Version: ",
+ asn1ct:vsn(),nl,
+ "%% Purpose: Erlang record definitions for each named and unnamed",nl,
+ "%% SEQUENCE and SET, and macro definitions for each value",nl,
+ "%% definition in module ",Mod,".",nl,nl]).
%% May only be a list or a two-tuple.
to_textual_order({Root,Ext}) ->
@@ -1426,7 +1322,6 @@ get_inner({fixedtypevaluefield,_,Type}) ->
get_inner({typefield,TypeName}) ->
TypeName;
get_inner(#'ObjectClassFieldType'{type=Type}) ->
-% get_inner(Type);
Type;
get_inner(T) when is_tuple(T) ->
case element(1,T) of
@@ -1435,9 +1330,7 @@ get_inner(T) when is_tuple(T) ->
{valuefieldreference,FieldName} ->
get_fieldtype(element(2,Tuple),FieldName);
{typefieldreference,FieldName} ->
- get_fieldtype(element(2,Tuple),FieldName);
- {'EXIT',Reason} ->
- throw({asn1,{'internal error in get_inner/1',Reason}})
+ get_fieldtype(element(2,Tuple),FieldName)
end;
_ -> element(1,T)
end.
@@ -1585,27 +1478,19 @@ constructed_suffix('SEQUENCE OF',_) ->
constructed_suffix('SET OF',_) ->
'SETOF'.
-erule(ber) -> ber;
-erule(per) -> per;
-erule(uper) -> per.
-
index2suffix(0) ->
"";
index2suffix(N) ->
lists:concat(["_",N]).
-ct_gen_module(ber) ->
+ct_gen_module(#gen{erule=ber}) ->
asn1ct_gen_ber_bin_v2;
-ct_gen_module(per) ->
- asn1ct_gen_per;
-ct_gen_module(uper) ->
+ct_gen_module(#gen{erule=per}) ->
asn1ct_gen_per.
-ct_constructed_module(ber) ->
+ct_constructed_module(#gen{erule=ber}) ->
asn1ct_constructed_ber_bin_v2;
-ct_constructed_module(per) ->
- asn1ct_constructed_per;
-ct_constructed_module(uper) ->
+ct_constructed_module(#gen{erule=per}) ->
asn1ct_constructed_per.
get_constraint(C,Key) ->
@@ -1617,19 +1502,9 @@ get_constraint(C,Key) ->
{value,Cnstr} ->
Cnstr
end.
-
-get_record_name_prefix() ->
- case lists:keysearch(record_name_prefix,1,get(encoding_options)) of
- false ->
- "";
- {value,{_,Prefix}} ->
- Prefix
- end.
-get_macro_name_prefix() ->
- case lists:keysearch(macro_name_prefix,1,get(encoding_options)) of
- false ->
- "";
- {value,{_,Prefix}} ->
- Prefix
- end.
+get_record_name_prefix(#gen{rec_prefix=Prefix}) ->
+ Prefix.
+
+get_macro_name_prefix(#gen{macro_prefix=Prefix}) ->
+ Prefix.
diff --git a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
index b884d14b0d..446f508998 100644
--- a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,21 +35,21 @@
-export([extaddgroup2sequence/1]).
-export([dialyzer_suppressions/1]).
--import(asn1ct_gen, [emit/1,demit/1]).
+-import(asn1ct_gen, [emit/1]).
- % the encoding of class of tag bits 8 and 7
+%% The encoding of class of tag bits 8 and 7
-define(UNIVERSAL, 0).
-define(APPLICATION, 16#40).
-define(CONTEXT, 16#80).
-define(PRIVATE, 16#C0).
- % primitive or constructed encoding % bit 6
+%% Primitive or constructed encoding % bit 6
-define(PRIMITIVE, 0).
-define(CONSTRUCTED, 2#00100000).
-define(T_ObjectDescriptor, ?UNIVERSAL bor ?PRIMITIVE bor 7).
- % restricted character string types
+%% Restricted character string types
-define(T_NumericString, ?UNIVERSAL bor ?PRIMITIVE bor 18). %can be constructed
-define(T_PrintableString, ?UNIVERSAL bor ?PRIMITIVE bor 19). %can be constructed
-define(T_TeletexString, ?UNIVERSAL bor ?PRIMITIVE bor 20). %can be constructed
@@ -107,20 +107,12 @@ gen_encode(Erules,Typename,Type) when is_record(Type,type) ->
case asn1ct_gen:type(InnerType) of
{constructed,bif} ->
- emit([nl,nl,nl,"%%================================"]),
- emit([nl,"%% ",asn1ct_gen:list2name(Typename)]),
- emit([nl,"%%================================",nl]),
- case length(Typename) of
- 1 -> % top level type
- emit(["'enc_",asn1ct_gen:list2name(Typename),
- "'(Val",ObjFun,") ->",nl]),
- emit([" 'enc_",asn1ct_gen:list2name(Typename),
- "'(Val, ", {asis,lists:reverse(Type#type.tag)},ObjFun,").",nl,nl]);
- _ -> % embedded type with constructed name
- true
- end,
- emit(["'enc_",asn1ct_gen:list2name(Typename),
- "'(Val, TagIn",ObjFun,") ->",nl," "]),
+ Func = {asis,enc_func(asn1ct_gen:list2name(Typename))},
+ emit([nl,nl,nl,"%%================================",nl,
+ "%% ",asn1ct_gen:list2name(Typename),nl,
+ "%%================================",nl,
+ Func,"(Val, TagIn",ObjFun,") ->",nl,
+ " "]),
asn1ct_gen:gen_encode_constructed(Erules,Typename,InnerType,Type);
_ ->
true
@@ -146,7 +138,7 @@ gen_encode_user(Erules, #typedef{}=D, Wrapper) ->
emit([nl,nl,"%%================================"]),
emit([nl,"%% ",Typename]),
emit([nl,"%%================================",nl]),
- FuncName = "'enc_" ++ asn1ct_gen:list2name(Typename) ++ "'",
+ FuncName = {asis,enc_func(asn1ct_gen:list2name(Typename))},
case Wrapper of
true ->
%% This is a top-level type. Generate an 'enc_Type'/1
@@ -169,9 +161,10 @@ gen_encode_user(Erules, #typedef{}=D, Wrapper) ->
gen_encode_prim(ber,Type,"TagIn","Val"),
emit([".",nl]);
#'Externaltypereference'{module=CurrentMod,type=Etype} ->
- emit([" 'enc_",Etype,"'(Val, TagIn).",nl]);
+ emit([" ",{asis,enc_func(Etype)},"(Val, TagIn).",nl]);
#'Externaltypereference'{module=Emod,type=Etype} ->
- emit([" '",Emod,"':'enc_",Etype,"'(Val, TagIn).",nl]);
+ emit([" ",{asis,Emod},":",{asis,enc_func(Etype)},
+ "(Val, TagIn).",nl]);
'ASN1_OPEN_TYPE' ->
emit(["%% OPEN TYPE",nl]),
gen_encode_prim(ber,
@@ -326,40 +319,39 @@ gen_decode(Erules,Type) when is_record(Type,typedef) ->
Tag = [(decode_class(X#tag.class) bsl 10) + X#tag.number || X <- InnerTag],
- FunctionName =
+ FuncName0 =
case {asn1ct:get_gen_state_field(active),
asn1ct:get_gen_state_field(prefix)} of
{true,Pref} ->
%% prevent duplicated function definitions
-% Pattern = asn1ct:get_gen_state_field(namelist),
-% FuncName=asn1ct:maybe_rename_function(Type#typedef.name,
-% Pattern),
case asn1ct:current_sindex() of
- I when is_integer(I),I>0 ->
- lists:concat([Pref,Type#typedef.name,"_",I]);
+ I when is_integer(I), I > 0 ->
+ [Pref,Type#typedef.name,"_",I];
_->
- lists:concat([Pref,Type#typedef.name])
- end; % maybe the current_sindex must be reset
- _ -> lists:concat(["dec_",Type#typedef.name])
+ [Pref,Type#typedef.name]
+ end;
+ {_,_} ->
+ ["dec_",Type#typedef.name]
end,
- emit({nl,nl}),
- emit(["'",FunctionName,"'(Tlv) ->",nl]),
- emit([" '",FunctionName,"'(Tlv, ",{asis,Tag},").",nl,nl]),
- emit(["'",FunctionName,"'(Tlv, TagIn) ->",nl]),
- dbdec(Type#typedef.name,"Tlv"),
+ FuncName = {asis,list_to_atom(lists:concat(FuncName0))},
+ emit([nl,nl,
+ FuncName,"(Tlv) ->",nl,
+ " ",FuncName,"(Tlv, ",{asis,Tag},").",nl,nl,
+ FuncName,"(Tlv, TagIn) ->",nl]),
gen_decode_user(Erules,Type).
gen_inc_decode(Erules,Type) when is_record(Type,typedef) ->
Prefix = asn1ct:get_gen_state_field(prefix),
Suffix = asn1ct_gen:index2suffix(asn1ct:current_sindex()),
- emit({nl,nl}),
- emit(["'",Prefix,Type#typedef.name,Suffix,"'(Tlv, TagIn) ->",nl]),
+ FuncName0 = [Prefix,Type#typedef.name,Suffix],
+ FuncName = {asis,list_to_atom(lists:concat(FuncName0))},
+ emit([nl,nl,
+ FuncName,"(Tlv, TagIn) ->",nl]),
gen_decode_user(Erules,Type).
%% gen_decode_selected exported function for selected decode
gen_decode_selected(Erules,Type,FuncName) ->
emit([FuncName,"(Bin) ->",nl]),
-% Pattern = asn1ct:get_gen_state_field(tag_pattern),
Patterns = asn1ct:read_config_data(partial_decode),
Pattern =
case lists:keysearch(FuncName,1,Patterns) of
@@ -398,12 +390,10 @@ gen_decode_selected_type(_Erules,TypeDef) ->
asn1ct_gen:list2name(TopType),"'"]),
emit([DecFunName,"(",BytesVar,
", ",{asis,Tag},")"]);
-% emit([";",nl]);
TheType ->
DecFunName = mkfuncname(TheType,dec),
emit([DecFunName,"(",BytesVar,
", ",{asis,Tag},")"])
-% emit([";",nl])
end.
%%===============================================================================
@@ -418,7 +408,6 @@ gen_decode(Erules,Typename,Type) when is_record(Type,type) ->
FunctionName =
case asn1ct:get_gen_state_field(active) of
true ->
-% Suffix = asn1ct_gen:index2suffix(SIndex),
Pattern = asn1ct:get_gen_state_field(namelist),
Suffix =
case asn1ct:maybe_saved_sindex(Typename,Pattern) of
@@ -431,8 +420,6 @@ gen_decode(Erules,Typename,Type) when is_record(Type,type) ->
_ ->
lists:concat(["'dec_",asn1ct_gen:list2name(Typename)])
end,
-% io:format("Typename: ~p,~n",[Typename]),
-% io:format("FunctionName: ~p~n",[FunctionName]),
case asn1ct_gen:type(InnerType) of
{constructed,bif} ->
ObjFun =
@@ -442,9 +429,7 @@ gen_decode(Erules,Typename,Type) when is_record(Type,type) ->
_ ->
""
end,
-% emit([Prefix,asn1ct_gen:list2name(Typename),"'(Tlv, TagIn",ObjFun,") ->",nl]),
emit([FunctionName,"'(Tlv, TagIn",ObjFun,") ->",nl]),
- dbdec(Typename,"Tlv"),
asn1ct_gen:gen_decode_constructed(Erules,Typename,InnerType,Type);
Rec when is_record(Rec,'Externaltypereference') ->
case {Typename,asn1ct:get_gen_state_field(namelist)} of
@@ -476,10 +461,10 @@ gen_decode(Erules,Typename,Type) when is_record(Type,type) ->
gen_decode(Erules,Tname,#'ComponentType'{name=Cname,typespec=Type}) ->
NewTname = [Cname|Tname],
- %% The tag is set to [] to avoid that it is
- %% taken into account twice, both as a component/alternative (passed as
- %% argument to the encode decode function and within the encode decode
- %% function it self.
+ %% The tag is set to [] to avoid that it is taken into account
+ %% twice, both as a component/alternative (passed as argument to
+ %% the encode/decode function), and within the encode decode
+ %% function itself.
NewType = Type#type{tag=[]},
case {asn1ct:get_gen_state_field(active),
asn1ct:get_tobe_refed_func(NewTname)} of
@@ -504,7 +489,7 @@ gen_decode_user(Erules,D) when is_record(D,typedef) ->
asn1ct_name:new(len),
gen_dec_prim(Def#type{def='ASN1_OPEN_TYPE'},
BytesVar, {string,"TagIn"}),
- emit({".",nl,nl});
+ emit([".",nl,nl]);
{primitive,bif} ->
asn1ct_name:new(len),
gen_dec_prim(Def, BytesVar, {string,"TagIn"}),
@@ -515,8 +500,7 @@ gen_decode_user(Erules,D) when is_record(D,typedef) ->
TheType ->
DecFunName = mkfuncname(TheType,dec),
emit([DecFunName,"(",BytesVar,
- ", TagIn)"]),
- emit([".",nl,nl])
+ ", TagIn).",nl,nl])
end.
@@ -746,9 +730,10 @@ gen_obj_code(Erules,_Module,Obj) when is_record(Obj,typedef) ->
#'Externaltypereference'{module=M,type=ClName} = Def#'Object'.classname,
Class = asn1_db:dbget(M,ClName),
{object,_,Fields} = Def#'Object'.def,
- emit({nl,nl,nl,"%%================================"}),
- emit({nl,"%% ",ObjName}),
- emit({nl,"%%================================",nl}),
+ emit([nl,nl,nl,
+ "%%================================",nl,
+ "%% ",ObjName,nl,
+ "%%================================",nl]),
EncConstructed =
gen_encode_objectfields(ClName,get_class_fields(Class),
ObjName,Fields,[]),
@@ -766,11 +751,9 @@ gen_encode_objectfields(ClassName,[{typefield,Name,OptOrMand}|Rest],
ObjName,ObjectFields,ConstrAcc) ->
EmitFuncClause =
fun(Arg) ->
- emit(["'enc_",ObjName,"'(",{asis,Name},
- ", ",Arg,", _RestPrimFieldName) ->",nl])
+ emit([{asis,enc_func(ObjName)},"(",{asis,Name},
+ ", ",Arg,", _RestPrimFieldName) ->",nl])
end,
-% emit(["'enc_",ObjName,"'(",{asis,Name},
-% ", Val, RestPrimFieldName) ->",nl]),
MaybeConstr=
case {get_object_field(Name,ObjectFields),OptOrMand} of
{false,'OPTIONAL'} ->
@@ -799,11 +782,9 @@ gen_encode_objectfields(ClassName,[{objectfield,Name,_,_,OptOrMand}|Rest],
CurrentMod = get(currmod),
EmitFuncClause =
fun(Args) ->
- emit(["'enc_",ObjName,"'(",{asis,Name},
+ emit([{asis,enc_func(ObjName)},"(",{asis,Name},
", ",Args,") ->",nl])
end,
-% emit(["'enc_",ObjName,"'(",{asis,Name},
-% ", Val,[H|T]) ->",nl]),
case {get_object_field(Name,ObjectFields),OptOrMand} of
{false,'OPTIONAL'} ->
EmitFuncClause("_,_"),
@@ -814,19 +795,14 @@ gen_encode_objectfields(ClassName,[{objectfield,Name,_,_,OptOrMand}|Rest],
{{Name,#'Externalvaluereference'{module=CurrentMod,
value=TypeName}},_} ->
EmitFuncClause(" Val, [H|T]"),
- emit({indent(3),"'enc_",TypeName,"'(H, Val, T)"});
+ emit([indent(3),{asis,enc_func(TypeName)},"(H, Val, T)"]);
{{Name,#'Externalvaluereference'{module=M,value=TypeName}},_} ->
EmitFuncClause(" Val, [H|T]"),
- emit({indent(3),"'",M,"':'enc_",TypeName,"'(H, Val, T)"});
- {{Name,TypeSpec},_} ->
+ emit([indent(3),{asis,M},":",{asis,enc_func(TypeName)},
+ "(H, Val, T)"]);
+ {{Name,#typedef{name=TypeName}},_} when is_atom(TypeName) ->
EmitFuncClause(" Val, [H|T]"),
- case TypeSpec#typedef.name of
- {ExtMod,TypeName} ->
- emit({indent(3),"'",ExtMod,"':'enc_",TypeName,
- "'(H, Val, T)"});
- TypeName ->
- emit({indent(3),"'enc_",TypeName,"'(H, Val, T)"})
- end
+ emit([indent(3),{asis,enc_func(TypeName)},"(H, Val, T)"])
end,
case more_genfields(Rest) of
true ->
@@ -862,10 +838,11 @@ gen_encode_field_call(_ObjName,_FieldName,
X <- OTag],
if
M == CurrentMod ->
- emit({" 'enc_",T,"'(Val, ",{asis,Tag},")"}),
+ emit([" ",{asis,enc_func(T)},"(Val, ",{asis,Tag},")"]),
[];
true ->
- emit({" '",M,"':'enc_",T,"'(Val, ",{asis,Tag},")"}),
+ emit([" ",{asis,M},":",{asis,enc_func(T)},
+ "(Val, ",{asis,Tag},")"]),
[]
end;
gen_encode_field_call(ObjName,FieldName,Type) ->
@@ -875,24 +852,21 @@ gen_encode_field_call(ObjName,FieldName,Type) ->
X#tag.form,X#tag.number)||
X <- OTag],
case Type#typedef.name of
- {primitive,bif} -> %%tag should be the primitive tag
-% OTag = Def#type.tag,
-% Tag = [encode_tag_val(decode_class(X#tag.class),
-% X#tag.form,X#tag.number)||
-% X <- OTag],
+ {primitive,bif} -> %tag should be the primitive tag
gen_encode_prim(ber,Def,{asis,lists:reverse(Tag)},
"Val"),
[];
{constructed,bif} ->
- emit({" 'enc_",ObjName,'_',FieldName,
- "'(Val,",{asis,Tag},")"}),
- [Type#typedef{name=list_to_atom(lists:concat([ObjName,'_',FieldName]))}];
+ Name = lists:concat([ObjName,'_',FieldName]),
+ emit([" ",{asis,enc_func(Name)},"(Val,",{asis,Tag},")"]),
+ [Type#typedef{name=list_to_atom(Name)}];
{ExtMod,TypeName} ->
- emit({" '",ExtMod,"':'enc_",TypeName,
- "'(Val,",{asis,Tag},")"}),
+ emit([" ",{asis,ExtMod},":",{asis,enc_func(TypeName)},
+ "(Val,",{asis,Tag},")"]),
[];
TypeName ->
- emit({" 'enc_",TypeName,"'(Val,",{asis,Tag},")"}),
+ emit([" ",{asis,enc_func(TypeName)},
+ "(Val,",{asis,Tag},")"]),
[]
end.
@@ -903,10 +877,10 @@ gen_encode_default_call(ClassName,FieldName,Type) ->
Tag = [encode_tag_val(decode_class(X#tag.class),X#tag.form,X#tag.number)|| X <- OTag],
case asn1ct_gen:type(InnerType) of
{constructed,bif} ->
- emit([" 'enc_",ClassName,'_',FieldName,"'",
+ Name = lists:concat([ClassName,'_',FieldName]),
+ emit([" ",{asis,enc_func(Name)},
"(Val, ",{asis,Tag},")"]),
- [#typedef{name=list_to_atom(lists:concat([ClassName,'_',FieldName])),
- typespec=Type}];
+ [#typedef{name=list_to_atom(Name),typespec=Type}];
{primitive,bif} ->
gen_encode_prim(ber,Type,{asis,lists:reverse(Tag)},"Val"),
[];
@@ -916,12 +890,6 @@ gen_encode_default_call(ClassName,FieldName,Type) ->
#'Externaltypereference'{module=Emod,type=Etype} ->
emit([" '",Emod,"':'enc_",Etype,"'(Val, ",{asis,Tag},")",nl]),
[]
-% 'ASN1_OPEN_TYPE' ->
-% emit(["%% OPEN TYPE",nl]),
-% gen_encode_prim(ber,
-% Type#type{def='ASN1_OPEN_TYPE'},
-% "TagIn","Val"),
-% emit([".",nl])
end.
%%%%%%%%%%%%%%%%
@@ -930,11 +898,9 @@ gen_decode_objectfields(ClassName,[{typefield,Name,OptOrMand}|Rest],
ObjName,ObjectFields,ConstrAcc) ->
EmitFuncClause =
fun(Arg) ->
- emit(["'dec_",ObjName,"'(",{asis,Name},
+ emit([{asis,dec_func(ObjName)},"(",{asis,Name},
", ",Arg,",_) ->",nl])
end,
-% emit(["'dec_",ObjName,"'(",{asis,Name},
-% ", Bytes, RestPrimFieldName) ->",nl]),
MaybeConstr=
case {get_object_field(Name,ObjectFields),OptOrMand} of
{false,'OPTIONAL'} ->
@@ -964,12 +930,9 @@ gen_decode_objectfields(ClassName,[{objectfield,Name,_,_,OptOrMand}|Rest],
CurrentMod = get(currmod),
EmitFuncClause =
fun(Args) ->
- emit(["'dec_",ObjName,"'(",{asis,Name},
+ emit([{asis,dec_func(ObjName)},"(",{asis,Name},
", ",Args,") ->",nl])
end,
-% emit(["'dec_",ObjName,"'(",{asis,Name},
-% ", Bytes,[H|T]) ->",nl]),
-% emit_tlv_format("Bytes"),
case {get_object_field(Name,ObjectFields),OptOrMand} of
{false,'OPTIONAL'} ->
EmitFuncClause("_,_"),
@@ -980,21 +943,14 @@ gen_decode_objectfields(ClassName,[{objectfield,Name,_,_,OptOrMand}|Rest],
{{Name,#'Externalvaluereference'{module=CurrentMod,
value=TypeName}},_} ->
EmitFuncClause("Bytes,[H|T]"),
- emit({indent(3),"'dec_",TypeName,"'(H, Bytes, T)"});
+ emit([indent(3),{asis,dec_func(TypeName)},"(H, Bytes, T)"]);
{{Name,#'Externalvaluereference'{module=M,value=TypeName}},_} ->
EmitFuncClause("Bytes,[H|T]"),
- emit({indent(3),"'",M,"':'dec_",TypeName,
- "'(H, Bytes, T)"});
- {{Name,TypeSpec},_} ->
- EmitFuncClause("Bytes,[H|T]"),
-% emit_tlv_format("Bytes"),
- case TypeSpec#typedef.name of
- {ExtMod,TypeName} ->
- emit({indent(3),"'",ExtMod,"':'dec_",TypeName,
- "'(H, Bytes, T)"});
- TypeName ->
- emit({indent(3),"'dec_",TypeName,"'(H, Bytes, T)"})
- end
+ emit([indent(3),{asis,M},":",{asis,dec_func(TypeName)},
+ "(H, Bytes, T)"]);
+ {{Name,#typedef{name=TypeName}},_} when is_atom(TypeName) ->
+ EmitFuncClause("Bytes,[H|T]"),
+ emit([indent(3),{asis,dec_func(TypeName)},"(H, Bytes, T)"])
end,
case more_genfields(Rest) of
true ->
@@ -1014,24 +970,20 @@ emit_tlv_format(Bytes) ->
notice_tlv_format_gen() ->
Module = get(currmod),
-% io:format("Noticed: ~p~n",[Module]),
case get(tlv_format) of
{done,Module} ->
ok;
- _ -> % true or undefined
+ _ -> % true or undefined
put(tlv_format,true)
end.
emit_tlv_format_function() ->
Module = get(currmod),
-% io:format("Tlv formated: ~p",[Module]),
case get(tlv_format) of
true ->
-% io:format(" YES!~n"),
emit_tlv_format_function1(),
put(tlv_format,{done,Module});
_ ->
-% io:format(" NO!~n"),
ok
end.
emit_tlv_format_function1() ->
@@ -1066,12 +1018,12 @@ gen_decode_field_call(_ObjName,_FieldName,Bytes,
X <- OTag],
if
M == CurrentMod ->
- emit({" 'dec_",T,"'(",Bytes,
- ", ",{asis,Tag},")"}),
+ emit([" ",{asis,dec_func(T)},"(",Bytes,
+ ", ",{asis,Tag},")"]),
[];
true ->
- emit({" '",M,"':'dec_",T,
- "'(",Bytes,", ",{asis,Tag},")"}),
+ emit([" ",{asis,M},":",{asis,dec_func(T)},
+ "(",Bytes,", ",{asis,Tag},")"]),
[]
end;
gen_decode_field_call(ObjName,FieldName,Bytes,Type) ->
@@ -1084,15 +1036,17 @@ gen_decode_field_call(ObjName,FieldName,Bytes,Type) ->
gen_dec_prim(Def, Bytes, Tag),
[];
{constructed,bif} ->
- emit({" 'dec_",ObjName,'_',FieldName,
- "'(",Bytes,",",{asis,Tag},")"}),
- [Type#typedef{name=list_to_atom(lists:concat([ObjName,'_',FieldName]))}];
+ Name = lists:concat([ObjName,"_",FieldName]),
+ emit([" ",{asis,dec_func(Name)},
+ "(",Bytes,",",{asis,Tag},")"]),
+ [Type#typedef{name=list_to_atom(Name)}];
{ExtMod,TypeName} ->
- emit({" '",ExtMod,"':'dec_",TypeName,
- "'(",Bytes,",",{asis,Tag},")"}),
+ emit([" ",{asis,ExtMod},":",{asis,dec_func(TypeName)},
+ "(",Bytes,",",{asis,Tag},")"]),
[];
TypeName ->
- emit({" 'dec_",TypeName,"'(",Bytes,",",{asis,Tag},")"}),
+ emit([" ",{asis,dec_func(TypeName)},
+ "(",Bytes,",",{asis,Tag},")"]),
[]
end.
@@ -1118,12 +1072,6 @@ gen_decode_default_call(ClassName,FieldName,Bytes,Type) ->
emit([" '",Emod,"':'dec_",Etype,"'(",Bytes,", ",
{asis,Tag},")",nl]),
[]
-% 'ASN1_OPEN_TYPE' ->
-% emit(["%% OPEN TYPE",nl]),
-% gen_encode_prim(ber,
-% Type#type{def='ASN1_OPEN_TYPE'},
-% "TagIn","Val"),
-% emit([".",nl])
end.
%%%%%%%%%%%
@@ -1162,15 +1110,15 @@ more_genfields([Field|Fields]) ->
gen_objectset_code(Erules,ObjSet) ->
ObjSetName = ObjSet#typedef.name,
Def = ObjSet#typedef.typespec,
-% {ClassName,ClassDef} = Def#'ObjectSet'.class,
#'Externaltypereference'{module=ClassModule,
type=ClassName} = Def#'ObjectSet'.class,
ClassDef = asn1_db:dbget(ClassModule,ClassName),
UniqueFName = Def#'ObjectSet'.uniquefname,
Set = Def#'ObjectSet'.set,
- emit({nl,nl,nl,"%%================================"}),
- emit({nl,"%% ",ObjSetName}),
- emit({nl,"%%================================",nl}),
+ emit([nl,nl,nl,
+ "%%================================",nl,
+ "%% ",ObjSetName,nl,
+ "%%================================",nl]),
case ClassName of
{_Module,ExtClassName} ->
gen_objset_code(Erules,ObjSetName,UniqueFName,Set,ExtClassName,ClassDef);
@@ -1200,17 +1148,20 @@ gen_objset_enc(Erules, ObjSetName, UniqueName,
{no_mod,no_name} ->
gen_inlined_enc_funs(Fields, ClFields, ObjSetName, Val, NthObj);
{CurrMod,Name} ->
- emit(["'getenc_",ObjSetName,"'(",{asis,Val},") ->",nl,
- " fun 'enc_",Name,"'/3;",nl]),
+ emit([asis_atom(["getenc_",ObjSetName]),
+ "(Id) when Id =:= ",{asis,Val}," ->",nl,
+ " fun ",asis_atom(["enc_",Name]),"/3;",nl]),
{[],NthObj};
{ModuleName,Name} ->
- emit(["'getenc_",ObjSetName,"'(",{asis,Val},") ->",nl]),
+ emit([asis_atom(["getenc_",ObjSetName]),
+ "(Id) when Id =:= ",{asis,Val}," ->",nl]),
emit_ext_fun(enc,ModuleName,Name),
emit([";",nl]),
{[],NthObj};
_ ->
- emit(["'getenc_",ObjSetName,"'(",{asis,Val},") ->",nl,
- " fun 'enc_",ObjName,"'/3;",nl]),
+ emit([asis_atom(["getenc_",ObjSetName]),
+ "(",{asis,Val},") ->",nl,
+ " fun ",asis_atom(["enc_",ObjName]),"/3;",nl]),
{[],NthObj}
end,
gen_objset_enc(Erules, ObjSetName, UniqueName, T, ClName, ClFields,
@@ -1218,7 +1169,7 @@ gen_objset_enc(Erules, ObjSetName, UniqueName,
%% See X.681 Annex E for the following case
gen_objset_enc(_,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,
_ClFields,_NthObj,Acc) ->
- emit(["'getenc_",ObjSetName,"'(_) ->",nl,
+ emit([asis_atom(["getenc_",ObjSetName]),"(_) ->",nl,
indent(2),"fun(_, Val, _RestPrimFieldName) ->",nl]),
emit_enc_open_type(4),
emit([nl,
@@ -1226,7 +1177,7 @@ gen_objset_enc(_,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,
Acc;
gen_objset_enc(_, ObjSetName, UniqueName, [], _, _, _, Acc) ->
emit_default_getenc(ObjSetName, UniqueName),
- emit({".",nl,nl}),
+ emit([".",nl,nl]),
Acc.
emit_ext_fun(EncDec,ModuleName,Name) ->
@@ -1234,14 +1185,15 @@ emit_ext_fun(EncDec,ModuleName,Name) ->
Name,"'(T,V,O) end"]).
emit_default_getenc(ObjSetName,UniqueName) ->
- emit(["'getenc_",ObjSetName,"'(ErrV) ->",nl]),
- emit([indent(3),"fun(C,V,_) -> exit({'Type not compatible with table constraint',{component,C},{value,V}, {unique_name_and_value,",{asis,UniqueName},", ErrV}}) end"]).
+ emit([asis_atom(["getenc_",ObjSetName]),"(ErrV) ->",nl,
+ indent(3),"fun(C,V,_) ->",nl,
+ "exit({'Type not compatible with table constraint',{component,C},{value,V}, {unique_name_and_value,",{asis,UniqueName},", ErrV}}) end"]).
%% gen_inlined_enc_funs for each object iterates over all fields of a
%% class, and for each typefield it checks if the object has that
%% field and emits the proper code.
gen_inlined_enc_funs(Fields, [{typefield,_,_}|_]=T, ObjSetName, Val, NthObj) ->
- emit(["'getenc_",ObjSetName,"'(",{asis,Val},") ->",nl,
+ emit([asis_atom(["getenc_",ObjSetName]),"(",{asis,Val},") ->",nl,
indent(3),"fun(Type, Val, _RestPrimFieldName) ->",nl,
indent(6),"case Type of",nl]),
gen_inlined_enc_funs1(Fields, T, ObjSetName, [], NthObj, []);
@@ -1281,8 +1233,8 @@ gen_inlined_enc_funs1(Fields, [{typefield,Name,_}|Rest], ObjSetName,
end,
{Acc0,0};
false ->
- %% This field was not present in the object thus there
- %% were no type in the table and we therefore generate
+ %% This field was not present in the object; thus, there
+ %% was no type in the table and we therefore generate
%% code that returns the input for application
%% treatment.
emit([indent(9),{asis,Name}," ->",nl]),
@@ -1320,7 +1272,6 @@ emit_inner_of_fun(TDef=#typedef{name={ExtMod,Name},typespec=Type},
InternalDefFunName) ->
OTag = Type#type.tag,
Tag = [encode_tag_val(decode_class(X#tag.class),X#tag.form,X#tag.number)|| X <- OTag],
-% remove Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
case {ExtMod,Name} of
{primitive,bif} ->
emit(indent(12)),
@@ -1331,20 +1282,14 @@ emit_inner_of_fun(TDef=#typedef{name={ExtMod,Name},typespec=Type},
InternalDefFunName,"'(Val, ",{asis,Tag},")"]),
{[TDef#typedef{name=InternalDefFunName}],1};
_ ->
- emit({indent(12),"'",ExtMod,"':'enc_",Name,"'(Val",{asis,Tag},")"}),
+ emit([indent(12),"'",ExtMod,"':'enc_",Name,"'(Val",{asis,Tag},")"]),
{[],0}
end;
emit_inner_of_fun(#typedef{name=Name},_) ->
-% OTag = Type#type.tag,
-% remove Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
-% Tag = [encode_tag_val(decode_class(X#tag.class),X#tag.form,X#tag.number)|| X <- OTag],
- emit({indent(12),"'enc_",Name,"'(Val)"}),
+ emit([indent(12),"'enc_",Name,"'(Val)"]),
{[],0};
emit_inner_of_fun(Type,_) when is_record(Type,type) ->
CurrMod = get(currmod),
-% OTag = Type#type.tag,
-% remove Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
-% Tag = [encode_tag_val(decode_class(X#tag.class),X#tag.form,X#tag.number)|| X <- OTag],
case Type#type.def of
Def when is_atom(Def) ->
OTag = Type#type.tag,
@@ -1382,16 +1327,19 @@ gen_objset_dec(Erules, ObjSName, UniqueName, [{ObjName,Val,Fields}|T],
{no_mod,no_name} ->
gen_inlined_dec_funs(Fields,ClFields,ObjSName,Val,NthObj);
{CurrMod,Name} ->
- emit(["'getdec_",ObjSName,"'(",{asis,Val},") ->",nl,
+ emit([asis_atom(["getdec_",ObjSName]),
+ "(Id) when Id =:= ",{asis,Val}," ->",nl,
" fun 'dec_",Name,"'/3;", nl]),
NthObj;
{ModuleName,Name} ->
- emit(["'getdec_",ObjSName,"'(",{asis,Val},") ->",nl]),
+ emit([asis_atom(["getdec_",ObjSName]),
+ "(Id) when Id =:= ",{asis,Val}," ->",nl]),
emit_ext_fun(dec,ModuleName,Name),
emit([";",nl]),
NthObj;
_ ->
- emit(["'getdec_",ObjSName,"'(",{asis,Val},") ->",nl,
+ emit([asis_atom(["getdec_",ObjSName]),
+ "(",{asis,Val},") ->",nl,
" fun 'dec_",ObjName,"'/3;", nl]),
NthObj
end,
@@ -1399,8 +1347,8 @@ gen_objset_dec(Erules, ObjSName, UniqueName, [{ObjName,Val,Fields}|T],
ClFields, NewNthObj);
gen_objset_dec(_,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,
_ClFields,_NthObj) ->
- emit(["'getdec_",ObjSetName,"'(_) ->",nl]),
- emit([indent(2),"fun(_,Bytes, _RestPrimFieldName) ->",nl]),
+ emit([asis_atom(["getdec_",ObjSetName]),"(_) ->",nl,
+ indent(2),"fun(_,Bytes, _RestPrimFieldName) ->",nl]),
emit_dec_open_type(4),
emit([nl,
indent(2),"end.",nl,nl]),
@@ -1491,7 +1439,6 @@ emit_dec_open_type(I) ->
emit_inner_of_decfun(#typedef{name={ExtName,Name},typespec=Type}, _Prop,
InternalDefFunName) ->
OTag = Type#type.tag,
-%% Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
Tag = [(decode_class(X#tag.class) bsl 10) + X#tag.number || X <- OTag],
case {ExtName,Name} of
{primitive,bif} ->
@@ -1500,8 +1447,6 @@ emit_inner_of_decfun(#typedef{name={ExtName,Name},typespec=Type}, _Prop,
0;
{constructed,bif} ->
emit([indent(12),"'dec_",
-% asn1ct_gen:list2name(InternalDefFunName),"'(Bytes, ",Prop,
-% ", ",{asis,Tag},")"]),
asn1ct_gen:list2name(InternalDefFunName),"'(Bytes, ",
{asis,Tag},")"]),
1;
@@ -1515,7 +1460,6 @@ emit_inner_of_decfun(#typedef{name=Name},_Prop,_) ->
0;
emit_inner_of_decfun(#type{}=Type, _Prop, _) ->
OTag = Type#type.tag,
-%% Tag = [X#tag{class=decode_class(X#tag.class)}|| X <- OTag],
Tag = [(decode_class(X#tag.class) bsl 10) + X#tag.number || X <- OTag],
CurrMod = get(currmod),
Def = Type#type.def,
@@ -1527,11 +1471,9 @@ emit_inner_of_decfun(#type{}=Type, _Prop, _) ->
gen_dec_prim(Type, "Bytes", Tag);
#'Externaltypereference'{module=CurrMod,type=T} ->
emit([indent(9),T," ->",nl,indent(12),"'dec_",T,
-% "'(Bytes, ",Prop,")"]);
"'(Bytes)"]);
#'Externaltypereference'{module=ExtMod,type=T} ->
emit([indent(9),T," ->",nl,indent(12),ExtMod,":'dec_",
-% T,"'(Bytes, ",Prop,")"])
T,"'(Bytes, ",{asis,Tag},")"])
end,
0.
@@ -1546,10 +1488,6 @@ gen_internal_funcs(Erules,[TypeDef|Rest]) ->
gen_internal_funcs(Erules,Rest).
-dbdec(Type,Arg) ->
- demit({"io:format(\"decoding: ",{asis,Type},"~w~n\",[",Arg,"]),",nl}).
-
-
decode_class('UNIVERSAL') ->
?UNIVERSAL;
decode_class('APPLICATION') ->
@@ -1601,7 +1539,7 @@ encode_tag_val(Class, Form, TagNo) ->
%%%%%%%%%%%
%% mk_object_val(Value) -> {OctetList, Len}
-%% returns a Val as a list of octets, the 8 bit is allways set to one except
+%% returns a Val as a list of octets, the 8 bit is always set to one except
%% for the last octet, where its 0
%%
@@ -1615,8 +1553,9 @@ mk_object_val(0, Ack, Len) ->
mk_object_val(Val, Ack, Len) ->
mk_object_val(Val bsr 7, [((Val band 127) bor 128) | Ack], Len + 1).
-%% For BER the ExtensionAdditionGroup notation has no impact on the encoding/decoding
-%% and therefore we only filter away the ExtensionAdditionGroup start and end markers
+%% For BER the ExtensionAdditionGroup notation has no impact on the
+%% encoding/decoding. Therefore we can filter away the
+%% ExtensionAdditionGroup start and end markers.
extaddgroup2sequence(ExtList) when is_list(ExtList) ->
lists:filter(fun(#'ExtensionAdditionGroup'{}) ->
false;
@@ -1628,3 +1567,12 @@ extaddgroup2sequence(ExtList) when is_list(ExtList) ->
call(F, Args) ->
asn1ct_func:call(ber, F, Args).
+
+enc_func(Tname) ->
+ list_to_atom(lists:concat(["enc_",Tname])).
+
+dec_func(Tname) ->
+ list_to_atom(lists:concat(["dec_",Tname])).
+
+asis_atom(List) ->
+ {asis,list_to_atom(lists:concat(List))}.
diff --git a/lib/asn1/src/asn1ct_gen_check.erl b/lib/asn1/src/asn1ct_gen_check.erl
index abe77dd0cb..4996491fa7 100644
--- a/lib/asn1/src/asn1ct_gen_check.erl
+++ b/lib/asn1/src/asn1ct_gen_check.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,45 +21,51 @@
%%
-module(asn1ct_gen_check).
--export([emit/3]).
+-export([emit/4]).
-import(asn1ct_gen, [emit/1]).
-include("asn1_records.hrl").
-emit(Type, Default, Value) ->
+emit(Gen, Type, Default, Value) ->
Key = {Type,Default},
- Gen = fun(Fd, Name) ->
- file:write(Fd, gen(Name, Type, Default))
- end,
+ DoGen = fun(Fd, Name) ->
+ file:write(Fd, gen(Gen, Name, Type, Default))
+ end,
emit(" case "),
- asn1ct_func:call_gen("is_default_", Key, Gen, [Value]),
+ asn1ct_func:call_gen("is_default_", Key, DoGen, [Value]),
emit([" of",nl,
"true -> {[],0};",nl,
"false ->",nl]).
-gen(Name, #type{def=T}, Default) ->
+gen(#gen{pack=Pack}=Gen, Name, #type{def=T}, Default) ->
+ DefMarker = case Pack of
+ record -> "asn1_DEFAULT";
+ map -> atom_to_list(?MISSING_IN_MAP)
+ end,
NameStr = atom_to_list(Name),
- [NameStr,"(asn1_DEFAULT) ->\n",
- "true;\n"|case do_gen(T, Default) of
- {literal,Literal} ->
- [NameStr,"(",term2str(Literal),") ->\n","true;\n",
- NameStr,"(_) ->\n","false.\n\n"];
- {exception,Func,Args} ->
- [NameStr,"(Value) ->\n",
- "try ",Func,"(Value",arg2str(Args),") of\n",
- "_ -> true\n"
- "catch throw:false -> false\n"
- "end.\n\n"]
- end].
+ [NameStr,"(",DefMarker,") ->\n",
+ "true;\n"|
+ case do_gen(Gen, T, Default) of
+ {literal,Literal} ->
+ [NameStr,"(Def) when Def =:= ",term2str(Literal)," ->\n",
+ "true;\n",
+ NameStr,"(_) ->\n","false.\n\n"];
+ {exception,Func,Args} ->
+ [NameStr,"(Value) ->\n",
+ "try ",Func,"(Value",arg2str(Args),") of\n",
+ "_ -> true\n"
+ "catch throw:false -> false\n"
+ "end.\n\n"]
+ end].
-do_gen(_, asn1_NOVALUE) ->
+do_gen(_Gen, _, asn1_NOVALUE) ->
{literal,asn1_NOVALUE};
-do_gen(#'Externaltypereference'{module=M,type=T}, Default) ->
+do_gen(Gen, #'Externaltypereference'{module=M,type=T}, Default) ->
#typedef{typespec=#type{def=Td}} = asn1_db:dbget(M, T),
- do_gen(Td, Default);
-do_gen('BOOLEAN', Default) ->
+ do_gen(Gen, Td, Default);
+do_gen(_Gen, 'BOOLEAN', Default) ->
{literal,Default};
-do_gen({'BIT STRING',[]}, Default) ->
+do_gen(_Gen, {'BIT STRING',[]}, Default) ->
true = is_bitstring(Default), %Assertion.
case asn1ct:use_legacy_types() of
false ->
@@ -67,17 +73,17 @@ do_gen({'BIT STRING',[]}, Default) ->
true ->
{exception,need(check_legacy_bitstring, 2),[Default]}
end;
-do_gen({'BIT STRING',[_|_]=NBL}, Default) ->
+do_gen(_Gen, {'BIT STRING',[_|_]=NBL}, Default) ->
do_named_bitstring(NBL, Default);
-do_gen({'ENUMERATED',_}, Default) ->
+do_gen(_Gen, {'ENUMERATED',_}, Default) ->
{literal,Default};
-do_gen('INTEGER', Default) ->
+do_gen(_Gen, 'INTEGER', Default) ->
{literal,Default};
-do_gen({'INTEGER',NNL}, Default) ->
+do_gen(_Gen, {'INTEGER',NNL}, Default) ->
{exception,need(check_int, 3),[Default,NNL]};
-do_gen('NULL', Default) ->
+do_gen(_Gen, 'NULL', Default) ->
{literal,Default};
-do_gen('OCTET STRING', Default) ->
+do_gen(_Gen, 'OCTET STRING', Default) ->
true = is_binary(Default), %Assertion.
case asn1ct:use_legacy_types() of
false ->
@@ -85,34 +91,34 @@ do_gen('OCTET STRING', Default) ->
true ->
{exception,need(check_octetstring, 2),[Default]}
end;
-do_gen('OBJECT IDENTIFIER', Default0) ->
+do_gen(_Gen, 'OBJECT IDENTIFIER', Default0) ->
Default = pre_process_oid(Default0),
{exception,need(check_objectidentifier, 2),[Default]};
-do_gen({'CHOICE',Cs}, Default) ->
+do_gen(Gen, {'CHOICE',Cs}, Default) ->
{Tag,Value} = Default,
[Type] = [Type || #'ComponentType'{name=T,typespec=Type} <- Cs,
T =:= Tag],
- case do_gen(Type#type.def, Value) of
+ case do_gen(Gen, Type#type.def, Value) of
{literal,Lit} ->
{literal,{Tag,Lit}};
{exception,Func0,Args} ->
Key = {Tag,Func0,Args},
- Gen = fun(Fd, Name) ->
- S = gen_choice(Name, Tag, Func0, Args),
- ok = file:write(Fd, S)
+ DoGen = fun(Fd, Name) ->
+ S = gen_choice(Name, Tag, Func0, Args),
+ ok = file:write(Fd, S)
end,
- Func = asn1ct_func:call_gen("is_default_choice", Key, Gen),
+ Func = asn1ct_func:call_gen("is_default_choice", Key, DoGen),
{exception,atom_to_list(Func),[]}
end;
-do_gen(#'SEQUENCE'{components=Cs}, Default) ->
- do_seq_set(Cs, Default);
-do_gen({'SEQUENCE OF',Type}, Default) ->
- do_sof(Type, Default);
-do_gen(#'SET'{components=Cs}, Default) ->
- do_seq_set(Cs, Default);
-do_gen({'SET OF',Type}, Default) ->
- do_sof(Type, Default);
-do_gen(Type, Default) ->
+do_gen(Gen, #'SEQUENCE'{components=Cs}, Default) ->
+ do_seq_set(Gen, Cs, Default);
+do_gen(Gen, {'SEQUENCE OF',Type}, Default) ->
+ do_sof(Gen, Type, Default);
+do_gen(Gen, #'SET'{components=Cs}, Default) ->
+ do_seq_set(Gen, Cs, Default);
+do_gen(Gen, {'SET OF',Type}, Default) ->
+ do_sof(Gen, Type, Default);
+do_gen(_Gen, Type, Default) ->
case asn1ct_gen:unify_if_string(Type) of
restrictedstring ->
{exception,need(check_restrictedstring, 2),[Default]};
@@ -136,39 +142,58 @@ do_named_bitstring(_, Default) when is_bitstring(Default) ->
end,
{exception,need(Func, 3),[Default,bit_size(Default)]}.
-do_seq_set(Cs0, Default) ->
+do_seq_set(#gen{pack=record}=Gen, Cs0, Default) ->
Tag = element(1, Default),
Cs1 = [T || #'ComponentType'{typespec=T} <- Cs0],
- Cs = components(Cs1, tl(tuple_to_list(Default))),
+ Cs = components(Gen, Cs1, tl(tuple_to_list(Default))),
case are_all_literals(Cs) of
true ->
Literal = list_to_tuple([Tag|[L || {literal,L} <- Cs]]),
{literal,Literal};
false ->
Key = {Cs,Default},
- Gen = fun(Fd, Name) ->
- S = gen_components(Name, Tag, Cs),
- ok = file:write(Fd, S)
- end,
- Func = asn1ct_func:call_gen("is_default_cs_", Key, Gen),
+ DoGen = fun(Fd, Name) ->
+ S = gen_components(Name, Tag, Cs),
+ ok = file:write(Fd, S)
+ end,
+ Func = asn1ct_func:call_gen("is_default_cs_", Key, DoGen),
+ {exception,atom_to_list(Func),[]}
+ end;
+do_seq_set(#gen{pack=map}=Gen, Cs0, Default) ->
+ Cs1 = [{N,T} || #'ComponentType'{name=N,typespec=T} <- Cs0],
+ Cs = map_components(Gen, Cs1, Default),
+ AllLiterals = lists:all(fun({_,{literal,_}}) -> true;
+ ({_,_}) -> false
+ end, Cs),
+ case AllLiterals of
+ true ->
+ L = [{Name,Lit} || {Name,{literal,Lit}} <- Cs],
+ {literal,maps:from_list(L)};
+ false ->
+ Key = {Cs,Default},
+ DoGen = fun(Fd, Name) ->
+ S = gen_map_components(Name, Cs),
+ ok = file:write(Fd, S)
+ end,
+ Func = asn1ct_func:call_gen("is_default_cs_", Key, DoGen),
{exception,atom_to_list(Func),[]}
end.
-do_sof(Type, Default0) ->
+do_sof(Gen, Type, Default0) ->
Default = lists:sort(Default0),
Cs0 = lists:duplicate(length(Default), Type),
- Cs = components(Cs0, Default),
+ Cs = components(Gen, Cs0, Default),
case are_all_literals(Cs) of
true ->
Literal = [Lit || {literal,Lit} <- Cs],
{exception,need(check_literal_sof, 2),[Literal]};
false ->
Key = Cs,
- Gen = fun(Fd, Name) ->
- S = gen_sof(Name, Cs),
- ok = file:write(Fd, S)
+ DoGen = fun(Fd, Name) ->
+ S = gen_sof(Name, Cs),
+ ok = file:write(Fd, S)
end,
- Func = asn1ct_func:call_gen("is_default_sof", Key, Gen),
+ Func = asn1ct_func:call_gen("is_default_sof", Key, DoGen),
{exception,atom_to_list(Func),[]}
end.
@@ -199,6 +224,39 @@ gen_cs_2([], _) ->
"throw(false)\n"
"end.\n"].
+gen_map_components(Name, Cs) ->
+ [atom_to_list(Name),"(Value) ->\n",
+ "case Value of\n",
+ "#{"|gen_map_cs_1(Cs, 1, "", [])].
+
+gen_map_cs_1([{Name,{literal,Lit}}|T], I, Sep, Acc) ->
+ Var = "E"++integer_to_list(I),
+ G = Var ++ " =:= " ++ term2str(Lit),
+ [Sep,term2str(Name),":=",Var|
+ gen_map_cs_1(T, I+1, ",\n", [{guard,G}|Acc])];
+gen_map_cs_1([{Name,Exc}|T], I, Sep, Acc) ->
+ Var = "E"++integer_to_list(I),
+ [Sep,term2str(Name),":=",Var|
+ gen_map_cs_1(T, I+1, ",\n", [{exc,{Var,Exc}}|Acc])];
+gen_map_cs_1([], _, _, Acc) ->
+ G = lists:join(", ", [S || {guard,S} <- Acc]),
+ Exc = [E || {exc,E} <- Acc],
+ Body = gen_map_cs_2(Exc, ""),
+ case G of
+ [] ->
+ ["} ->\n"|Body];
+ [_|_] ->
+ ["} when ",G," ->\n"|Body]
+ end.
+
+gen_map_cs_2([{Var,{exception,Func,Args}}|T], Sep) ->
+ [Sep,Func,"(",Var,arg2str(Args),")"|gen_map_cs_2(T, ",\n")];
+gen_map_cs_2([], _) ->
+ [";\n",
+ "_ ->\n"
+ "throw(false)\n"
+ "end.\n"].
+
gen_sof(Name, Cs) ->
[atom_to_list(Name),"(Value) ->\n",
"case length(Value) of\n",
@@ -221,9 +279,18 @@ gen_sof_1([{exception,Func,Args}|Cs], I) ->
gen_sof_1([], _) ->
".\n".
-components([#type{def=Def}|Ts], [V|Vs]) ->
- [do_gen(Def, V)|components(Ts, Vs)];
-components([], []) -> [].
+components(Gen, [#type{def=Def}|Ts], [V|Vs]) ->
+ [do_gen(Gen, Def, V)|components(Gen, Ts, Vs)];
+components(_Gen, [], []) -> [].
+
+map_components(Gen, [{Name,#type{def=Def}}|Ts], Value) ->
+ case maps:find(Name, Value) of
+ {ok,V} ->
+ [{Name,do_gen(Gen, Def, V)}|map_components(Gen, Ts, Value)];
+ error ->
+ map_components(Gen, Ts, Value)
+ end;
+map_components(_Gen, [], _Value) -> [].
gen_choice(Name, Tag, Func, Args) ->
NameStr = atom_to_list(Name),
diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl
index aa7223904e..c09b0f47d1 100644
--- a/lib/asn1/src/asn1ct_gen_per.erl
+++ b/lib/asn1/src/asn1ct_gen_per.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,7 +24,6 @@
%% all types in an ASN.1 module
-include("asn1_records.hrl").
-%-compile(export_all).
-export([gen_dec_imm/2]).
-export([gen_dec_prim/3,gen_encode_prim_imm/3]).
@@ -35,33 +34,36 @@
-export([extaddgroup2sequence/1]).
-export([dialyzer_suppressions/1]).
--import(asn1ct_gen, [emit/1,demit/1]).
+-import(asn1ct_gen, [emit/1]).
-import(asn1ct_func, [call/3]).
-%% Generate ENCODING ******************************
-%%****************************************x
+%%****************************************
+%% Generate ENCODING
+%%****************************************
-dialyzer_suppressions(Erules) ->
- case asn1ct_func:is_used({Erules,complete,1}) of
+dialyzer_suppressions(#gen{erule=per,aligned=Aligned}) ->
+ Mod = case Aligned of
+ false -> uper;
+ true -> per
+ end,
+ suppress({Mod,complete,1}),
+ suppress({per_common,to_bitstring,2}),
+ emit([" ok.",nl]).
+
+suppress({M,F,A}=MFA) ->
+ case asn1ct_func:is_used(MFA) of
false ->
ok;
true ->
- emit([" _ = complete(Arg),",nl])
- end,
- emit([" ok.",nl]).
-
+ Args =
+ [lists:concat(["element(",I,", Arg)"])
+ || I <- lists:seq(1, A)],
+ emit([" ",{call,M,F,Args},com,nl])
+ end.
gen_encode(Erules,Type) when is_record(Type,typedef) ->
gen_encode_user(Erules,Type).
-%% case Type#typedef.typespec of
-%% Def when is_record(Def,type) ->
-%% gen_encode_user(Erules,Type);
-%% Def when is_tuple(Def),(element(1,Def) == 'Object') ->
-%% gen_encode_object(Erules,Type);
-%% Other ->
-%% exit({error,{asn1,{unknown,Other}}})
-%% end.
gen_encode(Erules,Typename,#'ComponentType'{name=Cname,typespec=Type}) ->
NewTypename = [Cname|Typename],
@@ -72,15 +74,14 @@ gen_encode(Erules,Typename,Type) when is_record(Type,type) ->
ObjFun =
case lists:keysearch(objfun,1,Type#type.tablecinf) of
{value,{_,_Name}} ->
-%% lists:concat([", ObjFun",Name]);
", ObjFun";
false ->
""
end,
case asn1ct_gen:type(InnerType) of
{constructed,bif} ->
- emit({"'enc_",asn1ct_gen:list2name(Typename),"'(Val",ObjFun,
- ") ->",nl}),
+ Func = enc_func(asn1ct_gen:list2name(Typename)),
+ emit([{asis,Func},"(Val",ObjFun,") ->",nl]),
asn1ct_gen:gen_encode_constructed(Erules,Typename,InnerType,Type);
_ ->
true
@@ -92,20 +93,21 @@ gen_encode_user(Erules,D) when is_record(D,typedef) ->
Typename = [D#typedef.name],
Def = D#typedef.typespec,
InnerType = asn1ct_gen:get_inner(Def#type.def),
- emit({"'enc_",asn1ct_gen:list2name(Typename),"'(Val) ->",nl}),
+ Func = enc_func(asn1ct_gen:list2name(Typename)),
+ emit([{asis,Func},"(Val) ->",nl]),
case asn1ct_gen:type(InnerType) of
{primitive,bif} ->
gen_encode_prim(Erules, Def),
- emit({".",nl});
+ emit([".",nl]);
'ASN1_OPEN_TYPE' ->
gen_encode_prim(Erules, Def#type{def='ASN1_OPEN_TYPE'}),
- emit({".",nl});
+ emit([".",nl]);
{constructed,bif} ->
asn1ct_gen:gen_encode_constructed(Erules,Typename,InnerType,D);
#'Externaltypereference'{module=CurrMod,type=Etype} ->
- emit({"'enc_",Etype,"'(Val).",nl,nl});
+ emit([{asis,enc_func(Etype)},"(Val).",nl]);
#'Externaltypereference'{module=Emod,type=Etype} ->
- emit({"'",Emod,"':'enc_",Etype,"'(Val).",nl,nl})
+ emit([{asis,Emod},":",{asis,enc_func(Etype)},"(Val).",nl])
end.
@@ -113,11 +115,7 @@ gen_encode_prim(Erules, D) ->
Value = {var,atom_to_list(asn1ct_gen:mk_var(asn1ct_name:curr(val)))},
gen_encode_prim(Erules, D, Value).
-gen_encode_prim(Erules, #type{}=D, Value) ->
- Aligned = case Erules of
- uper -> false;
- per -> true
- end,
+gen_encode_prim(#gen{erule=per,aligned=Aligned}, #type{}=D, Value) ->
Imm = gen_encode_prim_imm(Value, D, Aligned),
asn1ct_imm:enc_cg(Imm, Aligned).
@@ -224,7 +222,6 @@ gen_objectset_code(_Erules, _ObjSet) ->
gen_decode(Erules, #typedef{}=Type) ->
DecFunc = dec_func(Type#typedef.name),
emit([nl,nl,{asis,DecFunc},"(Bytes) ->",nl]),
- dbdec(Type#typedef.name),
gen_decode_user(Erules, Type).
gen_decode(Erules,Tname,#'ComponentType'{name=Cname,typespec=Type}) ->
@@ -245,17 +242,11 @@ gen_decode(Erules,Typename,Type) when is_record(Type,type) ->
emit([nl,
{asis,dec_func(asn1ct_gen:list2name(Typename))},
"(Bytes",ObjFun,") ->",nl]),
- dbdec(Typename),
asn1ct_gen:gen_decode_constructed(Erules,Typename,InnerType,Type);
_ ->
true
end.
-dbdec(Type) when is_list(Type)->
- demit({"io:format(\"decoding: ",asn1ct_gen:list2name(Type),"~w~n\",[Bytes]),",nl});
-dbdec(Type) ->
- demit({"io:format(\"decoding: ",{asis,Type},"~w~n\",[Bytes]),",nl}).
-
gen_decode_user(Erules,D) when is_record(D,typedef) ->
Typename = [D#typedef.name],
Def = D#typedef.typespec,
@@ -263,17 +254,15 @@ gen_decode_user(Erules,D) when is_record(D,typedef) ->
case asn1ct_gen:type(InnerType) of
{primitive,bif} ->
gen_dec_prim(Erules,Def,"Bytes"),
- emit({".",nl,nl});
+ emit([".",nl,nl]);
'ASN1_OPEN_TYPE' ->
gen_dec_prim(Erules,Def#type{def='ASN1_OPEN_TYPE'},"Bytes"),
- emit({".",nl,nl});
+ emit([".",nl,nl]);
{constructed,bif} ->
asn1ct_gen:gen_decode_constructed(Erules,Typename,InnerType,D);
#'Externaltypereference'{}=Etype ->
gen_dec_external(Etype, "Bytes"),
- emit([".",nl,nl]);
- Other ->
- exit({error,{asn1,{unknown,Other}}})
+ emit([".",nl,nl])
end.
gen_dec_external(Ext, BytesVar) ->
@@ -284,11 +273,7 @@ gen_dec_external(Ext, BytesVar) ->
_ -> [{asis,Mod},":"]
end,{asis,dec_func(Type)},"(",BytesVar,")"]).
-gen_dec_imm(Erule, #type{def=Name,constraint=C}) ->
- Aligned = case Erule of
- uper -> false;
- per -> true
- end,
+gen_dec_imm(#gen{erule=per,aligned=Aligned}, #type{def=Name,constraint=C}) ->
gen_dec_imm_1(Name, C, Aligned).
gen_dec_imm_1('ASN1_OPEN_TYPE', Constraint, Aligned) ->
@@ -406,10 +391,11 @@ gen_dec_prim(Erule, Type, BytesVar) ->
asn1ct_imm:dec_code_gen(Imm, BytesVar).
-%% For PER the ExtensionAdditionGroup notation has significance for the encoding and decoding
-%% the components within the ExtensionAdditionGroup is treated in a similar way as if they
-%% have been specified within a SEQUENCE, therefore we construct a fake sequence type here
-%% so that we can generate code for it
+%% For PER the ExtensionAdditionGroup notation has significance for
+%% the encoding and decoding. The components within the
+%% ExtensionAdditionGroup is treated in a similar way as if they have
+%% been specified within a SEQUENCE. Therefore we construct a fake
+%% sequence type here so that we can generate code for it.
extaddgroup2sequence(ExtList) ->
extaddgroup2sequence(ExtList,0,[]).
diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl
index 8b96242c56..231048694a 100644
--- a/lib/asn1/src/asn1ct_imm.erl
+++ b/lib/asn1/src/asn1ct_imm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -37,9 +37,12 @@
per_enc_open_type/2,
per_enc_restricted_string/3,
per_enc_small_number/2]).
--export([per_enc_extension_bit/2,per_enc_extensions/4,per_enc_optional/3]).
+-export([per_enc_extension_bit/2,per_enc_extensions/4,
+ per_enc_extensions_map/4,
+ per_enc_optional/2]).
-export([per_enc_sof/5]).
--export([enc_absent/3,enc_append/1,enc_element/2]).
+-export([enc_absent/3,enc_append/1,enc_element/2,enc_maps_get/2,
+ enc_comment/1]).
-export([enc_cg/2]).
-export([optimize_alignment/1,optimize_alignment/2,
dec_slim_cg/2,dec_code_gen/2]).
@@ -214,7 +217,8 @@ per_enc_legacy_bit_string(Val0, NNL0, Constraint0, Aligned) ->
per_enc_boolean(Val0, _Aligned) ->
{B,[Val]} = mk_vars(Val0, []),
B++build_cond([[{eq,Val,false},{put_bits,0,1,[1]}],
- [{eq,Val,true},{put_bits,1,1,[1]}]]).
+ [{eq,Val,true},{put_bits,1,1,[1]}],
+ ['_',{error,{illegal_boolean,Val}}]]).
per_enc_choice(Val0, Cs0, _Aligned) ->
{B,[Val]} = mk_vars(Val0, []),
@@ -235,7 +239,7 @@ per_enc_enumerated(Val0, Root, Aligned) ->
B++[{'cond',Cs++enumerated_error(Val)}].
enumerated_error(Val) ->
- [['_',{error,Val}]].
+ [['_',{error,{illegal_enumerated,Val}}]].
per_enc_integer(Val0, Constraint0, Aligned) ->
{B,[Val]} = mk_vars(Val0, []),
@@ -349,27 +353,32 @@ per_enc_extensions(Val0, Pos0, NumBits, Aligned) when NumBits > 0 ->
['_'|Length ++ PutBits]]}],
{var,"Extensions"}}].
-per_enc_optional(Val0, {Pos,DefVals}, _Aligned) when is_integer(Pos),
- is_list(DefVals) ->
- {B,Val} = enc_element(Pos, Val0),
+per_enc_extensions_map(Val0, Vars, Undefined, Aligned) ->
+ NumBits = length(Vars),
+ {B,[_Val,Bitmap]} = mk_vars(Val0, [bitmap]),
+ Length = per_enc_small_length(NumBits, Aligned),
+ PutBits = case NumBits of
+ 1 -> [{put_bits,1,1,[1]}];
+ _ -> [{put_bits,Bitmap,NumBits,[1]}]
+ end,
+ BitmapExpr = extensions_bitmap(Vars, Undefined),
+ B++[{assign,Bitmap,BitmapExpr},
+ {list,[{'cond',[[{eq,Bitmap,0}],
+ ['_'|Length ++ PutBits]]}],
+ {var,"Extensions"}}].
+
+per_enc_optional(Val, DefVals) when is_list(DefVals) ->
Zero = {put_bits,0,1,[1]},
One = {put_bits,1,1,[1]},
- B++[{'cond',
- [[{eq,Val,DefVal},Zero] || DefVal <- DefVals] ++ [['_',One]]}];
-per_enc_optional(Val0, {Pos,{call,M,F,A}}, _Aligned) when is_integer(Pos) ->
- {B,Val} = enc_element(Pos, Val0),
+ [{'cond',
+ [[{eq,Val,DefVal},Zero] || DefVal <- DefVals] ++ [['_',One]]}];
+per_enc_optional(Val, {call,M,F,A}) ->
{[],[[],Tmp]} = mk_vars([], [tmp]),
Zero = {put_bits,0,1,[1]},
One = {put_bits,1,1,[1]},
- B++[{call,M,F,[Val|A],Tmp},
- {'cond',
- [[{eq,Tmp,true},Zero],['_',One]]}];
-per_enc_optional(Val0, Pos, _Aligned) when is_integer(Pos) ->
- {B,Val} = enc_element(Pos, Val0),
- Zero = {put_bits,0,1,[1]},
- One = {put_bits,1,1,[1]},
- B++[{'cond',[[{eq,Val,asn1_NOVALUE},Zero],
- ['_',One]]}].
+ [{call,M,F,[Val|A],Tmp},
+ {'cond',
+ [[{eq,Tmp,true},Zero],['_',One]]}].
per_enc_sof(Val0, Constraint, ElementVar, ElementImm, Aligned) ->
{B,[Val,Len]} = mk_vars(Val0, [len]),
@@ -423,6 +432,16 @@ enc_element(N, Val0) ->
{[],[Val,Dst]} = mk_vars(Val0, [element]),
{[{call,erlang,element,[N,Val],Dst}],Dst}.
+enc_maps_get(N, Val0) ->
+ {[],[Val,Dst0]} = mk_vars(Val0, [element]),
+ {var,Dst} = Dst0,
+ DstExpr = {expr,lists:concat(["#{",N,":=",Dst,"}"])},
+ {var,SrcVar} = Val,
+ {[{assign,DstExpr,SrcVar}],Dst0}.
+
+enc_comment(Comment) ->
+ {comment,Comment}.
+
enc_cg(Imm0, false) ->
Imm1 = enc_cse(Imm0),
Imm2 = enc_pre_cg(Imm1),
@@ -860,10 +879,8 @@ flatten_map_cs_1([integer_default], {Int,_}) ->
[{'_',Int}];
flatten_map_cs_1([enum_default], {Int,_}) ->
[{'_',["{asn1_enum,",Int,"}"]}];
-flatten_map_cs_1([enum_error], {Var,Cs}) ->
- Vs = [V || {_,V} <- Cs],
- [{'_',["exit({error,{asn1,{decode_enumerated,{",Var,",",
- {asis,Vs},"}}}})"]}];
+flatten_map_cs_1([enum_error], {Var,_}) ->
+ [{'_',["exit({error,{asn1,{decode_enumerated,",Var,"}}})"]}];
flatten_map_cs_1([], _) -> [].
flatten_hoist_align([[{align_bits,_,_}=Ab|T]|Cs]) ->
@@ -1037,6 +1054,7 @@ split_off_nonbuilding(Imm) ->
is_nonbuilding({assign,_,_}) -> true;
is_nonbuilding({call,_,_,_,_}) -> true;
+is_nonbuilding({comment,_}) -> true;
is_nonbuilding({lc,_,_,_,_}) -> true;
is_nonbuilding({set,_,_}) -> true;
is_nonbuilding({list,_,_}) -> true;
@@ -1093,7 +1111,7 @@ per_enc_integer_1(Val0, [{{_,_}=Constr,[]}], Aligned) ->
per_enc_integer_1(Val0, [Constr], Aligned) ->
{Prefix,Check,Action} = per_enc_integer_2(Val0, Constr, Aligned),
Prefix++build_cond([[Check|Action],
- ['_',{error,Val0}]]).
+ ['_',{error,{illegal_integer,Val0}}]]).
per_enc_integer_2(Val, {'SingleValue',Sv}, Aligned) when is_integer(Sv) ->
per_enc_constrained(Val, Sv, Sv, Aligned);
@@ -1240,6 +1258,20 @@ enc_length(Len, {Lb,Ub}, Aligned) when is_integer(Lb) ->
enc_length(Len, Sv, _Aligned) when is_integer(Sv) ->
[{'cond',[[{eq,Len,Sv}]]}].
+extensions_bitmap(Vs, Undefined) ->
+ Highest = 1 bsl (length(Vs)-1),
+ Cs = extensions_bitmap_1(Vs, Undefined, Highest),
+ lists:flatten(lists:join(" bor ", Cs)).
+
+extensions_bitmap_1([{var,V}|Vs], Undefined, Power) ->
+ S = ["case ",V," of\n",
+ " ",Undefined," -> 0;\n"
+ " _ -> ",integer_to_list(Power),"\n"
+ "end"],
+ [S|extensions_bitmap_1(Vs, Undefined, Power bsr 1)];
+extensions_bitmap_1([], _, _) ->
+ [].
+
put_bits_binary(Bin, _Unit, Aligned) when is_binary(Bin) ->
Sz = byte_size(Bin),
<<Int:Sz/unit:8>> = Bin,
@@ -1903,6 +1935,8 @@ enc_opt({'cond',Cs0}, St0) ->
{Cs,Type} = enc_opt_cond_1(Cs1, Type0, [{Cond,Imm}]),
{{'cond',Cs},St0#ost{t=Type}}
end;
+enc_opt({comment,_}=Imm, St) ->
+ {Imm,St#ost{t=undefined}};
enc_opt({cons,H0,T0}, St0) ->
{H,#ost{t=TypeH}=St1} = enc_opt(H0, St0),
{T,#ost{t=TypeT}=St} = enc_opt(T0, St1),
@@ -2292,6 +2326,9 @@ enc_cg({block,Imm}) ->
enc_cg(Imm),
emit([nl,
"end"]);
+enc_cg({seq,{comment,Comment},Then}) ->
+ emit(["%% ",Comment,nl]),
+ enc_cg(Then);
enc_cg({seq,First,Then}) ->
enc_cg(First),
emit([com,nl]),
@@ -2325,9 +2362,9 @@ enc_cg({'cond',Cs}) ->
enc_cg_cond(Cs);
enc_cg({error,Error}) when is_function(Error, 0) ->
Error();
-enc_cg({error,Var0}) ->
+enc_cg({error,{Tag,Var0}}) ->
Var = mk_val(Var0),
- emit(["exit({error,{asn1,{illegal_value,",Var,"}}})"]);
+ emit(["exit({error,{asn1,{",Tag,",",Var,"}}})"]);
enc_cg({integer,Int}) ->
emit(mk_val(Int));
enc_cg({lc,Body,Var,List}) ->
@@ -2590,6 +2627,8 @@ enc_opt_al({call,per_common,encode_unconstrained_number,[_]}=Call, _) ->
{[Call],0};
enc_opt_al({call,_,_,_,_}=Call, Al) ->
{[Call],Al};
+enc_opt_al({comment,_}=Imm, Al) ->
+ {[Imm],Al};
enc_opt_al({'cond',Cs0}, Al0) ->
{Cs,Al} = enc_opt_al_cond(Cs0, Al0),
{[{'cond',Cs}],Al};
@@ -2686,6 +2725,8 @@ per_fixup([{block,Block}|T]) ->
[{block,per_fixup(Block)}|per_fixup(T)];
per_fixup([{'assign',_,_}=H|T]) ->
[H|per_fixup(T)];
+per_fixup([{comment,_}=H|T]) ->
+ [H|per_fixup(T)];
per_fixup([{'cond',Cs0}|T]) ->
Cs = [[C|per_fixup(Act)] || [C|Act] <- Cs0],
[{'cond',Cs}|per_fixup(T)];
diff --git a/lib/asn1/src/asn1ct_name.erl b/lib/asn1/src/asn1ct_name.erl
index 72d541cbbc..281608f3ae 100644
--- a/lib/asn1/src/asn1ct_name.erl
+++ b/lib/asn1/src/asn1ct_name.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -20,7 +20,6 @@
%%
-module(asn1ct_name).
-%%-compile(export_all).
-export([start/0,
curr/1,
clear/0,
@@ -44,7 +43,6 @@ start() ->
end.
name_server_loop({Ref, Parent} = Monitor,Vars) ->
-%% io:format("name -- ~w~n",[Vars]),
receive
{_From,clear} ->
name_server_loop(Monitor, []);
diff --git a/lib/asn1/src/asn1ct_parser2.erl b/lib/asn1/src/asn1ct_parser2.erl
index 2de9b0e2f0..35c921e98d 100644
--- a/lib/asn1/src/asn1ct_parser2.erl
+++ b/lib/asn1/src/asn1ct_parser2.erl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1496,7 +1496,7 @@ parse_ContentsConstraint([{'ENCODED',_},{'BY',_}|Rest]) ->
parse_ContentsConstraint(Tokens) ->
parse_error(Tokens).
-% X.683 Parameterization of ASN.1 specifications
+%% X.683 Parameterization of ASN.1 specifications
parse_Governor(Tokens) ->
Flist = [fun parse_Type/1,
diff --git a/lib/asn1/src/asn1ct_value.erl b/lib/asn1/src/asn1ct_value.erl
index 57cd3f8af6..05fe2f4ef4 100644
--- a/lib/asn1/src/asn1ct_value.erl
+++ b/lib/asn1/src/asn1ct_value.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,18 +19,17 @@
%%
%%
-module(asn1ct_value).
--compile([{nowarn_deprecated_function,{asn1rt,utf8_list_to_binary,1}}]).
%% Generate Erlang values for ASN.1 types.
%% The value is randomized within it's constraints
-include("asn1_records.hrl").
-%-compile(export_all).
-export([from_type/2]).
-%% Generate examples of values ******************************
-%%****************************************x
+%%****************************************
+%% Generate examples of values
+%%****************************************
from_type(M,Typename) ->
@@ -65,7 +64,11 @@ from_type(M,Typename,Type) when is_record(Type,type) ->
end;
{constructed,bif} when Typename == ['EXTERNAL'] ->
Val=from_type_constructed(M,Typename,InnerType,Type),
- asn1ct_eval_ext:transform_to_EXTERNAL1994(Val);
+ T = case M:maps() of
+ false -> transform_to_EXTERNAL1994;
+ true -> transform_to_EXTERNAL1994_maps
+ end,
+ asn1ct_eval_ext:T(Val);
{constructed,bif} ->
from_type_constructed(M,Typename,InnerType,Type)
end;
@@ -89,9 +92,6 @@ get_inner(T) when is_tuple(T) ->
Other ->
Other
end.
-%%get_inner(T) when is_tuple(T) -> element(1,T).
-
-
from_type_constructed(M,Typename,InnerType,D) when is_record(D,type) ->
case InnerType of
@@ -108,9 +108,7 @@ from_type_constructed(M,Typename,InnerType,D) when is_record(D,type) ->
'SET OF' ->
{_,Type} = D#type.def,
NameSuffix = asn1ct_gen:constructed_suffix(InnerType,Type#type.def),
- get_sequence_of(M,Typename,D,NameSuffix);
- _ ->
- exit({nyi,InnerType})
+ get_sequence_of(M,Typename,D,NameSuffix)
end.
get_sequence(M,Typename,Type) ->
@@ -119,11 +117,13 @@ get_sequence(M,Typename,Type) ->
#'SEQUENCE'{components=Cl} -> {'SEQUENCE',Cl};
#'SET'{components=Cl} -> {'SET',to_textual_order(Cl)}
end,
- case get_components(M,Typename,CompList) of
- [] ->
- {list_to_atom(asn1ct_gen:list2rname(Typename))};
- C ->
- list_to_tuple([list_to_atom(asn1ct_gen:list2rname(Typename))|C])
+ Cs = get_components(M, Typename, CompList),
+ case M:maps() of
+ false ->
+ RecordTag = list_to_atom(asn1ct_gen:list2rname(Typename)),
+ list_to_tuple([RecordTag|[Val || {_,Val} <- Cs]]);
+ true ->
+ maps:from_list(Cs)
end.
get_components(M,Typename,{Root,Ext}) ->
@@ -131,9 +131,9 @@ get_components(M,Typename,{Root,Ext}) ->
%% Should enhance this *** HERE *** with proper handling of extensions
-get_components(M,Typename,[H|T]) ->
- [from_type(M,Typename,H)|
- get_components(M,Typename,T)];
+get_components(M, Typename, [H|T]) ->
+ #'ComponentType'{name=Name} = H,
+ [{Name,from_type(M, Typename, H)}|get_components(M, Typename, T)];
get_components(_,_,[]) ->
[].
@@ -142,7 +142,8 @@ get_choice(M,Typename,Type) ->
case TCompList of
[] ->
{asn1_EMPTY,asn1_EMPTY};
- {CompList,ExtList} -> % Should be enhanced to handle extensions too
+ {CompList,ExtList} ->
+ %% should be enhanced to handle extensions too.
CList = CompList ++ ExtList,
C = lists:nth(random(length(CList)),CList),
{C#'ComponentType'.name,from_type(M,Typename,C)};
@@ -242,14 +243,6 @@ from_type_prim(M, D) ->
_ ->
{2#11111111,2,2}
end;
-%% Sign1 = random_sign(integer),
-%% Sign2 = random_sign(integer),
-%% {Sign1*random(10000),2,Sign2*random(1028)};
-%% 2 ->
-%% %% base 10 tuple format
-%% Sign1 = random_sign(integer),
-%% Sign2 = random_sign(integer),
-%% {Sign1*random(10000),10,Sign2*random(1028)};
_ ->
%% base 10 string format, NR3 format
case random(2) of
@@ -292,12 +285,12 @@ from_type_prim(M, D) ->
'BMPString' ->
adjust_list(size_random(C),c_string(C,"BMPString"));
'UTF8String' ->
- {ok,Res}=asn1rt:utf8_list_to_binary(adjust_list(random(50),[$U,$T,$F,$8,$S,$t,$r,$i,$n,$g,16#ffff,16#fffffff,16#ffffff,16#fffff,16#fff])),
- Res;
+ L = adjust_list(random(50),
+ [$U,$T,$F,$8,$S,$t,$r,$i,$n,$g,
+ 16#ffff,16#ffee,16#10ffff,16#ffff,16#fff]),
+ unicode:characters_to_binary(L);
'UniversalString' ->
- adjust_list(size_random(C),c_string(C,"UniversalString"));
- XX ->
- exit({asn1_error,nyi,XX})
+ adjust_list(size_random(C),c_string(C,"UniversalString"))
end.
c_string(C,Default) ->
@@ -336,22 +329,6 @@ random_unnamed_bit_string(M, C) ->
{PadLen,<<BitString/bitstring,0:PadLen>>}
end.
-%% FIXME:
-%% random_sign(integer) ->
-%% case random(2) of
-%% 2 ->
-%% -1;
-%% _ ->
-%% 1
-%% end;
-%% random_sign(string) ->
-%% case random(2) of
-%% 2 ->
-%% "-";
-%% _ ->
-%% ""
-%% end.
-
random(Upper) ->
rand:uniform(Upper).
@@ -402,13 +379,6 @@ c_random(VRange,Single) ->
S;
{_,S} when is_list(S) ->
lists:nth(random(length(S)),S)
-%% {S1,S2} ->
-%% io:format("asn1ct_value: hejsan hoppsan~n");
-%% _ ->
-%% io:format("asn1ct_value: hejsan hoppsan 2~n")
-%% io:format("asn1ct_value: c_random/2: S1 = ~w~n"
-%% "S2 = ~w,~n",[S1,S2])
-%% exit(self(),goodbye)
end.
adjust_list(Len,Orig) ->
diff --git a/lib/asn1/src/asn1rt.erl b/lib/asn1/src/asn1rt.erl
deleted file mode 100644
index 3e09ce2252..0000000000
--- a/lib/asn1/src/asn1rt.erl
+++ /dev/null
@@ -1,184 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
--module(asn1rt).
--deprecated(module).
-
-%% Runtime functions for ASN.1 (i.e encode, decode)
-
--export([encode/2,encode/3,decode/3,load_driver/0,unload_driver/0,info/1]).
-
--export([utf8_binary_to_list/1,utf8_list_to_binary/1]).
-
-encode(Module,{Type,Term}) ->
- encode(Module,Type,Term).
-
-encode(Module,Type,Term) ->
- case catch apply(Module,encode,[Type,Term]) of
- {'EXIT',undef} ->
- {error,{asn1,{undef,Module,Type}}};
- Result ->
- Result
- end.
-
-decode(Module,Type,Bytes) ->
- case catch apply(Module,decode,[Type,Bytes]) of
- {'EXIT',undef} ->
- {error,{asn1,{undef,Module,Type}}};
- Result ->
- Result
- end.
-
-%% Remove in R16A
-load_driver() ->
- ok.
-
-unload_driver() ->
- ok.
-
-info(Module) ->
- case catch apply(Module,info,[]) of
- {'EXIT',{undef,_Reason}} ->
- {error,{asn1,{undef,Module,info}}};
- Result ->
- {ok,Result}
- end.
-
-%% utf8_binary_to_list/1 transforms a utf8 encoded binary to a list of
-%% unicode elements, where each element is the unicode integer value
-%% of a utf8 character.
-%% Bin is a utf8 encoded value. The return value is either {ok,Val} or
-%% {error,Reason}. Val is a list of integers, where each integer is a
-%% unicode character value.
-utf8_binary_to_list(Bin) when is_binary(Bin) ->
- utf8_binary_to_list(Bin,[]).
-
-utf8_binary_to_list(<<>>,Acc) ->
- {ok,lists:reverse(Acc)};
-utf8_binary_to_list(Bin,Acc) ->
- Len = utf8_binary_len(Bin),
- case catch split_binary(Bin,Len) of
- {CharBin,RestBin} ->
- case utf8_binary_char(CharBin) of
- C when is_integer(C) ->
- utf8_binary_to_list(RestBin,[C|Acc]);
- Err -> Err
- end;
- Err -> {error,{asn1,{bad_encoded_utf8string,Err}}}
- end.
-
-utf8_binary_len(<<0:1,_:7,_/binary>>) ->
- 1;
-utf8_binary_len(<<1:1,1:1,0:1,_:5,_/binary>>) ->
- 2;
-utf8_binary_len(<<1:1,1:1,1:1,0:1,_:4,_/binary>>) ->
- 3;
-utf8_binary_len(<<1:1,1:1,1:1,1:1,0:1,_:3,_/binary>>) ->
- 4;
-utf8_binary_len(<<1:1,1:1,1:1,1:1,1:1,0:1,_:2,_/binary>>) ->
- 5;
-utf8_binary_len(<<1:1,1:1,1:1,1:1,1:1,1:1,0:1,_:1,_/binary>>) ->
- 6;
-utf8_binary_len(Bin) ->
- {error,{asn1,{bad_utf8_length,Bin}}}.
-
-utf8_binary_char(<<0:1,Int:7>>) ->
- Int;
-utf8_binary_char(<<_:2,0:1,Int1:5,1:1,0:1,Int2:6>>) ->
- (Int1 bsl 6) bor Int2;
-utf8_binary_char(<<_:3,0:1,Int1:4,1:1,0:1,Int2:6,1:1,0:1,Int3:6>>) ->
- <<Res:16>> = <<Int1:4,Int2:6,Int3:6>>,
- Res;
-utf8_binary_char(<<_:4,0:1,Int1:3,Rest/binary>>) ->
- <<1:1,0:1,Int2:6,1:1,0:1,Int3:6,1:1,0:1,Int4:6>> = Rest,
- <<Res:24>> = <<0:3,Int1:3,Int2:6,Int3:6,Int4:6>>,
- Res;
-utf8_binary_char(<<_:5,0:1,Int1:2,Rest/binary>>) ->
- <<1:1,0:1,Int2:6,1:1,0:1,Int3:6,1:1,0:1,Int4:6,1:1,0:1,Int5:6>> = Rest,
- <<Res:32>> = <<0:6,Int1:2,Int2:6,Int3:6,Int4:6,Int5:6>>,
- Res;
-utf8_binary_char(<<_:6,0:1,I:1,Rest/binary>>) ->
- <<1:1,0:1,Int2:6,1:1,0:1,Int3:6,1:1,0:1,Int4:6,1:1,0:1,
- Int5:6,1:1,0:1,Int6:6>> = Rest,
- <<Res:32>> = <<0:1,I:1,Int2:6,Int3:6,Int4:6,Int5:6,Int6:6>>,
- Res;
-utf8_binary_char(Err) ->
- {error,{asn1,{bad_utf8_character_encoding,Err}}}.
-
-
-%% macros used for utf8 encoding
--define(bit1to6_into_utf8byte(I),16#80 bor (I band 16#3f)).
--define(bit7to12_into_utf8byte(I),16#80 bor ((I band 16#fc0) bsr 6)).
--define(bit13to18_into_utf8byte(I),16#80 bor ((I band 16#3f000) bsr 12)).
--define(bit19to24_into_utf8byte(I),16#80 bor ((Int band 16#fc0000) bsr 18)).
--define(bit25to30_into_utf8byte(I),16#80 bor ((Int band 16#3f000000) bsr 24)).
-
-%% utf8_list_to_binary/1 transforms a list of integers to a
-%% binary. Each element in the input list has the unicode (integer)
-%% value of an utf8 character.
-%% The return value is either {ok,Bin} or {error,Reason}. The
-%% resulting binary is utf8 encoded.
-utf8_list_to_binary(List) ->
- utf8_list_to_binary(List,[]).
-
-utf8_list_to_binary([],Acc) when is_list(Acc) ->
- {ok,list_to_binary(lists:reverse(Acc))};
-utf8_list_to_binary([],Acc) ->
- {error,{asn1,Acc}};
-utf8_list_to_binary([H|T],Acc) ->
- case catch utf8_encode(H,Acc) of
- NewAcc when is_list(NewAcc) ->
- utf8_list_to_binary(T,NewAcc);
- Err -> Err
- end.
-
-
-utf8_encode(Int,Acc) when Int < 128 ->
- %% range 16#00000000 - 16#0000007f
- %% utf8 encoding: 0xxxxxxx
- [Int|Acc];
-utf8_encode(Int,Acc) when Int < 16#800 ->
- %% range 16#00000080 - 16#000007ff
- %% utf8 encoding: 110xxxxx 10xxxxxx
- [?bit1to6_into_utf8byte(Int),16#c0 bor (Int bsr 6)|Acc];
-utf8_encode(Int,Acc) when Int < 16#10000 ->
- %% range 16#00000800 - 16#0000ffff
- %% utf8 encoding: 1110xxxx 10xxxxxx 10xxxxxx
- [?bit1to6_into_utf8byte(Int),?bit7to12_into_utf8byte(Int),
- 16#e0 bor ((Int band 16#f000) bsr 12)|Acc];
-utf8_encode(Int,Acc) when Int < 16#200000 ->
- %% range 16#00010000 - 16#001fffff
- %% utf8 encoding: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- [?bit1to6_into_utf8byte(Int),?bit7to12_into_utf8byte(Int),
- ?bit13to18_into_utf8byte(Int),
- 16#f0 bor ((Int band 16#1c0000) bsr 18)|Acc];
-utf8_encode(Int,Acc) when Int < 16#4000000 ->
- %% range 16#00200000 - 16#03ffffff
- %% utf8 encoding: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
- [?bit1to6_into_utf8byte(Int),?bit7to12_into_utf8byte(Int),
- ?bit13to18_into_utf8byte(Int),?bit19to24_into_utf8byte(Int),
- 16#f8 bor ((Int band 16#3000000) bsr 24)|Acc];
-utf8_encode(Int,Acc) ->
- %% range 16#04000000 - 16#7fffffff
- %% utf8 encoding: 1111110x 10xxxxxx ...(total 6 bytes) 10xxxxxx
- [?bit1to6_into_utf8byte(Int),?bit7to12_into_utf8byte(Int),
- ?bit13to18_into_utf8byte(Int),?bit19to24_into_utf8byte(Int),
- ?bit25to30_into_utf8byte(Int),
- 16#fc bor ((Int band 16#40000000) bsr 30)|Acc].
diff --git a/lib/asn1/src/asn1rt_nif.erl b/lib/asn1/src/asn1rt_nif.erl
index ff464885f6..a62b476644 100644
--- a/lib/asn1/src/asn1rt_nif.erl
+++ b/lib/asn1/src/asn1rt_nif.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
decode_ber_tlv/1,
encode_ber_tlv/1]).
+-compile(no_native).
-on_load(load_nif/0).
-define(ASN1_NIF_VSN,1).
diff --git a/lib/asn1/src/asn1rtt_ber.erl b/lib/asn1/src/asn1rtt_ber.erl
index fdb9b9061f..d1cd22579b 100644
--- a/lib/asn1/src/asn1rtt_ber.erl
+++ b/lib/asn1/src/asn1rtt_ber.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -92,7 +92,7 @@
-define(N_BMPString, 30).
-% the complete tag-word of built-in types
+%% The complete tag-word of built-in types
-define(T_BOOLEAN, ?UNIVERSAL bor ?PRIMITIVE bor 1).
-define(T_INTEGER, ?UNIVERSAL bor ?PRIMITIVE bor 2).
-define(T_BIT_STRING, ?UNIVERSAL bor ?PRIMITIVE bor 3). % can be CONSTRUCTED
@@ -137,11 +137,11 @@ ber_decode_erlang(Tlv) ->
decode_primitive(Bin) ->
{Form,TagNo,V,Rest} = decode_tag_and_length(Bin),
case Form of
- 1 -> % constructed
+ 1 -> % constructed
{{TagNo,decode_constructed(V)},Rest};
- 0 -> % primitive
+ 0 -> % primitive
{{TagNo,V},Rest};
- 2 -> % constructed indefinite
+ 2 -> % constructed indefinite
{Vlist,Rest2} = decode_constructed_indefinite(V,[]),
{{TagNo,Vlist},Rest2}
end.
@@ -165,31 +165,30 @@ decode_primitive_incomplete([[default,TagNo]],Bin) -> %default
{Form,TagNo,V,Rest} ->
decode_incomplete2(Form,TagNo,V,[],Rest);
_ ->
- %{asn1_DEFAULT,Bin}
asn1_NOVALUE
end;
-decode_primitive_incomplete([[default,TagNo,Directives]],Bin) -> %default, constructed type, Directives points into this type
+decode_primitive_incomplete([[default,TagNo,Directives]],Bin) ->
+ %% default, constructed type, Directives points into this type
case decode_tag_and_length(Bin) of
{Form,TagNo,V,Rest} ->
decode_incomplete2(Form,TagNo,V,Directives,Rest);
_ ->
- %{asn1_DEFAULT,Bin}
asn1_NOVALUE
end;
-decode_primitive_incomplete([[opt,TagNo]],Bin) -> %optional
+decode_primitive_incomplete([[opt,TagNo]],Bin) ->
+ %% optional
case decode_tag_and_length(Bin) of
{Form,TagNo,V,Rest} ->
decode_incomplete2(Form,TagNo,V,[],Rest);
_ ->
- %{{TagNo,asn1_NOVALUE},Bin}
asn1_NOVALUE
end;
-decode_primitive_incomplete([[opt,TagNo,Directives]],Bin) -> %optional
+decode_primitive_incomplete([[opt,TagNo,Directives]],Bin) ->
+ %% optional
case decode_tag_and_length(Bin) of
{Form,TagNo,V,Rest} ->
decode_incomplete2(Form,TagNo,V,Directives,Rest);
_ ->
- %{{TagNo,asn1_NOVALUE},Bin}
asn1_NOVALUE
end;
%% An optional that shall be undecoded
@@ -236,7 +235,8 @@ decode_primitive_incomplete([[alt_parts,TagNo]|RestAlts],Bin) ->
_ ->
decode_primitive_incomplete(RestAlts,Bin)
end;
-decode_primitive_incomplete([[undec,_TagNo]|_RestTag],Bin) -> %incomlete decode
+decode_primitive_incomplete([[undec,_TagNo]|_RestTag],Bin) ->
+ %% incomlete decode
decode_incomplete_bin(Bin);
decode_primitive_incomplete([[parts,TagNo]|_RestTag],Bin) ->
case decode_tag_and_length(Bin) of
@@ -301,7 +301,8 @@ decode_constructed_incomplete(Directives=[[Alt,_]|_],Bin)
{TagNo,Tlv};
{alt_parts,_} ->
[{TagNo,decode_parts_incomplete(V)}];
- no_match -> %% if a choice alternative was encoded that
+ no_match ->
+ %% if a choice alternative was encoded that
%% was not specified in the config file,
%% thus decode component anonomous.
{Tlv,_}=decode_primitive(Bin),
@@ -546,7 +547,7 @@ decode_tag_and_length(<<Class:2, Form:1, 31:5, Buffer/binary>>) ->
decode_tag(<<0:1,PartialTag:7, Buffer/binary>>, TagAck) ->
TagNo = (TagAck bsl 7) bor PartialTag,
{TagNo, Buffer};
-% more tags
+%% more tags
decode_tag(<<_:1,PartialTag:7, Buffer/binary>>, TagAck) ->
TagAck1 = (TagAck bsl 7) bor PartialTag,
decode_tag(Buffer, TagAck1).
@@ -941,12 +942,12 @@ encode_bit_string_bits(C, BitListVal, _NamedBitList, TagIn) when is_list(BitList
case length(BitListVal) of
BitSize when BitSize == Size ->
{Len, Unused, OctetList} = encode_bitstring(BitListVal),
- %%add unused byte to the Len
+ %% add unused byte to the Len
encode_tags(TagIn, [Unused | OctetList], Len+1);
BitSize when BitSize < Size ->
PaddedList = pad_bit_list(Size-BitSize,BitListVal),
{Len, Unused, OctetList} = encode_bitstring(PaddedList),
- %%add unused byte to the Len
+ %% add unused byte to the Len
encode_tags(TagIn, [Unused | OctetList], Len+1);
BitSize ->
exit({error,{asn1,
diff --git a/lib/asn1/src/asn1rtt_ext.erl b/lib/asn1/src/asn1rtt_ext.erl
index 3bf01823db..f028e33888 100644
--- a/lib/asn1/src/asn1rtt_ext.erl
+++ b/lib/asn1/src/asn1rtt_ext.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -19,7 +19,8 @@
%%
-module(asn1rtt_ext).
--export([transform_to_EXTERNAL1990/1,transform_to_EXTERNAL1994/1]).
+-export([transform_to_EXTERNAL1990/1,transform_to_EXTERNAL1990_maps/1,
+ transform_to_EXTERNAL1994/1,transform_to_EXTERNAL1994_maps/1]).
transform_to_EXTERNAL1990({_,_,_,_}=Val) ->
transform_to_EXTERNAL1990(tuple_to_list(Val), []);
@@ -51,6 +52,30 @@ transform_to_EXTERNAL1990([Data_value], Acc)
list_to_tuple(lists:reverse([{'octet-aligned',Data_value}|Acc])).
+transform_to_EXTERNAL1990_maps(#{identification:=Id,'data-value':=Value}=V) ->
+ M0 = case Id of
+ {syntax,DRef} ->
+ #{'direct-reference'=>DRef};
+ {'presentation-context-id',IndRef} ->
+ #{'indirect-reference'=>IndRef};
+ {'context-negotiation',
+ #{'presentation-context-id':=IndRef,
+ 'transfer-syntax':=DRef}} ->
+ #{'direct-reference'=>DRef,
+ 'indirect-reference'=>IndRef}
+ end,
+ M = case V of
+ #{'data-value-descriptor':=Dvd} ->
+ M0#{'data-value-descriptor'=>Dvd};
+ #{} ->
+ M0
+ end,
+ M#{encoding=>{'octet-aligned',Value}};
+transform_to_EXTERNAL1990_maps(#{encoding:=_}=V) ->
+ %% Already in the EXTERNAL 1990 format.
+ V.
+
+
transform_to_EXTERNAL1994({'EXTERNAL',DRef,IndRef,Data_v_desc,Encoding}=V) ->
Identification =
case {DRef,IndRef} of
@@ -71,3 +96,38 @@ transform_to_EXTERNAL1994({'EXTERNAL',DRef,IndRef,Data_v_desc,Encoding}=V) ->
%% information.
V
end.
+
+transform_to_EXTERNAL1994_maps(V0) ->
+ Identification =
+ case V0 of
+ #{'direct-reference':=DRef,
+ 'indirect-reference':=asn1_NOVALUE} ->
+ {syntax,DRef};
+ #{'direct-reference':=asn1_NOVALUE,
+ 'indirect-reference':=IndRef} ->
+ {'presentation-context-id',IndRef};
+ #{'direct-reference':=DRef,
+ 'indirect-reference':=IndRef} ->
+ {'context-negotiation',
+ #{'transfer-syntax'=>DRef,
+ 'presentation-context-id'=>IndRef}}
+ end,
+ case V0 of
+ #{encoding:={'octet-aligned',Val}}
+ when is_list(Val); is_binary(Val) ->
+ %% Transform to the EXTERNAL 1994 definition.
+ V = #{identification=>Identification,
+ 'data-value'=>Val},
+ case V0 of
+ #{'data-value-descriptor':=asn1_NOVALUE} ->
+ V;
+ #{'data-value-descriptor':=Dvd} ->
+ V#{'data-value-descriptor'=>Dvd}
+ end;
+ _ ->
+ %% Keep the EXTERNAL 1990 definition to avoid losing
+ %% information.
+ V = [{K,V} || {K,V} <- maps:to_list(V0),
+ V =/= asn1_NOVALUE],
+ maps:from_list(V)
+ end.
diff --git a/lib/asn1/src/asn1rtt_per_common.erl b/lib/asn1/src/asn1rtt_per_common.erl
index 3896cb7fa5..5b5f47dfee 100644
--- a/lib/asn1/src/asn1rtt_per_common.erl
+++ b/lib/asn1/src/asn1rtt_per_common.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -140,6 +140,8 @@ encode_relative_oid(Val) when is_tuple(Val) ->
encode_relative_oid(Val) when is_list(Val) ->
list_to_binary([e_object_element(X)||X <- Val]).
+encode_unconstrained_number(Val) when not is_integer(Val) ->
+ exit({error,{asn1,{illegal_integer,Val}}});
encode_unconstrained_number(Val) when Val >= 0 ->
if
Val < 16#80 ->
@@ -540,6 +542,7 @@ extension_bitmap(_Val, Pos, Limit, Acc) when Pos >= Limit ->
extension_bitmap(Val, Pos, Limit, Acc) ->
Bit = case element(Pos, Val) of
asn1_NOVALUE -> 0;
+ asn1_DEFAULT -> 0;
_ -> 1
end,
extension_bitmap(Val, Pos+1, Limit, (Acc bsl 1) bor Bit).
diff --git a/lib/asn1/test/Makefile b/lib/asn1/test/Makefile
index 0716d79291..c38d1c6ebd 100644
--- a/lib/asn1/test/Makefile
+++ b/lib/asn1/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2017. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -43,6 +43,7 @@ MODULES= \
testChoTypeRefSet \
testConstraints \
testDef \
+ testExtensionDefault \
testOpt \
testSeqDefault \
testSeqExtension \
@@ -82,6 +83,7 @@ MODULES= \
testInfObjExtract \
testParameterizedInfObj \
testFragmented \
+ testMaps \
testMergeCompile \
testMultipleLevels \
testDeepTConstr \
@@ -114,8 +116,7 @@ MODULES= \
testImporting \
testExtensibilityImplied \
asn1_test_lib \
- asn1_app_test \
- asn1_appup_test \
+ asn1_app_SUITE \
asn1_SUITE \
error_SUITE \
syntax_SUITE
@@ -134,7 +135,7 @@ RELSYSDIR = $(RELEASE_PATH)/asn1_test
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
-ERL_COMPILE_FLAGS += +warnings_as_errors
+ERL_COMPILE_FLAGS += +warnings_as_errors +nowarn_export_all
EBIN = .
# ----------------------------------------------------
diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl
index b6430134ab..bfeffa969f 100644
--- a/lib/asn1/test/asn1_SUITE.erl
+++ b/lib/asn1/test/asn1_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,6 +21,9 @@
-module(asn1_SUITE).
+%% Suppress compilation of an addititional module compiled for maps.
+-define(NO_MAPS_MODULE, asn1_test_lib_no_maps).
+
-define(only_ber(Func),
if Rule =:= ber -> Func;
true -> ok
@@ -39,10 +42,11 @@ suite() ->
{timetrap,{minutes,60}}].
all() ->
- [{group, compile},
+ [xref,
+ xref_export_all,
+
+ {group, compile},
{group, parallel},
- {group, app_test},
- {group, appup_test},
% TODO: Investigate parallel running of these:
testComment,
@@ -64,13 +68,8 @@ groups() ->
ber_optional,
tagdefault_automatic]},
- {app_test, [], [{asn1_app_test, all}]},
-
- {appup_test, [], [{asn1_appup_test, all}]},
-
{parallel, Parallel,
[cover,
- xref,
{group, ber},
% Uses 'P-Record', 'Constraints', 'MEDIA-GATEWAY-CONTROL'...
{group, [], [parse,
@@ -102,6 +101,7 @@ groups() ->
testMultipleLevels,
testOpt,
testSeqDefault,
+ testMaps,
% Uses 'External'
{group, [], [testExternal,
testSeqExtension]},
@@ -147,6 +147,7 @@ groups() ->
testImport,
testDER,
testDEFAULT,
+ testExtensionDefault,
testMvrasn6,
testContextSwitchingTypes,
testOpenTypeImplicitTag,
@@ -176,8 +177,11 @@ groups() ->
{performance, [],
[testTimer_ber,
+ testTimer_ber_maps,
testTimer_per,
- testTimer_uper]}].
+ testTimer_per_maps,
+ testTimer_uper,
+ testTimer_uper_maps]}].
%%------------------------------------------------------------------------------
%% Init/end
@@ -262,7 +266,7 @@ replace_path(PathA, PathB) ->
true = code:add_patha(PathB).
join(Rule, Opts) ->
- string:join([atom_to_list(Rule)|lists:map(fun atom_to_list/1, Opts)], "_").
+ lists:join("_", [atom_to_list(Rule)|lists:map(fun atom_to_list/1, Opts)]).
%%------------------------------------------------------------------------------
%% Test cases
@@ -441,6 +445,22 @@ testDEFAULT(Config, Rule, Opts) ->
testDef:main(Rule),
testSeqSetDefaultVal:main(Rule, Opts).
+testExtensionDefault(Config) ->
+ test(Config, fun testExtensionDefault/3).
+testExtensionDefault(Config, Rule, Opts) ->
+ asn1_test_lib:compile_all(["ExtensionDefault"], Config, [Rule|Opts]),
+ testExtensionDefault:main(Rule).
+
+testMaps(Config) ->
+ test(Config, fun testMaps/3,
+ [{ber,[maps,no_ok_wrapper]},
+ {ber,[maps,der,no_ok_wrapper]},
+ {per,[maps,no_ok_wrapper]},
+ {uper,[maps,no_ok_wrapper]}]).
+testMaps(Config, Rule, Opts) ->
+ asn1_test_lib:compile_all(['Maps'], Config, [Rule|Opts]),
+ testMaps:main(Rule).
+
testOpt(Config) -> test(Config, fun testOpt/3).
testOpt(Config, Rule, Opts) ->
asn1_test_lib:compile("Opt", Config, [Rule|Opts]),
@@ -614,12 +634,12 @@ parse(Config) ->
[asn1_test_lib:compile(M, Config, [abs]) || M <- test_modules()].
per(Config) ->
- test(Config, fun per/3, [per,uper]).
+ test(Config, fun per/3, [per,uper,{per,[maps]},{uper,[maps]}]).
per(Config, Rule, Opts) ->
[module_test(M, Config, Rule, Opts) || M <- per_modules()].
ber_other(Config) ->
- test(Config, fun ber_other/3, [ber]).
+ test(Config, fun ber_other/3, [ber,{ber,[maps]}]).
ber_other(Config, Rule, Opts) ->
[module_test(M, Config, Rule, Opts) || M <- ber_modules()].
@@ -628,7 +648,7 @@ der(Config) ->
asn1_test_lib:compile_all(ber_modules(), Config, [der]).
module_test(M0, Config, Rule, Opts) ->
- asn1_test_lib:compile(M0, Config, [Rule|Opts]),
+ asn1_test_lib:compile(M0, Config, [Rule,?NO_MAPS_MODULE|Opts]),
case list_to_atom(M0) of
'LDAP' ->
%% Because of the recursive definition of 'Filter' in
@@ -995,7 +1015,9 @@ testS1AP(Config, Rule, Opts) ->
testRfcs() ->
[{timetrap,{minutes,90}}].
-testRfcs(Config) -> test(Config, fun testRfcs/3, [{ber,[der]}]).
+testRfcs(Config) -> test(Config, fun testRfcs/3,
+ [{ber,[der,?NO_MAPS_MODULE]},
+ {ber,[der,maps]}]).
testRfcs(Config, Rule, Opts) ->
case erlang:system_info(system_architecture) of
"sparc-sun-solaris2.10" ->
@@ -1010,7 +1032,8 @@ test_compile_options(Config) ->
ok = test_compile_options:path(Config),
ok = test_compile_options:noobj(Config),
ok = test_compile_options:record_name_prefix(Config),
- ok = test_compile_options:verbose(Config).
+ ok = test_compile_options:verbose(Config),
+ ok = test_compile_options:maps(Config).
testDoubleEllipses(Config) -> test(Config, fun testDoubleEllipses/3).
testDoubleEllipses(Config, Rule, Opts) ->
@@ -1027,18 +1050,6 @@ test_modified_x420(Config, Rule, Opts) ->
test_modified_x420:test(Config).
-testX420() ->
- [{timetrap,{minutes,90}}].
-testX420(Config) ->
- case erlang:system_info(system_architecture) of
- "sparc-sun-solaris2.10" ->
- {skip,"Too slow for an old Sparc"};
- _ ->
- Rule = ber,
- testX420:compile(Rule, [der], Config),
- ok = testX420:ticket7759(Rule, Config)
- end.
-
test_x691(Config) ->
test(Config, fun test_x691/3, [per, uper]).
test_x691(Config, Rule, Opts) ->
@@ -1069,7 +1080,7 @@ test_x691(Config, Rule, Opts) ->
ok.
ticket_6143(Config) ->
- ok = test_compile_options:ticket_6143(Config).
+ asn1_test_lib:compile("AA1", Config, [?NO_MAPS_MODULE]).
testExtensionAdditionGroup(Config) ->
test(Config, fun testExtensionAdditionGroup/3).
@@ -1104,6 +1115,7 @@ test_modules() ->
"From",
"H235-SECURITY-MESSAGES",
"H323-MESSAGES",
+ "HighTagNumbers",
"Import",
"Int",
"MAP-commonDataTypes",
@@ -1157,20 +1169,33 @@ END
ok = asn1ct:compile(File, [{outdir, PrivDir}]).
-timer_compile(Config, Rule) ->
- asn1_test_lib:compile_all(["H235-SECURITY-MESSAGES", "H323-MESSAGES"],
- Config, [no_ok_wrapper,Rule]).
+timer_compile(Config, Opts0) ->
+ Files = ["H235-SECURITY-MESSAGES", "H323-MESSAGES"],
+ Opts = [no_ok_wrapper,?NO_MAPS_MODULE|Opts0],
+ asn1_test_lib:compile_all(Files, Config, Opts).
testTimer_ber(Config) ->
- timer_compile(Config, ber),
+ timer_compile(Config, [ber]),
testTimer:go().
testTimer_per(Config) ->
- timer_compile(Config, per),
+ timer_compile(Config, [per]),
testTimer:go().
testTimer_uper(Config) ->
- timer_compile(Config, uper),
+ timer_compile(Config, [uper]),
+ testTimer:go().
+
+testTimer_ber_maps(Config) ->
+ timer_compile(Config, [ber,maps]),
+ testTimer:go().
+
+testTimer_per_maps(Config) ->
+ timer_compile(Config, [per,maps]),
+ testTimer:go().
+
+testTimer_uper_maps(Config) ->
+ timer_compile(Config, [uper,maps]),
testTimer:go().
%% Test of multiple-line comment, OTP-8043
@@ -1179,20 +1204,23 @@ testComment(Config) ->
asn1_test_lib:roundtrip('Comment', 'Seq', {'Seq',12,true}).
testName2Number(Config) ->
- N2NOptions = [{n2n,Type} || Type <- ['CauseMisc', 'CauseProtocol',
- 'CauseRadioNetwork',
- 'CauseTransport','CauseNas']],
- asn1_test_lib:compile("S1AP-IEs", Config, N2NOptions),
+ N2NOptions0 = [{n2n,Type} ||
+ Type <- ['Cause-Misc', 'CauseProtocol']],
+ N2NOptions = [?NO_MAPS_MODULE|N2NOptions0],
+ asn1_test_lib:compile("EnumN2N", Config, N2NOptions),
- 0 = 'S1AP-IEs':name2num_CauseMisc('control-processing-overload'),
- 'unknown-PLMN' = 'S1AP-IEs':num2name_CauseMisc(5),
+ 0 = 'EnumN2N':'name2num_Cause-Misc'('control-processing-overload'),
+ 'unknown-PLMN' = 'EnumN2N':'num2name_Cause-Misc'(5),
+ 4 = 'EnumN2N':name2num_CauseProtocol('semantic-error'),
+ 'transfer-syntax-error' = 'EnumN2N':num2name_CauseProtocol(0),
%% OTP-10144
%% Test that n2n option generates name2num and num2name functions supporting
%% values not within the extension root if the enumeration type has an
%% extension marker.
- N2NOptionsExt = [{n2n, 'NoExt'}, {n2n, 'Ext'}, {n2n, 'Ext2'}],
+ N2NOptionsExt = [?NO_MAPS_MODULE,{n2n,'NoExt'},{n2n,'Ext'},{n2n,'Ext2'}],
asn1_test_lib:compile("EnumN2N", Config, N2NOptionsExt),
+
%% Previously, name2num and num2name was not generated if the type didn't
%% have an extension marker:
0 = 'EnumN2N':name2num_NoExt('blue'),
@@ -1210,9 +1238,11 @@ testName2Number(Config) ->
ok.
ticket_7407(Config) ->
- asn1_test_lib:compile("EUTRA-extract-7407", Config, [uper]),
+ Opts = [uper,?NO_MAPS_MODULE],
+ asn1_test_lib:compile("EUTRA-extract-7407", Config, Opts),
ticket_7407_code(true),
- asn1_test_lib:compile("EUTRA-extract-7407", Config, [uper,no_final_padding]),
+ asn1_test_lib:compile("EUTRA-extract-7407", Config,
+ [no_final_padding|Opts]),
ticket_7407_code(false).
ticket_7407_code(FinalPadding) ->
@@ -1287,16 +1317,72 @@ ticket7904(Config) ->
{ok,_} = 'RANAPextract1':encode('InitiatingMessage', Val1),
{ok,_} = 'RANAPextract1':encode('InitiatingMessage', Val1).
+
+%% Make sure that functions exported from other modules are
+%% actually used.
+
xref(_Config) ->
- xref:start(s),
- xref:set_default(s, [{verbose,false},{warnings,false},{builtins,true}]),
+ S = ?FUNCTION_NAME,
+ xref:start(S),
+ xref:set_default(S, [{verbose,false},{warnings,false},{builtins,true}]),
Test = filename:dirname(code:which(?MODULE)),
- {ok,_PMs} = xref:add_directory(s, Test),
- UnusedExports = "X - XU - asn1_appup_test - asn1_app_test - \".*_SUITE\" : Mod",
- case xref:q(s, UnusedExports) of
+ {ok,_PMs} = xref:add_directory(S, Test),
+ Q = "X - XU - \".*_SUITE\" : Mod",
+ UnusedExports = xref:q(S, Q),
+ xref:stop(S),
+ case UnusedExports of
{ok,[]} ->
ok;
{ok,[_|_]=Res} ->
io:format("Exported, but unused: ~p\n", [Res]),
?t:fail()
end.
+
+%% Ensure that all functions that are implicitly exported by
+%% 'export_all' in this module are actually used.
+
+xref_export_all(_Config) ->
+ S = ?FUNCTION_NAME,
+ xref:start(S),
+ xref:set_default(S, [{verbose,false},{warnings,false},{builtins,true}]),
+ {ok,_PMs} = xref:add_module(S, code:which(?MODULE)),
+ AllCalled = all_called(),
+ Def = "Called := " ++ lists:flatten(io_lib:format("~p", [AllCalled])),
+ {ok,_} = xref:q(S, Def),
+ {ok,Unused} = xref:q(S, "X - Called - range (closure E | Called)"),
+ xref:stop(S),
+ case Unused of
+ [] ->
+ ok;
+ [_|_] ->
+ Msg = [io_lib:format("~p:~p/~p\n", [M,F,A]) || {M,F,A} <- Unused],
+ io:format("There are unused functions:\n\n~s\n", [Msg]),
+ ?t:fail(unused_functions)
+ end.
+
+%% Collect all functions that common_test will call in this module.
+
+all_called() ->
+ [{?MODULE,end_per_group,2},
+ {?MODULE,end_per_suite,1},
+ {?MODULE,end_per_testcase,2},
+ {?MODULE,init_per_group,2},
+ {?MODULE,init_per_suite,1},
+ {?MODULE,init_per_testcase,2},
+ {?MODULE,suite,0}] ++
+ all_called_1(all() ++ groups()).
+
+all_called_1([{_,_}|T]) ->
+ all_called_1(T);
+all_called_1([{_Name,_Flags,Fs}|T]) ->
+ all_called_1(Fs ++ T);
+all_called_1([F|T]) when is_atom(F) ->
+ L = case erlang:function_exported(?MODULE, F, 0) of
+ false ->
+ [{?MODULE,F,1}];
+ true ->
+ [{?MODULE,F,0},{?MODULE,F,1}]
+ end,
+ L ++ all_called_1(T);
+all_called_1([]) ->
+ [].
diff --git a/lib/asn1/test/asn1_SUITE_data/EnumN2N.asn1 b/lib/asn1/test/asn1_SUITE_data/EnumN2N.asn1
index a724f2f3f5..a610eb6230 100644
--- a/lib/asn1/test/asn1_SUITE_data/EnumN2N.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/EnumN2N.asn1
@@ -1,6 +1,28 @@
EnumN2N DEFINITIONS AUTOMATIC TAGS ::=
BEGIN
+Cause-Misc ::= ENUMERATED {
+ control-processing-overload,
+ not-enough-user-plane-processing-resources,
+ hardware-failure,
+ om-intervention,
+ unspecified,
+ unknown-PLMN,
+...
+}
+
+CauseProtocol ::= ENUMERATED {
+ transfer-syntax-error,
+ abstract-syntax-error-reject,
+ abstract-syntax-error-ignore-and-notify,
+ message-not-compatible-with-receiver-state,
+ semantic-error,
+ abstract-syntax-error-falsely-constructed-message,
+ unspecified,
+ ...
+}
+
+
NoExt ::= ENUMERATED {
blue(0),
red(1),
diff --git a/lib/asn1/test/asn1_SUITE_data/ExtensionDefault.asn1 b/lib/asn1/test/asn1_SUITE_data/ExtensionDefault.asn1
new file mode 100644
index 0000000000..67d9cb6312
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/ExtensionDefault.asn1
@@ -0,0 +1,12 @@
+ExtensionDefault DEFINITIONS AUTOMATIC TAGS ::=
+
+BEGIN
+
+Message ::= SEQUENCE {
+ id INTEGER (0..5),
+ ...,
+ priority Priority DEFAULT low
+}
+Priority ::= ENUMERATED { low(0), high(1), ... }
+
+END
diff --git a/lib/asn1/test/asn1_SUITE_data/HighTagNumbers.asn1 b/lib/asn1/test/asn1_SUITE_data/HighTagNumbers.asn1
new file mode 100644
index 0000000000..b681063965
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/HighTagNumbers.asn1
@@ -0,0 +1,17 @@
+HighTagNumbers DEFINITIONS ::=
+BEGIN
+
+S ::= SEQUENCE {
+ a [127] INTEGER,
+ b [128] INTEGER,
+ c [150] INTEGER,
+ d [207] INTEGER,
+ e [255] INTEGER,
+ f [256] INTEGER,
+ g [7777] INTEGER,
+ h [9999] INTEGER,
+ i [16382] INTEGER,
+ j [16383] INTEGER
+}
+
+END
diff --git a/lib/asn1/test/asn1_SUITE_data/ImportsFrom.asn1 b/lib/asn1/test/asn1_SUITE_data/ImportsFrom.asn1
index 32b8f75dde..dee3cd5048 100644
--- a/lib/asn1/test/asn1_SUITE_data/ImportsFrom.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/ImportsFrom.asn1
@@ -1,8 +1,9 @@
ImportsFrom DEFINITIONS AUTOMATIC TAGS ::=
BEGIN
-IMPORTS Int FROM ImportsFrom2;
+IMPORTS Int, Quoted-Seq FROM ImportsFrom2;
i Int ::= 42
+My-Seq ::= Quoted-Seq
END
diff --git a/lib/asn1/test/asn1_SUITE_data/ImportsFrom2.asn1 b/lib/asn1/test/asn1_SUITE_data/ImportsFrom2.asn1
index b0c29d24ae..a8e619e215 100644
--- a/lib/asn1/test/asn1_SUITE_data/ImportsFrom2.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/ImportsFrom2.asn1
@@ -2,6 +2,11 @@ ImportsFrom2 DEFINITIONS AUTOMATIC TAGS ::=
BEGIN
IMPORTS Int FROM ImportsFrom3;
+Quoted-Seq ::= SEQUENCE {
+ x INTEGER(0..17),
+ y INTEGER(0..666)
+}
+
LocalDef ::= OCTET STRING
END
diff --git a/lib/asn1/test/asn1_SUITE_data/Maps.asn1 b/lib/asn1/test/asn1_SUITE_data/Maps.asn1
new file mode 100644
index 0000000000..fd5f373e45
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/Maps.asn1
@@ -0,0 +1,17 @@
+Maps DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+
+XY ::= SEQUENCE { x INTEGER DEFAULT 0, y INTEGER DEFAULT 0 }
+
+xy1 XY ::= { x 42, y 17 }
+xy2 XY ::= { }
+xy3 XY ::= { y 999 }
+
+S ::= SEQUENCE {
+ xy XY DEFAULT { x 100, y 100 },
+ os OCTET STRING OPTIONAL
+}
+
+s1 S ::= {}
+
+END
diff --git a/lib/asn1/test/asn1_SUITE_data/Prim.asn1 b/lib/asn1/test/asn1_SUITE_data/Prim.asn1
index 4fe0901683..91c8696e61 100644
--- a/lib/asn1/test/asn1_SUITE_data/Prim.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/Prim.asn1
@@ -18,6 +18,8 @@ BEGIN
IntExpPri ::= [PRIVATE 51] EXPLICIT INTEGER
IntExpApp ::= [APPLICATION 52] EXPLICIT INTEGER
+ IntConstrained ::= INTEGER (0..255)
+
IntEnum ::= INTEGER {first(1),last(31)}
Enum ::= ENUMERATED {monday(1),tuesday(2),wednesday(3),thursday(4),
diff --git a/lib/asn1/test/asn1_SUITE_data/SeqExtension.asn1 b/lib/asn1/test/asn1_SUITE_data/SeqExtension.asn1
index 5fda19303a..e866ef2f4f 100644
--- a/lib/asn1/test/asn1_SUITE_data/SeqExtension.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/SeqExtension.asn1
@@ -48,6 +48,17 @@ SeqExt6 ::= SEQUENCE
[[ i6 [106] INTEGER, i7 [107] INTEGER ]]
}
+SeqExt7 ::= SEQUENCE
+{
+ -- The spaces between the ellipsis and the comma will prevent them
+ -- from being removed.
+ ... ,
+ [[ a INTEGER (0..65535) OPTIONAL,
+ b OCTET STRING OPTIONAL,
+ c BOOLEAN
+ ]]
+}
+
SeqExt1X ::= XSeqExt1
SeqExt2X ::= XSeqExt2
diff --git a/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl b/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl
index 6cf8ecf451..cd6c74b995 100644
--- a/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl
+++ b/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl
@@ -120,10 +120,10 @@ run3(Erule) ->
asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE},
asn1_NOVALUE,asn1_NOVALUE}}}}}}},
io:format("~p:~p~n",[Erule,Val]),
- {ok,List}= asn1rt:encode('EUTRA-RRC-Definitions','DL-DCCH-Message',Val),
+ {ok,List}= 'EUTRA-RRC-Definitions':encode('DL-DCCH-Message',Val),
Enc = iolist_to_binary(List),
io:format("Result from encode:~n~p~n",[Enc]),
- {ok,Val2} = asn1rt:decode('EUTRA-RRC-Definitions','DL-DCCH-Message',Enc),
+ {ok,Val2} = 'EUTRA-RRC-Definitions':decode('DL-DCCH-Message', Enc),
io:format("Result from decode:~n~p~n",[Val2]),
case Val2 of
Val -> ok;
diff --git a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Discriptions.asn b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Descriptions.asn
index b9be9934e4..12a4475422 100644
--- a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Discriptions.asn
+++ b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Descriptions.asn
@@ -4,7 +4,7 @@
--
-- **************************************************************
-NBAP-PDU-Discriptions {
+NBAP-PDU-Descriptions {
itu-t (0) identified-organization (4) etsi (0) mobileDomain (0)
umts-Access (20) modules (3) nbap (2) version1 (1) nbap-PDU-Descriptions (0) }
diff --git a/lib/asn1/test/asn1_SUITE_data/test_records.erl b/lib/asn1/test/asn1_SUITE_data/test_records.erl
index 9fd07c1449..16167e2f85 100644
--- a/lib/asn1/test/asn1_SUITE_data/test_records.erl
+++ b/lib/asn1/test/asn1_SUITE_data/test_records.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,7 +25,7 @@
-define(line,put(test_server_loc,{?MODULE,?LINE}),).
--include("NBAP-PDU-Discriptions.hrl").
+-include("NBAP-PDU-Descriptions.hrl").
-include("NBAP-PDU-Contents.hrl").
-include("NBAP-Containers.hrl").
-include("NBAP-CommonDataTypes.hrl").
diff --git a/lib/asn1/test/asn1_SUITE_data/testobj.erl b/lib/asn1/test/asn1_SUITE_data/testobj.erl
index a0e00f8314..b582935f73 100644
--- a/lib/asn1/test/asn1_SUITE_data/testobj.erl
+++ b/lib/asn1/test/asn1_SUITE_data/testobj.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -967,7 +967,7 @@ pdu_pdp() ->
116,101,115,116, % lable1 = test
4, % length lable2
116,101,115,116, % lable2 = test
- 4, % lenght lable3
+ 4, % length lable3
116,101,115,116, % lable3 = test
4, % length lable3
116,101,115,116, % lable4 = test
@@ -1410,16 +1410,14 @@ int2bin(Int) ->
%%%%%%%%%%%%%%%%% wrappers %%%%%%%%%%%%%%%%%%%%%%%%
wrapper_encode(Module,Type,Value) ->
- case asn1rt:encode(Module,Type,Value) of
- {ok,X} when binary(X) ->
+ case Module:encode(Type, Value) of
+ {ok,X} when is_binary(X) ->
{ok, binary_to_list(X)};
- {ok,X} ->
- {ok, binary_to_list(list_to_binary(X))};
Error ->
Error
end.
wrapper_decode(Module, Type, Bytes) when is_binary(Bytes) ->
- asn1rt:decode(Module, Type, Bytes);
+ Module:decode(Type, Bytes);
wrapper_decode(Module, Type, Bytes) when is_list(Bytes) ->
- asn1rt:decode(Module, Type, list_to_binary(Bytes)).
+ Module:decode(Type, list_to_binary(Bytes)).
diff --git a/lib/asn1/test/asn1_app_test.erl b/lib/asn1/test/asn1_app_SUITE.erl
index 028322f555..b06eb59ed9 100644
--- a/lib/asn1/test/asn1_app_test.erl
+++ b/lib/asn1/test/asn1_app_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,23 +21,24 @@
%%----------------------------------------------------------------------
%% Purpose: Verify the application specifics of the asn1 application
%%----------------------------------------------------------------------
--module(asn1_app_test).
-
--compile(export_all).
+-module(asn1_app_SUITE).
+-export([all/0,groups/0,init_per_group/2,end_per_group/2,
+ init_per_suite/1,end_per_suite/1,
+ appup/1,fields/1,modules/1,export_all/1,app_depend/1]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-all() ->
- [fields, modules, exportall, app_depend].
+all() ->
+ [appup, fields, modules, export_all, app_depend].
-groups() ->
+groups() ->
[].
init_per_group(_GroupName, Config) ->
- Config.
+ Config.
end_per_group(_GroupName, Config) ->
- Config.
+ Config.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -65,12 +66,15 @@ is_app(App) ->
end_per_suite(Config) when is_list(Config) ->
Config.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+appup(Config) when is_list(Config) ->
+ ok = test_server:appup_test(asn1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% .
fields(Config) when is_list(Config) ->
- AppFile = key1search(app_file, Config),
+ AppFile = key1find(app_file, Config),
Fields = [vsn, description, modules, registered, applications],
case check_fields(Fields, AppFile, []) of
[] ->
@@ -96,10 +100,9 @@ check_field(Name, AppFile, Missing) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% .
modules(Config) when is_list(Config) ->
- AppFile = key1search(app_file, Config),
- Mods = key1search(modules, AppFile),
+ AppFile = key1find(app_file, Config),
+ Mods = key1find(modules, AppFile),
EbinList = get_ebin_mods(asn1),
case missing_modules(Mods, EbinList, []) of
[] ->
@@ -112,10 +115,9 @@ modules(Config) when is_list(Config) ->
ok;
Extra ->
check_asn1ct_modules(Extra)
-% throw({error, {extra_modules, Extra}})
end,
{ok, Mods}.
-
+
get_ebin_mods(App) ->
LibDir = code:lib_dir(App),
EbinDir = filename:join([LibDir,"ebin"]),
@@ -166,10 +168,9 @@ extra_modules(Mods, [Mod|Ebins], Extra) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% .
-exportall(Config) when is_list(Config) ->
- AppFile = key1search(app_file, Config),
- Mods = key1search(modules, AppFile),
+export_all(Config) when is_list(Config) ->
+ AppFile = key1find(app_file, Config),
+ Mods = key1find(modules, AppFile),
check_export_all(Mods).
@@ -180,10 +181,10 @@ check_export_all([Mod|Mods]) ->
{'EXIT', {undef, _}} ->
check_export_all(Mods);
O ->
- case lists:keysearch(options, 1, O) of
+ case lists:keyfind(options, 1, O) of
false ->
check_export_all(Mods);
- {value, {options, List}} ->
+ {options, List} ->
case lists:member(export_all, List) of
true ->
throw({error, {export_all, Mod}});
@@ -193,13 +194,12 @@ check_export_all([Mod|Mods]) ->
end
end.
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% .
app_depend(Config) when is_list(Config) ->
- AppFile = key1search(app_file, Config),
- Apps = key1search(applications, AppFile),
+ AppFile = key1find(app_file, Config),
+ Apps = key1find(applications, AppFile),
check_apps(Apps).
@@ -220,10 +220,10 @@ check_apps([App|Apps]) ->
fail(Reason) ->
exit({suite_failed, Reason}).
-key1search(Key, L) ->
- case lists:keysearch(Key, 1, L) of
- undefined ->
+key1find(Key, L) ->
+ case lists:keyfind(Key, 1, L) of
+ false ->
fail({not_found, Key, L});
- {value, {Key, Value}} ->
+ {Key, Value} ->
Value
end.
diff --git a/lib/asn1/test/asn1_appup_test.erl b/lib/asn1/test/asn1_appup_test.erl
deleted file mode 100644
index 54540e53cc..0000000000
--- a/lib/asn1/test/asn1_appup_test.erl
+++ /dev/null
@@ -1,58 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-%%----------------------------------------------------------------------
-%% Purpose: Verify the application specifics of the asn1 application
-%%----------------------------------------------------------------------
--module(asn1_appup_test).
--compile(export_all).
--include_lib("common_test/include/ct.hrl").
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-all() ->
- [appup].
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-init_per_suite(Config) when is_list(Config) ->
- Config.
-
-
-end_per_suite(Config) when is_list(Config) ->
- Config.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-appup() ->
- [{doc, "perform a simple check of the asn1 appup file"}].
-appup(Config) when is_list(Config) ->
- ok = ?t:appup_test(asn1).
diff --git a/lib/asn1/test/asn1_test_lib.erl b/lib/asn1/test/asn1_test_lib.erl
index dc614db4f2..1cc332406b 100644
--- a/lib/asn1/test/asn1_test_lib.erl
+++ b/lib/asn1/test/asn1_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,7 +25,8 @@
hex_to_bin/1,
match_value/2,
parallel/0,
- roundtrip/3,roundtrip/4,roundtrip_enc/3,roundtrip_enc/4]).
+ roundtrip/3,roundtrip/4,roundtrip_enc/3,roundtrip_enc/4,
+ map_roundtrip/3]).
-include_lib("common_test/include/ct.hrl").
@@ -94,15 +95,58 @@ module(F0) ->
list_to_atom(F).
%% filename:join(CaseDir, F ++ ".beam").
-compile_file(File, Options) ->
+compile_file(File, Options0) ->
+ Options = [warnings_as_errors|Options0],
try
- ok = asn1ct:compile(File, [warnings_as_errors|Options])
+ ok = asn1ct:compile(File, Options),
+ ok = compile_maps(File, Options)
catch
_:Reason ->
ct:print("Failed to compile ~s\n~p", [File,Reason]),
error
end.
+compile_maps(File, Options) ->
+ unload_map_mod(File),
+ Incompat = [abs,compact_bit_string,legacy_bit_string,
+ legacy_erlang_types,maps,asn1_test_lib_no_maps],
+ case lists:any(fun(E) -> lists:member(E, Incompat) end, Options) of
+ true ->
+ ok;
+ false ->
+ compile_maps_1(File, Options)
+ end.
+
+compile_maps_1(File, Options) ->
+ ok = asn1ct:compile(File, [maps,no_ok_wrapper,noobj|Options]),
+ OutDir = proplists:get_value(outdir, Options),
+ Base0 = filename:rootname(filename:basename(File)),
+ Base = case filename:extension(Base0) of
+ ".set" ->
+ filename:rootname(Base0);
+ _ ->
+ Base0
+ end,
+ ErlBase = Base ++ ".erl",
+ ErlFile = filename:join(OutDir, ErlBase),
+ {ok,Erl0} = file:read_file(ErlFile),
+ Erl = re:replace(Erl0, <<"-module\\('">>, "&maps_"),
+ MapsErlFile = filename:join(OutDir, "maps_" ++ ErlBase),
+ ok = file:write_file(MapsErlFile, Erl),
+ {ok,_} = compile:file(MapsErlFile, [report,{outdir,OutDir},{i,OutDir}]),
+ ok.
+
+unload_map_mod(File0) ->
+ File1 = filename:basename(File0),
+ File2 = filename:rootname(File1, ".asn"),
+ File3 = filename:rootname(File2, ".asn1"),
+ File4 = filename:rootname(File3, ".py"),
+ File = filename:rootname(File4, ".set"),
+ MapMod = list_to_atom("maps_"++File),
+ code:delete(MapMod),
+ code:purge(MapMod),
+ ok.
+
compile_erlang(Mod, Config, Options) ->
DataDir = proplists:get_value(data_dir, Config),
CaseDir = proplists:get_value(case_dir, Config),
@@ -147,24 +191,60 @@ roundtrip(Mod, Type, Value) ->
roundtrip(Mod, Type, Value, Value).
roundtrip(Mod, Type, Value, ExpectedValue) ->
- {ok,Encoded} = Mod:encode(Type, Value),
- {ok,ExpectedValue} = Mod:decode(Type, Encoded),
- test_ber_indefinite(Mod, Type, Encoded, ExpectedValue),
- ok.
+ roundtrip_enc(Mod, Type, Value, ExpectedValue).
roundtrip_enc(Mod, Type, Value) ->
roundtrip_enc(Mod, Type, Value, Value).
roundtrip_enc(Mod, Type, Value, ExpectedValue) ->
- {ok,Encoded} = Mod:encode(Type, Value),
- {ok,ExpectedValue} = Mod:decode(Type, Encoded),
+ case Mod:encode(Type, Value) of
+ {ok,Encoded} ->
+ {ok,ExpectedValue} = Mod:decode(Type, Encoded);
+ Encoded when is_binary(Encoded) ->
+ ExpectedValue = Mod:decode(Type, Encoded)
+ end,
+ map_roundtrip(Mod, Type, Encoded),
test_ber_indefinite(Mod, Type, Encoded, ExpectedValue),
Encoded.
+map_roundtrip(Mod, Type, Encoded) ->
+ MapMod = list_to_atom("maps_"++atom_to_list(Mod)),
+ try MapMod:maps() of
+ true ->
+ map_roundtrip_1(MapMod, Type, Encoded)
+ catch
+ error:undef ->
+ ok
+ end.
+
%%%
%%% Internal functions.
%%%
+map_roundtrip_1(Mod, Type, Encoded) ->
+ Decoded = Mod:decode(Type, Encoded),
+ case Mod:encode(Type, Decoded) of
+ Encoded ->
+ ok;
+ OtherEncoding ->
+ case is_named_bitstring(Decoded) of
+ true ->
+ %% In BER, named BIT STRINGs with different number of
+ %% trailing zeroes decode to the same value.
+ ok;
+ false ->
+ error({encode_mismatch,Decoded,Encoded,OtherEncoding})
+ end
+ end,
+ ok.
+
+is_named_bitstring([H|T]) ->
+ is_atom(H) andalso is_named_bitstring(T);
+is_named_bitstring([]) ->
+ true;
+is_named_bitstring(_) ->
+ false.
+
hex2num(C) when $0 =< C, C =< $9 -> C - $0;
hex2num(C) when $A =< C, C =< $F -> C - $A + 10;
hex2num(C) when $a =< C, C =< $f -> C - $a + 10.
@@ -179,7 +259,12 @@ test_ber_indefinite(Mod, Type, Encoded, ExpectedValue) ->
case Mod:encoding_rule() of
ber ->
Indefinite = iolist_to_binary(ber_indefinite(Encoded)),
- {ok,ExpectedValue} = Mod:decode(Type, Indefinite);
+ case Mod:decode(Type, Indefinite) of
+ {ok,ExpectedValue} ->
+ ok;
+ ExpectedValue ->
+ ok
+ end;
_ ->
ok
end.
diff --git a/lib/asn1/test/ber_decode_error.erl b/lib/asn1/test/ber_decode_error.erl
index c0840e02d7..e5b231a7c7 100644
--- a/lib/asn1/test/ber_decode_error.erl
+++ b/lib/asn1/test/ber_decode_error.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,48 +26,41 @@ run([]) ->
{ok,B} = 'Constructed':encode('S3', {'S3',17}),
[T,L|V] = binary_to_list(B),
Bytes = list_to_binary([T,L+3|V] ++ [2,1,3]),
- case 'Constructed':decode('S3', Bytes) of
- {error,{asn1,{unexpected,_}}} -> ok
- end,
+ {unexpected,_} = dec_error('S3', Bytes),
%% Unexpected bytes must be accepted if there is an extensionmark
{ok,{'S3ext',17}} = 'Constructed':decode('S3ext', Bytes),
%% Truncated tag.
- {error,{asn1,{invalid_tag,_}}} =
- (catch 'Constructed':decode('I', <<31,255,255>>)),
+ {invalid_tag,_} = dec_error('I', <<31,255,255>>),
%% Overlong tag.
- {error,{asn1,{invalid_tag,_}}} =
- (catch 'Constructed':decode('I', <<31,255,255,255,127>>)),
+ {invalid_tag,_} = dec_error('I', <<31,255,255,255,127>>),
%% Invalid length.
- {error,{asn1,{invalid_length,_}}} =
- (catch 'Constructed':decode('I', <<8,255>>)),
+ {invalid_length,_} = dec_error('I', <<8,255>>),
%% Other errors.
- {error,{asn1,{invalid_value,_}}} =
- (catch 'Constructed':decode('I', <<>>)),
+ {invalid_value,_} = dec_error('I', <<>>),
- {error,{asn1,{invalid_value,_}}} =
- (catch 'Constructed':decode('I', <<8,7>>)),
+ {invalid_value,_} = dec_error('I', <<8,7>>),
%% Short indefinite length. Make sure that the decoder doesn't look
%% beyond the end of binary when looking for a 0,0 terminator.
- {error,{asn1,{invalid_length,_}}} =
- (catch 'Constructed':decode('S', sub(<<8,16#80,0,0>>, 3))),
- {error,{asn1,{invalid_length,_}}} =
- (catch 'Constructed':decode('S', sub(<<8,16#80,0,0>>, 2))),
- {error,{asn1,{invalid_length,_}}} =
- (catch 'Constructed':decode('S', sub(<<40,16#80,1,1,255,0,0>>, 6))),
- {error,{asn1,{invalid_length,_}}} =
- (catch 'Constructed':decode('S', sub(<<40,16#80,1,1,255,0,0>>, 5))),
+ {invalid_length,_} = dec_error('S', sub(<<8,16#80,0,0>>, 3)),
+ {invalid_length,_} = dec_error('S', sub(<<8,16#80,0,0>>, 2)),
+ {invalid_length,_} = dec_error('S', sub(<<40,16#80,1,1,255,0,0>>, 6)),
+ {invalid_length,_} = dec_error('S', sub(<<40,16#80,1,1,255,0,0>>, 5)),
%% A primitive must not be encoded with an indefinite length.
- {error,{asn1,{invalid_length,_}}} =
- (catch 'Constructed':decode('OS', <<4,128,4,3,97,98,99,0,0>>)),
+ {invalid_length,_} = dec_error('OS', <<4,128,4,3,97,98,99,0,0>>),
ok.
+dec_error(T, Bin) ->
+ {error,{asn1,{Reason,Stk}}} = 'Constructed':decode(T, Bin),
+ [{_,_,_,_}|_] = Stk,
+ Reason.
+
sub(Bin, Bytes) ->
<<B:Bytes/binary,_/binary>> = Bin,
B.
diff --git a/lib/asn1/test/h323test.erl b/lib/asn1/test/h323test.erl
index 935af0ba09..c4eaa75c9a 100644
--- a/lib/asn1/test/h323test.erl
+++ b/lib/asn1/test/h323test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,6 +27,8 @@ run(per) -> run();
run(_Rules) -> ok.
run() ->
+ roundtrip('EndpointType', endpoint()),
+ roundtrip('Alerting-UUIE', alerting_uuie()),
roundtrip('H323-UserInformation', alerting_val(), alerting_enc()),
roundtrip('H323-UserInformation', connect_val(), connect_enc()),
general_string(),
@@ -36,18 +38,24 @@ alerting_val() ->
{'H323-UserInformation',
{'H323-UU-PDU',
{alerting,
- {'Alerting-UUIE',
- {0,0,8,2250,0,2},
- {'EndpointType',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,
- asn1_NOVALUE,asn1_NOVALUE,
- {'TerminalInfo',asn1_NOVALUE},
- false,false},
- asn1_NOVALUE,
- {'CallIdentifier',<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>},
- asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}},
+ alerting_uuie()},
asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE},
asn1_NOVALUE}.
+endpoint() ->
+ {'EndpointType',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,
+ asn1_NOVALUE,asn1_NOVALUE,
+ {'TerminalInfo',asn1_NOVALUE},
+ false,false}.
+
+alerting_uuie() ->
+ {'Alerting-UUIE',
+ {0,0,8,2250,0,2},
+ endpoint(),
+ asn1_NOVALUE,
+ {'CallIdentifier',<<0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>},
+ asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}.
+
alerting_enc() ->
"0380060008914a0002020120110000000000000000000000000000000000".
@@ -82,6 +90,9 @@ general_string() ->
UI = <<109,64,1,57>>,
{ok, _V} = 'MULTIMEDIA-SYSTEM-CONTROL':decode(Type, UI).
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('H323-MESSAGES', T, V).
+
roundtrip(T, V, HexString) ->
Enc = asn1_test_lib:hex_to_bin(HexString),
Enc = asn1_test_lib:roundtrip_enc('H323-MESSAGES', T, V),
diff --git a/lib/asn1/test/testChoPrim.erl b/lib/asn1/test/testChoPrim.erl
index 573c482f2b..91fbc1488a 100644
--- a/lib/asn1/test/testChoPrim.erl
+++ b/lib/asn1/test/testChoPrim.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,10 +31,10 @@ bool(Rules) ->
roundtrip('ChoCon', {int2,233}),
case Rules of
ber ->
- {error,{asn1,{invalid_choice_type,wrong}}} =
- (catch 'ChoPrim':encode('ChoCon', {wrong,233})),
- {error,{asn1,{invalid_choice_tag,_WrongTag}}} =
- (catch 'ChoPrim':decode('ChoCon', <<131,2,0,233>>));
+ {error,{asn1,{{invalid_choice_type,wrong},[_|_]}}} =
+ (catch 'ChoPrim':encode('ChoCon', {wrong,233})),
+ {error,{asn1,{{invalid_choice_tag,_WrongTag},[_|_]}}} =
+ (catch 'ChoPrim':decode('ChoCon', <<131,2,0,233>>));
per ->
ok;
uper ->
diff --git a/lib/asn1/test/testContextSwitchingTypes.erl b/lib/asn1/test/testContextSwitchingTypes.erl
index 10012908a9..bc7d9733b9 100644
--- a/lib/asn1/test/testContextSwitchingTypes.erl
+++ b/lib/asn1/test/testContextSwitchingTypes.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -90,5 +90,6 @@ check_object_identifier(Tuple) when is_tuple(Tuple) ->
enc_dec(T, V0) ->
M = 'ContextSwitchingTypes',
{ok,Enc} = M:encode(T, V0),
+ asn1_test_lib:map_roundtrip(M, T, Enc),
{ok,V} = M:decode(T, Enc),
V.
diff --git a/lib/asn1/test/testExtensionDefault.erl b/lib/asn1/test/testExtensionDefault.erl
new file mode 100644
index 0000000000..cc50fa95b8
--- /dev/null
+++ b/lib/asn1/test/testExtensionDefault.erl
@@ -0,0 +1,53 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+-module(testExtensionDefault).
+
+-export([main/1]).
+
+main(_Erule) ->
+ roundtrip('Message', {'Message',1,low}), %Will be explicitly encoded.
+ roundtrip('Message', {'Message',1,high}),
+ roundtrip('Message', {'Message',1,asn1_DEFAULT}, {'Message',1,low}),
+
+ map_roundtrip('Message', #{id=>1,priority=>low}), %Will be explicitly encoded.
+ map_roundtrip('Message', #{id=>1,priority=>high}),
+ map_roundtrip('Message', #{id=>1}, #{id=>1,priority=>low}),
+ ok.
+
+roundtrip(Type, Value) ->
+ asn1_test_lib:roundtrip('ExtensionDefault', Type, Value).
+
+roundtrip(Type, Value, Expected) ->
+ %% asn1_test_lib:roundtrip/3 will invoke map_roundtrip/3, which will
+ %% not work in this case. Therefore, implement the roundtrip ourselves.
+ M = 'ExtensionDefault',
+ {ok,Enc} = M:encode(Type, Value),
+ {ok,Expected} = M:decode(Type, Enc),
+ ok.
+
+map_roundtrip(Type, Value) ->
+ map_roundtrip(Type, Value, Value).
+
+map_roundtrip(Type, Value, Expected) ->
+ M = 'maps_ExtensionDefault',
+ Enc = M:encode(Type, Value),
+ Expected = M:decode(Type, Enc),
+ ok.
diff --git a/lib/asn1/test/testInfObj.erl b/lib/asn1/test/testInfObj.erl
index 5a9f47d865..d3ec35b652 100644
--- a/lib/asn1/test/testInfObj.erl
+++ b/lib/asn1/test/testInfObj.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -197,5 +197,6 @@ roundtrip(M, T, V) ->
enc_dec(M, T, V0) ->
{ok,Enc} = M:encode(T, V0),
+ asn1_test_lib:map_roundtrip(M, T, Enc),
{ok,V} = M:decode(T, Enc),
V.
diff --git a/lib/asn1/test/testInfObjectClass.erl b/lib/asn1/test/testInfObjectClass.erl
index 560986fac9..02ff38e78a 100644
--- a/lib/asn1/test/testInfObjectClass.erl
+++ b/lib/asn1/test/testInfObjectClass.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,19 +33,29 @@ main(Rule) ->
roundtrip('Seq', Val),
%% OTP-5783
- {error,{asn1,{'Type not compatible with table constraint',
- {component,'ArgumentType'},
- {value,_},_}}} = 'InfClass':encode('Seq', {'Seq',12,13,1}),
+ {'Type not compatible with table constraint',
+ {component,'ArgumentType'},
+ {value,_},_} = enc_error('Seq', {'Seq',12,13,1}),
Bytes2 = case Rule of
ber ->
<<48,9,2,1,12,2,1,11,2,1,1>>;
_ ->
<<1,12,1,11,1,1>>
end,
- {error,{asn1,{'Type not compatible with table constraint',
- {{component,_},
- {value,_B},_}}}} = 'InfClass':decode('Seq', Bytes2),
+ {'Type not compatible with table constraint',
+ {{component,_},
+ {value,_B},_}} = dec_error('Seq', Bytes2),
ok.
roundtrip(T, V) ->
asn1_test_lib:roundtrip('InfClass', T, V).
+
+enc_error(T, V) ->
+ {error,{asn1,{Reason,Stk}}} = 'InfClass':encode(T, V),
+ [{_,_,_,_}|_] = Stk,
+ Reason.
+
+dec_error(T, Bin) ->
+ {error,{asn1,{Reason,Stk}}} = 'InfClass':decode(T, Bin),
+ [{_,_,_,_}|_] = Stk,
+ Reason.
diff --git a/lib/asn1/test/testMaps.erl b/lib/asn1/test/testMaps.erl
new file mode 100644
index 0000000000..45dd2255ba
--- /dev/null
+++ b/lib/asn1/test/testMaps.erl
@@ -0,0 +1,50 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+-module(testMaps).
+
+-export([main/1]).
+
+main(_) ->
+ M = 'Maps',
+ true = M:maps(),
+
+ true = M:xy1() =:= #{x=>42,y=>17},
+ true = M:xy2() =:= #{x=>0,y=>0},
+ true = M:xy3() =:= #{x=>0,y=>999},
+ true = M:s1() =:= #{xy=>#{x=>100,y=>100}},
+
+ roundtrip('XY', M:xy1()),
+ roundtrip('XY', M:xy2()),
+ roundtrip('XY', M:xy3()),
+ roundtrip('XY', #{}, #{x=>0,y=>0}),
+
+ roundtrip('S', M:s1()),
+ roundtrip('S', #{}, #{xy=>#{x=>100,y=>100}}),
+ roundtrip('S', #{os=><<1,2,3>>}, #{xy=>#{x=>100,y=>100},
+ os=><<1,2,3>>}),
+
+ ok.
+
+roundtrip(Type, Value) ->
+ roundtrip(Type, Value, Value).
+
+roundtrip(Type, Value, Expected) ->
+ asn1_test_lib:roundtrip('Maps', Type, Value, Expected).
diff --git a/lib/asn1/test/testMultipleLevels.erl b/lib/asn1/test/testMultipleLevels.erl
index c610e59f3d..5de2c5a2fa 100644
--- a/lib/asn1/test/testMultipleLevels.erl
+++ b/lib/asn1/test/testMultipleLevels.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,5 +24,7 @@
main(_) ->
Data = {'Top',{short,"abc"},{long,"a long string follows here"}},
- {ok,B} = 'MultipleLevels':encode('Top', Data),
- {ok,Data} = 'MultipleLevels':decode('Top', iolist_to_binary(B)).
+ roundtrip('Top', Data).
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('MultipleLevels', T, V).
diff --git a/lib/asn1/test/testNBAPsystem.erl b/lib/asn1/test/testNBAPsystem.erl
index 1af283af42..264cf5abd4 100644
--- a/lib/asn1/test/testNBAPsystem.erl
+++ b/lib/asn1/test/testNBAPsystem.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -84,7 +84,7 @@ compile(Config, Options) ->
M <- ["NBAP-CommonDataTypes.asn",
"NBAP-IEs.asn",
"NBAP-PDU-Contents.asn",
- "NBAP-PDU-Discriptions.asn",
+ "NBAP-PDU-Descriptions.asn",
"NBAP-Constants.asn",
"NBAP-Containers.asn"]],
asn1_test_lib:compile_all(Fs, Config, Options),
@@ -98,16 +98,16 @@ test(_Erule,Config) ->
ticket_5812(Config) ->
Msg = v_5812(),
- {ok,B2} = 'NBAP-PDU-Discriptions':encode('NBAP-PDU', Msg),
+ {ok,B2} = 'NBAP-PDU-Descriptions':encode('NBAP-PDU', Msg),
V = <<0,28,74,0,3,48,0,0,1,0,123,64,41,0,0,0,126,64,35,95,208,2,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,145,0,1,205,0,0,0,0,2,98,64,1,128>>,
ok = compare(V,B2),
- {ok,Msg2} = 'NBAP-PDU-Discriptions':decode('NBAP-PDU', B2),
+ {ok,Msg2} = 'NBAP-PDU-Descriptions':decode('NBAP-PDU', B2),
ok = check_record_names(Msg2,Config).
enc_audit_req_msg() ->
Msg = {initiatingMessage, audit_req_msg()},
- {ok,B} = 'NBAP-PDU-Discriptions':encode('NBAP-PDU', Msg),
- {ok,_Msg} = 'NBAP-PDU-Discriptions':decode('NBAP-PDU', B),
+ {ok,B} = 'NBAP-PDU-Descriptions':encode('NBAP-PDU', Msg),
+ {ok,_Msg} = 'NBAP-PDU-Descriptions':decode('NBAP-PDU', B),
{initiatingMessage,
#'InitiatingMessage'{value=#'AuditRequest'{protocolIEs=[{_,114,ignore,_}],
protocolExtensions = asn1_NOVALUE}}} = _Msg,
@@ -116,8 +116,8 @@ enc_audit_req_msg() ->
cell_setup_req_msg_test() ->
Msg = {initiatingMessage, cell_setup_req_msg()},
- {ok,B} = 'NBAP-PDU-Discriptions':encode('NBAP-PDU', Msg),
- {ok,_Msg} = 'NBAP-PDU-Discriptions':decode('NBAP-PDU', B),
+ {ok,B} = 'NBAP-PDU-Descriptions':encode('NBAP-PDU', Msg),
+ {ok,_Msg} = 'NBAP-PDU-Descriptions':decode('NBAP-PDU', B),
io:format("Msg: ~P~n~n_Msg: ~P~n",[Msg,15,_Msg,15]),
ok.
diff --git a/lib/asn1/test/testPrim.erl b/lib/asn1/test/testPrim.erl
index 96a2dd6c79..a5d34f5f08 100644
--- a/lib/asn1/test/testPrim.erl
+++ b/lib/asn1/test/testPrim.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,15 +34,12 @@ bool(Rules) ->
Types = ['Bool','BoolCon','BoolPri','BoolApp',
'BoolExpCon','BoolExpPri','BoolExpApp'],
[roundtrip(T, V) || T <- Types, V <- [true,false]],
- case Rules of
- ber ->
- [begin
- {error,{asn1,{encode_boolean,517}}} = enc_error(T, 517)
- end || T <- Types],
- ok;
- _ ->
- ok
- end.
+ Tag = case Rules of
+ ber -> encode_boolean;
+ _ -> illegal_boolean
+ end,
+ [{Tag,517} = enc_error(T, 517) || T <- Types],
+ ok.
int(Rules) ->
@@ -60,10 +57,22 @@ int(Rules) ->
123456789,12345678901234567890,
-1,-2,-3,-4,-100,-127,-255,-256,-257,
-1234567890,-2147483648],
- [roundtrip(T, V) ||
- T <- ['Int','IntCon','IntPri','IntApp',
- 'IntExpCon','IntExpPri','IntExpApp'],
- V <- [1|Values]],
+ Types = ['Int','IntCon','IntPri','IntApp',
+ 'IntExpCon','IntExpPri','IntExpApp'],
+ _ = [roundtrip(T, V) || T <- Types, V <- [1|Values]],
+ Tag = case Rules of
+ ber -> encode_integer;
+ _ -> illegal_integer
+ end,
+ _ = [{Tag,V} = enc_error(T, V) ||
+ T <- Types, V <- [atom,42.0,{a,b,c}]],
+ case Rules of
+ ber ->
+ ok;
+ _ ->
+ _ = [{Tag,V} = enc_error('IntConstrained', V) ||
+ V <- [atom,-1,256,42.0]]
+ end,
%%==========================================================
%% IntEnum ::= INTEGER {first(1),last(31)}
@@ -119,7 +128,11 @@ enum(Rules) ->
roundtrip('Enum', monday),
roundtrip('Enum', thursday),
- {error,{asn1,{_,4}}} = enc_error('Enum', 4),
+ Tag = case Rules of
+ ber -> enumerated_not_in_range;
+ _ -> illegal_enumerated
+ end,
+ {Tag,4} = enc_error('Enum', 4),
case Rules of
Per when Per =:= per; Per =:= uper ->
@@ -182,13 +195,15 @@ roundtrip(Type, Value, ExpectedValue) ->
enc_error(T, V) ->
case get(no_ok_wrapper) of
false ->
- 'Prim':encode(T, V);
+ {error,{asn1,{Reason,Stk}}} = 'Prim':encode(T, V),
+ [{_,_,_,_}|_] = Stk,
+ Reason;
true ->
try 'Prim':encode(T, V) of
_ ->
?t:fail()
catch
- _:Reason ->
+ _:{error,{asn1,Reason}} ->
Reason
end
end.
diff --git a/lib/asn1/test/testPrimStrings.erl b/lib/asn1/test/testPrimStrings.erl
index cb97655c15..b7f0323301 100644
--- a/lib/asn1/test/testPrimStrings.erl
+++ b/lib/asn1/test/testPrimStrings.erl
@@ -19,8 +19,6 @@
%%
%%
-module(testPrimStrings).
--compile([{nowarn_deprecated_function,{asn1rt,utf8_list_to_binary,1}},
- {nowarn_deprecated_function,{asn1rt,utf8_binary_to_list,1}}]).
-export([bit_string/2]).
-export([octet_string/1]).
@@ -756,19 +754,21 @@ utf8_string(_Rules) ->
16#800,
16#ffff,
16#10000,
- 16#1fffff,
- 16#200000,
- 16#3ffffff,
- 16#4000000,
- 16#7fffffff],
+ 16#1ffff,
+ 16#20000,
+ 16#2ffff,
+ 16#e0000,
+ 16#effff,
+ 16#F0000,
+ 16#10ffff],
[begin
- {ok,UTF8} = asn1rt:utf8_list_to_binary([Char]),
- {ok,[Char]} = asn1rt:utf8_binary_to_list(UTF8),
+ UTF8 = unicode:characters_to_binary([Char]),
+ [Char] = unicode:characters_to_list([UTF8]),
roundtrip('UTF', UTF8)
end || Char <- AllRanges],
- {ok,UTF8} = asn1rt:utf8_list_to_binary(AllRanges),
- {ok,AllRanges} = asn1rt:utf8_binary_to_list(UTF8),
+ UTF8 = unicode:characters_to_binary(AllRanges),
+ AllRanges = unicode:characters_to_list(UTF8),
roundtrip('UTF', UTF8),
ok.
diff --git a/lib/asn1/test/testRfcs.erl b/lib/asn1/test/testRfcs.erl
index da7333ef98..502a53220e 100644
--- a/lib/asn1/test/testRfcs.erl
+++ b/lib/asn1/test/testRfcs.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,22 +35,27 @@ compile(Config, Erules, Options0) ->
asn1_test_lib:compile_all(Specs, Config, [Erules,{i,CaseDir}|Options]).
test() ->
- {1,3,6,1,5,5,7,48,1,2} =
- IdPkixOcspNonce =
- 'OCSP-2009':'id-pkix-ocsp-nonce'(),
- roundtrip('OCSP-2009', 'OCSPRequest',
- {'OCSPRequest',
- {'TBSRequest',
- 0,
- {rfc822Name,"name string"},
- [{'Request',
- {'CertID',{'_',{2,9,3,4,5},asn1_NOVALUE},
- <<"POTATOHASH">>,<<"HASHBROWN">>,42},
- [{'_',IdPkixOcspNonce,true,<<34,159,16,57,199>>}]}],
- asn1_NOVALUE},
- asn1_NOVALUE}),
- otp_7759(),
- ok.
+ M = 'OCSP-2009',
+ case M:maps() of
+ false ->
+ {1,3,6,1,5,5,7,48,1,2} =
+ IdPkixOcspNonce =
+ 'OCSP-2009':'id-pkix-ocsp-nonce'(),
+ roundtrip('OCSP-2009', 'OCSPRequest',
+ {'OCSPRequest',
+ {'TBSRequest',
+ 0,
+ {rfc822Name,"name string"},
+ [{'Request',
+ {'CertID',{'_',{2,9,3,4,5},asn1_NOVALUE},
+ <<"POTATOHASH">>,<<"HASHBROWN">>,42},
+ [{'_',IdPkixOcspNonce,true,<<34,159,16,57,199>>}]}],
+ asn1_NOVALUE},
+ asn1_NOVALUE}),
+ otp_7759(records);
+ true ->
+ otp_7759(maps)
+ end.
roundtrip(Module, Type, Value0) ->
Enc = Module:encode(Type, Value0),
@@ -58,7 +63,7 @@ roundtrip(Module, Type, Value0) ->
asn1_test_lib:match_value(Value0, Value1),
ok.
-otp_7759() ->
+otp_7759(Pack) ->
%% The release note for asn-1.6.6 says:
%% Decode of an open_type when the value was empty tagged
%% type encoded with indefinite length failed.
@@ -66,10 +71,15 @@ otp_7759() ->
Encoded = encoded_msg(),
ContentInfo = Mod:decode('ContentInfo', Encoded),
io:format("~p\n", [ContentInfo]),
- {'ContentInfo',_Id,PKCS7_content} = ContentInfo,
- X = Mod:decode('SignedData', PKCS7_content),
+ Content = case ContentInfo of
+ {'ContentInfo',_Id,Content0} when Pack =:= records ->
+ Content0;
+ #{'content-type':=_,'pkcs7-content':=Content0}
+ when Pack =:= maps ->
+ Content0
+ end,
+ X = Mod:decode('SignedData', Content),
io:format("~p\n", [X]),
- io:nl(),
ok.
encoded_msg() ->
diff --git a/lib/asn1/test/testSeqExtension.erl b/lib/asn1/test/testSeqExtension.erl
index f7885cb002..f7187314ce 100644
--- a/lib/asn1/test/testSeqExtension.erl
+++ b/lib/asn1/test/testSeqExtension.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -31,6 +31,7 @@
-record('SeqExt4',{bool, int}).
-record('SeqExt5',{name, shoesize}).
-record('SeqExt6',{i1,i2,i3,i4,i5,i6,i7}).
+-record('SeqExt7',{a=asn1_NOVALUE,b=asn1_NOVALUE,c}).
-record('SuperSeq',{s1,s2,s3,s4,s5,s6,i}).
main(Erule, DataDir, Opts) ->
@@ -45,8 +46,35 @@ main(Erule, DataDir, Opts) ->
roundtrip('SeqExt4', #'SeqExt4'{bool=true,int=12345}),
roundtrip('SeqExt4', #'SeqExt4'{bool=false,int=123456}),
+ case Erule of
+ ber ->
+ %% BER currently does not handle Extension Addition Groups
+ %% correctly.
+ ok;
+ _ ->
+ v_roundtrip3('SeqExt5', #'SeqExt5'{name=asn1_NOVALUE,
+ shoesize=asn1_NOVALUE},
+ Erule, #{per=>"00",
+ uper=>"00"}),
+ v_roundtrip3('SeqExt7', #'SeqExt7'{c=asn1_NOVALUE},
+ Erule, #{per=>"00",
+ uper=>"00"})
+ end,
roundtrip('SeqExt5', #'SeqExt5'{name = <<"Arne">>,shoesize=47}),
+ v_roundtrip3('SeqExt7', #'SeqExt7'{c=false},
+ Erule, #{per=>"80800100",
+ uper=>"80808000"}),
+ v_roundtrip3('SeqExt7', #'SeqExt7'{c=true},
+ Erule, #{per=>"80800120",
+ uper=>"80809000"}),
+ v_roundtrip3('SeqExt7', #'SeqExt7'{a=777,b = <<16#AA>>,c=false},
+ Erule, #{per=>"808006C0 030901AA 00",
+ uper=>"8082E061 20354000"}),
+ v_roundtrip3('SeqExt7', #'SeqExt7'{a=8888,c=false},
+ Erule, #{per=>"80800480 22B800",
+ uper=>"8081C457 0000"}),
+
%% Encode a value with this version of the specification.
BigInt = 128638468966,
SuperSeq = #'SuperSeq'{s1=#'SeqExt1'{},
@@ -106,6 +134,7 @@ main(Erule, DataDir, Opts) ->
v_roundtrip2(Erule, 'SeqExt130',
list_to_tuple(['SeqExt130'|
lists:duplicate(129, asn1_NOVALUE)++[199]])),
+
ok.
roundtrip(Type, Value) ->
@@ -118,6 +147,15 @@ v_roundtrip2(Erule, Type, Value) ->
roundtrip2(Type, Value) ->
asn1_test_lib:roundtrip_enc('SeqExtension2', Type, Value).
+v_roundtrip3(Type, Value, Erule, Map) ->
+ case maps:find(Erule, Map) of
+ {ok,Hex} ->
+ Encoded = asn1_test_lib:hex_to_bin(Hex),
+ Encoded = asn1_test_lib:roundtrip_enc('SeqExtension', Type, Value);
+ error ->
+ asn1_test_lib:roundtrip('SeqExtension', Type, Value)
+ end.
+
v(ber, 'SeqExt66') -> "30049F41 017D";
v(per, 'SeqExt66') -> "C0420000 00000000 00004001 FA";
v(uper, 'SeqExt66') -> "D0800000 00000000 00101FA0";
diff --git a/lib/asn1/test/testTCAP.erl b/lib/asn1/test/testTCAP.erl
index 422ae1f0fc..d892863f5e 100644
--- a/lib/asn1/test/testTCAP.erl
+++ b/lib/asn1/test/testTCAP.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -92,5 +92,6 @@ test_asn1config() ->
enc_dec(T, V0) ->
M = 'TCAPPackage',
{ok,Enc} = M:encode(T, V0),
+ asn1_test_lib:map_roundtrip(M, T, Enc),
{ok,V} = M:decode(T, Enc),
V.
diff --git a/lib/asn1/test/testTimer.erl b/lib/asn1/test/testTimer.erl
index bd8da85735..e8313802e4 100644
--- a/lib/asn1/test/testTimer.erl
+++ b/lib/asn1/test/testTimer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,7 +25,42 @@
-define(times, 5000).
-val() ->
+go() ->
+ Module = 'H323-MESSAGES',
+ Type = 'H323-UserInformation',
+ Value = case Module:maps() of
+ false -> val_records();
+ true -> val_maps()
+ end,
+ Bytes = Module:encode(Type, Value),
+ Value = Module:decode(Type, Bytes),
+
+ {ValWr,done} = timer:tc(fun() -> encode(?times, Module, Type, Value) end),
+ io:format("ASN.1 encoding: ~p micro~n", [ValWr / ?times]),
+
+ done = decode(2, Module, Type, Bytes),
+
+ {ValRead,done} = timer:tc(fun() -> decode(?times, Module, Type, Bytes) end),
+ io:format("ASN.1 decoding: ~p micro~n", [ValRead /?times]),
+
+ Comment = "encode: "++integer_to_list(round(ValWr/?times)) ++
+ " micro, decode: "++integer_to_list(round(ValRead /?times)) ++
+ " micro. [" ++ atom_to_list(Module:encoding_rule()) ++ "]",
+ {comment,Comment}.
+
+encode(0, _Module,_Type,_Value) ->
+ done;
+encode(N, Module,Type,Value) ->
+ Module:encode(Type, Value),
+ encode(N-1, Module, Type, Value).
+
+decode(0, _Module, _Type, _Value) ->
+ done;
+decode(N, Module, Type, Value) ->
+ Module:decode(Type, Value),
+ decode(N-1, Module, Type, Value).
+
+val_records() ->
{'H323-UserInformation',{'H323-UU-PDU',
{callProceeding,
{'CallProceeding-UUIE',
@@ -126,34 +161,66 @@ val() ->
{'H323-UserInformation_user-data',24,<<"O">>}}.
-go() ->
- Module = 'H323-MESSAGES',
- Type = 'H323-UserInformation',
- Value = val(),
- Bytes = Module:encode(Type, Value),
- Value = Module:decode(Type, Bytes),
-
- {ValWr,done} = timer:tc(fun() -> encode(?times, Module, Type, Value) end),
- io:format("ASN.1 encoding: ~p micro~n", [ValWr / ?times]),
-
- done = decode(2, Module, Type, Bytes),
-
- {ValRead,done} = timer:tc(fun() -> decode(?times, Module, Type, Bytes) end),
- io:format("ASN.1 decoding: ~p micro~n", [ValRead /?times]),
-
- Comment = "encode: "++integer_to_list(round(ValWr/?times)) ++
- " micro, decode: "++integer_to_list(round(ValRead /?times)) ++
- " micro. [" ++ atom_to_list(Module:encoding_rule()) ++ "]",
- {comment,Comment}.
-
-encode(0, _Module,_Type,_Value) ->
- done;
-encode(N, Module,Type,Value) ->
- Module:encode(Type, Value),
- encode(N-1, Module, Type, Value).
-
-decode(0, _Module, _Type, _Value) ->
- done;
-decode(N, Module, Type, Value) ->
- Module:decode(Type, Value),
- decode(N-1, Module, Type, Value).
+val_maps() ->
+#{'h323-uu-pdu' => #{h245Control => [],
+ h245Tunneling => true,
+ 'h323-message-body' => {callProceeding,#{callIdentifier => #{guid => <<"OCTET STRINGOCTE">>},
+ cryptoTokens => [{cryptoGKPwdEncr,#{algorithmOID => {1,18,467,467},
+ encryptedData => <<"OC">>,
+ paramS => #{iv8 => <<"OCTET ST">>,
+ ranInt => -7477016}}},
+ {cryptoGKPwdEncr,#{algorithmOID => {1,19,486,486},
+ encryptedData => <<>>,
+ paramS => #{iv8 => <<"OCTET ST">>,
+ ranInt => -2404513}}}],
+ destinationInfo => #{gatekeeper => #{nonStandardData => #{data => <<"O">>,
+ nonStandardIdentifier => {object,{0,10,260}}}},
+ gateway => #{nonStandardData => #{data => <<"O">>,
+ nonStandardIdentifier => {object,{0,13,326}}},
+ protocol => [{h320,#{dataRatesSupported => [#{channelMultiplier => 78,
+ channelRate => 1290470518,
+ nonStandardData => #{data => <<"O">>,
+ nonStandardIdentifier => {object,{0,11,295}}}}],
+ nonStandardData => #{data => <<"O">>,
+ nonStandardIdentifier => {object,{0,11,282}}},
+ supportedPrefixes => [#{nonStandardData => #{data => <<"O">>,
+ nonStandardIdentifier => {object,{0,12,312}}},
+ prefix => {'h323-ID',"BM"}}]}}]},
+ mc => true,
+ mcu => #{nonStandardData => #{data => <<"OC">>,
+ nonStandardIdentifier => {object,{1,13,340,340}}}},
+ nonStandardData => #{data => <<"O">>,nonStandardIdentifier => {object,{0,9,237}}},
+ terminal => #{nonStandardData => #{data => <<"OC">>,
+ nonStandardIdentifier => {object,{1,14,353,354}}}},
+ undefinedNode => true,
+ vendor => #{productId => <<"OC">>,
+ vendor => #{manufacturerCode => 16282,
+ t35CountryCode => 62,
+ t35Extension => 63},
+ versionId => <<"OC">>}},
+ fastStart => [],
+ h245Address => {ipxAddress,#{netnum => <<"OCTE">>,
+ node => <<"OCTET ">>,
+ port => <<"OC">>}},
+ h245SecurityMode => {noSecurity,'NULL'},
+ protocolIdentifier => {0,8,222},
+ tokens => [#{certificate => #{certificate => <<"OC">>,type => {1,16,405,406}},
+ challenge => <<"OCTET STR">>,
+ dhkey => #{generator => <<1:1>>,halfkey => <<1:1>>,modSize => <<1:1>>},
+ generalID => "BMP",
+ nonStandard => #{data => <<"OC">>,nonStandardIdentifier => {1,16,414,415}},
+ password => "BM",
+ random => -26430296,
+ timeStamp => 1667517741},
+ #{certificate => #{certificate => <<"OC">>,type => {1,17,442,443}},
+ challenge => <<"OCTET STRI">>,
+ dhkey => #{generator => <<1:1>>,halfkey => <<1:1>>,modSize => <<1:1>>},
+ generalID => "BMP",
+ nonStandard => #{data => <<"OC">>,nonStandardIdentifier => {1,18,452,452}},
+ password => "BMP",
+ random => -16356110,
+ timeStamp => 1817656756}]}},
+ h4501SupplementaryService => [],
+ nonStandardControl => [],
+ nonStandardData => #{data => <<>>,nonStandardIdentifier => {object,{0,3,84}}}},
+ 'user-data' => #{'protocol-discriminator' => 24,'user-information' => <<"O">>}}.
diff --git a/lib/asn1/test/testUniqueObjectSets.erl b/lib/asn1/test/testUniqueObjectSets.erl
index 4d3ec94391..cabdb44a0c 100644
--- a/lib/asn1/test/testUniqueObjectSets.erl
+++ b/lib/asn1/test/testUniqueObjectSets.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,6 +27,7 @@ seq_roundtrip(I, D0) ->
M = 'UniqueObjectSets',
try
{ok,Enc} = M:encode('Seq', {'Seq',I,D0}),
+ asn1_test_lib:map_roundtrip(M, 'Seq', Enc),
{ok,{'Seq',I,D}} = M:decode('Seq', Enc),
D
catch C:E ->
@@ -59,7 +60,7 @@ main(CaseDir, Rule, Opts) ->
Objs = [gen_obj(I) || {I,_,_} <- D1],
DupObjs = [gen_dup_obj(I, T) || {I,T,_} <- D1],
DupObjRefs0 = [gen_dup_obj_refs(I) || {I,_,_} <- D1],
- DupObjRefs = string:join(DupObjRefs0, " |\n"),
+ DupObjRefs = lists:join(" |\n", DupObjRefs0),
Asn1Spec = 'UniqueObjectSets',
A = ["UniqueObjectSets DEFINITIONS AUTOMATIC TAGS ::=\n",
"BEGIN\n\n",
diff --git a/lib/asn1/test/test_compile_options.erl b/lib/asn1/test/test_compile_options.erl
index ac74470537..f9997d37d0 100644
--- a/lib/asn1/test/test_compile_options.erl
+++ b/lib/asn1/test/test_compile_options.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2017. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -24,8 +24,8 @@
-include_lib("common_test/include/ct.hrl").
--export([wrong_path/1,comp/2,path/1,ticket_6143/1,noobj/1,
- record_name_prefix/1,verbose/1]).
+-export([wrong_path/1,comp/2,path/1,noobj/1,
+ record_name_prefix/1,verbose/1,maps/1]).
%% OTP-5689
wrong_path(Config) ->
@@ -64,8 +64,6 @@ path(Config) ->
file:set_cwd(CWD),
ok.
-ticket_6143(Config) -> asn1_test_lib:compile("AA1", Config, []).
-
noobj(Config) ->
DataDir = proplists:get_value(data_dir,Config),
OutDir = proplists:get_value(priv_dir,Config),
@@ -130,6 +128,28 @@ verbose(Config) when is_list(Config) ->
[] = test_server:capture_get(),
ok.
+maps(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ OutDir = proplists:get_value(case_dir, Config),
+ InFile = filename:join(DataDir, "P-Record"),
+
+ do_maps(ber, InFile, OutDir),
+ do_maps(per, InFile, OutDir),
+ do_maps(uper, InFile, OutDir).
+
+do_maps(Erule, InFile, OutDir) ->
+ Opts = [Erule,maps,{outdir,OutDir}],
+ ok = asn1ct:compile(InFile, Opts),
+
+ %% Make sure that no .hrl files are generated.
+ [] = filelib:wildcard(filename:join(OutDir, "*.hrl")),
+
+ %% Remove all generated files.
+ All = filelib:wildcard(filename:join(OutDir, "*")),
+ _ = [file:delete(N) || N <- All],
+
+ ok.
+
outfiles_check(OutDir) ->
outfiles_check(OutDir,outfiles1()).
diff --git a/lib/asn1/test/test_modified_x420.erl b/lib/asn1/test/test_modified_x420.erl
index 6cd9e0e33b..15f7c70978 100644
--- a/lib/asn1/test/test_modified_x420.erl
+++ b/lib/asn1/test/test_modified_x420.erl
@@ -38,7 +38,7 @@ read_pem(File) ->
extract_base64(Binary) ->
- extract_base64_lines(string:tokens(binary_to_list(Binary), "\n")).
+ extract_base64_lines(string:lexemes(binary_to_list(Binary), "\n")).
extract_base64_lines(["-----BEGIN"++_ | Lines]) ->
take_base64_lines(Lines, _Acc = []);
diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk
index e4bf3e2236..39dfe8f4fb 100644
--- a/lib/asn1/vsn.mk
+++ b/lib/asn1/vsn.mk
@@ -1 +1 @@
-ASN1_VSN = 4.0.4
+ASN1_VSN = 5.0.5