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