1#
2# This file is part of pyasn1 software.
3#
4# Copyright (c) 2005-2020, 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()