]> Cypherpunks.ru repositories - pyderasn.git/blobdiff - pyderasn.py
PrintableString can optionally allow * and &
[pyderasn.git] / pyderasn.py
index 5f0c0343ccd0d4153d29e6328fde4a73882229ec..f4f38a2c7121329bbd4ba797a55b87a2cf09e56a 100755 (executable)
@@ -570,6 +570,7 @@ _____________
 PrintableString
 _______________
 .. autoclass:: pyderasn.PrintableString
+   :members: __init__
 
 UTCTime
 _______
@@ -655,6 +656,7 @@ from math import ceil
 from os import environ
 from string import ascii_letters
 from string import digits
+from unicodedata import category as unicat
 
 from six import add_metaclass
 from six import binary_type
@@ -2750,13 +2752,7 @@ class OctetString(Obj):
         :param default: set default value. Type same as in ``value``
         :param bool optional: is object ``OPTIONAL`` in sequence
         """
-        super(OctetString, self).__init__(
-            impl,
-            expl,
-            default,
-            optional,
-            _decoded,
-        )
+        super(OctetString, self).__init__(impl, expl, default, optional, _decoded)
         self._value = value
         self._bound_min, self._bound_max = getattr(
             self,
@@ -3246,13 +3242,7 @@ class ObjectIdentifier(Obj):
         :param default: set default value. Type same as in ``value``
         :param bool optional: is object ``OPTIONAL`` in sequence
         """
-        super(ObjectIdentifier, self).__init__(
-            impl,
-            expl,
-            default,
-            optional,
-            _decoded,
-        )
+        super(ObjectIdentifier, self).__init__(impl, expl, default, optional, _decoded)
         self._value = value
         if value is not None:
             self._value = self._value_sanitize(value)
@@ -3523,13 +3513,7 @@ class Enumerated(Integer):
             bounds=None,  # dummy argument, workability for Integer.decode
     ):
         super(Enumerated, self).__init__(
-            value=value,
-            impl=impl,
-            expl=expl,
-            default=default,
-            optional=optional,
-            _specs=_specs,
-            _decoded=_decoded,
+            value, bounds, impl, expl,default, optional, _specs, _decoded,
         )
         if len(self.specs) == 0:
             raise ValueError("schema must be specified")
@@ -3590,6 +3574,12 @@ class Enumerated(Integer):
         )
 
 
+def escape_control_unicode(c):
+    if unicat(c).startswith("C"):
+        c = repr(c).lstrip("u").strip("'")
+    return c
+
+
 class CommonString(OctetString):
     """Common class for all strings
 
@@ -3708,7 +3698,10 @@ class CommonString(OctetString):
     def pps(self, decode_path=(), no_unicode=False):
         value = None
         if self.ready:
-            value = hexenc(bytes(self)) if no_unicode else self.__unicode__()
+            value = (
+                hexenc(bytes(self)) if no_unicode else
+                "".join(escape_control_unicode(c) for c in self.__unicode__())
+            )
         yield _pp(
             obj=self,
             asn1_type_name=self.asn1_type_name,
@@ -3787,6 +3780,32 @@ class PrintableString(AllowableCharsMixin, CommonString):
     _allowable_chars = frozenset(
         (ascii_letters + digits + " '()+,-./:=?").encode("ascii")
     )
+    _asterisk = frozenset("*".encode("ascii"))
+    _ampersand = frozenset("&".encode("ascii"))
+
+    def __init__(
+            self,
+            value=None,
+            bounds=None,
+            impl=None,
+            expl=None,
+            default=None,
+            optional=False,
+            _decoded=(0, 0, 0),
+            allow_asterisk=False,
+            allow_ampersand=False,
+    ):
+        """
+        :param allow_asterisk: allow asterisk character
+        :param allow_ampersand: allow ampersand character
+        """
+        if allow_asterisk:
+            self._allowable_chars |= self._asterisk
+        if allow_ampersand:
+            self._allowable_chars |= self._ampersand
+        super(PrintableString, self).__init__(
+            value, bounds, impl, expl, default, optional, _decoded,
+        )
 
     def _value_sanitize(self, value):
         value = super(PrintableString, self)._value_sanitize(value)
@@ -3794,6 +3813,34 @@ class PrintableString(AllowableCharsMixin, CommonString):
             raise DecodeError("non-printable value")
         return value
 
+    def copy(self):
+        obj = super(PrintableString, self).copy()
+        obj._allowable_chars = self._allowable_chars
+        return obj
+
+    def __call__(
+            self,
+            value=None,
+            bounds=None,
+            impl=None,
+            expl=None,
+            default=None,
+            optional=None,
+    ):
+        return self.__class__(
+            value=value,
+            bounds=(
+                (self._bound_min, self._bound_max)
+                if bounds is None else bounds
+            ),
+            impl=self.tag if impl is None else impl,
+            expl=self._expl if expl is None else expl,
+            default=self.default if default is None else default,
+            optional=self.optional if optional is None else optional,
+            allow_asterisk=self._asterisk <= self._allowable_chars,
+            allow_ampersand=self._ampersand <= self._allowable_chars,
+        )
+
 
 class TeletexString(CommonString):
     __slots__ = ()
@@ -3868,11 +3915,7 @@ class UTCTime(CommonString):
         :param bool optional: is object ``OPTIONAL`` in sequence
         """
         super(UTCTime, self).__init__(
-            impl=impl,
-            expl=expl,
-            default=default,
-            optional=optional,
-            _decoded=_decoded,
+            None, None, impl, expl, default, optional, _decoded,
         )
         self._value = value
         if value is not None:
@@ -5321,13 +5364,7 @@ class SequenceOf(Obj):
             optional=False,
             _decoded=(0, 0, 0),
     ):
-        super(SequenceOf, self).__init__(
-            impl,
-            expl,
-            default,
-            optional,
-            _decoded,
-        )
+        super(SequenceOf, self).__init__(impl, expl, default, optional, _decoded)
         if schema is None:
             schema = getattr(self, "schema", None)
         if schema is None: