diff options
Diffstat (limited to 'python/pyasn1/doc/constructed.html')
-rw-r--r-- | python/pyasn1/doc/constructed.html | 377 |
1 files changed, 377 insertions, 0 deletions
diff --git a/python/pyasn1/doc/constructed.html b/python/pyasn1/doc/constructed.html new file mode 100644 index 0000000000..88de750758 --- /dev/null +++ b/python/pyasn1/doc/constructed.html @@ -0,0 +1,377 @@ +<html> +<title> +PyASN1 Constructed types +</title> +<head> +</head> +<body> +<center> +<table width=60%> +<tr> +<td> + +<h4> +1.3 PyASN1 Constructed types +</h4> + +<p> +Besides scalar types, ASN.1 specifies so-called constructed ones - these +are capable of holding one or more values of other types, both scalar +and constructed. +</p> + +<p> +In pyasn1 implementation, constructed ASN.1 types behave like +Python sequences, and also support additional component addressing methods, +specific to particular constructed type. +</p> + +<a name="1.3.1"></a> +<h4> +1.3.1 Sequence and Set types +</h4> + +<p> +The Sequence and Set types have many similar properties: +</p> +<ul> +<li>they can hold any number of inner components of different types +<li>every component has a human-friendly identifier +<li>any component can have a default value +<li>some components can be absent. +</ul> + +<p> +However, Sequence type guarantees the ordering of Sequence value components +to match their declaration order. By contrast, components of the +Set type can be ordered to best suite application's needs. +<p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +Record ::= SEQUENCE { + id INTEGER, + room [0] INTEGER OPTIONAL, + house [1] INTEGER DEFAULT 0 +} +</pre> +</td></tr></table> + +<p> +Up to this moment, the only method we used for creating new pyasn1 types +is Python sub-classing. With this method, a new, named Python class is created +what mimics type derivation in ASN.1 grammar. However, ASN.1 also allows for +defining anonymous subtypes (room and house components in the example above). +To support anonymous subtyping in pyasn1, a cloning operation on an existing +pyasn1 type object can be invoked what creates a new instance of original +object with possibly modified properties. +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> from pyasn1.type import univ, namedtype, tag +>>> class Record(univ.Sequence): +... componentType = namedtype.NamedTypes( +... namedtype.NamedType('id', univ.Integer()), +... namedtype.OptionalNamedType( +... 'room', +... univ.Integer().subtype( +... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 0) +... ) +... ), +... namedtype.DefaultedNamedType( +... 'house', +... univ.Integer(0).subtype( +... implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1) +... ) +... ) +... ) +>>> +</pre> +</td></tr></table> + +<p> +All pyasn1 constructed type classes have a class attribute <b>componentType</b> +that represent default type specification. Its value is a NamedTypes object. +</p> + +<p> +The NamedTypes class instance holds a sequence of NameType, OptionalNamedType +or DefaultedNamedType objects which, in turn, refer to pyasn1 type objects that +represent inner SEQUENCE components specification. +</p> + +<p> +Finally, invocation of a subtype() method of pyasn1 type objects in the code +above returns an implicitly tagged copy of original object. +</p> + +<p> +Once a SEQUENCE or SET type is decleared with pyasn1, it can be instantiated +and initialized (continuing the above code): +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> record = Record() +>>> record.setComponentByName('id', 123) +>>> print(record.prettyPrint()) +Record: + id=123 +>>> +>>> record.setComponentByPosition(1, 321) +>>> print(record.prettyPrint()) +Record: + id=123 + room=321 +>>> +>>> record.setDefaultComponents() +>>> print(record.prettyPrint()) +Record: + id=123 + room=321 + house=0 +</pre> +</td></tr></table> + +<p> +Inner components of pyasn1 Sequence/Set objects could be accessed using the +following methods: +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> record.getComponentByName('id') +Integer(123) +>>> record.getComponentByPosition(1) +Integer(321) +>>> record[2] +Integer(0) +>>> for idx in range(len(record)): +... print(record.getNameByPosition(idx), record.getComponentByPosition(idx)) +id 123 +room 321 +house 0 +>>> +</pre> +</td></tr></table> + +<p> +The Set type share all the properties of Sequence type, and additionally +support by-tag component addressing (as all Set components have distinct +types). +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> from pyasn1.type import univ, namedtype, tag +>>> class Gamer(univ.Set): +... componentType = namedtype.NamedTypes( +... namedtype.NamedType('score', univ.Integer()), +... namedtype.NamedType('player', univ.OctetString()), +... namedtype.NamedType('id', univ.ObjectIdentifier()) +... ) +>>> gamer = Gamer() +>>> gamer.setComponentByType(univ.Integer().getTagSet(), 121343) +>>> gamer.setComponentByType(univ.OctetString().getTagSet(), 'Pascal') +>>> gamer.setComponentByType(univ.ObjectIdentifier().getTagSet(), (1,3,7,2)) +>>> print(gamer.prettyPrint()) +Gamer: + score=121343 + player=b'Pascal' + id=1.3.7.2 +>>> +</pre> +</td></tr></table> + +<a name="1.3.2"></a> +<h4> +1.3.2 SequenceOf and SetOf types +</h4> + +<p> +Both, SequenceOf and SetOf types resemble an unlimited size list of components. +All the components must be of the same type. +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +Progression ::= SEQUENCE OF INTEGER + +arithmeticProgression Progression ::= { 1, 3, 5, 7 } +</pre> +</td></tr></table> + +<p> +SequenceOf and SetOf types are expressed by the very similar pyasn1 type +objects. Their components can only be addressed by position and they +both have a property of automatic resize. +</p> + +<p> +To specify inner component type, the <b>componentType</b> class attribute +should refer to another pyasn1 type object. +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> from pyasn1.type import univ +>>> class Progression(univ.SequenceOf): +... componentType = univ.Integer() +>>> arithmeticProgression = Progression() +>>> arithmeticProgression.setComponentByPosition(1, 111) +>>> print(arithmeticProgression.prettyPrint()) +Progression: +-empty- 111 +>>> arithmeticProgression.setComponentByPosition(0, 100) +>>> print(arithmeticProgression.prettyPrint()) +Progression: +100 111 +>>> +>>> for idx in range(len(arithmeticProgression)): +... arithmeticProgression.getComponentByPosition(idx) +Integer(100) +Integer(111) +>>> +</pre> +</td></tr></table> + +<p> +Any scalar or constructed pyasn1 type object can serve as an inner component. +Missing components are prohibited in SequenceOf/SetOf value objects. +</p> + +<a name="1.3.3"></a> +<h4> +1.3.3 Choice type +</h4> + +<p> +Values of ASN.1 CHOICE type can contain only a single value of a type from a +list of possible alternatives. Alternatives must be ASN.1 types with +distinct tags for the whole structure to remain unambiguous. Unlike most +other types, CHOICE is an untagged one, e.g. it has no base tag of its own. +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +CodeOrMessage ::= CHOICE { + code INTEGER, + message OCTET STRING +} +</pre> +</td></tr></table> + +<p> +In pyasn1 implementation, Choice object behaves like Set but accepts only +a single inner component at a time. It also offers a few additional methods +specific to its behaviour. +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> from pyasn1.type import univ, namedtype +>>> class CodeOrMessage(univ.Choice): +... componentType = namedtype.NamedTypes( +... namedtype.NamedType('code', univ.Integer()), +... namedtype.NamedType('message', univ.OctetString()) +... ) +>>> +>>> codeOrMessage = CodeOrMessage() +>>> print(codeOrMessage.prettyPrint()) +CodeOrMessage: +>>> codeOrMessage.setComponentByName('code', 123) +>>> print(codeOrMessage.prettyPrint()) +CodeOrMessage: + code=123 +>>> codeOrMessage.setComponentByName('message', 'my string value') +>>> print(codeOrMessage.prettyPrint()) +CodeOrMessage: + message=b'my string value' +>>> +</pre> +</td></tr></table> + +<p> +Since there could be only a single inner component value in the pyasn1 Choice +value object, either of the following methods could be used for fetching it +(continuing previous code): +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> codeOrMessage.getName() +'message' +>>> codeOrMessage.getComponent() +OctetString(b'my string value') +>>> +</pre> +</td></tr></table> + +<a name="1.3.4"></a> +<h4> +1.3.4 Any type +</h4> + +<p> +The ASN.1 ANY type is a kind of wildcard or placeholder that matches +any other type without knowing it in advance. Like CHOICE type, ANY +has no base tag. +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +Error ::= SEQUENCE { + code INTEGER, + parameter ANY DEFINED BY code +} +</pre> +</td></tr></table> + +<p> +The ANY type is frequently used in specifications, where exact type is not +yet agreed upon between communicating parties or the number of possible +alternatives of a type is infinite. +Sometimes an auxiliary selector is kept around to help parties indicate +the kind of ANY payload in effect ("code" in the example above). +</p> + +<p> +Values of the ANY type contain serialized ASN.1 value(s) in form of +an octet string. Therefore pyasn1 Any value object share the properties of +pyasn1 OctetString object. +</p> + +<table bgcolor="lightgray" border=0 width=100%><TR><TD> +<pre> +>>> from pyasn1.type import univ +>>> someValue = univ.Any(b'\x02\x01\x01') +>>> someValue +Any(b'\x02\x01\x01') +>>> str(someValue) +'\x02\x01\x01' +>>> bytes(someValue) +b'\x02\x01\x01' +>>> +</pre> +</td></tr></table> + +<p> +Receiving application is supposed to explicitly deserialize the content of Any +value object, possibly using auxiliary selector for figuring out its ASN.1 +type to pick appropriate decoder. +</p> + +<p> +There will be some more talk and code snippets covering Any type in the codecs +chapters that follow. +</p> + +<hr> + +</td> +</tr> +</table> +</center> +</body> +</html> |