1# NamedType specification for constructed types
2import sys
3from pyasn1.type import tagmap
4from pyasn1 import error
5
6class NamedType:
7    isOptional = 0
8    isDefaulted = 0
9    def __init__(self, name, t):
10        self.__name = name; self.__type = t
11    def __repr__(self): return '%s(%s, %s)' % (
12        self.__class__.__name__, self.__name, self.__type
13        )
14    def getType(self): return self.__type
15    def getName(self): return self.__name
16    def __getitem__(self, idx):
17        if idx == 0: return self.__name
18        if idx == 1: return self.__type
19        raise IndexError()
20
21class OptionalNamedType(NamedType):
22    isOptional = 1
23class DefaultedNamedType(NamedType):
24    isDefaulted = 1
25
26class NamedTypes:
27    def __init__(self, *namedTypes):
28        self.__namedTypes = namedTypes
29        self.__namedTypesLen = len(self.__namedTypes)
30        self.__minTagSet = None
31        self.__tagToPosIdx = {}; self.__nameToPosIdx = {}
32        self.__tagMap = { False: None, True: None }
33        self.__ambigiousTypes = {}
34
35    def __repr__(self):
36        r = '%s(' % self.__class__.__name__
37        for n in self.__namedTypes:
38            r = r + '%r, ' % (n,)
39        return r + ')'
40
41    def __getitem__(self, idx): return self.__namedTypes[idx]
42
43    if sys.version_info[0] <= 2:
44        def __nonzero__(self): return bool(self.__namedTypesLen)
45    else:
46        def __bool__(self): return bool(self.__namedTypesLen)
47    def __len__(self): return self.__namedTypesLen
48
49    def getTypeByPosition(self, idx):
50        if idx < 0 or idx >= self.__namedTypesLen:
51            raise error.PyAsn1Error('Type position out of range')
52        else:
53            return self.__namedTypes[idx].getType()
54
55    def getPositionByType(self, tagSet):
56        if not self.__tagToPosIdx:
57            idx = self.__namedTypesLen
58            while idx > 0:
59                idx = idx - 1
60                tagMap = self.__namedTypes[idx].getType().getTagMap()
61                for t in tagMap.getPosMap():
62                    if t in self.__tagToPosIdx:
63                        raise error.PyAsn1Error('Duplicate type %s' % (t,))
64                    self.__tagToPosIdx[t] = idx
65        try:
66            return self.__tagToPosIdx[tagSet]
67        except KeyError:
68            raise error.PyAsn1Error('Type %s not found' % (tagSet,))
69
70    def getNameByPosition(self, idx):
71        try:
72            return self.__namedTypes[idx].getName()
73        except IndexError:
74            raise error.PyAsn1Error('Type position out of range')
75    def getPositionByName(self, name):
76        if not self.__nameToPosIdx:
77            idx = self.__namedTypesLen
78            while idx > 0:
79                idx = idx - 1
80                n = self.__namedTypes[idx].getName()
81                if n in self.__nameToPosIdx:
82                    raise error.PyAsn1Error('Duplicate name %s' % (n,))
83                self.__nameToPosIdx[n] = idx
84        try:
85            return self.__nameToPosIdx[name]
86        except KeyError:
87            raise error.PyAsn1Error('Name %s not found' % (name,))
88
89    def __buildAmbigiousTagMap(self):
90        ambigiousTypes = ()
91        idx = self.__namedTypesLen
92        while idx > 0:
93            idx = idx - 1
94            t = self.__namedTypes[idx]
95            if t.isOptional or t.isDefaulted:
96                ambigiousTypes = (t, ) + ambigiousTypes
97            else:
98                ambigiousTypes = (t, )
99            self.__ambigiousTypes[idx] = NamedTypes(*ambigiousTypes)
100
101    def getTagMapNearPosition(self, idx):
102        if not self.__ambigiousTypes: self.__buildAmbigiousTagMap()
103        try:
104            return self.__ambigiousTypes[idx].getTagMap()
105        except KeyError:
106            raise error.PyAsn1Error('Type position out of range')
107
108    def getPositionNearType(self, tagSet, idx):
109        if not self.__ambigiousTypes: self.__buildAmbigiousTagMap()
110        try:
111            return idx+self.__ambigiousTypes[idx].getPositionByType(tagSet)
112        except KeyError:
113            raise error.PyAsn1Error('Type position out of range')
114
115    def genMinTagSet(self):
116        if self.__minTagSet is None:
117            for t in self.__namedTypes:
118                __type = t.getType()
119                tagSet = getattr(__type,'getMinTagSet',__type.getTagSet)()
120                if self.__minTagSet is None or tagSet < self.__minTagSet:
121                    self.__minTagSet = tagSet
122        return self.__minTagSet
123
124    def getTagMap(self, uniq=False):
125        if self.__tagMap[uniq] is None:
126            tagMap = tagmap.TagMap()
127            for nt in self.__namedTypes:
128                tagMap = tagMap.clone(
129                    nt.getType(), nt.getType().getTagMap(), uniq
130                    )
131            self.__tagMap[uniq] = tagMap
132        return self.__tagMap[uniq]
133