1#
2# This file is part of pyasn1 software.
3#
4# Copyright (c) 2005-2019, Ilya Etingof <etingof@gmail.com>
5# License: http://snmplabs.com/pyasn1/license.html
6#
7import sys
8
9from pyasn1 import error
10from pyasn1.type import tag
11from pyasn1.type import univ
12
13__all__ = ['NumericString', 'PrintableString', 'TeletexString', 'T61String', 'VideotexString',
14           'IA5String', 'GraphicString', 'VisibleString', 'ISO646String',
15           'GeneralString', 'UniversalString', 'BMPString', 'UTF8String']
16
17NoValue = univ.NoValue
18noValue = univ.noValue
19
20
21class AbstractCharacterString(univ.OctetString):
22    """Creates |ASN.1| schema or value object.
23
24    |ASN.1| class is based on :class:`~pyasn1.type.base.SimpleAsn1Type`,
25    its objects are immutable and duck-type Python 2 :class:`str` or Python 3
26    :class:`bytes`. When used in octet-stream context, |ASN.1| type assumes
27    "|encoding|" encoding.
28
29    Keyword Args
30    ------------
31    value: :class:`unicode`, :class:`str`, :class:`bytes` or |ASN.1| object
32        :class:`unicode` object (Python 2) or :class:`str` (Python 3),
33        alternatively :class:`str` (Python 2) or :class:`bytes` (Python 3)
34        representing octet-stream of serialised unicode string
35        (note `encoding` parameter) or |ASN.1| class instance.
36        If `value` is not given, schema object will be created.
37
38    tagSet: :py:class:`~pyasn1.type.tag.TagSet`
39        Object representing non-default ASN.1 tag(s)
40
41    subtypeSpec: :py:class:`~pyasn1.type.constraint.ConstraintsIntersection`
42        Object representing non-default ASN.1 subtype constraint(s). Constraints
43        verification for |ASN.1| type occurs automatically on object
44        instantiation.
45
46    encoding: :py:class:`str`
47        Unicode codec ID to encode/decode :class:`unicode` (Python 2) or
48        :class:`str` (Python 3) the payload when |ASN.1| object is used
49        in octet-stream context.
50
51    Raises
52    ------
53    ~pyasn1.error.ValueConstraintError, ~pyasn1.error.PyAsn1Error
54        On constraint violation or bad initializer.
55    """
56
57    if sys.version_info[0] <= 2:
58        def __str__(self):
59            try:
60                # `str` is Py2 text representation
61                return self._value.encode(self.encoding)
62
63            except UnicodeEncodeError:
64                exc = sys.exc_info()[1]
65                raise error.PyAsn1UnicodeEncodeError(
66                    "Can't encode string '%s' with codec "
67                    "%s" % (self._value, self.encoding), exc
68                )
69
70        def __unicode__(self):
71            return unicode(self._value)
72
73        def prettyIn(self, value):
74            try:
75                if isinstance(value, unicode):
76                    return value
77                elif isinstance(value, str):
78                    return value.decode(self.encoding)
79                elif isinstance(value, (tuple, list)):
80                    return self.prettyIn(''.join([chr(x) for x in value]))
81                elif isinstance(value, univ.OctetString):
82                    return value.asOctets().decode(self.encoding)
83                else:
84                    return unicode(value)
85
86            except (UnicodeDecodeError, LookupError):
87                exc = sys.exc_info()[1]
88                raise error.PyAsn1UnicodeDecodeError(
89                    "Can't decode string '%s' with codec "
90                    "%s" % (value, self.encoding), exc
91                )
92
93        def asOctets(self, padding=True):
94            return str(self)
95
96        def asNumbers(self, padding=True):
97            return tuple([ord(x) for x in str(self)])
98
99    else:
100        def __str__(self):
101            # `unicode` is Py3 text representation
102            return str(self._value)
103
104        def __bytes__(self):
105            try:
106                return self._value.encode(self.encoding)
107            except UnicodeEncodeError:
108                exc = sys.exc_info()[1]
109                raise error.PyAsn1UnicodeEncodeError(
110                    "Can't encode string '%s' with codec "
111                    "%s" % (self._value, self.encoding), exc
112                )
113
114        def prettyIn(self, value):
115            try:
116                if isinstance(value, str):
117                    return value
118                elif isinstance(value, bytes):
119                    return value.decode(self.encoding)
120                elif isinstance(value, (tuple, list)):
121                    return self.prettyIn(bytes(value))
122                elif isinstance(value, univ.OctetString):
123                    return value.asOctets().decode(self.encoding)
124                else:
125                    return str(value)
126
127            except (UnicodeDecodeError, LookupError):
128                exc = sys.exc_info()[1]
129                raise error.PyAsn1UnicodeDecodeError(
130                    "Can't decode string '%s' with codec "
131                    "%s" % (value, self.encoding), exc
132                )
133
134        def asOctets(self, padding=True):
135            return bytes(self)
136
137        def asNumbers(self, padding=True):
138            return tuple(bytes(self))
139
140    #
141    # See OctetString.prettyPrint() for the explanation
142    #
143
144    def prettyOut(self, value):
145        return value
146
147    def prettyPrint(self, scope=0):
148        # first see if subclass has its own .prettyOut()
149        value = self.prettyOut(self._value)
150
151        if value is not self._value:
152            return value
153
154        return AbstractCharacterString.__str__(self)
155
156    def __reversed__(self):
157        return reversed(self._value)
158
159
160class NumericString(AbstractCharacterString):
161    __doc__ = AbstractCharacterString.__doc__
162
163    #: Set (on class, not on instance) or return a
164    #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
165    #: associated with |ASN.1| type.
166    tagSet = AbstractCharacterString.tagSet.tagImplicitly(
167        tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 18)
168    )
169    encoding = 'us-ascii'
170
171    # Optimization for faster codec lookup
172    typeId = AbstractCharacterString.getTypeId()
173
174
175class PrintableString(AbstractCharacterString):
176    __doc__ = AbstractCharacterString.__doc__
177
178    #: Set (on class, not on instance) or return a
179    #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
180    #: associated with |ASN.1| type.
181    tagSet = AbstractCharacterString.tagSet.tagImplicitly(
182        tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 19)
183    )
184    encoding = 'us-ascii'
185
186    # Optimization for faster codec lookup
187    typeId = AbstractCharacterString.getTypeId()
188
189
190class TeletexString(AbstractCharacterString):
191    __doc__ = AbstractCharacterString.__doc__
192
193    #: Set (on class, not on instance) or return a
194    #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
195    #: associated with |ASN.1| type.
196    tagSet = AbstractCharacterString.tagSet.tagImplicitly(
197        tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 20)
198    )
199    encoding = 'iso-8859-1'
200
201    # Optimization for faster codec lookup
202    typeId = AbstractCharacterString.getTypeId()
203
204
205class T61String(TeletexString):
206    __doc__ = TeletexString.__doc__
207
208    # Optimization for faster codec lookup
209    typeId = AbstractCharacterString.getTypeId()
210
211
212class VideotexString(AbstractCharacterString):
213    __doc__ = AbstractCharacterString.__doc__
214
215    #: Set (on class, not on instance) or return a
216    #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
217    #: associated with |ASN.1| type.
218    tagSet = AbstractCharacterString.tagSet.tagImplicitly(
219        tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 21)
220    )
221    encoding = 'iso-8859-1'
222
223    # Optimization for faster codec lookup
224    typeId = AbstractCharacterString.getTypeId()
225
226
227class IA5String(AbstractCharacterString):
228    __doc__ = AbstractCharacterString.__doc__
229
230    #: Set (on class, not on instance) or return a
231    #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
232    #: associated with |ASN.1| type.
233    tagSet = AbstractCharacterString.tagSet.tagImplicitly(
234        tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 22)
235    )
236    encoding = 'us-ascii'
237
238    # Optimization for faster codec lookup
239    typeId = AbstractCharacterString.getTypeId()
240
241
242class GraphicString(AbstractCharacterString):
243    __doc__ = AbstractCharacterString.__doc__
244
245    #: Set (on class, not on instance) or return a
246    #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
247    #: associated with |ASN.1| type.
248    tagSet = AbstractCharacterString.tagSet.tagImplicitly(
249        tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 25)
250    )
251    encoding = 'iso-8859-1'
252
253    # Optimization for faster codec lookup
254    typeId = AbstractCharacterString.getTypeId()
255
256
257class VisibleString(AbstractCharacterString):
258    __doc__ = AbstractCharacterString.__doc__
259
260    #: Set (on class, not on instance) or return a
261    #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
262    #: associated with |ASN.1| type.
263    tagSet = AbstractCharacterString.tagSet.tagImplicitly(
264        tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 26)
265    )
266    encoding = 'us-ascii'
267
268    # Optimization for faster codec lookup
269    typeId = AbstractCharacterString.getTypeId()
270
271
272class ISO646String(VisibleString):
273    __doc__ = VisibleString.__doc__
274
275    # Optimization for faster codec lookup
276    typeId = AbstractCharacterString.getTypeId()
277
278class GeneralString(AbstractCharacterString):
279    __doc__ = AbstractCharacterString.__doc__
280
281    #: Set (on class, not on instance) or return a
282    #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
283    #: associated with |ASN.1| type.
284    tagSet = AbstractCharacterString.tagSet.tagImplicitly(
285        tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 27)
286    )
287    encoding = 'iso-8859-1'
288
289    # Optimization for faster codec lookup
290    typeId = AbstractCharacterString.getTypeId()
291
292
293class UniversalString(AbstractCharacterString):
294    __doc__ = AbstractCharacterString.__doc__
295
296    #: Set (on class, not on instance) or return a
297    #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
298    #: associated with |ASN.1| type.
299    tagSet = AbstractCharacterString.tagSet.tagImplicitly(
300        tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 28)
301    )
302    encoding = "utf-32-be"
303
304    # Optimization for faster codec lookup
305    typeId = AbstractCharacterString.getTypeId()
306
307
308class BMPString(AbstractCharacterString):
309    __doc__ = AbstractCharacterString.__doc__
310
311    #: Set (on class, not on instance) or return a
312    #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
313    #: associated with |ASN.1| type.
314    tagSet = AbstractCharacterString.tagSet.tagImplicitly(
315        tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 30)
316    )
317    encoding = "utf-16-be"
318
319    # Optimization for faster codec lookup
320    typeId = AbstractCharacterString.getTypeId()
321
322
323class UTF8String(AbstractCharacterString):
324    __doc__ = AbstractCharacterString.__doc__
325
326    #: Set (on class, not on instance) or return a
327    #: :py:class:`~pyasn1.type.tag.TagSet` object representing ASN.1 tag(s)
328    #: associated with |ASN.1| type.
329    tagSet = AbstractCharacterString.tagSet.tagImplicitly(
330        tag.Tag(tag.tagClassUniversal, tag.tagFormatSimple, 12)
331    )
332    encoding = "utf-8"
333
334    # Optimization for faster codec lookup
335    typeId = AbstractCharacterString.getTypeId()
336