1# ASN.1 types tags
2from operator import getitem
3from pyasn1 import error
4
5tagClassUniversal = 0x00
6tagClassApplication = 0x40
7tagClassContext = 0x80
8tagClassPrivate = 0xC0
9
10tagFormatSimple = 0x00
11tagFormatConstructed = 0x20
12
13tagCategoryImplicit = 0x01
14tagCategoryExplicit = 0x02
15tagCategoryUntagged = 0x04
16
17class Tag:
18    def __init__(self, tagClass, tagFormat, tagId):
19        if tagId < 0:
20            raise error.PyAsn1Error(
21                'Negative tag ID (%s) not allowed' % (tagId,)
22                )
23        self.__tag = (tagClass, tagFormat, tagId)
24        self.uniq = (tagClass, tagId)
25        self.__hashedUniqTag = hash(self.uniq)
26
27    def __repr__(self):
28        return '%s(tagClass=%s, tagFormat=%s, tagId=%s)' % (
29            (self.__class__.__name__,) + self.__tag
30            )
31    # These is really a hotspot -- expose public "uniq" attribute to save on
32    # function calls
33    def __eq__(self, other): return self.uniq == other.uniq
34    def __ne__(self, other): return self.uniq != other.uniq
35    def __lt__(self, other): return self.uniq < other.uniq
36    def __le__(self, other): return self.uniq <= other.uniq
37    def __gt__(self, other): return self.uniq > other.uniq
38    def __ge__(self, other): return self.uniq >= other.uniq
39    def __hash__(self): return self.__hashedUniqTag
40    def __getitem__(self, idx): return self.__tag[idx]
41    def __and__(self, otherTag):
42        (tagClass, tagFormat, tagId) = otherTag
43        return self.__class__(
44            self.__tag&tagClass, self.__tag&tagFormat, self.__tag&tagId
45            )
46    def __or__(self, otherTag):
47        (tagClass, tagFormat, tagId) = otherTag
48        return self.__class__(
49            self.__tag[0]|tagClass,
50            self.__tag[1]|tagFormat,
51            self.__tag[2]|tagId
52            )
53    def asTuple(self): return self.__tag  # __getitem__() is slow
54
55class TagSet:
56    def __init__(self, baseTag=(), *superTags):
57        self.__baseTag = baseTag
58        self.__superTags = superTags
59        self.__hashedSuperTags = hash(superTags)
60        _uniq = ()
61        for t in superTags:
62            _uniq = _uniq + t.uniq
63        self.uniq = _uniq
64        self.__lenOfSuperTags = len(superTags)
65
66    def __repr__(self):
67        return '%s(%s)' % (
68            self.__class__.__name__,
69            ', '.join([repr(x) for x in self.__superTags])
70            )
71
72    def __add__(self, superTag):
73        return self.__class__(
74            self.__baseTag, *self.__superTags + (superTag,)
75            )
76    def __radd__(self, superTag):
77        return self.__class__(
78            self.__baseTag, *(superTag,) + self.__superTags
79            )
80
81    def tagExplicitly(self, superTag):
82        tagClass, tagFormat, tagId = superTag
83        if tagClass == tagClassUniversal:
84            raise error.PyAsn1Error(
85                'Can\'t tag with UNIVERSAL-class tag'
86                )
87        if tagFormat != tagFormatConstructed:
88            superTag = Tag(tagClass, tagFormatConstructed, tagId)
89        return self + superTag
90
91    def tagImplicitly(self, superTag):
92        tagClass, tagFormat, tagId = superTag
93        if self.__superTags:
94            superTag = Tag(tagClass, self.__superTags[-1][1], tagId)
95        return self[:-1] + superTag
96
97    def getBaseTag(self): return self.__baseTag
98    def __getitem__(self, idx):
99        if isinstance(idx, slice):
100            return self.__class__(
101               self.__baseTag, *getitem(self.__superTags, idx)
102            )
103        return self.__superTags[idx]
104    def __eq__(self, other): return self.uniq == other.uniq
105    def __ne__(self, other): return self.uniq != other.uniq
106    def __lt__(self, other): return self.uniq < other.uniq
107    def __le__(self, other): return self.uniq <= other.uniq
108    def __gt__(self, other): return self.uniq > other.uniq
109    def __ge__(self, other): return self.uniq >= other.uniq
110    def __hash__(self): return self.__hashedSuperTags
111    def __len__(self): return self.__lenOfSuperTags
112    def isSuperTagSetOf(self, tagSet):
113        if len(tagSet) < self.__lenOfSuperTags:
114            return
115        idx = self.__lenOfSuperTags - 1
116        while idx >= 0:
117            if self.__superTags[idx] != tagSet[idx]:
118                return
119            idx = idx - 1
120        return 1
121
122def initTagSet(tag): return TagSet(tag, tag)
123