eSNACC对ASN.1 constructors的处理

eSNACC对ASN.1 constructors的处理

首先让我们来学习一下ASN.1的Constructors类型 。
ASN.1 constructors 类型可以将简单的预定义类型封装成复杂的数据类型。而且,这种操作可以是嵌套的,比如,constructors中还可以包含其他的constructors类型。ASN.1的constructors类型有:
  • SEQUENCE
  • SEQUENCE OF
  • SET
  • SET OF
  • CHOICE

SEQUENCE

SEQUENCE是一个表示有序元素集合的数据类型。集合可能为空,集合中的元素可以是任意ASN.1类型,并且元素类型可以不同。集合中的元素还可以被命名。这类似于C/C++中的结构体。

  • ASequence ::= SEQUENCE {field1 INTEGER, field2 BOOLEAN}
  • a-value ASequence ::= { field1 123, field2 TRUE }

SEQUENCE OF

SEQUENCE OF 是一个表示有序元素集合的数据类型,集合可以为空。集合中的元素可以是任意ASN.1类型,但是要求所有元素为同一类型。集合中的元素可以被命名。这很类似于C/C++中的有序数组/链表。

  • ASequenceOf ::= SEQUENCE OF INTEGER { field1, field2 }

SET

SET 是一个表示无序元素集合的数据类型,集合可以为空。集合中的元素可以是任意ASN.1类型,并且元素类型可以不同。集合中的元素可以被命名。这同样类似于C/C++中的结构体。

  • ASet ::= SET { field1 INTEGER, field2 BOOLEAN }

SET OF

SET OF 是一个表示无序元素集合的数据类型,集合可以为空。集合中的元素可以是任意ASN.1类型,但是要求所有元素为同一类型。集合中的元素可以被命名。这很类似于C/C++中的无序数组/链表。 

  • ASetOf ::= SET OF INTEGER { field1, field2 }

一眼看上去似乎SEQUENCE 和SET是一样的。其实不同就在于SEQUENCE是有序的,而SET不是。比如,在上面的例子中,SET在编码时,字段field2就可以比field1先发送,而对SEQUENCE,我们希望field1必须在field2之前先处理。

SEQUENCE OF 和SET OF的区别也就在这。

总而言之,SEQUENCE 和SEQUENCE OF依赖顺序来避免模糊。而SET 和SET OF就依赖数据类型或者每个元素的标签来唯一区分每个元素。

OPTIONAL

 SEQUENCE 等集合中出现的关键字OPTIONAL表示集合中的那个元素不是必须的:也就是可以存在也可以省略。  例如:

  • ASequence ::= SEQUENCE { field1 INTEGER OPTIONAL, field2 BOOLEAN }
  • a-value1 ASequence ::= { 123, TRUE }
  • a-value2 ASequence ::= { TRUE }

这对SEQUENCE OF, SET 和SET OF都适用。

DEFAULT

在某些情况下,给指定类型的某个元素设定一个默认值在编码时是非常有用的。

  • ASequence ::= SEQUENCE { field1 INTEGER DEFAULT 0, field2 BOOLEAN }

CHOICE

CHOICE类型是一个定义一个或者多个类型的联合的数据类型。这个联合中的字段可以被命名。每一个CHOICE的实例,都必须指定为这个联合中的一个类型。例如: 

  • AllPDUs ::= CHOICE {pdu1 SEQUENCE { ..... }, pdu2 SEQUENCE { ..... }, pdu3 SEQUENCE { ..... } }
  • a_pdu AllPDUs ::= pdu2

以上内容翻译自http://www.lkn.ei.tum.de/arbeiten/faq/man/tau42_help/ttcncase8.html。

 

/*******************************************休息一下***************************************

下面我们来研究eSNACC的C代码生成和C运行时库对ASN.1 constructors的处理办法:

一、因为ASN.1允许不命名集合中的字段,但是C语言要求变量必须有名字,所以eSNACC对SETs, SEQUENCEs, CHOICEs中的空字段都会自动命名。名字依赖于该字段的类型名。

二、对SEQUENCE (of)SET (of)中用OPTIONAL指定的可选元素,大部分都以指针实现。当指针不为NULL时那么就代表这个元素存在。不过当元素是OCTET STRINGs, BIT STRINGs OBJECT IDENTIFIERs类型时例外,因为这些类型很小,而且底层实现还包含一个内部的指针,利用那个指针就可以表明元素是否存在。具体请参加本系列前面的文章:对比特串、字节串、OBJECT IDENTIFIERs的编码和解码等。

三、总结:eSNACC对ASN.1 constructors->C类型转换规则:

SEQUENCE —> C struct
SET —> C struct

SEQUENCE OF —> 双向链表AsnList
SET OF —> 双向链表AsnList

ENUMERATED  —> C enum
CHOICE : 比较有意思,我们以后再专门讨论。

ASN.1到C struct和enum就是直接的对应关系,很简单。这里我们主要看看eSNACC的双向链表AsnList。

看一下AsnList的定义:

typedef  struct  AsnListNode
{
    
struct AsnListNode    *prev;
    
struct AsnListNode    *next;
    
void        *data;        /**//* this must be the last field of this structure  */
}
 AsnListNode;

typedef 
struct  AsnList
{
    AsnListNode        
*first;
    AsnListNode        
*last;
    AsnListNode        
*curr;
    
int            count;        /**//* number of elements in list               */
    
int            dataSize;    /**//* space required in each node for the data */
}
 AsnList;

要注意AsnList与我们一般写的链表可能不同的是:他专门设计了一个头AsnList,而真正存放节点内容的是AsnListNode。AsnList中包含了头结点、尾节点、当前节点指针,节点元素的数目和每一个节点元素的数据大小(也就是为data分配内存时的值)。

利用AsnList,我们就能很方便的得知包括链表头尾指针、总数等的信息了。也能很方便的对整个链表进行遍历访问等操作了。

要说明的是:first节点的prev指针和last的next指针总是NULL。而且AsnList的dataSize字段必须在生成链表或者使用前初始化时就必须赋予明确的值,因为只是每创建一个AsnListNode时对data分配的内存大小数。

对AsnList的分析,我准备就只讲这些了。之所以不展开函数实现,是因为里面就是数据结构中的链表操作算法,想必大家都相当熟悉,所以不怕老生常谈,也担心班门弄斧,就算了吧。

 

不过,你可能发现有些问题:

1、上文中提到过:SEQUENCE OF是有序的,而SET OF无序的。那我们在编译成C语言时要怎么对应呢?我们看看eSNACC:他丝毫没有提这个,压根就无视这个性质!这有问题吗?

从ASN.1语义上来说,确实是没有体现,但是其实是没有问题的。因为ASN.1中所要求的有序无序,是说明数据编码和传输的问题:有序就是要保证数据定义的顺序。而我们转为C语言,本来就是按数据定义的顺序而转的,而编码解码自然就只能是C定义的顺序了,也就是说最后无论是对SEQUENCE OF还是SET OF,我们都保证了他是有序的,这当然没有问题了。

2、AsnList中存放数据的都是void*类型,这就不知道数据的原始类型了呀?

是的,AsnList中确实只是存放了void*,这导致类型丢失了。也就是你如果不小心存了不同类型的数据,他也一言不发的纵容了你。这是类型不安全的。BTW,在eSNACC的C++库中,就不存在这个问题了,这个留待以后对eSNACC的C++运行时库剖析时再说。

 

好了,本篇就到此了。

 

你可能感兴趣的:(eSNACC对ASN.1 constructors的处理)