summaryrefslogtreecommitdiff
path: root/pyasn1/type/tag.py
blob: f040c1b52de482c98a09f3ce6cc04592a08ed000 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#
# This file is part of pyasn1 software.
#
# Copyright (c) 2005-2015, Ilya Etingof <ilya@glas.net>
# License: http://pyasn1.sf.net/license.html
#
from operator import getitem
from pyasn1 import error

tagClassUniversal = 0x00
tagClassApplication = 0x40
tagClassContext = 0x80
tagClassPrivate = 0xC0

tagFormatSimple = 0x00
tagFormatConstructed = 0x20

tagCategoryImplicit = 0x01
tagCategoryExplicit = 0x02
tagCategoryUntagged = 0x04

class Tag:
    """ASN.1 types tags"""
    def __init__(self, tagClass, tagFormat, tagId):
        if tagId < 0:
            raise error.PyAsn1Error(
                'Negative tag ID (%s) not allowed' % (tagId,)
                )
        self.__tag = (tagClass, tagFormat, tagId)
        self.uniq = (tagClass, tagId)
        self.__hashedUniqTag = hash(self.uniq)

    def __str__(self):
        return '[%s:%s:%s]' % self.__tag

    def __repr__(self):
        return '%s(tagClass=%s, tagFormat=%s, tagId=%s)' % (
            (self.__class__.__name__,) + self.__tag
            )
    # These is really a hotspot -- expose public "uniq" attribute to save on
    # function calls
    def __eq__(self, other): return self.uniq == other.uniq
    def __ne__(self, other): return self.uniq != other.uniq
    def __lt__(self, other): return self.uniq < other.uniq
    def __le__(self, other): return self.uniq <= other.uniq
    def __gt__(self, other): return self.uniq > other.uniq
    def __ge__(self, other): return self.uniq >= other.uniq
    def __hash__(self): return self.__hashedUniqTag
    def __getitem__(self, idx): return self.__tag[idx]
    def __and__(self, otherTag):
        (tagClass, tagFormat, tagId) = otherTag
        return self.__class__(
            self.__tag&tagClass, self.__tag&tagFormat, self.__tag&tagId
            )
    def __or__(self, otherTag):
        (tagClass, tagFormat, tagId) = otherTag
        return self.__class__(
            self.__tag[0]|tagClass,
            self.__tag[1]|tagFormat,
            self.__tag[2]|tagId
            )
    def asTuple(self): return self.__tag  # __getitem__() is slow
    
class TagSet:
    def __init__(self, baseTag=(), *superTags):
        self.__baseTag = baseTag
        self.__superTags = superTags
        self.__hashedSuperTags = hash(superTags)
        _uniq = ()
        for t in superTags:
            _uniq = _uniq + t.uniq
        self.uniq = _uniq
        self.__lenOfSuperTags = len(superTags)

    def __str__(self):
        return self.__superTags and '+'.join([str(x) for x in self.__superTags]) or '[untagged]'
 
    def __repr__(self):
        return '%s(%s)' % (
            self.__class__.__name__,
            '(), ' + ', '.join([repr(x) for x in self.__superTags])
            )

    def __add__(self, superTag):
        return self.__class__(
            self.__baseTag, *self.__superTags + (superTag,)
            )
    def __radd__(self, superTag):
        return self.__class__(
            self.__baseTag, *(superTag,) + self.__superTags
            )

    def tagExplicitly(self, superTag):
        tagClass, tagFormat, tagId = superTag
        if tagClass == tagClassUniversal:
            raise error.PyAsn1Error(
                'Can\'t tag with UNIVERSAL-class tag'
                )
        if tagFormat != tagFormatConstructed:
            superTag = Tag(tagClass, tagFormatConstructed, tagId)
        return self + superTag

    def tagImplicitly(self, superTag):
        tagClass, tagFormat, tagId = superTag
        if self.__superTags:
            superTag = Tag(tagClass, self.__superTags[-1][1], tagId)
        return self[:-1] + superTag

    def getBaseTag(self): return self.__baseTag
    def __getitem__(self, idx):
        if isinstance(idx, slice):
            return self.__class__(
               self.__baseTag, *getitem(self.__superTags, idx)
            )
        return self.__superTags[idx]
    def __eq__(self, other): return self.uniq == other.uniq
    def __ne__(self, other): return self.uniq != other.uniq
    def __lt__(self, other): return self.uniq < other.uniq
    def __le__(self, other): return self.uniq <= other.uniq
    def __gt__(self, other): return self.uniq > other.uniq
    def __ge__(self, other): return self.uniq >= other.uniq
    def __hash__(self): return self.__hashedSuperTags
    def __len__(self): return self.__lenOfSuperTags
    def isSuperTagSetOf(self, tagSet):
        if len(tagSet) < self.__lenOfSuperTags:
            return
        idx = self.__lenOfSuperTags - 1
        while idx >= 0:
            if self.__superTags[idx] != tagSet[idx]:
                return
            idx = idx - 1
        return 1
    
def initTagSet(tag): return TagSet(tag, tag)