• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#
2# This file is part of pyasn1 software.
3#
4# Copyright (c) 2005-2018, Ilya Etingof <etingof@gmail.com>
5# License: http://snmplabs.com/pyasn1/license.html
6#
7from pyasn1 import error
8
9__all__ = ['tagClassUniversal', 'tagClassApplication', 'tagClassContext',
10           'tagClassPrivate', 'tagFormatSimple', 'tagFormatConstructed',
11           'tagCategoryImplicit', 'tagCategoryExplicit',
12           'tagCategoryUntagged', 'Tag', 'TagSet']
13
14#: Identifier for ASN.1 class UNIVERSAL
15tagClassUniversal = 0x00
16
17#: Identifier for ASN.1 class APPLICATION
18tagClassApplication = 0x40
19
20#: Identifier for ASN.1 class context-specific
21tagClassContext = 0x80
22
23#: Identifier for ASN.1 class private
24tagClassPrivate = 0xC0
25
26#: Identifier for "simple" ASN.1 structure (e.g. scalar)
27tagFormatSimple = 0x00
28
29#: Identifier for "constructed" ASN.1 structure (e.g. may have inner components)
30tagFormatConstructed = 0x20
31
32tagCategoryImplicit = 0x01
33tagCategoryExplicit = 0x02
34tagCategoryUntagged = 0x04
35
36
37class Tag(object):
38    """Create ASN.1 tag
39
40    Represents ASN.1 tag that can be attached to a ASN.1 type to make
41    types distinguishable from each other.
42
43    *Tag* objects are immutable and duck-type Python :class:`tuple` objects
44    holding three integer components of a tag.
45
46    Parameters
47    ----------
48    tagClass: :py:class:`int`
49        Tag *class* value
50
51    tagFormat: :py:class:`int`
52        Tag *format* value
53
54    tagId: :py:class:`int`
55        Tag ID value
56    """
57    def __init__(self, tagClass, tagFormat, tagId):
58        if tagId < 0:
59            raise error.PyAsn1Error('Negative tag ID (%s) not allowed' % tagId)
60        self.__tagClass = tagClass
61        self.__tagFormat = tagFormat
62        self.__tagId = tagId
63        self.__tagClassId = tagClass, tagId
64        self.__hash = hash(self.__tagClassId)
65
66    def __repr__(self):
67        representation = '[%s:%s:%s]' % (self.__tagClass, self.__tagFormat, self.__tagId)
68        return '<%s object at 0x%x tag %s>' % (self.__class__.__name__, id(self), representation)
69
70    def __eq__(self, other):
71        return self.__tagClassId == other
72
73    def __ne__(self, other):
74        return self.__tagClassId != other
75
76    def __lt__(self, other):
77        return self.__tagClassId < other
78
79    def __le__(self, other):
80        return self.__tagClassId <= other
81
82    def __gt__(self, other):
83        return self.__tagClassId > other
84
85    def __ge__(self, other):
86        return self.__tagClassId >= other
87
88    def __hash__(self):
89        return self.__hash
90
91    def __getitem__(self, idx):
92        if idx == 0:
93            return self.__tagClass
94        elif idx == 1:
95            return self.__tagFormat
96        elif idx == 2:
97            return self.__tagId
98        else:
99            raise IndexError()
100
101    def __iter__(self):
102        yield self.__tagClass
103        yield self.__tagFormat
104        yield self.__tagId
105
106    def __and__(self, otherTag):
107        return self.__class__(self.__tagClass & otherTag.tagClass,
108                              self.__tagFormat & otherTag.tagFormat,
109                              self.__tagId & otherTag.tagId)
110
111    def __or__(self, otherTag):
112        return self.__class__(self.__tagClass | otherTag.tagClass,
113                              self.__tagFormat | otherTag.tagFormat,
114                              self.__tagId | otherTag.tagId)
115
116    @property
117    def tagClass(self):
118        """ASN.1 tag class
119
120        Returns
121        -------
122        : :py:class:`int`
123            Tag class
124        """
125        return self.__tagClass
126
127    @property
128    def tagFormat(self):
129        """ASN.1 tag format
130
131        Returns
132        -------
133        : :py:class:`int`
134            Tag format
135        """
136        return self.__tagFormat
137
138    @property
139    def tagId(self):
140        """ASN.1 tag ID
141
142        Returns
143        -------
144        : :py:class:`int`
145            Tag ID
146        """
147        return self.__tagId
148
149
150class TagSet(object):
151    """Create a collection of ASN.1 tags
152
153    Represents a combination of :class:`~pyasn1.type.tag.Tag` objects
154    that can be attached to a ASN.1 type to make types distinguishable
155    from each other.
156
157    *TagSet* objects are immutable and duck-type Python :class:`tuple` objects
158    holding arbitrary number of :class:`~pyasn1.type.tag.Tag` objects.
159
160    Parameters
161    ----------
162    baseTag: :class:`~pyasn1.type.tag.Tag`
163        Base *Tag* object. This tag survives IMPLICIT tagging.
164
165    *superTags: :class:`~pyasn1.type.tag.Tag`
166        Additional *Tag* objects taking part in subtyping.
167
168    Examples
169    --------
170    .. code-block:: python
171
172        class OrderNumber(NumericString):
173            '''
174            ASN.1 specification
175
176            Order-number ::=
177                [APPLICATION 5] IMPLICIT NumericString
178            '''
179            tagSet = NumericString.tagSet.tagImplicitly(
180                Tag(tagClassApplication, tagFormatSimple, 5)
181            )
182
183        orderNumber = OrderNumber('1234')
184    """
185    def __init__(self, baseTag=(), *superTags):
186        self.__baseTag = baseTag
187        self.__superTags = superTags
188        self.__superTagsClassId = tuple(
189            [(superTag.tagClass, superTag.tagId) for superTag in superTags]
190        )
191        self.__lenOfSuperTags = len(superTags)
192        self.__hash = hash(self.__superTagsClassId)
193
194    def __repr__(self):
195        representation = '-'.join(['%s:%s:%s' % (x.tagClass, x.tagFormat, x.tagId)
196                                   for x in self.__superTags])
197        if representation:
198            representation = 'tags ' + representation
199        else:
200            representation = 'untagged'
201
202        return '<%s object at 0x%x %s>' % (self.__class__.__name__, id(self), representation)
203
204    def __add__(self, superTag):
205        return self.__class__(self.__baseTag, *self.__superTags + (superTag,))
206
207    def __radd__(self, superTag):
208        return self.__class__(self.__baseTag, *(superTag,) + self.__superTags)
209
210    def __getitem__(self, i):
211        if i.__class__ is slice:
212            return self.__class__(self.__baseTag, *self.__superTags[i])
213        else:
214            return self.__superTags[i]
215
216    def __eq__(self, other):
217        return self.__superTagsClassId == other
218
219    def __ne__(self, other):
220        return self.__superTagsClassId != other
221
222    def __lt__(self, other):
223        return self.__superTagsClassId < other
224
225    def __le__(self, other):
226        return self.__superTagsClassId <= other
227
228    def __gt__(self, other):
229        return self.__superTagsClassId > other
230
231    def __ge__(self, other):
232        return self.__superTagsClassId >= other
233
234    def __hash__(self):
235        return self.__hash
236
237    def __len__(self):
238        return self.__lenOfSuperTags
239
240    @property
241    def baseTag(self):
242        """Return base ASN.1 tag
243
244        Returns
245        -------
246        : :class:`~pyasn1.type.tag.Tag`
247            Base tag of this *TagSet*
248        """
249        return self.__baseTag
250
251    @property
252    def superTags(self):
253        """Return ASN.1 tags
254
255        Returns
256        -------
257        : :py:class:`tuple`
258            Tuple of :class:`~pyasn1.type.tag.Tag` objects that this *TagSet* contains
259        """
260        return self.__superTags
261
262    def tagExplicitly(self, superTag):
263        """Return explicitly tagged *TagSet*
264
265        Create a new *TagSet* representing callee *TagSet* explicitly tagged
266        with passed tag(s). With explicit tagging mode, new tags are appended
267        to existing tag(s).
268
269        Parameters
270        ----------
271        superTag: :class:`~pyasn1.type.tag.Tag`
272            *Tag* object to tag this *TagSet*
273
274        Returns
275        -------
276        : :class:`~pyasn1.type.tag.TagSet`
277            New *TagSet* object
278        """
279        if superTag.tagClass == tagClassUniversal:
280            raise error.PyAsn1Error("Can't tag with UNIVERSAL class tag")
281        if superTag.tagFormat != tagFormatConstructed:
282            superTag = Tag(superTag.tagClass, tagFormatConstructed, superTag.tagId)
283        return self + superTag
284
285    def tagImplicitly(self, superTag):
286        """Return implicitly tagged *TagSet*
287
288        Create a new *TagSet* representing callee *TagSet* implicitly tagged
289        with passed tag(s). With implicit tagging mode, new tag(s) replace the
290        last existing tag.
291
292        Parameters
293        ----------
294        superTag: :class:`~pyasn1.type.tag.Tag`
295            *Tag* object to tag this *TagSet*
296
297        Returns
298        -------
299        : :class:`~pyasn1.type.tag.TagSet`
300            New *TagSet* object
301        """
302        if self.__superTags:
303            superTag = Tag(superTag.tagClass, self.__superTags[-1].tagFormat, superTag.tagId)
304        return self[:-1] + superTag
305
306    def isSuperTagSetOf(self, tagSet):
307        """Test type relationship against given *TagSet*
308
309        The callee is considered to be a supertype of given *TagSet*
310        tag-wise if all tags in *TagSet* are present in the callee and
311        they are in the same order.
312
313        Parameters
314        ----------
315        tagSet: :class:`~pyasn1.type.tag.TagSet`
316            *TagSet* object to evaluate against the callee
317
318        Returns
319        -------
320        : :py:class:`bool`
321            `True` if callee is a supertype of *tagSet*
322        """
323        if len(tagSet) < self.__lenOfSuperTags:
324            return False
325        return self.__superTags == tagSet[:self.__lenOfSuperTags]
326
327    # Backward compatibility
328
329    def getBaseTag(self):
330        return self.__baseTag
331
332def initTagSet(tag):
333    return TagSet(tag, tag)
334